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

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

#1910 added anac2020 parties

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