1 | package parties.in4010.q12015.group15;
|
---|
2 |
|
---|
3 | import java.util.List;
|
---|
4 |
|
---|
5 | import java.util.ArrayList;
|
---|
6 | import java.util.Random;
|
---|
7 |
|
---|
8 | import genius.core.AgentID;
|
---|
9 | import genius.core.Bid;
|
---|
10 | import genius.core.actions.Accept;
|
---|
11 | import genius.core.actions.Action;
|
---|
12 | import genius.core.actions.DefaultAction;
|
---|
13 | import genius.core.actions.Offer;
|
---|
14 | import genius.core.bidding.BidDetails;
|
---|
15 | import genius.core.boaframework.Actions;
|
---|
16 | import genius.core.boaframework.SortedOutcomeSpace;
|
---|
17 | import genius.core.issue.Issue;
|
---|
18 | import genius.core.misc.Range;
|
---|
19 | import genius.core.parties.AbstractNegotiationParty;
|
---|
20 | import genius.core.parties.NegotiationInfo;
|
---|
21 | import genius.core.protocol.DefaultMultilateralProtocol;
|
---|
22 | import genius.core.protocol.StackedAlternatingOffersProtocol;
|
---|
23 | import genius.core.utility.AdditiveUtilitySpace;
|
---|
24 |
|
---|
25 | /**
|
---|
26 | * Negotiation party for Group15. Group members: Fabio Izzi, Kristin Fjola
|
---|
27 | * Tomasdottir, Valentina Bollini
|
---|
28 | *
|
---|
29 | * The bidding strategy is a version of time dependent concession with trade off
|
---|
30 | * using opponent modeling.
|
---|
31 | *
|
---|
32 | * We look at all offers in a certain range of utility. That range starts high
|
---|
33 | * (0.95 - 1) and lowers with time. First 2/3 of the time we choose an offer
|
---|
34 | * from that range with the lowest combined Hamming distance to all opponents
|
---|
35 | * based on their last bid. Last 1/3 of the time we choose an offer from that
|
---|
36 | * range using opponent modeling.
|
---|
37 | */
|
---|
38 | public class Group15 extends AbstractNegotiationParty {
|
---|
39 |
|
---|
40 | private double MIN_UTILITY_TO_OFFER;
|
---|
41 | private double OFFER_GROUP_SIZE;
|
---|
42 | private double TIME_TO_SWITCH_TO_OMS;
|
---|
43 | private double TIME_TO_LOWER_MIN_UTILITY;
|
---|
44 |
|
---|
45 | // Bidding strategy
|
---|
46 | private Bid lastBid;
|
---|
47 | private List<Bid> bidsOffered = new ArrayList<>();
|
---|
48 | private SortedOutcomeSpace outcomeSpace;
|
---|
49 | private double lastTimeMinUtilityWasLowered;
|
---|
50 | private boolean isUsingOMS;
|
---|
51 | private int rounds = 0;
|
---|
52 |
|
---|
53 | // BOA elements
|
---|
54 | private OpponentModel om;
|
---|
55 | private OMStrategy oms;
|
---|
56 | private AcceptanceStrategy as;
|
---|
57 |
|
---|
58 | // Time measurements
|
---|
59 | long ourStartTime = 0;
|
---|
60 | long roundStartTime = 0;
|
---|
61 | double timeCount = 0.0;
|
---|
62 | double ourTotalTime = 0;
|
---|
63 | double roundTotalTime = 0;
|
---|
64 |
|
---|
65 | public Group15() {
|
---|
66 | }
|
---|
67 |
|
---|
68 | @Override
|
---|
69 | public void init(NegotiationInfo info) {
|
---|
70 | super.init(info);
|
---|
71 |
|
---|
72 | outcomeSpace = new SortedOutcomeSpace(getUtilitySpace());
|
---|
73 | outcomeSpace.generateAllBids(getUtilitySpace());
|
---|
74 |
|
---|
75 | MIN_UTILITY_TO_OFFER = 0.95; // Start offering the highest utility for
|
---|
76 | // us
|
---|
77 | OFFER_GROUP_SIZE = 0.05; // Look at offers in a range of max-min=0.05
|
---|
78 | TIME_TO_SWITCH_TO_OMS = 2 / 3.0; // After 2/3 of the time we are
|
---|
79 | // confident in our OM
|
---|
80 | TIME_TO_LOWER_MIN_UTILITY = (2 / 3.0) / 6.0; // 6 steps of lowering
|
---|
81 | // minUtil by 0.05 to
|
---|
82 | // get to utility 0.7
|
---|
83 | lastTimeMinUtilityWasLowered = timeline.getTime(); // Keep track of when
|
---|
84 | // to lower min
|
---|
85 | // utility (concede)
|
---|
86 | isUsingOMS = false; // Start by not using OMS
|
---|
87 |
|
---|
88 | // BOA elements
|
---|
89 | om = new OpponentModel((AdditiveUtilitySpace) getUtilitySpace());
|
---|
90 | as = new AcceptanceStrategy((AdditiveUtilitySpace) getUtilitySpace());
|
---|
91 | oms = new OMStrategy(om, (AdditiveUtilitySpace) getUtilitySpace());
|
---|
92 | }
|
---|
93 |
|
---|
94 | /**
|
---|
95 | * @param validActions
|
---|
96 | * : Either a list containing both accept and offer or only
|
---|
97 | * offer.
|
---|
98 | * @return The chosen action.
|
---|
99 | */
|
---|
100 | @Override
|
---|
101 | public Action chooseAction(List<Class<? extends Action>> validActions) {
|
---|
102 | System.out.println("---- BS Choose action ---");
|
---|
103 | rounds++;
|
---|
104 | System.out.println("Round: " + rounds);
|
---|
105 | double roundTime = measureAverageRoundTime();
|
---|
106 |
|
---|
107 | // Accept if offer is good enough according to our AS
|
---|
108 | if (validActions.contains(Accept.class)
|
---|
109 | && as.determineAcceptability(lastBid, timeline, roundTime).equals(Actions.Accept)) {
|
---|
110 | return new Accept(getPartyId(), lastBid);
|
---|
111 | }
|
---|
112 |
|
---|
113 | // If we're the first one to make an offer
|
---|
114 | if (!validActions.contains(Accept.class)) {
|
---|
115 | try {
|
---|
116 | return getFirstBid();
|
---|
117 | } catch (Exception e) {
|
---|
118 | System.out.println("Could not generate first bid");
|
---|
119 | e.printStackTrace();
|
---|
120 | }
|
---|
121 | }
|
---|
122 |
|
---|
123 | // Concede to lower minimum utility if a certain time has passed
|
---|
124 | if ((timeline.getTime() - lastTimeMinUtilityWasLowered) >= TIME_TO_LOWER_MIN_UTILITY) {
|
---|
125 | lowerMinUtility();
|
---|
126 | }
|
---|
127 |
|
---|
128 | List<BidDetails> possibleBids = getPossibleBids();
|
---|
129 | Bid bestBid = null;
|
---|
130 |
|
---|
131 | // Switch to using OMS when we're confident in the OM
|
---|
132 | if (!isUsingOMS && timeline.getTime() >= TIME_TO_SWITCH_TO_OMS) {
|
---|
133 | switchToOms();
|
---|
134 | }
|
---|
135 |
|
---|
136 | // First we use Hamming Distance, then Opponent Modeling
|
---|
137 | if (!isUsingOMS) {
|
---|
138 | bestBid = getBidWithSmallestHammingDistance(possibleBids);
|
---|
139 | } else {
|
---|
140 | bestBid = oms.getBestBid(possibleBids);
|
---|
141 | }
|
---|
142 |
|
---|
143 | // If something goes wrong in the bidding strategy or if we already
|
---|
144 | // offered all bids in the interval
|
---|
145 | // we offer a random bid within our utility demand
|
---|
146 | if (bestBid == null) {
|
---|
147 | bestBid = getRandomBidInInterval(MIN_UTILITY_TO_OFFER, MIN_UTILITY_TO_OFFER + OFFER_GROUP_SIZE);
|
---|
148 | }
|
---|
149 |
|
---|
150 | System.out.println("---- BS Choose action ---");
|
---|
151 | System.out.println("My BID offered: " + bestBid);
|
---|
152 | try {
|
---|
153 | System.out.println("My BID Util: " + utilitySpace.getUtility(bestBid));
|
---|
154 | } catch (Exception e) {
|
---|
155 | e.printStackTrace();
|
---|
156 | }
|
---|
157 |
|
---|
158 | return new Offer(getPartyId(), bestBid);
|
---|
159 | }
|
---|
160 |
|
---|
161 | /**
|
---|
162 | * Lowers the minimum utility that we want to offer by a constant
|
---|
163 | */
|
---|
164 | public void lowerMinUtility() {
|
---|
165 | MIN_UTILITY_TO_OFFER -= OFFER_GROUP_SIZE;
|
---|
166 | lastTimeMinUtilityWasLowered = timeline.getTime();
|
---|
167 | System.out.println("Lowering MIN_UTILITY_TO_OFFER to: " + MIN_UTILITY_TO_OFFER + " in round: " + rounds);
|
---|
168 | }
|
---|
169 |
|
---|
170 | /**
|
---|
171 | * @return the bid we want to offer when we're the first one to make a bid
|
---|
172 | * @throws Exception
|
---|
173 | */
|
---|
174 | public Action getFirstBid() throws Exception {
|
---|
175 | // As our first bid we want to offer our best bid possible
|
---|
176 | return new Offer(getPartyId(), utilitySpace.getMaxUtilityBid());
|
---|
177 | }
|
---|
178 |
|
---|
179 | /**
|
---|
180 | * @return all possible bids in the range of our min utility + constant
|
---|
181 | */
|
---|
182 | public List<BidDetails> getPossibleBids() {
|
---|
183 | Range range = new Range(MIN_UTILITY_TO_OFFER, MIN_UTILITY_TO_OFFER + OFFER_GROUP_SIZE);
|
---|
184 | List<BidDetails> possibleBids = outcomeSpace.getBidsinRange(range);
|
---|
185 | return possibleBids;
|
---|
186 | }
|
---|
187 |
|
---|
188 | /**
|
---|
189 | * Switches from using Hamming distance to choose a bid to use our opponent
|
---|
190 | * modeling instead
|
---|
191 | */
|
---|
192 | private void switchToOms() {
|
---|
193 | isUsingOMS = true;
|
---|
194 | MIN_UTILITY_TO_OFFER = 0.95; // We might choose other offers than before
|
---|
195 | TIME_TO_LOWER_MIN_UTILITY = (1 / 3.0) / 6.0; // Only 1/3 of the time is
|
---|
196 | // left and we want to
|
---|
197 | // concede to utility
|
---|
198 | // 0.7
|
---|
199 | lastTimeMinUtilityWasLowered = timeline.getTime();
|
---|
200 | System.out.println("CHANGING TO OMS in round: " + rounds);
|
---|
201 | System.out.println("Setting min utility to: " + MIN_UTILITY_TO_OFFER);
|
---|
202 | }
|
---|
203 |
|
---|
204 | /**
|
---|
205 | * @param all
|
---|
206 | * possible bids in some range
|
---|
207 | * @return bid with smallest sum of Hamming distance to all opponents from
|
---|
208 | * the list of bids
|
---|
209 | */
|
---|
210 | private Bid getBidWithSmallestHammingDistance(List<BidDetails> bids) {
|
---|
211 | System.out.println("---- BS Hamming ----");
|
---|
212 | Bid bestBid = null; // If it doesn't succeed to calc Hamming distance
|
---|
213 | int smallestDist = Integer.MAX_VALUE;
|
---|
214 |
|
---|
215 | for (BidDetails b : bids) {
|
---|
216 | if (bidsOffered.contains(b.getBid())) { // Don't offer same bid
|
---|
217 | // twice
|
---|
218 | System.out.println("Has offered bid before: " + b.getBid());
|
---|
219 | continue;
|
---|
220 | }
|
---|
221 | int totalDist = 0;
|
---|
222 |
|
---|
223 | for (String opponent : om.getOpponents()) {
|
---|
224 | totalDist += getHammingDistance(b.getBid(), om.getLastBidFromAgent(opponent));
|
---|
225 | }
|
---|
226 |
|
---|
227 | if (totalDist < smallestDist) {
|
---|
228 | smallestDist = totalDist;
|
---|
229 | bestBid = b.getBid();
|
---|
230 | }
|
---|
231 | }
|
---|
232 | System.out.println("Smallest dist found: " + smallestDist);
|
---|
233 |
|
---|
234 | bidsOffered.add(bestBid);
|
---|
235 | return bestBid;
|
---|
236 | }
|
---|
237 |
|
---|
238 | /**
|
---|
239 | * @param bid1
|
---|
240 | * @param bid2
|
---|
241 | * @return Hamming distance between bid1 and bid2
|
---|
242 | */
|
---|
243 | private int getHammingDistance(Bid bid1, Bid bid2) {
|
---|
244 | int dist = 0;
|
---|
245 | List<Issue> issues = bid1.getIssues();
|
---|
246 | for (Issue issue : issues) {
|
---|
247 | int indexOfIssue = issues.indexOf(issue) + 1;
|
---|
248 | try {
|
---|
249 | if (!bid1.getValue(indexOfIssue).equals(bid2.getValue(indexOfIssue))) {
|
---|
250 | dist++;
|
---|
251 | }
|
---|
252 | } catch (Exception e) {
|
---|
253 | System.out.println("BS Could not calculate Hamming distance between " + bid1 + " and " + bid2);
|
---|
254 | e.printStackTrace();
|
---|
255 | }
|
---|
256 | }
|
---|
257 |
|
---|
258 | return dist;
|
---|
259 | }
|
---|
260 |
|
---|
261 | /**
|
---|
262 | * @return average time in seconds for each round
|
---|
263 | */
|
---|
264 | public double measureAverageRoundTime() {
|
---|
265 | timeCount++;
|
---|
266 | double roundAvgTime = 0;
|
---|
267 | if (roundStartTime != 0) {
|
---|
268 | long roundEndTime = System.nanoTime();
|
---|
269 | long roundTime = roundEndTime - roundStartTime;
|
---|
270 | double roundTimeSeconds = (double) roundTime / 1000000000.0;
|
---|
271 | roundTotalTime += roundTimeSeconds;
|
---|
272 | roundAvgTime = (roundTotalTime / (timeCount - 1));
|
---|
273 | }
|
---|
274 | ourStartTime = System.nanoTime();
|
---|
275 | roundStartTime = System.nanoTime();
|
---|
276 |
|
---|
277 | return roundAvgTime;
|
---|
278 | }
|
---|
279 |
|
---|
280 | /**
|
---|
281 | * @param min
|
---|
282 | * utility wanted
|
---|
283 | * @param max
|
---|
284 | * utility wanted
|
---|
285 | * @return random bid with utility between min and max
|
---|
286 | */
|
---|
287 | private Bid getRandomBidInInterval(double min, double max) {
|
---|
288 | System.out.println("WARNING: Offering random bid in range: " + min + " - " + max);
|
---|
289 | Random rand = new Random();
|
---|
290 | double randomUtility = min + (max - min) * rand.nextDouble();
|
---|
291 | BidDetails bidDetails = outcomeSpace.getBidNearUtility(randomUtility);
|
---|
292 | return bidDetails.getBid();
|
---|
293 | }
|
---|
294 |
|
---|
295 | /**
|
---|
296 | *
|
---|
297 | * @param sender
|
---|
298 | * The party that did the action.
|
---|
299 | * @param action
|
---|
300 | * The action that party did.
|
---|
301 | */
|
---|
302 | @Override
|
---|
303 | public void receiveMessage(AgentID sender, Action action) {
|
---|
304 | System.out.println("--- BS receive msg ---");
|
---|
305 | super.receiveMessage(sender, action);
|
---|
306 | System.out
|
---|
307 | .println("Receive " + action.getClass() + " at time: " + timeline.getTime() + " from agent " + sender);
|
---|
308 | if (action instanceof Offer && sender != null) {
|
---|
309 | lastBid = DefaultAction.getBidFromAction(action);
|
---|
310 | om.updateModel(sender.toString(), lastBid, rounds);
|
---|
311 | }
|
---|
312 | }
|
---|
313 |
|
---|
314 | @Override
|
---|
315 | public String getDescription() {
|
---|
316 | return "Multi Party Negotiation Agent Group 15";
|
---|
317 | }
|
---|
318 |
|
---|
319 | @Override
|
---|
320 | public Class<? extends DefaultMultilateralProtocol> getProtocol() {
|
---|
321 | return StackedAlternatingOffersProtocol.class;
|
---|
322 | }
|
---|
323 |
|
---|
324 | } |
---|