source: anac2021/dicehaggler/src/main/java/geniusweb/exampleparties/learningagent/LearningAgent.java@ 14

Last change on this file since 14 was 14, checked in by wouter, 3 years ago

#2 ANAC2021 parties received from Bram

File size: 13.9 KB
Line 
1package geniusweb.exampleparties.learningagent; // TODO: change name
2
3import java.io.File;
4import java.io.IOException;
5import java.math.BigInteger;
6import java.util.ArrayList;
7import java.util.Arrays;
8import java.util.Collections;
9import java.util.HashSet;
10import java.util.List;
11import java.util.Random;
12import java.util.logging.Level;
13
14import geniusweb.actions.FileLocation;
15
16import java.util.UUID;
17import geniusweb.actions.Accept;
18import geniusweb.actions.Action;
19import geniusweb.actions.LearningDone;
20import geniusweb.actions.Offer;
21import geniusweb.actions.PartyId;
22import geniusweb.bidspace.AllBidsList;
23import geniusweb.inform.ActionDone;
24import geniusweb.inform.Agreements;
25import geniusweb.inform.Finished;
26import geniusweb.inform.Inform;
27import geniusweb.inform.Settings;
28import geniusweb.inform.YourTurn;
29import geniusweb.issuevalue.Bid;
30import geniusweb.party.Capabilities;
31import geniusweb.party.DefaultParty;
32import geniusweb.profile.Profile;
33import geniusweb.profile.utilityspace.UtilitySpace;
34import geniusweb.profileconnection.ProfileConnectionFactory;
35import geniusweb.profileconnection.ProfileInterface;
36import geniusweb.progress.Progress;
37import geniusweb.progress.ProgressRounds;
38import geniusweb.references.Parameters;
39import tudelft.utilities.logging.Reporter;
40
41import com.fasterxml.jackson.databind.ObjectMapper;
42
43public class LearningAgent extends DefaultParty { // TODO: change name
44
45 private Bid lastReceivedBid = null;
46 private PartyId me;
47 private final Random random = new Random();
48 protected ProfileInterface profileint = null;
49 private Progress progress;
50 private String protocol;
51 private Parameters parameters;
52 private UtilitySpace utilitySpace;
53 private PersistentState persistentState;
54 private NegotiationData negotiationData;
55 private List<File> dataPaths;
56 private File persistentPath;
57 private String opponentName;
58
59 public LearningAgent() { // TODO: change name
60 }
61
62 public LearningAgent(Reporter reporter) { // TODO: change name
63 super(reporter); // for debugging
64 }
65
66 /**
67 * This method mostly contains utility functionallity for the agent to function
68 * properly. The code that is of most interest for the ANL competition is
69 * further below and in the other java files in this directory. It does,
70 * however, not hurt to read through this code to have a better understanding of
71 * what is going on.
72 *
73 * @param info information object for agent
74 */
75 @Override
76 public void notifyChange(Inform info) {
77 try {
78 if (info instanceof Settings) {
79 // info is a Settings object that is passed at the start of a negotiation
80 Settings settings = (Settings) info;
81
82 // ID of my agent
83 this.me = settings.getID();
84
85 // The progress object keeps track of the deadline
86 this.progress = settings.getProgress();
87
88 // Protocol that is initiate for the agent
89 this.protocol = settings.getProtocol().getURI().getPath();
90
91 // Parameters for the agent (can be passed through the GeniusWeb GUI, or a
92 // JSON-file)
93 this.parameters = settings.getParameters();
94
95 // The PersistentState is loaded here (see 'PersistenData,java')
96 if (this.parameters.containsKey("persistentstate"))
97 this.persistentPath = new FileLocation(
98 UUID.fromString((String) this.parameters.get("persistentstate"))).getFile();
99 if (this.persistentPath != null && this.persistentPath.exists()) {
100 ObjectMapper objectMapper = new ObjectMapper();
101 this.persistentState = objectMapper.readValue(this.persistentPath, PersistentState.class);
102 } else {
103 this.persistentState = new PersistentState();
104 }
105
106 // The negotiation data paths are converted here from List<String> to List<File>
107 // for improved usage. For safety reasons, this is more comprehensive than
108 // normally.
109 if (this.parameters.containsKey("negotiationdata")) {
110 List<String> dataPaths_raw = (List<String>) this.parameters.get("negotiationdata");
111 this.dataPaths = new ArrayList<>();
112 for (String path : dataPaths_raw)
113 this.dataPaths.add(new FileLocation(UUID.fromString(path)).getFile());
114 }
115 if ("Learn".equals(protocol)) {
116 // We are in the learning step: We execute the learning and notify when we are
117 // done. REMEMBER that there is a deadline of 60 seconds for this step.
118 learn();
119 getConnection().send(new LearningDone(me));
120 } else {
121 // We are in the negotiation step.
122
123 // Create a new NegotiationData object to store information on this negotiation.
124 // See 'NegotiationData.java'.
125 this.negotiationData = new NegotiationData();
126
127 // Obtain our utility space, i.e. the problem we are negotiating and our
128 // preferences over it.
129 try {
130 this.profileint = ProfileConnectionFactory.create(settings.getProfile().getURI(),
131 getReporter());
132 this.utilitySpace = ((UtilitySpace) profileint.getProfile());
133 } catch (IOException e) {
134 throw new IllegalStateException(e);
135 }
136 }
137 } else if (info instanceof ActionDone) {
138 // The info object is an action that is performed by an agent.
139 Action action = ((ActionDone) info).getAction();
140
141 // Check if this is not our own action
142 if (!this.me.equals(action.getActor())) {
143 // Check if we already know who we are playing against.
144 if (this.opponentName == null) {
145 // The part behind the last _ is always changing, so we must cut it off.
146 String fullOpponentName = action.getActor().getName();
147 int index = fullOpponentName.lastIndexOf("_");
148 this.opponentName = fullOpponentName.substring(0, index);
149
150 // Add name of the opponent to the negotiation data
151 this.negotiationData.setOpponentName(this.opponentName);
152 }
153 // Process the action of the opponent.
154 processAction(action);
155 }
156 } else if (info instanceof YourTurn) {
157 // Advance the round number if a round-based deadline is set.
158 if (progress instanceof ProgressRounds) {
159 progress = ((ProgressRounds) progress).advance();
160 }
161
162 // The info notifies us that it is our turn
163 myTurn();
164 } else if (info instanceof Finished) {
165 // The info is a notification that th negotiation has ended. This Finished
166 // object also contains the final agreement (if any).
167 Agreements agreements = ((Finished) info).getAgreement();
168 processAgreements(agreements);
169
170 // Write the negotiation data that we collected to the path provided.
171 if (this.dataPaths != null && this.negotiationData != null) {
172 try {
173 ObjectMapper objectMapper = new ObjectMapper();
174 objectMapper.writerWithDefaultPrettyPrinter().writeValue(this.dataPaths.get(0),
175 this.negotiationData);
176 } catch (IOException e) {
177 throw new RuntimeException("Failed to write negotiation data to disk", e);
178 }
179 }
180
181 // Log the final outcome and terminate
182 getReporter().log(Level.INFO, "Final outcome:" + info);
183 terminate();
184 }
185 } catch (Exception e) {
186 throw new RuntimeException("Failed to handle info", e);
187 }
188 }
189
190 /** Let GeniusWeb know what protocols that agent is capable of handling */
191 @Override
192 public Capabilities getCapabilities() {
193 return new Capabilities(new HashSet<>(Arrays.asList("SAOP", "Learn")), Collections.singleton(Profile.class));
194 }
195
196 /** Terminate agent */
197 @Override
198 public void terminate() {
199 super.terminate();
200 if (this.profileint != null) {
201 this.profileint.close();
202 this.profileint = null;
203 }
204 }
205
206 /*
207 * *****************************NOTE:************************************
208 * Everything below this comment is most relevant for the ANL competition.
209 * **********************************************************************
210 */
211
212 /** Provide a description of the agent */
213 @Override
214 public String getDescription() {
215 return "This is the example party of ANL 2021. It can handle the Learn protocol and learns simple characteristics of the opponent.";
216 }
217
218 /**
219 * Processes an Action performed by the opponent.
220 *
221 * @param action
222 */
223 private void processAction(Action action) {
224 if (action instanceof Offer) {
225 // If the action was an offer: Obtain the bid and add it's value to our
226 // negotiation data.
227 this.lastReceivedBid = ((Offer) action).getBid();
228 this.negotiationData.addBidUtil(this.utilitySpace.getUtility(this.lastReceivedBid).doubleValue());
229 }
230 }
231
232 /**
233 * This method is called when the negotiation has finished. It can process the
234 * final agreement.
235 *
236 * @param agreements
237 */
238 private void processAgreements(Agreements agreements) {
239 // Check if we reached an agreement (walking away or passing the deadline
240 // results in no agreement)
241 if (!agreements.getMap().isEmpty()) {
242 // Get the bid that is agreed upon and add it's value to our negotiation data
243 Bid agreement = agreements.getMap().values().iterator().next();
244 this.negotiationData.addAgreementUtil(this.utilitySpace.getUtility(agreement).doubleValue());
245 }
246 }
247
248 /**
249 * send our next offer
250 */
251 private void myTurn() throws IOException {
252 Action action;
253 if (isGood(lastReceivedBid)) {
254 // If the last received bid is good: create Accept action
255 action = new Accept(me, lastReceivedBid);
256 } else {
257 // Obtain ist of all bids
258 AllBidsList bidspace = new AllBidsList(this.utilitySpace.getDomain());
259 Bid bid = null;
260
261 // Iterate randomly through list of bids until we find a good bid
262 for (int attempt = 0; attempt < 500 && !isGood(bid); attempt++) {
263 long i = random.nextInt(bidspace.size().intValue());
264 bid = bidspace.get(BigInteger.valueOf(i));
265 }
266
267 // Create offer action
268 action = new Offer(me, bid);
269 }
270
271 // Send action
272 getConnection().send(action);
273 }
274
275 /**
276 * The method checks if a bid is good.
277 *
278 * @param bid the bid to check
279 * @return true iff bid is good for us.
280 */
281 private boolean isGood(Bid bid) {
282 if (bid == null)
283 return false;
284
285 // Check if we already know the opponent
286 if (this.persistentState.knownOpponent(this.opponentName)) {
287 // Obtain the average of the max utility that the opponent has offered us in
288 // previous negotiations.
289 Double avgMaxUtility = this.persistentState.getAvgMaxUtility(this.opponentName);
290
291 // Request 5% more than the average max utility offered by the opponent.
292 return this.utilitySpace.getUtility(bid).doubleValue() > (avgMaxUtility * 1.05);
293 }
294
295 // Check a simple business rule
296 Boolean nearDeadline = progress.get(System.currentTimeMillis()) > 0.95;
297 Boolean acceptable = this.utilitySpace.getUtility(bid).doubleValue() > 0.7;
298 Boolean good = this.utilitySpace.getUtility(bid).doubleValue() > 0.9;
299 return (nearDeadline && acceptable) || good;
300 }
301
302 /**
303 * This method is invoked if the learning phase is started. There is now time to
304 * process previously stored data and use it to update our persistent state.
305 * This persistent state is passed to the agent again in future negotiation
306 * session. REMEMBER that there is a deadline of 60 seconds for this step.
307 */
308 private void learn() {
309 ObjectMapper objectMapper = new ObjectMapper();
310
311 // Iterate through the negotiation data file paths
312 for (File dataPath : this.dataPaths) {
313 NegotiationData negotiationData;
314 try {
315 // Load the negotiation data object of a previous negotiation
316 negotiationData = objectMapper.readValue(dataPath, NegotiationData.class);
317 } catch (IOException e) {
318 throw new RuntimeException("Negotiation data provided to learning step does not exist", e);
319 }
320
321 // Process the negotiation data in our persistent state
322 this.persistentState.update(negotiationData);
323 }
324
325 // Write the persistent state object to file
326 try {
327 objectMapper.writerWithDefaultPrettyPrinter().writeValue(this.persistentPath, this.persistentState);
328 } catch (IOException e) {
329 throw new RuntimeException("Failed to write persistent state to disk", e);
330 }
331 }
332}
Note: See TracBrowser for help on using the repository browser.