Source code for pymarket.statistics.maximum_aggregated_utility

import pulp
import pandas as pd
from pymarket.bids import BidManager
from collections import OrderedDict


[docs]def maximum_aggregated_utility(bids, *args, reservation_prices=None): """Maximizes the total welfare Parameters ---------- bids : pd.DataFrame Collection of bids reservation_prices : dict of floats or None, (Default value = None) A maping from user ids to reservation prices. If no reservation price for a user is given, his bid will be assumed to be his true value. Returns ------- status : str Status of the optimization problem. Desired output is 'Optimal' objective: float Maximum aggregated utility that can be obtained variables: dict A set of values achieving the objective. Maps a pair of bids to the quantity traded by them. Examples --------- >>> bm = pm.BidManager() >>> bm.add_bid(1, 3, 0) 0 >>> bm.add_bid(1, 2, 1) 1 >>> bm.add_bid(1.5, 1, 2, False) 2 >>> s, o, v = maximum_aggregated_utility(bm.get_df()) >>> s 'Optimal' >>> o 2.5 >>> v OrderedDict([((0, 2), 1.0), ((1, 2), 0.5)]) If in reality the seller had 0 value for his commodity, the social welfare will be 1.5 units larger >>> bm = pm.BidManager() >>> bm.add_bid(1, 3, 0) 0 >>> bm.add_bid(1, 2, 1) 1 >>> bm.add_bid(1.5, 1, 2, False) 2 >>> rp = {2: 0} >>> s, o, v = maximum_aggregated_utility(bm.get_df(), ... reservation_prices=rp) >>> s 'Optimal' >>> o 4.0 >>> v OrderedDict([((0, 2), 1.0), ((1, 2), 0.5)]) """ if reservation_prices is None: reservation_prices = OrderedDict() model = pulp.LpProblem("Max aggregated utility", pulp.LpMaximize) buyers = bids.loc[bids['buying']].index.values sellers = bids.loc[~bids['buying']].index.values index = [(i, j) for i in buyers for j in sellers] for i, x in bids.iterrows(): if i not in reservation_prices: reservation_prices[i] = x.price coeffs = OrderedDict() for x in index: coeffs[x] = reservation_prices[x[0]] - reservation_prices[x[1]] qs = pulp.LpVariable.dicts('q', index, lowBound=0, cat='Continuous') model += pulp.lpSum([qs[x[0], x[1]] * coeffs[x] for x in index]) for b in buyers: model += pulp.lpSum(qs[b, j] for j in sellers) <= bids.iloc[b, 0] for s in sellers: model += pulp.lpSum(qs[i, s] for i in buyers) <= bids.iloc[s, 0] model.solve() status = pulp.LpStatus[model.status] objective = pulp.value(model.objective) variables = OrderedDict() sorted_keys = sorted(qs.keys()) for var in sorted_keys: varval = qs[var].varValue variables[var] = varval return status, objective, variables
[docs]def percentage_welfare(bids, transactions, reservation_prices=None, **kwargs): """Percentage of the total welfare that could be achieved calculated based on the transaction lists Parameters ---------- bids (pandas dataframe) : Table with all the submited bids transactions (pandas dataframe) : Table with all the transactions that ocurred in the market reservation_prices (dict, optional) : Reservation prices of the different participants. If None, the bids will be assumed to be the truthfull values. Returns ------- ratio : float The ratio of the maximum social welfare achieved by the collection of transactions. Examples --------- Only bid 0 and 2 trade. That represents a net utility of 2 which is 80% of the total max utility 2.5 >>> tm = pm.TransactionManager() >>> bm = pm.BidManager() >>> bm.add_bid(1, 3, 0) 0 >>> bm.add_bid(1, 2, 1) 1 >>> bm.add_bid(1.5, 1, 2, False) 2 >>> tm.add_transaction(0, 1, 2, 2, False) 0 >>> tm.add_transaction(2, 1, 2, 0, False) 1 >>> percentage_welfare(bm.get_df(), tm.get_df()) 0.8 """ reservation_prices = OrderedDict() for i, x in bids.iterrows(): if i not in reservation_prices: reservation_prices[i] = x.price _, objective, _ = maximum_aggregated_utility(bids, reservation_prices) tmp = bids.reset_index().rename(columns={'index': 'bid'}) tmp = tmp[['bid', 'price', 'buying']] merged = transactions.merge(tmp, on='bid') buyers = merged.loc[merged['buying']] profit_buyers = (buyers.price_y - buyers.price_x) * buyers.quantity profit_buyers = profit_buyers.sum() sellers = merged.loc[~merged['buying']] profit_sellers = (sellers.price_x - sellers.price_y) * sellers.quantity profit_sellers = profit_sellers.sum() welfare = profit_buyers + profit_sellers if objective > 0: return welfare / objective else: return None