source: anac2020/agentxx/src/main/java/geniusweb/exampleparties/newagentgg/NewAgentGG.java@ 24

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

#3

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