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

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

#5 fix supported profile type

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