source: ANL2022/agent007/agent007.py

Last change on this file was 75, checked in by wouter, 21 months ago

#6 added ANAC2022 parties

File size: 10.1 KB
Line 
1import logging
2import numpy as np
3from time import time
4from typing import cast
5from geniusweb.actions.Accept import Accept
6from geniusweb.actions.Action import Action
7from geniusweb.actions.Offer import Offer
8from geniusweb.actions.PartyId import PartyId
9from geniusweb.bidspace.AllBidsList import AllBidsList
10from geniusweb.inform.ActionDone import ActionDone
11from geniusweb.inform.Finished import Finished
12from geniusweb.inform.Inform import Inform
13from geniusweb.inform.Settings import Settings
14from geniusweb.inform.YourTurn import YourTurn
15from geniusweb.issuevalue.Bid import Bid
16from geniusweb.issuevalue.Domain import Domain
17from geniusweb.party.Capabilities import Capabilities
18from geniusweb.party.DefaultParty import DefaultParty
19from geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace import LinearAdditiveUtilitySpace
20from geniusweb.profileconnection.ProfileConnectionFactory import ProfileConnectionFactory
21from geniusweb.progress.ProgressTime import ProgressTime
22from geniusweb.references.Parameters import Parameters
23from tudelft_utilities_logging.ReportToLogger import ReportToLogger
24
25class agentBidHistory:
26 def __init__(self):
27 self.bidHistory = []
28
29 def addBid(self, bid, label):
30 self.bidHistory.append((bid, label))
31
32class Agent007(DefaultParty):
33 """Agent007"""
34 def __init__(self):
35 super().__init__()
36 self._profileint: LinearAdditiveUtilitySpace = None
37 self.lastOfferedBid = None
38 self.logger: ReportToLogger = self.getReporter()
39 self.logger.log(logging.INFO, "party is initialized")
40 self.me: PartyId = None
41 self.progress: ProgressTime = None
42 self.settings: Settings = None
43 self.domain: Domain = None
44 self.parameters: Parameters = None
45 self.other: str = None
46 self.storage_dir: str = None
47 self.bidHistory = None
48
49 def notifyChange(self, data: Inform):
50 """ Arg: info (Inform): Contains either a request for action or information. """
51 if isinstance(data, Settings):
52 self.settings = cast(Settings, data)
53 self.me = self.settings.getID()
54 self.progress = self.settings.getProgress()
55 self._profileint = ProfileConnectionFactory.create( # the profile contains the preferences of the agent over the domain
56 data.getProfile().getURI(), self.getReporter()
57 )
58 self.parameters = self.settings.getParameters()
59 self.storage_dir = self.parameters.get("storage_dir")
60 self.domain = self._profileint.getProfile().getDomain()
61 self._profileint.close()
62 self.rejected_bids = []
63 self.bidHistory = agentBidHistory()
64 self.issues = [issue for issue in sorted(self.domain.getIssues())]
65 self.num_values_in_issue = [self.domain.getValues(issue).size() for issue in self.issues]
66 self.bid_dict = self.bid_decode()
67
68 elif isinstance(data, ActionDone): # if opponent answered (reject or accept)
69 action: Action = data.getAction()
70 if isinstance(action, Offer): # [1] if opponent respond by reject our offer + proposed his offer
71 if self.lastOfferedBid: # if we have already proposed an offer before
72 self.rejected_bids.append(self.lastOfferedBid)
73 self.bidHistory.addBid(self.bid_encode(self.lastOfferedBid), 0) # opponent rejected our offer (negative label)
74 actor = action.getActor()
75 self.other = str(actor).rsplit("_", 1)[0] # obtain the name of the opponent, cutting of the position ID.
76 self.lastOfferedBid = cast(Offer, action).getBid()
77 self.bidHistory.addBid(self.bid_encode(self.lastOfferedBid), 1) # opponent offer (positive label)
78 else: # if [2] opponent accepted our offer
79 self.bidHistory.addBid(self.bid_encode(self.lastOfferedBid), 1) # opponent accepted our offer (positive label)
80 elif isinstance(data, YourTurn): # [3] YourTurn notifies you that it is your turn to act
81 action = self.chooseAction()
82 self.send_action(action)
83 elif isinstance(data, Finished): # [2] Finished will be send if the negotiation has ended (through agreement or deadline)
84 self.save_data()
85 self.logger.log(logging.INFO, "party is terminating:")
86 super().terminate() # terminate the agent MUST BE CALLED
87 else:
88 self.logger.log(logging.WARNING, "Ignoring unknown info " + str(data))
89
90 def send_action(self, action: Action):
91 """Sends an action to the opponent(s) """
92 self.getConnection().send(action)
93
94 def getCapabilities(self) -> Capabilities:
95 return Capabilities(set(["SAOP"]),set(["geniusweb.profile.utilityspace.LinearAdditive"]))
96
97 def getDescription(self) -> str:
98 return "Agent007 for the ANL 2022 competition"
99
100 def save_data(self):
101 """This method is called after the negotiation is finished. It can be used to store data
102 for learning capabilities. Note that no extensive calculations can be done within this method.
103 Taking too much time might result in your agent being killed, so use it for storage only.
104 """
105 data = "Data for learning (see README.md)"
106 with open(f"{self.storage_dir}/data.md", "w") as f:
107 f.write(data)
108
109 def bid_decode(self):
110 ''' perform decoding on the bid'''
111 bid_dict = {}
112 for bid in AllBidsList(self.domain):
113 bid_vals = tuple(self.domain.getValues(issue).getValues().index(bid.getValue(issue)) for issue in self.issues)
114 bid_dict[bid_vals] = bid
115 return bid_dict
116
117 def bid_encode(self, bid: Bid):
118 ''' perform One Hot Encoding on the bid'''
119 bid_vals = [self.domain.getValues(issue).getValues().index(bid.getValue(issue)) for issue in self.issues]
120 total_num_values = sum(self.num_values_in_issue)
121 ohe_vec = np.zeros(1+total_num_values) # added 1 for bias
122 ohe_vec[0] = 1.0 # the bias term
123 start = 1
124 for i in range(len(self.num_values_in_issue)):
125 ohe_vec[start + bid_vals[i]] = 1.0
126 start += self.num_values_in_issue[i]
127 return ohe_vec
128
129 def chooseAction(self):
130 ''' Choose if to accept the last offer or make a new offer
131 @return The chosen action
132 '''
133 progress = self.progress.get(time() * 1000)
134 if self.shouldAccept():
135 action = Accept(self.me, self.lastOfferedBid)
136 elif progress > 0.7: # if we have enough data
137 nextBid = self.get_bid()
138 self.lastOfferedBid = nextBid
139 action = Offer(self.me, nextBid)
140 else:
141 nextBid = self.findNextBid()
142 self.lastOfferedBid = nextBid
143 action = Offer(self.me, nextBid)
144 return action
145
146 def shouldAccept(self):
147 '''
148 @return Whether to accept the last bid or offer the nextBid
149 '''
150 progress = self.progress.get(time() * 1000)
151 if self.lastOfferedBid == None:
152 return False
153 if progress > 0.97:
154 return True
155 if progress > 0.9 and self._profileint.getProfile().getUtility(self.lastOfferedBid) > 0.5:
156 return True
157 if progress > 0.8 and self._profileint.getProfile().getUtility(self.lastOfferedBid) > 0.6:
158 return True
159 return False
160
161 def get_bid(self):
162 issue_pos = [1]+[sum(self.num_values_in_issue[:i])+1 for i in range(1, len(self.num_values_in_issue))]
163 profile = self._profileint.getProfile()
164 issue_weight = [float(profile.getWeights()[issue]) for issue in profile.getWeights()]
165 utilities = [profile.getUtilities()[issue] for issue in profile.getUtilities()]
166 issues_values = [[float(v) for v in util.getUtilities().values()] for util in utilities]
167
168 total_num_values = sum(self.num_values_in_issue)
169 offered = np.zeros(1+total_num_values) # added 1 for bias
170 for bid in self.bidHistory.bidHistory:
171 if bid[1] == 1:
172 offered = np.add(offered, bid[0])
173
174 issues_offered = [offered[v_pos: v_pos+v_len] for (v_pos, v_len) in zip(issue_pos, self.num_values_in_issue)]
175 vec = []
176 for i in range(len(self.issues)):
177 avg = sum(issue_weight) / len(issue_weight)
178 weight_ = issue_weight[i]/avg
179 avg = sum(issues_offered[i]) / len(issues_offered[i])
180 issues_offered_ = [issue_offered/avg for issue_offered in issues_offered[i]]
181 avg = (sum(issues_values[i])/len(issues_values[i]))
182 issues_values_ = [issue_value/avg for issue_value in issues_values[i]]
183 candidates = [(j,offer,val) for (j,offer,val) in zip(range(len(issues_offered_)), issues_offered_, issues_values_) if (offer >= 1 and val >= 1)]
184 if len(candidates) == 0:
185 if weight_ >= 1:
186 value_id = np.argmax(issues_values_) # select best for my agent
187 else:
188 value_id = np.argmax(issues_offered_) # select best for opponent
189 elif len(candidates) == 1:
190 value_id = candidates[0][0] # select best for both my agent and opponent
191 else:
192 values_ids, offers, values = zip(*candidates)
193 if weight_ >= 1:
194 id = np.argmax(values) # select best for my agent
195 else:
196 id = np.argmax(offers) # select best for opponent
197 value_id = values_ids[id]
198 vec.append(value_id)
199 bid = self.bid_dict[tuple(vec)]
200 return bid
201
202 def findNextBid(self):
203 '''
204 @return The next bid to offer
205 '''
206 all_bids = AllBidsList(self.domain)
207 bestBidEvaluation = 0
208 nextBid = None
209 for _ in range(500):
210 domain_size = all_bids.size()
211 id = np.random.randint(domain_size)
212 bid = all_bids.get(id)
213 bid_utility = float(self._profileint.getProfile().getUtility(bid))
214 if bid_utility >= bestBidEvaluation:
215 nextBid = bid
216 bestBidEvaluation = bid_utility
217 return nextBid
Note: See TracBrowser for help on using the repository browser.