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

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

Voting requests now contain Offers. Fixed windows whitespace issue. Partiesserver now supports up to 8 parties simultaneously.

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