source: anac2020/agentxx/src/main/java/geniusweb/exampleparties/agentgg/AgentGG.java@ 24

Last change on this file since 24 was 24, checked in by wouter, 3 years ago

#3

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