source: src/main/java/agents/anac/y2019/harddealer/HardDealer_OM.java@ 230

Last change on this file since 230 was 200, checked in by Katsuhide Fujita, 5 years ago

Add ANAC 2019 agents

  • Property svn:executable set to *
File size: 15.8 KB
Line 
1package agents.anac.y2019.harddealer;
2import java.util.ArrayList;
3import java.util.HashMap;
4import java.util.HashSet;
5import java.util.List;
6import java.util.Map;
7import java.util.Set;
8import java.util.Map.Entry;
9
10import genius.core.Bid;
11import genius.core.bidding.BidDetails;
12import genius.core.boaframework.BOAparameter;
13import genius.core.boaframework.NegotiationSession;
14import genius.core.boaframework.OpponentModel;
15import genius.core.issue.Issue;
16import genius.core.issue.IssueDiscrete;
17import genius.core.issue.Objective;
18import genius.core.issue.Value;
19import genius.core.issue.ValueDiscrete;
20import genius.core.timeline.TimeLineInfo;
21import genius.core.utility.AdditiveUtilitySpace;
22import genius.core.utility.Evaluator;
23import genius.core.utility.EvaluatorDiscrete;
24
25public class HardDealer_OM extends OpponentModel {
26
27 private double learnCoeff;
28
29 private double issueUpdate;
30
31 private int valueUpdate;
32
33 private double minOppUtil = 0; // Minimum utility value for opponent when Negotiation Time ends
34 private double maxOppUtil = 1; // Maximum utility value for opponent when Negotiation Time starts
35 private double nOfHypothesis;
36 private double nOfIssues;
37 HashMap<List<Issue>, Double> probHyp = new HashMap<List<Issue>, Double>(); // the probabilities for each hypothesis
38 List<List<Issue>> spaceOfHypothesis = new ArrayList<List<Issue>>(); // All the possible hypothesis
39 HashMap<List<Issue>, Double> oppUF = new HashMap<List<Issue>, Double>(); // List of utility evaluations for each hypothesis
40 HashMap<List<Issue>, Double> probHypGivenBid = new HashMap<List<Issue>, Double>(); // List of probabilities for each hypothesis given as bid
41 List<Double> oppTargetUtility = new ArrayList<Double>(); // List of target utilities for the opponent for each time interval
42 HashMap<List<Issue>,HashMap<Integer, Double>> ListWeight = new HashMap<List<Issue>, HashMap<Integer, Double>>();
43
44 HashMap<Objective, Double> simpleWeights = new HashMap<Objective, Double>(); // List of weights for the SimpleLearning model
45
46 TimeLineInfo negTime;
47
48 public void init(NegotiationSession negotiationSession,
49 Map<String, Double> parameters) {
50 this.negotiationSession = negotiationSession;
51 if (parameters != null && parameters.get("l") != null) {
52 learnCoeff = parameters.get("l");
53 } else {
54 learnCoeff = 0.13;
55 }
56 negTime = negotiationSession.getTimeline();
57 valueUpdate = 1;
58 opponentUtilitySpace = (AdditiveUtilitySpace) negotiationSession
59 .getUtilitySpace().copy();
60 nOfIssues = opponentUtilitySpace.getDomain().getIssues().size();
61 /*
62 * This is the value to be added to weights of unchanged issues before
63 * normalization. Also the value that is taken as the minimum possible
64 * weight, (therefore defining the maximum possible also).
65 */
66 issueUpdate = learnCoeff / nOfIssues;
67
68 initializeModel();
69
70 }
71
72 /**
73 * Update both the bayesian learning model as the simple learning model
74 */
75
76 @Override
77 public void updateModel(Bid bid, double time) {
78 double alpha = 1;
79 // Calculate target utility for the opponent given the concession formula
80 double targetUtility = maxOppUtil - (maxOppUtil - minOppUtil) *
81 Math.pow((negTime.getCurrentTime() / negTime.getTotalTime()), alpha);
82
83 oppTargetUtility.add(targetUtility);
84
85 /**
86 * For each hypothesis, calculate the utility of the current bid given the weights of that hypothesis
87 * Calculation of utility of bid inspired by getUtility() function in the AdditiveUtilitySpace of genius
88 */
89 for (List<Issue> Hypothesis : spaceOfHypothesis) {
90 HashMap<Integer, Double> Weights = ListWeight.get(Hypothesis);
91 HashMap<Integer, Value> Values = bid.getValues();
92 double CompleteUF = 0;
93 for (Issue issues : Hypothesis) {
94 for (Entry<Objective, Evaluator> e : opponentUtilitySpace.getEvaluators()) {
95 EvaluatorDiscrete evaluator = (EvaluatorDiscrete) e.getValue();
96 double value = 0;
97 try {
98 value = evaluator.getEvaluation((ValueDiscrete)Values.get(issues.getNumber()));
99 double OppUtilityFun = value * Weights.get(issues.getNumber());
100 CompleteUF = CompleteUF + OppUtilityFun;
101 } catch (Exception e1) {
102
103 }
104 }
105 }
106 if(CompleteUF > 1) {
107 CompleteUF = 1;
108 }
109 oppUF.put(Hypothesis, CompleteUF);
110 }
111
112 /**
113 * Calculate the probability of the hypothesis given this bid as the 1 - the distance between the calculated utility and the target utility
114 */
115 for (List<Issue> Hypothesis : spaceOfHypothesis) {
116 probHypGivenBid.put(Hypothesis, 1 - Math.abs(oppUF.get(Hypothesis) - oppTargetUtility.get(oppTargetUtility.size()-1)));
117 }
118
119 double sumProbHypGivenBid = 0;
120 for (List<Issue> hypothesis : spaceOfHypothesis) {
121 sumProbHypGivenBid += probHypGivenBid.get(hypothesis) * probHyp.get(hypothesis);
122 }
123
124 double maxProb = 0;
125 List<Issue> maxHyp = new ArrayList<>();
126 // Bayesian Rule to calculate the new probability of each hypothesis
127 for (List<Issue> hypothesis : spaceOfHypothesis) {
128 double prob = probHypGivenBid.get(hypothesis) * probHyp.get(hypothesis) / sumProbHypGivenBid;
129 if(Double.isNaN(prob))
130 prob = 0;
131 probHyp.put(hypothesis, prob);
132 // Record which hypothesis has the highest probability to use in the actual weights for the model
133 if(prob > maxProb) {
134 maxProb = prob;
135 maxHyp = hypothesis;
136 }
137 }
138
139 // Only start updating the simple learning and updating weights and values after at least 2 opponent bids
140 if (negotiationSession.getOpponentBidHistory().size() < 2) {
141 return;
142 }
143 /**
144 * Gets the last 5 bids, or if there are less than 5 bids, return all the last bids.
145 */
146 ArrayList<BidDetails> multipleBids = new ArrayList<BidDetails>();
147 BidDetails oppBid = negotiationSession.getOpponentBidHistory().getHistory()
148 .get(negotiationSession.getOpponentBidHistory().size() - 1);
149 multipleBids.add(oppBid);
150 BidDetails prevOppBid1 = negotiationSession.getOpponentBidHistory().getHistory()
151 .get(negotiationSession.getOpponentBidHistory().size() - 2);
152 multipleBids.add(prevOppBid1);
153 if (negotiationSession.getOpponentBidHistory().size() > 2) {
154 BidDetails prevOppBid2 = negotiationSession.getOpponentBidHistory()
155 .getHistory()
156 .get(negotiationSession.getOpponentBidHistory().size() - 3);
157 multipleBids.add(prevOppBid2);
158 }
159 if (negotiationSession.getOpponentBidHistory().size() > 3) {
160 BidDetails prevOppBid3 = negotiationSession.getOpponentBidHistory()
161 .getHistory()
162 .get(negotiationSession.getOpponentBidHistory().size() - 4);
163 multipleBids.add(prevOppBid3);
164 }
165 if (negotiationSession.getOpponentBidHistory().size() > 4) {
166 BidDetails prevOppBid4 = negotiationSession.getOpponentBidHistory()
167 .getHistory()
168 .get(negotiationSession.getOpponentBidHistory().size() - 5);
169 multipleBids.add(prevOppBid4);
170 }
171 /**
172 * Get for each of the issues how many bids the value has not changed
173 */
174 HashMap<Integer, Integer> lastDiffSet = last5oppBid(multipleBids);
175
176 /**
177 * Calculate the new total weight
178 * Each weight will have the issue Update value * the number of bids the value in this issue has not changed added to it
179 */
180 double totalweight = 0;
181 for (Integer i : lastDiffSet.keySet()) {
182 double weight = opponentUtilitySpace.getWeight(i);
183 if (lastDiffSet.get(i) == 4) {
184 totalweight += (weight + 4 * issueUpdate);
185 }
186 else if (lastDiffSet.get(i) == 3) {
187 totalweight += (weight + 3 * issueUpdate);
188 }
189 else if (lastDiffSet.get(i) == 2) {
190 totalweight += (weight + 2 * issueUpdate);
191 }
192 else if (lastDiffSet.get(i) == 1) {
193 totalweight += (weight + 1 * issueUpdate);
194 }
195 else {
196 totalweight += weight;
197 }
198 }
199
200 /**
201 * Update the weights to the new weights as explained above, but now normalized corresponding to the total weight
202 */
203 for (Integer i : lastDiffSet.keySet()) {
204 Objective issue = opponentUtilitySpace.getDomain()
205 .getObjectivesRoot().getObjective(i);
206 double weight = opponentUtilitySpace.getWeight(i);
207 double newWeight;
208 if (lastDiffSet.get(i) == 4) {
209 newWeight = (weight + 4 * issueUpdate) / totalweight;
210 }
211 else if (lastDiffSet.get(i) == 3) {
212 newWeight = (weight + 3 * issueUpdate) / totalweight;
213 }
214 else if (lastDiffSet.get(i) == 2) {
215 newWeight = (weight + 2 * issueUpdate) / totalweight;
216 }
217 else if (lastDiffSet.get(i) == 1) {
218 newWeight = (weight + 1 * issueUpdate) / totalweight;
219 }
220 else {
221 newWeight = weight / totalweight;
222 }
223 simpleWeights.put(issue, newWeight);
224 }
225
226 /*
227 * The weights for the opponent model are updated to a combination of the bayesian model and the simple learning model
228 * The weights are calculated as the probability of the highest hypothesis * the weight corresponding to this hypothesis
229 * Combined with 1 - that probability * the weights as calculated by the simple learning model
230 */
231 HashMap<Integer, Double> maxWeights = ListWeight.get(maxHyp);
232 for(Issue issue: maxHyp) {
233 opponentUtilitySpace.setWeight(issue, (maxProb * maxWeights.get(issue.getNumber())) + ((1- maxProb) * simpleWeights.get( (Objective) issue) ) );
234 }
235
236
237 try {
238 for (Entry<Objective, Evaluator> e : opponentUtilitySpace
239 .getEvaluators()) {
240 EvaluatorDiscrete value = (EvaluatorDiscrete) e.getValue();
241 IssueDiscrete issue = ((IssueDiscrete) e.getKey());
242 /*
243 * add constant learnValueAddition to the current preference of
244 * the value to make it more important
245 */
246 ValueDiscrete issuevalue = (ValueDiscrete) multipleBids.get(0).getBid()
247 .getValue(issue.getNumber());
248 Integer eval = value.getEvaluationNotNormalized(issuevalue);
249 value.setEvaluation(issuevalue, (valueUpdate + eval));
250 }
251 } catch (Exception ex) {
252 ex.printStackTrace();
253 }
254 }
255
256 public double getBidEvaluation(Bid bid) {
257 double result = 0;
258 try {
259 result = opponentUtilitySpace.getUtility(bid);
260 } catch (Exception e) {
261 e.printStackTrace();
262 }
263 return result;
264 }
265
266 public String getName() {
267 return "HardDealer_OM";
268 }
269
270 @Override
271 public Set<BOAparameter> getParameterSpec() {
272 Set<BOAparameter> set = new HashSet<BOAparameter>();
273 set.add(new BOAparameter("l", 0.13,
274 "The learning coefficient determines how quickly the issue weights are learned"));
275 return set;
276 }
277
278 /**
279 * Initialize both the simple learning and bayesian learning model
280 */
281 private void initializeModel() {
282 double commonWeight = 1D / nOfIssues;
283
284 for (Entry<Objective, Evaluator> e : opponentUtilitySpace
285 .getEvaluators()) {
286
287 opponentUtilitySpace.unlock(e.getKey());
288 // Set the weights to 1 / number of issues
289 e.getValue().setWeight(commonWeight);
290 try {
291 // set all value weights to one (they are normalized when
292 // calculating the utility)
293 for (ValueDiscrete vd : ((IssueDiscrete) e.getKey())
294 .getValues())
295 ((EvaluatorDiscrete) e.getValue()).setEvaluation(vd, 1);
296 } catch (Exception ex) {
297 ex.printStackTrace();
298 }
299 }
300
301 List<Issue> issues = negotiationSession.getIssues();
302 // Initialise the space of hypothesis
303 generateHypSpace(issues);
304
305 nOfHypothesis = spaceOfHypothesis.size();
306
307 // Initialise the probabilities of each hypothesis to 1 / number of hypothesis
308 for (List<Issue> hypothesis : spaceOfHypothesis) {
309 probHyp.put(hypothesis, 1D / nOfHypothesis);
310 }
311
312
313 for (List<Issue> Hypothesis : spaceOfHypothesis) {
314 HashMap<Integer, Double> hypWeights = new HashMap<Integer, Double>();
315 for (Issue issue : Hypothesis) {
316 // The weights for each issue in a hypothesis is defined as 2 * rank / number of issues * number of issues - 1
317 double OppNewWeight = 2 * (Hypothesis.indexOf(issue) + 1) / (nOfIssues * (nOfIssues + 1));
318 hypWeights.put(issue.getNumber(), OppNewWeight);
319 }
320 ListWeight.put(Hypothesis, hypWeights);
321 oppUF.put(Hypothesis, 0D);
322 }
323 }
324
325 /*
326 * Returns for each issue how many bids in a row the value for that issue has not changed
327 */
328 private HashMap<Integer, Integer> last5oppBid(ArrayList<BidDetails> multipleBids) {
329
330 HashMap<Integer, Integer> oppBiddiff = new HashMap<Integer, Integer>();
331 try {
332 for (Issue i : opponentUtilitySpace.getDomain().getIssues()) {
333 Value value1 = null;
334 Value value2 = null;
335 Value value3 = null;
336 Value value4 = null;
337 Value value5 = null;
338 value1 = multipleBids.get(0).getBid().getValue(i.getNumber());
339 value2 = multipleBids.get(1).getBid().getValue(i.getNumber());
340 if (multipleBids.size() > 2) {
341 value3 = multipleBids.get(2).getBid().getValue(i.getNumber());
342 }
343 if (multipleBids.size() > 3) {
344 value4 = multipleBids.get(3).getBid().getValue(i.getNumber());
345 }
346 if (multipleBids.size() > 4) {
347 value5 = multipleBids.get(4).getBid().getValue(i.getNumber());
348 }
349 /**
350 * Checks first if the last 4 values equals the current value
351 * If not, it checks for 3, 2 and 1 last values.
352 */
353 if (value1.equals(value2) && value2.equals(value3) && value3.equals(value4) && value4.equals(value5)) {
354 oppBiddiff.put(i.getNumber(), 4);
355 }
356 else if (value1.equals(value2) && value2.equals(value3) && value3.equals(value4) && !(value4.equals(value5))) {
357 oppBiddiff.put(i.getNumber(), 3);
358 }
359 else if (value1.equals(value2) && value2.equals(value3) && !(value3.equals(value4))) {
360 oppBiddiff.put(i.getNumber(), 2);
361 }
362 else if (value1.equals(value2) && !(value2.equals(value3))) {
363 oppBiddiff.put(i.getNumber(), 1);
364 }
365 else if (!(value1.equals(value2))) {
366 oppBiddiff.put(i.getNumber(), 0);
367 }
368 }
369 } catch (Exception ex) {
370 ex.printStackTrace();
371 }
372 return oppBiddiff;
373 }
374
375
376 /*
377 * Creates the list of possible hypothesis by creating all permutations of the list of issues
378 * All the following code for creating permutations was inspired by https://stackoverflow.com/questions/36373719/java-permutations-of-an-array
379 */
380 private ArrayList<List<Issue>> generateHypSpace(List<Issue> issues) {
381 return permutations(issues);
382 }
383
384
385 /*
386 * Swaps two issues in a hypothesis
387 */
388 private List<Issue> swap(List<Issue> spaceOfHypothesis2, int i, int j) {
389 Issue tmp = spaceOfHypothesis2.get(i);
390 spaceOfHypothesis2.set(i, spaceOfHypothesis2.get(j));
391 spaceOfHypothesis2.set(j, tmp);
392 return spaceOfHypothesis2;
393 }
394
395 /*
396 * Creates a list of all permutations of a list of issues
397 */
398 private void permutations(List<Issue> spaceOfHypothesis2, int loc, int len) {
399 // If you reach the end of the list, this permutation is done
400 // Make a hard copy of this permutation to prevent referencing issues and add it to the result
401 if (loc == len){
402 ArrayList<Issue> copy = new ArrayList<Issue>();
403 for(Issue i : spaceOfHypothesis2) {
404 copy.add(i);
405 }
406 spaceOfHypothesis.add(copy);
407 return;
408 }
409
410 // Make all permutations from the next issue
411 permutations(spaceOfHypothesis2, loc + 1, len);
412 for (int i = loc + 1; i < len; i++) {
413 // Swap the current issue with the issue at index i
414 spaceOfHypothesis2 = swap(spaceOfHypothesis2, loc, i);
415 // Create all permutations with these two issues swapped
416 permutations(spaceOfHypothesis2, loc + 1, len);
417 // Restore the permutation
418 spaceOfHypothesis2 = swap(spaceOfHypothesis2, loc, i);
419 }
420 }
421
422 /*
423 * Create the permutations by intialising the result, and starting at index 0
424 */
425 public ArrayList<List<Issue>> permutations(List<Issue> spaceOfHypothesis2) {
426 ArrayList<List<Issue>> result = new ArrayList<List<Issue>>();
427 permutations(spaceOfHypothesis2, 0, spaceOfHypothesis2.size());
428 return result;
429 }
430}
Note: See TracBrowser for help on using the repository browser.