source: ai2020/group7/src/main/java/geniusweb/exampleparties/nataliaparty/Group7_Main.java

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

#5 tune getCapabilities

File size: 10.9 KB
Line 
1package geniusweb.exampleparties.nataliaparty;
2
3import java.io.IOException;
4import java.util.ArrayList;
5import java.util.Arrays;
6import java.util.Collections;
7import java.util.HashMap;
8import java.util.HashSet;
9import java.util.List;
10import java.util.Map;
11import java.util.PriorityQueue;
12import java.util.Queue;
13import java.util.Set;
14import java.util.logging.Level;
15import java.util.stream.Collectors;
16
17import geniusweb.actions.Offer;
18import geniusweb.actions.PartyId;
19import geniusweb.actions.Vote;
20import geniusweb.actions.Votes;
21import geniusweb.inform.ActionDone;
22import geniusweb.inform.Finished;
23import geniusweb.inform.Inform;
24import geniusweb.inform.OptIn;
25import geniusweb.inform.Settings;
26import geniusweb.inform.Voting;
27import geniusweb.inform.YourTurn;
28import geniusweb.issuevalue.Bid;
29import geniusweb.issuevalue.Domain;
30import geniusweb.issuevalue.Value;
31import geniusweb.party.Capabilities;
32import geniusweb.party.DefaultParty;
33import geniusweb.profile.utilityspace.LinearAdditive;
34import geniusweb.profile.utilityspace.ValueSetUtilities;
35import geniusweb.profileconnection.ProfileConnectionFactory;
36import geniusweb.profileconnection.ProfileInterface;
37import geniusweb.progress.Progress;
38import geniusweb.progress.ProgressRounds;
39import tudelft.utilities.logging.Reporter;
40
41public class Group7_Main extends DefaultParty {
42
43 private PartyId me;
44 protected ProfileInterface profileInt;
45 private Progress progress;
46 private Settings settings;
47 private Votes lastVotes;
48
49 private double bestUtility = 1;
50 private Bid bestBid;
51 LinearAdditive profile;
52 private Voting previousVoting;
53 Map<String, ValueSetUtilities> issueUtilities;
54 Domain domain;
55 private Offer previousOffer;
56 private Map<PartyId, Integer> powers;
57 private Integer systemTotalPower = 0;
58
59 private List<Offer> rejects;
60
61 public Group7_Main() {
62 }
63
64 public Group7_Main(Reporter reporter) {
65 super(reporter); // for debugging
66 }
67
68 @Override
69 public void notifyChange(Inform info) {
70 try {
71 if (info instanceof Settings) {
72 Settings settings = (Settings) info;
73 this.profileInt = ProfileConnectionFactory.create(settings.getProfile().getURI(), getReporter());
74 this.me = settings.getID();
75 this.progress = settings.getProgress();
76 this.settings = settings;
77 this.profile = (LinearAdditive) profileInt.getProfile();
78 this.issueUtilities = profile.getUtilities();
79 this.domain = profile.getDomain();
80 } else if (info instanceof ActionDone) {
81 } else if (info instanceof YourTurn) {
82 makeOffer();
83 } else if (info instanceof Finished) {
84 getReporter().log(Level.INFO, "Final outcome:" + info);
85 } else if (info instanceof Voting) {
86 previousVoting = (Voting) info;
87 powers = ((Voting) info).getPowers();
88 systemTotalPower = powers.values().stream().reduce(0, Integer::sum);
89 lastVotes = vote(previousVoting);
90 getConnection().send(lastVotes);
91 } else if (info instanceof OptIn) {
92 getConnection().send(optInStrategy((OptIn) info));
93 nextRound();
94 }
95 } catch (Exception e) {
96 throw new RuntimeException("Failed to handle info", e);
97 }
98 }
99
100 /**
101 * send our next offer
102 */
103 private void makeOffer() throws IOException {
104 Bid nextBid;
105 // First round, make the best bid
106 if (bestBid == null) {
107 bestBid = ourBestBid();
108 bestUtility = profile.getUtility(bestBid).doubleValue();
109 nextBid = bestBid;
110 } else {
111 nextBid = biddingStrategy(getPopularity(previousVoting));
112 }
113 Offer nextOffer = new Offer(me, nextBid);
114 getConnection().send(nextOffer);
115 previousOffer = nextOffer;
116 }
117
118 /**
119 * @param voting the {@link Voting} object containing the options
120 * @return our next Votes.
121 */
122 private Votes vote(Voting voting) {
123 Set<Vote> votes;
124 if (voting.getBids().size() > 2) {
125 votes = votingStrategy(voting);
126 } else {
127 Map<Boolean, List<Offer>> partitions = voting.getBids().stream()
128 .collect(Collectors.partitioningBy(this::isGood));
129 rejects = new ArrayList<>(partitions.get(false));
130 votes = partitions.get(true).stream().distinct()
131 .map(offer -> new Vote(me, offer.getBid(), getMinPower(), getMaxPower()))
132 .collect(Collectors.toSet());
133 }
134 return new Votes(me, votes);
135 }
136
137 private Bid biddingStrategy(DoubleMap valuePopularity) {
138 Map<String, Value> issueValues = new HashMap<>(bestBid.getIssueValues());
139 Queue<ValueOption> valueOptions = getAllValueOption(valuePopularity);
140
141 double totalUtility;
142 double threshold = getTimeThreshold(bestUtility);
143
144 Map<String, Value> previousIssueValues = issueValues;
145 while (!valueOptions.isEmpty()) {
146 ValueOption option = valueOptions.poll();
147 issueValues.replace(option.getIssue(), option.getValue());
148 totalUtility = profile.getUtility(new Bid(issueValues)).doubleValue();
149 if (totalUtility < threshold) {
150 break;
151 }
152 previousIssueValues = issueValues;
153 }
154 return new Bid(previousIssueValues);
155 }
156
157 private Set<Vote> votingStrategy(Voting voting) {
158 double totalUtility = 0;
159 double totalPower = 0;
160 for (Offer offer : voting.getBids()) {
161 double utility = profile.getUtility(offer.getBid()).doubleValue();
162 double power = powers.get(offer.getActor());
163 totalUtility += utility * power;
164 totalPower += power;
165 }
166 double averageUtility = totalUtility / totalPower;
167
168 Set<Vote> acceptedVotes = new HashSet<>();
169 rejects = new ArrayList<>();
170 for (Offer offer : voting.getBids()) {
171 double utility = profile.getUtility(offer.getBid()).doubleValue();
172 if (utility > averageUtility) {
173 acceptedVotes.add(new Vote(me, offer.getBid(), getMinPower(), getMaxPower()));
174 } else {
175 rejects.add(offer);
176 }
177 }
178 return acceptedVotes;
179 }
180
181 private Votes optInStrategy(OptIn optin) {
182 Map<Bid, Integer> bidPower = new HashMap<>();
183 for (Votes partyVotes : optin.getVotes()) {
184 int partyPower = powers.get(partyVotes.getActor());
185 for (Vote vote : partyVotes.getVotes()) {
186 Bid bid = vote.getBid();
187 if (bidPower.containsKey(bid)) {
188 bidPower.put(bid, bidPower.get(bid) + partyPower);
189 } else {
190 bidPower.put(bid, partyPower);
191 }
192 }
193 }
194 Set<Vote> myNewVotes = new HashSet<>(lastVotes.getVotes());
195 for (Offer offer : rejects) {
196 Bid bid = offer.getBid();
197 int power = bidPower.getOrDefault(bid, 0);
198 if (power >= getMinPower()) {
199 myNewVotes.add(new Vote(me, bid, getMinPower(), getMaxPower()));
200 }
201 }
202 return new Votes(me, myNewVotes);
203 }
204
205 /**
206 * Create a Bid with the highest utility value for each issue.
207 *
208 * @return a new Bid with the highest utility.
209 */
210 private Bid ourBestBid() {
211 // Create a new map which stores the best value for each issue
212 HashMap<String, Value> issueValues = new HashMap<>();
213
214 for (String issueName : domain.getIssues()) {
215 ValueSetUtilities valueUtilities = issueUtilities.get(issueName);
216
217 // Find the value with the best utility
218 double bestUtility = 0;
219 Value bestValue = null;
220 for (Value value : domain.getValues(issueName)) {
221 double utility = valueUtilities.getUtility(value).doubleValue();
222 if (utility >= bestUtility) {
223 bestUtility = utility;
224 bestValue = value;
225 }
226 }
227 issueValues.put(issueName, bestValue);
228 }
229 return new Bid(issueValues);
230 }
231
232 private DoubleMap getPopularity(Voting voting) {
233 // Get all the offers, excluding our own
234 List<Offer> offers = new ArrayList<>(voting.getBids());
235 offers.remove(previousOffer);
236
237 // Count the amount of power for each issue-value
238 DoubleMap popularity = new DoubleMap();
239 for (Offer offer : offers) {
240 Set<String> issues = offer.getBid().getIssues();
241 for (String issue : issues) {
242 Value value = offer.getBid().getValue(issue);
243 int power = powers.getOrDefault(offer.getActor(), 1);
244 // Normalize all the power
245 double powerPercent = power / (double) systemTotalPower;
246 popularity.add(issue, value, powerPercent);
247 }
248 }
249 return popularity;
250 }
251
252 private Queue<ValueOption> getAllValueOption(DoubleMap valuePopularity) {
253 Map<String, Value> issueValues = new HashMap<>(bestBid.getIssueValues());
254 Queue<ValueOption> valueOptions = new PriorityQueue<>();
255
256 for (String issue : domain.getIssues()) {
257 ValueSetUtilities valueUtilities = issueUtilities.get(issue);
258 Value bestValue = issueValues.get(issue);
259 double bestUtility = valueUtilities.getUtility(bestValue).doubleValue();
260 double weight = profile.getWeight(issue).doubleValue();
261
262 for (Value value : domain.getValues(issue)) {
263 if (value.equals(bestValue)) {
264 continue;
265 }
266 double utility = valueUtilities.getUtility(value).doubleValue();
267 double utilityLoss = bestUtility - utility;
268 double popularity = (powers.get(me) / (double) systemTotalPower) + valuePopularity.get(issue, value);
269 double bestValuePopularity = (powers.get(me) / (double) systemTotalPower)
270 + valuePopularity.get(issue, bestValue);
271
272 boolean skipEvaluation = false;
273 for (Value otherValue : domain.getValues(issue)) {
274 if (otherValue.equals(bestValue) || otherValue.equals(value)) {
275 continue;
276 }
277 double otherUtility = valueUtilities.getUtility(otherValue).doubleValue();
278 double otherPopularity = (powers.get(me) / (double) systemTotalPower)
279 + valuePopularity.get(issue, otherValue);
280
281 if (otherUtility >= utility && otherPopularity >= popularity) {
282 skipEvaluation = true;
283 break;
284 }
285 }
286 if (skipEvaluation) {
287 continue;
288 }
289 double penalty = (utilityLoss * weight * (1 / popularity) + 1) * bestValuePopularity;
290 valueOptions.add(new ValueOption(issue, value, penalty));
291 }
292 }
293 return valueOptions;
294 }
295
296 private double getTimeThreshold(double startValue) {
297 double timeFraction;
298 if (progress instanceof ProgressRounds) {
299 timeFraction = ((ProgressRounds) progress).getCurrentRound()
300 / (double) ((ProgressRounds) progress).getTotalRounds();
301 } else {
302 timeFraction = progress.get(System.currentTimeMillis());
303 }
304 double threshold = ((1 - Math.pow(timeFraction, 1.5)) * (startValue - 0.1)) + 0.1;
305 if (threshold < 0)
306 return 0;
307 if (threshold > 1)
308 return 1;
309 return threshold;
310 }
311
312 /**
313 * @param offer the offer to check
314 * @return true iff offer is good for us.
315 */
316 private boolean isGood(Offer offer) {
317 if (offer == null) {
318 return false;
319 }
320 double threshold = getTimeThreshold(bestUtility * 0.9);
321 return profile.getUtility(offer.getBid()).doubleValue() > threshold;
322 }
323
324 private void nextRound() {
325 if (progress instanceof ProgressRounds) {
326 progress = ((ProgressRounds) progress).advance();
327 }
328 }
329
330 @Override
331 public Capabilities getCapabilities() {
332 return new Capabilities(new HashSet<>(Arrays.asList("SAOP", "MOPAC")),
333 Collections.singleton(LinearAdditive.class));
334 }
335
336 @Override
337 public String getDescription() {
338 return "Uses penalties to create the next bid. Accepts all bids better than the weighted average. Opts into all the bids that already have enough power to form an agreement";
339 }
340
341 private int getMinPower() {
342 Object val = settings.getParameters().get("minPower");
343 return (val instanceof Integer) ? (Integer) val : 2;
344 }
345
346 private int getMaxPower() {
347 Object val = settings.getParameters().get("maxPower");
348 return (val instanceof Integer) ? (Integer) val : systemTotalPower;
349 }
350}
Note: See TracBrowser for help on using the repository browser.