source: exampleparties/anac2019/agentgg/src/main/java/geniusweb/exampleparties/agentgg/AgentGG.java@ 19

Last change on this file since 19 was 19, checked in by bart, 4 years ago

Tries harder to kill parties after deadline

File size: 16.3 KB
Line 
1package geniusweb.exampleparties.agentgg;
2
3import static java.lang.Math.max;
4
5import java.io.IOException;
6import java.util.Arrays;
7import java.util.HashMap;
8import java.util.HashSet;
9import java.util.List;
10import java.util.Map;
11import java.util.Random;
12import java.util.logging.Level;
13
14import javax.websocket.DeploymentException;
15
16import geniusweb.actions.Accept;
17import geniusweb.actions.Action;
18import geniusweb.actions.Offer;
19import geniusweb.actions.PartyId;
20import geniusweb.bidspace.AllBidsList;
21import geniusweb.issuevalue.Bid;
22import geniusweb.issuevalue.Value;
23import geniusweb.party.Capabilities;
24import geniusweb.party.DefaultParty;
25import geniusweb.party.inform.ActionDone;
26import geniusweb.party.inform.Finished;
27import geniusweb.party.inform.Inform;
28import geniusweb.party.inform.Settings;
29import geniusweb.party.inform.YourTurn;
30import geniusweb.profile.PartialOrdering;
31import geniusweb.profileconnection.ProfileConnectionFactory;
32import geniusweb.profileconnection.ProfileInterface;
33import geniusweb.progress.Progress;
34import geniusweb.progress.ProgressRounds;
35import tudelft.utilities.logging.Reporter;
36
37/**
38 * Translated version of Genius ANAC 2019 AgentGG originally written by Shaobo
39 * Xu and Peihao Ren of University of Southampton. This party requires a partial
40 * ordering as input (notice that most profiles are also partial ordering
41 * anyway). Much javadoc has been added after reverse engineering, to enable the
42 * translation.
43 */
44public class AgentGG extends DefaultParty {
45
46 private ImpMap impMap;
47 private ImpMap opponentImpMap;
48 private double offerLowerRatio = 1.0;
49 private double offerHigherRatio = 1.1;
50 protected double MAX_IMPORTANCE;
51 protected double MIN_IMPORTANCE;
52 private double MEDIAN_IMPORTANCE;
53 private Bid MAX_IMPORTANCE_BID;
54 private Bid MIN_IMPORTANCE_BID;
55 private Bid receivedBid;
56 private double reservationImportanceRatio;
57 private boolean offerRandomly = true;
58
59 private double startTime;
60 private boolean maxOppoBidImpForMeGot = false;
61 private double maxOppoBidImpForMe;
62 private double estimatedNashPoint;
63 private Bid lastReceivedBid;
64 private boolean initialTimePass = false;
65
66 // new for GeniusWeb
67 private ProfileInterface profileint;
68 private PartyId me;
69 private Progress progress;
70 private Action lastReceivedAction = null;
71 private final Random rand = new Random();
72 private AllBidsList allbids; // all bids in domain.
73
74 public AgentGG() {
75 super();
76 }
77
78 public AgentGG(Reporter reporter) {
79 super(reporter);
80 }
81
82 @Override
83 public void notifyChange(Inform info) {
84 try {
85 if (info instanceof Settings) {
86 init((Settings) info);
87 } else if (info instanceof ActionDone) {
88 lastReceivedAction = ((ActionDone) info).getAction();
89 if (lastReceivedAction instanceof Offer) {
90 this.receivedBid = ((Offer) lastReceivedAction).getBid();
91 }
92 } else if (info instanceof YourTurn) {
93 Action action = chooseAction();
94 getConnection().send(action);
95 if (progress instanceof ProgressRounds) {
96 progress = ((ProgressRounds) progress).advance();
97 }
98 } else if (info instanceof Finished) {
99 getReporter().log(Level.INFO, "Final ourcome:" + info);
100 }
101 } catch (Exception e) {
102 throw new RuntimeException("Failed to handle info", e);
103 }
104 }
105
106 @Override
107 public Capabilities getCapabilities() {
108 return new Capabilities(new HashSet<>(Arrays.asList("SAOP")));
109 }
110
111 @Override
112 public String getDescription() {
113 return "ANAC 2019 AgentGG translated to GeniusWeb. Requires partial profile. Use frequency counting to estimate important opponent values. ";
114 }
115
116 /***************
117 * private
118 *
119 * @throws DeploymentException
120 *********************/
121
122 private void init(Settings info) throws IOException, DeploymentException {
123 this.me = info.getID();
124 this.progress = info.getProgress();
125
126 this.profileint = ProfileConnectionFactory
127 .create(info.getProfile().getURI(), getReporter());
128 PartialOrdering partialprofile = (PartialOrdering) profileint
129 .getProfile();
130 allbids = new AllBidsList(partialprofile.getDomain());
131
132 // Create empty my import map
133 this.impMap = new ImpMap(partialprofile);
134 // and opponent's value map. CHECK why is the opponent map not initially
135 // empty?
136 this.opponentImpMap = new ImpMap(partialprofile);
137
138 // Wouter we use SimpleLinearOrdering (from shaop party) to get sorted
139 // bids from our profile.
140 List<Bid> orderedbids = new SimpleLinearOrdering(
141 profileint.getProfile()).getBids();
142
143 // Update my importance map
144 this.impMap.self_update(orderedbids);
145
146 // Get maximum, minimum, median bid
147 this.getMaxAndMinBid();
148 this.getMedianBid(orderedbids);
149
150 // Get the reservation value, converted to the percentage of importance
151 this.reservationImportanceRatio = this.getReservationRatio();
152
153 getReporter().log(Level.INFO,
154 "reservation ratio: " + this.reservationImportanceRatio);
155 getReporter().log(Level.INFO,
156 "my max importance bid: " + this.MAX_IMPORTANCE_BID);
157 getReporter().log(Level.INFO,
158 "my max importance: " + this.MAX_IMPORTANCE);
159 getReporter().log(Level.INFO,
160 "my min importance bid: " + this.MIN_IMPORTANCE_BID);
161 getReporter().log(Level.INFO,
162 "my min importance: " + this.MIN_IMPORTANCE);
163 getReporter().log(Level.INFO,
164 "my median importance: " + this.MEDIAN_IMPORTANCE);
165 getReporter().log(Level.INFO,
166 "Party " + me + " has finished initialization");
167 }
168
169 private Action chooseAction() {
170 double time = progress.get(System.currentTimeMillis());
171
172 // Start competition
173 if (!(this.lastReceivedAction instanceof Offer))
174 return new Offer(me, this.MAX_IMPORTANCE_BID);
175
176 // The ratio of the other party's offer to me
177 double impRatioForMe = (this.impMap.getImportance(this.receivedBid)
178 - this.MIN_IMPORTANCE)
179 / (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE);
180
181 // Accept the terms of the offer, which is higher than my threshold
182 if (impRatioForMe >= this.offerLowerRatio) {
183 getReporter().log(Level.INFO, "\n\naccepted agent: Agent" + me);
184 getReporter().log(Level.INFO, "last bid: " + this.receivedBid);
185 getReporter().log(Level.INFO,
186 "\ncurrent threshold: " + this.offerLowerRatio);
187 getReporter().log(Level.INFO, "\n\n");
188 return new Accept(me, this.receivedBid);
189 }
190
191 // When the opponent's importance is around 1.0, how much can he get.
192 // Finding the endpoints of the Pareto boundary
193 if (!maxOppoBidImpForMeGot)
194 this.getMaxOppoBidImpForMe(time, 3.0 / 1000.0);
195
196 // Update opponent importance table
197 if (time < 0.3)
198 this.opponentImpMap.opponent_update(this.receivedBid);
199
200 // Strategy
201 this.getThreshold(time);
202
203 // Last round
204 if (time >= 0.9989) {
205 double ratio = (this.impMap.getImportance(this.receivedBid)
206 - this.MIN_IMPORTANCE)
207 / (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE);
208 if (ratio > this.reservationImportanceRatio + 0.2) {
209 return new Accept(me, receivedBid);
210 }
211 }
212
213 getReporter().log(Level.INFO,
214 "high threshold: " + this.offerHigherRatio);
215 getReporter().log(Level.INFO, "low threshold: " + this.offerLowerRatio);
216 getReporter().log(Level.INFO,
217 "estimated nash: " + this.estimatedNashPoint);
218 getReporter().log(Level.INFO,
219 "reservation: " + this.reservationImportanceRatio);
220
221 Bid bid = getNeededRandomBid(this.offerLowerRatio,
222 this.offerHigherRatio);
223 this.lastReceivedBid = this.receivedBid;
224 return new Offer(me, bid);
225 }
226
227 /**
228 * Get our optimal value (Pareto optimal boundary point) when the utility of
229 * the other party is around 1.0 The opponent may first report the same bid
230 * several times, ignore it, and start timing at different times. For
231 * durations (such as 20 rounds), choose the bid with the highest importance
232 * for me. Since the bid of the other party must be very important to the
233 * other party at this time, it can meet our requirements.
234 */
235 private void getMaxOppoBidImpForMe(double time, double timeLast) {
236 double thisBidImp = this.impMap.getImportance(this.receivedBid);
237 if (thisBidImp > this.maxOppoBidImpForMe)
238 this.maxOppoBidImpForMe = thisBidImp;
239
240 if (this.initialTimePass) {
241 if (time - this.startTime > timeLast) {
242 double maxOppoBidRatioForMe = (this.maxOppoBidImpForMe
243 - this.MIN_IMPORTANCE)
244 / (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE);
245 this.estimatedNashPoint = (1 - maxOppoBidRatioForMe) / 1.7
246 + maxOppoBidRatioForMe; // 1.414 是圆,2是直线
247 this.maxOppoBidImpForMeGot = true;
248 }
249 } else {
250 if (this.lastReceivedBid != this.receivedBid) {
251 this.initialTimePass = true;
252 this.startTime = time;
253 }
254 }
255 }
256
257 /**
258 * Get upper and lower thresholds based on time
259 */
260 private void getThreshold(double time) {
261 if (time < 0.01) {
262 // The first 10 rounds of 0.9999, in order to adapt to some special
263 // domains
264 this.offerLowerRatio = 0.9999;
265 } else if (time < 0.02) {
266 // 10 ~ 20 rounds of 0.99, in order to adapt to some special domains
267 this.offerLowerRatio = 0.99;
268 } else if (time < 0.2) {
269 // 20 ~ 200 rounds reported high price, dropped to 0.9
270 this.offerLowerRatio = 0.99 - 0.5 * (time - 0.02);
271 } else if (time < 0.5) {
272 this.offerRandomly = false;
273 // 200 ~ 500 rounds gradually reduce the threshold to 0.5 from the
274 // estimated Nash point
275 double p2 = 0.3 * (1 - this.estimatedNashPoint)
276 + this.estimatedNashPoint;
277 this.offerLowerRatio = 0.9
278 - (0.9 - p2) / (0.5 - 0.2) * (time - 0.2);
279 } else if (time < 0.9) {
280 // 500 ~ 900 rounds quickly decrease the threshold to 0.2 from the
281 // estimated Nash point
282 double p1 = 0.3 * (1 - this.estimatedNashPoint)
283 + this.estimatedNashPoint;
284 double p2 = 0.15 * (1 - this.estimatedNashPoint)
285 + this.estimatedNashPoint;
286 this.offerLowerRatio = p1 - (p1 - p2) / (0.9 - 0.5) * (time - 0.5);
287 } else if (time < 0.98) {
288 // Compromise 1
289 double p1 = 0.15 * (1 - this.estimatedNashPoint)
290 + this.estimatedNashPoint;
291 double p2 = 0.05 * (1 - this.estimatedNashPoint)
292 + this.estimatedNashPoint;
293 double possibleRatio = p1 - (p1 - p2) / (0.98 - 0.9) * (time - 0.9);
294 this.offerLowerRatio = max(possibleRatio,
295 this.reservationImportanceRatio + 0.3);
296 } else if (time < 0.995) {
297 // Compromise 2 980 ~ 995 rounds
298 double p1 = 0.05 * (1 - this.estimatedNashPoint)
299 + this.estimatedNashPoint;
300 double p2 = 0.0 * (1 - this.estimatedNashPoint)
301 + this.estimatedNashPoint;
302 double possibleRatio = p1
303 - (p1 - p2) / (0.995 - 0.98) * (time - 0.98);
304 this.offerLowerRatio = max(possibleRatio,
305 this.reservationImportanceRatio + 0.25);
306 } else if (time < 0.999) {
307 // Compromise 3 995 ~ 999 rounds
308 double p1 = 0.0 * (1 - this.estimatedNashPoint)
309 + this.estimatedNashPoint;
310 double p2 = -0.35 * (1 - this.estimatedNashPoint)
311 + this.estimatedNashPoint;
312 double possibleRatio = p1
313 - (p1 - p2) / (0.9989 - 0.995) * (time - 0.995);
314 this.offerLowerRatio = max(possibleRatio,
315 this.reservationImportanceRatio + 0.25);
316 } else {
317 double possibleRatio = -0.4 * (1 - this.estimatedNashPoint)
318 + this.estimatedNashPoint;
319 this.offerLowerRatio = max(possibleRatio,
320 this.reservationImportanceRatio + 0.2);
321 }
322 // #1799 HACK not in original code : somethmes above computation goes
323 // wildly off bounds.
324 if (this.offerLowerRatio > 1)
325 this.offerLowerRatio = 0.9999;
326 this.offerHigherRatio = this.offerLowerRatio + 0.1;
327 }
328
329 /**
330 * Get the ratio of the reservation value to the importance matrix. ASSUMES
331 * The imgMap has been initialized.
332 *
333 */
334 private double getReservationRatio() throws IOException {
335 double medianBidRatio = (this.MEDIAN_IMPORTANCE - this.MIN_IMPORTANCE)
336 / (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE);
337 Bid resBid = this.profileint.getProfile().getReservationBid();
338 double resValue = 0.1;
339 if (resBid != null) {
340 resValue = this.impMap.getImportance(resBid);
341 }
342 return resValue * medianBidRatio / 0.5;
343 }
344
345 /**
346 * Get the maximum and minimum importance values and corresponding offers
347 */
348 private void getMaxAndMinBid() {
349 HashMap<String, Value> lValues1 = new HashMap<>();
350 HashMap<String, Value> lValues2 = new HashMap<>();
351 for (Map.Entry<String, List<impUnit>> entry : this.impMap.entrySet()) {
352 Value value1 = entry.getValue().get(0).valueOfIssue;
353 Value value2 = entry.getValue()
354 .get(entry.getValue().size() - 1).valueOfIssue;
355 String issue = entry.getKey();
356 lValues1.put(issue, value1);
357 lValues2.put(issue, value2);
358 }
359 this.MAX_IMPORTANCE_BID = new Bid(lValues1);
360 this.MIN_IMPORTANCE_BID = new Bid(lValues2);
361 this.MAX_IMPORTANCE = this.impMap
362 .getImportance(this.MAX_IMPORTANCE_BID);
363 this.MIN_IMPORTANCE = this.impMap
364 .getImportance(this.MIN_IMPORTANCE_BID);
365 }
366
367 /**
368 * Get the import value corresponding to the median bid in bid ranking
369 *
370 * @param orderedbids a list of bids, ordered from low to high utility.
371 */
372 private void getMedianBid(List<Bid> orderedbids) {
373
374 int median = (orderedbids.size() - 1) / 2;
375 int median2 = -1;
376 if (orderedbids.size() % 2 == 0) {
377 median2 = median + 1;
378 }
379 int current = 0;
380 for (Bid bid : orderedbids) {
381 current += 1;
382 if (current == median) {
383 this.MEDIAN_IMPORTANCE = this.impMap.getImportance(bid);
384 if (median2 == -1)
385 break;
386 }
387 if (current == median2) {
388 this.MEDIAN_IMPORTANCE += this.impMap.getImportance(bid);
389 break;
390 }
391 }
392 if (median2 != -1)
393 this.MEDIAN_IMPORTANCE /= 2;
394 }
395
396// /**
397// * 更新对手的最大及最小Importance的值及对应OFFER
398// */
399// private void getOpponentMaxAndMinBid() {
400// HashMap<Integer, Value> lValues1 = new HashMap<>();
401// HashMap<Integer, Value> lValues2 = new HashMap<>();
402// for (Map.Entry<Issue, List<impUnit>> entry : this.opponentImpMap.entrySet()) {
403// Value value1 = entry.getValue().get(0).valueOfIssue;
404// Value value2 = entry.getValue().get(entry.getValue().size() - 1).valueOfIssue;
405// int issueNumber = entry.getKey().getNumber();
406// lValues1.put(issueNumber, value1);
407// lValues2.put(issueNumber, value2);
408// }
409// Bid OPPONENT_MAX_IMPORTANCE_BID = new Bid(this.getDomain(), lValues1);
410// Bid OPPONENT_MIN_IMPORTANCE_BID = new Bid(this.getDomain(), lValues2);
411// this.OPPONENT_MAX_IMPORTANCE = this.opponentImpMap.getImportance(OPPONENT_MAX_IMPORTANCE_BID);
412// this.OPPONENT_MIN_IMPORTANCE = this.opponentImpMap.getImportance(OPPONENT_MIN_IMPORTANCE_BID);
413// }
414
415 /**
416 * Get eligible random bids. Generate k bids randomly, select bids within
417 * the threshold range, and return the bid with the highest opponent import.
418 *
419 * @param lowerRatio Generate a lower limit for the random bid in [0,1]
420 * @param upperRatio Generate random bid upper limit can be >1
421 * @return Bid
422 * @throws IOException
423 */
424 private Bid getNeededRandomBid(double lowerRatio, double upperRatio) {
425 final long k = 2 * this.allbids.size().longValue();
426 double lowerThreshold = lowerRatio
427 * (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE)
428 + this.MIN_IMPORTANCE;
429 double upperThreshold = upperRatio
430 * (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE)
431 + this.MIN_IMPORTANCE;
432
433 for (int t = 0; t < 3; t++) {
434 double highest_opponent_importance = 0.0;
435 Bid returnedBid = null;
436 for (int i = 0; i < k; i++) {
437 Bid bid = generateRandomBid();
438 double bidImportance = this.impMap.getImportance(bid);
439 double bidOpponentImportance = this.opponentImpMap
440 .getImportance(bid);
441 if (bidImportance >= lowerThreshold
442 && bidImportance <= upperThreshold) {
443 if (this.offerRandomly)
444 return bid; // Randomly bid for the first 0.2 time
445 if (bidOpponentImportance > highest_opponent_importance) {
446 highest_opponent_importance = bidOpponentImportance;
447 returnedBid = bid;
448 }
449 }
450 }
451 if (returnedBid != null) {
452 return returnedBid;
453 }
454 }
455 // If something goes wrong and no suitable bid is found, then a higher
456 // than the lower limit
457 while (true) {
458 Bid bid = generateRandomBid();
459 if (this.impMap.getImportance(bid) >= lowerThreshold) {
460 return bid;
461 }
462 }
463 }
464
465 private Bid generateRandomBid() {
466 return allbids.get(rand.nextInt(allbids.size().intValue()));
467 }
468
469}
Note: See TracBrowser for help on using the repository browser.