1 | package genius.core.parties;
|
---|
2 |
|
---|
3 | import java.util.List;
|
---|
4 |
|
---|
5 | import java.util.ArrayList;
|
---|
6 | import java.util.Map;
|
---|
7 |
|
---|
8 | import java.io.IOException;
|
---|
9 | import java.io.Serializable;
|
---|
10 |
|
---|
11 | import genius.core.AgentID;
|
---|
12 | import genius.core.Bid;
|
---|
13 | import genius.core.actions.Action;
|
---|
14 | import genius.core.actions.ActionWithBid;
|
---|
15 | import genius.core.exceptions.NegotiatorException;
|
---|
16 | import genius.core.list.ReadonlyList;
|
---|
17 | import genius.core.list.Tuple;
|
---|
18 | import genius.core.persistent.DefaultPersistentDataContainer;
|
---|
19 | import genius.core.persistent.DefaultStandardInfo;
|
---|
20 | import genius.core.persistent.PersistentDataType;
|
---|
21 | import genius.core.persistent.StandardInfo;
|
---|
22 | import genius.core.persistent.StandardInfoList;
|
---|
23 | import genius.core.repository.ParticipantRepItem;
|
---|
24 | import genius.core.repository.ProfileRepItem;
|
---|
25 | import genius.core.session.RepositoryException;
|
---|
26 | import genius.core.session.Session;
|
---|
27 | import genius.core.timeline.Timeline;
|
---|
28 | import genius.core.uncertainty.UNCERTAINTYTYPE;
|
---|
29 | import genius.core.uncertainty.UncertainPreferenceContainer;
|
---|
30 | import genius.core.uncertainty.User;
|
---|
31 | import genius.core.uncertainty.UserModel;
|
---|
32 | import genius.core.utility.AbstractUtilitySpace;
|
---|
33 | import genius.core.utility.UncertainAdditiveUtilitySpace;
|
---|
34 | import genius.core.utility.UtilitySpace;
|
---|
35 |
|
---|
36 | /**
|
---|
37 | * Only for use in the core. Keeps a NegotiationParty along with core-private
|
---|
38 | * information.
|
---|
39 | *
|
---|
40 | * @author W.Pasman 21jul15
|
---|
41 | */
|
---|
42 | public class NegotiationPartyInternal implements PartyWithUtility {
|
---|
43 |
|
---|
44 | private NegotiationParty party;
|
---|
45 | private UtilitySpace utilitySpace;
|
---|
46 | private Session session;
|
---|
47 | /**
|
---|
48 | * ID that should be unique for this party.
|
---|
49 | */
|
---|
50 | private AgentID ID;
|
---|
51 | private SessionsInfo sessionsInfo;
|
---|
52 | private ProfileRepItem profileRepItem;
|
---|
53 | private DefaultPersistentDataContainer storageMap;
|
---|
54 | private ParticipantRepItem partyRepItem;
|
---|
55 | private UncertainPreferenceContainer uncertainModel;
|
---|
56 | private User user;
|
---|
57 |
|
---|
58 | /**
|
---|
59 | * Creates a new {@link NegotiationParty} from repository items and
|
---|
60 | * initializes it.
|
---|
61 | *
|
---|
62 | * @param partyRepItem
|
---|
63 | * the party reference
|
---|
64 | * @param profileRepItem
|
---|
65 | * the profile to use for this party
|
---|
66 | * @param session
|
---|
67 | * the session in which this runs
|
---|
68 | * @param agentID
|
---|
69 | * the unique agentId to use, or null. If null, a unique ID will
|
---|
70 | * be generated. For all default implementations, this has either
|
---|
71 | * the format "ClassName" if only one such an agent exists (in
|
---|
72 | * case of mediator for example [mediator always has the name
|
---|
73 | * "mediator"]), "Party N" or it has the format "ClassName@N"
|
---|
74 | * with N a unique integer if multiple agents of the same type
|
---|
75 | * can exists.
|
---|
76 | * @param info
|
---|
77 | * a SessionsInfo object that contains info shared with other
|
---|
78 | * sessions.
|
---|
79 | * @throws RepositoryException
|
---|
80 | * @throws NegotiatorException
|
---|
81 | */
|
---|
82 | public NegotiationPartyInternal(ParticipantRepItem partyRepItem,
|
---|
83 | ProfileRepItem profileRepItem, Session session, SessionsInfo info,
|
---|
84 | AgentID agentID) throws RepositoryException, NegotiatorException {
|
---|
85 | if (agentID == null) {
|
---|
86 | throw new NullPointerException("agentID");
|
---|
87 | }
|
---|
88 | this.session = session;
|
---|
89 | this.sessionsInfo = info;
|
---|
90 | this.ID = agentID;
|
---|
91 | this.uncertainModel = uncertainModel;
|
---|
92 | init(partyRepItem, profileRepItem, session, agentID);
|
---|
93 | }
|
---|
94 |
|
---|
95 | /**
|
---|
96 | * @return the agent implementation
|
---|
97 | */
|
---|
98 | public NegotiationParty getParty() {
|
---|
99 | return party;
|
---|
100 | }
|
---|
101 |
|
---|
102 | public double getUtility(Bid bid) {
|
---|
103 | try {
|
---|
104 | // throws exception if bid incomplete or not in utility space
|
---|
105 | return bid == null ? 0 : utilitySpace.getUtility(bid);
|
---|
106 | } catch (Exception e) {
|
---|
107 | e.printStackTrace();
|
---|
108 | return 0;
|
---|
109 | }
|
---|
110 | }
|
---|
111 |
|
---|
112 | public double getUtilityWithDiscount(Bid bid) {
|
---|
113 | if (bid == null) {
|
---|
114 | // utility is null if no bid
|
---|
115 | return 0;
|
---|
116 | } else if (session.getTimeline() == null) {
|
---|
117 | // return undiscounted utility if no timeline given
|
---|
118 | return getUtility(bid);
|
---|
119 | } else {
|
---|
120 | // otherwise, return discounted utility
|
---|
121 | return utilitySpace.discount(utilitySpace.getUtility(bid),
|
---|
122 | session.getTimeline().getTime());
|
---|
123 | }
|
---|
124 |
|
---|
125 | }
|
---|
126 |
|
---|
127 | /**
|
---|
128 | * Gets the agent's utility space.
|
---|
129 | *
|
---|
130 | * @return the agent's utility space
|
---|
131 | */
|
---|
132 | @Override
|
---|
133 | public UtilitySpace getUtilitySpace() {
|
---|
134 | return utilitySpace;
|
---|
135 | }
|
---|
136 |
|
---|
137 | /**
|
---|
138 | * Gets the timeline for this agent.
|
---|
139 | *
|
---|
140 | * @return The timeline object or null if no timeline object (no time
|
---|
141 | * constraints) set
|
---|
142 | */
|
---|
143 | public Timeline getTimeLine() {
|
---|
144 | return session.getTimeline();
|
---|
145 | }
|
---|
146 |
|
---|
147 | /**
|
---|
148 | * Get the session that this party is using.
|
---|
149 | *
|
---|
150 | * @return {@link Session}.
|
---|
151 | */
|
---|
152 | public Session getSession() {
|
---|
153 | return session;
|
---|
154 | }
|
---|
155 |
|
---|
156 | @Override
|
---|
157 | public String toString() {
|
---|
158 | return ID.toString();
|
---|
159 | }
|
---|
160 |
|
---|
161 | @Override
|
---|
162 | public int hashCode() {
|
---|
163 | final int prime = 31;
|
---|
164 | int result = 1;
|
---|
165 | result = prime * result + ((party == null) ? 0 : party.hashCode());
|
---|
166 | return result;
|
---|
167 | }
|
---|
168 |
|
---|
169 | @Override
|
---|
170 | public boolean equals(Object obj) {
|
---|
171 | if (this == obj)
|
---|
172 | return true;
|
---|
173 | if (obj == null)
|
---|
174 | return false;
|
---|
175 | if (getClass() != obj.getClass())
|
---|
176 | return false;
|
---|
177 | NegotiationPartyInternal other = (NegotiationPartyInternal) obj;
|
---|
178 | if (party == null) {
|
---|
179 | if (other.party != null)
|
---|
180 | return false;
|
---|
181 | } else if (!party.equals(other.party))
|
---|
182 | return false;
|
---|
183 | return true;
|
---|
184 | }
|
---|
185 |
|
---|
186 | /************************* support functions ******************/
|
---|
187 |
|
---|
188 | /**
|
---|
189 | * Creates a new {@link NegotiationParty} from repository items and
|
---|
190 | * initializes it. This call is not sandboxed.
|
---|
191 | *
|
---|
192 | * @param partyRepItem
|
---|
193 | * Party Repository item to createFrom party from
|
---|
194 | * @param profileRepItem
|
---|
195 | * Profile Repository item to createFrom party from
|
---|
196 | * @return new Party
|
---|
197 | * @throws RepositoryException
|
---|
198 | * @throws java.lang.NoSuchMethodException
|
---|
199 | * If requested Party does not have a constructor accepting only
|
---|
200 | * preference profiles
|
---|
201 | * @throws java.lang.ClassNotFoundException
|
---|
202 | * If requested Party class can not be found.
|
---|
203 | */
|
---|
204 | private NegotiationParty init(ParticipantRepItem partyRepItem,
|
---|
205 | ProfileRepItem profileRepItem, Session session, AgentID agentID)
|
---|
206 | throws RepositoryException, NegotiatorException {
|
---|
207 | this.profileRepItem = profileRepItem;
|
---|
208 | this.partyRepItem = partyRepItem;
|
---|
209 | this.utilitySpace = profileRepItem.create();
|
---|
210 | if (!(utilitySpace instanceof AbstractUtilitySpace)) {
|
---|
211 | throw new IllegalArgumentException("utilityspace in "
|
---|
212 | + profileRepItem
|
---|
213 | + " is not extending AbstractUtilitySpace and currently not supported for negotiation parties");
|
---|
214 | }
|
---|
215 | String err = utilitySpace.isComplete();
|
---|
216 | if (err != null) {
|
---|
217 | throw new IllegalArgumentException("utilityspace in "
|
---|
218 | + profileRepItem + " is not ready to run:" + err);
|
---|
219 | }
|
---|
220 | long randomSeed = System.currentTimeMillis();
|
---|
221 | try {
|
---|
222 | party = partyRepItem.load();
|
---|
223 | } catch (Exception e) {
|
---|
224 | throw new RepositoryException("failed to load " + partyRepItem, e);
|
---|
225 | }
|
---|
226 |
|
---|
227 | getPersistentData(partyRepItem, profileRepItem);
|
---|
228 |
|
---|
229 | // Either a copy of the utility space is passed, or the estimate of the user model
|
---|
230 | if (utilitySpace instanceof UncertainAdditiveUtilitySpace)
|
---|
231 | {
|
---|
232 | this.uncertainModel = new UncertainPreferenceContainer((UncertainAdditiveUtilitySpace) utilitySpace,
|
---|
233 | UNCERTAINTYTYPE.PAIRWISECOMP);
|
---|
234 |
|
---|
235 | UserModel pairwiseCompUserModel = this.uncertainModel.getPairwiseCompUserModel();
|
---|
236 |
|
---|
237 | this.user = new User((UncertainAdditiveUtilitySpace) utilitySpace);
|
---|
238 | // put into NegoInfo
|
---|
239 |
|
---|
240 | // estimate the utility space for any NegotiationParty for backwards compatibility
|
---|
241 | // For an AbstractNegotiationParty, this is overriden in the init
|
---|
242 | AbstractUtilitySpace passedUtilitySpace = AbstractNegotiationParty.defaultUtilitySpaceEstimator(utilitySpace.getDomain(), pairwiseCompUserModel);
|
---|
243 | passedUtilitySpace.setReservationValue(utilitySpace.getReservationValue());
|
---|
244 | passedUtilitySpace.setDiscount(((AbstractUtilitySpace) utilitySpace).getDiscountFactor());
|
---|
245 |
|
---|
246 | party.init(new NegotiationInfo(passedUtilitySpace,
|
---|
247 | pairwiseCompUserModel, user,
|
---|
248 | session.getDeadlines(), session.getTimeline(), randomSeed,
|
---|
249 | agentID, storageMap));
|
---|
250 | }
|
---|
251 | else
|
---|
252 | {
|
---|
253 | // Otherwise, pass a copy of the utility space to the agent to prevent modification, with a null user model
|
---|
254 | party.init(new NegotiationInfo(
|
---|
255 | (AbstractUtilitySpace) utilitySpace.copy(), null, null,
|
---|
256 | session.getDeadlines(), session.getTimeline(), randomSeed,
|
---|
257 | agentID, storageMap));
|
---|
258 |
|
---|
259 | }
|
---|
260 | return party;
|
---|
261 | }
|
---|
262 |
|
---|
263 | /**
|
---|
264 | * Try to get the persistent storage data.
|
---|
265 | *
|
---|
266 | * @param partyRepItem
|
---|
267 | * @param profileRepItem
|
---|
268 | */
|
---|
269 | private void getPersistentData(ParticipantRepItem partyRepItem,
|
---|
270 | ProfileRepItem profileRepItem) {
|
---|
271 | PersistentDataType type = sessionsInfo.getPersistentDataType();
|
---|
272 | Serializable data = null;
|
---|
273 | switch (type) {
|
---|
274 | case SERIALIZABLE:
|
---|
275 | case STANDARD:
|
---|
276 | try {
|
---|
277 | data = sessionsInfo.getStorage(partyRepItem, profileRepItem);
|
---|
278 | } catch (Exception e) {
|
---|
279 | e.printStackTrace();
|
---|
280 | }
|
---|
281 | break;
|
---|
282 | default:
|
---|
283 | data = null;
|
---|
284 | break;
|
---|
285 | }
|
---|
286 | if (data == null && type == PersistentDataType.STANDARD) {
|
---|
287 | data = new DefaultStandardInfoList();
|
---|
288 | }
|
---|
289 |
|
---|
290 | storageMap = new DefaultPersistentDataContainer(data, type);
|
---|
291 | }
|
---|
292 |
|
---|
293 | /**
|
---|
294 | * Saves the persistent storage , see {@link SessionsInfo}.
|
---|
295 | *
|
---|
296 | * @param actions
|
---|
297 | * the actions that have been done in the last session. This is
|
---|
298 | * added to the data first, if possible.
|
---|
299 | * @param agreement
|
---|
300 | * agreement information: Bid and utility of the bid for this
|
---|
301 | * party. Null if no agreement was reached.
|
---|
302 | * @profiles a list of [AgentID, profile-of-agent] names.
|
---|
303 | *
|
---|
304 | * @throws IOException
|
---|
305 | */
|
---|
306 | public void saveStorage(List<Action> actions, Map<String, String> profiles,
|
---|
307 | Tuple<Bid, Double> agreement) throws IOException {
|
---|
308 | if (storageMap.getPersistentDataType() == PersistentDataType.DISABLED)
|
---|
309 | return;
|
---|
310 | if (storageMap.getPersistentDataType() == PersistentDataType.STANDARD) {
|
---|
311 | // update the data. bit hacky
|
---|
312 | String startingagent = actions.isEmpty() ? "-"
|
---|
313 | : actions.get(0).getAgent().toString();
|
---|
314 | DefaultStandardInfoList data = (DefaultStandardInfoList) storageMap
|
---|
315 | .get();
|
---|
316 | List<Tuple<String, Double>> utilities = new ArrayList<>();
|
---|
317 | for (Action action : actions) {
|
---|
318 | if (action instanceof ActionWithBid) {
|
---|
319 | utilities.add(new Tuple<String, Double>(
|
---|
320 | action.getAgent().toString(),
|
---|
321 | getUtility(((ActionWithBid) action).getBid())));
|
---|
322 | }
|
---|
323 | }
|
---|
324 |
|
---|
325 | data.addInternal(new DefaultStandardInfo(profiles, startingagent,
|
---|
326 | utilities, session.getDeadlines(), agreement));
|
---|
327 | }
|
---|
328 |
|
---|
329 | sessionsInfo.saveStorage(storageMap.get(), partyRepItem,
|
---|
330 | profileRepItem);
|
---|
331 | }
|
---|
332 |
|
---|
333 | /**
|
---|
334 | *
|
---|
335 | * @return true iff htis party is a {@link Mediator}.
|
---|
336 | */
|
---|
337 | public boolean isMediator() {
|
---|
338 | return party instanceof Mediator;
|
---|
339 | }
|
---|
340 |
|
---|
341 | public boolean isUncertain() {
|
---|
342 | if (uncertainModel != null)
|
---|
343 | return true;
|
---|
344 | else
|
---|
345 | return false;
|
---|
346 | }
|
---|
347 |
|
---|
348 | @Override
|
---|
349 | public AgentID getID() {
|
---|
350 | return ID;
|
---|
351 | }
|
---|
352 |
|
---|
353 | /**
|
---|
354 | *
|
---|
355 | * @return {@link UncertainPreferenceContainer} or null if the profile was
|
---|
356 | * not an {@link UncertainProfileRepItem}.
|
---|
357 | */
|
---|
358 | public UncertainPreferenceContainer getUncertainModel() {
|
---|
359 | return uncertainModel;
|
---|
360 | }
|
---|
361 |
|
---|
362 | /**
|
---|
363 | *
|
---|
364 | * @return {@link User} or null if the profile was
|
---|
365 | * not an {@link User}.
|
---|
366 | */
|
---|
367 | public User getUser() {
|
---|
368 | return user;
|
---|
369 | }
|
---|
370 |
|
---|
371 | /**
|
---|
372 | * Inner class, to prevent others casting to this. static to prevent
|
---|
373 | * serializer to serialize the superclass.
|
---|
374 | */
|
---|
375 | @SuppressWarnings("serial")
|
---|
376 | static class DefaultStandardInfoList extends ReadonlyList<StandardInfo>
|
---|
377 | implements StandardInfoList, Serializable {
|
---|
378 |
|
---|
379 | public DefaultStandardInfoList(List<StandardInfo> infos) {
|
---|
380 | super(infos);
|
---|
381 | }
|
---|
382 |
|
---|
383 | public DefaultStandardInfoList() {
|
---|
384 | super(new ArrayList<StandardInfo>());
|
---|
385 | }
|
---|
386 |
|
---|
387 | /**
|
---|
388 | * backdoor for the usual {@link #add(StandardInfo)} this can be called
|
---|
389 | * only from the encapculating class.
|
---|
390 | *
|
---|
391 | * @param e
|
---|
392 | * the item to add to the list.
|
---|
393 | */
|
---|
394 | public void addInternal(StandardInfo e) {
|
---|
395 | list.add(e);
|
---|
396 | }
|
---|
397 | }
|
---|
398 |
|
---|
399 | }
|
---|