def check_110_101(buyers: List[float], sellersA: List[float], sellersB: List[float], expected_num_of_deals: int, expected_prices: List[float]): market = Market([ AgentCategory("buyer", buyers), AgentCategory("sellerA", sellersA), AgentCategory("sellerB", sellersB), ]) # ps_recipes = [[1, 1, 0], [1, 0, 1]] ps_recipe_struct = [0, [1, None, 2, None]] self._check_market(market, ps_recipe_struct, expected_num_of_deals, expected_prices)
def check_1_1(buyers: List[float], sellers: List[float], expected_num_of_deals: int, expected_prices: List[float]): market = Market([ AgentCategory("buyer", buyers), AgentCategory("seller", sellers), ]) ps_recipe = [1, 1] self._check_market(market, ps_recipe, expected_num_of_deals, expected_prices)
def check_1100_1011(buyers: List[float], sellers: List[float], producers: List[float], movers: List[float], expected_num_of_deals: int, expected_prices: List[float]): market = Market([ AgentCategory("buyer", buyers), AgentCategory("seller", sellers), AgentCategory("producer", producers), AgentCategory("mover", movers), ]) # ps_recipes = [[1, 1, 0, 0], [1, 0, 1, 1]] ps_recipe_struct = [0, [1, None, 2, [3, None]]] self._check_market(market, ps_recipe_struct, expected_num_of_deals, expected_prices)
def check_11100_10011(buyers: List[float], sellers1: List[float], sellers2: List[float], producers1: List[float], producers2: List[float], expected_num_of_deals: int, expected_prices: List[float]): market = Market([ AgentCategory("buyer", buyers), AgentCategory("seller1", sellers1), AgentCategory("seller2", sellers2), AgentCategory("producer1", producers1), AgentCategory("producer2", producers2), ]) ps_recipe_struct = [0, [1, [2, None], 3, [4, None]]] self._check_market(market, ps_recipe_struct, expected_num_of_deals, expected_prices)
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 empty_agent_categories(self) -> list: """ Construct k empty categories, one for each category in the present market. :return: a list of AgentCategory objects. """ categories = [None] * self.num_categories for i in range(self.num_categories): categories[i] = AgentCategory(self.categories[i].name, []) return categories
def experiment(results_csv_file: str, recipe: list, value_ranges: list, nums_of_agents: list, num_of_iterations: int, agent_counts: list, agent_values: list, recipe_tree_agent_counts: list, num_recipes: int): """ 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 = [ "iterations", "recipe", "numofagents", "optimalcount", "optimalkmin", "optimalkmax", "gftformula", "auctioncount", "auctionkmin", "auctionkmax", "countratio", "optimalgft", "auctiongft", "gftratio" ] print('recipe:', recipe, 'size:', num_recipes) GFT_ROUND = 1 - 1 K_ROUND = 2 - 1 RATIO_ROUND = 3 - 1 results_table = TeeTable(TABLE_COLUMNS, results_csv_file) recipe_str = str(recipe).replace(',', '-') is_binary = len(set(recipe_tree_agent_counts)) == 1 for i in range(len(nums_of_agents)): now = datetime.now() sum_optimal_count = sum_auction_count = sum_optimal_kmin = sum_optimal_kmax = 0 # count the number of deals done in the optimal vs. the actual auction. sum_optimal_gft = sum_auction_total_gft = sum_auction_kmin = sum_auction_kmax = 0 for iteration in range(num_of_iterations): #if iteration % 10000 == 0: # print('iteration:', iteration) agents = [] for category in range(len(recipe_tree_agent_counts)): sign = 0 if category == 0 else 1 agents.append( AgentCategory.uniformly_random( "agent", int(nums_of_agents[i] * agent_counts[category]), value_ranges[sign][0] * agent_values[category], value_ranges[sign][1] * agent_values[category])) #agents.append(AgentCategory.uniformly_random("agent", nums_of_agents[i], value_ranges[sign][0], value_ranges[sign][1])) market = Market(agents) #print(market) #print(agents) recipe_tree = RecipeTree(market.categories, recipe, recipe_tree_agent_counts) optimal_trade, optimal_count, optimal_gft, kmin, kmax, categories_optimal_counters = recipe_tree.optimal_trade_with_counters( ) #print('counters:' + str(categories_counters)) #print('optimal trade:', optimal_trade, optimal_count, optimal_gft) auction_trade = budget_balanced_ascending_auction( market, recipe, recipe_tree_agent_counts) auction_count = auction_trade.num_of_deals() auction_kmin = auction_trade.min_num_of_deals() auction_kmax = auction_trade.max_num_of_deals() path_counters = auction_trade.path_counters gft = auction_trade.gain_from_trade() #print('Compare:', categories_optimal_counters, path_counters) for counter in categories_optimal_counters.keys(): if categories_optimal_counters[ counter] > path_counters[counter] + 1 and False: print(market) print('Compare:', categories_optimal_counters, path_counters) print('Warning counters', str(counter), 'are not in same size!', categories_optimal_counters[counter], '!=', path_counters[counter]) #for i in range(len(path_counters)): # print('Compare:', categories_optimal_counters, path_counters) #if optimal_count > 0 and gft < optimal_gft * (kmin - 1)/(kmin + 2): #the auction count is less more than 1 than the optimal count. # print('Warning GFT!!!', 'optimal_count:', optimal_count, 'auction_count:', auction_count, # 'num_of_possible_ps:', nums_of_agents[i], 'optimal_gft:', optimal_gft, 'gft:', gft, 'lower bound:', optimal_gft * (1 - 1/optimal_count)) # if nums_of_agents[i] < 20: # print(market.categories) sum_optimal_count += optimal_count sum_auction_count += auction_count sum_optimal_kmin += kmin sum_optimal_kmax += kmax sum_auction_kmin += auction_kmin sum_auction_kmax += auction_kmax sum_optimal_gft += optimal_gft sum_auction_total_gft += gft #if auction_count < optimal_count - 2: #the auction count is less more than 1 than the optimal count. #print('Warning!!!', 'optimal_count:', optimal_count, 'auction_count:', auction_count, 'num_of_possible_ps:', nums_of_agents[i]) #if nums_of_agents[i] < 10: # print(market.categories) # 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)) kmin_mean = sum_optimal_kmin / num_of_iterations if is_binary: gft_formula = int_round( (kmin_mean - 1) / kmin_mean * 100 if kmin_mean - 1 > 0 else 0, RATIO_ROUND) else: gft_formula = int_round( (kmin_mean - num_recipes) / (kmin_mean + num_recipes) * 100 if kmin_mean - num_recipes > 0 else 0, RATIO_ROUND) results_table.add( OrderedDict([ ("iterations", num_of_iterations), ("recipe", recipe_str), ("numofagents", nums_of_agents[i]), ("optimalcount", int_round(sum_optimal_count / num_of_iterations, K_ROUND)), ("optimalkmin", int_round(kmin_mean, K_ROUND)), ("optimalkmax", int_round(sum_optimal_kmax / num_of_iterations, K_ROUND)), ("gftformula", gft_formula), ("auctioncount", int_round(sum_auction_count / num_of_iterations, K_ROUND)), ("auctionkmin", int_round(sum_auction_kmin / num_of_iterations, K_ROUND)), ("auctionkmax", int_round(sum_auction_kmax / num_of_iterations, K_ROUND)), ("countratio", int_round( 0 if sum_optimal_count == 0 else (sum_auction_count / sum_optimal_count) * 100, RATIO_ROUND)), ("optimalgft", int_round(sum_optimal_gft / num_of_iterations, GFT_ROUND)), ("auctiongft", int_round(sum_auction_total_gft / num_of_iterations, GFT_ROUND)), ("gftratio", '0.00' if sum_optimal_gft == 0 else int_round( sum_auction_total_gft / sum_optimal_gft * 100, RATIO_ROUND)), ])) print('took', (datetime.now() - now).seconds) results_table.done()
prices.logger.setLevel(logging.INFO) print("\n\n###### TEST MULTI RECIPE AUCTION - 4 PATHS") # market = Market([ # AgentCategory("C0", [400, 300, 200, 100]), # AgentCategory("C1", [-1, -11]), # AgentCategory("C2", [-2, -22]), # AgentCategory("C3", [-3, -33]), # AgentCategory("C4", [-4, -44]), # AgentCategory("C5", [-5, -55]), # AgentCategory("C6", [-6, -66]), # ]) market = Market([ AgentCategory("C0", [400, 300, 200, 100]), AgentCategory("C1", [-1, -11]), AgentCategory("C2", [-2]), AgentCategory("C3", [-3]), AgentCategory("C4", [-4, -44]), AgentCategory("C5", [-5]), AgentCategory("C6", [-6]), ]) recipes_4paths = [0, [1, [2, None, 3, None], 4, [5, None, 6, None]]] # The recipes are: # 1,1,1,0,0,0,0 [C0, C1, C2] # 1,1,0,1,0,0,0 [C0, C1, C3] # 1,0,0,0,1,1,0 [C0, C4, C5] # 1,0,0,0,1,0,1 [C0, C4, C6]
for a bilateral market with buyers and sellers. Since: 2019-08 Author: Erel Segal-Halevi """ from markets import Market from agents import AgentCategory import mcafee_protocol from mcafee_protocol import mcafee_trade_reduction import logging mcafee_protocol.logger.setLevel(logging.INFO) recipe = [1, 1] print("\n\n### Example without trade reduction") market = Market([ AgentCategory("buyer", [17, 14, 13, 9, 6]), AgentCategory("seller", [-1, -4, -5, -8, -11]), ]) print(mcafee_trade_reduction(market, recipe)) print("\n\n### Example with trade reduction") market = Market([ AgentCategory("buyer", [17, 14, 13, 9, 6]), AgentCategory("seller", [-1, -4, -5, -8, -13]), ]) print(mcafee_trade_reduction(market, recipe))
""" prices = [None] * self.num_categories for category_index in range(self.num_categories): if category_index == pivot_index: prices[category_index] = (pivot_value*ps_recipe[category_index] - sum([best_containing_PS[i]*ps_recipe[i] for i in range(len(best_containing_PS))]))\ / ps_recipe[category_index] else: prices[category_index] = best_containing_PS[category_index] prices = tuple(prices) return prices def __str__(self) -> str: return "Traders: {}".format(self.categories) def clone(self): return Market([c.clone() for c in self.categories]) if __name__ == "__main__": import doctest (failures, tests) = doctest.testmod(report=True) print("{} failures, {} tests".format(failures, tests)) market2 = Market([ AgentCategory("buyer", [9, 7, 11, 5]), AgentCategory("seller", [-4, -6, -8, -2]) ]) (trade, remaining_market) = market2.optimal_trade([1, 1])
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()
Since: 2019-11 """ import sys, os sys.path.insert(0, os.path.abspath('..')) from markets import Market from agents import AgentCategory import ascending_auction_protocol from ascending_auction_protocol import budget_balanced_ascending_auction import logging ascending_auction_protocol.logger.setLevel(logging.INFO) print("\n\n###### RUNNING EXAMPLE 3 FROM THE PAPER FOR TYPE (2,2,3)") 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(budget_balanced_ascending_auction(market, [2,2,3])) print("\n\n###### OTHER EXAMPLES FOR (2,2,3)") 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(budget_balanced_ascending_auction(market, [2, 2, 3]))
# AgentCategory("sellerB", [-3, -4]), # ]) # print(budget_balanced_ascending_auction_twolevels(market, [1, 1 ,1])) # print("\n\n###### TWO NON-BINARY RECIPES: [1,2,0], [1,0,2]") # market = Market([ # AgentCategory("buyer", [19,18,17,16,15,14,13]), # AgentCategory("sellerA", [-1, -2]), # AgentCategory("sellerB", [-3, -4]), # ]) # print(budget_balanced_ascending_auction_twolevels(market, [1, 2, 2])) print("\n\n###### COUNTER-EXAMPLE FOR CEILING CHILDREN") num_of_seller_categories = 8 market = Market( [AgentCategory("buyer", [101] * 10 * (num_of_seller_categories + 1))] + [AgentCategory("producer", [-50] * 20)] + [AgentCategory("seller", [-100] + [-2] * 21)] * num_of_seller_categories) # print(budget_balanced_ascending_auction_twolevels(market, [1, 2] + [2] * num_of_seller_categories)) print("\n\n###### DVIR'S EXAMPLE BINARY") num_of_seller_categories = 8 market = Market([AgentCategory("buyer", [100] * num_of_seller_categories)] + [ AgentCategory("seller", [-80 + i]) for i in range(num_of_seller_categories) ]) print( budget_balanced_ascending_auction_twolevels( market, [1] + [1] * num_of_seller_categories)) ascending_auction_recipetree_twolevels_protocol.logger.setLevel(logging.INFO) prices.logger.setLevel(logging.INFO)
""" Demonstration of a multiple-clock strongly-budget-balanced ascending auction for a multi-lateral market with two buyers per three sellers (recipe: 2,3) Author: Erel Segal-Halevi Since: 2019-08 """ import sys, os sys.path.insert(0, os.path.abspath('..')) from markets import Market from agents import AgentCategory import ascending_auction_protocol from ascending_auction_protocol import budget_balanced_ascending_auction import logging ascending_auction_protocol.logger.setLevel(logging.INFO) market = Market([ AgentCategory("buyer", [20., 18., 16., 9., 2., 1.]), AgentCategory("seller", [-2., -4., -6., -8., -10., -12., -14.]), ]) print(budget_balanced_ascending_auction(market, [2, 3])) # Here, k=1, and the final trade involves 2 buyers and 5 sellers # (so 3 sellers should be selected at random). print(budget_balanced_ascending_auction(market, [3, 2])) # Here, k=1, and the final trade involves 5 buyers and 3 sellers # (so 3 buyers and 2 sellers should be selected at random).
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()
-14.95, -14.95, -14.6, -14.55, -14.45, -14.45, -14.4, -14.15, -14.05, -13.75, -13.7, -13.15, -12.9, -12.9, -12.65 ] # # buyers = removeSeconds(buyers, reduce_number) # sellers = removeSeconds(sellers, reduce_number) # mediators = removeSeconds(mediators, reduce_number) # mediatorsB = removeSeconds(mediatorsB, reduce_number) # # random.shuffle(buyers) # random.shuffle(sellers) # random.shuffle(mediators) # random.shuffle(mediatorsB) market = Market([ AgentCategory("buyer", buyers), AgentCategory("seller", sellers), AgentCategory("mediator", mediators), AgentCategory("mediatorB", mediatorsB), ]) without_gft0 = budget_balanced_trade_reduction(market, recipe, False) with_gft0 = budget_balanced_trade_reduction(market, recipe, True) print(without_gft0) print(with_gft0) without_count = without_gft0.num_of_deals() with_count = with_gft0.num_of_deals() without_gft = without_gft0.gain_from_trade() with_gft = with_gft0.gain_from_trade() print('Compare: Without:', without_gft, "With:", with_gft)
buyers = randomArray(2, 20, 10) sellers = randomArray(-10, -1, 20) # # buyers = [135.9, 136.7999, 143.5499, 135.9, 136.7999, 143.5499, 144.0] # sellers = [-135.9, -136.7999, -143.5499, -18.95, -18.9, -17.95, -17.9, -17.7999, -17.7999, -17.2999, -17.0, -16.95, -16.7999, -15.15, -15.0, -15.0, -14.9, -14.2, -14.2, -14.1, -13.95] # # random.shuffle(buyers) # random.shuffle(sellers) # # buyers = removeSeconds(buyers, reduce_number) # sellers = removeSeconds(sellers, reduce_number) market = Market([ AgentCategory("buyer", buyers), AgentCategory("seller", sellers), ]) without_gft0 = budget_balanced_trade_reduction(market, recipe, False) with_gft0 = budget_balanced_trade_reduction(market, recipe, True) print(without_gft0) print(with_gft0) without_count = without_gft0.num_of_deals() with_count = with_gft0.num_of_deals() without_gft = without_gft0.gain_from_trade() with_gft = with_gft0.gain_from_trade() print('Compare: Without:', without_gft, "With:", with_gft) print('Compare: Without:', without_count, "With:", with_count) if without_count != with_count and with_gft != without_gft:
""" from markets import Market from agents import AgentCategory import ascending_auction_protocol from ascending_auction_protocol import budget_balanced_ascending_auction import logging ascending_auction_protocol.logger.setLevel(logging.INFO) ps_recipe = [1,1,1] print("\n\n###### RUNNING EXAMPLE FROM THE PAPER FOR TYPE (1,1,1)") # Price stops between buyers, k=3: market = Market([ AgentCategory("buyer", [17, 14, 13, 9, 6]), AgentCategory("seller", [-1, -4, -5, -8, -11]), AgentCategory("mediator", [-1, -3, -4, -7, -10])]) print(budget_balanced_ascending_auction(market, ps_recipe)) print("\n\n###### SIMILAR EXAMPLE, WHERE PRICE STOPS BETWEEN SELLERS:") market = Market([ AgentCategory("buyer", [17, 14, 13, 9, 6]), AgentCategory("seller", [-1, -4, -5, -8, -11]), AgentCategory("mediator", [-1, -3, -6, -7, -10])]) print(budget_balanced_ascending_auction(market, ps_recipe)) print("\n\n###### SIMILAR EXAMPLE, WHERE PRICE STOPS BETWEEN MEDIATORS:") market = Market([ AgentCategory("buyer", [17, 14, 13, 9, 6]),
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()
explanation += "{} deals overall\n".format(num_of_deals) return (num_of_deals,explanation) if __name__=="__main__": logger.addHandler(logging.StreamHandler(sys.stdout)) logger.setLevel(logging.DEBUG) import doctest (failures,tests) = doctest.testmod(report=True) print ("doctest: {} failures, {} tests".format(failures,tests)) buyer = AgentCategory("buyer", [17, 14, 13, 9, 6]) seller = AgentCategory("seller", [-1, -3, -4, -5, -8, -10]) producerA = AgentCategory("producerA", [-1, -3, -5]) producerB = AgentCategory("producerB", [-1, -4, -6]) categories = [buyer, seller, producerA, producerB] # Indices: 0, 1, 2, 3 tree = RecipeTree(categories, [0, [1, None, 2, [3, None]]]) # buyer -> seller, buyer -> producerA -> producerB print("Tree structure: ") for pre, fill, node in RenderTree(tree): print("{}{}".format(pre,node.name)) # buyer # ├── seller # └── producerA # └── producerB
#!python3 """ Demonstration of a multiple-clock strongly-budget-balanced ascending auction for a multi-lateral market with one buyer per two sellers (recipe: 1,2) Author: Erel Segal-Halevi Since: 2019-08 """ from markets import Market from agents import AgentCategory import ascending_auction_protocol, prices from ascending_auction_protocol import budget_balanced_ascending_auction import logging ascending_auction_protocol.logger.setLevel(logging.INFO) prices.logger.setLevel(logging.INFO) print("\n\n###### EXAMPLE OF PS with GFT=0") market = Market([ AgentCategory("buyer", [1, 1, 1, 1, 1]), AgentCategory("seller", [-1, -1, -1, -1, -1]), ]) print(budget_balanced_ascending_auction(market, [1, 1]))
class TestAscendingAuctionWithTwoRecpies(unittest.TestCase): """ This TestCase class runs unittests for settings with two recipes. """ def _check_market(self, market: Market, ps_recipe_struct:List[Any], expected_num_of_deals:int, expected_prices:List[float]): trade = ascending_auction_recipetree_protocol.budget_balanced_ascending_auction(market, ps_recipe_struct) self.assertEqual(trade.num_of_deals(), expected_num_of_deals) for i, price in enumerate(expected_prices): if price is not None: self.assertEqual(trade.prices[i], expected_prices[i]) def test_market_110_101(self): """ Unit-tests with two recipes: [1,1,0] and [1,0,1]. Note that the two latter categories are equivalent, so we expect the results to be identical to a single recipe [1,1]. :return: """ def check_110_101(buyers: List[float], sellersA: List[float], sellersB: List[float], expected_num_of_deals: int, expected_prices: List[float]): market = Market([ AgentCategory("buyer", buyers), AgentCategory("sellerA", sellersA), AgentCategory("sellerB", sellersB), ]) # ps_recipes = [[1, 1, 0], [1, 0, 1]] ps_recipe_struct = [0, [1, None, 2, None]] self._check_market(market, ps_recipe_struct, expected_num_of_deals, expected_prices) check_110_101(buyers=[9,8], sellersA=[-4], sellersB=[-3], expected_num_of_deals=1, expected_prices=[4,-4,-4]) # The following checks are based on the following: # check_1_1(buyers=[19,17,15,13,11,9], sellers=[-12,-10,-8,-6,-4,-2], # expected_num_of_deals=4, expected_prices=[11,-11]) check_110_101(buyers=[19,17,15,13,11,9], sellersA=[], sellersB=[-12,-10,-8,-6,-4,-2], expected_num_of_deals=4, expected_prices=[10,None,-10]) check_110_101(buyers=[19,17,15,13,11,9], sellersA=[-12], sellersB=[-10,-8,-6,-4,-2], expected_num_of_deals=4, expected_prices=[10,-10,-10]) check_110_101(buyers=[19,17,15,13,11,9], sellersA=[-4,-2], sellersB=[-12,-10,-8,-6], expected_num_of_deals=4, expected_prices=[10,-10,-10]) check_110_101(buyers=[19,17,15,13,11,9], sellersA=[-10,-4], sellersB=[-12,-8,-6,-2], expected_num_of_deals=4, expected_prices=[10,-10,-10]) check_110_101(buyers=[19,17,15,13,11,9], sellersA=[-12,-10,-8,-6,-4,-2], sellersB=[], expected_num_of_deals=4, expected_prices=[10,-10,None]) def test_market_1100_1011(self): """ Unit-tests with two recipes: [1,1,0,0] and [1,0,1,1]. This is the smallest case in which multi-recipe substantially differs than single-recipe. :return: """ def check_1100_1011(buyers: List[float], sellers: List[float], producers: List[float], movers: List[float], expected_num_of_deals: int, expected_prices: List[float]): market = Market([ AgentCategory("buyer", buyers), AgentCategory("seller", sellers), AgentCategory("producer", producers), AgentCategory("mover", movers), ]) # ps_recipes = [[1, 1, 0, 0], [1, 0, 1, 1]] ps_recipe_struct = [0, [1, None, 2, [3, None]]] self._check_market(market, ps_recipe_struct, expected_num_of_deals, expected_prices) check_1100_1011(buyers=[19, 17, 15, 13, 11, 9], sellers=[-12, -10, -8, -6, -4, -2], producers=[], movers=[], expected_num_of_deals=4, expected_prices=[10.0, -10.0, None, None]) # show_log() check_1100_1011(buyers=[19, 17, 15, 13, 11, 9], sellers=[], producers=[-6,-5,-4,-3,-2,-1], movers=[-6,-5,-4,-3,-2,-1], expected_num_of_deals=4, expected_prices=[10, None, -5, -5]) # hide_log() def test_market_11100_10011(self): """ Unit-tests with two recipes: [1,1,0,0] and [1,0,1,1]. This is the smallest case in which multi-recipe substantially differs than single-recipe. :return: """ def check_11100_10011(buyers: List[float], sellers1: List[float], sellers2: List[float], producers1: List[float], producers2: List[float], expected_num_of_deals: int, expected_prices: List[float]): market = Market([ AgentCategory("buyer", buyers), AgentCategory("seller1", sellers1), AgentCategory("seller2", sellers2), AgentCategory("producer1", producers1), AgentCategory("producer2", producers2), ]) ps_recipe_struct = [0, [1, [2, None], 3, [4, None]]] self._check_market(market, ps_recipe_struct, expected_num_of_deals, expected_prices) check_11100_10011(buyers=[400, 300, 200, 100], sellers1=[-1, -2], sellers2=[-3, -4], producers1=[-5,-6], producers2=[-7,-8], expected_num_of_deals=2, expected_prices=[None, None, None, None, None]) AgentCategory("buyer", [400, 300, 200, 100]), AgentCategory("seller1", [-1, -2]), AgentCategory("seller2", [-3, -4]), AgentCategory("producer1", [-5, -6]), AgentCategory("producer2", [-7, -8]),
def experiment(results_csv_file: str, recipe: list, agent_counts:list, agent_values:list, nums_of_agents:list = None, num_of_iterations:int = 1, stocks_prices=None, stock_names=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", "optimalkmin", "optimalkmax","gftformula", "optimalcount", "optimalgft", "auctioncount", "countratio", "gft", "gftratio"] print('recipe:', recipe) results_table = TeeTable(TABLE_COLUMNS, results_csv_file) recipe_str = str(recipe).replace(',', '->') if stocks_prices is None: (stocks_prices, stock_names) = getStocksTreePrices(recipe, agent_counts, agent_values) if nums_of_agents is None: nums_of_agents = [10000000] total_results = {} for num_of_agents_per_category in nums_of_agents: total_results[str(num_of_agents_per_category)] = [] for i in range(len(stock_names)): for _ in range(num_of_iterations): last_iteration = False for j in range(len(stocks_prices[i])): random.shuffle(stocks_prices[i][j]) 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:int(num_of_possible_ps*agent_counts[j])]) for j in range(len(stocks_prices[i]))]) if num_of_agents_per_category == 6 and _ == 0: print(stock_names[i], market.categories) recipe_tree = RecipeTree(market.categories, recipe) optimal_trade, optimal_count, optimal_gft, kmin, kmax = recipe_tree.optimal_trade_with_counters() #print('optimal trade:', optimal_trade, optimal_count, optimal_gft) auction_trade = budget_balanced_ascending_auction(market, recipe) auction_count = auction_trade.num_of_deals() gft = auction_trade.gain_from_trade() #if auction_count < optimal_count - 1: # #the auction count is less more than 1 than the optimal count. # print('Warning!!!', 'optimal_count:', optimal_count, 'auction_count:', auction_count, 'num_of_possible_ps:', num_of_possible_ps) # if num_of_possible_ps < 10: # print(market.categories) #if optimal_count > 0 and gft < optimal_gft * (1 - 1/optimal_count): # #the auction count is less more than 1 than the optimal count. # print('Warning GFT!!!', 'optimal_count:', optimal_count, 'auction_count:', auction_count, # 'num_of_possible_ps:', num_of_possible_ps, 'optimal_gft:', optimal_gft, 'gft:', gft) # if num_of_possible_ps < 20: # print(market.categories) if optimal_count < auction_count : #the auction count is less more than 1 than the optimal count. print('Warning count!!!', 'optimal_count:', optimal_count, 'auction_count:', auction_count, 'num_of_possible_ps:', num_of_possible_ps, 'optimal_gft:', optimal_gft, 'gft:', gft) if num_of_possible_ps < 20: print(market.categories) results = [("stockname", stock_names[i]), ("recipe", recipe_str), ("numpossibletrades", num_of_possible_ps), ("optimalcount", optimal_count), ("optimalkmin", kmin), ("optimalkmax", kmax), ("optimalgft", optimal_gft), ("auctioncount", auction_count), ("countratio", 0 if optimal_count==0 else auction_count / optimal_count*100), ("gft", gft), ("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)] kmin = 0 for index in range(len(results)): if index > 2: #if 'ratio' in results[index][0]: # results[index] = (results[index][0], results[index][1]/len(stock_names)) #elif 'count' in results[index][0]: # results[index] = (results[index][0], results[index][1]/len(stock_names)) #else: results[index] = (results[index][0], results[index][1]/len(stock_names)/num_of_iterations) elif index == 0: results[index] = (results[index][0], 'Average') if results[index][0] == 'optimalkmin': kmin = results[index][1] results.append(('gftformula', 0 if kmin <= 1 else (1-1/kmin)*100)) 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()
""" from markets import Market from agents import AgentCategory from old import ascending_auction_multibuyer_protocol from old.ascending_auction_multibuyer_protocol import budget_balanced_ascending_auction import prices import logging ascending_auction_multibuyer_protocol.logger.setLevel(logging.INFO) prices.logger.setLevel(logging.INFO) print("\n\n###### TEST MULTI RECIPE AUCTION WITH A SINGLE RECIPE (1,2)") market = Market([ AgentCategory("buyer", [17, 14, 13, 9, 6]), AgentCategory("seller", [-1, -2, -3, -4, -5, -7, -8, -10, -11]), ]) print(budget_balanced_ascending_auction(market, [[1, 2]])) print("\n\n###### TEST TWO RECIPES: (1,0,1) and (0,1,2)") market = Market([ AgentCategory("onebuyer", [12, 13, 15, 17, 19]), AgentCategory("twobuyer", [16, 18, 25, 27, 31]), AgentCategory("seller", [-1, -2, -3, -4, -5, -7, -8, -10, -11]), ]) print(budget_balanced_ascending_auction(market, [[1, 0, 1], [0, 1, 2]]))
def experiment(results_csv_file: str, recipe: list, value_ranges: list, nums_of_agents: list, num_of_iterations: int, agent_counts: list, agent_values: list, agent_counts_integer: list): """ 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 = [ "iterations", "recipe", "numofagents", "optimalcount", "optimalkmin", "optimalkmax", "gftformula", "auctioncount", "auctionkmin", "auctionkmax", "countratio", "optimalgft", "auctiongft", "gftratio" ] GFT_ROUND = 1 K_ROUND = 2 RATIO_ROUND = 3 print('recipe:', recipe) results_table = TeeTable(TABLE_COLUMNS, results_csv_file) results_table_integer = TeeTable(TABLE_COLUMNS, results_csv_file[0:-4] + '_integer.csv') recipe_str = str(recipe).replace(',', '-') category_size_list = get_agents_analyze(recipe) for i in range(len(nums_of_agents)): sum_optimal_count = sum_auction_count = sum_optimal_kmin = sum_optimal_kmax = 0 # count the number of deals done in the optimal vs. the actual auction. sum_optimal_gft = sum_auction_total_gft = sum_auction_kmin = sum_auction_kmax = 0 sum_optimal_count_integer = sum_auction_count_integer = sum_optimal_kmin_integer = sum_optimal_kmax_integer = 0 # count the number of deals done in the optimal vs. the actual auction. sum_optimal_gft_integer = sum_auction_total_gft_integer = sum_auction_kmin_integer = sum_auction_kmax_integer = 0 for iteration in range(num_of_iterations): if iteration % 10000 == 0: print('iteration:', iteration) agents = [] agents_integer = [] for category in range(len(category_size_list)): sign = 0 if category == 0 else 1 agent_category = AgentCategory.uniformly_random( "agent", int(nums_of_agents[i] * agent_counts[category]), value_ranges[sign][0] * agent_values[category], value_ranges[sign][1] * agent_values[category]) agents.append(agent_category) agents_integer.append( AgentCategory( agent_category.name, agent_category.values + agent_category.values)) #agents.append(AgentCategory.uniformly_random("agent", nums_of_agents[i], value_ranges[sign][0], value_ranges[sign][1])) market = Market(agents) market_integer = Market(agents_integer) #print(agents) recipe_tree = RecipeTree(market.categories, recipe) recipe_tree_integer = RecipeTree(market_integer.categories, recipe, agent_counts_integer) optimal_trade, optimal_count, optimal_gft, kmin, kmax = recipe_tree.optimal_trade_with_counters( ) optimal_trade_integer, optimal_count_integer, optimal_gft_integer, kmin_integer, kmax_integer = recipe_tree_integer.optimal_trade_with_counters( ) #print('optimal trade:', optimal_trade, optimal_count, optimal_gft) auction_trade = budget_balanced_ascending_auction(market, recipe) auction_trade_integer = budget_balanced_ascending_auction( market_integer, recipe, agent_counts_integer) auction_count = auction_trade.num_of_deals() auction_count_integer = auction_trade_integer.num_of_deals() auction_kmin = auction_trade.min_num_of_deals() auction_kmin_integer = auction_trade_integer.min_num_of_deals() auction_kmax = auction_trade.max_num_of_deals() auction_kmax_integer = auction_trade_integer.max_num_of_deals() gft = auction_trade.gain_from_trade() gft_integer = auction_trade_integer.gain_from_trade() #if optimal_count > 0 and gft < optimal_gft * (1 - 1/optimal_count): #the auction count is less more than 1 than the optimal count. # print('Warning GFT!!!', 'optimal_count:', optimal_count, 'auction_count:', auction_count, # 'num_of_possible_ps:', nums_of_agents[i], 'optimal_gft:', optimal_gft, 'gft:', gft) # if nums_of_agents[i] < 20: # print(market.categories) sum_optimal_count += optimal_count sum_optimal_count_integer += optimal_count_integer sum_auction_count += auction_count sum_auction_count_integer += auction_count_integer sum_optimal_kmin += kmin sum_optimal_kmin_integer += kmin_integer sum_optimal_kmax += kmax sum_optimal_kmax_integer += kmax_integer sum_auction_kmin += auction_kmin sum_auction_kmin_integer += auction_kmin_integer sum_auction_kmax += auction_kmax sum_auction_kmax_integer += auction_kmax_integer sum_optimal_gft += optimal_gft sum_optimal_gft_integer += optimal_gft_integer sum_auction_total_gft += gft sum_auction_total_gft_integer += gft_integer if auction_count < optimal_count - 2: #the auction count is less more than 1 than the optimal count. print('Warning!!!', 'optimal_count:', optimal_count, 'auction_count:', auction_count, 'num_of_possible_ps:', nums_of_agents[i]) if nums_of_agents[i] < 10: print(market.categories) # 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)) kmin_mean = sum_optimal_kmin / num_of_iterations kmin_mean_integer = sum_optimal_kmin_integer / num_of_iterations results_table.add( OrderedDict([ ("iterations", num_of_iterations), ("recipe", recipe_str), ("numofagents", nums_of_agents[i]), ("optimalcount", int_round(sum_optimal_count / num_of_iterations, K_ROUND)), ("optimalkmin", int_round(kmin_mean, K_ROUND)), ("optimalkmax", int_round(sum_optimal_kmax / num_of_iterations, K_ROUND)), ("gftformula", int_round((1 - 1 / kmin_mean) * 100 if kmin_mean > 1 else 0, RATIO_ROUND)), ("auctioncount", int_round(sum_auction_count / num_of_iterations, K_ROUND)), ("auctionkmin", int_round(sum_auction_kmin / num_of_iterations, K_ROUND)), ("auctionkmax", int_round(sum_auction_kmax / num_of_iterations, K_ROUND)), ("countratio", int_round( 0 if sum_optimal_count == 0 else (sum_auction_count / sum_optimal_count) * 100, RATIO_ROUND)), ("optimalgft", int_round(sum_optimal_gft / num_of_iterations, GFT_ROUND)), ("auctiongft", int_round(sum_auction_total_gft / num_of_iterations, GFT_ROUND)), ("gftratio", '0.00' if sum_optimal_gft == 0 else int_round( sum_auction_total_gft / sum_optimal_gft * 100, RATIO_ROUND)), ])) results_table_integer.add( OrderedDict([ ("iterations", num_of_iterations), ("recipe", recipe_str), ("numofagents", nums_of_agents[i]), ("optimalcount", int_round(sum_optimal_count_integer / num_of_iterations, K_ROUND)), ("optimalkmin", int_round(kmin_mean_integer, K_ROUND)), ("optimalkmax", int_round(sum_optimal_kmax_integer / num_of_iterations, K_ROUND)), ("gftformula", int_round((1 - 1 / kmin_mean_integer) * 100 if kmin_mean_integer > 1 else 0, RATIO_ROUND)), ("auctioncount", int_round(sum_auction_count_integer / num_of_iterations, K_ROUND)), ("auctionkmin", int_round(sum_auction_kmin_integer / num_of_iterations, K_ROUND)), ("auctionkmax", int_round(sum_auction_kmax_integer / num_of_iterations, K_ROUND)), ("countratio", int_round( 0 if sum_optimal_count_integer == 0 else (sum_auction_count_integer / sum_optimal_count_integer) * 100, RATIO_ROUND)), ("optimalgft", int_round(sum_optimal_gft_integer / num_of_iterations, GFT_ROUND)), ("auctiongft", int_round(sum_auction_total_gft_integer / num_of_iterations, GFT_ROUND)), ("gftratio", '0.00' if sum_optimal_gft_integer == 0 else int_round( sum_auction_total_gft_integer / sum_optimal_gft_integer * 100, RATIO_ROUND)), ])) results_table.done()
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()
# print("\n\n###### TEST MULTI RECIPE AUCTION - RICA'S EXAMPLE") # market = Market([ # AgentCategory("buyer", [20, 19, 18, 17, 16, 15]), # AgentCategory("seller", [-1, -2, -5, -6, -9, -10]), # AgentCategory("producerA", [-4, -8]), # AgentCategory("producerB", [-3, -7]), # ]) # print(budget_balanced_ascending_auction(market, recipes_1100_1011)) import sys, os; sys.path.insert(0, os.path.abspath('..')) print("\n\n###### TEST MULTI RECIPE AUCTION - 4 PATHS") market = Market([ AgentCategory("C0", [400, 300, 200, 100]), AgentCategory("C1", [-1, -11]), AgentCategory("C2", [-2, -22]), AgentCategory("C3", [-3, -33]), AgentCategory("C4", [-4, -44]), AgentCategory("C5", [-5, -55]), AgentCategory("C6", [-6, -66]), ]) recipes_4paths = [0, [1, [2, None, 3, None], 4, [5, None, 6, None]]] # The recipes are: # 1,1,1,0,0,0,0 [C0, C1, C2] # 1,1,0,1,0,0,0 [C0, C1, C3] # 1,0,0,0,1,1,0 [C0, C4, C5] # 1,0,0,0,1,0,1 [C0, C4, C6] print(budget_balanced_ascending_auction(market, recipes_4paths))
from markets import Market from agents import AgentCategory from old import ascending_auction_multirecipe_protocol from old.ascending_auction_multirecipe_protocol import budget_balanced_ascending_auction import prices import logging ascending_auction_multirecipe_protocol.logger.setLevel(logging.INFO) prices.logger.setLevel(logging.INFO) print( "\n\n###### TEST MULTI RECIPE AUCTION WITH TWO EQUIVALENT RECIPES: [1,0,1] [1,1,0]" ) market = Market([ AgentCategory("buyer", [17, 14, 13, 9, 6]), AgentCategory("sellerA", [-1, -3, -4, -5, -8, -10]), AgentCategory("sellerB", [-2, -7, -11]), ]) # print(budget_balanced_ascending_auction(market, [[1, 1, 0], [1, 0, 1]])) print( "\n\n###### TEST MULTI RECIPE AUCTION WITH TWO DIFFERENT RECIPES: [1,1,0,0] [1,0,1,1]" ) market = Market([ AgentCategory("buyer", [17, 14, 13, 9, 6]), AgentCategory("seller", [-1, -3, -4, -5, -8, -10]), AgentCategory("producerA", [-1, -3, -5]), AgentCategory("producerB", [-1, -4, -6]),
Since: 2019-08 """ from markets import Market from agents import AgentCategory import ascending_auction_protocol, prices from ascending_auction_protocol import budget_balanced_ascending_auction import logging ascending_auction_protocol.logger.setLevel(logging.INFO) prices.logger.setLevel(logging.INFO) print("\n\n###### RUNNING EXAMPLE FROM THE PAPER FOR TYPE (1,2)") market = Market([ AgentCategory("buyer", [17, 14, 13, 9, 6]), AgentCategory("seller", [-1, -2, -3, -4, -5, -7, -8, -10, -11]), ]) print(budget_balanced_ascending_auction(market, [1, 2])) print( "\n\n###### RUNNING EXAMPLE FROM THE PAPER, WITH DIFFERENT CATEGORY ORDER") market = Market([ AgentCategory("seller", [-1, -2, -3, -4, -5, -7, -8, -10, -11]), AgentCategory("buyer", [17, 14, 13, 9, 6]), ]) print(budget_balanced_ascending_auction(market, [2, 1]))