source: anac2020/agentKT/src/main/java/geniusweb/exampleparties/simpleshaop/ShaopParty.java@ 14

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

#1910 added anac2020 parties

File size: 14.6 KB
Line 
1package geniusweb.exampleparties.simpleshaop;
2
3import java.io.IOException;
4import java.math.BigDecimal;
5import java.util.ArrayList;
6import java.util.Arrays;
7import java.util.HashMap;
8import java.util.HashSet;
9import java.util.List;
10import java.util.Random;
11import java.util.Set;
12import java.util.logging.Level;
13
14import geniusweb.actions.Accept;
15import geniusweb.actions.Action;
16import geniusweb.actions.Comparison;
17import geniusweb.actions.ElicitComparison;
18import geniusweb.actions.EndNegotiation;
19import geniusweb.actions.Offer;
20import geniusweb.actions.PartyId;
21import geniusweb.issuevalue.Bid;
22import geniusweb.issuevalue.Value;
23import geniusweb.party.Capabilities;
24import geniusweb.party.DefaultParty;
25import geniusweb.party.inform.ActionDone;
26import geniusweb.party.inform.Finished;
27import geniusweb.party.inform.Inform;
28import geniusweb.party.inform.Settings;
29import geniusweb.party.inform.YourTurn;
30import geniusweb.profile.PartialOrdering;
31import geniusweb.profileconnection.ProfileConnectionFactory;
32import geniusweb.profileconnection.ProfileInterface;
33import geniusweb.progress.Progress;
34import geniusweb.progress.ProgressRounds;
35import tudelft.utilities.logging.Reporter;
36
37/**
38 * A simple implementation of a SHAOP party that can handle only bilateral
39 * negotiations (1 other party). It will ignore all other parties except the one
40 * that has the turn right before us. It estimates the utilities of bids by
41 * assigning a linear increasing utility from the orderings that have been
42 * created.
43 * <p>
44 * <b>Requirement<b> the initial {@link PartialOrdering} must contain at least
45 * the bids with lowest utility and highest utility, and the proper comparison
46 * info for these two bids.
47 */
48public class ShaopParty extends DefaultParty {
49
50 private Bid lastReceivedBid = null; // we ignore all others
51 private PartyId me;
52 private PartyId sender;
53 private final Random random = new Random();
54 protected ProfileInterface profileint;
55 private Progress progress;
56 private List<String> allIssues;
57
58 private CompRegress compRegress;
59 private SimpleLinearOrdering estProfile = null;
60 private NegotiationInfo negotiationInfo = null;
61
62 private double time;
63 private int totalRounds;
64 private int currentRound;
65
66 private int initElicitPhase;
67 private List<Bid> initOfferedList;
68 private List<Bid> initSentList;
69 private HashMap<Bid, String> indicatorBidMap;
70
71 private Bid maxBid;
72 private Bid minBid;
73 private Bid reserveBid;
74 private Bid myLastBid;
75 private Bid bestJointBid;
76
77 private int offerNum;
78 private int myTurnNum = 0;
79 private int elicitNum = 0;
80 private boolean thruComparison = false;
81
82 public ShaopParty() {
83 }
84
85 public ShaopParty(Reporter reporter) {
86 super(reporter); // for debugging
87 }
88
89 @Override
90 public void notifyChange(Inform info) {
91 try {
92 // Inform was Setting - indicating start of session
93 if (info instanceof Settings) {
94 Settings settings = (Settings) info;
95 this.profileint = ProfileConnectionFactory.
96 create(settings.getProfile().getURI(), getReporter());
97 this.me = settings.getID();
98 this.progress = settings.getProgress();
99 init();
100 }
101 // Inform was ActionDone - informing an agent did an action
102 else if (info instanceof ActionDone) {
103 Action doneact = ((ActionDone) info).getAction();
104 // ActionDone was Offer
105 if (doneact instanceof Offer) {
106 offerNum += 1;
107 if (myTurnNum == 0) myTurnNum = 2;
108 receivedOffer(doneact);
109 lastReceivedBid = ((Offer) doneact).getBid();
110 }
111 // ActionDone was Comparison from our agent
112 else if (doneact instanceof Comparison) {
113 thruComparison = true;
114 estProfile = estProfile.with(((Comparison) doneact).
115 getBid(),((Comparison) doneact).getWorse());
116 if (compRegress != null) {
117 compRegress.fit(estProfile.getBids());
118 negotiationInfo.updateCompRegress(compRegress);
119 }
120 myTurn();
121 }
122 }
123 // Inform was YourTurn - indicating our agent has turn
124 else if (info instanceof YourTurn) {
125 if (myTurnNum == 0) myTurnNum = 1;
126 myTurn();
127 }
128 // Inform was Finished - indicating session finished
129 else if (info instanceof Finished) {
130 getReporter().log(Level.INFO, "Final outcome:" + info);
131 }
132 } catch (Exception e) {
133 throw new RuntimeException("Failed to handle info", e);
134 }
135 }
136
137 @Override
138 public Capabilities getCapabilities() {
139 return new Capabilities(new HashSet<>(Arrays.asList("SHAOP")));
140 }
141
142 @Override
143 public String getDescription() {
144 return "Testing";
145 }
146
147 ////////////////////////////////////////////////////////////////////////////////
148 // initialization methods and its helpers
149 ////////////////////////////////////////////////////////////////////////////////
150
151 /**
152 * initializes parameters
153 * @throws IOException
154 */
155 private void init() throws IOException {
156 Set<String> issues = profileint.getProfile().getDomain().getIssues();
157 this.allIssues = new ArrayList<String>();
158 for (String issue : issues) allIssues.add(issue);
159
160 this.time = 0.0;
161
162 this.offerNum = 0;
163 this.totalRounds = ((ProgressRounds) progress).getTotalRounds();
164
165 this.estProfile = new SimpleLinearOrdering(profileint.getProfile());
166
167 this.maxBid = estProfile.maxBid();
168 this.minBid = estProfile.minBid();
169 this.reserveBid = profileint.getProfile().getReservationBid();
170
171 this.initElicitPhase = allIssues.size();
172 this.indicatorBidMap = new HashMap<Bid, String>();
173 this.initOfferedList = new ArrayList<Bid>();
174 this.initSentList = new ArrayList<Bid>();
175 }
176
177 /**
178 * the round of elicitations for bids that have one issue that has min
179 * utility, all others with max utility
180 * @param index
181 * @throws IOException
182 */
183 private Action initElicit(int index) throws IOException {
184 initElicitPhase--;
185 if (index > 0) {
186 String issue = allIssues.get(index - 1);
187 Value minValue = minBid.getValue(issue);
188 Bid indicatorBid = putValue(maxBid, issue, minValue);
189
190 indicatorBidMap.put(indicatorBid, issue);
191
192 return new ElicitComparison(me, indicatorBid, estProfile.getBids());
193 }
194 else {
195 initCompRegress();
196 return chooseOffer();
197 }
198 }
199
200 /**
201 * initializes the compRegress and negotiationInfo
202 * @param doneact - the action done
203 * @throws IOException
204 */
205 private void initCompRegress() throws IOException{
206 this.compRegress = new CompRegress(profileint.getProfile(),
207 estProfile.getBids(), indicatorBidMap);
208 this.negotiationInfo = new NegotiationInfo(compRegress);
209
210 negotiationInfo.initOpponent();
211 for (Bid offeredBid : initOfferedList) {
212 negotiationInfo.updateInfo(offeredBid);
213 }
214 for (Bid sentBid : initSentList) {
215 negotiationInfo.updateMyBidHistory(sentBid);
216 }
217 }
218
219
220 /**
221 * replaces one value in a bid with a new value
222 * @param originalBid - the original bid
223 * @param inputIssue - the issue of the value to replace
224 * @param inputValue - the value to replace
225 * @return - the new bid with the replaced value
226 */
227 private Bid putValue(Bid originalBid, String inputIssue, Value inputValue) {
228 Bid modifiedBid = new Bid(inputIssue, inputValue);
229 Set<String> issues = originalBid.getIssues();
230 for (String issue : issues) {
231 if (!issue.equals(inputIssue)) {
232 modifiedBid = modifiedBid.merge(new Bid(issue,
233 originalBid.getValue(issue)));
234 }
235 }
236 return modifiedBid;
237 }
238
239 /**
240 * updates the negotiationInfo when offer received
241 *
242 * @param doneAction - the action done
243 */
244 private void receivedOffer(Action doneAction) {
245 this.sender = ((Offer) doneAction).getActor();
246 Bid offeredBid = ((Offer) doneAction).getBid();
247
248 if (offerNum % 2 != myTurnNum % 2) {
249 if (negotiationInfo == null) {
250 initOfferedList.add(offeredBid);
251 }
252 else {
253 if (sender != null) {
254 try {
255 negotiationInfo.updateInfo(offeredBid);
256 } catch (Exception e) {
257 System.out.println("update negotiationInfo failed");
258 e.printStackTrace();
259 }
260 }
261 }
262 }
263 else {
264 myLastBid = offeredBid;
265 }
266 }
267
268 ////////////////////////////////////////////////////////////////////////////////
269 // myTurn method and its helpers
270 ////////////////////////////////////////////////////////////////////////////////
271
272 /**
273 * decides which action to take on turn
274 * @throws IOException
275 */
276 private void myTurn() throws IOException {
277 time = getCurrentTime();
278 Action action = null;
279
280 // initial phase
281 if (initElicitPhase >= 0) {
282 if (thruComparison) {
283 thruComparison = false;
284 action = new Offer(me, maxBid);
285 //update Progress
286 if (progress instanceof ProgressRounds) {
287 progress = ((ProgressRounds) progress).advance();
288 }
289 }
290 else {
291 action = initElicit(initElicitPhase);
292 }
293 }
294 else if (elicitNum < 3 && !estProfile.contains(myLastBid)) {
295 action = new ElicitComparison(me, myLastBid, estProfile.getBids());
296 elicitNum++;
297 }
298 else {
299 // decide action in final round
300 if (currentRound == totalRounds) {
301 action = chooseFinal();
302 }
303 // decide action during start phase
304 else if (inStartPhase()) {
305 action = chooseStart();
306 }
307 // decide action: Accept
308 else if (selectAccept(lastReceivedBid)) {
309 action = new Accept(me, lastReceivedBid);
310 }
311 // decide action during middle phase
312 else if (inMidPhase()) {
313 action = chooseMid();
314 }
315 // decide action: Offer
316 else {
317 action = chooseOffer();
318 }
319 //update Progress
320 if (progress instanceof ProgressRounds) {
321 progress = ((ProgressRounds) progress).advance();
322 }
323 }
324
325 // send action
326 getConnection().send(action);
327 }
328
329 /**
330 * retrieves the current time as a double
331 * @return the current round number divided by the total number of rounds
332 */
333 private double getCurrentTime() {
334 totalRounds = ((ProgressRounds) progress).getTotalRounds();
335 currentRound = ((ProgressRounds) progress).getCurrentRound() + myTurnNum ;
336
337 if (totalRounds == 0) return 0.0;
338 else return (currentRound * 1.0) / totalRounds;
339 }
340
341 ////////////////////////////////////////////////////////////////////////////////
342 // start phase methods
343 ////////////////////////////////////////////////////////////////////////////////
344
345 /**
346 * determines if the negotiation is in the start phase
347 * @return true if current time satisfies
348 */
349 private boolean inStartPhase() {
350 return time <= 0.5;
351 }
352
353 /**
354 * determines which action to take during start phase
355 * @return an offer action
356 */
357 private Action chooseStart() {
358 BigDecimal threshold = BigDecimal.valueOf(0.95 - time * time * 0.5);
359 List<Bid> highUtilBids = compRegress.getBetterThan(threshold);
360 int i = random.nextInt(highUtilBids.size());
361 Bid randomHighUtilBid = highUtilBids.get(i);
362 randomHighUtilBid = replaceMin(randomHighUtilBid);
363 return new Offer(me, randomHighUtilBid);
364 }
365
366 ////////////////////////////////////////////////////////////////////////////////
367 // middle phase methods
368 ////////////////////////////////////////////////////////////////////////////////
369
370 /**
371 * determines if the negotiation is in the middle phase
372 * @return true if current time satisfies
373 */
374 private boolean inMidPhase() {
375 return time < 0.95;
376 }
377
378 /**
379 * determines which action to take during middle phase
380 * @return an offer action
381 */
382 private Action chooseMid() {
383 BigDecimal initThreshold = BigDecimal.valueOf(0.95 - time * time* 0.5);
384 List<Bid> initHighUtilBids = compRegress.getBetterThan(initThreshold);
385 negotiationInfo.initOpponentProbs();
386 List<Bid> jointOrderedBids = negotiationInfo.getJointPref(initHighUtilBids, time);
387 double jointThreshold = compRegress.getUtil(jointOrderedBids.get(0)).doubleValue();
388 BigDecimal threshold = BigDecimal.valueOf(Math.max(initThreshold.doubleValue(), jointThreshold));
389 List<Bid> highUtilBids = compRegress.getBetterThan(threshold);
390 int i = random.nextInt(highUtilBids.size());
391 Bid randomHighUtilBid = highUtilBids.get(i);
392 randomHighUtilBid = replaceMin(randomHighUtilBid);
393 return new Offer(me, randomHighUtilBid);
394 }
395
396 /**
397 * replace a value in a bid if that value is in minBid
398 * @param bid - the bid to determine whether to replace one of its values
399 * @return a new bid with any min values replaced with a random value
400 */
401 private Bid replaceMin(Bid bid) {
402 Bid newBid = bid;
403 for (String issue : bid.getIssues()) {
404 Value value = bid.getValue(issue);
405 int valueSetSize = compRegress.getValues(issue).size().intValue();
406 if (value == minBid.getValue(issue) && valueSetSize > 2) {
407 int i = random.nextInt(valueSetSize-2);
408 Value newValue = compRegress.randomNonMinMax(issue, i);
409 newBid = putValue(newBid, issue, newValue);
410 }
411 }
412 return newBid;
413 }
414
415 ////////////////////////////////////////////////////////////////////////////////
416 // final round methods
417 ////////////////////////////////////////////////////////////////////////////////
418
419 /**
420 * choose what action to take in final round
421 * @return an action: offer, accept, or end negotiation
422 */
423 private Action chooseFinal() {
424 // went first
425 if (myTurnNum == 1) return new Offer(me, bestJointBid);
426 // went second
427 else if (compRegress.getUtil(lastReceivedBid).
428 compareTo(compRegress.getUtil(reserveBid)) > 0) {
429 return new Accept(me, lastReceivedBid);
430 }
431 else return new EndNegotiation(me);
432 }
433
434 ////////////////////////////////////////////////////////////////////////////////
435 // accept methods
436 ////////////////////////////////////////////////////////////////////////////////
437
438// // selects bid when the estimated utility is greater than 0.75
439// private boolean selectAccept(Bid offeredBid) {
440// if (offeredBid == null) return false;
441// return compRegress.getUtil(offeredBid).compareTo(BigDecimal.
442// valueOf(0.95 - time * time * 0.1)) >= 0;
443// }
444
445 /**
446 * selectAccept method from negotiationStrategy
447 * @param bid - the bid offered
448 * @return true, if decided to accept the offer, false otherwise
449 */
450 private boolean selectAccept(Bid bid) {
451 NegotiationStrategy negotiationStrategy = new NegotiationStrategy(
452 compRegress, negotiationInfo, reserveBid);
453 return negotiationStrategy.selectAccept(bid, BigDecimal.valueOf(time));
454 }
455
456 ////////////////////////////////////////////////////////////////////////////////
457 // offer methods
458 ////////////////////////////////////////////////////////////////////////////////
459
460 /**
461 * chooses offer during the remainder phases based on joint utility
462 * @return an offer action with the best joint bid
463 */
464 private Action chooseOffer() {
465 BigDecimal threshold = BigDecimal.valueOf(0.85 - time*time*0.15);
466 List<Bid> highUtilBids = compRegress.getBetterThan(threshold);
467 negotiationInfo.initOpponentProbs();
468 List<Bid> jointOrderedBids = negotiationInfo.getJointPref(highUtilBids, time);
469 bestJointBid = jointOrderedBids.get(0);
470 return offerBidAction(bestJointBid);
471 }
472
473 /**
474 * updates my bid history and returns offer
475 * @param offerBid - the bid to offer
476 * @return an offer action with the input bid
477 */
478 private Action offerBidAction(Bid offerBid) {
479 negotiationInfo.updateMyBidHistory(offerBid);
480 return new Offer(me, offerBid);
481 }
482}
Note: See TracBrowser for help on using the repository browser.