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

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

#3 agentkt updated

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