source: src/main/java/genius/core/session/TournamentManager.java

Last change on this file was 166, checked in by Tim Baarslag, 6 years ago

RLBOA agents can listen to sessions only when training with access to partner preferences

Refined and renamed an example of a party that deals with preference uncertainty by defining a custom UtilitySpace based on the closest known bid.

File size: 12.0 KB
Line 
1package genius.core.session;
2
3import static genius.core.misc.ConsoleHelper.useConsoleOut;
4import static genius.core.misc.Time.prettyTimeSpan;
5import static java.lang.String.format;
6
7import java.util.List;
8
9import java.util.ArrayList;
10import java.util.concurrent.Callable;
11import java.util.concurrent.ExecutionException;
12import java.util.concurrent.TimeoutException;
13
14import java.io.IOException;
15import java.io.PrintStream;
16import java.lang.reflect.Constructor;
17
18import genius.core.AgentID;
19import genius.core.config.MultilateralTournamentConfiguration;
20import genius.core.events.BrokenPartyException;
21import genius.core.events.NegotiationEvent;
22import genius.core.events.SessionFailedEvent;
23import genius.core.events.TournamentEndedEvent;
24import genius.core.events.TournamentSessionStartedEvent;
25import genius.core.events.TournamentStartedEvent;
26import genius.core.exceptions.InstantiateException;
27import genius.core.exceptions.NegotiatorException;
28import genius.core.list.Tuple;
29import genius.core.listener.DefaultListenable;
30import genius.core.listener.Listenable;
31import genius.core.listener.Listener;
32import genius.core.misc.RLBOAUtils;
33import genius.core.parties.NegotiationParty;
34import genius.core.parties.NegotiationPartyInternal;
35import genius.core.parties.SessionsInfo;
36import genius.core.protocol.MultilateralProtocol;
37import genius.core.repository.MultiPartyProtocolRepItem;
38import genius.core.timeline.Timeline;
39import genius.core.tournament.SessionConfigurationList;
40import genius.core.tournament.TournamentConfiguration;
41
42/**
43 * Manages a multi-lateral tournament and makes sure that the
44 * {@link genius.core.session.SessionManager} are instantiated. It uses the
45 * configuration object which is created by the user interface and extracts
46 * individual session from configuration object which it wil pass on to the
47 * session manager.
48 *
49 * <p>
50 * Agents in a tournament must be of class {@link NegotiationParty}.
51 */
52public class TournamentManager extends Thread
53 implements Listenable<NegotiationEvent> {
54
55 /**
56 * Holds the configuration used by this tournament manager
57 */
58 private SessionConfigurationList sessionConfigurationsList;
59
60 /**
61 * Used to silence and restore console output for agents
62 */
63 PrintStream orgOut = System.out;
64 PrintStream orgErr = System.err;
65
66 /**
67 * Used for printing time related console output.
68 */
69 long start = System.nanoTime();
70
71 /**
72 * our listeners.
73 */
74 private DefaultListenable<NegotiationEvent> listeners = new DefaultListenable<>();
75
76 private SessionsInfo info;
77
78 /**
79 * Initializes a new instance of the
80 * {@link genius.core.session.TournamentManager} class. The tournament
81 * manager uses the provided configuration to find which sessions to run and
82 * how many collections of these sessions (tournaments) to run.
83 *
84 * @param config
85 * The configuration to use for this Tournament
86 * @throws InstantiateException
87 * @throws IOException
88 */
89 public TournamentManager(MultilateralTournamentConfiguration config)
90 throws IOException, InstantiateException {
91 sessionConfigurationsList = new SessionConfigurationList(config);
92 info = new SessionsInfo(getProtocol(config.getProtocolItem()),
93 config.getPersistentDataType(), config.isPrintEnabled());
94 if (sessionConfigurationsList.size().bitLength() > 31) {
95 throw new InstantiateException(
96 "Configuration results in more than 2 billion runs: "
97 + sessionConfigurationsList.size());
98 }
99
100 }
101
102 /****************** listener support *******************/
103 @Override
104 public void addListener(Listener<NegotiationEvent> listener) {
105 listeners.addListener(listener);
106 }
107
108 @Override
109 public void removeListener(Listener<NegotiationEvent> listener) {
110 listeners.removeListener(listener);
111 }
112
113 /****************** manager *****************************/
114
115 /**
116 * Runnable implementation for thread
117 */
118 @Override
119 public void run() {
120 start = System.nanoTime();
121 try {
122 this.runSessions();
123 System.out.println("Tournament completed");
124 System.out.println("------------------");
125 System.out.println("");
126 } catch (Exception e) {
127 e.printStackTrace();
128 System.out.println("Tournament exited with an error");
129 System.out.println("------------------");
130 System.out.println("");
131
132 }
133 long end = System.nanoTime();
134 System.out.println("Run finished in " + prettyTimeSpan(end - start));
135 info.close();
136 }
137
138 /**
139 * Run all sessions in the given generator.
140 *
141 * @throws ArithmeticException
142 * if number of sessions does not fit in a 32 bit int
143 */
144 private void runSessions() {
145 int sessionNumber = 0;
146 int tournamentNumber = 1;
147 int totalSessions = sessionConfigurationsList.size().intValueExact();
148 listeners.notifyChange(
149 new TournamentStartedEvent(tournamentNumber, totalSessions));
150
151 for (SessionConfiguration sessionInfo : sessionConfigurationsList) {
152 sessionNumber++;
153 listeners.notifyChange(new TournamentSessionStartedEvent(
154 sessionNumber, totalSessions));
155
156 runSingleSession1(sessionInfo);
157
158 int nDone = totalSessions * tournamentNumber + sessionNumber;
159 int nRemaining = totalSessions - nDone;
160 System.out.println(format("approx. %s remaining",
161 prettyTimeSpan(estimatedTimeRemaining(nDone, nRemaining))));
162 System.out.println("");
163
164 }
165 listeners.notifyChange(new TournamentEndedEvent());
166 }
167
168 /**
169 * Run single session and notify listeners when we're done. No throwing
170 * should occur from here.
171 *
172 * @param sessionInfo
173 * the sessionInfo for the session
174 */
175 private void runSingleSession1(final SessionConfiguration sessionInfo) {
176 List<NegotiationPartyInternal> partyList = null;
177 final Session session = new Session(sessionInfo.getDeadline(), info);
178 ExecutorWithTimeout executor = new ExecutorWithTimeout(
179 1000 * sessionInfo.getDeadline().getTimeOrDefaultTimeout());
180
181 try {
182 partyList = getPartyList(executor, sessionInfo, info, session);
183 } catch (TimeoutException | ExecutionException e) {
184 e.printStackTrace();
185 listeners.notifyChange(new SessionFailedEvent(
186 new BrokenPartyException("failed to construct agent ",
187 sessionInfo, session, e)));
188 return;// do not run any further if we don't have the agents.
189 }
190
191 runSingleSession(sessionInfo, partyList, executor);
192 }
193
194 /**
195 * Run a single session for the given parties (protocol and session are also
196 * used, but extracted from the tournament manager's configuration)
197 *
198 * @param parties
199 * the parties to run the tournament for. Must contain at least 1
200 * party. All parties must not be null.
201 *
202 */
203 private void runSingleSession(final SessionConfiguration config,
204 final List<NegotiationPartyInternal> parties,
205 final ExecutorWithTimeout executor) {
206 if (parties == null || parties.isEmpty()) {
207 throw new IllegalArgumentException(
208 "parties list doesn't contain a party");
209 }
210 for (NegotiationPartyInternal party : parties) {
211 if (party == null) {
212 throw new IllegalArgumentException(
213 "parties contains a null party:" + parties);
214 }
215 }
216
217 Session session = parties.get(0).getSession();
218
219 Timeline timeline = parties.get(0).getTimeLine();
220 session.setTimeline(timeline);
221 SessionManager sessionManager = new SessionManager(config, parties,
222 session, executor);
223 sessionManager.addListener(new Listener<NegotiationEvent>() {
224 @Override
225 public void notifyChange(NegotiationEvent data) {
226 listeners.notifyChange(data);
227 }
228 });
229 // When training, the RLBOA agents can listen to the sessions
230 if (TournamentConfiguration.getBooleanOption("accessPartnerPreferences", false))
231 RLBOAUtils.addReinforcementAgentListeners(parties, sessionManager);
232 setPrinting(false, info.isPrintEnabled());
233 sessionManager.runAndWait();
234 setPrinting(true, info.isPrintEnabled());
235 }
236
237
238 /**
239 * Generate the parties involved in the next round of the tournament
240 * generator. Assumes generator.hasNext(). <br>
241 * Checks various error cases and reports accordingly. If repository fails
242 * completely, we call System.exit(). useConsoleOut is called to disable
243 * console output while running agent code. <br>
244 *
245 * @param executor
246 * the executor to use
247 * @param config
248 * the {@link MultilateralSessionConfiguration} to use
249 * @param info
250 * the global {@link SessionsInfo}.
251 * @return list of parties for next round. May return null if one or more
252 * agents could not be created.
253 * @throws TimeoutException
254 * if we run out of time during the construction.
255 * @throws ExecutionException
256 * if one of the agents does not construct properly
257 */
258 public static List<NegotiationPartyInternal> getPartyList(
259 ExecutorWithTimeout executor,
260 final MultilateralSessionConfiguration config,
261 final SessionsInfo info, final Session session)
262 throws TimeoutException, ExecutionException {
263
264 final List<Participant> parties = new ArrayList<Participant>(
265 config.getParties());
266 if (config.getProtocol().getHasMediator()) {
267 parties.add(0, config.getMediator());
268 }
269
270 // add AgentIDs
271 final List<Tuple<AgentID, Participant>> partiesWithId = new ArrayList<>();
272 for (Participant party : parties) {
273 AgentID id = AgentID
274 .generateID(party.getStrategy().getUniqueName());
275 partiesWithId.add(new Tuple<>(id, party));
276 }
277
278 setPrinting(false, info.isPrintEnabled());
279
280 List<NegotiationPartyInternal> partieslist = new ArrayList<>();
281
282 try {
283 for (Tuple<AgentID, Participant> p : partiesWithId) {
284 executor.execute("init" + p, new Callable<Integer>() {
285 @Override
286 public Integer call()
287 throws RepositoryException, NegotiatorException {
288 partieslist.add(new NegotiationPartyInternal(
289 p.get2().getStrategy(), p.get2().getProfile(),
290 session, info, p.get1()));
291 return 0;
292 }
293 });
294 }
295 } finally {
296 setPrinting(true, info.isPrintEnabled());
297 }
298 return partieslist;
299
300 }
301
302 @Override
303 protected Object clone() throws CloneNotSupportedException {
304 return super.clone();
305 }
306
307 /**
308 * Tries to switch the console output to the preferred setting. Only
309 * possible if {@link SessionsInfo#isPrintEnabled} is true.
310 *
311 * @param isPreferablyEnabled
312 * true if we'd like to have print to stdout enabled, false if
313 * preferred disabled. Typically used in tournament where much
314 * printing is bad.
315 * @param forceEnable
316 * true if user manually set printing enabled, overriding the
317 * default.
318 */
319 private static void setPrinting(boolean isPreferablyEnabled,
320 boolean forceEnable) {
321 if (forceEnable) {
322 // if enabled, we ignore the setPrinting preferences so
323 // that all printing stays enabled.
324 return;
325 }
326 useConsoleOut(isPreferablyEnabled);
327 }
328
329 /**
330 * Calculate estimated time remaining using extrapolation
331 *
332 * @return estimation of time remaining in nano seconds
333 */
334 private double estimatedTimeRemaining(int nSessionsDone,
335 int nSessionsRemaining) {
336 long now = System.nanoTime() - start;
337 double res = nSessionsRemaining * now / (double) nSessionsDone;
338 return res;
339 }
340
341 /**
342 * Create a new instance of the Protocol object from a
343 * {@link MultiPartyProtocolRepItem}
344 *
345 * @return the created protocol.
346 * @throws InstantiateException
347 * if failure occurs while constructing the rep item.
348 */
349 public static MultilateralProtocol getProtocol(
350 MultiPartyProtocolRepItem protocolRepItem)
351 throws InstantiateException {
352
353 ClassLoader loader = ClassLoader.getSystemClassLoader();
354 Class<?> protocolClass;
355 try {
356 protocolClass = loader.loadClass(protocolRepItem.getClassPath());
357
358 Constructor<?> protocolConstructor = protocolClass.getConstructor();
359
360 return (MultilateralProtocol) protocolConstructor.newInstance();
361 } catch (Exception e) {
362 throw new InstantiateException(
363 "failed to instantiate " + protocolRepItem, e);
364 }
365
366 }
367
368}
Note: See TracBrowser for help on using the repository browser.