1 | package agents.anac.y2014.Gangster;
|
---|
2 |
|
---|
3 | import java.util.ArrayList;
|
---|
4 | import java.util.List;
|
---|
5 |
|
---|
6 | import genius.core.Agent;
|
---|
7 | import genius.core.Bid;
|
---|
8 | import genius.core.actions.Accept;
|
---|
9 | import genius.core.actions.Action;
|
---|
10 | import genius.core.actions.Offer;
|
---|
11 | import genius.core.bidding.BidDetails;
|
---|
12 | import genius.core.issue.Issue;
|
---|
13 | import genius.core.utility.NonlinearUtilitySpace;
|
---|
14 |
|
---|
15 | //
|
---|
16 | //
|
---|
17 | //
|
---|
18 | // @author Dave de Jonge
|
---|
19 | //
|
---|
20 | //
|
---|
21 | public class Gangster extends Agent {
|
---|
22 |
|
---|
23 | double RESERVATION_VALUE = 0.0;
|
---|
24 | int NUM_ISSUES = -1;
|
---|
25 | double DISCOUNT_FACTOR;
|
---|
26 |
|
---|
27 | // PARAMETERS
|
---|
28 | // concession
|
---|
29 | int MINIMAL_MAX_DISTANCE = 5;
|
---|
30 | int INITIAL_MAX_DISTANCE;
|
---|
31 | private int DECREASE_THRESHOLD = 4; // if local search finds more than this
|
---|
32 | // amount of altruistic bids, decrease
|
---|
33 | // the max distance.
|
---|
34 | int DECREASE_AMOUNT = 1; // the amount by which the max distance is
|
---|
35 | // decreased each time this happens
|
---|
36 | double DEADLINE_MARGIN = 0.01; // we aim to reach u_star at t_star, which
|
---|
37 | // equals DISCOUNT_FACTOR - DEADLINE_MARGIN
|
---|
38 | double INITIAL_TARGET_UTILITY = 0.995;
|
---|
39 |
|
---|
40 | // regression
|
---|
41 | int NUM_INTERVALS = 100; // we take one sample per interval.
|
---|
42 | double WINDOW_SIZE = 0.1; // we look only at a certain number of intervals
|
---|
43 | // in the past. e.g. if num intervals is 100 and
|
---|
44 | // window size is 0.1, then the window consists
|
---|
45 | // of 10 intervals.
|
---|
46 | int MiN_NUM_SAMPLES = 5; // the minimum numbers of samples we need before
|
---|
47 | // doing regression.
|
---|
48 |
|
---|
49 | // storage
|
---|
50 | final int MAX_CAPACITY = 2 * 1000; // maximum size to avoid decrease in
|
---|
51 | // performance.
|
---|
52 | final int MAX_SIZE_AFTER_CLEANING = 2 * 250; // 2 times the minimum size we
|
---|
53 | // need to maintain good
|
---|
54 | // results.
|
---|
55 | final int EXPECTED_NUM_PROPOSALS = 180 * 100; // the number of proposals we
|
---|
56 | // expect to receive during
|
---|
57 | // the entire negotiation.
|
---|
58 |
|
---|
59 | // genetic algorithm
|
---|
60 | final int INIT_GENERATION_SIZE = 120; // the size of the initial generation.
|
---|
61 | final int NUM_SURVIVORS = 10; // the number of samples that survive from
|
---|
62 | // each generation.
|
---|
63 | int MAX_NUM_GENERATIONS = 10; // the maximum number of generations befor the
|
---|
64 | // gen alg returns.
|
---|
65 | int MIN_DISTANCE = 1; // the minimum distance between any pair of elements
|
---|
66 | // in a survivor set.
|
---|
67 |
|
---|
68 | String name = "Gangster";
|
---|
69 | String version = "1.0";
|
---|
70 |
|
---|
71 | List<Issue> issues;
|
---|
72 | Bid latestReceivedBid;
|
---|
73 | double latestReceivedUtility;
|
---|
74 | int numProposalsReceived = 0;
|
---|
75 |
|
---|
76 | GenAlg genAlg;
|
---|
77 | BidStorage bidStorage;
|
---|
78 |
|
---|
79 | ArrayList<BidDetails> globalSearchResults = null;
|
---|
80 | int nextSelfishBidToPropose = 0;
|
---|
81 | int maxDistance;
|
---|
82 |
|
---|
83 | private int numGoodResultsFromLocalSearch;
|
---|
84 | private ExtendedBidDetails lastProposedByUs;
|
---|
85 |
|
---|
86 | /**
|
---|
87 | * init is called when a next session starts with the same opponent.
|
---|
88 | */
|
---|
89 | @Override
|
---|
90 | public void init() {
|
---|
91 |
|
---|
92 | try {
|
---|
93 |
|
---|
94 | // 0. Make sure it works in linear cases ;)
|
---|
95 | if (!(utilitySpace instanceof NonlinearUtilitySpace)) {
|
---|
96 | return;
|
---|
97 | }
|
---|
98 |
|
---|
99 | issues = utilitySpace.getDomain().getIssues();
|
---|
100 |
|
---|
101 | RESERVATION_VALUE = utilitySpace.getReservationValueUndiscounted();
|
---|
102 | NUM_ISSUES = issues.size();
|
---|
103 | DISCOUNT_FACTOR = utilitySpace.getDiscountFactor();
|
---|
104 |
|
---|
105 | // set the initial maxDistance;
|
---|
106 | maxDistance = (int) Math.round(1.5 * NUM_ISSUES);
|
---|
107 | numGoodResultsFromLocalSearch = 0;
|
---|
108 |
|
---|
109 | bidStorage = new BidStorage(MAX_CAPACITY, MAX_SIZE_AFTER_CLEANING,
|
---|
110 | EXPECTED_NUM_PROPOSALS);
|
---|
111 |
|
---|
112 | if (utilitySpace instanceof NonlinearUtilitySpace) {
|
---|
113 | genAlg = new GenAlg((NonlinearUtilitySpace) utilitySpace,
|
---|
114 | INIT_GENERATION_SIZE, NUM_SURVIVORS,
|
---|
115 | MAX_NUM_GENERATIONS, MIN_DISTANCE);
|
---|
116 |
|
---|
117 | }
|
---|
118 | } catch (Exception e) {
|
---|
119 |
|
---|
120 | }
|
---|
121 | }
|
---|
122 |
|
---|
123 | @Override
|
---|
124 | public void ReceiveMessage(Action opponentAction) {
|
---|
125 |
|
---|
126 | try {
|
---|
127 |
|
---|
128 | // update history
|
---|
129 | if (opponentAction instanceof Offer) { // NOTE: an offer is a bid,
|
---|
130 | // together with the id of
|
---|
131 | // the agent that made the
|
---|
132 | // offer.
|
---|
133 |
|
---|
134 | double time = timeline.getTime();
|
---|
135 |
|
---|
136 | // store the bid and its utility, this is necessary in case we
|
---|
137 | // want to accept it.
|
---|
138 | latestReceivedBid = ((Offer) opponentAction).getBid();
|
---|
139 | latestReceivedUtility = utilitySpace
|
---|
140 | .getUtility(latestReceivedBid);
|
---|
141 |
|
---|
142 | // 0. Make sure it works in linear cases ;)
|
---|
143 | if (!(utilitySpace instanceof NonlinearUtilitySpace)) {
|
---|
144 | return;
|
---|
145 | }
|
---|
146 |
|
---|
147 | numProposalsReceived++;
|
---|
148 |
|
---|
149 | if (latestReceivedUtility > RESERVATION_VALUE) {
|
---|
150 | BidDetails bd = new BidDetails(latestReceivedBid,
|
---|
151 | latestReceivedUtility, time);
|
---|
152 | bidStorage.addOpponentBid(bd);
|
---|
153 | }
|
---|
154 |
|
---|
155 | }
|
---|
156 |
|
---|
157 | } catch (Exception e) {
|
---|
158 |
|
---|
159 | latestReceivedUtility = 0;
|
---|
160 | }
|
---|
161 |
|
---|
162 | }
|
---|
163 |
|
---|
164 | @Override
|
---|
165 | public Action chooseAction() {
|
---|
166 |
|
---|
167 | try {
|
---|
168 |
|
---|
169 | // 0. Make sure it works in linear cases ;)
|
---|
170 | if (!(utilitySpace instanceof NonlinearUtilitySpace)) {
|
---|
171 |
|
---|
172 | if (latestReceivedUtility > 0.8) {
|
---|
173 | return new Accept(getAgentID(), latestReceivedBid);
|
---|
174 | }
|
---|
175 |
|
---|
176 | Bid returnBid = utilitySpace.getDomain().getRandomBid(null);
|
---|
177 | return new Offer(getAgentID(), returnBid);
|
---|
178 | }
|
---|
179 |
|
---|
180 | // 1. Get current time (value between 0 and 1, where 1 represents
|
---|
181 | // the deadline).
|
---|
182 | double time = timeline.getTime();
|
---|
183 |
|
---|
184 | // 2. Calculate the minimum utility we are going to demand this
|
---|
185 | // turn.
|
---|
186 | // get the best bid proposed so far by opponent, in the past time n
|
---|
187 | // time units.
|
---|
188 | double ourTargetUtility = getTargetUtility(time,
|
---|
189 | DISCOUNT_FACTOR - DEADLINE_MARGIN);
|
---|
190 |
|
---|
191 | bidStorage.setTargetUtility(ourTargetUtility);
|
---|
192 |
|
---|
193 | if (latestReceivedUtility >= ourTargetUtility) {
|
---|
194 |
|
---|
195 | // ACCEPT BID
|
---|
196 | return new Accept(getAgentID(), latestReceivedBid);
|
---|
197 |
|
---|
198 | }
|
---|
199 |
|
---|
200 | // 3. Get the maximum distance to the latest bid from the opponent.
|
---|
201 | maxDistance = getMaxDistance(time, maxDistance,
|
---|
202 | numGoodResultsFromLocalSearch);
|
---|
203 |
|
---|
204 | // 4. Do global search. Repeat it until we have found something
|
---|
205 | // selfish enough.
|
---|
206 | while (!bidStorage.weHaveSelfishEnoughBids()) {
|
---|
207 |
|
---|
208 | ArrayList<BidDetails> globalSearchResults = genAlg
|
---|
209 | .globalSearch();
|
---|
210 |
|
---|
211 | bidStorage.addAll(globalSearchResults, false);
|
---|
212 |
|
---|
213 | // recalculate target utility.
|
---|
214 |
|
---|
215 | ourTargetUtility = getTargetUtility(timeline.getTime(),
|
---|
216 | DISCOUNT_FACTOR - DEADLINE_MARGIN);
|
---|
217 |
|
---|
218 | bidStorage.setTargetUtility(ourTargetUtility);
|
---|
219 |
|
---|
220 | }
|
---|
221 |
|
---|
222 | // 5. Do local search.
|
---|
223 | // initiate a genetic algorithm that searches within the allowed
|
---|
224 | // space.
|
---|
225 | // the returned values are always altruistic enough so we don't need
|
---|
226 | // to repeat this.
|
---|
227 | if (latestReceivedBid != null) {
|
---|
228 |
|
---|
229 | ArrayList<BidDetails> localSearchResults = genAlg
|
---|
230 | .localSearch(latestReceivedBid, maxDistance);
|
---|
231 |
|
---|
232 | // count how many bids we have found that are both selfish
|
---|
233 | // enough and altruistic enough. Note that we already know they
|
---|
234 | // must be altruistic enough, so
|
---|
235 | // We only need to test wether they are selfish enough.
|
---|
236 | numGoodResultsFromLocalSearch = 0;
|
---|
237 | for (BidDetails bd : localSearchResults) {
|
---|
238 | if (bd.getMyUndiscountedUtil() > 0.9 * ourTargetUtility) {
|
---|
239 | numGoodResultsFromLocalSearch++;
|
---|
240 | }
|
---|
241 | }
|
---|
242 |
|
---|
243 | bidStorage.addAll(localSearchResults, true);
|
---|
244 | }
|
---|
245 |
|
---|
246 | // 6. Get the best bid of all possible bids in storage
|
---|
247 | ExtendedBidDetails nextBid = bidStorage.getNext(ourTargetUtility,
|
---|
248 | maxDistance);
|
---|
249 |
|
---|
250 | if (nextBid == null) {
|
---|
251 | proposeOrAccept(time, lastProposedByUs, ourTargetUtility);
|
---|
252 | }
|
---|
253 |
|
---|
254 | // 7. Propose it, or accept an earlier proposal from the opponent
|
---|
255 | return proposeOrAccept(time, nextBid, ourTargetUtility);
|
---|
256 |
|
---|
257 | } catch (Exception e) {
|
---|
258 |
|
---|
259 | if (lastProposedByUs == null || lastProposedByUs.bidDetails == null
|
---|
260 | || lastProposedByUs.bidDetails.getBid() == null) {
|
---|
261 | return new Offer(getAgentID(),
|
---|
262 | utilitySpace.getDomain().getRandomBid(null));
|
---|
263 | }
|
---|
264 |
|
---|
265 | return new Offer(getAgentID(),
|
---|
266 | lastProposedByUs.bidDetails.getBid());
|
---|
267 |
|
---|
268 | }
|
---|
269 |
|
---|
270 | }
|
---|
271 |
|
---|
272 | private int getMaxDistance(double time, int previousValue,
|
---|
273 | int numSelfishAndAltruisticBids) {
|
---|
274 |
|
---|
275 | if (numSelfishAndAltruisticBids > DECREASE_THRESHOLD
|
---|
276 | && previousValue > MINIMAL_MAX_DISTANCE) {
|
---|
277 | return previousValue - DECREASE_AMOUNT;
|
---|
278 | } else {
|
---|
279 | return previousValue;
|
---|
280 | }
|
---|
281 |
|
---|
282 | }
|
---|
283 |
|
---|
284 | /**
|
---|
285 | * Compares my bid with the latest received proposal from the opponent and
|
---|
286 | * converts the best one of the two in an Action, which is returned.
|
---|
287 | *
|
---|
288 | * @param myExtendedBid
|
---|
289 | * @return
|
---|
290 | * @throws Exception
|
---|
291 | */
|
---|
292 | Action proposeOrAccept(double time, ExtendedBidDetails myExtendedBid,
|
---|
293 | double ourTargetUtility) throws Exception {
|
---|
294 |
|
---|
295 | BidDetails earlierProposal = bidStorage.getReproposableBid(time,
|
---|
296 | ourTargetUtility, (1 - time) + 0.01);
|
---|
297 |
|
---|
298 | if (earlierProposal != null) {
|
---|
299 |
|
---|
300 | // repropose the bid
|
---|
301 | bidStorage.addBidProposedByUs(earlierProposal.getBid());
|
---|
302 | return new Offer(getAgentID(), earlierProposal.getBid());
|
---|
303 |
|
---|
304 | } else {
|
---|
305 |
|
---|
306 | this.lastProposedByUs = myExtendedBid;
|
---|
307 |
|
---|
308 | bidStorage.addBidProposedByUs(myExtendedBid.bidDetails.getBid());
|
---|
309 |
|
---|
310 | // remove the bid from the list of candidates to propose. This way
|
---|
311 | // we keep the storage clean, cause we know we will never propose it
|
---|
312 | // again anyway.
|
---|
313 | bidStorage.removeBid(myExtendedBid);
|
---|
314 |
|
---|
315 | return new Offer(getAgentID(), myExtendedBid.bidDetails.getBid());
|
---|
316 | }
|
---|
317 |
|
---|
318 | }
|
---|
319 |
|
---|
320 | double previousCalculationTime = 0; // the time at which we did the previous
|
---|
321 | // calculation of the target utility.
|
---|
322 | double previousTarget = INITIAL_TARGET_UTILITY; // the previous value of the
|
---|
323 | // target utility
|
---|
324 |
|
---|
325 | double getTargetUtility(double time, double t_star) {
|
---|
326 |
|
---|
327 | double u_star = bidStorage.getBestOfferedUtility(time,
|
---|
328 | (1 - time) + 0.01);
|
---|
329 |
|
---|
330 | if (time < t_star) {
|
---|
331 | return getTargetUtility1(time, t_star, u_star);
|
---|
332 | } else {
|
---|
333 | return u_star;
|
---|
334 | }
|
---|
335 |
|
---|
336 | }
|
---|
337 |
|
---|
338 | double getTargetUtility1(double time, double t_star, double u_star) {
|
---|
339 |
|
---|
340 | double high = 0.5 * (1 + u_star); // half-way between bestProposedSoFar
|
---|
341 | // and 1.
|
---|
342 | // double low = 0.5* (u_star + RESERVATION_VALUE); //half-way between
|
---|
343 | // bestProposedSoFar and rv.
|
---|
344 | double low = u_star;
|
---|
345 |
|
---|
346 | double finalTargetUtility = (high - low)
|
---|
347 | * Math.pow((t_star - time), 0.3) + low;
|
---|
348 |
|
---|
349 | // calculate which part of the interval has passed since last
|
---|
350 | // calculation
|
---|
351 | double ratio = (t_star - time) / (t_star - previousCalculationTime);
|
---|
352 |
|
---|
353 | // target utility decreases linearly from the previous value to the
|
---|
354 | // final value
|
---|
355 | double currentTargetUtility = ratio
|
---|
356 | * (previousTarget - finalTargetUtility) + finalTargetUtility;
|
---|
357 |
|
---|
358 | // System.out.println("Current target utility: " +
|
---|
359 | // currentTargetUtility);
|
---|
360 |
|
---|
361 | // reset these two values for the next calculation.
|
---|
362 | previousCalculationTime = time;
|
---|
363 | previousTarget = currentTargetUtility;
|
---|
364 |
|
---|
365 | return currentTargetUtility;
|
---|
366 | }
|
---|
367 |
|
---|
368 | @Override
|
---|
369 | public String getName() {
|
---|
370 |
|
---|
371 | return name;
|
---|
372 | }
|
---|
373 |
|
---|
374 | @Override
|
---|
375 | public String getVersion() {
|
---|
376 | return version;
|
---|
377 | }
|
---|
378 |
|
---|
379 | @Override
|
---|
380 | public String getDescription() {
|
---|
381 | return "ANAC2014 compatible with non-linear utility spaces";
|
---|
382 | }
|
---|
383 |
|
---|
384 | }
|
---|