source: anac2020/ShineAgent/src/main/java/shineagent/ShineParty.java

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

#3

File size: 10.2 KB
Line 
1package shineagent;
2
3import java.io.IOException;
4import java.math.BigInteger;
5import java.util.ArrayList;
6import java.util.Arrays;
7import java.util.Collections;
8import java.util.HashSet;
9import java.util.List;
10import java.util.Map;
11import java.util.Random;
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.Offer;
19import geniusweb.actions.PartyId;
20import geniusweb.bidspace.AllBidsList;
21import geniusweb.inform.ActionDone;
22import geniusweb.inform.Finished;
23import geniusweb.inform.Inform;
24import geniusweb.inform.Settings;
25import geniusweb.inform.YourTurn;
26import geniusweb.issuevalue.Bid;
27import geniusweb.issuevalue.NumberValue;
28import geniusweb.issuevalue.Value;
29import geniusweb.issuevalue.ValueSet;
30import geniusweb.party.Capabilities;
31import geniusweb.party.DefaultParty;
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 * Shine Agent Main Class
41 */
42public class ShineParty extends DefaultParty {
43 private static final double acceptQualityThreshold = 0.85;
44 private static final double acceptQualityThresholdMin = 0.55;
45 private static final double acceptDistanceThreshold = 0.15;
46 private static final double newOfferDistanceThreshold = 0.15;
47 private static final int numberOfTurnsToElicit = 1;
48 private Bid lastReceivedBid = null; // we ignore all others
49 private PartyId me;
50 private final Random random = new Random();
51 protected ProfileInterface profileint;
52 private Progress progress;
53 private SimpleLinearOrdering myEstimatedProfile = null;
54 private SimpleLinearOrdering opponentEstimatedProfile = null;
55 // private IssueCounter opponentIssueCounter = null;
56 private Bid reservationBid = null;
57 private int turnsWithElicitPassed = 0;
58
59 public ShineParty() {
60 }
61
62 public ShineParty(Reporter reporter) {
63 super(reporter); // for debugging
64 }
65
66 @Override
67 public void notifyChange(Inform info) {
68 try {
69 if (info instanceof Settings) {
70 Settings settings = (Settings) info;
71 this.profileint = ProfileConnectionFactory.create(settings.getProfile().getURI(), getReporter());
72 this.me = settings.getID();
73 this.progress = settings.getProgress();
74 } else if (info instanceof ActionDone) {
75 Action otheract = ((ActionDone) info).getAction();
76 if (otheract instanceof Offer) {
77 lastReceivedBid = ((Offer) otheract).getBid();
78 } else if (otheract instanceof Comparison) {
79 myEstimatedProfile = myEstimatedProfile.with(((Comparison) otheract).getBid(),
80 ((Comparison) otheract).getWorse());
81 myTurn();
82 }
83 } else if (info instanceof YourTurn) {
84 myTurn();
85 } else if (info instanceof Finished) {
86 getReporter().log(Level.INFO, "Final ourcome:" + info);
87 }
88 } catch (Exception e) {
89 throw new RuntimeException("Failed to handle info", e);
90 }
91 }
92
93 @Override
94 public Capabilities getCapabilities() {
95 return new Capabilities(new HashSet<>(Arrays.asList("SHAOP")), Collections.singleton(Profile.class));
96 }
97
98 @Override
99 public String getDescription() {
100 return "Shine Agent :)";
101 }
102
103 /**
104 * Called when it's (still) our turn and we should take some action. Also
105 * Updates the progress if necessary.
106 */
107 private void myTurn() throws IOException {
108 Action action = null;
109 if (myEstimatedProfile == null) {
110 myEstimatedProfile = new SimpleLinearOrdering(profileint.getProfile());
111 reservationBid = profileint.getProfile().getReservationBid();
112 }
113
114 if (lastReceivedBid != null) {
115 processOpponentBid(lastReceivedBid);
116 double lastBidQuality = getBidQuality(lastReceivedBid, myEstimatedProfile);
117
118 // then we do the action now, no need to ask user
119 if (myEstimatedProfile.contains(lastReceivedBid)) {
120 if (lastBidQuality >= getBidQuality(reservationBid, myEstimatedProfile)
121 && lastBidQuality >= getCurrentThreshold(acceptQualityThreshold, acceptQualityThresholdMin))
122 action = new Accept(me, lastReceivedBid);
123 } else {
124 // we did not yet assess the received bid
125
126 Bid closestBid = getClosestBid(myEstimatedProfile, lastReceivedBid);
127 if (hammingDistance(closestBid, lastReceivedBid) < acceptDistanceThreshold) {
128 if (getBidQuality(closestBid, myEstimatedProfile) >= getCurrentThreshold(acceptQualityThreshold,
129 acceptQualityThresholdMin))
130 action = new Accept(me, lastReceivedBid);
131 else {
132 action = newOffer();
133 }
134 } else {
135 if (turnsWithElicitPassed >= numberOfTurnsToElicit) {
136 action = new ElicitComparison(me, lastReceivedBid, myEstimatedProfile.getBids());
137
138 turnsWithElicitPassed = 0;
139 } else {
140 ++turnsWithElicitPassed;
141 action = newOffer();
142 }
143
144 }
145 }
146 if (progress instanceof ProgressRounds) {
147 progress = ((ProgressRounds) progress).advance();
148 }
149 }
150
151 if (action == null)
152 action = newOffer();
153
154 getConnection().send(action);
155 }
156
157 private void processOpponentBid(Bid inputBid) throws IOException {
158
159 if (opponentEstimatedProfile == null) {
160 List<Bid> oneBidList = new ArrayList<>();
161 oneBidList.add(inputBid);
162 opponentEstimatedProfile = new SimpleLinearOrdering(profileint.getProfile().getDomain(), oneBidList);
163 }
164
165 /*
166 * if(opponentIssueCounter == null) opponentIssueCounter = new
167 * IssueCounter(profileint.getProfile().getDomain());
168 */
169
170 // Insert new bid to opponent profile & Counter. This assumes all previous bids
171 // are worst, as the opponent learning it's own preferences as well.
172 opponentEstimatedProfile = opponentEstimatedProfile.with(inputBid, opponentEstimatedProfile.getBids());
173 // opponentIssueCounter.addElement(inputBid);
174 }
175
176 private Bid getClosestBid(SimpleLinearOrdering profile, Bid inputBid) throws IOException {
177 Bid closestBid = null;
178 double closestDist = 1.1;
179 for (Bid currBid : profile.getBids()) {
180 if (closestDist > hammingDistance(currBid, inputBid)) {
181 closestBid = currBid;
182 closestDist = hammingDistance(currBid, inputBid);
183 }
184 }
185 return closestBid;
186 }
187
188 private Offer randomBid() throws IOException {
189 AllBidsList bidspace = new AllBidsList(profileint.getProfile().getDomain());
190 long i = random.nextInt(bidspace.size().intValue());
191 Bid bid = bidspace.get(BigInteger.valueOf(i));
192 return new Offer(me, bid);
193 }
194
195 private Offer newOffer() throws IOException {
196 Bid selectedBid = null;
197 double myBidQuality = 0.0;
198 double opponentBidQuality = 0.0;
199 double myBidDistanceToOpponent = 1.0;
200 double myBidScore = 0.0;
201 RandomCollection<Bid> weightedBids = new RandomCollection<>();
202 for (Bid currBid : myEstimatedProfile.getBids()) {
203 myBidQuality = getBidQuality(currBid, myEstimatedProfile);
204
205 // Drop bad offers
206 if (myBidQuality < getBidQuality(reservationBid, myEstimatedProfile)
207 || myBidQuality < getCurrentThreshold(acceptQualityThreshold, acceptQualityThresholdMin))
208 continue;
209
210 if (opponentEstimatedProfile != null) {
211 // Calculate bid score using the opponent profile
212 for (Bid currOpponentBid : opponentEstimatedProfile.getBids()) {
213 myBidDistanceToOpponent = hammingDistance(currBid, currOpponentBid);
214 opponentBidQuality = getBidQuality(currOpponentBid, opponentEstimatedProfile);
215
216 // Drop not similar bids
217 if (myBidDistanceToOpponent > newOfferDistanceThreshold)
218 continue;
219
220 // Weight by opponent quality & distance
221 myBidScore += (1 - myBidDistanceToOpponent) * opponentBidQuality;
222 }
223 }
224
225 // Add a default score good bids with no information in opponent profile
226 if (myBidScore <= 0.0)
227 myBidScore = 0.1;
228
229 // Weight by quality for the party
230 myBidScore = myBidScore * myBidQuality;
231 weightedBids.add(myBidScore, currBid);
232 myBidScore = 0.0;
233 }
234
235 if (weightedBids.isEmpty()) {
236 return new Offer(me, myEstimatedProfile.getBids().get(0));
237 }
238
239 Bid weightedBid = weightedBids.next();
240 AllBidsList allBids = new AllBidsList(myEstimatedProfile.getDomain());
241 List<Bid> similarBids = new ArrayList<Bid>();
242 for (Bid bid : allBids) {
243 if (hammingDistance(bid, weightedBid) >= 0.1)
244 continue;
245
246 similarBids.add(bid);
247 }
248
249 return new Offer(me, similarBids.get(random.nextInt(similarBids.size())));
250 }
251
252 /**
253 * Calculate an index stating how good is this bid to this profile, between 0
254 * (worst) to 1 (best)
255 *
256 * @param bid
257 * @param profile
258 * @return
259 */
260 private double getBidQuality(Bid bid, SimpleLinearOrdering profile) {
261 // TODO: Implement by threshold
262 if (bid == null)
263 return 0.0;
264
265 return profile.getUtility(bid).doubleValue();
266 }
267
268 private double getMinMaxDistance(String issue) throws IOException {
269 ValueSet vs1 = profileint.getProfile().getDomain().getValues(issue);
270 NumberValue minValue = (NumberValue) vs1.get(0);
271 NumberValue maxValue = (NumberValue) vs1.get(1);
272 return (maxValue.getValue().doubleValue() - minValue.getValue().doubleValue());
273 }
274
275 /**
276 * Returns a score between 0 to 1 that determine how much the bids are similar 0
277 * - identical, 1 - totally different
278 *
279 * @param bid1
280 * @param bid2
281 * @return
282 * @throws IOException
283 */
284 private double hammingDistance(Bid bid1, Bid bid2) throws IOException {
285 double similarityIndex = 0.0;
286 for (Map.Entry<String, Value> valueEntry1 : bid1.getIssueValues().entrySet()) {
287 Value value1 = valueEntry1.getValue();
288 Value value2 = bid2.getValue(valueEntry1.getKey());
289
290 // Find out the type of bid value (range or discrete)
291 if (value1 instanceof NumberValue) {
292 double valueDist = Math.abs((((NumberValue) value1).getValue().doubleValue()
293 - ((NumberValue) value2).getValue().doubleValue()));
294 similarityIndex += (valueDist / getMinMaxDistance(valueEntry1.getKey()));
295 } else {
296 if (!valueEntry1.getValue().equals(value2)) {
297 similarityIndex++;
298 }
299 }
300 }
301 return (similarityIndex / bid1.getIssueValues().entrySet().size());
302 }
303
304 private double getCurrentThreshold(double threshold, double minValue) {
305 if (!(progress instanceof ProgressRounds))
306 return threshold;
307
308 int currentRound = ((ProgressRounds) progress).getCurrentRound();
309 int totalRounds = ((ProgressRounds) progress).getTotalRounds();
310 if (totalRounds == 0)
311 totalRounds++;
312 return (1 - currentRound / totalRounds) * (threshold - minValue) + minValue;
313 }
314
315}
Note: See TracBrowser for help on using the repository browser.