source: src/main/java/parties/in4010/q12015/group5/Group5.java@ 3

Last change on this file since 3 was 1, checked in by Wouter Pasman, 7 years ago

Initial import : Genius 9.0.0

File size: 9.1 KB
Line 
1package parties.in4010.q12015.group5;
2
3import java.util.ArrayList;
4import java.util.HashMap;
5import java.util.List;
6import java.util.Map;
7import java.util.Set;
8
9import genius.core.AgentID;
10import genius.core.Bid;
11import genius.core.actions.Accept;
12import genius.core.actions.Action;
13import genius.core.actions.Offer;
14import genius.core.bidding.BidDetails;
15import genius.core.boaframework.SortedOutcomeSpace;
16import genius.core.parties.AbstractNegotiationParty;
17import genius.core.parties.NegotiationInfo;
18import genius.core.utility.AdditiveUtilitySpace;
19
20/**
21 * NegotiationParty for Group 5. This agent moves closer to the estimated Nash
22 * point as time progresses. For an extended explanation of what our agent does,
23 * see our report.
24 */
25public class Group5 extends AbstractNegotiationParty {
26
27 /**
28 * All possible bids from the SortedOutcomeSpace.
29 */
30 private List<BidDetails> allOutcomes;
31
32 /**
33 * The last bid that has been made by any agent (including us).
34 */
35 private Bid lastBid;
36
37 /**
38 * The models that we build for every opponent.
39 */
40 private Map<Object, OpponentModel> opponentModels;
41
42 /**
43 * The SortedOutcomeSpace of our UtilitySpace.
44 */
45 private SortedOutcomeSpace sos;
46
47 /**
48 * The threshold above which we will always accept.
49 */
50 private double utilityThreshold;
51
52 /*
53 * (non-Javadoc)
54 *
55 * @see negotiator.parties.AbstractNegotiationParty#init(negotiator.utility.
56 * UtilitySpace, negotiator.Deadline, negotiator.session.TimeLineInfo, long,
57 * negotiator.AgentID)
58 */
59 @Override
60 public void init(NegotiationInfo info) {
61 super.init(info);
62 opponentModels = new HashMap<Object, OpponentModel>();
63 sos = new SortedOutcomeSpace(info.getUtilitySpace());
64 allOutcomes = sos.getAllOutcomes();
65
66 double minBid = sos.getMinBidPossible().getMyUndiscountedUtil();
67 utilityThreshold = 1 - (1 - minBid) * 0.1; // Get top 90%
68 }
69
70 /**
71 * All offers proposed by the other parties will be received as a message.
72 * You can use this information to your advantage, for example to predict
73 * their utility.
74 *
75 * @param sender
76 * The party that did the action.
77 * @param action
78 * The action that party did.
79 */
80 @Override
81 public void receiveMessage(AgentID sender, Action action) {
82 super.receiveMessage(sender, action);
83
84 try {
85 if (action instanceof Offer) {
86 lastBid = ((Offer) action).getBid();
87 updateModel(sender, lastBid);
88 } else if (action instanceof Accept) {
89 updateModel(sender, lastBid);
90 }
91 } catch (Exception e) {
92 e.printStackTrace();
93 }
94 }
95
96 /**
97 * Each round this method gets called and ask you to accept or offer. The
98 * first party in the first round is a bit different, it can only propose an
99 * offer.
100 *
101 * @param validActions
102 * Either a list containing both accept and offer or only offer.
103 * @return The chosen action.
104 */
105 @Override
106 public Action chooseAction(List<Class<? extends Action>> validActions) {
107 try {
108 Bid bid = generateBid();
109 if (acceptBid(bid))
110 return new Accept(getPartyId(), lastBid);
111 else {
112 lastBid = bid;
113 return new Offer(getPartyId(), new Bid(bid));
114 }
115 } catch (Exception e) {
116 e.printStackTrace();
117 // Accepting is always
118 // better than crashing
119 return new Accept(getPartyId(), lastBid);
120 }
121 }
122
123 /**
124 * Generates a new bid according to the bidding strategy. Finds a bid by
125 * looping through all bids and - Calculate the Nash score for the bid based
126 * on the opponent models. - Calculate own utility for the bid. - Take the
127 * weighted average of own utility and the Nash score. This weighted average
128 * starts at 100% own utility and moves to 100% theoretical Nash point. Of
129 * these the top 5 is chosen and from those the one with the highest utility
130 * is chosen.
131 *
132 * @return The preferred bid based on the chosen strategy.
133 * @throws Exception
134 */
135 private Bid generateBid() throws Exception {
136 Double time = timeline.getTime();
137 double ownFactor = 1 - (time * time); // 1 - x^2
138 double nashFactor = 1 - ownFactor;
139
140 // Get modeled utility spaces for opponents
141 Set<Object> opponents = opponentModels.keySet();
142 Map<Object, AdditiveUtilitySpace> opponentUtilSpaces = new HashMap<Object, AdditiveUtilitySpace>();
143 for (Object opponent : opponents) {
144 opponentUtilSpaces.put(opponent, opponentModels.get(opponent).getUtilitySpace());
145 }
146
147 // weightedAverages contains the top 5 weighted averages found
148 Map<BidDetails, Double> weightedAverages = new HashMap<BidDetails, Double>();
149 weightedAverages.put(null, 0.);
150 for (BidDetails bid : allOutcomes) {
151 // First find the minimum in order to know which one we should
152 // replace if we find a better one.
153 double min = Double.MAX_VALUE;
154 BidDetails minBid = null;
155 for (BidDetails mapBid : weightedAverages.keySet()) {
156 double mapAvg = weightedAverages.get(mapBid);
157 if (mapAvg <= min) {
158 min = mapAvg;
159 minBid = mapBid;
160 }
161 }
162
163 // If based on our utility alone we won't make it, break because:
164 // - Adding the opponents utilities to the nash will only decrease
165 // the value (because U <= 1)
166 // - The list is sorted in decreasing order so all next bids will be
167 // worse.
168 double ourUtil = bid.getMyUndiscountedUtil();
169 if (ownFactor * ourUtil + nashFactor * ourUtil < min)
170 break;
171
172 double nash = ourUtil;
173 for (Object opponent : opponents) {
174 AdditiveUtilitySpace opponentUtilSpace = opponentUtilSpaces.get(opponent);
175 nash *= opponentUtilSpace.getUtility(bid.getBid());
176 }
177
178 double weightedAverage = ownFactor * ourUtil + nashFactor * nash;
179 if (weightedAverage > min) {
180 if (weightedAverages.size() >= 5) {
181 weightedAverages.remove(minBid);
182 }
183
184 weightedAverages.put(bid, weightedAverage);
185 }
186 }
187
188 // Find the one that gives the highest utility of the top 5.
189 double max = 0;
190 BidDetails maxBid = null;
191 for (BidDetails mapBid : weightedAverages.keySet()) {
192 double mapUtil = mapBid.getMyUndiscountedUtil();
193 if (mapUtil > max) {
194 max = mapUtil;
195 maxBid = mapBid;
196 }
197 }
198
199 return maxBid.getBid();
200 }
201
202 // Accept when either:
203 // - It is above our minimum
204 // - It is better than we would bid
205 // - (late in the bidding), it is better than all the bids in the previous
206 // window
207 /**
208 * Decides whether to accept the last bid based on the bid that was
209 * generated by the bidding strategy. Acceptance strategy is as follows.
210 * Accept when either: - The bid is above our threshold This is a linear
211 * function from the top 100% of the space to the top 80% of the space - The
212 * bid is better than the bid generated by the strategy. - When 0.95 of the
213 * negotiation has passed, accept if we don't expect a better bid. This is
214 * the case if the bid is better than all the bids we have seen in the
215 * previous time window.
216 *
217 * @param bid
218 * The bid generated by the bidding strategy.
219 * @return Whether to accept the current bid.
220 * @throws Exception
221 */
222 private boolean acceptBid(Bid bid) throws Exception {
223 double time = timeline.getTime();
224 double minUtility = getUtilityThreshold(time / 0.5);
225 double lastUtility = (lastBid != null) ? utilitySpace.getUtility(lastBid) : 0;
226 double bidUtility = utilitySpace.getUtility(bid);
227 if (lastUtility >= minUtility || lastUtility >= bidUtility)
228 return true;
229
230 if (time >= 0.95) {
231 List<Bid> opponentBids = new ArrayList<Bid>();
232 for (Object opponent : opponentModels.keySet()) {
233 opponentBids.addAll(opponentModels.get(opponent).getBidHistory(1 - time));
234 }
235 double maxUtility = 0;
236 for (Bid oppBid : opponentBids) {
237 double utility = utilitySpace.getUtility(oppBid);
238 if (utility > maxUtility) {
239 maxUtility = utility;
240 }
241 }
242 if (bidUtility >= maxUtility)
243 return true;
244 }
245
246 return false;
247 }
248
249 /**
250 * Linear function from 1 to utilityThreshold, multiplied by the factor (to
251 * reach it sooner, for example)
252 *
253 * @param factor
254 * The factor by which to multiply
255 * @return The utilty above which we will always accept.
256 */
257 private double getUtilityThreshold(double factor) {
258 return 1 - (1 - utilityThreshold) * factor;
259 }
260
261 /**
262 * Updates the opponent model with the specified opponents new bid. If no
263 * model is yet present, one will be created and added to the list.
264 *
265 * @param opponent
266 * The opponent of which the model needs to be updated.
267 * @param newBid
268 * The new bid of the opponent
269 * @throws Exception
270 */
271 private void updateModel(AgentID opponent, Bid newBid) throws Exception {
272 OpponentModel opponentModel = opponentModels.get(opponent);
273 if (opponentModel == null) {
274 opponentModel = new OpponentModel(utilitySpace.getDomain(), newBid);
275 opponentModels.put(opponent, opponentModel);
276 } else {
277 opponentModel.updateModel(newBid);
278 }
279 }
280
281 /*
282 * (non-Javadoc)
283 *
284 * @see negotiator.parties.AbstractNegotiationParty#getDescription()
285 */
286 @Override
287 public String getDescription() {
288 return "I heard you like parties so we created a party to negotiate about your party";
289 }
290}
Note: See TracBrowser for help on using the repository browser.