1 | package parties.in4010.q12015.group15;
|
---|
2 |
|
---|
3 | import java.util.ArrayList;
|
---|
4 | import java.util.List;
|
---|
5 | import java.util.Random;
|
---|
6 |
|
---|
7 | import genius.core.AgentID;
|
---|
8 | import genius.core.Bid;
|
---|
9 | import genius.core.actions.Accept;
|
---|
10 | import genius.core.actions.Action;
|
---|
11 | import genius.core.actions.DefaultAction;
|
---|
12 | import genius.core.actions.Offer;
|
---|
13 | import genius.core.bidding.BidDetails;
|
---|
14 | import genius.core.boaframework.Actions;
|
---|
15 | import genius.core.boaframework.SortedOutcomeSpace;
|
---|
16 | import genius.core.issue.Issue;
|
---|
17 | import genius.core.misc.Range;
|
---|
18 | import genius.core.parties.AbstractNegotiationParty;
|
---|
19 | import genius.core.parties.NegotiationInfo;
|
---|
20 | import genius.core.protocol.DefaultMultilateralProtocol;
|
---|
21 | import genius.core.protocol.StackedAlternatingOffersProtocol;
|
---|
22 | import genius.core.utility.AdditiveUtilitySpace;
|
---|
23 |
|
---|
24 | /**
|
---|
25 | * Negotiation party for Group15. Group members: Fabio Izzi, Kristin Fjola
|
---|
26 | * Tomasdottir, Valentina Bollini
|
---|
27 | *
|
---|
28 | * The bidding strategy is a version of time dependent concession with trade off
|
---|
29 | * using opponent modeling.
|
---|
30 | *
|
---|
31 | * We look at all offers in a certain range of utility. That range starts high
|
---|
32 | * (0.95 - 1) and lowers with time. First 2/3 of the time we choose an offer
|
---|
33 | * from that range with the lowest combined Hamming distance to all opponents
|
---|
34 | * based on their last bid. Last 1/3 of the time we choose an offer from that
|
---|
35 | * range using opponent modeling.
|
---|
36 | */
|
---|
37 | public class Group15 extends AbstractNegotiationParty {
|
---|
38 |
|
---|
39 | private double MIN_UTILITY_TO_OFFER;
|
---|
40 | private double OFFER_GROUP_SIZE;
|
---|
41 | private double TIME_TO_SWITCH_TO_OMS;
|
---|
42 | private double TIME_TO_LOWER_MIN_UTILITY;
|
---|
43 |
|
---|
44 | // Bidding strategy
|
---|
45 | private Bid lastBid;
|
---|
46 | private List<Bid> bidsOffered = new ArrayList<>();
|
---|
47 | private SortedOutcomeSpace outcomeSpace;
|
---|
48 | private double lastTimeMinUtilityWasLowered;
|
---|
49 | private boolean isUsingOMS;
|
---|
50 | private int rounds = 0;
|
---|
51 |
|
---|
52 | // BOA elements
|
---|
53 | private OpponentModel om;
|
---|
54 | private OMStrategy oms;
|
---|
55 | private AcceptanceStrategy as;
|
---|
56 |
|
---|
57 | // Time measurements
|
---|
58 | long ourStartTime = 0;
|
---|
59 | long roundStartTime = 0;
|
---|
60 | double timeCount = 0.0;
|
---|
61 | double ourTotalTime = 0;
|
---|
62 | double roundTotalTime = 0;
|
---|
63 |
|
---|
64 | public Group15() {
|
---|
65 | }
|
---|
66 |
|
---|
67 | @Override
|
---|
68 | public void init(NegotiationInfo info) {
|
---|
69 | super.init(info);
|
---|
70 |
|
---|
71 | outcomeSpace = new SortedOutcomeSpace(info.getUtilitySpace());
|
---|
72 | outcomeSpace.generateAllBids(info.getUtilitySpace());
|
---|
73 |
|
---|
74 | MIN_UTILITY_TO_OFFER = 0.95; // Start offering the highest utility for
|
---|
75 | // us
|
---|
76 | OFFER_GROUP_SIZE = 0.05; // Look at offers in a range of max-min=0.05
|
---|
77 | TIME_TO_SWITCH_TO_OMS = 2 / 3.0; // After 2/3 of the time we are
|
---|
78 | // confident in our OM
|
---|
79 | TIME_TO_LOWER_MIN_UTILITY = (2 / 3.0) / 6.0; // 6 steps of lowering
|
---|
80 | // minUtil by 0.05 to
|
---|
81 | // get to utility 0.7
|
---|
82 | lastTimeMinUtilityWasLowered = timeline.getTime(); // Keep track of when
|
---|
83 | // to lower min
|
---|
84 | // utility (concede)
|
---|
85 | isUsingOMS = false; // Start by not using OMS
|
---|
86 |
|
---|
87 | // BOA elements
|
---|
88 | om = new OpponentModel((AdditiveUtilitySpace) info.getUtilitySpace());
|
---|
89 | as = new AcceptanceStrategy((AdditiveUtilitySpace) info.getUtilitySpace());
|
---|
90 | oms = new OMStrategy(om, (AdditiveUtilitySpace) info.getUtilitySpace());
|
---|
91 | }
|
---|
92 |
|
---|
93 | /**
|
---|
94 | * @param validActions
|
---|
95 | * : Either a list containing both accept and offer or only
|
---|
96 | * offer.
|
---|
97 | * @return The chosen action.
|
---|
98 | */
|
---|
99 | @Override
|
---|
100 | public Action chooseAction(List<Class<? extends Action>> validActions) {
|
---|
101 | System.out.println("---- BS Choose action ---");
|
---|
102 | rounds++;
|
---|
103 | System.out.println("Round: " + rounds);
|
---|
104 | double roundTime = measureAverageRoundTime();
|
---|
105 |
|
---|
106 | // Accept if offer is good enough according to our AS
|
---|
107 | if (validActions.contains(Accept.class)
|
---|
108 | && as.determineAcceptability(lastBid, timeline, roundTime).equals(Actions.Accept)) {
|
---|
109 | return new Accept(getPartyId(), lastBid);
|
---|
110 | }
|
---|
111 |
|
---|
112 | // If we're the first one to make an offer
|
---|
113 | if (!validActions.contains(Accept.class)) {
|
---|
114 | try {
|
---|
115 | return getFirstBid();
|
---|
116 | } catch (Exception e) {
|
---|
117 | System.out.println("Could not generate first bid");
|
---|
118 | e.printStackTrace();
|
---|
119 | }
|
---|
120 | }
|
---|
121 |
|
---|
122 | // Concede to lower minimum utility if a certain time has passed
|
---|
123 | if ((timeline.getTime() - lastTimeMinUtilityWasLowered) >= TIME_TO_LOWER_MIN_UTILITY) {
|
---|
124 | lowerMinUtility();
|
---|
125 | }
|
---|
126 |
|
---|
127 | List<BidDetails> possibleBids = getPossibleBids();
|
---|
128 | Bid bestBid = null;
|
---|
129 |
|
---|
130 | // Switch to using OMS when we're confident in the OM
|
---|
131 | if (!isUsingOMS && timeline.getTime() >= TIME_TO_SWITCH_TO_OMS) {
|
---|
132 | switchToOms();
|
---|
133 | }
|
---|
134 |
|
---|
135 | // First we use Hamming Distance, then Opponent Modeling
|
---|
136 | if (!isUsingOMS) {
|
---|
137 | bestBid = getBidWithSmallestHammingDistance(possibleBids);
|
---|
138 | } else {
|
---|
139 | bestBid = oms.getBestBid(possibleBids);
|
---|
140 | }
|
---|
141 |
|
---|
142 | // If something goes wrong in the bidding strategy or if we already
|
---|
143 | // offered all bids in the interval
|
---|
144 | // we offer a random bid within our utility demand
|
---|
145 | if (bestBid == null) {
|
---|
146 | bestBid = getRandomBidInInterval(MIN_UTILITY_TO_OFFER, MIN_UTILITY_TO_OFFER + OFFER_GROUP_SIZE);
|
---|
147 | }
|
---|
148 |
|
---|
149 | System.out.println("---- BS Choose action ---");
|
---|
150 | System.out.println("My BID offered: " + bestBid);
|
---|
151 | try {
|
---|
152 | System.out.println("My BID Util: " + utilitySpace.getUtility(bestBid));
|
---|
153 | } catch (Exception e) {
|
---|
154 | e.printStackTrace();
|
---|
155 | }
|
---|
156 |
|
---|
157 | return new Offer(getPartyId(), bestBid);
|
---|
158 | }
|
---|
159 |
|
---|
160 | /**
|
---|
161 | * Lowers the minimum utility that we want to offer by a constant
|
---|
162 | */
|
---|
163 | public void lowerMinUtility() {
|
---|
164 | MIN_UTILITY_TO_OFFER -= OFFER_GROUP_SIZE;
|
---|
165 | lastTimeMinUtilityWasLowered = timeline.getTime();
|
---|
166 | System.out.println("Lowering MIN_UTILITY_TO_OFFER to: " + MIN_UTILITY_TO_OFFER + " in round: " + rounds);
|
---|
167 | }
|
---|
168 |
|
---|
169 | /**
|
---|
170 | * @return the bid we want to offer when we're the first one to make a bid
|
---|
171 | * @throws Exception
|
---|
172 | */
|
---|
173 | public Action getFirstBid() throws Exception {
|
---|
174 | // As our first bid we want to offer our best bid possible
|
---|
175 | return new Offer(getPartyId(), utilitySpace.getMaxUtilityBid());
|
---|
176 | }
|
---|
177 |
|
---|
178 | /**
|
---|
179 | * @return all possible bids in the range of our min utility + constant
|
---|
180 | */
|
---|
181 | public List<BidDetails> getPossibleBids() {
|
---|
182 | Range range = new Range(MIN_UTILITY_TO_OFFER, MIN_UTILITY_TO_OFFER + OFFER_GROUP_SIZE);
|
---|
183 | List<BidDetails> possibleBids = outcomeSpace.getBidsinRange(range);
|
---|
184 | return possibleBids;
|
---|
185 | }
|
---|
186 |
|
---|
187 | /**
|
---|
188 | * Switches from using Hamming distance to choose a bid to use our opponent
|
---|
189 | * modeling instead
|
---|
190 | */
|
---|
191 | private void switchToOms() {
|
---|
192 | isUsingOMS = true;
|
---|
193 | MIN_UTILITY_TO_OFFER = 0.95; // We might choose other offers than before
|
---|
194 | TIME_TO_LOWER_MIN_UTILITY = (1 / 3.0) / 6.0; // Only 1/3 of the time is
|
---|
195 | // left and we want to
|
---|
196 | // concede to utility
|
---|
197 | // 0.7
|
---|
198 | lastTimeMinUtilityWasLowered = timeline.getTime();
|
---|
199 | System.out.println("CHANGING TO OMS in round: " + rounds);
|
---|
200 | System.out.println("Setting min utility to: " + MIN_UTILITY_TO_OFFER);
|
---|
201 | }
|
---|
202 |
|
---|
203 | /**
|
---|
204 | * @param all
|
---|
205 | * possible bids in some range
|
---|
206 | * @return bid with smallest sum of Hamming distance to all opponents from
|
---|
207 | * the list of bids
|
---|
208 | */
|
---|
209 | private Bid getBidWithSmallestHammingDistance(List<BidDetails> bids) {
|
---|
210 | System.out.println("---- BS Hamming ----");
|
---|
211 | Bid bestBid = null; // If it doesn't succeed to calc Hamming distance
|
---|
212 | int smallestDist = Integer.MAX_VALUE;
|
---|
213 |
|
---|
214 | for (BidDetails b : bids) {
|
---|
215 | if (bidsOffered.contains(b.getBid())) { // Don't offer same bid
|
---|
216 | // twice
|
---|
217 | System.out.println("Has offered bid before: " + b.getBid());
|
---|
218 | continue;
|
---|
219 | }
|
---|
220 | int totalDist = 0;
|
---|
221 |
|
---|
222 | for (String opponent : om.getOpponents()) {
|
---|
223 | totalDist += getHammingDistance(b.getBid(), om.getLastBidFromAgent(opponent));
|
---|
224 | }
|
---|
225 |
|
---|
226 | if (totalDist < smallestDist) {
|
---|
227 | smallestDist = totalDist;
|
---|
228 | bestBid = b.getBid();
|
---|
229 | }
|
---|
230 | }
|
---|
231 | System.out.println("Smallest dist found: " + smallestDist);
|
---|
232 |
|
---|
233 | bidsOffered.add(bestBid);
|
---|
234 | return bestBid;
|
---|
235 | }
|
---|
236 |
|
---|
237 | /**
|
---|
238 | * @param bid1
|
---|
239 | * @param bid2
|
---|
240 | * @return Hamming distance between bid1 and bid2
|
---|
241 | */
|
---|
242 | private int getHammingDistance(Bid bid1, Bid bid2) {
|
---|
243 | int dist = 0;
|
---|
244 | List<Issue> issues = bid1.getIssues();
|
---|
245 | for (Issue issue : issues) {
|
---|
246 | int indexOfIssue = issues.indexOf(issue) + 1;
|
---|
247 | try {
|
---|
248 | if (!bid1.getValue(indexOfIssue).equals(bid2.getValue(indexOfIssue))) {
|
---|
249 | dist++;
|
---|
250 | }
|
---|
251 | } catch (Exception e) {
|
---|
252 | System.out.println("BS Could not calculate Hamming distance between " + bid1 + " and " + bid2);
|
---|
253 | e.printStackTrace();
|
---|
254 | }
|
---|
255 | }
|
---|
256 |
|
---|
257 | return dist;
|
---|
258 | }
|
---|
259 |
|
---|
260 | /**
|
---|
261 | * @return average time in seconds for each round
|
---|
262 | */
|
---|
263 | public double measureAverageRoundTime() {
|
---|
264 | timeCount++;
|
---|
265 | double roundAvgTime = 0;
|
---|
266 | if (roundStartTime != 0) {
|
---|
267 | long roundEndTime = System.nanoTime();
|
---|
268 | long roundTime = roundEndTime - roundStartTime;
|
---|
269 | double roundTimeSeconds = (double) roundTime / 1000000000.0;
|
---|
270 | roundTotalTime += roundTimeSeconds;
|
---|
271 | roundAvgTime = (roundTotalTime / (timeCount - 1));
|
---|
272 | }
|
---|
273 | ourStartTime = System.nanoTime();
|
---|
274 | roundStartTime = System.nanoTime();
|
---|
275 |
|
---|
276 | return roundAvgTime;
|
---|
277 | }
|
---|
278 |
|
---|
279 | /**
|
---|
280 | * @param min
|
---|
281 | * utility wanted
|
---|
282 | * @param max
|
---|
283 | * utility wanted
|
---|
284 | * @return random bid with utility between min and max
|
---|
285 | */
|
---|
286 | private Bid getRandomBidInInterval(double min, double max) {
|
---|
287 | System.out.println("WARNING: Offering random bid in range: " + min + " - " + max);
|
---|
288 | Random rand = new Random();
|
---|
289 | double randomUtility = min + (max - min) * rand.nextDouble();
|
---|
290 | BidDetails bidDetails = outcomeSpace.getBidNearUtility(randomUtility);
|
---|
291 | return bidDetails.getBid();
|
---|
292 | }
|
---|
293 |
|
---|
294 | /**
|
---|
295 | *
|
---|
296 | * @param sender
|
---|
297 | * The party that did the action.
|
---|
298 | * @param action
|
---|
299 | * The action that party did.
|
---|
300 | */
|
---|
301 | @Override
|
---|
302 | public void receiveMessage(AgentID sender, Action action) {
|
---|
303 | System.out.println("--- BS receive msg ---");
|
---|
304 | super.receiveMessage(sender, action);
|
---|
305 | System.out
|
---|
306 | .println("Receive " + action.getClass() + " at time: " + timeline.getTime() + " from agent " + sender);
|
---|
307 | if (action instanceof Offer && sender != null) {
|
---|
308 | lastBid = DefaultAction.getBidFromAction(action);
|
---|
309 | om.updateModel(sender.toString(), lastBid, rounds);
|
---|
310 | }
|
---|
311 | }
|
---|
312 |
|
---|
313 | @Override
|
---|
314 | public String getDescription() {
|
---|
315 | return "Multi Party Negotiation Agent Group 15";
|
---|
316 | }
|
---|
317 |
|
---|
318 | @Override
|
---|
319 | public Class<? extends DefaultMultilateralProtocol> getProtocol() {
|
---|
320 | return StackedAlternatingOffersProtocol.class;
|
---|
321 | }
|
---|
322 |
|
---|
323 | } |
---|