Skip to content

Commit

Permalink
Merge pull request #5 from Abodi-Massarwa/main
Browse files Browse the repository at this point in the history
Implementation of Algorithms from 'Fair Division under Heterogeneous Matroid Constraints'
  • Loading branch information
erelsgl authored Jul 24, 2024
2 parents 4105580 + d07c8b0 commit ff71aac
Show file tree
Hide file tree
Showing 6 changed files with 1,779 additions and 10 deletions.
193 changes: 193 additions & 0 deletions experiments/compare_heterogeneous_matroid_constraints_algorithms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
from fairpyx.algorithms.fractional_egalitarian import fractional_egalitarian_allocation
from fairpyx.algorithms.heterogeneous_matroid_constraints_algorithms import *
from fairpyx.utils.test_heterogeneous_matroid_constraints_algorithms_utils import *


def compare_heterogeneous_matroid_constraints_algorithms_egalitarian_utilitarian(): #egalitarian: prioritizes the poor
"""
this function contains 6 input ranges in which
input_ranges_intersection: is an input range which is acceptable to all the algorithms combined
input_ranges_algorithm_1 : per-category RR same capacities
input_ranges_algorithm_2 :CRR -> single category
input_ranges_algorithm_3 : back and forth CRR -> 2 categories
input_ranges_algorithm_4 : per-category CRR -> equal valuations
input_ranges_algorithm_5 : iterated priority-matching -> binary valuations
"""
expr=experiments_csv.Experiment('results/', 'egalitarian_utilitarian_comparison_heterogeneous_constraints_algorithms_bigData.csv')
expr.clear_previous_results()#TODO close after saving results
input_ranges_intersection = { #an input range which is appropriate for all the algorithms
'equal_capacities': [True],
'equal_valuations': [True],
'binary_valuations': [True],
'num_of_items':range(10,20),
'category_count': [2],
'item_capacity_bounds': range(1, 1 + 1),
'random_seed_num': range(0,10),
'num_of_agents': range(10,100),
'algorithm': [per_category_round_robin, capped_round_robin,
per_category_capped_round_robin, two_categories_capped_round_robin, iterated_priority_matching,
egalitarian_algorithm,utilitarian_algorithm]
}
input_ranges_algorithm_1 = {#same capacities else doesn't matter
'equal_capacities': [True],
'equal_valuations': [True,False],
'binary_valuations': [True,False],
'num_of_items': range(10,20),
'category_count': [10],
'item_capacity_bounds': range(1, 1 + 1),
'random_seed_num': range(0,10),
'num_of_agents': range(1,100),
'algorithm': [per_category_round_robin,
egalitarian_algorithm,utilitarian_algorithm,iterated_maximum_matching]
} # equal capacities for the sake of the compatibility of input with the implemented egalitarian and utilitarian algorithms
# we also need to consider giving each agent a capacity which is >= number of items
input_ranges_algorithm_2 = {# crr -> single category
'equal_capacities': [True,False],
'equal_valuations': [True,False],
'binary_valuations': [True,False],
'num_of_items': range(10,20),
'category_count': [1],
'item_capacity_bounds': range(1, 1 + 1),
'random_seed_num': range(0,10),
'num_of_agents': range(1,100),
'algorithm': [
capped_round_robin,egalitarian_algorithm,utilitarian_algorithm]
}
input_ranges_algorithm_3 = { # back and forth crr -> 2 categories
'equal_capacities': [True,False],
'equal_valuations': [True,False],
'binary_valuations': [True,False],
'num_of_items': range(10, 20),
'category_count': [2],
'item_capacity_bounds': range(1, 1 + 1),
'random_seed_num': range(0,10),
'num_of_agents': range(1, 100),
'algorithm': [
two_categories_capped_round_robin,utilitarian_algorithm,egalitarian_algorithm]
}
input_ranges_algorithm_4 = { # per-category crr -> equal valuations
'equal_capacities': [True,False],
'equal_valuations': [True],
'binary_valuations': [True,False],
'num_of_items': range(10, 20),
'category_count': [10],
'item_capacity_bounds': range(1, 1 + 1),
'random_seed_num': range(0,10),
'num_of_agents': range(1, 100),
'algorithm': [
per_category_capped_round_robin,egalitarian_algorithm,utilitarian_algorithm]
}
input_ranges_algorithm_5 = {# iterated priority-matching -> binary valuations
'equal_capacities': [True,False],
'equal_valuations': [True,False],
'binary_valuations': [True],
'num_of_items': range(10, 20),
'category_count': [10],
'item_capacity_bounds': range(1, 1 + 1),
'random_seed_num': range(0,10),
'num_of_agents': range(1, 100),
'algorithm': [
iterated_priority_matching,egalitarian_algorithm,utilitarian_algorithm]
}
expr.run_with_time_limit(run_experiment,input_ranges_intersection,10)
expr.run_with_time_limit(run_experiment, input_ranges_algorithm_1, 10)
expr.run_with_time_limit(run_experiment, input_ranges_algorithm_2, 10)
expr.run_with_time_limit(run_experiment, input_ranges_algorithm_3, 10)
expr.run_with_time_limit(run_experiment, input_ranges_algorithm_4, 10)
expr.run_with_time_limit(run_experiment, input_ranges_algorithm_5, 10)
def run_experiment(equal_capacities:bool,equal_valuations:bool,binary_valuations:bool,category_count:int,item_capacity_bounds:int,random_seed_num:int,num_of_agents:int,algorithm:callable,num_of_items:int):
# Mapping of algorithms to their specific argument sets
algo_args = {
per_category_round_robin: {'alloc', 'agent_category_capacities', 'item_categories', 'initial_agent_order'},
capped_round_robin: {'alloc', 'item_categories', 'agent_category_capacities',
'initial_agent_order', 'target_category'},
two_categories_capped_round_robin: {'alloc', 'item_categories', 'agent_category_capacities', 'initial_agent_order','target_category_pair'},
iterated_priority_matching: {'alloc', 'item_categories', 'agent_category_capacities'},
egalitarian_algorithm:{'instance'},
utilitarian_algorithm:{'instance'},
iterated_maximum_matching:{'alloc'}

}

