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

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

#5 tune getCapabilities

File size: 19.3 KB
RevLine 
[1]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;
[33]12import java.util.List;
[1]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;
[33]23import geniusweb.inform.ActionDone;
24import geniusweb.inform.Finished;
25import geniusweb.inform.Inform;
26import geniusweb.inform.Settings;
27import geniusweb.inform.YourTurn;
[1]28import geniusweb.issuevalue.Bid;
29import geniusweb.issuevalue.Value;
30import geniusweb.party.Capabilities;
31import geniusweb.party.DefaultParty;
[60]32import geniusweb.profile.DefaultPartialOrdering;
[1]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
[33]63 private HashMap<String, Value> fixedZoneValue = new HashMap<>();
[1]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<>();
[33]70
[1]71 private Bid elicitBid = null;
[33]72 // params for training
[1]73 private double LearningRate = 0.01;
74 private int Epoch = 40;
[33]75 // params for elicit
76 private double elicitthreshold = 0.7;// if opputility of bid is above this threshold, then elicit the space.
[1]77 private double elicitcost = 0.01;
78 private int elicitflag = 0;
79 private int elicitcnt = 0;
[33]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
[1]84 private double reservationThreshold;
[33]85 private int rethreshold;// 第一次获得可接受的bid的轮数,获得可接受的threshold之后,则就在该acceptthreshold之上寻找新的bid。
86 // params for opponent modeling.
[1]87// private int opprecordlength = 100;//记录前100个不同的
88// private int recordcnt = 0;
[33]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.
[1]92// private int nashrecordlength = 20;
93// private int nashcnt = 0;
[33]94 // threshold parameter
95 private int exploreRounds = 150; // for opponent modeling and understand the opposition
[1]96 private double exploreStageThreshold = 0.95;
[33]97 private int agreementSearchRounds = 195; // for agreement search, gradually drop to estimate Nash Point.
[1]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
[33]99 private double generateRangeSize = 0.01; // a value from 0.1 to 0.2.
100 private double randomlevel = 0.5;
[1]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 {
[33]114 if (info instanceof Settings) {// init
[1]115 Settings settings = (Settings) info;
[33]116
117 // params setting
118 if (settings.getParameters().get("lr") != null) {
[1]119 LearningRate = (double) settings.getParameters().get("lr");
120 }
[33]121 if (settings.getParameters().get("epoch") != null) {
[1]122 Epoch = (int) settings.getParameters().get("epoch");
123 }
[33]124 if (settings.getParameters().get("explorernd") != null) {
[1]125 exploreRounds = (int) settings.getParameters().get("explorernd");
126 }
[33]127 if (settings.getParameters().get("explorethreshold") != null) {
[1]128 exploreStageThreshold = (double) settings.getParameters().get("explorethreshold");
129 }
[33]130 if (settings.getParameters().get("agreementrnd") != null) {
[1]131 agreementSearchRounds = (int) settings.getParameters().get("agreementrnd");
132 }
[33]133 if (settings.getParameters().get("concederratio") != null) {
[1]134 exploreStageThreshold = (double) settings.getParameters().get("explorethreshold");
135 }
[33]136 if (settings.getParameters().get("generaterange") != null) {
[1]137 generateRangeSize = (double) settings.getParameters().get("generaterange");
138 }
[33]139
140 if (settings.getParameters().get("elicitthreshold") != null) {
[1]141 elicitthreshold = (double) settings.getParameters().get("elicitthreshold");
142 }
[33]143 if (settings.getParameters().get("elicitationcost") != null) {
[1]144 elicitcost = (double) settings.getParameters().get("elicitationcost");
145 }
[33]146 if (settings.getParameters().get("nashutility") != null) {
[1]147 estimateNashThreshold = (double) settings.getParameters().get("nashutility");
148 }
[33]149 if (settings.getParameters().get("useall") != null) {
[1]150 useAllflag = (int) settings.getParameters().get("useall");
151 }
[33]152 if (settings.getParameters().get("randomlevel") != null) {
[1]153 randomlevel = (int) settings.getParameters().get("randomlevel");
154 }
[33]155 this.profileint = ProfileConnectionFactory.create(settings.getProfile().getURI(), getReporter());
[1]156 this.me = settings.getID();
157 this.progress = (ProgressRounds) settings.getProgress();
[33]158 this.oppProfile = new OpponentProfile(profileint.getProfile().getDomain());// set opponent model
[1]159
[33]160 this.myProfile = new MyProfile(profileint.getProfile(), Epoch, LearningRate);
[1]161
[33]162 allbids = new AllBidsList(myProfile.getDomain());
[1]163
[33]164 } else if (info instanceof ActionDone) { // the relationship bettween ActionDne and Myturn??
[1]165 Action otheract = ((ActionDone) info).getAction();
166 if (otheract instanceof Offer) {
[33]167
[1]168 this.nowReceivedBid = ((Offer) otheract).getBid();
[33]169
[1]170 } else if (otheract instanceof Comparison) {
[33]171 myProfile.update(((Comparison) otheract).getBid(), ((Comparison) otheract).getBetter(),
172 ((Comparison) otheract).getWorse()); // update the estimate profile
[1]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()));
[33]180
[1]181 }
182 } catch (Exception e) {
183 throw new RuntimeException("Fail:", e);
184 }
185 }
186
187 @Override
188 public Capabilities getCapabilities() {
[60]189 return new Capabilities(new HashSet<>(Arrays.asList("SAOP", "SHAOP")),
190 Collections.singleton(DefaultPartialOrdering.class));
[1]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 */
[33]202 private void myTurn() throws IOException {// equals choose action
203 int round = progress.getCurrentRound(); // only support round deadline
204 int tround = progress.getTotalRounds();
[1]205 Action action = null;
[33]206
[1]207 if (myProfile == null) {
[33]208 myProfile = new MyProfile(profileint.getProfile(), Epoch, LearningRate);
[1]209 }
[33]210 if (round <= 7) {
[1]211 myProfile.subtrain(Epoch, LearningRate);
212 }
[33]213 if (nowReceivedBid != null && round <= 2) {
214 oppProfile.registerOffer(nowReceivedBid);// register the first offer
[1]215 }
[33]216
217 if (lastReceivedBid != null && lastReceivedBid != nowReceivedBid) {
218 startRecord = true; // start record from the first different
[1]219 }
[33]220 if (startRecord && round <= exploreRounds) {// if possible the explore rounds could be the result of hyperparam
221 // optimation
[1]222 oppProfile.registerOffer(nowReceivedBid);
223// estimateNashPoint();
224 }
[33]225
226 // update the threshold
[1]227 setThreshold(round, tround);
[33]228
229 // accept or not?
[1]230 if (nowReceivedBid != null) {
231 // then we do the action now, no need to ask user
[33]232 if (isAcceptable(nowReceivedBid, round)) {
[1]233 action = new Accept(me, nowReceivedBid);
234 }
235
236 }
[33]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);
[1]243 }
[33]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
[1]258 }
[33]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
[1]264 }
265 elicitcnt++;
[33]266 elicitflag = 1;
[1]267 }
268 }
269 if (elicitflag == 1) {
270 myProfile.subtrain(Epoch, LearningRate);
271 }
[33]272 if (elicitcnt == elicitrnd) {
[1]273 getNash();
274 elicitcnt++;
275 }
276
[33]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) {
[1]280 action = generateNextBid(threshold);
281 }
[33]282 if (action == null && round == tround) {// final round
283 if (myProfile.getRankUtility(nowReceivedBid) > myProfile.getRankUtility(myProfile.getReservationBid())) {
[1]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));
[33]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.
[1]292 }
293 }
[33]294
[1]295 lastReceivedBid = nowReceivedBid;
296 if (action instanceof Offer) {
297 elicitflag = 0;
[33]298
[1]299 }
300 getConnection().send(action);// report Action
301 progress = progress.advance();
302
303 }
[33]304
[1]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// }
[33]316
[1]317 private boolean isAcceptable(Bid bid, int round) {
318 if (round > agreementSearchRounds) {
[33]319 if (myProfile.getRankUtility(bid) >= threshold) {
[1]320 return true;
[33]321 } else {
[1]322 return false;
323 }
[33]324 } else {
[1]325 if (acceptableBids.isEmpty()) {
[33]326 if (myProfile.getRankUtility(bid) >= threshold) {
[1]327 acceptthreshold = threshold;
328 rethreshold = round;
329 acceptableBids.add(bid);
[33]330 threshold = 1.0;// restart from 1.0
[1]331 }
332 return false;
[33]333 } else {
334 if (myProfile.getRankUtility(bid) >= threshold) {
[1]335 return true;
[33]336 }
337 if (myProfile.getRankUtility(bid) >= acceptthreshold) {
[1]338 if (!acceptableBids.contains(bid)) {
339 acceptableBids.add(bid);
[33]340 }
[1]341 }
342 return false;
343 }
344 }
[33]345
[1]346 }
[33]347
[1]348 private boolean ifElicitComparison(List<Bid> inbidlist) {
349 if (inbidlist.isEmpty()) {
350 return false;
351 }
[33]352 // if need elicit comparison. need more discussion.
[1]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 });
[33]362 for (Bid bid : inbidlist) {
[1]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) {
[33]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不空的话,那么已经结束了。
[1]380 if (round < 10) {
[33]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;
[1]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// }
[33]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.
[1]398 }
399 }
[33]400
401 private List<Bid> getSortedAcceptable(List<Bid> accbidlist) {// decending order according to myProfile utility
[1]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 }
[33]413
[1]414 private void estimateNashPoint() {
[33]415 // use the AutoML to determine the ratio? //use two profiles to estimate nash
416 // point.
[1]417 double thisutility = myProfile.getRankUtility(nowReceivedBid);
[33]418 if (thisutility > maxUtilityOppForMe) {
[1]419 maxUtilityOppForMe = thisutility;
420 }
[33]421 estimateNashThreshold = (1 - maxUtilityOppForMe) / nashratio + maxUtilityOppForMe; // is there a better function
422 // to estimate the nash
423 // point utility?
[1]424 }
[33]425
[1]426 private Offer generateParetoNextBid(double generatethreshold) {
[33]427 // update paretoBids
[1]428 getParetoFrontier();
[33]429 Bid candidatebid = null;
[1]430 double distance = 1;
[33]431 for (Bid bid : paretoBids) {
432 if (myProfile.getRankUtility(bid) >= generatethreshold) {
[1]433 double d = myProfile.getRankUtility(bid) - generatethreshold;
[33]434 if (d < distance) {
[1]435 distance = d;
436 candidatebid = bid;
437 }
438 }
439 }
440 return new Offer(me, candidatebid);
441 }
[33]442
[1]443 private Offer generateNextBid(double generatethreshold) {
[33]444 // return Offer,
[1]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;
[33]450 for (int n = 0; n < spacesize; n++) {
[1]451 Bid bid = allbids.get(BigInteger.valueOf(n));
[33]452 if (myProfile.getRankUtility(bid) >= generatethreshold
453 && myProfile.getRankUtility(bid) < (generatethreshold + generateRangeSize)) {
[1]454 candidate.add(bid);
455 }
[33]456 if (myProfile.getRankUtility(bid) >= generatethreshold) {
[1]457 candidatebackup.add(bid);
458 }
459 }
460
[33]461 // generate random bid to explore? not sure about the performance
[1]462 if (!candidate.isEmpty()) {
[33]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
[1]466 if (!rand.contains(candidate.get(temp))) {
467 rand.add(candidate.get(temp));
[33]468 } else {
[1]469 i--;
470 }
471 }
[33]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());//
[1]477 if (!rand.contains(candidatebackup.get(temp))) {
[33]478 rand.add(candidatebackup.get(temp));
479 } else {
480 i--;// if generate the same, then this should not count in.
[1]481 }
[33]482 }
[1]483 }
[33]484
[1]485 Collections.sort(rand, new Comparator<Bid>() {
486 @Override
487 public int compare(Bid b1, Bid b2) {
[33]488 return oppProfile.getPredOppUtility(b1) >= oppProfile.getPredOppUtility(b2) ? -1 : 1;
[1]489 }
490
491 });
492
[33]493 Bid bid = rand.get(0);// return the maximum utility bid of the opponent
[1]494 if (!acceptableBids.isEmpty()) {
495 acceptableBids = getSortedAcceptable(acceptableBids);
[33]496 if (myProfile.getRankUtility(acceptableBids.get(0)) >= generatethreshold
497 && myProfile.getRankUtility(acceptableBids.get(0)) < (generatethreshold + generateRangeSize)) {
[1]498 bid = acceptableBids.get(0);
499 }
500 }
501
502 return new Offer(me, bid);
503 }
[33]504
505 public void getNash() {// note here we didn't consider the reservation value.
[1]506 if (paretoBids.isEmpty()) {
507 return;
508 }
509 Bid nashbid = null;
510 double maxnashproduct = 0;
[33]511 for (Bid bid : paretoBids) {
[1]512 double nashproduct = myProfile.getRankUtility(bid) * oppProfile.getPredOppUtility(bid);
[33]513 if (nashproduct > maxnashproduct) {
[1]514 nashbid = bid;
515 maxnashproduct = nashproduct;
516 }
517 }
[33]518 if (myProfile.getRankUtility(nashbid) > estimateNashThreshold) {
519 estimateNashThreshold = Math.max(myProfile.getRankUtility(nashbid),
520 myProfile.getRankUtility(myProfile.getReservationBid()));
[1]521 }
[33]522
[1]523 }
[33]524
525 // return the pareto frontier.
526 public void getParetoFrontier() {
527 for (Bid bid : myProfile.getAllBidlist()) {
[1]528 if (paretoBids.isEmpty()) {
529 paretoBids.add(bid);
530 continue;
531 }
[33]532 for (Bid pbid : paretoBids) {
[1]533 if (isDominated(pbid, bid)) {
534 paretoBids.remove(pbid);
535 paretoBids.add(bid);
[33]536 } else {
[1]537 paretoBids.add(bid);
538 }
539 }
[33]540
[1]541 }
542 }
[33]543
544 // bid1 is dominatedby bid2 or not.
[1]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);
[33]550 if (bid2_myutility >= bid1_myutility && bid2_opputility >= bid1_opputility) {
[1]551 return true;
[33]552 } else {
[1]553 return false;
554 }
[33]555
[1]556 }
557
558}
Note: See TracBrowser for help on using the repository browser.