Beispiel #1
0
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()
Beispiel #2
0
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 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()
Beispiel #4
0
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()
Beispiel #5
0
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()
Beispiel #6
0
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,
               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()
Beispiel #8
0
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: 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 experiment(results_csv_file: str, recipe: 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 = ["stockname", "recipe", "numofagents",
                     "optimalkmin", "optimalkmax", "gftformula",
                     "optimalcount", "optimalgft", "auctioncount",
                     "auctionkmin", "auctionkmax", "countratio", "gft", "gftratio"]
    print('recipe:', recipe, 'size:', num_recipes)
    GFT_ROUND = 1
    K_ROUND = 2
    RATIO_ROUND = 3
    results_table = TeeTable(TABLE_COLUMNS, results_csv_file)
    recipe_str = str(recipe).replace(',', '->')
    stocks_prices, stock_names = getStocksPricesShuffled()
    sum_agent_counts = sum(agent_counts)
    is_binary = len(set(recipe_tree_agent_counts)) == 1

    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)):
        print(stock_names[i], end=' ')
        for num_of_agents_per_category in nums_of_agents:
            # print(num_of_agents_per_category, end=' ')
            if sum_agent_counts * num_of_agents_per_category > len(stocks_prices[i]):
                break

            for iteration in range(num_of_iterations):
                random.shuffle(stocks_prices[i])
                agents = []
                chunk_index = 0
                for category in range(len(agent_counts)):
                    next_chunk_index = chunk_index + num_of_agents_per_category * agent_counts[category]
                    agents.append(AgentCategory("agent", [value * agent_values[category] for value in stocks_prices[i][chunk_index:next_chunk_index]]))
                    chunk_index = next_chunk_index
                # 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)
                results = [("stockname", stock_names[i]),
                           ("recipe", recipe_str),
                           ("numofagents", num_of_agents_per_category),
                           ("optimalcount", optimal_count),
                           ("optimalkmin", kmin),
                           ("optimalkmax", kmax),
                           ("gftformula", 0 if kmin <= num_recipes else (kmin - num_recipes) / (kmin + num_recipes) * 100),
                           ("optimalgft", optimal_gft),
                           ("auctioncount", auction_count),
                           ("auctionkmin", auction_kmin),
                           ("auctionkmax", auction_kmax),
                           ("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])
    print()
    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 results[index][0] == 'optimalkmin':
                kmin = results[index][1] / len(stock_names) / num_of_iterations
            if index > 2:
                if 'ratio' in results[index][0]:
                   results[index] = (results[index][0], int_round(results[index][1] / len(stock_names) / num_of_iterations, RATIO_ROUND))
                elif 'gft' in results[index][0]:
                   results[index] = (results[index][0], int_round(results[index][1] / len(stock_names) / num_of_iterations / 100, GFT_ROUND))
                else:
                    results[index] = (results[index][0], int_round(results[index][1] / len(stock_names) / num_of_iterations, K_ROUND))
            elif index == 0:
                results[index] = (results[index][0], 'Average')
            if results[index][0] == 'gftformula':
                if is_binary:
                    gft_formula = int_round(0 if kmin <= 1 else (kmin - 1) / kmin * 100, RATIO_ROUND)
                else:
                    gft_formula = int_round(0 if kmin <= num_recipes else (kmin - num_recipes) / (kmin + num_recipes) * 100, RATIO_ROUND)
                results[index] = (results[index][0], gft_formula)

        # results.append(('gftformula', 0 if kmin <= num_recipes else round((kmin - num_recipes) / (kmin + num_recipes) * 100, ROUND)))
        results_table.add(OrderedDict(results))

    results_table.done()