instance, agent_category_capacities, categories, initial_agent_order = random_instance(
equal_capacities=equal_capacities,
equal_valuations=equal_valuations,
binary_valuations=binary_valuations,
category_count=category_count,
item_capacity_bounds=(1, item_capacity_bounds), random_seed_num=random_seed_num, num_of_agents=num_of_agents,num_of_items=num_of_items,agent_capacity_bounds=(num_of_items,num_of_items+1))
alloc = AllocationBuilder(instance)
kwargs = {'alloc': alloc, 'agent_category_capacities': agent_category_capacities, 'item_categories': categories,
'initial_agent_order': initial_agent_order, 'target_category_pair': ('c1', 'c2'), 'target_category': 'c1','instance':instance}

# Extract the set of required arguments for the chosen algorithm
required_args = algo_args.get(algorithm, set())

# Filter kwargs to include only those required by the chosen algorithm
filtered_kwargs = {k: v for k, v in kwargs.items() if k in required_args}
current_algorithm_bundle_sum = 0
current_algorithm_bundle_min_value = float('inf') # useless since there is no comparison could be replaced with 0
if algorithm.__name__=='egalitarian_algorithm':
#egalitarian algorithm
current_algorithm_bundle_sum, current_algorithm_bundle_min_value = egalitarian_algorithm(instance)
elif algorithm.__name__=='utilitarian_algorithm':
# Utilitarian algorithm
current_algorithm_bundle_sum,current_algorithm_bundle_min_value = utilitarian_algorithm(instance)
# our algorithm
else:# one of our algorithms then !
algorithm(**filtered_kwargs)
current_algorithm_bundle_min_value=min(alloc.agent_bundle_value(agent,bundle) for agent,bundle in alloc.bundles.items())# to compare with egalitarian algorithm
current_algorithm_bundle_sum=sum(alloc.agent_bundle_value(agent,bundle)for agent,bundle in alloc.bundles.items())# to compare with utilitarian



return {'current_algorithm_bundle_min_value':current_algorithm_bundle_min_value,'current_algorithm_bundle_sum':current_algorithm_bundle_sum}


def utilitarian_algorithm(instance):
alloc_utilitarian = AllocationBuilder(instance)# to make sure we're using a fresh copy of allocation
utilitarian_matching(alloc_utilitarian)

agent_bundle_values = [
alloc_utilitarian.agent_bundle_value(agent, bundle)
for agent, bundle in alloc_utilitarian.bundles.items()
]

utilitarian_bundle_sum = sum(agent_bundle_values)
min_utilitarian_value = min(agent_bundle_values)

return utilitarian_bundle_sum, min_utilitarian_value


def egalitarian_algorithm(instance):
# Egalitarian algorithm
# Step 1: Form the valuation matrix
valuation_matrix = [
[instance.agent_item_value(agent, item) for item in instance.items]
for agent in instance.agents
]
# Step 2: Compute the fractional egalitarian allocation
not_rounded_egal = fractional_egalitarian_allocation(
Instance(valuation_matrix), normalize_utilities=False
)
# Step 3: Multiply the fractions by the original valuation matrix
not_rounded_egalitarian_valuations_matrix = [
[
not_rounded_egal[agent][item] * valuation_matrix[agent][item]
for item in range(len(instance.items))
]
for agent in range(len(instance.agents))
]
min_egalitarian_algorithm_value = min(not_rounded_egalitarian_valuations_matrix) # egalitarian value
total_sum = sum(sum(row) for row in not_rounded_egalitarian_valuations_matrix) # sum of bundles (for the sake of comparison with utilitarian algorithm)

return total_sum, min_egalitarian_algorithm_value


if __name__ == '__main__':
#experiments_csv.logger.setLevel(logging.INFO)
compare_heterogeneous_matroid_constraints_algorithms_egalitarian_utilitarian()
experiments_csv.single_plot_results('results/egalitarian_utilitarian_comparison_heterogeneous_constraints_algorithms_bigData.csv',filter={},x_field='num_of_agents',y_field='current_algorithm_bundle_min_value',z_field='algorithm',save_to_file='results/egalitarian_comparison_heterogeneous_constraints_algorithms_bigData.png') # egalitarian ratio plot
experiments_csv.single_plot_results('results/egalitarian_utilitarian_comparison_heterogeneous_constraints_algorithms_bigData.csv',filter={},x_field='num_of_agents',y_field='current_algorithm_bundle_sum',z_field='algorithm',save_to_file='results/utilitarian_comparison_heterogeneous_constraints_algorithms_bigData.png') # utilitarian ratio plot
experiments_csv.single_plot_results('results/egalitarian_utilitarian_comparison_heterogeneous_constraints_algorithms_bigData.csv',filter={},x_field='num_of_agents',y_field='runtime',z_field='algorithm',save_to_file='results/runtime_comparison_heterogeneous_constraints_algorithms_bigData.png') # runtime plot
pass
#
Loading

0 comments on commit ff71aac

Please sign in to comment.