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

Last change on this file since 52 was 52, checked in by ruud, 14 months ago

Fixed small issues in domaineditor.

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