source: boa/src/main/java/geniusweb/boa/biddingstrategy/TimeDependentBiddingStrategy.java@ 21

Last change on this file since 21 was 21, checked in by bart, 4 years ago

Version 1.5.

File size: 7.9 KB
Line 
1package geniusweb.boa.biddingstrategy;
2
3import java.math.BigDecimal;
4import java.util.HashMap;
5import java.util.List;
6import java.util.concurrent.ThreadLocalRandom;
7import java.util.logging.Level;
8
9import geniusweb.actions.Accept;
10import geniusweb.actions.Action;
11import geniusweb.actions.EndNegotiation;
12import geniusweb.actions.Offer;
13import geniusweb.actions.PartyId;
14import geniusweb.boa.BoaState;
15import geniusweb.inform.Settings;
16import geniusweb.issuevalue.Bid;
17import geniusweb.profile.Profile;
18import geniusweb.profile.utilityspace.LinearAdditive;
19import tudelft.utilities.immutablelist.ImmutableList;
20
21/**
22 * This is an abstract class used to implement a TimeDependentAgent Strategy
23 * adapted from S. Shaheen Fatima Michael Wooldridge Nicholas R. Jennings
24 * Optimal Negotiation Strategies for Agents with Incomplete Information
25 * http://eprints.ecs.soton.ac.uk/6151/1/atal01.pdf
26 * <p>
27 * Required: the profile is {@link LinearAdditive}. Does not currently handle
28 * profile changes.
29 * <p>
30 * As basis, the original Genius'
31 * negotiator.boaframework.offeringstrategy.other.GeniusTimeDependent_Offering
32 * was used. However that seems to ignore the reservation value. This was fixed
33 * here.
34 * <p>
35 * The default strategy was extended to enable the usage of opponent models.
36 * <p>
37 * The time-dependent utility target function is f(t) = k + (1.0 - k) *
38 * Math.pow((t - startTime) / (1.0 - startTime), 1.0 / e). The utility target is
39 * then set at min+(max-min)*f(t) where the default values for min = either the
40 * utility of the reservation bid or the absolute minimum utility of the
41 * profile, and default for max the maximum attainable utility.
42 * <p>
43 *
44 * Parameters:
45 * <ul>
46 * <li>e: see {@link #getE(BoaState)}
47 * <li>k: see {@link #getK(BoaState)}
48 * <li>min: see {@link #getMin(BoaState)}.
49 * <li>max: see {@link #getMax(BoaState)}
50 * </ul>
51 */
52public class TimeDependentBiddingStrategy implements BiddingStrategy {
53 // bidSpace=null means we're not yet initialized.
54 private ExtendedUtilSpace bidSpace = null;
55 private Double e, k, min, max; // min, max attainable utility
56 private PartyId me;
57
58 @Override
59 public Action getAction(BoaState state) {
60 if (bidSpace == null) {
61 init(state);
62 }
63
64 double utilityGoal = p(
65 state.getProgress().get(System.currentTimeMillis()));
66
67 // if there is no opponent model available
68 ImmutableList<Bid> bidOptions = bidSpace
69 .getBids((BigDecimal.valueOf(utilityGoal)));
70
71 if (bidOptions.size().intValue() == 0) {
72 // should not happen, emergency exit
73 state.getReporter().log(Level.WARNING,
74 "No viable bids found around current utility target");
75 Bid lastBid = getLastBid(state.getActionHistory());
76 if (lastBid == null)
77 return new EndNegotiation(me);
78 return new Accept(me, lastBid);
79 }
80 Bid pickedBid = bidOptions.get(ThreadLocalRandom.current()
81 .nextInt(bidOptions.size().intValue()));
82 return new Offer(me, pickedBid);
83
84 }
85
86 /**
87 * Overrideable for hard configuring this component.
88 *
89 * @param state the {@link BoaState}
90 * @return the parameter e for the time depemdency function
91 * {@link #f(double)}. The parameter is 1 by default, or the value
92 * for the "e" parameter in the {@link Settings} if available.
93 */
94 protected Double getE(BoaState state) {
95 HashMap<String, Object> params = state.getSettings().getParameters();
96 Double e = 1d;
97 if (params.containsKey("e")) {
98 e = (Double) params.get("e");
99 if (e < 0 || e > 1)
100 throw new IllegalArgumentException(
101 "e must be in [0,1] but got " + this.e);
102 }
103 return e;
104 }
105
106 /**
107 * Overrideable for hard configuring this component.
108 *
109 * @param state the {@link BoaState}
110 * @return the parameter k for the time depemdency function
111 * {@link #f(double)}. The parameter is 0 by default, or the value
112 * for the "k" parameter in the {@link Settings} if available.
113 */
114 protected Double getK(BoaState state) {
115 HashMap<String, Object> params = state.getSettings().getParameters();
116 Double k = 0d; // default
117 if (params.containsKey("k")) {
118 k = (Double) params.get("k");
119 if (k < 0 || k > 1)
120 throw new IllegalArgumentException(
121 "k must be in [0,1] but got " + this.e);
122 }
123 return k;
124 }
125
126 /**
127 * Assumes {@link #bidSpace} has been initialized.
128 * <p>
129 * Overrideable for hard configuring this component.
130 *
131 * @param state the {@link BoaState}
132 * @return the min value for {@link #p(double)}. We use the "min" parameter
133 * in the {@link Settings} if available. If not available, the
134 * parameter is computed as the utility of the reservation bid. If
135 * there is no reservation bid, we use the minimum utility of the
136 * available profile.
137 */
138 protected Double getMin(BoaState state) {
139 HashMap<String, Object> params = state.getSettings().getParameters();
140 if (params.containsKey("min")) {
141 return Math.max(0f, Math.min(1f, (Double) params.get("min")));
142 }
143 LinearAdditive profile = (LinearAdditive) state.getProfile();
144 if (profile.getReservationBid() != null) {
145 return profile.getUtility(profile.getReservationBid())
146 .doubleValue();
147 }
148
149 return bidSpace.getMin().doubleValue();
150 }
151
152 /**
153 * Assumes {@link #bidSpace} has been initialized.
154 * <p>
155 * Overrideable for hard configuring this component.
156 *
157 * @param state the {@link BoaState}
158 * @return the max value for {@link #p(double)}. We use the "max" parameter
159 * in the {@link Settings} if available. If not available, we use
160 * the maximum utility of the available profile.
161 */
162 protected Double getMax(BoaState state) {
163 HashMap<String, Object> params = state.getSettings().getParameters();
164 if (params.containsKey("max")) {
165 return Math.max(0f, Math.min(1f, (Double) params.get("max")));
166 }
167 return bidSpace.getMax().doubleValue();
168
169 }
170
171 /**
172 * @return the most recent bid that was offered, or null if no offer has
173 * been done yet.
174 */
175 private Bid getLastBid(List<Action> history) {
176 for (int n = history.size() - 1; n >= 0; n--) {
177 Action action = history.get(n);
178 if (action instanceof Offer) {
179 return ((Offer) action).getBid();
180 }
181 }
182 return null;
183 }
184
185 /**
186 * initializes bidSpace
187 *
188 * @param state
189 */
190 private void init(BoaState state) {
191 this.me = state.getSettings().getID();
192 Profile prof = state.getProfile();
193 if (!(prof instanceof LinearAdditive))
194 throw new IllegalArgumentException(
195 "Requires a LinearAdditive space but got " + prof);
196 LinearAdditive profile = (LinearAdditive) prof;
197
198 this.bidSpace = getBidSpace(profile);
199 this.e = getE(state);
200 this.k = getK(state);
201 this.min = getMin(state);
202 this.max = getMax(state);
203
204 state.getReporter().log(Level.INFO,
205 "BOA biddingstrategy min util = " + this.min);
206 }
207
208 /**
209 * Makes sure the target utility with in the acceptable range according to
210 * the domain
211 *
212 * @param t the normalized current time in the negotiation, where t=9 at
213 * start of negotiation and t=1 at end of negotiation.
214 * @return double
215 */
216 private double p(double t) {
217 return this.min + (this.max - this.min) * (1.0 - f(t));
218 }
219
220 /**
221 * From the paper:
222 *
223 * A wide range of time dependent functions can be defined by varying the
224 * way in which f(t) is computed. However, functions must ensure that 0 <=
225 * f(t) <= 1, f(0) = k, and f(1) = 1.
226 *
227 * That is, the offer will always be between the value range, at the
228 * beginning it will give the initial constant and when the deadline is
229 * reached, it will offer the reservation value.
230 *
231 * @param t the normalized current time in the negotiation, where t=9 at
232 * start of negotiation and t=1 at end of negotiation.
233 * @return
234 */
235 private double f(double t) {
236 double ft = k + (1.0 - k) * Math.pow(t, 1.0 / e);
237 return ft;
238 }
239
240 /**
241 * Factory method to get the {@link ExtendedUtilSpace} helper class.
242 * Overridable eg for tests
243 *
244 * @param profile
245 *
246 * @return {@link ExtendedUtilSpace}
247 */
248 protected ExtendedUtilSpace getBidSpace(LinearAdditive profile) {
249 return new ExtendedUtilSpace(profile);
250 }
251}
Note: See TracBrowser for help on using the repository browser.