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

Last change on this file since 19 was 1, checked in by wouter, 4 years ago

#1910 added anac2020 parties

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