source: anac2020/BlingBling/src/main/java/geniusweb/blingbling/Blingbling.java@ 60

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

#5 tune getCapabilities

File size: 19.3 KB
Line 
1package geniusweb.blingbling;
2
3//import java.awt.List;
4import java.io.IOException;
5import java.math.BigInteger;
6import java.util.ArrayList;
7import java.util.Arrays;
8import java.util.Collections;
9import java.util.Comparator;
10import java.util.HashMap;
11import java.util.HashSet;
12import java.util.List;
13import java.util.Random;
14import java.util.logging.Level;
15
16import geniusweb.actions.Accept;
17import geniusweb.actions.Action;
18import geniusweb.actions.Comparison;
19import geniusweb.actions.ElicitComparison;
20import geniusweb.actions.Offer;
21import geniusweb.actions.PartyId;
22import geniusweb.bidspace.AllBidsList;
23import geniusweb.inform.ActionDone;
24import geniusweb.inform.Finished;
25import geniusweb.inform.Inform;
26import geniusweb.inform.Settings;
27import geniusweb.inform.YourTurn;
28import geniusweb.issuevalue.Bid;
29import geniusweb.issuevalue.Value;
30import geniusweb.party.Capabilities;
31import geniusweb.party.DefaultParty;
32import geniusweb.profile.DefaultPartialOrdering;
33import geniusweb.profile.PartialOrdering;
34import geniusweb.profileconnection.ProfileConnectionFactory;
35import geniusweb.profileconnection.ProfileInterface;
36import geniusweb.progress.ProgressRounds;
37import tudelft.utilities.logging.Reporter;
38
39/**
40 * A simple implementation of a SHAOP party that can handle only bilateral
41 * negotiations (1 other party). It will ignore all other parties except the one
42 * that has the turn right before us. It estimates the utilities of bids by
43 * assigning a linear increasing utility from the orderings that have been
44 * created.
45 * <p>
46 * <b>Requirement<b> the initial {@link PartialOrdering} must contain at least
47 * the bids with lowest utility and highest utility, and the proper comparison
48 * info for these two bids.
49 */
50public class Blingbling extends DefaultParty {
51
52// private static final BigDecimal N09 = new BigDecimal("0.9");
53 private Bid nowReceivedBid = null; // we ignore all others
54 private Bid lastReceivedBid = null; // the bid received in the last round.
55 private PartyId me;
56 private final Random random = new Random();
57 protected ProfileInterface profileint; // the preference profile
58 private ProgressRounds progress;
59 private MyProfile myProfile;
60 private OpponentProfile oppProfile;
61 private Boolean startRecord = false;
62
63 private HashMap<String, Value> fixedZoneValue = new HashMap<>();
64 private List<String> negoZone = new ArrayList<>();
65// private List<Bid> FirstReceivedBidList = null;
66 private AllBidsList allbids = null;
67 private List<Bid> acceptableBids = new ArrayList<>();
68 private List<Bid> elicitlist = new ArrayList<>();
69 private List<Bid> paretoBids = new ArrayList<>();
70
71 private Bid elicitBid = null;
72 // params for training
73 private double LearningRate = 0.01;
74 private int Epoch = 40;
75 // params for elicit
76 private double elicitthreshold = 0.7;// if opputility of bid is above this threshold, then elicit the space.
77 private double elicitcost = 0.01;
78 private int elicitflag = 0;
79 private int elicitcnt = 0;
80 // params for strategy threshold.
81 private double threshold = 1.0;// for generate bid;
82 private double acceptthreshold = 1.0;// to determine acceptable bid.
83 private double estimateNashThreshold = 0.7; // the my utility of estimated nash point
84 private double reservationThreshold;
85 private int rethreshold;// 第一次获得可接受的bid的轮数,获得可接受的threshold之后,则就在该acceptthreshold之上寻找新的bid。
86 // params for opponent modeling.
87// private int opprecordlength = 100;//记录前100个不同的
88// private int recordcnt = 0;
89 // params for estimate nash point.
90 private double maxUtilityOppForMe;// record the my max utility among the opponent bid
91 private double nashratio = 1.7;// determine the shape of the pareto frontier.
92// private int nashrecordlength = 20;
93// private int nashcnt = 0;
94 // threshold parameter
95 private int exploreRounds = 150; // for opponent modeling and understand the opposition
96 private double exploreStageThreshold = 0.95;
97 private int agreementSearchRounds = 195; // for agreement search, gradually drop to estimate Nash Point.
98// private double concedeRangeRatio = 0.05; // this is for the case that my estimate nash point is not accurate. the ratio between reservation and nash estimate point
99 private double generateRangeSize = 0.01; // a value from 0.1 to 0.2.
100 private double randomlevel = 0.5;
101// private double slope = 0.02;//if we use the slope
102 private int useAllflag = 0;
103
104 public Blingbling() {
105 }
106
107 public Blingbling(Reporter reporter) {
108 super(reporter); // for debugging
109 }
110
111 @Override
112 public void notifyChange(Inform info) {
113 try {
114 if (info instanceof Settings) {// init
115 Settings settings = (Settings) info;
116
117 // params setting
118 if (settings.getParameters().get("lr") != null) {
119 LearningRate = (double) settings.getParameters().get("lr");
120 }
121 if (settings.getParameters().get("epoch") != null) {
122 Epoch = (int) settings.getParameters().get("epoch");
123 }
124 if (settings.getParameters().get("explorernd") != null) {
125 exploreRounds = (int) settings.getParameters().get("explorernd");
126 }
127 if (settings.getParameters().get("explorethreshold") != null) {
128 exploreStageThreshold = (double) settings.getParameters().get("explorethreshold");
129 }
130 if (settings.getParameters().get("agreementrnd") != null) {
131 agreementSearchRounds = (int) settings.getParameters().get("agreementrnd");
132 }
133 if (settings.getParameters().get("concederratio") != null) {
134 exploreStageThreshold = (double) settings.getParameters().get("explorethreshold");
135 }
136 if (settings.getParameters().get("generaterange") != null) {
137 generateRangeSize = (double) settings.getParameters().get("generaterange");
138 }
139
140 if (settings.getParameters().get("elicitthreshold") != null) {
141 elicitthreshold = (double) settings.getParameters().get("elicitthreshold");
142 }
143 if (settings.getParameters().get("elicitationcost") != null) {
144 elicitcost = (double) settings.getParameters().get("elicitationcost");
145 }
146 if (settings.getParameters().get("nashutility") != null) {
147 estimateNashThreshold = (double) settings.getParameters().get("nashutility");
148 }
149 if (settings.getParameters().get("useall") != null) {
150 useAllflag = (int) settings.getParameters().get("useall");
151 }
152 if (settings.getParameters().get("randomlevel") != null) {
153 randomlevel = (int) settings.getParameters().get("randomlevel");
154 }
155 this.profileint = ProfileConnectionFactory.create(settings.getProfile().getURI(), getReporter());
156 this.me = settings.getID();
157 this.progress = (ProgressRounds) settings.getProgress();
158 this.oppProfile = new OpponentProfile(profileint.getProfile().getDomain());// set opponent model
159
160 this.myProfile = new MyProfile(profileint.getProfile(), Epoch, LearningRate);
161
162 allbids = new AllBidsList(myProfile.getDomain());
163
164 } else if (info instanceof ActionDone) { // the relationship bettween ActionDne and Myturn??
165 Action otheract = ((ActionDone) info).getAction();
166 if (otheract instanceof Offer) {
167
168 this.nowReceivedBid = ((Offer) otheract).getBid();
169
170 } else if (otheract instanceof Comparison) {
171 myProfile.update(((Comparison) otheract).getBid(), ((Comparison) otheract).getBetter(),
172 ((Comparison) otheract).getWorse()); // update the estimate profile
173 myTurn();
174 }
175 } else if (info instanceof YourTurn) {
176 myTurn();
177 } else if (info instanceof Finished) {
178 getReporter().log(Level.INFO, "Final ourcome:" + info);
179// getReporter().log(Level.INFO, "Final EstUtility" + myProfile.getRankUtility(((Finished) info).getAgreement()));
180
181 }
182 } catch (Exception e) {
183 throw new RuntimeException("Fail:", e);
184 }
185 }
186
187 @Override
188 public Capabilities getCapabilities() {
189 return new Capabilities(new HashSet<>(Arrays.asList("SAOP", "SHAOP")),
190 Collections.singleton(DefaultPartialOrdering.class));
191 }
192
193 @Override
194 public String getDescription() {
195 return "The Blingbling Agent from TU Delft! A stage based method can be optimized via AUTOML!";
196 }
197
198 /**
199 * Called when it's (still) our turn and we should take some action. Also
200 * Updates the progress if necessary.
201 */
202 private void myTurn() throws IOException {// equals choose action
203 int round = progress.getCurrentRound(); // only support round deadline
204 int tround = progress.getTotalRounds();
205 Action action = null;
206
207 if (myProfile == null) {
208 myProfile = new MyProfile(profileint.getProfile(), Epoch, LearningRate);
209 }
210 if (round <= 7) {
211 myProfile.subtrain(Epoch, LearningRate);
212 }
213 if (nowReceivedBid != null && round <= 2) {
214 oppProfile.registerOffer(nowReceivedBid);// register the first offer
215 }
216
217 if (lastReceivedBid != null && lastReceivedBid != nowReceivedBid) {
218 startRecord = true; // start record from the first different
219 }
220 if (startRecord && round <= exploreRounds) {// if possible the explore rounds could be the result of hyperparam
221 // optimation
222 oppProfile.registerOffer(nowReceivedBid);
223// estimateNashPoint();
224 }
225
226 // update the threshold
227 setThreshold(round, tround);
228
229 // accept or not?
230 if (nowReceivedBid != null) {
231 // then we do the action now, no need to ask user
232 if (isAcceptable(nowReceivedBid, round)) {
233 action = new Accept(me, nowReceivedBid);
234 }
235
236 }
237 // elicit or not?
238 int elicitrnd = 0;
239 if (elicitcost >= 0.05 && elicitcost <= 0.07) {
240 elicitrnd = 1;
241 } else {
242 elicitrnd = (int) (0.05 / elicitcost);
243 }
244
245 if (action == null && round > exploreRounds && elicitcnt < elicitrnd && elicitflag == 0) {// right after the
246 // explore rounds,
247 // we determine
248 // whether to elicit
249 // compare or not.
250 List<Bid> elicitbidlist = myProfile.getElicitBid();// 获取比较的bid, which combined via the values with low
251 // frequency in pairwise data.
252 if (ifElicitComparison(elicitbidlist)) {// determine whether to elicit or not
253 if (useAllflag == 1) {
254 action = new ElicitComparison(me, elicitBid, myProfile.getAllBidlist()); // can compare with all the
255 // bids
256 // myProfile.getBidlist()//compare
257 // with exist bid
258 }
259 if (useAllflag == 0) {
260 action = new ElicitComparison(me, elicitBid, myProfile.getBidlist()); // can compare with all the
261 // bids
262 // myProfile.getBidlist()//compare
263 // with exist bid
264 }
265 elicitcnt++;
266 elicitflag = 1;
267 }
268 }
269 if (elicitflag == 1) {
270 myProfile.subtrain(Epoch, LearningRate);
271 }
272 if (elicitcnt == elicitrnd) {
273 getNash();
274 elicitcnt++;
275 }
276
277 // Otherwise just offer a bid. Note the situation at the accept stage. and last
278 // two rounds.
279 if (action == null && round <= tround - 1) {
280 action = generateNextBid(threshold);
281 }
282 if (action == null && round == tround) {// final round
283 if (myProfile.getRankUtility(nowReceivedBid) > myProfile.getRankUtility(myProfile.getReservationBid())) {
284 action = new Accept(me, nowReceivedBid);
285 }
286 List<Bid> oppbid = getSortedAcceptable(oppProfile.getOppOffers());
287 if (myProfile.getRankUtility(oppbid.get(0)) > myProfile.getRankUtility(myProfile.getReservationBid())) {
288 action = new Offer(me, oppbid.get(0));
289 } else {
290 action = generateNextBid(threshold);// why I don't set it to the reservation value? Because I aim to get
291 // the Nash output.
292 }
293 }
294
295 lastReceivedBid = nowReceivedBid;
296 if (action instanceof Offer) {
297 elicitflag = 0;
298
299 }
300 getConnection().send(action);// report Action
301 progress = progress.advance();
302
303 }
304
305// private void reduceSpace(Bid bid, Domain domain) {
306// //here we only us the first bid, use first N bid and pick the maximum is a better choice.
307// //devide the negotiation space to setzone and negotiation zone. return the issue list of negotiatable zone
308// for (String issue : bid.getIssues()) {
309// if (bid.getValue(issue).toString().equals(bestBid.getValue(issue).toString())){
310// fixedZoneValue.put(issue, bid.getValue(issue));
311// }else {
312// negoZone.add(issue);
313// }
314// }
315// }
316
317 private boolean isAcceptable(Bid bid, int round) {
318 if (round > agreementSearchRounds) {
319 if (myProfile.getRankUtility(bid) >= threshold) {
320 return true;
321 } else {
322 return false;
323 }
324 } else {
325 if (acceptableBids.isEmpty()) {
326 if (myProfile.getRankUtility(bid) >= threshold) {
327 acceptthreshold = threshold;
328 rethreshold = round;
329 acceptableBids.add(bid);
330 threshold = 1.0;// restart from 1.0
331 }
332 return false;
333 } else {
334 if (myProfile.getRankUtility(bid) >= threshold) {
335 return true;
336 }
337 if (myProfile.getRankUtility(bid) >= acceptthreshold) {
338 if (!acceptableBids.contains(bid)) {
339 acceptableBids.add(bid);
340 }
341 }
342 return false;
343 }
344 }
345
346 }
347
348 private boolean ifElicitComparison(List<Bid> inbidlist) {
349 if (inbidlist.isEmpty()) {
350 return false;
351 }
352 // if need elicit comparison. need more discussion.
353 Collections.sort(inbidlist, new Comparator<Bid>() {
354
355 @Override
356 public int compare(Bid b1, Bid b2) {
357 return (oppProfile.getPredOppUtility(b1) >= oppProfile.getPredOppUtility(b2)) ? -1 : 1;
358// return new Double(oppProfile.getPredOppUtility(b1)).compareTo(new Double(oppProfile.getPredOppUtility(b2)));
359 }
360
361 });
362 for (Bid bid : inbidlist) {
363 if (!elicitlist.contains(bid)) {
364 if (oppProfile.getPredOppUtility(bid) >= elicitthreshold) {
365 elicitBid = bid;
366 elicitlist.add(bid);
367 return true;
368 }
369 }
370 }
371
372 return false;
373 }
374
375 private void setThreshold(int round, int totalRound) {
376 // Here we drop the threshold gradually, this will help the search of outcome
377 // space.
378 // pay attention to the boundary case
379 if (acceptableBids.isEmpty()) {// 如果到agreement Stage不空的话,那么已经结束了。
380 if (round < 10) {
381 this.threshold = 0.95;// the first several steps.
382 } else if (round < this.exploreRounds) {
383 this.threshold = (this.exploreRounds - round) * (1.0 - this.exploreStageThreshold)
384 / (this.exploreRounds - 10) + this.exploreStageThreshold;
385 } else if (round <= totalRound - 1) {
386 this.threshold = (totalRound - 1 - round) * (this.exploreStageThreshold - this.estimateNashThreshold)
387 / (totalRound - 1 - this.exploreRounds) + this.estimateNashThreshold;
388 }
389// else if (round <= totalRound-1) {
390// this.threshold = this.concedeRangeRatio*(totalRound - 1 - round) * (this.estimateNashThreshold - this.reservationThreshold)
391// /(totalRound-1-this.agreementSearchRounds) + this.reservationThreshold;
392// }
393
394 } else {
395 this.threshold = Math
396 .min((totalRound - 1 - round) * (1 - this.acceptthreshold) / (totalRound - 1 - this.rethreshold)
397 + this.acceptthreshold, 1.0);// decrease from 1.0. we can also use a slope for this.
398 }
399 }
400
401 private List<Bid> getSortedAcceptable(List<Bid> accbidlist) {// decending order according to myProfile utility
402 List<Bid> temp = accbidlist;
403 Collections.sort(temp, new Comparator<Bid>() {
404
405 @Override
406 public int compare(Bid b1, Bid b2) {
407 return (myProfile.getRankUtility(b1) >= myProfile.getRankUtility(b2)) ? -1 : 1;
408 }
409
410 });
411 return temp;
412 }
413
414 private void estimateNashPoint() {
415 // use the AutoML to determine the ratio? //use two profiles to estimate nash
416 // point.
417 double thisutility = myProfile.getRankUtility(nowReceivedBid);
418 if (thisutility > maxUtilityOppForMe) {
419 maxUtilityOppForMe = thisutility;
420 }
421 estimateNashThreshold = (1 - maxUtilityOppForMe) / nashratio + maxUtilityOppForMe; // is there a better function
422 // to estimate the nash
423 // point utility?
424 }
425
426 private Offer generateParetoNextBid(double generatethreshold) {
427 // update paretoBids
428 getParetoFrontier();
429 Bid candidatebid = null;
430 double distance = 1;
431 for (Bid bid : paretoBids) {
432 if (myProfile.getRankUtility(bid) >= generatethreshold) {
433 double d = myProfile.getRankUtility(bid) - generatethreshold;
434 if (d < distance) {
435 distance = d;
436 candidatebid = bid;
437 }
438 }
439 }
440 return new Offer(me, candidatebid);
441 }
442
443 private Offer generateNextBid(double generatethreshold) {
444 // return Offer,
445 long spacesize = this.allbids.size().intValue();
446 List<Bid> candidate = new ArrayList<Bid>();
447 List<Bid> candidatebackup = new ArrayList<Bid>();
448 List<Bid> rand = new ArrayList<Bid>();
449 int candidatenum;
450 for (int n = 0; n < spacesize; n++) {
451 Bid bid = allbids.get(BigInteger.valueOf(n));
452 if (myProfile.getRankUtility(bid) >= generatethreshold
453 && myProfile.getRankUtility(bid) < (generatethreshold + generateRangeSize)) {
454 candidate.add(bid);
455 }
456 if (myProfile.getRankUtility(bid) >= generatethreshold) {
457 candidatebackup.add(bid);
458 }
459 }
460
461 // generate random bid to explore? not sure about the performance
462 if (!candidate.isEmpty()) {
463 candidatenum = (int) (Math.floor(candidate.size() * randomlevel) + 1); // 取size的一半。还是全取?
464 for (int i = 0; i < candidatenum; i++) {
465 int temp = random.nextInt(candidate.size());// explore
466 if (!rand.contains(candidate.get(temp))) {
467 rand.add(candidate.get(temp));
468 } else {
469 i--;
470 }
471 }
472 } else {
473 candidatenum = (int) (Math.floor(candidatebackup.size() * randomlevel) + 1); // 取size的一半。还是全取?,can be a
474 // parameter here.
475 for (int i = 0; i < candidatenum; i++) {
476 int temp = random.nextInt(candidatebackup.size());//
477 if (!rand.contains(candidatebackup.get(temp))) {
478 rand.add(candidatebackup.get(temp));
479 } else {
480 i--;// if generate the same, then this should not count in.
481 }
482 }
483 }
484
485 Collections.sort(rand, new Comparator<Bid>() {
486 @Override
487 public int compare(Bid b1, Bid b2) {
488 return oppProfile.getPredOppUtility(b1) >= oppProfile.getPredOppUtility(b2) ? -1 : 1;
489 }
490
491 });
492
493 Bid bid = rand.get(0);// return the maximum utility bid of the opponent
494 if (!acceptableBids.isEmpty()) {
495 acceptableBids = getSortedAcceptable(acceptableBids);
496 if (myProfile.getRankUtility(acceptableBids.get(0)) >= generatethreshold
497 && myProfile.getRankUtility(acceptableBids.get(0)) < (generatethreshold + generateRangeSize)) {
498 bid = acceptableBids.get(0);
499 }
500 }
501
502 return new Offer(me, bid);
503 }
504
505 public void getNash() {// note here we didn't consider the reservation value.
506 if (paretoBids.isEmpty()) {
507 return;
508 }
509 Bid nashbid = null;
510 double maxnashproduct = 0;
511 for (Bid bid : paretoBids) {
512 double nashproduct = myProfile.getRankUtility(bid) * oppProfile.getPredOppUtility(bid);
513 if (nashproduct > maxnashproduct) {
514 nashbid = bid;
515 maxnashproduct = nashproduct;
516 }
517 }
518 if (myProfile.getRankUtility(nashbid) > estimateNashThreshold) {
519 estimateNashThreshold = Math.max(myProfile.getRankUtility(nashbid),
520 myProfile.getRankUtility(myProfile.getReservationBid()));
521 }
522
523 }
524
525 // return the pareto frontier.
526 public void getParetoFrontier() {
527 for (Bid bid : myProfile.getAllBidlist()) {
528 if (paretoBids.isEmpty()) {
529 paretoBids.add(bid);
530 continue;
531 }
532 for (Bid pbid : paretoBids) {
533 if (isDominated(pbid, bid)) {
534 paretoBids.remove(pbid);
535 paretoBids.add(bid);
536 } else {
537 paretoBids.add(bid);
538 }
539 }
540
541 }
542 }
543
544 // bid1 is dominatedby bid2 or not.
545 public boolean isDominated(Bid bid1, Bid bid2) {
546 double bid1_myutility = myProfile.getRankUtility(bid1);
547 double bid1_opputility = oppProfile.getPredOppUtility(bid1);
548 double bid2_myutility = myProfile.getRankUtility(bid2);
549 double bid2_opputility = oppProfile.getPredOppUtility(bid2);
550 if (bid2_myutility >= bid1_myutility && bid2_opputility >= bid1_opputility) {
551 return true;
552 } else {
553 return false;
554 }
555
556 }
557
558}
Note: See TracBrowser for help on using the repository browser.