source: anac2020/agentP1DAMO/src/main/java/geniusweb/exampleparties/agentgg/agentp1damo/AgentP1DAMO.java

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

#3

File size: 14.8 KB
Line 
1package geniusweb.exampleparties.agentgg.agentp1damo;
2
3import static java.lang.Math.max;
4import static java.util.stream.Collectors.toList;
5
6import java.io.IOException;
7import java.util.Arrays;
8import java.util.Collections;
9import java.util.HashMap;
10import java.util.HashSet;
11import java.util.List;
12import java.util.Map;
13import java.util.Random;
14import java.util.logging.Level;
15import java.util.stream.IntStream;
16
17import javax.websocket.DeploymentException;
18
19import geniusweb.actions.Accept;
20import geniusweb.actions.Action;
21import geniusweb.actions.Comparison;
22import geniusweb.actions.ElicitComparison;
23import geniusweb.actions.Offer;
24import geniusweb.actions.PartyId;
25import geniusweb.bidspace.AllBidsList;
26import geniusweb.inform.ActionDone;
27import geniusweb.inform.Finished;
28import geniusweb.inform.Inform;
29import geniusweb.inform.Settings;
30import geniusweb.inform.YourTurn;
31import geniusweb.issuevalue.Bid;
32import geniusweb.issuevalue.Value;
33import geniusweb.party.Capabilities;
34import geniusweb.party.DefaultParty;
35import geniusweb.profile.PartialOrdering;
36import geniusweb.profile.Profile;
37import geniusweb.profileconnection.ProfileConnectionFactory;
38import geniusweb.profileconnection.ProfileInterface;
39import geniusweb.progress.Progress;
40import geniusweb.progress.ProgressRounds;
41import tudelft.utilities.logging.Reporter;
42
43public class AgentP1DAMO extends DefaultParty {
44 private SimpleLinearOrdering estimatedProfile = null;
45 private HillClimbing hillClimbing;
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 private Settings settings;
74 private FitnessBid fitnessFunction;
75 private SearchSpaceBid localSearchSpace;
76 private double elicitationCost;
77 private boolean shouldCall;
78 private double numOfCalling;
79
80 public AgentP1DAMO() {
81 super();
82 }
83
84 public AgentP1DAMO(Reporter reporter) {
85 super(reporter);
86 }
87
88 @Override
89 public void notifyChange(Inform info) {
90 try {
91 if (info instanceof Settings) {
92 init((Settings) info);
93 } else if (info instanceof ActionDone) {
94 lastReceivedAction = ((ActionDone) info).getAction();
95 if (lastReceivedAction instanceof Comparison) {
96 estimatedProfile = estimatedProfile.with(((Comparison) lastReceivedAction).getBid(),
97 ((Comparison) lastReceivedAction).getWorse());
98 this.impMap.self_update(estimatedProfile.getBids());
99 allbids = new AllBidsList(estimatedProfile.getDomain());
100 Action action = chooseAction();
101 getConnection().send(action);
102 if (progress instanceof ProgressRounds) {
103 progress = ((ProgressRounds) progress).advance();
104 }
105 }
106 if (lastReceivedAction instanceof Offer) {
107 this.receivedBid = ((Offer) lastReceivedAction).getBid();
108 }
109 } else if (info instanceof YourTurn) {
110 Action action = chooseAction();
111 getConnection().send(action);
112 if (progress instanceof ProgressRounds) {
113 progress = ((ProgressRounds) progress).advance();
114 }
115 } else if (info instanceof Finished) {
116 getReporter().log(Level.INFO, "Final ourcome:" + info);
117 }
118 } catch (Exception e) {
119 throw new RuntimeException("Failed to handle info", e);
120 }
121 }
122
123 @Override
124 public Capabilities getCapabilities() {
125 return new Capabilities(new HashSet<>(Arrays.asList("SHAOP")), Collections.singleton(Profile.class));
126 }
127
128 @Override
129 public String getDescription() {
130 return "ANAC 2020 - best agent ever. ";
131 }
132
133 /***************
134 * private
135 *
136 * @throws DeploymentException
137 *********************/
138
139 private void init(Settings info) throws IOException, DeploymentException {
140 this.shouldCall = true;
141 this.numOfCalling = 0;
142 this.settings = info;
143 this.me = info.getID();
144 this.progress = info.getProgress();
145
146 this.profileint = ProfileConnectionFactory.create(info.getProfile().getURI(), getReporter());
147
148 Object cost = info.getParameters().get("elicitationcost");
149 if (!(cost instanceof Double)) {
150 elicitationCost = 0.01;
151 } else {
152 elicitationCost = (double) cost;
153 }
154
155 PartialOrdering partialprofile = (PartialOrdering) profileint.getProfile();
156 allbids = new AllBidsList(partialprofile.getDomain());
157 if (estimatedProfile == null) {
158 try {
159 estimatedProfile = new SimpleLinearOrdering(profileint.getProfile());
160 } catch (IOException e) {
161 System.out.println(e);
162 }
163 }
164 hillClimbing = new HillClimbing(2, 1, rand.nextInt());
165 fitnessFunction = new FitnessBid(estimatedProfile);
166 localSearchSpace = new SearchSpaceBid(getBids(), 2);
167
168 this.impMap = new ImpMap(partialprofile);
169 // and opponent's value map. CHECK why is the opponent map not initially
170 // empty?
171 this.opponentImpMap = new ImpMap(partialprofile);
172
173 // Wouter we use SimpleLinearOrdering (from shaop party) to get sorted
174 // bids from our profile.
175 List<Bid> orderedbids = new SimpleLinearOrdering(profileint.getProfile()).getBids();
176
177 // Update my importance map
178 this.impMap.self_update(orderedbids);
179
180 // Get maximum, minimum, median bid
181 this.getMaxAndMinBid();
182 this.getMedianBid(orderedbids);
183
184 // Get the reservation value, converted to the percentage of importance
185 this.reservationImportanceRatio = this.getReservationRatio();
186
187 getReporter().log(Level.INFO, "reservation ratio: " + this.reservationImportanceRatio);
188 getReporter().log(Level.INFO, "my max importance bid: " + this.MAX_IMPORTANCE_BID);
189 getReporter().log(Level.INFO, "my max importance: " + this.MAX_IMPORTANCE);
190 getReporter().log(Level.INFO, "my min importance bid: " + this.MIN_IMPORTANCE_BID);
191 getReporter().log(Level.INFO, "my min importance: " + this.MIN_IMPORTANCE);
192 getReporter().log(Level.INFO, "my median importance: " + this.MEDIAN_IMPORTANCE);
193 getReporter().log(Level.INFO, "Party " + me + " has finished initialization");
194 }
195
196 private Action chooseAction() {
197 double time = progress.get(System.currentTimeMillis());
198
199 // Start competition
200 if (!(this.lastReceivedAction instanceof Offer))
201 return new Offer(me, this.MAX_IMPORTANCE_BID);
202
203 // The ratio of the other party's offer to me
204 double impRatioForMe = (this.impMap.getImportance(this.receivedBid) - this.MIN_IMPORTANCE)
205 / (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE);
206
207 // Accept the terms of the offer, which is higher than my threshold
208 if (impRatioForMe >= this.offerLowerRatio) {
209 getReporter().log(Level.INFO, "\n\naccepted agent: Agent" + me);
210 getReporter().log(Level.INFO, "last bid: " + this.receivedBid);
211 getReporter().log(Level.INFO, "\ncurrent threshold: " + this.offerLowerRatio);
212 getReporter().log(Level.INFO, "\n\n");
213 return new Accept(me, this.receivedBid);
214 }
215
216 // When the opponent's importance is around 1.0, how much can he get.
217 // Finding the endpoints of the Pareto boundary
218 if (!maxOppoBidImpForMeGot)
219 this.getMaxOppoBidImpForMe(time, 3.0 / 1000.0);
220
221 // Update opponent importance table
222 if (time < 0.3)
223 this.opponentImpMap.opponent_update(this.receivedBid);
224
225 // Strategy
226 this.getThreshold(time);
227
228 // Last round
229 if (time >= 0.9989) {
230 double ratio = (this.impMap.getImportance(this.receivedBid) - this.MIN_IMPORTANCE)
231 / (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE);
232 if (ratio > this.reservationImportanceRatio + 0.2) {
233 return new Accept(me, receivedBid);
234 }
235 }
236
237 getReporter().log(Level.INFO, "high threshold: " + this.offerHigherRatio);
238 getReporter().log(Level.INFO, "low threshold: " + this.offerLowerRatio);
239 getReporter().log(Level.INFO, "estimated nash: " + this.estimatedNashPoint);
240 getReporter().log(Level.INFO, "reservation: " + this.reservationImportanceRatio);
241
242 if (shouldCallElicitation(time)) {
243 if (this.lastReceivedBid != null)
244 return new ElicitComparison(me, lastReceivedBid, estimatedProfile.getBids());
245 }
246
247 Bid bid = getOptimizeBid();
248 this.lastReceivedBid = this.receivedBid;
249 return new Offer(me, bid);
250
251 }
252
253 private boolean shouldCallElicitation(double time) {
254 if (numOfCalling < 10 || rand.nextDouble() < Math.exp(-elicitationCost)) {
255 numOfCalling++;
256 return rand.nextDouble() < Math.exp(-time);
257 }
258 return false;
259 }
260
261 /**
262 * Get our optimal value (Pareto optimal boundary point) when the utility of the
263 * other party is around 1.0 The opponent may first report the same bid several
264 * times, ignore it, and start timing at different times. For durations (such as
265 * 20 rounds), choose the bid with the highest importance for me. Since the bid
266 * of the other party must be very important to the other party at this time, it
267 * can meet our requirements.
268 */
269 private void getMaxOppoBidImpForMe(double time, double timeLast) {
270 double thisBidImp = this.impMap.getImportance(this.receivedBid);
271 if (thisBidImp > this.maxOppoBidImpForMe)
272 this.maxOppoBidImpForMe = thisBidImp;
273
274 if (this.initialTimePass) {
275 if (time - this.startTime > timeLast) {
276 double maxOppoBidRatioForMe = (this.maxOppoBidImpForMe - this.MIN_IMPORTANCE)
277 / (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE);
278 this.estimatedNashPoint = (1 - maxOppoBidRatioForMe) / 1.7 + maxOppoBidRatioForMe; // 1.414 是圆,2是直线
279 this.maxOppoBidImpForMeGot = true;
280 }
281 } else {
282 if (this.lastReceivedBid != this.receivedBid) {
283 this.initialTimePass = true;
284 this.startTime = time;
285 }
286 }
287 }
288
289 /**
290 * Get upper and lower thresholds based on time
291 */
292 private void getThreshold(double time) {
293 if (time < 0.01) {
294 // The first 10 rounds of 0.9999, in order to adapt to some special
295 // domains
296 this.offerLowerRatio = 0.9999;
297 } else if (time < 0.02) {
298 // 10 ~ 20 rounds of 0.99, in order to adapt to some special domains
299 this.offerLowerRatio = 0.99;
300 } else if (time < 0.2) {
301 // 20 ~ 200 rounds reported high price, dropped to 0.9
302 this.offerLowerRatio = 0.99 - 0.5 * (time - 0.02);
303 } else if (time < 0.5) {
304 this.offerRandomly = false;
305 // 200 ~ 500 rounds gradually reduce the threshold to 0.5 from the
306 // estimated Nash point
307 double p2 = 0.3 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
308 this.offerLowerRatio = 0.9 - (0.9 - p2) / (0.5 - 0.2) * (time - 0.2);
309 } else if (time < 0.9) {
310 // 500 ~ 900 rounds quickly decrease the threshold to 0.2 from the
311 // estimated Nash point
312 double p1 = 0.3 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
313 double p2 = 0.15 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
314 this.offerLowerRatio = p1 - (p1 - p2) / (0.9 - 0.5) * (time - 0.5);
315 } else if (time < 0.98) {
316 // Compromise 1
317 double p1 = 0.15 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
318 double p2 = 0.05 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
319 double possibleRatio = p1 - (p1 - p2) / (0.98 - 0.9) * (time - 0.9);
320 this.offerLowerRatio = max(possibleRatio, this.reservationImportanceRatio + 0.3);
321 } else if (time < 0.995) {
322 // Compromise 2 980 ~ 995 rounds
323 double p1 = 0.05 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
324 double p2 = 0.0 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
325 double possibleRatio = p1 - (p1 - p2) / (0.995 - 0.98) * (time - 0.98);
326 this.offerLowerRatio = max(possibleRatio, this.reservationImportanceRatio + 0.25);
327 } else if (time < 0.999) {
328 // Compromise 3 995 ~ 999 rounds
329 double p1 = 0.0 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
330 double p2 = -0.35 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
331 double possibleRatio = p1 - (p1 - p2) / (0.9989 - 0.995) * (time - 0.995);
332 this.offerLowerRatio = max(possibleRatio, this.reservationImportanceRatio + 0.25);
333 } else {
334 double possibleRatio = -0.4 * (1 - this.estimatedNashPoint) + this.estimatedNashPoint;
335 this.offerLowerRatio = max(possibleRatio, this.reservationImportanceRatio + 0.2);
336 }
337 this.offerHigherRatio = this.offerLowerRatio + 0.1;
338 }
339
340 /**
341 * Get the ratio of the reservation value to the importance matrix. ASSUMES The
342 * imgMap has been initialized.
343 */
344 private double getReservationRatio() throws IOException {
345 double medianBidRatio = (this.MEDIAN_IMPORTANCE - this.MIN_IMPORTANCE)
346 / (this.MAX_IMPORTANCE - this.MIN_IMPORTANCE);
347 Bid resBid = this.profileint.getProfile().getReservationBid();
348 double resValue = 0.1;
349 if (resBid != null) {
350 resValue = this.impMap.getImportance(resBid);
351 }
352 return resValue * medianBidRatio / 0.5;
353 }
354
355 /**
356 * Get the maximum and minimum importance values and corresponding offers
357 */
358 private void getMaxAndMinBid() {
359 HashMap<String, Value> lValues1 = new HashMap<>();
360 HashMap<String, Value> lValues2 = new HashMap<>();
361 for (Map.Entry<String, List<impUnit>> entry : this.impMap.entrySet()) {
362 Value value1 = entry.getValue().get(0).valueOfIssue;
363 Value value2 = entry.getValue().get(entry.getValue().size() - 1).valueOfIssue;
364 String issue = entry.getKey();
365 lValues1.put(issue, value1);
366 lValues2.put(issue, value2);
367 }
368 this.MAX_IMPORTANCE_BID = new Bid(lValues1);
369 this.MIN_IMPORTANCE_BID = new Bid(lValues2);
370 this.MAX_IMPORTANCE = this.impMap.getImportance(this.MAX_IMPORTANCE_BID);
371 this.MIN_IMPORTANCE = this.impMap.getImportance(this.MIN_IMPORTANCE_BID);
372 }
373
374 /**
375 * Get the import value corresponding to the median bid in bid ranking
376 *
377 * @param orderedbids a list of bids, ordered from low to high utility.
378 */
379 private void getMedianBid(List<Bid> orderedbids) {
380
381 int median = (orderedbids.size() - 1) / 2;
382 int median2 = -1;
383 if (orderedbids.size() % 2 == 0) {
384 median2 = median + 1;
385 }
386 int current = 0;
387 for (Bid bid : orderedbids) {
388 current += 1;
389 if (current == median) {
390 this.MEDIAN_IMPORTANCE = this.impMap.getImportance(bid);
391 if (median2 == -1)
392 break;
393 }
394 if (current == median2) {
395 this.MEDIAN_IMPORTANCE += this.impMap.getImportance(bid);
396 break;
397 }
398 }
399 if (median2 != -1)
400 this.MEDIAN_IMPORTANCE /= 2;
401 }
402
403 private Bid getOptimizeBid() {
404 return hillClimbing.search(fitnessFunction, localSearchSpace, estimatedProfile, allbids);
405 }
406
407 private List<Bid> getBids() {
408 return IntStream.range(0, allbids.size().intValue()).mapToObj(i -> allbids.get(i)).collect(toList());
409 }
410
411}
Note: See TracBrowser for help on using the repository browser.