source: src/main/java/genius/core/logging/CsvLogger.java

Last change on this file was 232, checked in by Adel Magra, 5 years ago

Created a User class that implements an elicit functionality.

Created a Top_3 Agent with the BOA framework to showcase this functionality.

File size: 13.1 KB
Line 
1package genius.core.logging;
2
3import static java.lang.String.format;
4
5import java.util.List;
6
7import java.util.ArrayList;
8import java.util.Arrays;
9import java.util.Collection;
10import java.util.Collections;
11import java.util.Iterator;
12
13import java.io.Closeable;
14import java.io.File;
15import java.io.FileNotFoundException;
16import java.io.IOException;
17import java.io.PrintStream;
18
19import genius.core.Bid;
20import genius.core.analysis.MultilateralAnalysis;
21import genius.core.parties.AbstractNegotiationParty;
22import genius.core.parties.NegotiationParty;
23import genius.core.parties.NegotiationPartyInternal;
24import genius.core.protocol.MediatorProtocol;
25import genius.core.protocol.MultilateralProtocol;
26import genius.core.session.Session;
27import genius.core.utility.AbstractUtilitySpace;
28
29/**
30 * Logger interface that writes the log to a comma separated value file (.csv
31 * file) File is created upon logger interface creation and logger class should
32 * be released (i.e. log.close() to release internal file handle when done with
33 * logger). *
34 *
35 * @author David Festen
36 */
37public class CsvLogger implements Closeable {
38 // use "," for english and ";" for dutch excel readable output
39 public static final String DELIMITER = ";";
40
41 // The internal print stream used for file writing
42 PrintStream ps;
43
44 // The buffer of objects to write (we only do a write call per complete
45 // line)
46 List<Object> buffer;
47
48 // Flag to indicate if header is already printed (we will print the header
49 // only once)
50 boolean printedHeader;
51
52 /**
53 * Initializes a new instance of the CsvLogger class. Initializing this
54 * class opens a print stream, the user of the instance should take care to
55 * close (i.e. logger.close()) this instance when done.
56 *
57 * @param fileName
58 * The name of the file to log to (including the .csv extension)
59 * @throws FileNotFoundException
60 * Thrown by the PrintStream if the location is not writable.
61 */
62 public CsvLogger(String fileName) throws IOException {
63 File file = new File(fileName);
64 file.getParentFile().mkdirs();
65 ps = new PrintStream(file);
66 buffer = new ArrayList<Object>();
67
68 // Used to tell excel to handle file correctly.
69 logLine("sep=" + DELIMITER);
70 }
71
72 /**
73 * Helper method. Joins all the elements in the collection using the given
74 * delimiter. For each element the to string function is used to generate
75 * the string.
76 *
77 * @param s
78 * Collection of objects to create string of
79 * @param delimiter
80 * The delimiter used between object
81 * @return The string delimited with the given delimiter
82 */
83 public static String join(Collection<?> s, String delimiter) {
84 StringBuilder builder = new StringBuilder();
85 Iterator<?> iterator = s.iterator();
86 while (iterator.hasNext()) {
87 builder.append(iterator.next());
88 if (!iterator.hasNext()) {
89 break;
90 }
91 builder.append(delimiter);
92 }
93 return builder.toString();
94 }
95
96 /**
97 * Log a given object. This actually just adds it to the buffer, to print to
98 * file, call logLine() afterwards.
99 *
100 * @param value
101 * The object to log
102 */
103 public void log(Object value) {
104 buffer.add(value);
105 }
106
107 /**
108 * Logs a complete line to the file.
109 *
110 * @param values
111 * zero or more objects to log, using ; delimiter
112 */
113 public void logLine(Object... values) {
114 buffer.addAll(Arrays.asList(values));
115 String line = join(buffer, DELIMITER);
116 ps.println(line);
117 buffer.clear();
118 }
119
120 /**
121 * Log default session information. Seems applicable only when an agreement
122 * was reached.
123 */
124 public static String getDefaultSessionLog(Session session,
125 MultilateralProtocol protocol,
126 List<NegotiationPartyInternal> partiesint, double runTime)
127 throws Exception {
128 List<String> values = new ArrayList<String>();
129 List<NegotiationParty> parties = new ArrayList<NegotiationParty>();
130 for (NegotiationPartyInternal p : partiesint) {
131 parties.add(p.getParty());
132 }
133
134 try {
135 Bid agreement = protocol.getCurrentAgreement(session, parties);
136 values.add(format("%.3f", runTime));
137 values.add("" + (session.getRoundNumber() + 1));
138
139 // round / time
140 values.add(session.getDeadlines().toString());
141
142 // discounted and agreement
143 boolean isDiscounted = false;
144 for (NegotiationPartyInternal party : partiesint)
145 isDiscounted |= (party.getUtilitySpace().discount(1, 1) != 1);
146 values.add(agreement == null ? "No" : "Yes");
147 values.add(isDiscounted ? "Yes" : "No");
148
149 // number of agreeing parties
150 List<NegotiationParty> agents = MediatorProtocol
151 .getNonMediators(parties);
152 values.add(
153 "" + protocol.getNumberOfAgreeingParties(session, agents));
154
155 // discounted min and max utility
156 List<Double> utils = getUtils(partiesint, agreement, true);
157 values.add(format("%.5f", Collections.min(utils)));
158 values.add(format("%.5f", Collections.max(utils)));
159
160 // analysis (distances, social welfare, etc)
161 MultilateralAnalysis analysis = new MultilateralAnalysis(partiesint,
162 protocol.getCurrentAgreement(session, parties),
163 session.getTimeline().getTime());
164 values.add(format("%.5f", analysis.getDistanceToPareto()));
165 values.add(format("%.5f", analysis.getDistanceToNash()));
166 values.add(format("%.5f", analysis.getSocialWelfare()));
167
168 // enumerate agents names, utils, protocols
169 for (NegotiationPartyInternal agent : partiesint)
170 values.add("" + agent);
171 for (double util : utils)
172 values.add(format("%.5f", util));
173 for (NegotiationPartyInternal agent : partiesint) {
174 String name = "-";
175 if (agent.getUtilitySpace() instanceof AbstractUtilitySpace) {
176 name = stripPath(
177 ((AbstractUtilitySpace) agent.getUtilitySpace())
178 .getFileName());
179 }
180 values.add(name);
181
182 }
183
184 } catch (Exception e) {
185 values.add("EXCEPTION OCCURRED");
186 }
187
188 return join(values, DELIMITER);
189 }
190
191 /**
192 * @param parties
193 * the parties in the nego
194 * @param agreement
195 * the reached agreement, or null if there was no agreement.
196 * @param discount
197 * true iff you want the discounted utilities.
198 * @return list with (possibly discounted) utilities/res value of each of
199 * the parties. Res value is only used if agreement=null.
200 *
201 */
202 public static List<Double> getUtils(List<NegotiationPartyInternal> parties,
203 Bid agreement, boolean discount) {
204 List<Double> utils = new ArrayList<Double>();
205 double time = 0;
206
207 if (parties.size() > 0) {
208 time = parties.get(0).getTimeLine().getTime();
209 }
210
211 for (NegotiationPartyInternal agent : parties) {
212 double util = getUtil(agent, agreement);
213 if (discount) {
214 util = agent.getUtilitySpace().discount(util, time);
215 }
216 utils.add(util);
217 }
218 return utils;
219 }
220
221 /**
222 * Asks the parties themselves for the perceived utilties; this may yield a
223 * different number from the real utilities specified by
224 * {@link NegotiationPartyInternal} in case of preference uncertainty.
225 */
226 public static List<Double> getPerceivedUtils(
227 List<NegotiationPartyInternal> parties, Bid agreement,
228 boolean discount) {
229 List<Double> utils = new ArrayList<Double>();
230 double time = 0;
231 if (parties.size() > 0) {
232 time = parties.get(0).getTimeLine().getTime();
233 }
234
235 for (NegotiationPartyInternal agent : parties) {
236 NegotiationParty party = agent.getParty();
237 if (party instanceof AbstractNegotiationParty) {
238 double util = ((AbstractNegotiationParty) party)
239 .getUtility(agreement);
240 if (discount)
241 util = agent.getUtilitySpace().discount(util, time);
242 utils.add(util);
243 } else
244 utils.add(0.);
245 }
246 return utils;
247 }
248
249 /**
250 * Returns a list of the user bothers
251 */
252
253 public static List<Double> getUserBothers(List<NegotiationPartyInternal> parties) {
254 List<Double> bothers = new ArrayList<Double>();
255 for (NegotiationPartyInternal agent : parties) {
256 double userBother = (agent.getUser() != null) ? (agent.getUser().getTotalBother()) : 0.0;
257 bothers.add(userBother);
258 }
259 return bothers;
260
261 }
262
263 /**
264 * Returns a list of the user utilities, which are just the true utilities - user bothers
265 */
266
267 public static List<Double> getUserUtilities(List<NegotiationPartyInternal> parties, Bid agreement, boolean discount) {
268
269 List<Double> userUtils = new ArrayList<Double>();
270 List<Double> utils = getUtils(parties, agreement, discount);
271 List<Double> bothers = getUserBothers(parties);
272 for(int i = 0; i < utils.size(); i++) {
273 double userUtility = (utils.get(i)>bothers.get(i)) ? utils.get(i)-bothers.get(i) : 0.0;
274 userUtils.add(userUtility);
275 }
276 return userUtils;
277
278 }
279
280
281 /**
282 *
283 * @param agent
284 * the agent for which to compute the utility
285 * @param agreement
286 * the agreement, or null if there is no agreement in which case
287 * the reservation value is used
288 * @return the undiscounted utility/reservation value of the given
289 * agreement.
290 */
291 private static double getUtil(NegotiationPartyInternal agent,
292 Bid agreement) {
293 if (agreement == null) {
294 return agent.getUtilitySpace().getReservationValue();
295 }
296 return agent.getUtility(agreement);
297 }
298
299 /**
300 *
301 * @param session
302 * @param protocol
303 * @param partiesint
304 * @param runTime
305 * @return string for the log file
306 * @throws Exception
307 */
308 public static String logSingleSession(Session session,
309 MultilateralProtocol protocol,
310 List<NegotiationPartyInternal> partiesint, double runTime)
311 throws Exception {
312
313 List<String> values = new ArrayList<String>();
314 List<NegotiationParty> parties = new ArrayList<NegotiationParty>();
315 for (NegotiationPartyInternal p : partiesint) {
316 parties.add(p.getParty());
317 }
318
319 Bid agreement = protocol.getCurrentAgreement(session, parties);
320 List<Double> utils = getUtils(partiesint, agreement, true);
321
322 double minUtil = Collections.min(utils);
323 double maxUtil = Collections.max(utils);
324
325 MultilateralAnalysis analysis = new MultilateralAnalysis(partiesint,
326 protocol.getCurrentAgreement(session, parties),
327 session.getTimeline().getTime());
328
329 // check if at least one of the util spaces is discounted.
330 boolean isDiscounted = false;
331 for (NegotiationPartyInternal party : partiesint) {
332 if (party.getUtilitySpace().discount(1, 1) != 1) {
333 isDiscounted = true;
334 }
335 }
336 values.add("Time (s):\t\t");
337 values.add("" + runTime + "\n");
338
339 values.add("Rounds:\t\t");
340 values.add("" + (session.getRoundNumber()) + "\n");
341
342 values.add("Agreement?:\t\t");
343 values.add(agreement == null ? "No\n" : "Yes\n");
344
345 values.add("Discounted?:\t\t");
346 values.add(isDiscounted ? "Yes\n" : "No\n");
347
348 values.add("Number of parties:\t\t" + protocol.getNumberOfAgreeingParties(session, parties)
349 + "\n");
350
351 values.add("Min. utility:\t\t");
352 values.add(String.format("%.5f\n", minUtil));
353
354 values.add("Max. utility:\t\t");
355 values.add(String.format("%.5f\n", maxUtil));
356
357 values.add("Distance to pareto:\t");
358 values.add(String.format("%.5f\n", analysis.getDistanceToPareto()));
359
360 values.add("Distance to Nash:\t");
361 values.add(String.format("%.5f\n", analysis.getDistanceToNash()));
362
363 values.add("Social welfare:\t\t");
364 values.add(String.format("%.5f\n", analysis.getSocialWelfare()));
365
366 values.add("Opposition:\t\t");
367 values.add(String.format("%.5f\n", analysis.getOpposition()));
368
369 // If you need this, then you should also
370 // use buildSpace(false); in MultilateralAnalysis to get actual bid
371 // contents.
372
373 // values.add("Nash point:\t\t");
374 // values.add(analysis.getNashPoint().toString() + "\n");
375 //
376 // values.add("Social Welfare point:\t");
377 // values.add(analysis.getSocialwelfarePoint().toString() + "\n");
378
379 for (int i = 0; i < partiesint.size(); i++) {
380 values.add(String.format("Agent utility:\t\t%.5f (%s)\n",
381 utils.get(i), partiesint.get(i).getID()));
382 }
383
384 double bother = 0;
385 for (int i = 0; i < partiesint.size(); i++) {
386 bother = (partiesint.get(i).getUser() != null)? partiesint.get(i).getUser().getTotalBother():0.0;
387 values.add(String.format("User bother:\t\t%.5f (%s)\n",
388 bother, partiesint.get(i).getID()));
389 }
390 double trueUtil = 0;
391 for (int i = 0; i < partiesint.size(); i++) {
392 trueUtil = (partiesint.get(i).getUser() != null)? utils.get(i)-partiesint.get(i).getUser().getTotalBother():utils.get(i);
393 trueUtil = (trueUtil>0) ? trueUtil:0.0;
394 values.add(String.format("User utility:\t\t%.5f (%s)\n",
395 trueUtil, partiesint.get(i).getID()));
396 }
397
398
399 return join(values, "");
400 }
401
402 public static String stripPath(String filenameWithPath) {
403 String[] split = filenameWithPath.split("/");
404 if (split.length < 2)
405 return filenameWithPath;
406 else
407 return split[split.length - 2] + "/" + split[split.length - 1];
408 }
409
410 /**
411 * Closes this stream and releases any system resources associated with it.
412 * If the stream is already closed then invoking this method has no effect.
413 *
414 * @throws java.io.IOException
415 * if an I/O error occurs
416 */
417 @Override
418 public void close() throws IOException {
419 ps.close();
420 }
421}
Note: See TracBrowser for help on using the repository browser.