source: exampleparties/timedependentparty/src/main/java/geniusweb/exampleparties/timedependentparty/TimeDependentParty.java@ 28

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

minor fixes to improve extendability

File size: 9.4 KB
Line 
1package geniusweb.exampleparties.timedependentparty;
2
3import java.io.IOException;
4import java.math.BigDecimal;
5import java.math.BigInteger;
6import java.math.RoundingMode;
7import java.util.Arrays;
8import java.util.Collections;
9import java.util.HashSet;
10import java.util.Random;
11import java.util.Set;
12import java.util.logging.Level;
13import java.util.stream.Collectors;
14
15import geniusweb.actions.Accept;
16import geniusweb.actions.Action;
17import geniusweb.actions.Offer;
18import geniusweb.actions.PartyId;
19import geniusweb.actions.Vote;
20import geniusweb.actions.Votes;
21import geniusweb.inform.ActionDone;
22import geniusweb.inform.Finished;
23import geniusweb.inform.Inform;
24import geniusweb.inform.OptIn;
25import geniusweb.inform.Settings;
26import geniusweb.inform.Voting;
27import geniusweb.inform.YourTurn;
28import geniusweb.issuevalue.Bid;
29import geniusweb.party.Capabilities;
30import geniusweb.party.DefaultParty;
31import geniusweb.profile.Profile;
32import geniusweb.profile.utilityspace.LinearAdditive;
33import geniusweb.profile.utilityspace.UtilitySpace;
34import geniusweb.profileconnection.ProfileConnectionFactory;
35import geniusweb.profileconnection.ProfileInterface;
36import geniusweb.progress.Progress;
37import geniusweb.progress.ProgressRounds;
38import tudelft.utilities.immutablelist.ImmutableList;
39import tudelft.utilities.logging.Reporter;
40
41/**
42 * General time dependent party. This is a simplistic implementation that does
43 * brute-force search through the bidspace and can handle bidspace sizes up to
44 * 2^31 (approx 1 billion bids). It may take excessive time and run out of time
45 * on bidspaces > 10000 bids. In special cases it may even run out of memory,
46 *
47 * <p>
48 * Supports parameters as follows
49 * <table summary="parameters">
50 * <tr>
51 * <td>e</td>
52 * <td>e determines how fast the party makes concessions with time. Typically
53 * around 1. 0 means no concession, 1 linear concession, &gt;1 faster than
54 * linear concession.</td>
55 * </tr>
56 *
57 * <tr>
58 * <td>minPower</td>
59 * <td>This value is used as minPower for placed {@link Vote}s. Default value is
60 * 1.</td>
61 * </tr>
62 *
63 * <tr>
64 * <td>maxPower</td>
65 * <td>This value is used as maxPower for placed {@link Vote}s. Default value is
66 * infinity.</td>
67 * </tr>
68 *
69 * </table>
70 * <p>
71 * TimeDependentParty requires a {@link UtilitySpace}
72 */
73public class TimeDependentParty extends DefaultParty {
74
75 private ProfileInterface profileint;
76 private LinearAdditive utilspace = null; // last received space
77 private PartyId me;
78 private Progress progress;
79 private Bid lastReceivedBid = null;
80 private ExtendedUtilSpace extendedspace;
81 private double e = 1.2;
82 private Votes lastvotes;
83 private Settings settings;
84
85 public TimeDependentParty() {
86 super();
87 }
88
89 public TimeDependentParty(Reporter reporter) {
90 super(reporter); // for debugging
91 }
92
93 @Override
94 public Capabilities getCapabilities() {
95 return new Capabilities(new HashSet<>(Arrays.asList("SAOP", "MOPAC")),
96 Collections.singleton(LinearAdditive.class));
97 }
98
99 @Override
100 public void notifyChange(Inform info) {
101 try {
102 if (info instanceof Settings) {
103 settings = (Settings) info;
104 this.profileint = ProfileConnectionFactory
105 .create(settings.getProfile().getURI(), getReporter());
106 this.me = settings.getID();
107 this.progress = settings.getProgress();
108 Object newe = settings.getParameters().get("e");
109 if (newe != null) {
110 if (newe instanceof Double) {
111 this.e = (Double) newe;
112 } else {
113 getReporter().log(Level.WARNING,
114 "parameter e should be Double but found "
115 + newe);
116 }
117 }
118 } else if (info instanceof ActionDone) {
119 Action otheract = ((ActionDone) info).getAction();
120 if (otheract instanceof Offer) {
121 lastReceivedBid = ((Offer) otheract).getBid();
122 }
123 } else if (info instanceof YourTurn) {
124 myTurn();
125 } else if (info instanceof Finished) {
126 getReporter().log(Level.INFO, "Final ourcome:" + info);
127 } else if (info instanceof Voting) {
128 lastvotes = vote((Voting) info);
129 getConnection().send(lastvotes);
130 } else if (info instanceof OptIn) {
131 getConnection().send(lastvotes);
132 }
133 } catch (Exception ex) {
134 getReporter().log(Level.SEVERE, "Failed to handle info", ex);
135 }
136 updateRound(info);
137 }
138
139 /**
140 * @return the E value that controls the party's behaviour. Depending on the
141 * value of e, extreme sets show clearly different patterns of
142 * behaviour [1]:
143 *
144 * 1. Boulware: For this strategy e &lt; 1 and the initial offer is
145 * maintained till time is almost exhausted, when the agent concedes
146 * up to its reservation value.
147 *
148 * 2. Conceder: For this strategy e &gt; 1 and the agent goes to its
149 * reservation value very quickly.
150 *
151 * 3. When e = 1, the price is increased linearly.
152 *
153 * 4. When e = 0, the agent plays hardball.
154 */
155 public double getE() {
156 return e;
157 }
158
159 @Override
160 public String getDescription() {
161 return "Time-dependent conceder. Aims at utility u(t) = scale * t^(1/e) "
162 + "where t is the time (0=start, 1=end), e is the concession speed parameter (default 1.1), and scale such that u(0)=minimum and "
163 + "u(1) = maximum possible utility. Parameters minPower (default 1) and maxPower (default infinity) are used "
164 + "when voting";
165 }
166
167 /******************* private support funcs ************************/
168
169 /**
170 * Update {@link #progress}, depending on the protocol and last received
171 * {@link Inform}
172 *
173 * @param info the received info.
174 */
175 private void updateRound(Inform info) {
176 if (settings == null) // not yet initialized
177 return;
178 String protocol = settings.getProtocol().getURI().getPath();
179
180 switch (protocol) {
181 case "SAOP":
182 case "SHAOP":
183 if (!(info instanceof YourTurn))
184 return;
185 break;
186 case "MOPAC":
187 if (!(info instanceof OptIn))
188 return;
189 break;
190 default:
191 return;
192 }
193 // if we get here, round must be increased.
194 if (progress instanceof ProgressRounds) {
195 progress = ((ProgressRounds) progress).advance();
196 }
197
198 }
199
200 private void myTurn() throws IOException {
201 updateUtilSpace();
202 Bid bid = makeBid();
203
204 Action myAction;
205 if (bid == null || (lastReceivedBid != null
206 && utilspace.getUtility(lastReceivedBid)
207 .compareTo(utilspace.getUtility(bid)) >= 0)) {
208 // if bid==null we failed to suggest next bid.
209 myAction = new Accept(me, lastReceivedBid);
210 } else {
211 myAction = new Offer(me, bid);
212 }
213 getConnection().send(myAction);
214
215 }
216
217 private LinearAdditive updateUtilSpace() throws IOException {
218 Profile newutilspace = profileint.getProfile();
219 if (!newutilspace.equals(utilspace)) {
220 utilspace = (LinearAdditive) newutilspace;
221 extendedspace = new ExtendedUtilSpace(utilspace);
222 }
223 return utilspace;
224 }
225
226 /**
227 * @return next possible bid with current target utility, or null if no such
228 * bid.
229 */
230 private Bid makeBid() {
231 double time = progress.get(System.currentTimeMillis());
232
233 BigDecimal utilityGoal = getUtilityGoal(time, getE(),
234 extendedspace.getMin(), extendedspace.getMax());
235 ImmutableList<Bid> options = extendedspace.getBids(utilityGoal);
236 if (options.size() == BigInteger.ZERO) {
237 // if we can't find good bid, get max util bid....
238 options = extendedspace.getBids(extendedspace.getMax());
239 }
240 // pick a random one.
241 return options.get(new Random().nextInt(options.size().intValue()));
242
243 }
244
245 /**
246 *
247 * @param t the time in [0,1] where 0 means start of nego and 1 the
248 * end of nego (absolute time/round limit)
249 * @param e the e value that determinses how fast the party makes
250 * concessions with time. Typically around 1. 0 means no
251 * concession, 1 linear concession, &gt;1 faster than linear
252 * concession.
253 * @param minUtil the minimum utility possible in our profile
254 * @param maxUtil the maximum utility possible in our profile
255 * @return the utility goal for this time and e value
256 */
257 protected BigDecimal getUtilityGoal(double t, double e, BigDecimal minUtil,
258 BigDecimal maxUtil) {
259
260 BigDecimal ft1 = BigDecimal.ONE;
261 if (e != 0)
262 ft1 = BigDecimal.valueOf(1 - Math.pow(t, 1 / e)).setScale(6,
263 RoundingMode.HALF_UP);
264 return minUtil.add((maxUtil.subtract(minUtil).multiply(ft1)))
265 .min(maxUtil).max(minUtil);
266 }
267
268 /**
269 * @param voting the {@link Voting} object containing the options
270 *
271 * @return our next Votes.
272 */
273 private Votes vote(Voting voting) throws IOException {
274 Object val = settings.getParameters().get("minPower");
275 // max utility requires smallest possible group/power
276 Integer minpower = (val instanceof Integer) ? (Integer) val : 1;
277 val = settings.getParameters().get("maxPower");
278 Integer maxpower = (val instanceof Integer) ? (Integer) val
279 : Integer.MAX_VALUE;
280
281 Set<Vote> votes = voting.getBids().stream().distinct()
282 .filter(offer -> isGood(offer.getBid()))
283 .map(offer -> new Vote(me, offer.getBid(), minpower, maxpower))
284 .collect(Collectors.toSet());
285 return new Votes(me, votes);
286 }
287
288 /**
289 * @param bid the bid to check
290 * @return true iff bid is good for us.
291 */
292 private boolean isGood(Bid bid) {
293 if (bid == null || profileint == null)
294 return false;
295 Profile profile;
296 try {
297 profile = profileint.getProfile();
298 } catch (IOException ex) {
299 throw new IllegalStateException(ex);
300 }
301 // the profile MUST contain UtilitySpace
302 double time = progress.get(System.currentTimeMillis());
303 return ((UtilitySpace) profile).getUtility(bid)
304 .compareTo(getUtilityGoal(time, getE(), extendedspace.getMin(),
305 extendedspace.getMax())) >= 0;
306
307 }
308}
Note: See TracBrowser for help on using the repository browser.