def offer_debug(agent, their_good, their_amt, counterparty=None): if DEBUG: if counterparty is None: counterparty = "Unknown" user_debug( f" {agent.name} has received an offer of {their_amt} " + f"of {their_good} from {counterparty}")
def send_offer(trader2, their_good, their_amt, counterparty, comp=False): """ trader2 receives an offer sent by counterparty. We don't need to ever change my_amt in this function, because if the counter-party can't bid enough for a single unit, no trade is possible. """ offer_debug(trader2, their_good, their_amt, counterparty) my_amt = 1 gain = utility_delta(trader2, their_good, their_amt) if comp: gain += trader2[GOODS][their_good]["incr"] # we randomize to eliminate bias towards earlier goods in list rand_goods = rand_goods_list(trader2["goods"]) for my_good in rand_goods: # adjust my_amt if "divisibility" is one of the attributes my_amt = amt_adjust(trader2, my_good) # don't bother trading identical goods AND we must have some # of any good we will trade if my_good != their_good and trader2["goods"][my_good][AMT_AVAIL] > 0: loss = -utility_delta(trader2, my_good, -my_amt) if comp: loss += trader2[GOODS][my_good]["incr"] trade_debug(trader2, counterparty, my_good, their_good, my_amt, their_amt, gain, loss) if gain > loss: if send_reply(counterparty, their_good, their_amt, my_good, my_amt, comp=comp): trade(trader2, my_good, my_amt, counterparty, their_good, their_amt, comp=comp) # both goods' trade_count will be increased in sender's dic item = list(trader2["goods"])[0] if "trade_count" in trader2["goods"][item]: counterparty["goods"][my_good]["trade_count"] += 1 counterparty["goods"][their_good]["trade_count"] += 1 print("RESULT:", trader2.name, "accepts the offer\n") return ACCEPT else: print("RESULT:", trader2.name, "rejects the offer\n") return REJECT else: print("RESULT: offer is inadequate\n") return INADEQ if DEBUG: user_debug(f"{trader2} is rejecting all offers of {their_good}") return REJECT
def move_location(self, nx, ny, ox, oy): """ Move a member to a new position, if that position is not already occupied. """ old_loc = str((ox, oy)) new_loc = str((nx, ny)) if old_loc not in self.locations: user_debug("Trying to move unlocated agent.") elif new_loc not in self.locations: self.locations[new_loc] = self.locations[old_loc] del self.locations[old_loc] else: user_debug("Trying to place agent in occupied space.")
def negotiate(trader1, trader2, comp=False, amt=1): # this_good is a dict user_debug(f" {trader1.name} is entering negotiations with" + f"{trader2.name}") # we randomize to eliminate bias towards earlier goods in list rand_goods = rand_goods_list(trader1["goods"]) for this_good in rand_goods: amt = amt_adjust(trader1, this_good) incr = amt while trader1["goods"][this_good][AMT_AVAIL] >= amt: # we want to offer "divisibility" amount extra each loop ans = send_offer(trader2, this_good, amt, trader1, comp=comp) # Besides acceptance or rejection, the offer can be inadequate! if ans == ACCEPT or ans == REJECT: break amt += incr
def move_location(self, nx, ny, ox, oy, agent_name="NA"): """ Move a member to a new position, if that position is not already occupied. """ old_loc = str((ox, oy)) new_loc = str((nx, ny)) if new_loc not in self.locations: if old_loc not in self.locations: user_log_warn("Trying to move agent not in locations: " + agent_name + " at " + old_loc) else: self.locations[new_loc] = self.locations[old_loc] del self.locations[old_loc] else: user_debug("Trying to place agent in occupied space.")
def send_reply(trader1, my_good, my_amt, their_good, their_amt, comp=False): """ trader1 evaluates trader2's offer here: """ # offer_debug(trader1, their_good, their_amt) gain = utility_delta(trader1, their_good, their_amt) loss = utility_delta(trader1, my_good, -my_amt) user_debug(f" {trader1.name} is evaluating the offer with gain: " + f"{round(gain, 2)}, loss: {round(loss, 2)}") if comp: gain += trader1[GOODS][their_good]["incr"] loss -= trader1[GOODS][my_good]["incr"] if gain > abs(loss): return ACCEPT else: # this will call a halt to negotiations on this good: return INADEQ
def adj_add_good_w_comp(agent, good, amt, old_amt): if new_good(old_amt, amt): if is_compl_good(agent, good): incr_util(agent[GOODS], good, amt=amt * STEEP_GRADIENT, agent=agent, graph=True) # now increase utility of this good's complements: for comp in compl_lst(agent, good): incr_util(agent[GOODS], comp, amt=amt * STEEP_GRADIENT, agent=agent, graph=True, comp=good) user_debug(agent[GOODS]) if good_all_gone(agent, good): for comp in compl_lst(agent, good): agent[GOODS][comp]['incr'] = 0
def get_rand_good(goods_dict, nonzero=False): """ What should this do with empty dict? """ # user_debug("Calling get_rand_good()") if goods_dict is None or not len(goods_dict): return None else: if nonzero and is_depleted(goods_dict): # we can't allocate what we don't have! user_debug("Goods are depleted!") return None goods_list = list(goods_dict.keys()) good = random.choice(goods_list) if nonzero: # pick again if the goods is endowed (amt is 0) # if we get big goods dicts, this could be slow: while goods_dict[good][AMT_AVAIL] == 0: good = random.choice(goods_list) return good
def trader_debug(agent): if DEBUG: user_debug(f"{agent.name} has {goods_to_str(agent[GOODS])}")
def trade_debug(agent1, agent2, good1, good2, amt1, amt2, gain, loss): if DEBUG: user_debug(f" {agent1.name} is offering {amt1} of {good1} to " + f"{agent2.name} for {amt2} of {good2} with a " + f"gain of {round(gain, 2)} and " + f"a loss of {round(loss, 2)}")