source: src/main/java/negotiator/boaframework/offeringstrategy/anac2013/InoxAgent_Offering.java

Last change on this file was 127, checked in by Wouter Pasman, 6 years ago

#41 ROLL BACK of rev.126 . So this version is equal to rev. 125

File size: 11.0 KB
Line 
1package negotiator.boaframework.offeringstrategy.anac2013;
2
3import java.io.Serializable;
4import java.util.ArrayList;
5import java.util.Iterator;
6import java.util.List;
7import java.util.Map;
8
9import genius.core.NegotiationResult;
10import genius.core.bidding.BidDetails;
11import genius.core.boaframework.NegotiationSession;
12import genius.core.boaframework.OMStrategy;
13import genius.core.boaframework.OfferingStrategy;
14import genius.core.boaframework.OpponentModel;
15import genius.core.boaframework.SortedOutcomeSpace;
16import negotiator.boaframework.offeringstrategy.anac2013.inoxAgent.SaveHelper;
17
18/**
19 * This class implements a conceding strategy that tries to choose bids that are
20 * also good for the opponent.
21 *
22 * However, if the opponent shows non-conceding behaviour, this strategy will
23 * reset to the best possible bid.
24 *
25 * Over time the window that is used to pick bids from is increased, this will
26 * happen more quickly on a discounted domain.
27 *
28 * @author Ruben van Zessen, Mariana Branco
29 */
30public class InoxAgent_Offering extends OfferingStrategy {
31
32 /** Initial size of the search window */
33 private double startSize;
34 /** Final size of the search window */
35 private double finSize;
36 /** Size of the outcome space */
37 private int outcomeSize;
38 /** Index of the bid made in the outcome space */
39 private int lastBidIndex;
40 /** Discount factor of the current domain */
41 private double discountFactor;
42 /** Median utility in the sorted outcome space */
43 private double medianutil;
44
45 /** Previously obtained utility */
46 private double prevRes;
47 /** Number of previous negotiations */
48 private int prevNegos;
49
50 /** A check for whether we made our initial concession move */
51 private boolean oneConcession = false;
52 /** A check whether the median has been set yet */
53 private boolean medianDecided = false;
54 /** A check whether the median is the true median or a saved value */
55 private boolean realmedian = true;
56
57 /** Time of the previous iteration */
58 private double lastTime = 0.0;
59 /** List of time differences between iterations */
60 private ArrayList<Double> timeList = new ArrayList<Double>();
61 /** Estimated number of rounds left in the negotiation */
62 private int roundsLeft = Integer.MAX_VALUE;
63
64 /** Outcome space */
65 private SortedOutcomeSpace outcomespace;
66 /** Best possible bid */
67 private BidDetails bestBid;
68
69 /**
70 * Empty constructor.
71 */
72 public InoxAgent_Offering() {
73 }
74
75 /**
76 * Regular constructor.
77 *
78 * Sets initial values and loads old data if available.
79 */
80 public InoxAgent_Offering(NegotiationSession negoSession, OpponentModel model, OMStrategy oms) {
81 this.negotiationSession = negoSession;
82 discountFactor = negotiationSession.getDiscountFactor();
83 outcomespace = new SortedOutcomeSpace(negotiationSession.getUtilitySpace());
84 negotiationSession.setOutcomeSpace(outcomespace);
85 List<BidDetails> alloutcomes = outcomespace.getAllOutcomes();
86 outcomeSize = alloutcomes.size();
87 startSize = 0.01 * outcomeSize;
88 finSize = 0.1 * outcomeSize;
89 this.opponentModel = model;
90 this.omStrategy = oms;
91
92 Serializable oldData = loadData();
93 if (oldData != null) {
94 SaveHelper prevData = (SaveHelper) oldData;
95 medianutil = prevData.getResult();
96 prevRes = prevData.getResult();
97 prevNegos = prevData.getNumber();
98 realmedian = false;
99 }
100 }
101
102 /**
103 * Initialization function.
104 *
105 * Does the same as the regular constructor.
106 */
107 @Override
108 public void init(NegotiationSession negoSession, OpponentModel model, OMStrategy oms,
109 Map<String, Double> parameters) throws Exception {
110
111 this.negotiationSession = negoSession;
112 discountFactor = negotiationSession.getDiscountFactor();
113 outcomespace = new SortedOutcomeSpace(negotiationSession.getUtilitySpace());
114 negotiationSession.setOutcomeSpace(outcomespace);
115 List<BidDetails> alloutcomes = outcomespace.getAllOutcomes();
116 outcomeSize = alloutcomes.size();
117 startSize = 0.01 * outcomeSize;
118 finSize = 0.1 * outcomeSize;
119 this.opponentModel = model;
120 this.omStrategy = oms;
121
122 Serializable oldData = loadData();
123 if (oldData != null) {
124 SaveHelper prevData = (SaveHelper) oldData;
125 medianutil = prevData.getResult();
126 prevRes = prevData.getResult();
127 prevNegos = prevData.getNumber();
128 realmedian = false;
129 }
130 }
131
132 /**
133 * Initially offer the best possible bid and save it's index in the outcome
134 * space.
135 */
136 @Override
137 public BidDetails determineOpeningBid() {
138 bestBid = negotiationSession.getOutcomeSpace().getMaxBidPossible();
139 lastBidIndex = 0;
140 return bestBid;
141 }
142
143 /**
144 * "Harsh conceder" bidding strategy.
145 *
146 * This bidding strategy attempts to concede to the opponent by selecting
147 * their best bids in a growing window, starting at it's own best bids. In
148 * the case that the opponent shows non-conceding behaviour, this agent
149 * "resets" it's offer.
150 */
151 @Override
152 public BidDetails determineNextBid() {
153 // Read time and receiveMessage roundsLeft estimate
154 double time = negotiationSession.getTime();
155 updateRoundsLeft(time);
156
157 // Determine median if is yet to be determined
158 if (!medianDecided || (roundsLeft <= 4 && !realmedian)) {
159 int opplocation = outcomespace.getIndexOfBidNearUtility(
160 negotiationSession.getOpponentBidHistory().getFirstBidDetails().getMyUndiscountedUtil());
161 List<BidDetails> alloutcomes = outcomespace.getAllOutcomes();
162 medianutil = alloutcomes.get((int) Math.floor(((double) opplocation) / 2)).getMyUndiscountedUtil();
163 medianDecided = true;
164 realmedian = true;
165 }
166
167 int oppHistSize = negotiationSession.getOpponentBidHistory().size();
168 BidDetails bestOppBidDetails = negotiationSession.getOpponentBidHistory()
169 .getBestDiscountedBidDetails(negotiationSession.getUtilitySpace());
170
171 // If some bid of the opponent was already good for us, make that offer
172 // again
173 if (bestOppBidDetails.getMyUndiscountedUtil() > negotiationSession.getOwnBidHistory().getWorstBidDetails()
174 .getMyUndiscountedUtil()) {
175 return bestOppBidDetails;
176 }
177
178 // if the opponent shows non-conceding behaviour, reset to our best bid
179 if (time < 0.99) {
180 if (oppNotConceding(oppHistSize)) {
181 // If we havent yet, make our initial single concession
182 if (!oneConcession) {
183 lastBidIndex = 1;
184 oneConcession = true;
185 return outcomespace.getAllOutcomes().get(1);
186 }
187 lastBidIndex = 0;
188 return bestBid;
189 // early on in the negotiation, concede according to our utility
190 } else if (time < 0.05) {
191 if (outcomespace.getAllOutcomes().get(lastBidIndex + 1)
192 .getMyUndiscountedUtil() > Math.max(
193 Math.max(medianutil,
194 negotiationSession.getOpponentBidHistory().getBestBidDetails()
195 .getMyUndiscountedUtil()),
196 negotiationSession.getUtilitySpace().getReservationValueUndiscounted())) {
197 lastBidIndex += 1;
198 return outcomespace.getAllOutcomes().get(lastBidIndex + 1);
199 } else {
200 return bestBid;
201 }
202 }
203 }
204
205 // get the outcomes in the current window
206 int lowWin = Math.max(lastBidIndex - windowSize(time), 0);
207 int upWin = lastBidIndex + windowSize(time) + 1;
208 List<BidDetails> bidWindow = outcomespace.getAllOutcomes().subList(lowWin, upWin);
209
210 // get the most fair bid from the window, according to Kalai-Smorodinsky
211 BidDetails sendBid = kalaiSmor(bidWindow, lowWin, time);
212
213 // If the opponent has at some point made a better offer than we are
214 // about to make, make that offer instead
215 if (bestOppBidDetails.getMyUndiscountedUtil() > sendBid.getMyUndiscountedUtil()) {
216 sendBid = bestOppBidDetails;
217 }
218
219 return sendBid;
220
221 }
222
223 /**
224 * Function that returns true if the opponent is not showing improvement
225 * from the lowest of its last four bids.
226 *
227 * @param oHS
228 * The size of the opponents bid history
229 */
230 private boolean oppNotConceding(int oHS) {
231 double minLastOppUtils = 1.0;
232 Iterator<BidDetails> bidIter = negotiationSession.getOpponentBidHistory().getHistory()
233 .subList(Math.max(oHS - 4, 0), oHS).iterator();
234 while (bidIter.hasNext()) {
235 double bid = bidIter.next().getMyUndiscountedUtil();
236 if (bid < minLastOppUtils) {
237 minLastOppUtils = bid;
238 }
239 }
240 return (minLastOppUtils >= negotiationSession.getOpponentBidHistory().getLastBidDetails()
241 .getMyUndiscountedUtil());
242 }
243
244 /**
245 * Calculate the size of the window that bids are evaluated in. The window
246 * size increases with time using a 20th order function in an undiscounted
247 * domain, the order decreases when discounts have more influence.
248 */
249 private int windowSize(double t) {
250 int wSize = (int) Math.ceil(startSize + (finSize - startSize) * Math.pow(t, discountFactor * 20));
251 return wSize;
252 }
253
254 /**
255 * Determines most fair bid from a list of bids, using the bid that is
256 * closest to a rotating line which converges to the Kalai-Smorodinsky line.
257 * A requirement that the offer needs to be at least 0.12 better for us is
258 * imposed as a safety measure.
259 *
260 * Also updates the lastBidIndex corresponding to the index of this bid in
261 * the outcome space.
262 */
263 private BidDetails kalaiSmor(List<BidDetails> bList, int startIndex, double t) {
264 Iterator<BidDetails> it = bList.iterator();
265 BidDetails optBid = it.next();
266 int currIndex = startIndex;
267
268 // Calculate the slope of the rotating line
269 double a;
270 if (discountFactor < 0.75) {
271 a = Math.max(Math.exp(5 - 5 * (Math.log(discountFactor) / Math.log(0.75)) * t), 1.0);
272 } else {
273 a = Math.exp(5 - 5 * t);
274 }
275
276 // Find the point closest to the line
277 while (it.hasNext()) {
278 BidDetails itBid = it.next();
279 currIndex++;
280 double itKalai = Math.min(itBid.getMyUndiscountedUtil(),
281 a * opponentModel.getBidEvaluation(itBid.getBid()));
282 double optKalai = Math.min(optBid.getMyUndiscountedUtil(),
283 a * opponentModel.getBidEvaluation(optBid.getBid()));
284 if (itKalai > optKalai
285 && itBid.getMyUndiscountedUtil() >= (opponentModel.getBidEvaluation(itBid.getBid()) + 0.12)) {
286 optBid = itBid;
287 lastBidIndex = currIndex;
288 }
289 }
290
291 return optBid;
292 }
293
294 /**
295 * Method used to estimate the number of rounds that are left by using the
296 * time between iteration for the last 10 rounds.
297 */
298 private void updateRoundsLeft(double t) {
299 timeList.add(t - lastTime);
300 lastTime = t;
301 if (timeList.size() >= 10) {
302 if (timeList.size() > 10) {
303 timeList.remove(0);
304 }
305
306 double sum = 0;
307 for (int i = 0; i < timeList.size(); i++) {
308 sum += timeList.get(i);
309 }
310 roundsLeft = (int) ((1 - t) * timeList.size() / sum);
311 }
312 }
313
314 /**
315 * Method used for saving results between sessions.
316 */
317 public void endSession(NegotiationResult result) {
318 if (result.isAgreement()) {
319 double saveRes = (prevRes * prevNegos + result.getMyDiscountedUtility()) / (prevNegos + 1);
320 storeData(new SaveHelper(saveRes, prevNegos + 1));
321 } else {
322 double saveRes = (prevRes * prevNegos + medianutil) / (prevNegos + 1);
323 storeData(new SaveHelper(saveRes, prevNegos + 1));
324 }
325 }
326
327 @Override
328 public String getName() {
329 return "2013- INOX";
330 }
331
332}
Note: See TracBrowser for help on using the repository browser.