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

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

Added ANAC2019 Example parties: Agentgg and WinkyAgent

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