def reserve(self, good, quantity): self._reserved[good] += quantity if self._reserved[good] > self.haves[good]: if isclose(self._reserved[good], self.haves[good]): self._reserved[good] = self.haves[good] else: self._reserved[good] -= quantity raise NotEnoughGoods( self.name, good, quantity - (self.haves[good] - self._reserved[good]))
def pay_contract(self, contract): """ delivers on a contract """ assert contract.pay_group == self.group and contract.pay_id == self.id money = contract.quantity * contract.price available = self._haves['money'] if money > available + epsilon + epsilon * max(money, available): raise NotEnoughGoods(self.name, 'money', money - available) if money > available: money = available self._haves['money'] -= money self._send(contract.deliver_good_group, contract.deliver_good_id, '_dp', contract)
def deliver_contract(self, contract): """ delivers on a contract """ assert contract.deliver_good_group == self.group and contract.deliver_good_id == self.id quantity = contract.quantity available = self._haves[contract.good] if quantity > available + epsilon + epsilon * max(quantity, available): raise NotEnoughGoods(self.name, contract.good, quantity - available) if quantity > available: quantity = available self._haves[contract.good] -= quantity self._send(contract.pay_group, contract.pay_id, '_dp', contract)
def __sub__(self, other): if isinstance(other, ExpiringGood): other = float(other) sum_time_structure = sum(self.time_structure) if sum_time_structure < - epsilon: raise NotEnoughGoods("AnAgent", "ExpiringGood", -sum_time_structure) for i in range(len(self.time_structure)): if other >= self.time_structure[i]: other -= self.time_structure[i] self.time_structure[i] = 0 else: self.time_structure[i] -= other break return self
def give(self, receiver, good, quantity, epsilon=epsilon): """ gives a good to another agent Args: receiver: The name of the receiving agent a tuple (group, id). e.G. ('firm', 15) good: the good to be transfered quantity: amount to be transfered epsilon (optional): if you have floating point errors, a quantity or prices is a fraction of number to high or low. You can increase the floating point tolerance. See troubleshooting -- floating point problems Raises: AssertionError, when good smaller than 0. Return: Dictionary, with the transfer, which can be used by self.log(...). Example:: self.log('taxes', self.give('money': 0.05 * self['money']) """ assert quantity > -epsilon, 'quantity %.30f is smaller than 0 - epsilon (%.30f)' % ( quantity, -epsilon) if quantity < 0: quantity = 0 available = self._inventory[good] if quantity > available + epsilon + epsilon * max(quantity, available): raise NotEnoughGoods(self.name, good, quantity - available) if quantity > available: quantity = available self._inventory.haves[good] -= quantity self.send(receiver, 'abcEconomics_receive_good', [good, quantity]) return {good: quantity}
def destroy(self, good, quantity=None): """ destroys quantity of the good. If quantity is omitted destroys all Use with care. Args:: 'good': is the name of the good quantity (optional): number Raises:: NotEnoughGoods: when goods are insufficient """ if quantity is None: self.haves[good] = 0 else: assert quantity >= 0.0 available = self.haves[good] if available < quantity - epsilon: raise NotEnoughGoods(self.name, good, quantity - available) self.haves[good] -= quantity
def accept(self, offer, quantity=-999, epsilon=epsilon): """ The buy or sell offer is accepted and cleared. If no quantity is given the offer is fully accepted; If a quantity is given the offer is partial accepted. Args: offer: the offer the other party made quantity: quantity to accept. If not given all is accepted epsilon (optional): if you have floating point errors, a quantity or prices is a fraction of number to high or low. You can increase the floating point tolerance. See troubleshooting -- floating point problems Return: Returns a dictionary with the good's quantity and the amount paid. """ offer_quantity = offer.quantity if quantity == -999: quantity = offer_quantity assert quantity > -epsilon, 'quantity %.30f is smaller than 0 - epsilon (%.30f)' % ( quantity, -epsilon) if quantity < 0: quantity = 0 if quantity > offer_quantity + epsilon * max(quantity, offer_quantity): raise AssertionError( 'accepted more than offered %s: %.100f >= %.100f' % (offer.good, quantity, offer_quantity)) if quantity > offer_quantity: quantity = offer_quantity if quantity == 0: self.reject(offer) return {offer.good: 0, offer.currency: 0} money_amount = quantity * offer.price if offer.sell: # ord('s') assert money_amount > -epsilon, 'money = quantity * offer.price %.30f is smaller than 0 - epsilon (%.30f)' % ( money_amount, -epsilon) if money_amount < 0: money_amount = 0 available = self._inventory[offer.currency] if money_amount > available + epsilon + epsilon * max( money_amount, available): raise NotEnoughGoods(self.name, offer.currency, money_amount - available) if money_amount > available: money_amount = available self._inventory.haves[offer.good] += quantity self._inventory.haves[offer.currency] -= quantity * offer.price else: assert quantity > -epsilon, 'quantity %.30f is smaller than 0 - epsilon (%.30f)' % ( quantity, -epsilon) if quantity < 0: quantity = 0 available = self._inventory[offer.good] if quantity > available + epsilon + epsilon * max( quantity, available): raise NotEnoughGoods(self.name, offer.good, quantity - available) if quantity > available: quantity = available self._inventory.haves[offer.good] -= quantity self._inventory.haves[offer.currency] += quantity * offer.price offer.final_quantity = quantity self.send(offer.sender, 'abcEconomics_receive_accept', (offer.id, quantity)) del self._polled_offers[offer.id] if offer.sell: return {offer.good: -quantity, offer.currency: money_amount} else: return {offer.good: quantity, offer.currency: -money_amount}
def sell(self, receiver, good, quantity, price, currency='money', epsilon=epsilon): """ commits to sell the quantity of good at price The good is not available for the agent. When the offer is rejected it is automatically re-credited. When the offer is accepted the money amount is credited. (partial acceptance accordingly) Args: receiver_group: group of the receiving agent receiver_id: number of the receiving agent 'good': name of the good quantity: maximum units disposed to buy at this price price: price per unit currency: is the currency of this transaction (defaults to 'money') epsilon (optional): if you have floating point errors, a quantity or prices is a fraction of number to high or low. You can increase the floating point tolerance. See troubleshooting -- floating point problems Returns: A reference to the offer. The offer and the offer status can be accessed with `self.info(offer_reference)`. Example:: def subround_1(self): self.offer = self.sell('household', 1, 'cookies', quantity=5, price=0.1) def subround_2(self): offer = self.info(self.offer) if offer.status == 'accepted': print(offer.final_quantity , 'cookies have be bougth') else: offer.status == 'rejected': print('On diet') """ assert price > - epsilon, 'price %.30f is smaller than 0 - epsilon (%.30f)' % (price, - epsilon) if price < 0: price = 0 # makes sure the quantity is between zero and maximum available, but # if its only a little bit above or below its set to the bounds available = self._inventory[good] assert quantity > - epsilon, 'quantity %.30f is smaller than 0 - epsilon (%.30f)' % (quantity, - epsilon) if quantity < 0: quantity = 0 if quantity > available + epsilon + epsilon * fmax(quantity, available): raise NotEnoughGoods(self.name, good, quantity - available) if quantity > available: quantity = available offer_id = self._offer_counter() self._inventory.reserve(good, quantity) offer = Offer(self.name, receiver, good, quantity, price, currency, True, 'new', -2, offer_id, self.time, -2) self.given_offers[offer_id] = offer self.send(receiver, 'abcEconomics_propose_sell', offer) return offer