def experiment(results_csv_file: str, auction_function: Callable, auction_name: str, recipe: tuple, stocks_prices: list = None, stock_names: list = None): """ Run an experiment similar to McAfee (1992) experiment on the given auction. :param results_csv_file: the experiment result file. :param auction_function: the function for executing the auction under consideration. :param auction_name: title of the experiment, for printouts. :param recipe: can be any vector of ones, e.g. (1,1,1), for our trade-reduction mechanism, or any vector of positive integers for our ascending-auction mechanism. :param stocks_prices: list of prices for each stock and each agent. :param stock_names: list of stocks names which prices are belongs, for naming only. """ if stocks_prices is None: (stocks_prices, stock_names) = getStocksPrices(recipe) results_table = TeeTable(TABLE_COLUMNS, results_csv_file) recipe_str = ":".join(map(str, recipe)) for i in range(len(stocks_prices)): market = Market([ AgentCategory("agent", category) for category in stocks_prices[i] ]) num_of_possible_ps = min([ len(stocks_prices[i][j]) / recipe[j] for j in range(len(stocks_prices[i])) ]) (optimal_trade, _) = market.optimal_trade(recipe) auction_trade = auction_function(market, recipe) optimal_count = optimal_trade.num_of_deals() auction_count = auction_trade.num_of_deals() if (auction_trade.num_of_deals() > optimal_trade.num_of_deals()): print( "Warning!!! the number of deals in action is greater than optimal!" ) print("Optimal num of deals: ", optimal_trade.num_of_deals()) print("Auction num of deals: ", auction_trade.num_of_deals()) optimal_gft = optimal_trade.gain_from_trade() auction_gft = auction_trade.gain_from_trade(including_auctioneer=True) auction_market_gft = auction_trade.gain_from_trade( including_auctioneer=False) results_table.add( OrderedDict(( ("stock_name", stock_names[i]), ("auction_name", auction_name), ("recipe", recipe_str), ("num_possible_trades", round(num_of_possible_ps)), ("optimal_count", round(optimal_count, 2)), ("auction_count", round(auction_count, 2)), ("count_ratio", 0 if optimal_count == 0 else int( (auction_count / optimal_count) * 100000) / 1000), ("optimal_gft", round(optimal_gft, 2)), ("auction_gft", round(auction_gft, 2)), ("auction_gft_ratio", 0 if optimal_gft == 0 else round( auction_gft / optimal_gft * 100, 3)), ("auction_market_gft", round(auction_market_gft, 2)), ("market_gft_ratio", 0 if optimal_gft == 0 else round( auction_market_gft / optimal_gft * 100, 3)), ))) results_table.done()
def experiment(results_csv_file: str, auction_functions: list, auction_names: str, recipe: tuple, iterations: int, nums_of_agents: list = None, stocks_prices: list = None, stock_names: list = None): """ Run an experiment similar to McAfee (1992) experiment on the given auction. :param results_csv_file: the experiment result file. :param auction_functions: list of functions for executing the auction under consideration. :param auction_names: titles of the experiment, for printouts. :param recipe: can be any vector of ones, e.g. (1,1,1), for our trade-reduction mechanism, or any vector of positive integers for our ascending-auction mechanism. :param nums_of_agents: list of n(s) for number of possible trades to make the calculations. :param stocks_prices: list of prices for each stock and each agent. :param stock_names: list of stocks names which prices are belongs, for naming only. """ TABLE_COLUMNS = [ "stockname", "recipe", "numpossibletrades", "optimalcount", "optimalcountwithgftzero", "optimalgft" ] AUCTION_COLUMNS = ["auctioncount", "countratio", "gft", "gftratio"] print(recipe) if stocks_prices is None: (stocks_prices, stock_names) = getStocksPricesShuffled() column_names = TABLE_COLUMNS column_names += [ auction_name + column for auction_name in auction_names for column in AUCTION_COLUMNS ] results_table = TeeTable(column_names, results_csv_file) recipe_str = ":".join(map(str, recipe)) recipe_sum = sum(recipe) if nums_of_agents is None: nums_of_agents = [10000000] average_total_results = {} for num_of_agents_per_category in nums_of_agents: average_total_results[str(num_of_agents_per_category)] = [] for i in range(len(stocks_prices)): total_results = {} for num_of_agents_per_category in nums_of_agents: total_results[str(num_of_agents_per_category)] = [] stock_prices = stocks_prices[i] last_iteration = False for num_of_agents_per_category in nums_of_agents: for iteration in range(iterations): num_of_possible_ps = min(num_of_agents_per_category, int(len(stock_prices) / recipe_sum)) if last_iteration and num_of_possible_ps < num_of_agents_per_category: break if num_of_possible_ps < num_of_agents_per_category: if last_iteration: break last_iteration = True categories = [] buyer_agent_count = recipe[0] index = 0 for category in recipe: next_index = index + num_of_possible_ps * category price_value_multiple = -1 * buyer_agent_count if index > 0 else recipe_sum - buyer_agent_count categories.append( AgentCategory("agent", [ int(price * price_value_multiple) for price in stock_prices[index:next_index] ])) index = next_index market = Market(categories) (optimal_trade, _) = market.optimal_trade(ps_recipe=list(recipe), max_iterations=10000000, include_zero_gft_ps=False) optimal_count = optimal_trade.num_of_deals() optimal_gft = optimal_trade.gain_from_trade() (optimal_trade_with_gft_zero, _) = market.optimal_trade(ps_recipe=list(recipe), max_iterations=10000000) optimal_count_with_gft_zero = optimal_trade_with_gft_zero.num_of_deals( ) results = [ ("stockname", stock_names[i]), ("recipe", recipe_str), ("numpossibletrades", round(num_of_possible_ps)), ("optimalcount", optimal_count), ("optimalcountwithgftzero", optimal_count_with_gft_zero), ("optimalgft", optimal_gft) ] for auction_index in range(len(auction_functions)): if 'mcafee' in auction_names[auction_index]: results.append((auction_name + "auctioncount", 0)) results.append((auction_name + "countratio", 0)) results.append((auction_name + "gft", 0)) results.append((auction_name + "gftratio", 0)) auction_trade = auction_functions[auction_index](market, recipe) auction_count = auction_trade.num_of_deals() # for j in range(len(stocks_prices[i])): # print(sorted(stocks_prices[i][j][:num_of_possible_ps*recipe[j]])) if (auction_trade.num_of_deals() > optimal_trade_with_gft_zero.num_of_deals()): # print(sorted(stocks_prices[i][0][:num_of_possible_ps*recipe[0]])) # print(sorted(stocks_prices[i][1][:num_of_possible_ps*recipe[1]])) print( "Warning!!! the number of deals in action is greater than optimal!" ) print("Optimal num of deals: ", optimal_trade.num_of_deals()) print("Auction num of deals: ", auction_trade.num_of_deals()) print("Auction name: ", auction_names[auction_index]) gft = auction_trade.gain_from_trade( including_auctioneer=False) auction_name = auction_names[auction_index] results.append((auction_name + "auctioncount", auction_trade.num_of_deals())) results.append( (auction_name + "countratio", 0 if optimal_count_with_gft_zero == 0 else (auction_count / optimal_count_with_gft_zero) * 100)) results.append((auction_name + "gft", gft)) results.append( (auction_name + "gftratio", 0 if optimal_gft == 0 else gft / optimal_gft * 100)) #results_table.add(OrderedDict(results)) if len(total_results[str(num_of_agents_per_category)]) == 0: total_results[str( num_of_agents_per_category)] = results[0:len(results)] else: sum_result = total_results[str(num_of_agents_per_category)] for index in range(len(results)): if index > 2: sum_result[index] = (results[index][0], sum_result[index][1] + results[index][1]) for num_of_agents_per_category in nums_of_agents: results = total_results[str(num_of_agents_per_category)] if len(results) == 0: continue for index in range(len(results)): if index > 2: if 'ratio' in results[index][0]: results[index] = (results[index][0], results[index][1] / iterations) else: results[index] = (results[index][0], results[index][1] / iterations) #elif index == 0: # results[index] = (results[index][0], 'Average') results_table.add(OrderedDict(results)) if len(average_total_results[str( num_of_agents_per_category)]) == 0: average_total_results[str( num_of_agents_per_category)] = results[0:len(results)] else: sum_result = average_total_results[str( num_of_agents_per_category)] for index in range(len(results)): if index > 2: sum_result[index] = (sum_result[index][0], sum_result[index][1] + results[index][1]) for num_of_agents_per_category in nums_of_agents: results = average_total_results[str(num_of_agents_per_category)] if len(results) == 0: continue for index in range(len(results)): if index > 2: if 'ratio' in results[index][0]: results[index] = ( results[index][0], int(results[index][1] / len(stocks_prices) * 1000) / 1000) else: results[index] = (results[index][0], round( results[index][1] / len(stocks_prices), 1)) elif index == 0: results[index] = (results[index][0], 'Average') results_table.add(OrderedDict(results)) results_table.done()
def mcafee_trade_reduction(market: Market, ps_recipe: list, price_heuristic=True): """ Calculate the trade and prices using generalized-trade-reduction. :param market: contains a list of k categories, each containing several agents. :param ps_recipe: a list of integers, one integer per category. Each integer i represents the number of agents of category i that should be in each procurement-set. :param price_heuristic: whether to use the heuristic of setting the price to (s_{k+1)+b_{k+1})/2. Default is true, as in the original paper. :return: Trade object, representing the trade and prices. >>> # ONE BUYER, ONE SELLER >>> market = Market([AgentCategory("buyer", [9.]), AgentCategory("seller", [-4.])]) >>> print(market); print(mcafee_trade_reduction(market, [1,1])) Traders: [buyer: [9.0], seller: [-4.0]] No trade >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("seller", [-4.])]) >>> print(market); print(mcafee_trade_reduction(market, [1,1])) Traders: [buyer: [9.0, 8.0], seller: [-4.0]] No trade >>> market = Market([AgentCategory("seller", [-4.]), AgentCategory("buyer", [9.,8.])]) >>> print(market); print(mcafee_trade_reduction(market, [1,1])) Traders: [seller: [-4.0], buyer: [9.0, 8.0]] No trade >>> market = Market([AgentCategory("seller", [-4.,-3.]), AgentCategory("buyer", [9.])]) >>> print(market); print(mcafee_trade_reduction(market, [1,1])) Traders: [seller: [-3.0, -4.0], buyer: [9.0]] No trade >>> market = Market([AgentCategory("buyer", [9.]), AgentCategory("seller", [-4.,-3.])]) >>> print(market); print(mcafee_trade_reduction(market, [1,1])) Traders: [buyer: [9.0], seller: [-3.0, -4.0]] No trade >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("seller", [-4.,-3.])]) >>> print(market); print(mcafee_trade_reduction(market, [1,1])) Traders: [buyer: [9.0, 8.0], seller: [-3.0, -4.0]] buyer: [9.0]: all 1 agents trade and pay 8.0 seller: [-3.0]: all 1 agents trade and pay -4.0 >>> market = Market([AgentCategory("seller", [-4.,-3.]), AgentCategory("buyer", [9.,8.])]) >>> print(mcafee_trade_reduction(market, [1,1])) seller: [-3.0]: all 1 agents trade and pay -4.0 buyer: [9.0]: all 1 agents trade and pay 8.0 >>> market = Market([AgentCategory("seller", [-8.,-3.]), AgentCategory("buyer", [9.,4.])]) >>> print(mcafee_trade_reduction(market, [1,1])) seller: [-3.0]: all 1 agents trade and pay -6.0 buyer: [9.0]: all 1 agents trade and pay 6.0 # # >>> # >>> # ONE BUYER, ONE SELLER, ONE MEDIATOR # >>> market = Market([AgentCategory("seller", [-4.,-3.]), AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-1.,-2.])]) # >>> print(market); print(mcafee_trade_reduction(market, [1,1,1])) # Traders: [seller: [-3.0, -4.0], buyer: [9.0, 8.0], mediator: [-1.0, -2.0]] # seller: [-3.0]: all 1 agents trade and pay -4.0 # buyer: [9.0]: all 1 agents trade and pay 8.0 # mediator: [-1.0, -2.0]: random 1 out of 2 agents trade and pay -4.0 # # >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-1.,-2.]), AgentCategory("seller", [-4.,-3.,-10.])]) # >>> print(market); print(mcafee_trade_reduction(market, [1,1,1])) # Traders: [buyer: [9.0, 8.0], mediator: [-1.0, -2.0], seller: [-3.0, -4.0, -10.0]] # buyer: [9.0]: all 1 agents trade and pay 8.0 # mediator: [-1.0]: all 1 agents trade and pay -2.0 # seller: [-3.0, -4.0]: random 1 out of 2 agents trade and pay -6.0 # # >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-1.,-2.]), AgentCategory("seller", [-4.,-3.,-5.])]) # >>> print(market); print(mcafee_trade_reduction(market, [1,1,1])) # Traders: [buyer: [9.0, 8.0], mediator: [-1.0, -2.0], seller: [-3.0, -4.0, -5.0]] # buyer: [9.0]: all 1 agents trade and pay 8.0 # mediator: [-1.0, -2.0]: random 1 out of 2 agents trade and pay -3.0 # seller: [-3.0, -4.0]: random 1 out of 2 agents trade and pay -5.0 # # >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-1.,-2.]), AgentCategory("seller", [-4.,-3.,-2.])]) # >>> print(market); print(mcafee_trade_reduction(market, [1,1,1])) # Traders: [buyer: [9.0, 8.0], mediator: [-1.0, -2.0], seller: [-2.0, -3.0, -4.0]] # buyer: [9.0]: all 1 agents trade and pay 8.0 # mediator: [-1.0, -2.0]: random 1 out of 2 agents trade and pay -4.0 # seller: [-2.0, -3.0]: random 1 out of 2 agents trade and pay -4.0 # # >>> market = Market([AgentCategory("buyer", [9.,8.,7.]), AgentCategory("mediator", [-1.,-2.,-3.]), AgentCategory("seller", [-4.,-3.,-2.])]) # >>> print(market); print(mcafee_trade_reduction(market, [1,1,1])) # Traders: [buyer: [9.0, 8.0, 7.0], mediator: [-1.0, -2.0, -3.0], seller: [-2.0, -3.0, -4.0]] # buyer: [9.0, 8.0]: all 2 agents trade and pay 7.0 # mediator: [-1.0, -2.0]: all 2 agents trade and pay -3.0 # seller: [-2.0, -3.0]: all 2 agents trade and pay -4.0 # # >>> market = Market([AgentCategory("buyer", [9.,8.,4.]), AgentCategory("mediator", [-1.,-2.,-3.]), AgentCategory("seller", [-4.,-3.,-2.])]) # >>> print(market); print(mcafee_trade_reduction(market, [1,1,1])) # Traders: [buyer: [9.0, 8.0, 4.0], mediator: [-1.0, -2.0, -3.0], seller: [-2.0, -3.0, -4.0]] # buyer: [9.0, 8.0]: all 2 agents trade and pay 7.0 # mediator: [-1.0, -2.0]: all 2 agents trade and pay -3.0 # seller: [-2.0, -3.0]: all 2 agents trade and pay -4.0 """ if len(ps_recipe) != market.num_categories: raise ValueError( "There are {} categories but {} elements in the PS recipe".format( market.num_categories, len(ps_recipe))) if any(r != 1 for r in ps_recipe): raise ValueError( "Currently, the trade-reduction protocol supports only recipes of ones; {} was given" .format(ps_recipe)) logger.info("\n#### McAfee Trade Reduction\n") logger.info(market) (optimal_trade, remaining_market) = market.optimal_trade(ps_recipe) for category in remaining_market.categories: if len(category) == 0: category.append(-MAX_VALUE) logger.info("Optimal trade, by increasing GFT: {}".format(optimal_trade)) first_negative_ps = remaining_market.get_highest_agents(ps_recipe) if price_heuristic: price_candidate = sum([abs(x) for x in first_negative_ps ]) / len(first_negative_ps) logger.info("First negative PS: {}, candidate price: {}".format( first_negative_ps, price_candidate)) actual_traders = market.empty_agent_categories() if optimal_trade.num_of_deals() > 0: last_positive_ps = optimal_trade.procurement_sets[0] if price_heuristic and is_price_good_for_ps(price_candidate, last_positive_ps): # All optimal traders trade in the candidate price - no reduction prices = [ price_candidate * (-1 if last_positive_ps[i] < 0 else +1) for i in range(market.num_categories) ] else: # Trade reduction del optimal_trade.procurement_sets[0] prices = last_positive_ps for ps in optimal_trade.procurement_sets: for i in range(market.num_categories): if ps[i] is not None: actual_traders[i].append(ps[i]) else: prices = [0 for i in range(market.num_categories)] logger.info("\n") return TradeWithSinglePrice(actual_traders, ps_recipe, prices)
def experiment(results_csv_file: str, auction_function: Callable, auction_name: str, recipe: tuple, value_ranges: list, nums_of_agents: list, num_of_iterations: int): """ Run an experiment similar to McAfee (1992) experiment on the given auction. :param auction_function: the function for executing the auction under consideration. :param auction_name: title of the experiment, for printouts. :param nums_of_agents: a list of the numbers of agents with which to run the experiment. :param value_ranges: for each category, a pair (min_value,max_value). The value for each agent in this category is selected uniformly at random between min_value and max_value. :param num_of_iterations: how many times to repeat the experiment for each num of agents. """ results_table = TeeTable(TABLE_COLUMNS, results_csv_file) recipe_str = ":".join(map(str, recipe)) num_of_categories = len(recipe) for num_of_agents_per_category in nums_of_agents: sum_optimal_count = sum_auction_count = 0 # count the number of deals done in the optimal vs. the actual auction. sum_optimal_gft = sum_auction_total_gft = sum_auction_market_gft = 0 for _ in range(num_of_iterations): market = Market([ AgentCategory.uniformly_random( "agent", num_of_agents_per_category * recipe[category], value_ranges[category][0], value_ranges[category][1]) for category in range(num_of_categories) ]) (optimal_trade, _) = market.optimal_trade(recipe) auction_trade = auction_function(market, recipe) sum_optimal_count += optimal_trade.num_of_deals() sum_auction_count += auction_trade.num_of_deals() sum_optimal_gft += optimal_trade.gain_from_trade() sum_auction_total_gft += auction_trade.gain_from_trade( including_auctioneer=True) sum_auction_market_gft += auction_trade.gain_from_trade( including_auctioneer=False) # print("Num of times {} attains the maximum GFT: {} / {} = {:.2f}%".format(title, count_optimal_gft, num_of_iterations, count_optimal_gft * 100 / num_of_iterations)) # print("GFT of {}: {:.2f} / {:.2f} = {:.2f}%".format(title, sum_auction_gft, sum_optimal_gft, 0 if sum_optimal_gft==0 else sum_auction_gft * 100 / sum_optimal_gft)) results_table.add( OrderedDict(( ("iterations", num_of_iterations), ("auction_name", auction_name), ("recipe", recipe_str), ("num_of_agents", num_of_agents_per_category), ("mean_optimal_count", round(sum_optimal_count / num_of_iterations, 2)), ("mean_auction_count", round(sum_auction_count / num_of_iterations, 2)), ("count_ratio", 0 if sum_optimal_count == 0 else int( (sum_auction_count / sum_optimal_count) * 10000) / 100), ("mean_optimal_gft", round(sum_optimal_gft / num_of_iterations, 2)), ("mean_auction_total_gft", round(sum_auction_total_gft / num_of_iterations, 2)), ("total_gft_ratio", 0 if sum_optimal_gft == 0 else round( sum_auction_total_gft / sum_optimal_gft * 100, 2)), ("mean_auction_market_gft", round(sum_auction_market_gft / num_of_iterations, 2)), ("market_gft_ratio", 0 if sum_optimal_gft == 0 else round( sum_auction_market_gft / sum_optimal_gft * 100, 2)), ))) results_table.done()
def experiment(results_csv_file: str, recipes: tuple, value_ranges: list, nums_of_agents: list, num_of_iterations: int): """ Run an experiment similar to McAfee (1992) experiment on the given auction. :param recipes: list of recipes. :param nums_of_agents: a list of the numbers of agents with which to run the experiment. :param value_ranges: for each category, a pair (min_value,max_value). The value for each agent in this category is selected uniformly at random between min_value and max_value. :param num_of_iterations: how many times to repeat the experiment for each num of agents. """ results_table = TeeTable(TABLE_COLUMNS, results_csv_file) for recipe in recipes: recipe_str = ":".join(map(str, recipe)) num_of_categories = len(recipe) external_wins_gft = tie_gft = ascending_wins_gft = 0 external_wins_k = tie_k = ascending_wins_k = 0 for num_of_agents_per_category in nums_of_agents: external_sum_auction_count = ascending_sum_auction_count = 0 # count the number of deals done the ascending auction. external_sum_auction_gft = ascending_sum_auction_gft = 0 agents_recipe_values = [sum(recipe) - recipe[0]] + [ recipe[0] for _ in range(1, len(recipe)) ] for _ in range(num_of_iterations): market = Market([ AgentCategory.uniformly_random( "agent", num_of_agents_per_category * recipe[category], value_ranges[category][0] * agents_recipe_values[category], value_ranges[category][1] * agents_recipe_values[category]) for category in range(num_of_categories) ]) (optimal_trade, _) = market.optimal_trade(recipe) external_auction_trade = budget_balanced_trade_reduction( market, recipe) ascending_auction_trade = budget_balanced_ascending_auction( market, recipe) external_sum_auction_count += external_auction_trade.num_of_deals( ) ascending_sum_auction_count += ascending_auction_trade.num_of_deals( ) external_sum_auction_gft += external_auction_trade.gain_from_trade( ) ascending_sum_auction_gft += ascending_auction_trade.gain_from_trade( ) if external_sum_auction_count > ascending_sum_auction_count: external_wins_k += 1 elif external_sum_auction_count == ascending_sum_auction_count: tie_k += 1 else: ascending_wins_k += 1 if external_sum_auction_gft > ascending_sum_auction_gft: external_wins_gft += 1 elif external_sum_auction_gft == ascending_sum_auction_gft: tie_gft += 1 else: ascending_wins_gft += 1 num_agents = len(nums_of_agents) results_table.add( OrderedDict(( ("recipe", recipe), ("external_wins_gft", int(external_wins_gft * 100 / num_agents)), ("tie_gft", int(tie_gft * 100 / num_agents)), ("ascending_wins_gft", int(ascending_wins_gft * 100 / num_agents)), ("external_wins_k", int(external_wins_k * 100 / num_agents)), ("tie_k", int(tie_k * 100 / num_agents)), ("ascending_wins_k", int(ascending_wins_k * 100 / num_agents)), ("external_wins", external_wins_gft), ("tie", tie_gft), ("ascending_wins", ascending_wins_gft), ))) results_table.done()
def experiment(results_csv_file: str, auction_functions: list, auction_names: str, recipe: tuple, nums_of_agents=None, stocks_prices: list = None, stock_names: list = None, num_of_iterations=1000, run_with_stock_prices=True, report_diff=False): """ Run an experiment similar to McAfee (1992) experiment on the given auction. :param results_csv_file: the experiment result file. :param auction_functions: list of functions for executing the auction under consideration. :param auction_names: titles of the experiment, for printouts. :param recipe: can be any vector of ones, e.g. (1,1,1), for our trade-reduction mechanism, or any vector of positive integers for our ascending-auction mechanism. :param stocks_prices: list of prices for each stock and each agent. :param stock_names: list of stocks names which prices are belongs, for naming only. """ TABLE_COLUMNS = [ "iterations", "stockname", "recipe", "numpossibletrades", "optimalcount", "gftratioformula", "optimalcountwithgftzero", "optimalgft", "optimalgftwithgftzero" ] AUCTION_COLUMNS = [ "count", "countratio", "totalgft", "totalgftratio", "withoutgftzerocountratio", "withoutgftzerototalgft", "withoutgftzerototalgftratio", "marketgft", "marketgftratio" ] if path.exists(results_csv_file): print('The file', results_csv_file, 'already exists, skipping') return else: print('Running for the file', results_csv_file) if stocks_prices is None: (stocks_prices, stock_names) = getStocksPricesShuffled() column_names = TABLE_COLUMNS column_names += [ auction_name + column for auction_name in auction_names for column in AUCTION_COLUMNS ] results_table = TeeTable(column_names, results_csv_file) recipe_str = ":".join(map(str, recipe)) recipe_sum = sum(recipe) recipe_sum_for_buyer = (recipe_sum - recipe[0]) / recipe[0] if nums_of_agents is None: nums_of_agents = [10000000] #print(nums_of_agents) total_results = {} for num_of_agents_per_category in nums_of_agents: total_results[str(num_of_agents_per_category)] = [] #print(total_results) for i in range(len(stocks_prices)): stock_prices = stocks_prices[i] for num_of_possible_ps in nums_of_agents: for iteration in range(num_of_iterations): categories = [] if run_with_stock_prices: while len(stock_prices) < num_of_possible_ps * recipe_sum: stock_prices = stock_prices + stock_prices random.shuffle(stock_prices) index = 0 for category in recipe: next_index = index + num_of_possible_ps * category price_sign = recipe_sum_for_buyer if index == 0 else -1 #price_value_multiple = -1 * buyer_agent_count if index > 0 else recipe_sum - buyer_agent_count categories.append( AgentCategory("agent", [ int(price * price_sign) for price in stock_prices[index:next_index] ])) index = next_index else: #prices from random. for index in range(len(recipe)): #for category in recipe: min_value = -100000 if index > 0 else recipe_sum_for_buyer max_value = -1 if index > 0 else 100000 * recipe_sum_for_buyer categories.append( AgentCategory.uniformly_random( "agent", num_of_possible_ps * recipe[index], min_value, max_value)) market = Market(categories) (optimal_trade, _) = market.optimal_trade(ps_recipe=list(recipe), max_iterations=10000000, include_zero_gft_ps=False) optimal_count = optimal_trade.num_of_deals() optimal_gft = optimal_trade.gain_from_trade() (optimal_trade_with_gft_zero, _) = market.optimal_trade(ps_recipe=list(recipe), max_iterations=10000000) optimal_count_with_gft_zero = optimal_trade_with_gft_zero.num_of_deals( ) optimal_gft_with_gft_zero = optimal_trade_with_gft_zero.gain_from_trade( ) results = [ ("iterations", num_of_iterations), ("stockname", stock_names[i]), ("recipe", recipe_str), ("numpossibletrades", int(num_of_possible_ps)), ("optimalcount", optimal_count), ("gftratioformula", (optimal_count - 1) * 100 / (optimal_count if min(recipe) == max(recipe) and recipe[0] == 1 else optimal_count + 1) if optimal_count > 1 else 0), ("optimalcountwithgftzero", optimal_count_with_gft_zero), ("optimalgft", optimal_gft), ("optimalgftwithgftzero", optimal_gft_with_gft_zero) ] for auction_index in range(len(auction_functions)): auction_trade = auction_functions[auction_index](market, recipe) count = auction_trade.num_of_deals() total_gft = auction_trade.gain_from_trade( including_auctioneer=True) market_gft = auction_trade.gain_from_trade( including_auctioneer=False) auction_name = auction_names[auction_index] results.append( (auction_name + "count", auction_trade.num_of_deals())) results.append( (auction_name + "countratio", 0 if optimal_count == 0 else (count / optimal_count_with_gft_zero) * 100)) results.append((auction_name + "totalgft", total_gft)) results.append((auction_name + "totalgftratio", 0 if optimal_gft == 0 else total_gft / optimal_gft_with_gft_zero * 100)) results.append((auction_name + "marketgft", market_gft)) results.append((auction_name + "marketgftratio", 0 if optimal_gft == 0 else market_gft / optimal_gft_with_gft_zero * 100)) results.append((auction_name + "withoutgftzerocountratio", 0 if optimal_count == 0 else (count / optimal_count) * 100)) results.append( (auction_name + "withoutgftzerototalgft", total_gft)) results.append( (auction_name + "withoutgftzerototalgftratio", 0 if optimal_gft == 0 else total_gft / optimal_gft * 100)) #We check which auction did better and print the market and their results. if report_diff: gft_to_compare = -1 k_to_compare = -1 gft_found = False k_found = False for (label, value) in results: if 'SBB' in label: if gft_found is False and label.endswith( 'totalgft'): if gft_to_compare < 0: gft_to_compare = value elif gft_to_compare != value: with open('diff_in_sbbs_gft.txt', 'a') as f: f.write( 'There is diff in gft between two auctions: ' + str(gft_to_compare) + ' ' + str(value) + '\n') f.write(str(results) + '\n') if num_of_possible_ps < 10: f.write(str(market) + '\n') gft_found = True elif k_found is False and label.endswith('count'): if k_to_compare < 0: k_to_compare = value elif k_to_compare != value: with open('diff_in_sbbs_k.txt', 'a') as f: f.write( 'There is diff in gft between two auctions: ' + str(k_to_compare) + ' ' + str(value) + '\n') f.write(str(results) + '\n') if num_of_possible_ps < 10: f.write(str(market) + '\n') k_found = True compare_sbbs = True if compare_sbbs: gft_to_compare = -1 k_to_compare = -1 gft_found = False k_found = False for (label, value) in results: if 'SBB' in label: if gft_found is False and label.endswith( 'totalgft'): if gft_to_compare < 0: gft_to_compare = value elif gft_to_compare > value: with open('diff_in_sbbs_gft.txt', 'a') as f: f.write( 'There is diff in gft between two auctions: ' + str(gft_to_compare) + ' ' + str(value) + '\n') f.write(str(results) + '\n') if num_of_possible_ps < 10: f.write(str(market) + '\n') gft_found = True elif k_found is False and label.endswith('count'): if k_to_compare < 0: k_to_compare = value elif k_to_compare > value: with open('diff_in_sbbs_k.txt', 'a') as f: f.write( 'There is diff in gft between two auctions: ' + str(k_to_compare) + ' ' + str(value) + '\n') f.write(str(results) + '\n') if num_of_possible_ps < 10: f.write(str(market) + '\n') k_found = True #results_table.add(OrderedDict(results)) #print(results) if len(total_results[str(num_of_possible_ps)]) == 0: total_results[str( num_of_possible_ps)] = results[0:len(results)] else: sum_result = total_results[str(num_of_possible_ps)] for index in range(len(results)): if index > 3: sum_result[index] = (results[index][0], sum_result[index][1] + results[index][1]) #print(total_results) print(stock_names[i], end=',') #break print() division_number = num_of_iterations * len(stocks_prices) #division_number = num_of_iterations for num_of_possible_ps in nums_of_agents: results = total_results[str(num_of_possible_ps)] for index in range(len(results)): if 'gftratio' in results[index][0]: results[index] = (results[index][0], padding_zeroes( results[index][1] / division_number, 3)) elif index > 3: results[index] = (results[index][0], padding_zeroes( results[index][1] / division_number, 2)) elif index == 1: results[index] = (results[index][0], 'Average') #print(results) results_table.add(OrderedDict(results)) results_table.done()
def experiment(results_csv_file: str, auction_functions: list, auction_names: str, recipe: tuple, nums_of_agents: list = None, stocks_prices: list = None, stock_names: list = None): """ Run an experiment similar to McAfee (1992) experiment on the given auction. :param results_csv_file: the experiment result file. :param auction_functions: list of functions for executing the auction under consideration. :param auction_names: titles of the experiment, for printouts. :param recipe: can be any vector of ones, e.g. (1,1,1), for our trade-reduction mechanism, or any vector of positive integers for our ascending-auction mechanism. :param nums_of_agents: list of n(s) for number of possible trades to make the calculations. :param stocks_prices: list of prices for each stock and each agent. :param stock_names: list of stocks names which prices are belongs, for naming only. """ TABLE_COLUMNS = [ "stock_name", "recipe", "num_possible_trades", "optimal_count", "optimal_count_with_gft_zero", "optimal_gft" ] AUCTION_COLUMNS = ["auction_count", "count_ratio", "gft", "gft_ratio"] print(recipe) if stocks_prices is None: (stocks_prices, stock_names) = getStocksPrices(recipe) column_names = TABLE_COLUMNS column_names += [ auction_name + '_' + column for auction_name in auction_names for column in AUCTION_COLUMNS ] results_table = TeeTable(column_names, results_csv_file) recipe_str = ":".join(map(str, recipe)) if nums_of_agents is None: nums_of_agents = [10000000] for i in range(len(stocks_prices)): last_iteration = False for num_of_agents_per_category in nums_of_agents: num_of_possible_ps = min(num_of_agents_per_category, len(stocks_prices[i][0])) if last_iteration is True and num_of_possible_ps < num_of_agents_per_category: break if num_of_possible_ps < num_of_agents_per_category: if last_iteration is True: break else: last_iteration = True market = Market([ AgentCategory("agent", stocks_prices[i][j]) for j in range(len(stocks_prices[i])) ]) else: market = Market([ AgentCategory( "agent", stocks_prices[i][j][0:num_of_possible_ps * recipe[j]]) for j in range(len(stocks_prices[i])) ]) (optimal_trade, _) = market.optimal_trade(ps_recipe=list(recipe), max_iterations=10000000, include_zero_gft_ps=False) optimal_count = optimal_trade.num_of_deals() optimal_gft = optimal_trade.gain_from_trade() (optimal_trade_with_gft_zero, _) = market.optimal_trade(ps_recipe=list(recipe), max_iterations=10000000) optimal_count_with_gft_zero = optimal_trade_with_gft_zero.num_of_deals( ) results = [("stock_name", stock_names[i]), ("recipe", recipe_str), ("num_possible_trades", round(num_of_possible_ps)), ("optimal_count", round(optimal_count, 2)), ("optimal_count_with_gft_zero", round(optimal_count_with_gft_zero, 2)), ("optimal_gft", round(optimal_gft, 2))] for auction_index in range(len(auction_functions)): auction_trade = auction_functions[auction_index](market, recipe) auction_count = auction_trade.num_of_deals() if (auction_trade.num_of_deals() > optimal_trade_with_gft_zero.num_of_deals()): # print(sorted(stocks_prices[i][0][:num_of_possible_ps*recipe[0]])) # print(sorted(stocks_prices[i][1][:num_of_possible_ps*recipe[1]])) print( "Warning!!! the number of deals in action is greater than optimal!" ) print("Optimal num of deals: ", optimal_trade.num_of_deals()) print("Auction num of deals: ", auction_trade.num_of_deals()) print("Auction name: ", auction_names[auction_index]) gft = auction_trade.gain_from_trade(including_auctioneer=False) auction_name = auction_names[auction_index] results.append((auction_name + "_auction_count", round(auction_trade.num_of_deals(), 2))) results.append( (auction_name + "_count_ratio", 0 if optimal_count_with_gft_zero == 0 else int( (auction_count / optimal_count_with_gft_zero) * 100000) / 1000)) results.append((auction_name + "_gft", round(gft, 2))) results.append( (auction_name + "_gft_ratio", 0 if optimal_gft == 0 else round(gft / optimal_gft * 100, 3))) results_table.add(OrderedDict(results)) results_table.done()
def budget_balanced_ascending_auction( market: Market, ps_recipe: list, max_iterations=999999999) -> TradeWithSinglePrice: """ Calculate the trade and prices using generalized-ascending-auction. :param market: contains a list of k categories, each containing several agents. :param ps_recipe: a list of integers, one integer per category. Each integer i represents the number of agents of category i that should be in each procurement-set. :return: Trade object, representing the trade and prices. >>> # ONE BUYER, ONE SELLER >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("seller", [-4.])]) >>> print(market); print(budget_balanced_ascending_auction(market, [1,1])) Traders: [buyer: [9.0, 8.0], seller: [-4.0]] No trade >>> market = Market([AgentCategory("seller", [-4.]), AgentCategory("buyer", [9.,8.])]) >>> print(market); print(budget_balanced_ascending_auction(market, [1,1])) Traders: [seller: [-4.0], buyer: [9.0, 8.0]] seller: [-4.0]: all 1 agents trade and pay -8.0 buyer: [9.0]: all 1 agents trade and pay 8.0 >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("seller", [-4.,-3.])]) >>> print(market); print(budget_balanced_ascending_auction(market, [1,1])) Traders: [buyer: [9.0, 8.0], seller: [-3.0, -4.0]] buyer: [9.0]: all 1 agents trade and pay 8.0 seller: [-3.0, -4.0]: random 1 out of 2 agents trade and pay -8.0 >>> # ONE BUYER, ONE SELLER, ONE MEDIATOR >>> market = Market([AgentCategory("seller", [-4.,-3.]), AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-1.,-2.])]) >>> print(market); print(budget_balanced_ascending_auction(market, [1,1,1])) Traders: [seller: [-3.0, -4.0], buyer: [9.0, 8.0], mediator: [-1.0, -2.0]] seller: [-3.0]: all 1 agents trade and pay -4.0 buyer: [9.0]: all 1 agents trade and pay 8.0 mediator: [-1.0, -2.0]: random 1 out of 2 agents trade and pay -4.0 >>> market = Market([AgentCategory("buyer", [9.,8.,7.]), AgentCategory("mediator", [-1.,-2.,-3.]), AgentCategory("seller", [-4.,-3.,-2.])]) >>> print(market); print(budget_balanced_ascending_auction(market, [1,1,1])) Traders: [buyer: [9.0, 8.0, 7.0], mediator: [-1.0, -2.0, -3.0], seller: [-2.0, -3.0, -4.0]] buyer: [9.0, 8.0]: all 2 agents trade and pay 7.0 mediator: [-1.0, -2.0]: all 2 agents trade and pay -3.0 seller: [-2.0, -3.0, -4.0]: random 2 out of 3 agents trade and pay -4.0 >>> # ONE BUYER, TWO SELLERS >>> market = Market([AgentCategory("buyer", [9., 8., 7., 6.]), AgentCategory("seller", [-6., -5., -4.,-3.,-2.,-1.])]) >>> print(market); print(budget_balanced_ascending_auction(market, [1,2])) Traders: [buyer: [9.0, 8.0, 7.0, 6.0], seller: [-1.0, -2.0, -3.0, -4.0, -5.0, -6.0]] buyer: [9.0]: all 1 agents trade and pay 8.0 seller: [-1.0, -2.0, -3.0, -4.0]: random 2 out of 4 agents trade and pay -4.0 >>> market = Market([AgentCategory("seller", [-4.,-3.,-2.,-1.]), AgentCategory("buyer", [9.,8.])]) >>> print(market); print(budget_balanced_ascending_auction(market, [2,1])) Traders: [seller: [-1.0, -2.0, -3.0, -4.0], buyer: [9.0, 8.0]] seller: [-1.0, -2.0, -3.0]: random 2 out of 3 agents trade and pay -4.0 buyer: [9.0, 8.0]: random 1 out of 2 agents trade and pay 8.0 >>> # ONE SELLER, ONE BUYER, ZERO MEDIATORS >>> market = Market([AgentCategory("seller", [-4.]), AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-5, -7])]) >>> print(market); print(budget_balanced_ascending_auction(market, [1,1,0])) Traders: [seller: [-4.0], buyer: [9.0, 8.0], mediator: [-5, -7]] seller: [-4.0]: all 1 agents trade and pay -8.0 buyer: [9.0]: all 1 agents trade and pay 8.0 """ num_categories = market.num_categories if len(ps_recipe) != num_categories: raise ValueError( "There are {} categories but {} elements in the PS recipe".format( num_categories, len(ps_recipe))) relevant_category_indices = [ i for i in range(num_categories) if ps_recipe[i] > 0 ] logger.info("\n#### Budget-Balanced Ascending Auction\n") logger.info(market) logger.info("Procurement-set recipe: {}".format(ps_recipe)) optimal_trade = market.optimal_trade(ps_recipe, max_iterations=max_iterations)[0] logger.info("For comparison, the optimal trade is: %s\n", optimal_trade) remaining_market = market.clone() prices = AscendingPriceVector(ps_recipe, -MAX_VALUE) # Functions for calculating the number of potential PS that can be supported by a category: fractional_potential_ps = lambda category_index: remaining_market.categories[ category_index].size() / ps_recipe[category_index] integral_potential_ps = lambda category_index: math.floor( remaining_market.categories[category_index].size() / ps_recipe[ category_index]) while True: # find a category with a largest number of potential PS, and increase its price main_category_index = max(relevant_category_indices, key=fractional_potential_ps) main_category = remaining_market.categories[main_category_index] logger.info("Chosen category: {} with {} agents and ratio {}".format( main_category.name, main_category.size(), fractional_potential_ps(main_category_index))) if main_category.size() == 0: logger.info("\nThe %s category became empty - no trade!", main_category.name) logger.info(" Final price-per-unit vector: %s", prices) break prices.increase_price_up_to_balance(main_category_index, main_category.lowest_agent_value(), main_category.name) if prices.status == PriceStatus.STOPPED_AT_ZERO_SUM: logger.info("\nPrice crossed zero.") logger.info(" Final price-per-unit vector: %s", prices) break main_category.remove_lowest_agent() logger.info( " {} price increases to {}: {} agents and ratio {}".format( main_category.name, prices[main_category_index], main_category.size(), fractional_potential_ps(main_category_index))) logger.info(remaining_market) return TradeWithSinglePrice(remaining_market.categories, ps_recipe, prices.prices)
def budget_balanced_trade_reduction(market:Market, ps_recipe:list, including_gft_0:bool = True): """ Calculate the trade and prices using generalized-trade-reduction. :param market: contains a list of k categories, each containing several agents. :param ps_recipe: a list of integers, one integer per category. Each integer i represents the number of agents of category i that should be in each procurement-set. :return: Trade object, representing the trade and prices. >>> market = Market([AgentCategory("seller", [-1, -2, -3, -4, -5, -7, -8, -10, -11]),AgentCategory("buyer", [17, 14, 13, 9, 6])]) >>> print(market); print(budget_balanced_trade_reduction(market, [2, 1])) Traders: [seller: [-1, -2, -3, -4, -5, -7, -8, -10, -11], buyer: [17, 14, 13, 9, 6]] seller: [-1, -2, -3, -4]: all 4 agents trade and pay -5 buyer: [17, 14, 13]: random 2 out of 3 agents trade and pay 10.0 >>> market = Market([AgentCategory("mediator", [-3, -4, -5, -6, -7, -8, -9, -10]),AgentCategory("seller", [-1, -2, -3, -4, -5, -6, -7, -8]),AgentCategory("buyer", [17, 16, 15, 14, 13, 12, 10, 6])]) >>> print(market); print(budget_balanced_trade_reduction(market, [2,3,2])) Traders: [mediator: [-3, -4, -5, -6, -7, -8, -9, -10], seller: [-1, -2, -3, -4, -5, -6, -7, -8], buyer: [17, 16, 15, 14, 13, 12, 10, 6]] mediator: [-3, -4]: all 2 agents trade and pay -5 seller: [-1, -2, -3, -4, -5]: random 3 out of 5 agents trade and pay -5.333333333333333 buyer: [17, 16, 15, 14]: random 2 out of 4 agents trade and pay 13 >>> market = Market([AgentCategory("seller", [-2, -4, -6, -8, -10, -12, -14]),AgentCategory("buyer", [20, 18, 16, 9, 2, 1])]) >>> print(market); print(budget_balanced_trade_reduction(market, [2,3])) Traders: [seller: [-2, -4, -6, -8, -10, -12, -14], buyer: [20, 18, 16, 9, 2, 1]] seller: [-2, -4]: all 2 agents trade and pay -6 buyer: [20, 18, 16, 9]: random 3 out of 4 agents trade and pay 4.0 >>> # Multi trade >>> market = Market([AgentCategory("buyer", [17, 14, 13, 9, 6]),AgentCategory("seller", [-1, -2, -3, -4, -5, -7, -8, -10, -11])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1, 2])) Traders: [buyer: [17, 14, 13, 9, 6], seller: [-1, -2, -3, -4, -5, -7, -8, -10, -11]] buyer: [17, 14]: all 2 agents trade and pay 13 seller: [-1, -2, -3, -4, -5]: random 4 out of 5 agents trade and pay -6.5 >>> market = Market([AgentCategory("buyer", [17, 16, 15, 14, 13, 12, 10, 6]),AgentCategory("mediator", [-3, -4, -5, -6, -7, -8, -9, -10]),AgentCategory("seller", [-1, -2, -3, -4, -5, -6, -7, -8])]) >>> print(market); print(budget_balanced_trade_reduction(market, [2,2,3])) Traders: [buyer: [17, 16, 15, 14, 13, 12, 10, 6], mediator: [-3, -4, -5, -6, -7, -8, -9, -10], seller: [-1, -2, -3, -4, -5, -6, -7, -8]] buyer: [17, 16]: all 2 agents trade and pay 15 mediator: [-3, -4]: all 2 agents trade and pay -5 seller: [-1, -2, -3, -4, -5, -6]: random 3 out of 6 agents trade and pay -6.666666666666667 >>> market = Market([AgentCategory("buyer", [20, 18, 16, 9, 2, 1]),AgentCategory("seller", [-2, -4, -6, -8, -10, -12, -14])]) >>> print(market); print(budget_balanced_trade_reduction(market, [3,2])) Traders: [buyer: [20, 18, 16, 9, 2, 1], seller: [-2, -4, -6, -8, -10, -12, -14]] buyer: [20, 18, 16, 9]: random 3 out of 4 agents trade and pay 6.666666666666667 seller: [-2, -4, -6, -8]: random 2 out of 4 agents trade and pay -10 >>> # Multi trade >>> market = Market([AgentCategory("seller", [-1, -2, -2, -3]),AgentCategory("buyer", [2, 2, 2, 3])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1, 1])) Traders: [seller: [-1, -2, -2, -3], buyer: [3, 2, 2, 2]] seller: [-1, -2, -2]: all 3 agents trade and pay -2.0 buyer: [3, 2, 2]: all 3 agents trade and pay 2 >>> # Multi trade >>> market = Market([AgentCategory("buyer", [2, 2, 2, 3]),AgentCategory("seller", [-1, -2, -2, -3])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1, 1])) Traders: [buyer: [3, 2, 2, 2], seller: [-1, -2, -2, -3]] buyer: [3, 2]: all 2 agents trade and pay 2 seller: [-1, -2, -2]: random 2 out of 3 agents trade and pay -2.0 >>> market = Market([AgentCategory("buyer", [17, 16, 15, 14, 13, 12, 10, 6]),AgentCategory("mediator", [-3, -4, -5, -6, -7, -8, -9, -10]),AgentCategory("seller", [-1, -2, -3, -4, -5, -6, -7, -8])]) >>> print(market); print(budget_balanced_trade_reduction(market, [2,2,3])) Traders: [buyer: [17, 16, 15, 14, 13, 12, 10, 6], mediator: [-3, -4, -5, -6, -7, -8, -9, -10], seller: [-1, -2, -3, -4, -5, -6, -7, -8]] buyer: [17, 16]: all 2 agents trade and pay 15 mediator: [-3, -4]: all 2 agents trade and pay -5 seller: [-1, -2, -3, -4, -5, -6]: random 3 out of 6 agents trade and pay -6.666666666666667 >>> # ONE BUYER, ONE SELLER >>> market = Market([AgentCategory("buyer", [9.]), AgentCategory("seller", [-4.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [buyer: [9.0], seller: [-4.0]] No trade >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("seller", [-4.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [buyer: [9.0, 8.0], seller: [-4.0]] No trade >>> market = Market([AgentCategory("seller", [-4.]), AgentCategory("buyer", [9.,8.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [seller: [-4.0], buyer: [9.0, 8.0]] seller: [-4.0]: all 1 agents trade and pay -8.0 buyer: [9.0]: all 1 agents trade and pay 8.0 >>> market = Market([AgentCategory("seller", [-4.,-3.]), AgentCategory("buyer", [9.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [seller: [-3.0, -4.0], buyer: [9.0]] No trade >>> market = Market([AgentCategory("buyer", [9.]), AgentCategory("seller", [-4.,-3.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [buyer: [9.0], seller: [-3.0, -4.0]] buyer: [9.0]: all 1 agents trade and pay 4.0 seller: [-3.0]: all 1 agents trade and pay -4.0 >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("seller", [-4.,-3.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [buyer: [9.0, 8.0], seller: [-3.0, -4.0]] buyer: [9.0]: all 1 agents trade and pay 8.0 seller: [-3.0, -4.0]: random 1 out of 2 agents trade and pay -8.0 >>> market = Market([AgentCategory("seller", [-4.,-3.]), AgentCategory("buyer", [9.,8.])]) >>> print(budget_balanced_trade_reduction(market, [1,1])) seller: [-3.0]: all 1 agents trade and pay -4.0 buyer: [9.0, 8.0]: random 1 out of 2 agents trade and pay 4.0 >>> # ALL POSITIVE VALUES >>> market = Market([AgentCategory("buyer1", [4.,3.]), AgentCategory("buyer2", [9.,8.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [buyer1: [4.0, 3.0], buyer2: [9.0, 8.0]] buyer1: [4.0]: all 1 agents trade and pay 3.0 buyer2: [9.0, 8.0]: random 1 out of 2 agents trade and pay -3.0 >>> # ALL NEGATIVE VALUES >>> market = Market([AgentCategory("seller1", [-4.,-3.]), AgentCategory("seller2", [-9.,-8.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [seller1: [-3.0, -4.0], seller2: [-8.0, -9.0]] No trade >>> >>> # ONE BUYER, ONE SELLER, ONE MEDIATOR >>> market = Market([AgentCategory("seller", [-4.,-3.]), AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-1.,-2.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1,1])) Traders: [seller: [-3.0, -4.0], buyer: [9.0, 8.0], mediator: [-1.0, -2.0]] seller: [-3.0]: all 1 agents trade and pay -4.0 buyer: [9.0]: all 1 agents trade and pay 8.0 mediator: [-1.0, -2.0]: random 1 out of 2 agents trade and pay -4.0 >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-1.,-2.]), AgentCategory("seller", [-4.,-3.,-10.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1,1])) Traders: [buyer: [9.0, 8.0], mediator: [-1.0, -2.0], seller: [-3.0, -4.0, -10.0]] buyer: [9.0]: all 1 agents trade and pay 8.0 mediator: [-1.0]: all 1 agents trade and pay -2.0 seller: [-3.0, -4.0]: random 1 out of 2 agents trade and pay -6.0 >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-1.,-2.]), AgentCategory("seller", [-4.,-3.,-5.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1,1])) Traders: [buyer: [9.0, 8.0], mediator: [-1.0, -2.0], seller: [-3.0, -4.0, -5.0]] buyer: [9.0]: all 1 agents trade and pay 8.0 mediator: [-1.0, -2.0]: random 1 out of 2 agents trade and pay -3.0 seller: [-3.0, -4.0]: random 1 out of 2 agents trade and pay -5.0 >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-1.,-2.]), AgentCategory("seller", [-4.,-3.,-2.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1,1])) Traders: [buyer: [9.0, 8.0], mediator: [-1.0, -2.0], seller: [-2.0, -3.0, -4.0]] buyer: [9.0]: all 1 agents trade and pay 8.0 mediator: [-1.0, -2.0]: random 1 out of 2 agents trade and pay -4.0 seller: [-2.0, -3.0]: random 1 out of 2 agents trade and pay -4.0 >>> market = Market([AgentCategory("buyer", [9.,8.,7.]), AgentCategory("mediator", [-1.,-2.,-3.]), AgentCategory("seller", [-4.,-3.,-2.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1,1])) Traders: [buyer: [9.0, 8.0, 7.0], mediator: [-1.0, -2.0, -3.0], seller: [-2.0, -3.0, -4.0]] buyer: [9.0, 8.0]: all 2 agents trade and pay 7.0 mediator: [-1.0, -2.0]: all 2 agents trade and pay -3.0 seller: [-2.0, -3.0, -4.0]: random 2 out of 3 agents trade and pay -4.0 >>> market = Market([AgentCategory("buyer", [9.,8.,4.]), AgentCategory("mediator", [-1.,-2.,-3.]), AgentCategory("seller", [-4.,-3.,-2.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1,1])) Traders: [buyer: [9.0, 8.0, 4.0], mediator: [-1.0, -2.0, -3.0], seller: [-2.0, -3.0, -4.0]] buyer: [9.0, 8.0]: all 2 agents trade and pay 7.0 mediator: [-1.0, -2.0]: all 2 agents trade and pay -3.0 seller: [-2.0, -3.0]: all 2 agents trade and pay -4.0 """ if len(ps_recipe) != market.num_categories: raise ValueError( "There are {} categories but {} elements in the PS recipe". format(market.num_categories, len(ps_recipe))) logger.info("\n#### Budget-Balanced Trade Reduction\n") logger.info(market) (optimal_trade, remaining_market) = market.optimal_trade(ps_recipe) if len(optimal_trade.procurement_sets) == 0: return TradeWithSinglePrice(market.empty_agent_categories(), ps_recipe, [0] * len(ps_recipe)) highest_negative_ps = remaining_market.get_highest_agents(ps_recipe) list_ps_to_compete = optimal_trade.procurement_sets if highest_negative_ps: list_ps_to_compete = [highest_negative_ps] + list_ps_to_compete remaining_market.remove_highest_agents(ps_recipe) for category in remaining_market.categories: if len(category)==0: category.append(-MAX_VALUE) logger.info("Optimal trade including one highest non-positive trade, by increasing GFT: {}".format(optimal_trade)) logger.info("Remaining market: {}".format(remaining_market)) actual_traders = market.empty_agent_categories() # Preparing the order of pivot index for trade_reduction pivot_indexes = [] pivot_index_to_category_index = [] total = 0 index = 0 for agent in ps_recipe: pivot_indexes += [total+i for i in range(agent-1, -1, -1)] pivot_index_to_category_index += [index for _ in range(agent)] total += agent index += 1 found_external = False latest_prices = None for ps in list_ps_to_compete: ps = list(ps) if latest_prices is None: logger.info("\nCalculating prices for PS {}:".format(ps)) for pivot_index in pivot_indexes: pivot_value = ps[pivot_index] if found_external: actual_traders[pivot_index_to_category_index[pivot_index]].append(pivot_value) continue pivot_category_index = convert_category_index(ps_recipe, pivot_index) pivot_category = market.categories[pivot_category_index] logger.info(" Looking for external competition to {} with value {}:". format(pivot_category.name, pivot_value)) best_containing_PS = remaining_market.best_containing_PS(pivot_category_index, pivot_value) best_containing_GFT = sum([best_containing_PS[i]*ps_recipe[i] for i in range(len(best_containing_PS))]) if best_containing_GFT > 0 or (including_gft_0 and best_containing_GFT == 0): # EXTERNAL COMPETITION - KEEP TRADER found_external = True logger.info(" best PS is {},{} with GFT {}. It is positive so it is an external competition.". format(best_containing_PS, ps_recipe, best_containing_GFT)) prices = market.calculate_prices_by_external_competition(pivot_category_index, pivot_value, best_containing_PS, ps_recipe) logger.info(" Prices are {}".format(prices)) latest_prices = prices actual_traders[pivot_index_to_category_index[pivot_index]].append(pivot_value) #for i in range(len(prices)): # agent_prices = market.categories[i].values # for value in agent_prices: # #TODO: should we check if value is greater or equal? # if value >= prices[i]: # actual_traders[i].append(value) #break # done with current PS - move to next PS else: # NO EXTERNAL COMPETITION - REMOVE TRADER logger.info(" Best PS is {},{} with GFT {}. It is negative so it is not an external competition.". format(best_containing_PS, ps_recipe, best_containing_GFT)) logger.info(" Remove {} {} from trade and add to remaining market". format(pivot_category.name, pivot_value)) ps[pivot_index] = None remaining_market.append_trader(pivot_category_index, pivot_value) logger.info(" Remaining market is now: {}".format(remaining_market)) else: logger.info("\nPrices for PS {} are {}".format(ps, latest_prices)) #print(pivot_index_to_category_index) for pivot_index in pivot_indexes: pivot_value = ps[pivot_index] actual_traders[pivot_index_to_category_index[pivot_index]].append(pivot_value) logger.info("\n") result = TradeWithSinglePrice(actual_traders, ps_recipe, latest_prices) logger.info(result) return result
def budget_balanced_trade_reduction(market: Market, ps_recipe: list): """ Calculate the trade and prices using generalized-trade-reduction. :param market: contains a list of k categories, each containing several agents. :param ps_recipe: a list of integers, one integer per category. Each integer i represents the number of agents of category i that should be in each procurement-set. :return: Trade object, representing the trade and prices. >>> # ONE BUYER, ONE SELLER >>> market = Market([AgentCategory("buyer", [9.]), AgentCategory("seller", [-4.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [buyer: [9.0], seller: [-4.0]] No trade >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("seller", [-4.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [buyer: [9.0, 8.0], seller: [-4.0]] No trade >>> market = Market([AgentCategory("seller", [-4.]), AgentCategory("buyer", [9.,8.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [seller: [-4.0], buyer: [9.0, 8.0]] seller: [-4.0]: all 1 agents trade and pay -8.0 buyer: [9.0]: all 1 agents trade and pay 8.0 >>> market = Market([AgentCategory("seller", [-4.,-3.]), AgentCategory("buyer", [9.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [seller: [-3.0, -4.0], buyer: [9.0]] No trade >>> market = Market([AgentCategory("buyer", [9.]), AgentCategory("seller", [-4.,-3.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [buyer: [9.0], seller: [-3.0, -4.0]] buyer: [9.0]: all 1 agents trade and pay 4.0 seller: [-3.0]: all 1 agents trade and pay -4.0 >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("seller", [-4.,-3.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [buyer: [9.0, 8.0], seller: [-3.0, -4.0]] buyer: [9.0]: all 1 agents trade and pay 8.0 seller: [-3.0, -4.0]: random 1 out of 2 agents trade and pay -8.0 >>> market = Market([AgentCategory("seller", [-4.,-3.]), AgentCategory("buyer", [9.,8.])]) >>> print(budget_balanced_trade_reduction(market, [1,1])) seller: [-3.0]: all 1 agents trade and pay -4.0 buyer: [9.0, 8.0]: random 1 out of 2 agents trade and pay 4.0 >>> # ALL POSITIVE VALUES >>> market = Market([AgentCategory("buyer1", [4.,3.]), AgentCategory("buyer2", [9.,8.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [buyer1: [4.0, 3.0], buyer2: [9.0, 8.0]] buyer1: [4.0]: all 1 agents trade and pay 3.0 buyer2: [9.0, 8.0]: random 1 out of 2 agents trade and pay -3.0 >>> # ALL NEGATIVE VALUES >>> market = Market([AgentCategory("seller1", [-4.,-3.]), AgentCategory("seller2", [-9.,-8.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1])) Traders: [seller1: [-3.0, -4.0], seller2: [-8.0, -9.0]] No trade >>> >>> # ONE BUYER, ONE SELLER, ONE MEDIATOR >>> market = Market([AgentCategory("seller", [-4.,-3.]), AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-1.,-2.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1,1])) Traders: [seller: [-3.0, -4.0], buyer: [9.0, 8.0], mediator: [-1.0, -2.0]] seller: [-3.0]: all 1 agents trade and pay -4.0 buyer: [9.0]: all 1 agents trade and pay 8.0 mediator: [-1.0, -2.0]: random 1 out of 2 agents trade and pay -4.0 >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-1.,-2.]), AgentCategory("seller", [-4.,-3.,-10.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1,1])) Traders: [buyer: [9.0, 8.0], mediator: [-1.0, -2.0], seller: [-3.0, -4.0, -10.0]] buyer: [9.0]: all 1 agents trade and pay 8.0 mediator: [-1.0]: all 1 agents trade and pay -2.0 seller: [-3.0, -4.0]: random 1 out of 2 agents trade and pay -6.0 >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-1.,-2.]), AgentCategory("seller", [-4.,-3.,-5.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1,1])) Traders: [buyer: [9.0, 8.0], mediator: [-1.0, -2.0], seller: [-3.0, -4.0, -5.0]] buyer: [9.0]: all 1 agents trade and pay 8.0 mediator: [-1.0, -2.0]: random 1 out of 2 agents trade and pay -3.0 seller: [-3.0, -4.0]: random 1 out of 2 agents trade and pay -5.0 >>> market = Market([AgentCategory("buyer", [9.,8.]), AgentCategory("mediator", [-1.,-2.]), AgentCategory("seller", [-4.,-3.,-2.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1,1])) Traders: [buyer: [9.0, 8.0], mediator: [-1.0, -2.0], seller: [-2.0, -3.0, -4.0]] buyer: [9.0]: all 1 agents trade and pay 8.0 mediator: [-1.0, -2.0]: random 1 out of 2 agents trade and pay -4.0 seller: [-2.0, -3.0]: random 1 out of 2 agents trade and pay -4.0 >>> market = Market([AgentCategory("buyer", [9.,8.,7.]), AgentCategory("mediator", [-1.,-2.,-3.]), AgentCategory("seller", [-4.,-3.,-2.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1,1])) Traders: [buyer: [9.0, 8.0, 7.0], mediator: [-1.0, -2.0, -3.0], seller: [-2.0, -3.0, -4.0]] buyer: [9.0, 8.0]: all 2 agents trade and pay 7.0 mediator: [-1.0, -2.0]: all 2 agents trade and pay -3.0 seller: [-2.0, -3.0]: all 2 agents trade and pay -4.0 >>> market = Market([AgentCategory("buyer", [9.,8.,4.]), AgentCategory("mediator", [-1.,-2.,-3.]), AgentCategory("seller", [-4.,-3.,-2.])]) >>> print(market); print(budget_balanced_trade_reduction(market, [1,1,1])) Traders: [buyer: [9.0, 8.0, 4.0], mediator: [-1.0, -2.0, -3.0], seller: [-2.0, -3.0, -4.0]] buyer: [9.0, 8.0]: all 2 agents trade and pay 7.0 mediator: [-1.0, -2.0]: all 2 agents trade and pay -3.0 seller: [-2.0, -3.0]: all 2 agents trade and pay -4.0 """ if len(ps_recipe) != market.num_categories: raise ValueError( "There are {} categories but {} elements in the PS recipe".format( market.num_categories, len(ps_recipe))) if any(r != 1 for r in ps_recipe): raise ValueError( "Currently, the trade-reduction protocol supports only recipes of ones; {} was given" .format(ps_recipe)) logger.info("\n#### Budget-Balanced Trade Reduction\n") logger.info(market) (optimal_trade, remaining_market) = market.optimal_trade(ps_recipe) for category in remaining_market.categories: if len(category) == 0: category.append(-MAX_VALUE) logger.info("Optimal trade, by increasing GFT: {}".format(optimal_trade)) logger.info("Remaining market: {}".format(remaining_market)) actual_traders = market.empty_agent_categories() latest_prices = None for ps in optimal_trade.procurement_sets: ps = list(ps) if latest_prices is None: logger.info("\nCalculating prices for PS {}:".format(ps)) for pivot_index in range(len(ps)): pivot_value = ps[pivot_index] pivot_category = market.categories[pivot_index] logger.info( " Looking for external competition to {} with value {}:". format(pivot_category.name, pivot_value)) best_containing_PS = remaining_market.best_containing_PS( pivot_index, pivot_value) best_containing_GFT = sum(best_containing_PS) if best_containing_GFT > 0: # EXTERNAL COMPETITION - KEEP TRADER logger.info( " best PS is {} with GFT {}. It is positive so it is an external competition." .format(best_containing_PS, best_containing_GFT)) prices = market.calculate_prices_by_external_competition( pivot_index, pivot_value, best_containing_PS) logger.info(" Prices are {}".format(prices)) latest_prices = prices for i in range(market.num_categories): if ps[i] is not None: actual_traders[i].append(ps[i]) break # done with current PS - move to next PS else: # NO EXTERNAL COMPETITION - REMOVE TRADER logger.info( " Best PS is {} with GFT {}. It is negative so it is not an external competition." .format(best_containing_PS, best_containing_GFT)) logger.info( " Remove {} {} from trade and add to remaining market" .format(pivot_category.name, pivot_value)) ps[pivot_index] = None remaining_market.append_trader(pivot_index, pivot_value) logger.info(" Remaining market is now: {}".format( remaining_market)) else: logger.info("\nPrices for PS {} are {}".format(ps, latest_prices)) for i in range(market.num_categories): if ps[i] is not None: actual_traders[i].append(ps[i]) logger.info("\n") return TradeWithSinglePrice(actual_traders, ps_recipe, latest_prices)
-0.1523, -0.1445, -11.2, -11.2, -3.1406, -11.2, -11.2, -2.6875, -11.2 ] random.shuffle(buyers) random.shuffle(sellers) reduce_number += 1 print(reduce_number) buyers = removeSeconds(buyers, reduce_number) sellers = removeSeconds(sellers, reduce_number) # buyers1 = [4]*10 + [8]*20 + [12]*30 # sellers1 = [-2]*40 + [-2]*80 + [-3]*120 market = Market([ AgentCategory("buyer", buyers), AgentCategory("seller", sellers), ]) auction_trade = budget_balanced_ascending_auction(market, [1, 4]) (optimal_trade, _) = market.optimal_trade([1, 4]) auction_trade_num_of_deals = auction_trade.num_of_deals() optimal_trade_num_of_deals = optimal_trade.num_of_deals() print(auction_trade_num_of_deals) print("Optimal:", optimal_trade_num_of_deals) # print(len(buyers), ",", len(sellers)) # print("max buyer: ", max(buyers), ", min buyer: ", min(buyers), ", max seller: ", max(sellers), ", min seller: ", min(sellers)) # buyers.sort() # sellers.sort() print("buyers =", buyers) print("sellers =", sellers)