1 | import logging
|
---|
2 | import math
|
---|
3 | import os.path
|
---|
4 | import random
|
---|
5 | import pickle
|
---|
6 | from time import time
|
---|
7 | from typing import cast
|
---|
8 | from collections import defaultdict
|
---|
9 | from typing import List
|
---|
10 | from geniusweb.profileconnection.ProfileInterface import ProfileInterface
|
---|
11 | from geniusweb.actions.Accept import Accept
|
---|
12 | from geniusweb.actions.Action import Action
|
---|
13 | from geniusweb.actions.Offer import Offer
|
---|
14 | from geniusweb.actions.PartyId import PartyId
|
---|
15 | from geniusweb.inform.ActionDone import ActionDone
|
---|
16 | from geniusweb.inform.Finished import Finished
|
---|
17 | from geniusweb.inform.Inform import Inform
|
---|
18 | from geniusweb.inform.Settings import Settings
|
---|
19 | from geniusweb.inform.YourTurn import YourTurn
|
---|
20 | from geniusweb.issuevalue.Bid import Bid
|
---|
21 | from geniusweb.bidspace.AllBidsList import AllBidsList
|
---|
22 | from geniusweb.party.Capabilities import Capabilities
|
---|
23 | from geniusweb.party.DefaultParty import DefaultParty
|
---|
24 | from geniusweb.utils import val
|
---|
25 | from geniusweb.issuevalue.Value import Value
|
---|
26 | from geniusweb.issuevalue import DiscreteValue
|
---|
27 | from geniusweb.issuevalue import NumberValue
|
---|
28 | from geniusweb.inform.Agreements import Agreements
|
---|
29 | from geniusweb.references.Parameters import Parameters
|
---|
30 | from geniusweb.profileconnection.ProfileConnectionFactory import (
|
---|
31 | ProfileConnectionFactory,
|
---|
32 | )
|
---|
33 | from geniusweb.progress.ProgressRounds import ProgressRounds
|
---|
34 |
|
---|
35 | from .utils.utils import get_ms_current_time
|
---|
36 | from .utils.pair import Pair
|
---|
37 | from .utils.persistent_data import PersistentData
|
---|
38 | from .utils.negotiation_data import NegotiationData
|
---|
39 |
|
---|
40 |
|
---|
41 | class SuperAgent(DefaultParty):
|
---|
42 | """
|
---|
43 | A Super party that places empty bids because it can't download the profile,
|
---|
44 | and accepts the first incoming offer.
|
---|
45 | """
|
---|
46 |
|
---|
47 | def __init__(self):
|
---|
48 | super().__init__()
|
---|
49 | self.getReporter().log(logging.INFO, "party is initialized")
|
---|
50 | self._last_received_bid: Bid = None
|
---|
51 | self._me = None
|
---|
52 | self._profile_interface: ProfileInterface = None
|
---|
53 | self._progress = None
|
---|
54 | self._protocol = None
|
---|
55 | self._parameters: Parameters = None
|
---|
56 | self._utility_space = None
|
---|
57 | self._domain = None
|
---|
58 | self._settings: Settings = None
|
---|
59 |
|
---|
60 | self._best_offer_bid: Bid = None
|
---|
61 | self._profile = None
|
---|
62 | self._persistent_path: str = None
|
---|
63 | self._persistent_data: PersistentData = None
|
---|
64 | # NeogtiationData
|
---|
65 | self._negotiation_data: NegotiationData = None
|
---|
66 | self._data_paths_raw: List[str] = []
|
---|
67 | # self._data_paths: List[str] = []
|
---|
68 | self._negotiation_data_paths: List[str] = []
|
---|
69 | self._opponent_name = None
|
---|
70 | self._freq_map = defaultdict()
|
---|
71 | self._avg_utility = 0.95
|
---|
72 | self._std_utility = 0.15
|
---|
73 | self._util_threshold = 0.95
|
---|
74 | self._min_utility = 0.6
|
---|
75 | self.default_alpha = 10.7
|
---|
76 | self.alpha = self.default_alpha
|
---|
77 | self.t_split = 40
|
---|
78 | self.op_counter = [0] * self.t_split
|
---|
79 | self.op_sum = [0.0] * self.t_split
|
---|
80 | self.op_threshold = [0.0] * self.t_split
|
---|
81 | self.t_phase = 0.2
|
---|
82 | self.t_social_welfare = 0.997
|
---|
83 |
|
---|
84 | self._max_bid_space_iteration = 50000
|
---|
85 | self._optimal_bid: Bid = None
|
---|
86 | self._all_bid_list: AllBidsList = None
|
---|
87 | self._sorted_bid_list: List = None
|
---|
88 | self._len_sorted_bid_list: int = 0
|
---|
89 | self._storage_dir: str = None
|
---|
90 |
|
---|
91 | def create_empty_negotiation_data(self, opponent_name):
|
---|
92 | self._negotiation_data = NegotiationData(opponent_name=opponent_name)
|
---|
93 |
|
---|
94 | def initialize_negotiation_data(self, opponent_name):
|
---|
95 | self._negotiation_data_paths = []
|
---|
96 | data_path_raw = os.path.join(self._storage_dir, f"negotiation_data_{opponent_name}.log")
|
---|
97 | self._negotiation_data_paths.append(data_path_raw)
|
---|
98 | if self._negotiation_data is not None and os.path.exists(data_path_raw):
|
---|
99 | # print("non-empty NegotiationData")
|
---|
100 | with open(data_path_raw, "rb") as negotiation_data_file:
|
---|
101 | self._negotiation_data: NegotiationData = pickle.load(negotiation_data_file)
|
---|
102 | else:
|
---|
103 | # print("empty NegotiationData")
|
---|
104 | self.create_empty_negotiation_data(opponent_name=opponent_name)
|
---|
105 |
|
---|
106 | def initialize_persistent_data(self, opponent_name):
|
---|
107 | self._persistent_path = os.path.join(self._storage_dir, f"persistent_data_{opponent_name}.log")
|
---|
108 | if self._persistent_path is not None and os.path.exists(self._persistent_path):
|
---|
109 | # json load
|
---|
110 | # print("non-empty PersistentData")
|
---|
111 | with open(self._persistent_path, "rb") as persistent_file:
|
---|
112 | self._persistent_data: PersistentData = pickle.load(persistent_file)
|
---|
113 | self._avg_utility = self._persistent_data.get_avg_utility()
|
---|
114 | self._std_utility = self._persistent_data.get_std_utility()
|
---|
115 | else:
|
---|
116 | self._persistent_data: PersistentData = PersistentData()
|
---|
117 |
|
---|
118 | def first_better_then(self, utility):
|
---|
119 | idx = None
|
---|
120 | try:
|
---|
121 | idx = next(len(self._sorted_bid_list) - 1 - x for x, val in enumerate(self._sorted_bid_list[-1::-1]) if
|
---|
122 | self.calc_utility(val) > utility)
|
---|
123 | except StopIteration:
|
---|
124 | pass
|
---|
125 | finally:
|
---|
126 | return idx
|
---|
127 |
|
---|
128 | def last_bids(self, good_bid: int):
|
---|
129 | # this session's max utility got
|
---|
130 | if self._progress.get(get_ms_current_time()) <= 0.97 and self.is_good(self._best_offer_bid):
|
---|
131 | return self._best_offer_bid
|
---|
132 | # all session's max utility got
|
---|
133 | avg_max_util = self._persistent_data.get_avg_max_utility(self._opponent_name)
|
---|
134 | if not avg_max_util:
|
---|
135 | return self._best_offer_bid
|
---|
136 | if self._progress.get(get_ms_current_time()) <= 0.99:
|
---|
137 | idx = self.first_better_then(avg_max_util)
|
---|
138 | if idx != None:
|
---|
139 | self.getReporter().log(logging.INFO, "avg_max_util: {0}, bid_utility: {1}".format(avg_max_util,
|
---|
140 | self._utility_space.getUtility(
|
---|
141 | self._sorted_bid_list[
|
---|
142 | idx])))
|
---|
143 | if self.is_good(self._sorted_bid_list[idx]):
|
---|
144 | return self._sorted_bid_list[idx]
|
---|
145 |
|
---|
146 | # last try we give him the best possible suggestion we have
|
---|
147 | if good_bid == 0:
|
---|
148 | bid = self._optimal_bid
|
---|
149 | else:
|
---|
150 | bid = max(self._sorted_bid_list[0:good_bid], key=self.calc_op_value)
|
---|
151 |
|
---|
152 | self.getReporter().log(logging.INFO, "chosen bid utility: {}".format(self._utility_space.getUtility(bid)))
|
---|
153 | return bid
|
---|
154 |
|
---|
155 | @classmethod
|
---|
156 | def parse_opponent_name(cls, full_opponent_name):
|
---|
157 | agent_index = full_opponent_name.rindex("_")
|
---|
158 | if agent_index != -1:
|
---|
159 | return full_opponent_name[:agent_index]
|
---|
160 | return None
|
---|
161 |
|
---|
162 | def initialize_storage(self, opponent_name):
|
---|
163 | if self._storage_dir is not None:
|
---|
164 | self.initialize_persistent_data(opponent_name=opponent_name)
|
---|
165 | self.initialize_negotiation_data(opponent_name=opponent_name)
|
---|
166 | else:
|
---|
167 | self.create_empty_negotiation_data(opponent_name=opponent_name)
|
---|
168 | self._persistent_data: PersistentData = PersistentData()
|
---|
169 |
|
---|
170 | # Override
|
---|
171 | def notifyChange(self, info: Inform):
|
---|
172 | # self.getReporter().log(logging.INFO, "received info:" + str(info))
|
---|
173 | if isinstance(info, Settings):
|
---|
174 | # self.getReporter().log(logging.WARNING, "SETTINGS")
|
---|
175 | settings: Settings = cast(Settings, info)
|
---|
176 | self._settings = settings
|
---|
177 | self._me: PartyId = settings.getID()
|
---|
178 | self._progress = settings.getProgress()
|
---|
179 | self._protocol = str(settings.getProtocol().getURI())
|
---|
180 | self._parameters = settings.getParameters()
|
---|
181 | if "storage_dir" in self._parameters.getParameters():
|
---|
182 | self.getReporter().log(logging.INFO, "storage_dir is on parameters")
|
---|
183 | self._storage_dir = self._parameters.get("storage_dir")
|
---|
184 |
|
---|
185 | try:
|
---|
186 | self._profile_interface: ProfileInterface = ProfileConnectionFactory.create(
|
---|
187 | settings.getProfile().getURI(), self.getReporter()
|
---|
188 | )
|
---|
189 | self._profile = self._profile_interface.getProfile()
|
---|
190 | self._domain = self._profile.getDomain()
|
---|
191 |
|
---|
192 | if self._freq_map is None:
|
---|
193 | self._freq_map = defaultdict()
|
---|
194 | else:
|
---|
195 | self._freq_map.clear()
|
---|
196 |
|
---|
197 | issues = self._domain.getIssues()
|
---|
198 | for issue in issues:
|
---|
199 | p = Pair()
|
---|
200 | vs = self._domain.getValues(issue)
|
---|
201 | if isinstance(vs.get(0), DiscreteValue.DiscreteValue):
|
---|
202 | p.value_type = 0
|
---|
203 | elif isinstance(vs.get(0), NumberValue.NumberValue):
|
---|
204 | p.value_type = 1
|
---|
205 | for v in vs:
|
---|
206 | vstr = self.value_to_str(v, p)
|
---|
207 | p.vlist[vstr] = 0
|
---|
208 | self._freq_map[issue] = p
|
---|
209 |
|
---|
210 | self._utility_space = self._profile_interface.getProfile()
|
---|
211 | self._all_bid_list: AllBidsList = AllBidsList(domain=self._domain)
|
---|
212 | self._sorted_bid_list = sorted(AllBidsList(domain=self._domain),
|
---|
213 | key=self._utility_space.getUtility, reverse=True)
|
---|
214 | self._len_sorted_bid_list = len(self._sorted_bid_list)
|
---|
215 | # after sort of bid list the optimal bid is in the first element
|
---|
216 | self._optimal_bid = self._sorted_bid_list[0]
|
---|
217 |
|
---|
218 | except Exception as e:
|
---|
219 | print("error in settings:{}", e)
|
---|
220 | self.getReporter().log(logging.WARNING, "Error in {}".format(str(e)))
|
---|
221 |
|
---|
222 | elif isinstance(info, ActionDone):
|
---|
223 | # self.getReporter().log(logging.WARNING, "ActionDone")
|
---|
224 | # TODO: initalizie with negotiaiondata
|
---|
225 | action: Action = cast(ActionDone, info).getAction()
|
---|
226 | if self._me is not None and self._me != action.getActor():
|
---|
227 | opponent_name = self.parse_opponent_name(full_opponent_name=action.getActor().getName())
|
---|
228 | if self._opponent_name is None and opponent_name is not None:
|
---|
229 | self.initialize_storage(opponent_name)
|
---|
230 | # which means index found
|
---|
231 | self._opponent_name = opponent_name
|
---|
232 | self._negotiation_data.set_opponent_name(self._opponent_name)
|
---|
233 |
|
---|
234 | self.op_threshold = self._persistent_data.get_smooth_threshold_over_time(self._opponent_name
|
---|
235 | )
|
---|
236 | if self.op_threshold is not None:
|
---|
237 | for i in range(1, self.t_split):
|
---|
238 | self.op_threshold[i] = self.op_threshold[i] if self.op_threshold[i] > 0 else \
|
---|
239 | self.op_threshold[i - 1]
|
---|
240 | self.alpha = self._persistent_data.get_opponent_alpha(self._opponent_name)
|
---|
241 | self.alpha = self.alpha if self.alpha > 0.0 else self.default_alpha
|
---|
242 | self.process_action(action)
|
---|
243 |
|
---|
244 | elif isinstance(info, YourTurn):
|
---|
245 | # This is a super party
|
---|
246 | # self.getReporter().log(logging.WARNING, "YourTurn")
|
---|
247 | if isinstance(self._progress, ProgressRounds):
|
---|
248 | self._progress = self._progress.advance()
|
---|
249 | # self.initialize_storage(self._opponent_name)
|
---|
250 | action = self._my_turn()
|
---|
251 | val(self.getConnection()).send(action)
|
---|
252 |
|
---|
253 | elif isinstance(info, Finished):
|
---|
254 | # TODO:: handle NEGOTIATIONDATA
|
---|
255 | finished_info = cast(Finished, info)
|
---|
256 | agreements: Agreements = finished_info.getAgreements()
|
---|
257 | self.process_agreements(agreements)
|
---|
258 | self.learn()
|
---|
259 | if self._negotiation_data_paths is not None and len(
|
---|
260 | self._negotiation_data_paths) > 0 and self._negotiation_data is not None:
|
---|
261 | for negotiation_path in self._negotiation_data_paths:
|
---|
262 | try:
|
---|
263 | with open(negotiation_path, "wb") as negotiation_file:
|
---|
264 | pickle.dump(self._negotiation_data, negotiation_file)
|
---|
265 | except Exception as e:
|
---|
266 | self.getReporter().log(logging.WARNING, "Error in {}".format(str(e)))
|
---|
267 | self.terminate()
|
---|
268 | else:
|
---|
269 | self.getReporter().log(
|
---|
270 | logging.WARNING, "Ignoring unknown info " + str(info)
|
---|
271 | )
|
---|
272 |
|
---|
273 | # Override
|
---|
274 | def getCapabilities(self) -> Capabilities:
|
---|
275 | return Capabilities(
|
---|
276 | set(["SAOP", "Learn"]),
|
---|
277 | set(["geniusweb.profile.utilityspace.LinearAdditive"]),
|
---|
278 | )
|
---|
279 |
|
---|
280 | # Override
|
---|
281 | def getDescription(self) -> str:
|
---|
282 | return "This is a party of ANL 2022. It can handle the Learn protocol and learns simple characteristics of the opponent."
|
---|
283 |
|
---|
284 | # Override
|
---|
285 | def terminate(self):
|
---|
286 | self.getReporter().log(logging.INFO, "party is terminating:")
|
---|
287 | super().terminate()
|
---|
288 | if self._profile_interface is not None:
|
---|
289 | self._profile_interface.close()
|
---|
290 |
|
---|
291 | def value_to_str(self, v: Value, p: Pair) -> str:
|
---|
292 | v_str = ""
|
---|
293 | if p.value_type == 0:
|
---|
294 | v_str = str(cast(DiscreteValue, v).getValue())
|
---|
295 | elif p.value_type == 1:
|
---|
296 | v_str = str(cast(NumberValue, v).getValue())
|
---|
297 |
|
---|
298 | if v_str == "":
|
---|
299 | self.getReporter().log(logging.WARNING, "Warning: Value wasn't found")
|
---|
300 | return v_str
|
---|
301 |
|
---|
302 | def process_action(self, action: Action):
|
---|
303 | if isinstance(action, Offer):
|
---|
304 | self._last_received_bid = cast(Offer, action).getBid()
|
---|
305 | self.update_freq_map(self._last_received_bid)
|
---|
306 | util_value = float(self._utility_space.getUtility(self._last_received_bid))
|
---|
307 | self._negotiation_data.add_bid_util(util_value)
|
---|
308 |
|
---|
309 | def update_freq_map(self, bid: Bid):
|
---|
310 | if bid is not None:
|
---|
311 | issues = bid.getIssues()
|
---|
312 | for issue in issues:
|
---|
313 | p: Pair = self._freq_map[issue]
|
---|
314 | v: Value = bid.getValue(issue)
|
---|
315 | vs: str = self.value_to_str(v, p)
|
---|
316 | p.vlist[vs] = p.vlist[vs] + 1
|
---|
317 |
|
---|
318 | def calc_op_value(self, bid: Bid):
|
---|
319 | value: float = 0
|
---|
320 | issues: set[str] = bid.getIssues()
|
---|
321 | val_util: list[float] = [0] * len(issues)
|
---|
322 | is_weight: list[float] = [0] * len(issues)
|
---|
323 | k: int = 0
|
---|
324 | for issue in issues:
|
---|
325 | p: Pair = self._freq_map[issue]
|
---|
326 | v: Value = bid.getValue(issue)
|
---|
327 | vs: str = self.value_to_str(v=v, p=p)
|
---|
328 | sum_of_values = 0
|
---|
329 | max_value = 1
|
---|
330 | for vString in p.vlist.keys():
|
---|
331 | sum_of_values = sum_of_values + p.vlist.get(vString)
|
---|
332 | max_value = max(max_value, p.vlist.get(vString))
|
---|
333 | val_util[k] = float(p.vlist.get(vs)) / max_value
|
---|
334 | mean = sum_of_values / len(p.vlist)
|
---|
335 | for v_string in p.vlist.keys():
|
---|
336 | is_weight[k] = is_weight[k] + math.pow(p.vlist.get(v_string) - mean, 2)
|
---|
337 | is_weight[k] = 1 / math.sqrt((is_weight[k] + 0.1) / len(p.vlist))
|
---|
338 | k = k + 1
|
---|
339 | sum_of_weight = 0
|
---|
340 | for k in range(len(issues)):
|
---|
341 | value = value + val_util[k] * is_weight[k]
|
---|
342 | sum_of_weight = sum_of_weight + is_weight[k]
|
---|
343 | return value / sum_of_weight
|
---|
344 |
|
---|
345 | def is_op_good(self, bid: Bid):
|
---|
346 | if bid is None:
|
---|
347 | return False
|
---|
348 | value = self.calc_op_value(bid=bid)
|
---|
349 | index = int(
|
---|
350 | ((self.t_split - 1) / (1 - self.t_phase) * (self._progress.get(get_ms_current_time()) - self.t_phase)))
|
---|
351 | op_threshold = max(1 - 2 * self.op_threshold[index], 0.2) if self.op_threshold is not None else 0.6
|
---|
352 | return value > op_threshold
|
---|
353 | # index = (int)((t_split - 1) / (1 - t_phase) * (progress.get(System.currentTimeMillis()) - t_phase));
|
---|
354 |
|
---|
355 | def is_last_turn(self):
|
---|
356 | return self._progress.get(time() * 1000) > 0.997
|
---|
357 |
|
---|
358 | def is_near_negotiation_end(self):
|
---|
359 | return self._progress.get(time() * 1000) > self.t_phase
|
---|
360 |
|
---|
361 | def is_social_welfare_time(self):
|
---|
362 | return self._progress.get(time() * 1000) > self.t_social_welfare
|
---|
363 |
|
---|
364 | def calc_utility(self, bid):
|
---|
365 | # get utility from utility space
|
---|
366 | return self._utility_space.getUtility(bid)
|
---|
367 |
|
---|
368 | def calc_social_welfare(self, bid: Bid):
|
---|
369 | return 0.8 * float(self.calc_utility(bid)) + math.fabs(1 - 0.8) * float(self.calc_op_value(bid))
|
---|
370 |
|
---|
371 | def cmp_social_welfare(self, first_bid, second_bid):
|
---|
372 | return self.calc_social_welfare(first_bid) >= self.calc_social_welfare(second_bid)
|
---|
373 |
|
---|
374 | def is_good(self, bid):
|
---|
375 | if bid is None:
|
---|
376 | return False
|
---|
377 | max_value = 0.95 if self._optimal_bid is None else 0.95 * float(self.calc_utility(self._optimal_bid))
|
---|
378 | avg_max_utility = self._persistent_data.get_avg_max_utility(self._opponent_name) \
|
---|
379 | if self._persistent_data._known_opponent(self._opponent_name) \
|
---|
380 | else self._avg_utility
|
---|
381 | self._util_threshold = max_value - (
|
---|
382 | max_value - 0.55 * self._avg_utility - 0.4 * avg_max_utility + 0.5 * pow(self._std_utility, 2)) * \
|
---|
383 | (math.exp(self.alpha * self._progress.get(get_ms_current_time())) - 1) / (math.exp(
|
---|
384 | self.alpha) - 1)
|
---|
385 | if self._util_threshold < self._min_utility:
|
---|
386 | self._util_threshold = self._min_utility
|
---|
387 | return float(self.calc_utility(bid)) >= self._util_threshold
|
---|
388 |
|
---|
389 | def first_is_good_idx(self):
|
---|
390 | for i in range(len(self._sorted_bid_list)):
|
---|
391 | if not self.is_good(self._sorted_bid_list[i]):
|
---|
392 | return i
|
---|
393 | return len(self._sorted_bid_list) - 1
|
---|
394 |
|
---|
395 | def on_negotiation_near_end(self):
|
---|
396 | slice_idx = self.first_is_good_idx()
|
---|
397 | end_slice = int(min(slice_idx + 0.005 * self._len_sorted_bid_list - 1, self._len_sorted_bid_list - 1))
|
---|
398 | idx = random.randint(0, slice_idx)
|
---|
399 |
|
---|
400 | if self._progress.get(get_ms_current_time()) >= 0.95:
|
---|
401 | bid = self.last_bids(idx)
|
---|
402 | if self.calc_utility(bid) <= 0.5:
|
---|
403 | bid = self._optimal_bid
|
---|
404 | return bid
|
---|
405 | # if self._progress.get(get_ms_current_time()) > 0.992 and self.is_good(self._best_offer_bid):
|
---|
406 | # return self._best_offer_bid
|
---|
407 | return self._sorted_bid_list[idx]
|
---|
408 |
|
---|
409 | def on_negotiation_continues(self):
|
---|
410 | bid: Bid = None
|
---|
411 |
|
---|
412 | slice_idx = self.first_is_good_idx()
|
---|
413 | end_slice = int(min(slice_idx + 0.005 * self._len_sorted_bid_list - 1, self._len_sorted_bid_list - 1))
|
---|
414 | for i in range(slice_idx, 0, -1):
|
---|
415 | tmp_bid = self._sorted_bid_list[i]
|
---|
416 | if tmp_bid == self._optimal_bid or self.is_op_good(tmp_bid):
|
---|
417 | bid = tmp_bid
|
---|
418 | break
|
---|
419 | if self._progress.get(get_ms_current_time()) > 0.992 and self.is_good(self._best_offer_bid):
|
---|
420 | bid = self._best_offer_bid
|
---|
421 | if bid is None or not self.is_good(bid):
|
---|
422 | idx = random.randint(0, slice_idx)
|
---|
423 | bid = self._sorted_bid_list[idx]
|
---|
424 | return bid
|
---|
425 |
|
---|
426 | def cmp_utility(self, first_bid, second_bid):
|
---|
427 | # return 1 if first_bid with higher utility, 0 else
|
---|
428 | return self._utility_space.getUtility(first_bid) > self._utility_space.getUtility(second_bid)
|
---|
429 |
|
---|
430 | def _find_bid(self):
|
---|
431 | bid: Bid = None
|
---|
432 | if self._best_offer_bid is None:
|
---|
433 | self._best_offer_bid = self._last_received_bid
|
---|
434 | elif self.cmp_utility(self._last_received_bid, self._best_offer_bid):
|
---|
435 | self._best_offer_bid = self._last_received_bid
|
---|
436 | # if self.is_social_welfare_time():
|
---|
437 | # self.on_negotiation_social_welfare()
|
---|
438 | if self.is_near_negotiation_end():
|
---|
439 | bid = self.on_negotiation_near_end()
|
---|
440 | else:
|
---|
441 | bid = self.on_negotiation_continues()
|
---|
442 |
|
---|
443 | action: Offer = Offer(self._me, bid)
|
---|
444 | return action
|
---|
445 |
|
---|
446 | def _my_turn(self):
|
---|
447 | # save average of the last avgSplit offers (only when frequency table is stabilized)
|
---|
448 | if self._opponent_name is None:
|
---|
449 | return Offer(self._me, self._optimal_bid)
|
---|
450 |
|
---|
451 | if self.is_near_negotiation_end():
|
---|
452 | index = int(
|
---|
453 | (self.t_split - 1) / (1 - self.t_phase) * (self._progress.get(get_ms_current_time()) - self.t_phase))
|
---|
454 | self.op_sum[index] += self.calc_op_value(self._last_received_bid)
|
---|
455 | self.op_counter[index] += 1
|
---|
456 | if self.is_good(self._last_received_bid) or (self.is_last_turn() and self.calc_utility(self._last_received_bid)>=0.5):
|
---|
457 | # if the last bid is good - accept it.
|
---|
458 | action = Accept(self._me, self._last_received_bid)
|
---|
459 | else:
|
---|
460 | action = self._find_bid()
|
---|
461 | return action
|
---|
462 |
|
---|
463 | def learn(self):
|
---|
464 | self.getReporter().log(logging.INFO, "party is learning")
|
---|
465 | # probably have to shift to self._negotiation_data_paths
|
---|
466 | for path in self._negotiation_data_paths:
|
---|
467 | try:
|
---|
468 | with open(path, "rb") as f:
|
---|
469 | nego_data = pickle.load(f)
|
---|
470 | self._persistent_data.update(nego_data)
|
---|
471 | except Exception as e:
|
---|
472 | print("error in learn function - persistent data update, error:{}", str(e))
|
---|
473 |
|
---|
474 | try:
|
---|
475 | with open(self._persistent_path, "wb") as pers_file:
|
---|
476 | pickle.dump(self._persistent_data, pers_file)
|
---|
477 | except Exception as e:
|
---|
478 | print("error in persistent path dump:{}", str(e))
|
---|
479 |
|
---|
480 | def process_agreements(self, agreements: Agreements):
|
---|
481 | # Check if we reached an agreement (walking away or passing the deadline
|
---|
482 | # results in no agreement)
|
---|
483 | self.getReporter().log(logging.INFO, "Length of agreements: {} :{}".format(len(agreements.getMap().items()),
|
---|
484 | agreements.getMap()))
|
---|
485 | if len(agreements.getMap().items()) > 0:
|
---|
486 | # Get the bid that is agreed upon and add it's value to our negotiation data
|
---|
487 | agreement: Bid = agreements.getMap().values().__iter__().__next__()
|
---|
488 | self._negotiation_data.add_agreement_util(float(self.calc_utility(agreement)))
|
---|
489 | self._negotiation_data.set_opponent_util(self.calc_op_value(agreement))
|
---|
490 | self.getReporter().log(logging.INFO, "Agreement in time: {} percent".format(self._progress.get(get_ms_current_time())))
|
---|
491 | self.getReporter().log(logging.INFO, "MY OWN THRESHOLD: {}".format(self._util_threshold))
|
---|
492 | self.getReporter().log(logging.INFO, "MY OWN UTIL:{}".format(self.calc_utility(agreement)))
|
---|
493 | self.getReporter().log(logging.INFO, "EXP OPPONENT UTIL:{}".format(self.calc_op_value(agreement)))
|
---|
494 | else:
|
---|
495 | if self._best_offer_bid is not None:
|
---|
496 | self._negotiation_data.add_agreement_util(float(self.calc_utility(self._best_offer_bid)))
|
---|
497 | self.getReporter().log(logging.INFO,
|
---|
498 | "!!!!!!!!!!!!!! NO AGREEMENT !!!!!!!!!!!!!!! /// MY THRESHOLD: {}".format(
|
---|
499 | self._util_threshold))
|
---|
500 |
|
---|
501 | self.getReporter().log(logging.INFO, "TIME OF AGREEMENT: {}".format(self._progress.get(get_ms_current_time())))
|
---|
502 | # update the opponent offers map, regardless of achieving agreement or not
|
---|
503 | try:
|
---|
504 | self._negotiation_data.update_opponent_offers(self.op_sum, self.op_counter)
|
---|
505 | except Exception as e:
|
---|
506 | self.getReporter().log(logging.INFO, "Error in process_agreements,{}".format(str(e)))
|
---|