source: anac2020/agentxx/src/main/java/geniusweb/exampleparties/newagentgg/AgentGG.java

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

#5 fix supported profile type

File size: 15.4 KB
Line 
1package geniusweb.exampleparties.newagentgg;
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.profileconnection.ProfileConnectionFactory;
33import geniusweb.profileconnection.ProfileInterface;
34import geniusweb.progress.Progress;
35import geniusweb.progress.ProgressRounds;
36import tudelft.utilities.logging.Reporter;
37
38/**
39 * Translated version of Genius ANAC 2019 AgentGG originally written by Shaobo
40 * Xu and Peihao Ren of University of Southampton. This party requires a partial
41 * ordering as input (notice that most profiles are also partial ordering
42 * anyway).
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 private double MAX_IMPORTANCE;
51 private 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")), Collections.singleton(PartialOrdering.class));
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.create(info.getProfile().getURI(), getReporter());
127 PartialOrdering partialprofile = (PartialOrdering) profileint.getProfile();
128 allbids = new AllBidsList(partialprofile.getDomain());
129
130 // Create empty my import map
131 this.impMap = new ImpMap(partialprofile);
132 // and opponent's value map. CHECK why is the opponent map not initially
133 // empty?
134 this.opponentImpMap = new ImpMap(partialprofile);
135
136 // Wouter we use SimpleLinearOrdering (from shaop party) to get sorted
137 // bids from our profile.
138 List<Bid> orderedbids = new SimpleLinearOrdering(profileint.getProfile()).getBids();
139
140 // Update my importance map
141 this.impMap.self_update(orderedbids);
142
143 // Get maximum, minimum, median bid
144 this.getMaxAndMinBid();
145 this.getMedianBid(orderedbids);
146
147 // Get the reservation value, converted to the percentage of importance
148 this.reservationImportanceRatio = this.getReservationRatio();
149
150 getReporter().log(Level.INFO, "reservation ratio: " + this.reservationImportanceRatio);
151 getReporter().log(Level.INFO, "my max importance bid: " + this.MAX_IMPORTANCE_BID);
152 getReporter().log(Level.INFO, "my max importance: " + this.MAX_IMPORTANCE);
153 getReporter().log(Level.INFO, "my min importance bid: " + this.MIN_IMPORTANCE_BID);
154 getReporter().log(Level.INFO, "my min importance: " + this.MIN_IMPORTANCE);
155 getReporter().log(Level.INFO, "my median importance: " + this.MEDIAN_IMPORTANCE);
156 getReporter().log(Level.INFO, "Party " + me + " has finished initialization");
157 }
158
159 private Action chooseAction() {
160 double time = progress.get(System.currentTimeMillis());
161
162 // Start competition
163 if (!(this.lastReceivedAction instanceof Offer))
164 return new Offer(me, this.MAX_IMPORTANCE_BID);
165
166 // The ratio of the other party's offer to me
167 double impRatioForMe = (this.impMap.getImportance(this.receivedBid) - this.MIN_IMPORTANCE)
168 / (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE);
169
170 // Accept the terms of the offer, which is higher than my threshold
171 if (impRatioForMe >= this.offerLowerRatio) {
172 getReporter().log(Level.INFO, "\n\naccepted agent: Agent" + me);
173 getReporter().log(Level.INFO, "last bid: " + this.receivedBid);
174 getReporter().log(Level.INFO, "\ncurrent threshold: " + this.offerLowerRatio);
175 getReporter().log(Level.INFO, "\n\n");
176 return new Accept(me, this.receivedBid);
177 }
178
179 // When the opponent's importance is around 1.0, how much can he get.
180 // Finding the endpoints of the Pareto boundary
181 if (!maxOppoBidImpForMeGot)
182 this.getMaxOppoBidImpForMe(time, 3.0 / 1000.0);
183
184 // Update opponent importance table
185 if (time < 0.3)
186 this.opponentImpMap.opponent_update(this.receivedBid);
187
188 // Strategy
189 this.getThreshold(time);
190
191 // Last round
192 if (time >= 0.9989) {
193 double ratio = (this.impMap.getImportance(this.receivedBid) - this.MIN_IMPORTANCE)
194 / (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE);
195 if (ratio > this.reservationImportanceRatio + 0.2) {
196 return new Accept(me, receivedBid);
197 }
198 }
199
200 getReporter().log(Level.INFO, "high threshold: " + this.offerHigherRatio);
201 getReporter().log(Level.INFO, "low threshold: " + this.offerLowerRatio);
202 getReporter().log(Level.INFO, "estimated nash: " + this.estimatedNashPoint);
203 getReporter().log(Level.INFO, "reservation: " + this.reservationImportanceRatio);
204
205 Bid bid = getNeededRandomBid(this.offerLowerRatio, this.offerHigherRatio);
206 this.lastReceivedBid = this.receivedBid;
207 return new Offer(me, bid);
208 }
209
210 /**
211 * Get our optimal value (Pareto optimal boundary point) when the utility of the
212 * other party is around 1.0 The opponent may first report the same bid several
213 * times, ignore it, and start timing at different times. For durations (such as
214 * 20 rounds), choose the bid with the highest importance for me. Since the bid
215 * of the other party must be very important to the other party at this time, it
216 * can meet our requirements.
217 */
218 private void getMaxOppoBidImpForMe(double time, double timeLast) {
219 double thisBidImp = this.impMap.getImportance(this.receivedBid);
220 if (thisBidImp > this.maxOppoBidImpForMe)
221 this.maxOppoBidImpForMe = thisBidImp;
222
223 if (this.initialTimePass) {
224 if (time - this.startTime > timeLast) {
225 double maxOppoBidRatioForMe = (this.maxOppoBidImpForMe - this.MIN_IMPORTANCE)
226 / (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE);
227 this.estimatedNashPoint = (1 - maxOppoBidRatioForMe) / 1.7 + maxOppoBidRatioForMe; // 1.414 是圆,2是直线
228 this.maxOppoBidImpForMeGot = true;
229 }
230 } else {
231 if (this.lastReceivedBid != this.receivedBid) {
232 this.initialTimePass = true;
233 this.startTime = time;
234 }
235 }
236 }
237
238 /**
239 * Get upper and lower thresholds based on time
240 */
241 private void getThreshold(double time) {
242 if (time < 0.01) {
243 // The first 10 rounds of 0.9999, in order to adapt to some special
244 // domains
245 this.offerLowerRatio = 0.9999;
246 } else if (time < 0.02) {
247 // 10 ~ 20 rounds of 0.99, in order to adapt to some special domains
248 this.offerLowerRatio = 0.99;
249 } else if (time < 0.2) {
250 // 20 ~ 200 rounds reported high price, dropped to 0.9
251 this.offerLowerRatio = 0.99 - 0.5 * (time - 0.02);
252 } else if (time < 0.5) {
253 this.offerRandomly = false;
254 // 200 ~ 500 rounds gradually reduce the threshold to 0.5 from the
255 // estimated Nash point
256 double p2 = 0.3 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
257 this.offerLowerRatio = 0.9 - (0.9 - p2) / (0.5 - 0.2) * (time - 0.2);
258 } else if (time < 0.9) {
259 // 500 ~ 900 rounds quickly decrease the threshold to 0.2 from the
260 // estimated Nash point
261 double p1 = 0.3 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
262 double p2 = 0.15 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
263 this.offerLowerRatio = p1 - (p1 - p2) / (0.9 - 0.5) * (time - 0.5);
264 } else if (time < 0.98) {
265 // Compromise 1
266 double p1 = 0.15 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
267 double p2 = 0.05 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
268 double possibleRatio = p1 - (p1 - p2) / (0.98 - 0.9) * (time - 0.9);
269 this.offerLowerRatio = max(possibleRatio, this.reservationImportanceRatio + 0.3);
270 } else if (time < 0.995) {
271 // Compromise 2 980 ~ 995 rounds
272 double p1 = 0.05 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
273 double p2 = 0.0 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
274 double possibleRatio = p1 - (p1 - p2) / (0.995 - 0.98) * (time - 0.98);
275 this.offerLowerRatio = max(possibleRatio, this.reservationImportanceRatio + 0.25);
276 } else if (time < 0.999) {
277 // Compromise 3 995 ~ 999 rounds
278 double p1 = 0.0 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
279 double p2 = -0.35 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
280 double possibleRatio = p1 - (p1 - p2) / (0.9989 - 0.995) * (time - 0.995);
281 this.offerLowerRatio = max(possibleRatio, this.reservationImportanceRatio + 0.25);
282 } else {
283 double possibleRatio = -0.4 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
284 this.offerLowerRatio = max(possibleRatio, this.reservationImportanceRatio + 0.2);
285 }
286 this.offerHigherRatio = this.offerLowerRatio + 0.1;
287 }
288
289 /**
290 * Get the ratio of the reservation value to the importance matrix. ASSUMES The
291 * imgMap has been initialized.
292 *
293 */
294 private double getReservationRatio() throws IOException {
295 double medianBidRatio = (this.MEDIAN_IMPORTANCE - this.MIN_IMPORTANCE)
296 / (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE);
297 Bid resBid = this.profileint.getProfile().getReservationBid();
298 double resValue = 0.1;
299 if (resBid != null) {
300 resValue = this.impMap.getImportance(resBid);
301 }
302 return resValue * medianBidRatio / 0.5;
303 }
304
305 /**
306 * Get the maximum and minimum importance values and corresponding offers
307 */
308 private void getMaxAndMinBid() {
309 HashMap<String, Value> lValues1 = new HashMap<>();
310 HashMap<String, Value> lValues2 = new HashMap<>();
311 for (Map.Entry<String, List<impUnit>> entry : this.impMap.entrySet()) {
312 Value value1 = entry.getValue().get(0).valueOfIssue;
313 Value value2 = entry.getValue().get(entry.getValue().size() - 1).valueOfIssue;
314 String issue = entry.getKey();
315 lValues1.put(issue, value1);
316 lValues2.put(issue, value2);
317 }
318 this.MAX_IMPORTANCE_BID = new Bid(lValues1);
319 this.MIN_IMPORTANCE_BID = new Bid(lValues2);
320 this.MAX_IMPORTANCE = this.impMap.getImportance(this.MAX_IMPORTANCE_BID);
321 this.MIN_IMPORTANCE = this.impMap.getImportance(this.MIN_IMPORTANCE_BID);
322 }
323
324 /**
325 * Get the import value corresponding to the median bid in bid ranking
326 *
327 * @param orderedbids a list of bids, ordered from low to high utility.
328 */
329 private void getMedianBid(List<Bid> orderedbids) {
330
331 int median = (orderedbids.size() - 1) / 2;
332 int median2 = -1;
333 if (orderedbids.size() % 2 == 0) {
334 median2 = median + 1;
335 }
336 int current = 0;
337 for (Bid bid : orderedbids) {
338 current += 1;
339 if (current == median) {
340 this.MEDIAN_IMPORTANCE = this.impMap.getImportance(bid);
341 if (median2 == -1)
342 break;
343 }
344 if (current == median2) {
345 this.MEDIAN_IMPORTANCE += this.impMap.getImportance(bid);
346 break;
347 }
348 }
349 if (median2 != -1)
350 this.MEDIAN_IMPORTANCE /= 2;
351 }
352
353// /**
354// * 更新对手的最大及最小Importance的值及对应OFFER
355// */
356// private void getOpponentMaxAndMinBid() {
357// HashMap<Integer, Value> lValues1 = new HashMap<>();
358// HashMap<Integer, Value> lValues2 = new HashMap<>();
359// for (Map.Entry<Issue, List<impUnit>> entry : this.opponentImpMap.entrySet()) {
360// Value value1 = entry.getValue().get(0).valueOfIssue;
361// Value value2 = entry.getValue().get(entry.getValue().size() - 1).valueOfIssue;
362// int issueNumber = entry.getKey().getNumber();
363// lValues1.put(issueNumber, value1);
364// lValues2.put(issueNumber, value2);
365// }
366// Bid OPPONENT_MAX_IMPORTANCE_BID = new Bid(this.getDomain(), lValues1);
367// Bid OPPONENT_MIN_IMPORTANCE_BID = new Bid(this.getDomain(), lValues2);
368// this.OPPONENT_MAX_IMPORTANCE = this.opponentImpMap.getImportance(OPPONENT_MAX_IMPORTANCE_BID);
369// this.OPPONENT_MIN_IMPORTANCE = this.opponentImpMap.getImportance(OPPONENT_MIN_IMPORTANCE_BID);
370// }
371
372 /**
373 * Get eligible random bids. Generate k bids randomly, select bids within the
374 * threshold range, and return the bid with the highest opponent import.
375 *
376 * @param lowerRatio Generate a lower limit for the random bid
377 * @param upperRatio Generate random bid upper limit
378 * @return Bid
379 * @throws IOException
380 */
381 private Bid getNeededRandomBid(double lowerRatio, double upperRatio) {
382 final long k = 2 * this.allbids.size().longValue();
383 double lowerThreshold = lowerRatio * (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE) + this.MIN_IMPORTANCE;
384 double upperThreshold = upperRatio * (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE) + this.MIN_IMPORTANCE;
385
386 for (int t = 0; t < 3; t++) {
387 double highest_opponent_importance = 0.0;
388 Bid returnedBid = null;
389 for (int i = 0; i < k; i++) {
390 Bid bid = generateRandomBid();
391 double bidImportance = this.impMap.getImportance(bid);
392 double bidOpponentImportance = this.opponentImpMap.getImportance(bid);
393 if (bidImportance >= lowerThreshold && bidImportance <= upperThreshold) {
394 if (this.offerRandomly)
395 return bid; // Randomly bid for the first 0.2 time
396 if (bidOpponentImportance > highest_opponent_importance) {
397 highest_opponent_importance = bidOpponentImportance;
398 returnedBid = bid;
399 }
400 }
401 }
402 if (returnedBid != null) {
403 return returnedBid;
404 }
405 }
406 // If something goes wrong and no suitable bid is found, then a higher
407 // than the lower limit
408 while (true) {
409 Bid bid = generateRandomBid();
410 if (this.impMap.getImportance(bid) >= lowerThreshold) {
411 return bid;
412 }
413 }
414 }
415
416 private Bid generateRandomBid() {
417 return allbids.get(rand.nextInt(allbids.size().intValue()));
418 }
419
420}
Note: See TracBrowser for help on using the repository browser.