From 10fd72e58eec00d64b00639f5a6ef452145fb562 Mon Sep 17 00:00:00 2001 From: Eyad-Amer Date: Wed, 14 Dec 2022 00:46:31 +0200 Subject: [PATCH 01/23] done --- fairpy/items/Bounded_Subsidy.py | 50 +++++++++++++++++++++++++++ fairpy/items/tests_bounded_subsidy.py | 40 +++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 fairpy/items/Bounded_Subsidy.py create mode 100644 fairpy/items/tests_bounded_subsidy.py diff --git a/fairpy/items/Bounded_Subsidy.py b/fairpy/items/Bounded_Subsidy.py new file mode 100644 index 00000000..6fa3a511 --- /dev/null +++ b/fairpy/items/Bounded_Subsidy.py @@ -0,0 +1,50 @@ + +from ast import Dict, List +from fairpy import AgentList +def bounded_subsidy(agents: List, goods: List, weights: Dict[str, int]): + """ + One Dollar Each Eliminates Envy + by Jack Dippel and Adrian Vetta (Preprint · December 2019) https://www.researchgate.net/publication/337781386_One_Dollar_Each_Eliminates_Envy + Programmer: Eyad Amer + + Algorithem bounded_subsidy: + The algorithm getting a list of agents, goods list and array of the weights of the goods + and it's returns a bundle of agents when each of the holds the best allocation to his valuation of the goods. + + + >>> agents1 = ["Alice", "Bob"] + >>> goods1 = ["a", "b", "c", "d"] + >>> weights1 = {agents[0]: ["a":0.4, "b":1, "c":0.8, "d":0.7], agents[1]: ["a":0.5, "b":0.9, "c":0.5, "d":1]} + >>> print(bounded_subsidy(agents: List, goods: List, weights: Dict[str, int])) + {"Alice": ["b", "c"], "Bob": ["a", "d"]} + + >>> agents1 + ["Alice", "Bob"] + >>> goods1 + ["a", "b", "c", "d"] + >>> weights1 + {agents[0]: ["a":0.4, "b":1, "c":0.8, "d":0.7], agents[1]: ["a":0.5, "b":0.9, "c":0.5, "d":1]} + + >>> agents2 = ["Alice", "Bob"] + >>> goods2 = ["a", "b", "c", "d", "e", "f"] + >>> weights2 = [agents[0]: {"a":1, "b":0.8, "c":0.5, "d":1, "e":0.3, "f":0], agents[1]: ["a":0.9, "b":0.2, "c":0.4, "d":0.7, "e":1, "f":0]} + >>> print(bounded_subsidy(agents: List, goods: List, weights: Dict[str, int])) + {"Alice": ["a", "b", "c"], "Bob": ["d", "e", "f"]} + + >>> agents2 + ["Alice", "Bob"] + >>> goods2 + ["a", "b", "c", "d", "e", "f"] + >>> weights2 + [agents[0]: {"a":1, "b":0.8, "c":0.5, "d":1, "e":0.3, "f":0], agents[1]: ["a":0.9, "b":0.2, "c":0.4, "d":0.7, "e":1, "f":0]} + + + """ + + return 0 + +# main function +if __name__ == "__main__": + import doctest + (failures,tests) = doctest.testmod(report=True) + print ("{} failures, {} tests".format(failures,tests)) \ No newline at end of file diff --git a/fairpy/items/tests_bounded_subsidy.py b/fairpy/items/tests_bounded_subsidy.py new file mode 100644 index 00000000..30880264 --- /dev/null +++ b/fairpy/items/tests_bounded_subsidy.py @@ -0,0 +1,40 @@ +import unittest + +from items.Bounded_Subsidy import bounded_subsidy + + +class TestMain(unittest.TestCase): + + def test_goods(self): + """ + This test passes without implementation of Bounded Subsidy algorithem + """ + agents1 = ["Alice", "Bob"] + goods1 = ["a", "b", "c", "d", "e", "f", "g"] + weights1 = {agents1[0]: {"a": 2, "b": 6, "c": 3, "d":1,"e":4,"f":7,"g":12}, + agents1[1]: {"a": 3, "b": 5, "c": 4, "d":1,"e":2,"f":10,"g":15}} + + ans1 = bounded_subsidy(agents1, goods1, weights1) + self.assertEqual(ans1, {"Alice": ["b", "c"], "Bob": ["a", "d"]}) + + + agents2 = ["Alice", "Bob"] + goods2 = ["a", "b", "c", "d", "e", "f"] + weights2 = {agents2[0]: {"a":1, "b":0.8, "c":0.5, "d":1, "e":0.3, "f":0}, agents2[1]: {"a":0.9, "b":0.2, "c":0.4, "d":0.7, "e":1, "f":0}} + + ans2 = bounded_subsidy(agents2, goods2, weights2) + self.assertEqual(ans2, {"Alice": ["a", "b", "c"], "Bob": ["d", "e", "f"]}) + + + ### nothing to allocate + agents3 = ["Alice", "Bob"] + goods3 = [] + weights3 = {agents3[0]: {}, agents3[1]: {}} + + ans3 = bounded_subsidy(agents3, goods3, weights3) + self.assertEqual(ans3, {"Alice": [], "Bob": []}) + + + if __name__ == '__main__': + unittest.main() + From 320582d82a9c6a50d499ffbb559a95beda03cd41 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Wed, 28 Dec 2022 03:07:13 +0200 Subject: [PATCH 02/23] Assignment-8 done --- Bounded_Subsidy_Algorithem.py | 119 ++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 Bounded_Subsidy_Algorithem.py diff --git a/Bounded_Subsidy_Algorithem.py b/Bounded_Subsidy_Algorithem.py new file mode 100644 index 00000000..9983c862 --- /dev/null +++ b/Bounded_Subsidy_Algorithem.py @@ -0,0 +1,119 @@ + +""" +#----------------------------------------------------- +# name of the article: One Dollar Each Eliminates Envy +# authors: J. Brustle, J. Dippel, V.V. Narayan, M. Suzuki and A. Vetta +# link to the article: https://www.researchgate.net/publication/337781386_One_Dollar_Each_Eliminates_Envy + +# Programmer: Eyad Amer +# Since : 2022-12 +#----------------------------------------------------- +""" + +import fairpy +import networkx +from typing import * +from fairpy.items.utilitarian_matching import instance_to_graph, matching_to_allocation +from fairpy import AgentList +from dicttools import stringify + +import logging +logger = logging.getLogger(__name__) + + + +def Bounded_Subsidy(agents: Dict[str, Dict[str, int]], items: Dict[str,int], weights: Dict[str,int]): + """ + The algorithm getting a list of agents, list of goods and array of the weights of the goods + and it's returns a bundle of agents when each of the holds the best allocation to his valuation of the goods. + + Algorithem bounded_subsidy: + -------------------------------------------------------------------------- + * I = {1, 2, . . . , n} => set of agents + * J = {J1, J2, . . . , Jm} => set of indivisible goods (items) + * A = {A1, . . . , An} => An allocation is an ordered partition of the set of items into n bundles. (The task is to construct an envy-freeable allocation A with maximum path weight 1 in the envy graph GA) + * vi => Each agent i ∈ I has a valuation function vi over the set of items. + * H[I, Jt] => The valuation graph H is the complete bipartite graph on vertex sets I and J, where edge (i, j) has weight vi(j). + * Mt => a maximum-weight matching in H[I, Jt]. + * µti => If agent i is matched to item j = µti then we allocate item µti to that agent. + + + Ai ← ∅ for all i ∈ I; + t ← 1; J1 ← J; // For the first round, we set J1 = J + while Jt != ∅ do: // The process ends when every item has been allocated + Compute a maximum-weight matching Mt = {(i, µti)}i∈I in H[I, Jt]; // we find a maximum-weight matching Mt in H[I, Jt] + Set Ai ← Ai ∪ {µti} for all i ∈ I; // If agent i is matched to item j = µti then we allocate item µti to that agent + Set Jt+1 ← Jt \ ∪i∈I{µti}; // We recurse on the remaining items + t ← t + 1; + end + ---------------------------------------------------------------------------- + + >>> agents1 = ({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}) + >>> alloc_max_weight_one = iterated_maximum_matching(agents1, items={"a":1,"b":1,"c":1,"d":1}) + >>> stringify(alloc_max_weight_one) + "{Alice: ['b', 'c'], Bob: ['a', 'd']}" + + + >>> agents2 = ({"Alice": {"a":10, "b":8, "c":5, "d":10, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":0}) + >>> alloc_max_weight_one = iterated_maximum_matching(agents2, items={"a":1, "b":1, "c":1, "d":1, "e":1, "f":1}) + >>> stringify(alloc_max_weight_one) + "{Alice: ['a', 'b', 'c'], Bob: ['d', 'e', 'f']}" + + """ + items = None + weights = None + + listOfAgents = fairpy.agents_from(agents) # list of agents + NamesOfAgent = fairpy.agent_names_from(agents) # names of agents + + allTheItems = listOfAgents[0].all_items() # list of items + if items is None: + items = {item:1 for item in allTheItems} + result = {agent.name(): [] for agent in agents} # list for the result + + while len(items) >= 1: # The process ends when every item has been allocated + # The valuation graph H is the complete bipartite graph on vertex sets I and J, where edge (i, j) has weight vi(j) + H = instance_to_graph(agents, weights=weights, items=items) + logger.info("Graph edges: %s", list(H.edges.data())) + # a maximum weight matching in H[I, Jt] + Mt = networkx.max_weight_matching(H, maxcardinality=False) + logger.info("Matching: %s", Mt) + # if agent i is matched to item j = µti then we allocate item µti to that agent + agentsBundle = matching_to_allocation(Mt, agent_names=NamesOfAgent) + for agent,bundle in agentsBundle.items(): + result[agent] += bundle + # Remove the given items and recurse on the remaining items + allocated_items = sum([bundle for bundle in agentsBundle.values()], []) # the number of the items that allocated to the agents + items = delete_items(items, allocated_items) # delete_items + + return result + +Bounded_Subsidy.logger = logger + + +def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: + """ + # This is help function that Remove the given items from the graph + + >>> stringify(delete_items({"a":4, "b":10, "c":8, "d":7}, ["a","b","d"])) + '{a:3, b:9, c:8, d:6}' + + >>> stringify(delete_items({"a":9, "b":2, "c":4, "d":7, "e":10, "f":0}, ["b","c"])) + '{a:9, b:1, c:3, d:7, e:10}' + + >>> stringify(delete_items({"a":1, "b":2, "c":1}, ["a", "b", "c"])) + '{b:1}' + """ + for i in items_to_remove: + items[i] -= 1 + + for item,newSize in items.items(): + if newSize > 0: + return {item:newSize} + + +# Main Function +if __name__ == "__main__": + import doctest + (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) + print("{} failures, {} tests".format(failures, tests)) \ No newline at end of file From c8c3ca3676ce43e384dd262722c7c0a0fc1da423 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Wed, 28 Dec 2022 03:07:47 +0200 Subject: [PATCH 03/23] Assignment-8 done --- fairpy/items/Bounded_Subsidy_Algorithem.py | 119 +++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 fairpy/items/Bounded_Subsidy_Algorithem.py diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py new file mode 100644 index 00000000..9983c862 --- /dev/null +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -0,0 +1,119 @@ + +""" +#----------------------------------------------------- +# name of the article: One Dollar Each Eliminates Envy +# authors: J. Brustle, J. Dippel, V.V. Narayan, M. Suzuki and A. Vetta +# link to the article: https://www.researchgate.net/publication/337781386_One_Dollar_Each_Eliminates_Envy + +# Programmer: Eyad Amer +# Since : 2022-12 +#----------------------------------------------------- +""" + +import fairpy +import networkx +from typing import * +from fairpy.items.utilitarian_matching import instance_to_graph, matching_to_allocation +from fairpy import AgentList +from dicttools import stringify + +import logging +logger = logging.getLogger(__name__) + + + +def Bounded_Subsidy(agents: Dict[str, Dict[str, int]], items: Dict[str,int], weights: Dict[str,int]): + """ + The algorithm getting a list of agents, list of goods and array of the weights of the goods + and it's returns a bundle of agents when each of the holds the best allocation to his valuation of the goods. + + Algorithem bounded_subsidy: + -------------------------------------------------------------------------- + * I = {1, 2, . . . , n} => set of agents + * J = {J1, J2, . . . , Jm} => set of indivisible goods (items) + * A = {A1, . . . , An} => An allocation is an ordered partition of the set of items into n bundles. (The task is to construct an envy-freeable allocation A with maximum path weight 1 in the envy graph GA) + * vi => Each agent i ∈ I has a valuation function vi over the set of items. + * H[I, Jt] => The valuation graph H is the complete bipartite graph on vertex sets I and J, where edge (i, j) has weight vi(j). + * Mt => a maximum-weight matching in H[I, Jt]. + * µti => If agent i is matched to item j = µti then we allocate item µti to that agent. + + + Ai ← ∅ for all i ∈ I; + t ← 1; J1 ← J; // For the first round, we set J1 = J + while Jt != ∅ do: // The process ends when every item has been allocated + Compute a maximum-weight matching Mt = {(i, µti)}i∈I in H[I, Jt]; // we find a maximum-weight matching Mt in H[I, Jt] + Set Ai ← Ai ∪ {µti} for all i ∈ I; // If agent i is matched to item j = µti then we allocate item µti to that agent + Set Jt+1 ← Jt \ ∪i∈I{µti}; // We recurse on the remaining items + t ← t + 1; + end + ---------------------------------------------------------------------------- + + >>> agents1 = ({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}) + >>> alloc_max_weight_one = iterated_maximum_matching(agents1, items={"a":1,"b":1,"c":1,"d":1}) + >>> stringify(alloc_max_weight_one) + "{Alice: ['b', 'c'], Bob: ['a', 'd']}" + + + >>> agents2 = ({"Alice": {"a":10, "b":8, "c":5, "d":10, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":0}) + >>> alloc_max_weight_one = iterated_maximum_matching(agents2, items={"a":1, "b":1, "c":1, "d":1, "e":1, "f":1}) + >>> stringify(alloc_max_weight_one) + "{Alice: ['a', 'b', 'c'], Bob: ['d', 'e', 'f']}" + + """ + items = None + weights = None + + listOfAgents = fairpy.agents_from(agents) # list of agents + NamesOfAgent = fairpy.agent_names_from(agents) # names of agents + + allTheItems = listOfAgents[0].all_items() # list of items + if items is None: + items = {item:1 for item in allTheItems} + result = {agent.name(): [] for agent in agents} # list for the result + + while len(items) >= 1: # The process ends when every item has been allocated + # The valuation graph H is the complete bipartite graph on vertex sets I and J, where edge (i, j) has weight vi(j) + H = instance_to_graph(agents, weights=weights, items=items) + logger.info("Graph edges: %s", list(H.edges.data())) + # a maximum weight matching in H[I, Jt] + Mt = networkx.max_weight_matching(H, maxcardinality=False) + logger.info("Matching: %s", Mt) + # if agent i is matched to item j = µti then we allocate item µti to that agent + agentsBundle = matching_to_allocation(Mt, agent_names=NamesOfAgent) + for agent,bundle in agentsBundle.items(): + result[agent] += bundle + # Remove the given items and recurse on the remaining items + allocated_items = sum([bundle for bundle in agentsBundle.values()], []) # the number of the items that allocated to the agents + items = delete_items(items, allocated_items) # delete_items + + return result + +Bounded_Subsidy.logger = logger + + +def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: + """ + # This is help function that Remove the given items from the graph + + >>> stringify(delete_items({"a":4, "b":10, "c":8, "d":7}, ["a","b","d"])) + '{a:3, b:9, c:8, d:6}' + + >>> stringify(delete_items({"a":9, "b":2, "c":4, "d":7, "e":10, "f":0}, ["b","c"])) + '{a:9, b:1, c:3, d:7, e:10}' + + >>> stringify(delete_items({"a":1, "b":2, "c":1}, ["a", "b", "c"])) + '{b:1}' + """ + for i in items_to_remove: + items[i] -= 1 + + for item,newSize in items.items(): + if newSize > 0: + return {item:newSize} + + +# Main Function +if __name__ == "__main__": + import doctest + (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) + print("{} failures, {} tests".format(failures, tests)) \ No newline at end of file From a416819caab9076efdfb2d2eb52a0bff47afb37b Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Sun, 1 Jan 2023 15:52:55 +0200 Subject: [PATCH 04/23] delete demo algo --- Bounded_Subsidy_Algorithem.py | 119 ---------------------------------- 1 file changed, 119 deletions(-) delete mode 100644 Bounded_Subsidy_Algorithem.py diff --git a/Bounded_Subsidy_Algorithem.py b/Bounded_Subsidy_Algorithem.py deleted file mode 100644 index 9983c862..00000000 --- a/Bounded_Subsidy_Algorithem.py +++ /dev/null @@ -1,119 +0,0 @@ - -""" -#----------------------------------------------------- -# name of the article: One Dollar Each Eliminates Envy -# authors: J. Brustle, J. Dippel, V.V. Narayan, M. Suzuki and A. Vetta -# link to the article: https://www.researchgate.net/publication/337781386_One_Dollar_Each_Eliminates_Envy - -# Programmer: Eyad Amer -# Since : 2022-12 -#----------------------------------------------------- -""" - -import fairpy -import networkx -from typing import * -from fairpy.items.utilitarian_matching import instance_to_graph, matching_to_allocation -from fairpy import AgentList -from dicttools import stringify - -import logging -logger = logging.getLogger(__name__) - - - -def Bounded_Subsidy(agents: Dict[str, Dict[str, int]], items: Dict[str,int], weights: Dict[str,int]): - """ - The algorithm getting a list of agents, list of goods and array of the weights of the goods - and it's returns a bundle of agents when each of the holds the best allocation to his valuation of the goods. - - Algorithem bounded_subsidy: - -------------------------------------------------------------------------- - * I = {1, 2, . . . , n} => set of agents - * J = {J1, J2, . . . , Jm} => set of indivisible goods (items) - * A = {A1, . . . , An} => An allocation is an ordered partition of the set of items into n bundles. (The task is to construct an envy-freeable allocation A with maximum path weight 1 in the envy graph GA) - * vi => Each agent i ∈ I has a valuation function vi over the set of items. - * H[I, Jt] => The valuation graph H is the complete bipartite graph on vertex sets I and J, where edge (i, j) has weight vi(j). - * Mt => a maximum-weight matching in H[I, Jt]. - * µti => If agent i is matched to item j = µti then we allocate item µti to that agent. - - - Ai ← ∅ for all i ∈ I; - t ← 1; J1 ← J; // For the first round, we set J1 = J - while Jt != ∅ do: // The process ends when every item has been allocated - Compute a maximum-weight matching Mt = {(i, µti)}i∈I in H[I, Jt]; // we find a maximum-weight matching Mt in H[I, Jt] - Set Ai ← Ai ∪ {µti} for all i ∈ I; // If agent i is matched to item j = µti then we allocate item µti to that agent - Set Jt+1 ← Jt \ ∪i∈I{µti}; // We recurse on the remaining items - t ← t + 1; - end - ---------------------------------------------------------------------------- - - >>> agents1 = ({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}) - >>> alloc_max_weight_one = iterated_maximum_matching(agents1, items={"a":1,"b":1,"c":1,"d":1}) - >>> stringify(alloc_max_weight_one) - "{Alice: ['b', 'c'], Bob: ['a', 'd']}" - - - >>> agents2 = ({"Alice": {"a":10, "b":8, "c":5, "d":10, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":0}) - >>> alloc_max_weight_one = iterated_maximum_matching(agents2, items={"a":1, "b":1, "c":1, "d":1, "e":1, "f":1}) - >>> stringify(alloc_max_weight_one) - "{Alice: ['a', 'b', 'c'], Bob: ['d', 'e', 'f']}" - - """ - items = None - weights = None - - listOfAgents = fairpy.agents_from(agents) # list of agents - NamesOfAgent = fairpy.agent_names_from(agents) # names of agents - - allTheItems = listOfAgents[0].all_items() # list of items - if items is None: - items = {item:1 for item in allTheItems} - result = {agent.name(): [] for agent in agents} # list for the result - - while len(items) >= 1: # The process ends when every item has been allocated - # The valuation graph H is the complete bipartite graph on vertex sets I and J, where edge (i, j) has weight vi(j) - H = instance_to_graph(agents, weights=weights, items=items) - logger.info("Graph edges: %s", list(H.edges.data())) - # a maximum weight matching in H[I, Jt] - Mt = networkx.max_weight_matching(H, maxcardinality=False) - logger.info("Matching: %s", Mt) - # if agent i is matched to item j = µti then we allocate item µti to that agent - agentsBundle = matching_to_allocation(Mt, agent_names=NamesOfAgent) - for agent,bundle in agentsBundle.items(): - result[agent] += bundle - # Remove the given items and recurse on the remaining items - allocated_items = sum([bundle for bundle in agentsBundle.values()], []) # the number of the items that allocated to the agents - items = delete_items(items, allocated_items) # delete_items - - return result - -Bounded_Subsidy.logger = logger - - -def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: - """ - # This is help function that Remove the given items from the graph - - >>> stringify(delete_items({"a":4, "b":10, "c":8, "d":7}, ["a","b","d"])) - '{a:3, b:9, c:8, d:6}' - - >>> stringify(delete_items({"a":9, "b":2, "c":4, "d":7, "e":10, "f":0}, ["b","c"])) - '{a:9, b:1, c:3, d:7, e:10}' - - >>> stringify(delete_items({"a":1, "b":2, "c":1}, ["a", "b", "c"])) - '{b:1}' - """ - for i in items_to_remove: - items[i] -= 1 - - for item,newSize in items.items(): - if newSize > 0: - return {item:newSize} - - -# Main Function -if __name__ == "__main__": - import doctest - (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) - print("{} failures, {} tests".format(failures, tests)) \ No newline at end of file From 14932ed4801a266679548a103b2274a5cc458d75 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Wed, 4 Jan 2023 04:29:07 +0200 Subject: [PATCH 05/23] Update Bounded_Subsidy_Algorithem.py --- fairpy/items/Bounded_Subsidy_Algorithem.py | 188 ++++++++++++++++----- 1 file changed, 149 insertions(+), 39 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index 9983c862..46c2bea6 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -1,4 +1,3 @@ - """ #----------------------------------------------------- # name of the article: One Dollar Each Eliminates Envy @@ -10,19 +9,20 @@ #----------------------------------------------------- """ -import fairpy + import networkx +import sys +import doctest from typing import * -from fairpy.items.utilitarian_matching import instance_to_graph, matching_to_allocation from fairpy import AgentList -from dicttools import stringify +from fairpy.items.utilitarian_matching import instance_to_graph, matching_to_allocation +from fairpy import AdditiveAgent import logging logger = logging.getLogger(__name__) - -def Bounded_Subsidy(agents: Dict[str, Dict[str, int]], items: Dict[str,int], weights: Dict[str,int]): +def Bounded_Subsidy(agents: AgentList, items: Dict[str,int]=None, weights: Dict[str, int]=None): """ The algorithm getting a list of agents, list of goods and array of the weights of the goods and it's returns a bundle of agents when each of the holds the best allocation to his valuation of the goods. @@ -47,50 +47,151 @@ def Bounded_Subsidy(agents: Dict[str, Dict[str, int]], items: Dict[str,int], wei t ← t + 1; end ---------------------------------------------------------------------------- + Tests + ---------------------------------------------------------------------------- + >>> agents1 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) + >>> print(Bounded_Subsidy(agents1)) + {'Alice': ['b', 'c'], 'Bob': ['d', 'a']} - >>> agents1 = ({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}) - >>> alloc_max_weight_one = iterated_maximum_matching(agents1, items={"a":1,"b":1,"c":1,"d":1}) - >>> stringify(alloc_max_weight_one) - "{Alice: ['b', 'c'], Bob: ['a', 'd']}" - + >>> agents2 = AgentList({"Alice": {"a":10, "b":8, "c":5, "d":9, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":0}}) + >>> alloc_max_weight_one = Bounded_Subsidy(agents2, items={"a":1, "b":1, "c":1, "d":1, "e":1, "f":1}) + >>> print(alloc_max_weight_one) + {'Alice': ['a', 'b', 'c'], 'Bob': ['e', 'd', 'f']} - >>> agents2 = ({"Alice": {"a":10, "b":8, "c":5, "d":10, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":0}) - >>> alloc_max_weight_one = iterated_maximum_matching(agents2, items={"a":1, "b":1, "c":1, "d":1, "e":1, "f":1}) - >>> stringify(alloc_max_weight_one) - "{Alice: ['a', 'b', 'c'], Bob: ['d', 'e', 'f']}" + >>> agents3 = AgentList([[5,4,3,2],[2,3,4,5]]) + >>> print(Bounded_Subsidy(agents3)) + {'Agent #0': [0, 1], 'Agent #1': [3, 2]} - """ - items = None - weights = None + >>> agents4 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) + >>> print(Bounded_Subsidy(agents4)) + {'Alice': ['b'], 'Bob': ['a']} - listOfAgents = fairpy.agents_from(agents) # list of agents - NamesOfAgent = fairpy.agent_names_from(agents) # names of agents + >>> agents5 = AgentList({"Alice": {"a":3, "b":2}, "Bob": {"a":4, "b":1}}) + >>> print(Bounded_Subsidy(agents5)) + {'Alice': ['b'], 'Bob': ['a']} - allTheItems = listOfAgents[0].all_items() # list of items + """ + assert isinstance(agents, AgentList) + allTheItems = agents[0].all_items() # list of all items if items is None: - items = {item:1 for item in allTheItems} - result = {agent.name(): [] for agent in agents} # list for the result - - while len(items) >= 1: # The process ends when every item has been allocated + items = {item:1 for item in allTheItems} + result = {agent.name(): [] for agent in agents} # empty list for the result => {agent.name: ['item.name']} + # print(allTheItems) + + while len(items) > 0: # The process ends when every item has been allocated # The valuation graph H is the complete bipartite graph on vertex sets I and J, where edge (i, j) has weight vi(j) - H = instance_to_graph(agents, weights=weights, items=items) + H = instance_to_graph(agents, agent_weights=weights, item_capacities=items) + # print(H) logger.info("Graph edges: %s", list(H.edges.data())) # a maximum weight matching in H[I, Jt] - Mt = networkx.max_weight_matching(H, maxcardinality=False) + Mt = networkx.max_weight_matching(H, maxcardinality=False) # H חשב התאמה משוקללת מקסימלית של . + # print(Mt) logger.info("Matching: %s", Mt) # if agent i is matched to item j = µti then we allocate item µti to that agent - agentsBundle = matching_to_allocation(Mt, agent_names=NamesOfAgent) - for agent,bundle in agentsBundle.items(): - result[agent] += bundle - # Remove the given items and recurse on the remaining items - allocated_items = sum([bundle for bundle in agentsBundle.values()], []) # the number of the items that allocated to the agents + agentsBundle = matching_to_allocation(Mt, agent_names=agents.agent_names()) # ממירה התאמה של אחד לרבים בגרף דו-חלקי + # print(agentsBundle) + for agent_name,item_name in agentsBundle.items(): + result[agent_name] += item_name + # print(agent_name, item_name) + # print(result) + # The items that allocated to the agents in this round + allocated_items = sum([item for item in agentsBundle.values()], []) + # print(allocated_items) + # Remove the allocated items and recurse on the remaining items items = delete_items(items, allocated_items) # delete_items - + return result Bounded_Subsidy.logger = logger +def allocate_items_with_Subsidy(agents: AgentList, items: Dict[str,int]=None, weights: Dict[str, int]=None): + """ + The algorithm getting a list of agents, list of goods and array of the weights of the goods + and it returns a bundle of agents each holding the best allocation for their own valuation, + with the subsidy that eliminates envy + + >>> agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) + >>> allocate_items_with_Subsidy(agents1) + Alice gets ['b'] ,Bob gets ['a'] and subsidy of 1 + + >>> agents2 = AgentList({"Alice": {"a":3, "b":2}, "Bob": {"a":4, "b":1}}) + >>> allocate_items_with_Subsidy(agents2) + Alice gets ['b'] and subsidy of 1 ,Bob gets ['a'] + + >>> agents3 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) + >>> allocate_items_with_Subsidy(agents3) + Alice gets ['b', 'c'] ,Bob gets ['d', 'a'] .No subsidy + + >>> agents4 = AgentList({"Alice": {"a":10, "b":8, "c":5, "d":9, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":1}}) + >>> allocate_items_with_Subsidy(agents4) + Alice gets ['a', 'b', 'c'] ,Bob gets ['e', 'd', 'f'] .No subsidy + + """ + + + assert isinstance(agents, AgentList) + allTheItems = agents[0].all_items() # list of all items + + sum_of_all_values_Alice = agents[0].value(list(allTheItems)) + sum_of_all_values_bob = agents[1].value(list(allTheItems)) + + if items is None: + items = {item:1 for item in allTheItems} + result = {agent.name(): [] for agent in agents} # empty list for the result => {agent.name: ['item.name']} + # print(allTheItems) + + sum_Alice = 0 + sum_Bob = 0 + + while len(items) > 0: # The process ends when every item has been allocated + # The valuation graph H is the complete bipartite graph on vertex sets I and J, where edge (i, j) has weight vi(j) + H = instance_to_graph(agents, agent_weights=weights, item_capacities=items) + # print(H) + logger.info("Graph edges: %s", list(H.edges.data())) + # a maximum weight matching in H[I, Jt] + Mt = networkx.max_weight_matching(H, maxcardinality=False) # H חשב התאמה משוקללת מקסימלית של . + # print(Mt) + logger.info("Matching: %s", Mt) + # if agent i is matched to item j = µti then we allocate item µti to that agent + agentsBundle = matching_to_allocation(Mt, agent_names=agents.agent_names()) # ממירה התאמה של אחד לרבים בגרף דו-חלקי + # print(agentsBundle) + agent1 = (list(agentsBundle.keys())[0]) + # agent2 = (list(agentsBundle.keys())[1]) + + Alice = agents[0].name() + # Bob = agents[1].name() + + for agent_name,item_name in agentsBundle.items(): + result[agent_name] += item_name + + # The items that allocated to the agents in this round + allocated_items = sum([item for item in agentsBundle.values()], []) + + if(agent1 == Alice): + sum_Alice += agents[0].value(allocated_items[0]) + sum_Bob += agents[1].value(allocated_items[1]) + else: + sum_Alice += agents[0].value(allocated_items[1]) + sum_Bob += agents[1].value(allocated_items[0]) + + # Remove the allocated items and recurse on the remaining items + items = delete_items(items, allocated_items) # delete_items + + # subsid value + subsid_alice = ((2 * sum_Alice)-sum_of_all_values_Alice) + subsid_Bob = ((2 * sum_Bob)-sum_of_all_values_bob) + + if (subsid_alice < 0): + print("Alice gets", list(result.values())[0], "and subsidy of",subsid_alice*-1, ",Bob gets", list(result.values())[1]) + elif (subsid_Bob < 0): + print("Alice gets", list(result.values())[0], ",Bob gets", list(result.values())[1],"and subsidy of",subsid_Bob*-1) + else: + print("Alice gets", list(result.values())[0], ",Bob gets", list(result.values())[1],".No subsidy") + +allocate_items_with_Subsidy.logger = logger + + def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: """ # This is help function that Remove the given items from the graph @@ -107,13 +208,22 @@ def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: for i in items_to_remove: items[i] -= 1 - for item,newSize in items.items(): - if newSize > 0: - return {item:newSize} + return {item:newSize for item,newSize in items.items() if newSize > 0} + + +#### MAIN -# Main Function if __name__ == "__main__": - import doctest + # import sys + # logger.addHandler(logging.StreamHandler(sys.stdout)) + # logger.setLevel(logging.INFO) (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) - print("{} failures, {} tests".format(failures, tests)) \ No newline at end of file + print("{} failures, {} tests".format(failures, tests)) + # agents4 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) + # agents1 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) + # agents5 = AgentList({"Alice": {"a":3, "b":2}, "Bob": {"a":4, "b":1}}) + # agents2 = AgentList({"Alice": {"a":10, "b":8, "c":5, "d":9, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":1}}) + + # Bounded_Subsidy(agents1) + # allocate_items_with_Subsidy(agents2) From b585b6196decf59dd8ccc7bec8c5bf0bcf1681c2 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Wed, 4 Jan 2023 23:36:54 +0200 Subject: [PATCH 06/23] done --- fairpy/items/Bounded_Subsidy_Algorithem.py | 124 +++++++++++++-------- 1 file changed, 76 insertions(+), 48 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index 46c2bea6..421a3fc9 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -17,6 +17,8 @@ from fairpy import AgentList from fairpy.items.utilitarian_matching import instance_to_graph, matching_to_allocation from fairpy import AdditiveAgent +import numpy as np + import logging logger = logging.getLogger(__name__) @@ -70,6 +72,10 @@ def Bounded_Subsidy(agents: AgentList, items: Dict[str,int]=None, weights: Dict[ >>> print(Bounded_Subsidy(agents5)) {'Alice': ['b'], 'Bob': ['a']} + >>> agents6 = AgentList([[3,2],[4,1]]) + >>> print(Bounded_Subsidy(agents6)) + {'Agent #0': [1], 'Agent #1': [0]} + """ assert isinstance(agents, AgentList) allTheItems = agents[0].all_items() # list of all items @@ -111,21 +117,34 @@ def allocate_items_with_Subsidy(agents: AgentList, items: Dict[str,int]=None, we and it returns a bundle of agents each holding the best allocation for their own valuation, with the subsidy that eliminates envy + ###### Two agens ###### >>> agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) >>> allocate_items_with_Subsidy(agents1) - Alice gets ['b'] ,Bob gets ['a'] and subsidy of 1 + Alice gets ['b'] with no subsidy + Bob gets ['a'] with subsidy of 1 >>> agents2 = AgentList({"Alice": {"a":3, "b":2}, "Bob": {"a":4, "b":1}}) >>> allocate_items_with_Subsidy(agents2) - Alice gets ['b'] and subsidy of 1 ,Bob gets ['a'] + Alice gets ['b'] with subsidy of 1 + Bob gets ['a'] with no subsidy >>> agents3 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) >>> allocate_items_with_Subsidy(agents3) - Alice gets ['b', 'c'] ,Bob gets ['d', 'a'] .No subsidy + Alice gets ['b', 'c'] with no subsidy + Bob gets ['d', 'a'] with no subsidy >>> agents4 = AgentList({"Alice": {"a":10, "b":8, "c":5, "d":9, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":1}}) >>> allocate_items_with_Subsidy(agents4) - Alice gets ['a', 'b', 'c'] ,Bob gets ['e', 'd', 'f'] .No subsidy + Alice gets ['a', 'b', 'c'] with no subsidy + Bob gets ['e', 'd', 'f'] with no subsidy + + ###### Three agents ###### + + >>> agents6 = AgentList({"Alice": {"a":3, "b":4, "c":6}, "Bob": {"a":4, "b":3, "c":1}, "Max": {"a":4, "b":5, "c":1}}) + >>> allocate_items_with_Subsidy(agents5) + Alice gets ['c'] with subsidy of 1 + Bob gets ['a'] with no subsidy + Max gets ['b'] with no subsidy """ @@ -133,16 +152,25 @@ def allocate_items_with_Subsidy(agents: AgentList, items: Dict[str,int]=None, we assert isinstance(agents, AgentList) allTheItems = agents[0].all_items() # list of all items - sum_of_all_values_Alice = agents[0].value(list(allTheItems)) - sum_of_all_values_bob = agents[1].value(list(allTheItems)) + # list of the sum of all the values of the items for all agents + sum_of_all_values_agents = {} + # list of the values of the items that allocate to the agent + sum_items_val_that_agent_gets = {} + + # Initialize both lists + i = 0 + while i < len(agents): + key = agents[i].name() + value = agents[i].value(list(allTheItems)) + sum_of_all_values_agents[key] = value + sum_items_val_that_agent_gets[key] = 0 + i += 1 if items is None: items = {item:1 for item in allTheItems} - result = {agent.name(): [] for agent in agents} # empty list for the result => {agent.name: ['item.name']} - # print(allTheItems) - - sum_Alice = 0 - sum_Bob = 0 + + # empty list for the result => {agent.name: ['item.name']} + result = {agent.name(): [] for agent in agents} while len(items) > 0: # The process ends when every item has been allocated # The valuation graph H is the complete bipartite graph on vertex sets I and J, where edge (i, j) has weight vi(j) @@ -155,12 +183,6 @@ def allocate_items_with_Subsidy(agents: AgentList, items: Dict[str,int]=None, we logger.info("Matching: %s", Mt) # if agent i is matched to item j = µti then we allocate item µti to that agent agentsBundle = matching_to_allocation(Mt, agent_names=agents.agent_names()) # ממירה התאמה של אחד לרבים בגרף דו-חלקי - # print(agentsBundle) - agent1 = (list(agentsBundle.keys())[0]) - # agent2 = (list(agentsBundle.keys())[1]) - - Alice = agents[0].name() - # Bob = agents[1].name() for agent_name,item_name in agentsBundle.items(): result[agent_name] += item_name @@ -168,26 +190,33 @@ def allocate_items_with_Subsidy(agents: AgentList, items: Dict[str,int]=None, we # The items that allocated to the agents in this round allocated_items = sum([item for item in agentsBundle.values()], []) - if(agent1 == Alice): - sum_Alice += agents[0].value(allocated_items[0]) - sum_Bob += agents[1].value(allocated_items[1]) - else: - sum_Alice += agents[0].value(allocated_items[1]) - sum_Bob += agents[1].value(allocated_items[0]) + # add the values of the items that allocate to the agents into the appropriate list + j,k = 0,0 + while j < len(sum_items_val_that_agent_gets): + k=0 + while k < len(agentsBundle): + if (list(agentsBundle)[k] == list(sum_items_val_that_agent_gets)[j]): + sum_items_val_that_agent_gets[agents[j].name()] += agents[j].value(allocated_items[k]) + k +=1 + j += 1 # Remove the allocated items and recurse on the remaining items items = delete_items(items, allocated_items) # delete_items - - # subsid value - subsid_alice = ((2 * sum_Alice)-sum_of_all_values_Alice) - subsid_Bob = ((2 * sum_Bob)-sum_of_all_values_bob) - if (subsid_alice < 0): - print("Alice gets", list(result.values())[0], "and subsidy of",subsid_alice*-1, ",Bob gets", list(result.values())[1]) - elif (subsid_Bob < 0): - print("Alice gets", list(result.values())[0], ",Bob gets", list(result.values())[1],"and subsidy of",subsid_Bob*-1) - else: - print("Alice gets", list(result.values())[0], ",Bob gets", list(result.values())[1],".No subsidy") + # create a list of subsidies for the items that allocate to the agents + i=0 + subsid_list = {} + while i < len(agents): + key = agents[i].name() + value = (2 * sum_items_val_that_agent_gets[key]) - sum_of_all_values_agents[key] + subsid_list[key] = value + + # print the results + if (subsid_list[key] < 0): + print(agents[i].name(), "gets", list(result.values())[i], "with subsidy of", subsid_list[key]*-1) + else: + print(agents[i].name(), "gets", list(result.values())[i], "with no subsidy") + i += 1 allocate_items_with_Subsidy.logger = logger @@ -196,14 +225,14 @@ def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: """ # This is help function that Remove the given items from the graph - >>> stringify(delete_items({"a":4, "b":10, "c":8, "d":7}, ["a","b","d"])) - '{a:3, b:9, c:8, d:6}' + >>> print(delete_items({"a":4, "b":10, "c":8, "d":7}, ["a","b","d"])) + {'a': 3, 'b': 9, 'c': 8, 'd': 6} - >>> stringify(delete_items({"a":9, "b":2, "c":4, "d":7, "e":10, "f":0}, ["b","c"])) - '{a:9, b:1, c:3, d:7, e:10}' + >>> print(delete_items({"a":9, "b":2, "c":4, "d":7, "e":10, "f":0}, ["b","c"])) + {'a': 9, 'b': 1, 'c': 3, 'd': 7, 'e': 10} - >>> stringify(delete_items({"a":1, "b":2, "c":1}, ["a", "b", "c"])) - '{b:1}' + >>> print(delete_items({"a":1, "b":2, "c":1}, ["a", "b", "c"])) + {'b': 1} """ for i in items_to_remove: items[i] -= 1 @@ -211,19 +240,18 @@ def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: return {item:newSize for item,newSize in items.items() if newSize > 0} - #### MAIN if __name__ == "__main__": - # import sys + import sys # logger.addHandler(logging.StreamHandler(sys.stdout)) # logger.setLevel(logging.INFO) (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) print("{} failures, {} tests".format(failures, tests)) - # agents4 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) - # agents1 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) - # agents5 = AgentList({"Alice": {"a":3, "b":2}, "Bob": {"a":4, "b":1}}) - # agents2 = AgentList({"Alice": {"a":10, "b":8, "c":5, "d":9, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":1}}) - - # Bounded_Subsidy(agents1) - # allocate_items_with_Subsidy(agents2) + # agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) + # agents2 = AgentList({"Alice": {"a":3, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) + # agents3 = AgentList({"Alice": {"a":3, "b":2}, "Bob": {"a":4, "b":1}}) + # agents4 = AgentList({"Alice": {"a":10, "b":8, "c":5, "d":9, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":1}}) + # agents5 = AgentList({"Alice": {"a":3, "b":4, "c":6}, "Bob": {"a":4, "b":3, "c":1}, "Max": {"a":4, "b":5, "c":1}}) + # allocate_items_with_Subsidy(agents5) + From f6d89daedef743aaa09605cc480356da65e737ff Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Thu, 5 Jan 2023 11:22:07 +0200 Subject: [PATCH 07/23] add more tests --- fairpy/items/Bounded_Subsidy_Algorithem.py | 34 ++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index 421a3fc9..ea3caf83 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -77,7 +77,6 @@ def Bounded_Subsidy(agents: AgentList, items: Dict[str,int]=None, weights: Dict[ {'Agent #0': [1], 'Agent #1': [0]} """ - assert isinstance(agents, AgentList) allTheItems = agents[0].all_items() # list of all items if items is None: items = {item:1 for item in allTheItems} @@ -117,7 +116,13 @@ def allocate_items_with_Subsidy(agents: AgentList, items: Dict[str,int]=None, we and it returns a bundle of agents each holding the best allocation for their own valuation, with the subsidy that eliminates envy - ###### Two agens ###### + ###### Two agens, one items ###### + >>> agents0 = AgentList({"Alice": {"a":5}, "Bob": {"a":4}}) + >>> allocate_items_with_Subsidy(agents0) + Alice gets ['a'] with no subsidy + Bob gets [] with subsidy of 4 + + ###### Two agens, Two items ###### >>> agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) >>> allocate_items_with_Subsidy(agents1) Alice gets ['b'] with no subsidy @@ -138,18 +143,37 @@ def allocate_items_with_Subsidy(agents: AgentList, items: Dict[str,int]=None, we Alice gets ['a', 'b', 'c'] with no subsidy Bob gets ['e', 'd', 'f'] with no subsidy - ###### Three agents ###### + ###### Three agents, Three items ###### - >>> agents6 = AgentList({"Alice": {"a":3, "b":4, "c":6}, "Bob": {"a":4, "b":3, "c":1}, "Max": {"a":4, "b":5, "c":1}}) + >>> agents5 = AgentList({"Alice": {"a":3, "b":4, "c":6}, "Bob": {"a":4, "b":3, "c":1}, "Max": {"a":4, "b":5, "c":1}}) >>> allocate_items_with_Subsidy(agents5) Alice gets ['c'] with subsidy of 1 Bob gets ['a'] with no subsidy Max gets ['b'] with no subsidy + >>> agents6 = AgentList({"Alice": {"a":1, "b":2, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) + >>> allocate_items_with_Subsidy(agents6) + Alice gets ['c'] with no subsidy + Bob gets ['b'] with no subsidy + Max gets ['a'] with no subsidy + + >>> agents7 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) + >>> allocate_items_with_Subsidy(agents7) + Alice gets ['b'] with no subsidy + Bob gets ['c'] with subsidy of 2 + Max gets ['a'] with no subsidy + + ###### Four agents ###### + >>> agents8 = AgentList({"Alice": {"a":5}, "Bob": {"a":3}, "Max": {"a":2}, "Nancy": {"a":2}}) + >>> allocate_items_with_Subsidy(agents8) + Alice gets ['a'] with no subsidy + Bob gets [] with subsidy of 3 + Max gets [] with subsidy of 2 + Nancy gets [] with subsidy of 2 + """ - assert isinstance(agents, AgentList) allTheItems = agents[0].all_items() # list of all items # list of the sum of all the values of the items for all agents From c21481b07b11ce4d9d2a54dc83463541991afae4 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Wed, 11 Jan 2023 18:34:32 +0200 Subject: [PATCH 08/23] update the code --- fairpy/items/Bounded_Subsidy_Algorithem.py | 285 +++++++++++---------- 1 file changed, 154 insertions(+), 131 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index ea3caf83..1f3df1dd 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -110,158 +110,170 @@ def Bounded_Subsidy(agents: AgentList, items: Dict[str,int]=None, weights: Dict[ Bounded_Subsidy.logger = logger -def allocate_items_with_Subsidy(agents: AgentList, items: Dict[str,int]=None, weights: Dict[str, int]=None): +def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: """ - The algorithm getting a list of agents, list of goods and array of the weights of the goods - and it returns a bundle of agents each holding the best allocation for their own valuation, - with the subsidy that eliminates envy - - ###### Two agens, one items ###### - >>> agents0 = AgentList({"Alice": {"a":5}, "Bob": {"a":4}}) - >>> allocate_items_with_Subsidy(agents0) - Alice gets ['a'] with no subsidy - Bob gets [] with subsidy of 4 - - ###### Two agens, Two items ###### - >>> agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) - >>> allocate_items_with_Subsidy(agents1) - Alice gets ['b'] with no subsidy - Bob gets ['a'] with subsidy of 1 - - >>> agents2 = AgentList({"Alice": {"a":3, "b":2}, "Bob": {"a":4, "b":1}}) - >>> allocate_items_with_Subsidy(agents2) - Alice gets ['b'] with subsidy of 1 - Bob gets ['a'] with no subsidy - - >>> agents3 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) - >>> allocate_items_with_Subsidy(agents3) - Alice gets ['b', 'c'] with no subsidy - Bob gets ['d', 'a'] with no subsidy - - >>> agents4 = AgentList({"Alice": {"a":10, "b":8, "c":5, "d":9, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":1}}) - >>> allocate_items_with_Subsidy(agents4) - Alice gets ['a', 'b', 'c'] with no subsidy - Bob gets ['e', 'd', 'f'] with no subsidy - - ###### Three agents, Three items ###### - - >>> agents5 = AgentList({"Alice": {"a":3, "b":4, "c":6}, "Bob": {"a":4, "b":3, "c":1}, "Max": {"a":4, "b":5, "c":1}}) - >>> allocate_items_with_Subsidy(agents5) - Alice gets ['c'] with subsidy of 1 - Bob gets ['a'] with no subsidy - Max gets ['b'] with no subsidy - - >>> agents6 = AgentList({"Alice": {"a":1, "b":2, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) - >>> allocate_items_with_Subsidy(agents6) - Alice gets ['c'] with no subsidy - Bob gets ['b'] with no subsidy - Max gets ['a'] with no subsidy - - >>> agents7 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) - >>> allocate_items_with_Subsidy(agents7) - Alice gets ['b'] with no subsidy - Bob gets ['c'] with subsidy of 2 - Max gets ['a'] with no subsidy - - ###### Four agents ###### - >>> agents8 = AgentList({"Alice": {"a":5}, "Bob": {"a":3}, "Max": {"a":2}, "Nancy": {"a":2}}) - >>> allocate_items_with_Subsidy(agents8) - Alice gets ['a'] with no subsidy - Bob gets [] with subsidy of 3 - Max gets [] with subsidy of 2 - Nancy gets [] with subsidy of 2 + # This is help function that Remove the given items from the graph - """ + >>> print(delete_items({"a":4, "b":10, "c":8, "d":7}, ["a","b","d"])) + {'a': 3, 'b': 9, 'c': 8, 'd': 6} + >>> print(delete_items({"a":9, "b":2, "c":4, "d":7, "e":10, "f":0}, ["b","c"])) + {'a': 9, 'b': 1, 'c': 3, 'd': 7, 'e': 10} - allTheItems = agents[0].all_items() # list of all items + >>> print(delete_items({"a":1, "b":2, "c":1}, ["a", "b", "c"])) + {'b': 1} + """ + for i in items_to_remove: + items[i] -= 1 - # list of the sum of all the values of the items for all agents - sum_of_all_values_agents = {} - # list of the values of the items that allocate to the agent - sum_items_val_that_agent_gets = {} + return {item:newSize for item,newSize in items.items() if newSize > 0} - # Initialize both lists - i = 0 - while i < len(agents): - key = agents[i].name() - value = agents[i].value(list(allTheItems)) - sum_of_all_values_agents[key] = value - sum_items_val_that_agent_gets[key] = 0 - i += 1 - if items is None: - items = {item:1 for item in allTheItems} - # empty list for the result => {agent.name: ['item.name']} - result = {agent.name(): [] for agent in agents} +##### algorithm 2 ##### - while len(items) > 0: # The process ends when every item has been allocated - # The valuation graph H is the complete bipartite graph on vertex sets I and J, where edge (i, j) has weight vi(j) - H = instance_to_graph(agents, agent_weights=weights, item_capacities=items) - # print(H) - logger.info("Graph edges: %s", list(H.edges.data())) - # a maximum weight matching in H[I, Jt] - Mt = networkx.max_weight_matching(H, maxcardinality=False) # H חשב התאמה משוקללת מקסימלית של . - # print(Mt) - logger.info("Matching: %s", Mt) - # if agent i is matched to item j = µti then we allocate item µti to that agent - agentsBundle = matching_to_allocation(Mt, agent_names=agents.agent_names()) # ממירה התאמה של אחד לרבים בגרף דו-חלקי +def maximizes_allocation(agents: Dict[str,AgentList], item_list: List[ItemsView]): + + + """ + + # Allocate each agent with his highest item that has not been allocated. + + >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Alice") + >>> Alice.aq_items = [] + >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Bob") + >>> Bob.aq_items = [] + >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") + >>> Eve.aq_items = [] + >>> agents_dict = {x.name():x for x in [Alice,Bob,Eve]} + >>> items_remaining = list('abcdef') + >>> maximizes_allocation(agents_dict,items_remaining) + >>> [(x.name(),sorted(x.aq_items)) for x in agents_dict.values()] + [('Alice', ['d', 'e']), ('Bob', ['a', 'f']), ('Eve', ['b', 'c'])] + + """ + agents_items = list(agents.items()) + while len(item_list) > 0: + for k, i in (agents_items): + max_item = max([x for x in i.valuation.desired_items if x[0] in item_list], key=lambda x: i.value(x)) + item_list.remove(max_item) + i.aq_items.append(max_item) + agents_items.reverse() - for agent_name,item_name in agentsBundle.items(): - result[agent_name] += item_name - - # The items that allocated to the agents in this round - allocated_items = sum([item for item in agentsBundle.values()], []) - # add the values of the items that allocate to the agents into the appropriate list - j,k = 0,0 - while j < len(sum_items_val_that_agent_gets): - k=0 - while k < len(agentsBundle): - if (list(agentsBundle)[k] == list(sum_items_val_that_agent_gets)[j]): - sum_items_val_that_agent_gets[agents[j].name()] += agents[j].value(allocated_items[k]) - k +=1 - j += 1 - - # Remove the allocated items and recurse on the remaining items - items = delete_items(items, allocated_items) # delete_items +def create_Envy_Graph(agents: Dict[str, AdditiveAgent]) -> networkx.DiGraph: + """ + This function creates an Envy Graph of agents, and maximizes the allocation + for every two nodes representing agent u and v, + there will be an edge from u to v if agent u believes agent vs bundle is worth more then his. + + >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Alice") + >>> Alice.aq_items = ['d', 'e'] + >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Bob") + >>> Bob.aq_items = ['a', 'f'] + >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") + >>> Eve.aq_items = ['b', 'c'] + >>> agents = {x.name():x for x in [Alice,Bob,Eve]} + + >>> list(create_Envy_Graph(agents).nodes) + ['Alice', 'Bob', 'Eve'] + + >>> list(create_Envy_Graph(agents).edges) + [('Alice', 'Bob'), ('Alice', 'Eve')] + """ + + # DiGraph — Directed graphs with self loops + # its stores nodes and edges with optional data, or attributes. + # DiGraphs hold directed edges. Self loops are allowed but multiple (parallel) edges are not. + envy_graph = networkx.DiGraph() + for i in agents.values(): + envy_graph.add_node(i.name()) + i_value = i.value(i.aq_items) # values of items of agent "i" from his eyes + for k in agents.values(): + if i is k: + continue + k_value = i.value(k.aq_items) # values of items of agent "k" from eyes of agent "i" + if k_value > i_value: + envy_graph.add_edge(i.name(), k.name()) + return envy_graph + + +def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph, agents: Dict[str, AdditiveAgent]) -> bool: + """ + This function checks if its envy graph does not contain a positive-weight directed cycle + + >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Alice") + >>> Alice.aq_items = ['d', 'e'] + >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Bob") + >>> Bob.aq_items = ['a', 'f'] + >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") + >>> Eve.aq_items = ['b', 'c'] + >>> agents = {x.name():x for x in [Alice,Bob,Eve]} + + >>> envy_graph = create_Envy_Graph(agents) + >>> check_positive_weight_directed_cycles(envy_graph, agents) + False + + """ - # create a list of subsidies for the items that allocate to the agents - i=0 - subsid_list = {} - while i < len(agents): - key = agents[i].name() - value = (2 * sum_items_val_that_agent_gets[key]) - sum_of_all_values_agents[key] - subsid_list[key] = value + try: + cycle = networkx.find_cycle(envy_graph, orientation="original") + for edge in cycle[:-1]: + to_p, from_p = edge[0], edge[1] + agents[to_p].aq_items, agents[from_p].aq_items = [agents[from_p].aq_items, agents[to_p].aq_items] + return True - # print the results - if (subsid_list[key] < 0): - print(agents[i].name(), "gets", list(result.values())[i], "with subsidy of", subsid_list[key]*-1) - else: - print(agents[i].name(), "gets", list(result.values())[i], "with no subsidy") - i += 1 + except networkx.NetworkXNoCycle: + return False -allocate_items_with_Subsidy.logger = logger +def cal_Subsidy(agents: Dict[str, AdditiveAgent]): + """ + This function calculates the subsidy + + >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 6, "d": 11, "e": 3, "f": 6}, name="Alice") + >>> Alice.aq_items = [] + >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 5, "e": 3, "f": 6}, name="Bob") + >>> Bob.aq_items = [] + >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") + >>> Eve.aq_items = [] + >>> agents_dict = {x.name():x for x in [Alice,Bob,Eve]} + >>> cal_Subsidy(agents_dict) + subsidy of: Alice is 1 + + >>> Alice = AdditiveAgent({"a":3, "b":4, "c":6}, name="Alice") + >>> Alice.aq_items = [] + >>> Bob = AdditiveAgent({"a":4, "b":3, "c":1}, name="Bob") + >>> Bob.aq_items = [] + >>> Eve = AdditiveAgent({"a":4, "b":5, "c":1}, name="Eve") + >>> Eve.aq_items = [] + >>> agents_dict = {x.name():x for x in [Alice,Bob,Eve]} + >>> cal_Subsidy(agents_dict) # no subsidy -def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: """ - # This is help function that Remove the given items from the graph - >>> print(delete_items({"a":4, "b":10, "c":8, "d":7}, ["a","b","d"])) - {'a': 3, 'b': 9, 'c': 8, 'd': 6} + for i in agents.values(): + all_items = list(i.all_items()) + break - >>> print(delete_items({"a":9, "b":2, "c":4, "d":7, "e":10, "f":0}, ["b","c"])) - {'a': 9, 'b': 1, 'c': 3, 'd': 7, 'e': 10} + maximizes_allocation(agents, all_items) - >>> print(delete_items({"a":1, "b":2, "c":1}, ["a", "b", "c"])) - {'b': 1} - """ - for i in items_to_remove: - items[i] -= 1 - return {item:newSize for item,newSize in items.items() if newSize > 0} + # DiGraph — Directed graphs with self loops + # its stores nodes and edges with optional data, or attributes. + # DiGraphs hold directed edges. Self loops are allowed but multiple (parallel) edges are not. + envy_graph = networkx.DiGraph() + for i in agents.values(): + envy_graph.add_node(i.name()) + i_value = i.value(i.aq_items) # values of items of agent "i" from his eyes + for k in agents.values(): + if i is k: + continue + k_value = i.value(k.aq_items) # values of items of agent "k" from eyes of agent "i" + if k_value > i_value and check_positive_weight_directed_cycles(create_Envy_Graph(agents), agents) == False: + envy_graph.add_edge(i.name(), k.name()) + print("subsidy of: ",i.name(), "is", k_value-i_value) + #### MAIN @@ -278,4 +290,15 @@ def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: # agents4 = AgentList({"Alice": {"a":10, "b":8, "c":5, "d":9, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":1}}) # agents5 = AgentList({"Alice": {"a":3, "b":4, "c":6}, "Bob": {"a":4, "b":3, "c":1}, "Max": {"a":4, "b":5, "c":1}}) # allocate_items_with_Subsidy(agents5) + + # Alice = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Alice") + # Alice.aq_items = [] + # Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Bob") + # Bob.aq_items = [] + # Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") + # Eve.aq_items = [] + + # agents_dict = {x.name():x for x in [Alice,Bob,Eve]} + + From 5af69219afb619822445b5b10dba366f9dbf3801 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Thu, 12 Jan 2023 10:26:48 +0200 Subject: [PATCH 09/23] Update Bounded_Subsidy_Algorithem.py --- fairpy/items/Bounded_Subsidy_Algorithem.py | 175 ++++++++++++++++----- 1 file changed, 137 insertions(+), 38 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index 1f3df1dd..f1d2a3c3 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -14,16 +14,17 @@ import sys import doctest from typing import * + from fairpy import AgentList from fairpy.items.utilitarian_matching import instance_to_graph, matching_to_allocation -from fairpy import AdditiveAgent +from fairpy.agents import Agent, AdditiveAgent import numpy as np import logging logger = logging.getLogger(__name__) - +##### algorithm 1 ##### def Bounded_Subsidy(agents: AgentList, items: Dict[str,int]=None, weights: Dict[str, int]=None): """ The algorithm getting a list of agents, list of goods and array of the weights of the goods @@ -132,32 +133,57 @@ def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: ##### algorithm 2 ##### -def maximizes_allocation(agents: Dict[str,AgentList], item_list: List[ItemsView]): - +def maximizes_allocation(agents: Dict[str,Agent], item_list: List[Any]): """ # Allocate each agent with his highest item that has not been allocated. + ##### test 1 ##### + >>> Alice = AdditiveAgent({"a": 1, "b": 5, "c": 3}, name="Alice") + >>> Alice.aq_items = [] + >>> Bob = AdditiveAgent({"a": 1, "b": 3, "c": 2}, name="Bob") + >>> Bob.aq_items = [] + >>> Eve = AdditiveAgent({"a": 3, "b": 2, "c": 1}, name="Eve") + >>> Eve.aq_items = [] + >>> agents = {x.name():x for x in [Alice,Bob,Eve]} + >>> items_list = list('abc') + >>> maximizes_allocation(agents,items_list) + >>> [(x.name(),sorted(x.aq_items)) for x in agents.values()] + [('Alice', ['b']), ('Bob', ['c']), ('Eve', ['a'])] + + ##### test 2 ##### + >>> Alice = AdditiveAgent({"a": 1, "b": 5, "c": 3, "d":2}, name="Alice") + >>> Alice.aq_items = [] + >>> Bob = AdditiveAgent({"a": 2, "b": 3, "c": 3, "d":1}, name="Bob") + >>> Bob.aq_items = [] + >>> agents = {x.name():x for x in [Alice,Bob]} + >>> items_list = list('abcd') + >>> maximizes_allocation(agents,items_list) + >>> [(x.name(),sorted(x.aq_items)) for x in agents.values()] + [('Alice', ['b', 'd']), ('Bob', ['a', 'c'])] + + ##### test 3 ##### >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Alice") >>> Alice.aq_items = [] - >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Bob") + >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Bob") >>> Bob.aq_items = [] - >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") + >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") >>> Eve.aq_items = [] - >>> agents_dict = {x.name():x for x in [Alice,Bob,Eve]} - >>> items_remaining = list('abcdef') - >>> maximizes_allocation(agents_dict,items_remaining) - >>> [(x.name(),sorted(x.aq_items)) for x in agents_dict.values()] + >>> agents = {x.name():x for x in [Alice,Bob,Eve]} + >>> items_list = list('abcdef') + >>> maximizes_allocation(agents,items_list) + >>> [(x.name(),sorted(x.aq_items)) for x in agents.values()] [('Alice', ['d', 'e']), ('Bob', ['a', 'f']), ('Eve', ['b', 'c'])] """ + agents_items = list(agents.items()) while len(item_list) > 0: - for k, i in (agents_items): - max_item = max([x for x in i.valuation.desired_items if x[0] in item_list], key=lambda x: i.value(x)) + for name, val in (agents_items): + max_item = max([x for x in val.valuation.desired_items if x[0] in item_list], key=lambda x: val.value(x)) item_list.remove(max_item) - i.aq_items.append(max_item) + val.aq_items.append(max_item) agents_items.reverse() @@ -167,19 +193,43 @@ def create_Envy_Graph(agents: Dict[str, AdditiveAgent]) -> networkx.DiGraph: for every two nodes representing agent u and v, there will be an edge from u to v if agent u believes agent vs bundle is worth more then his. + ##### test 1 ##### + >>> Alice = AdditiveAgent({"a": 5}, name="Alice") + >>> Alice.aq_items = ['a'] + >>> Bob = AdditiveAgent({"a":4}, name="Bob") + >>> Bob.aq_items = [] + >>> agents = {x.name():x for x in [Alice,Bob]} + >>> list(create_Envy_Graph(agents).nodes) + ['Alice', 'Bob'] + >>> list(create_Envy_Graph(agents).edges) + [('Bob', 'Alice')] + + ##### test 2 ##### + >>> Alice = AdditiveAgent({"a": 1, "b": 5, "c": 3}, name="Alice") + >>> Alice.aq_items = ['b'] + >>> Bob = AdditiveAgent({"a": 1, "b": 3, "c": 2}, name="Bob") + >>> Bob.aq_items = ['c'] + >>> Eve = AdditiveAgent({"a": 3, "b": 2, "c": 1}, name="Eve") + >>> Eve.aq_items = ['a'] + >>> agents = {x.name():x for x in [Alice,Bob,Eve]} + >>> list(create_Envy_Graph(agents).nodes) + ['Alice', 'Bob', 'Eve'] + >>> list(create_Envy_Graph(agents).edges) + [('Bob', 'Alice')] + + ##### test 3 ##### >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Alice") >>> Alice.aq_items = ['d', 'e'] - >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Bob") + >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Bob") >>> Bob.aq_items = ['a', 'f'] - >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") + >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") >>> Eve.aq_items = ['b', 'c'] >>> agents = {x.name():x for x in [Alice,Bob,Eve]} - >>> list(create_Envy_Graph(agents).nodes) ['Alice', 'Bob', 'Eve'] - >>> list(create_Envy_Graph(agents).edges) [('Alice', 'Bob'), ('Alice', 'Eve')] + """ # DiGraph — Directed graphs with self loops @@ -202,6 +252,29 @@ def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph, agents: """ This function checks if its envy graph does not contain a positive-weight directed cycle + ##### test 1 ##### + >>> Alice = AdditiveAgent({"a": 5, "b": 3}, name="Alice") + >>> Alice.aq_items = ['b'] + >>> Bob = AdditiveAgent({"a": 3, "b": 5}, name="Bob") + >>> Bob.aq_items = ['a'] + >>> agents = {x.name():x for x in [Alice,Bob]} + >>> envy_graph = create_Envy_Graph(agents) + >>> check_positive_weight_directed_cycles(envy_graph, agents) + True + + ##### test 2 ##### + >>> Alice = AdditiveAgent({"a": 3, "b": 2, "c": 1}, name="Alice") + >>> Alice.aq_items = ['b'] + >>> Bob = AdditiveAgent({"a": 2, "b": 2, "c": 3}, name="Bob") + >>> Bob.aq_items = ['a'] + >>> Eve = AdditiveAgent({"a": 1, "b": 3, "c": 2}, name="Eve") + >>> Eve.aq_items = ['c'] + >>> agents = {x.name():x for x in [Alice,Bob,Eve]} + >>> envy_graph = create_Envy_Graph(agents) + >>> check_positive_weight_directed_cycles(envy_graph, agents) + True + + ##### test 3 ##### >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Alice") >>> Alice.aq_items = ['d', 'e'] >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Bob") @@ -209,7 +282,6 @@ def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph, agents: >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") >>> Eve.aq_items = ['b', 'c'] >>> agents = {x.name():x for x in [Alice,Bob,Eve]} - >>> envy_graph = create_Envy_Graph(agents) >>> check_positive_weight_directed_cycles(envy_graph, agents) False @@ -217,30 +289,39 @@ def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph, agents: """ try: - cycle = networkx.find_cycle(envy_graph, orientation="original") - for edge in cycle[:-1]: - to_p, from_p = edge[0], edge[1] - agents[to_p].aq_items, agents[from_p].aq_items = [agents[from_p].aq_items, agents[to_p].aq_items] + # The cycle is a list of edges indicating the cyclic path. Orientation of directed edges is controlled + networkx.find_cycle(envy_graph, orientation="original") return True except networkx.NetworkXNoCycle: return False -def cal_Subsidy(agents: Dict[str, AdditiveAgent]): +def Subsidy_calculation(agents: Dict[str, AdditiveAgent]): """ This function calculates the subsidy - >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 6, "d": 11, "e": 3, "f": 6}, name="Alice") + ##### tets 1 ##### + >>> Alice = AdditiveAgent({"a": 1, "b": 5}, name="Alice") >>> Alice.aq_items = [] - >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 5, "e": 3, "f": 6}, name="Bob") + >>> Bob = AdditiveAgent({"a": 2, "b": 3}, name="Bob") >>> Bob.aq_items = [] - >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") + >>> agents = {x.name():x for x in [Alice,Bob]} + >>> Subsidy_calculation(agents) + subsidy of: Bob is 1 + + ##### tets 2 ##### + >>> Alice = AdditiveAgent({"a": 1, "b": 5, "c": 3}, name="Alice") + >>> Alice.aq_items = [] + >>> Bob = AdditiveAgent({"a": 1, "b": 3, "c": 2}, name="Bob") + >>> Bob.aq_items = [] + >>> Eve = AdditiveAgent({"a": 3, "b": 2, "c": 1}, name="Eve") >>> Eve.aq_items = [] - >>> agents_dict = {x.name():x for x in [Alice,Bob,Eve]} - >>> cal_Subsidy(agents_dict) - subsidy of: Alice is 1 + >>> agents = {x.name():x for x in [Alice,Bob,Eve]} + >>> Subsidy_calculation(agents) + subsidy of: Bob is 1 + ##### test 3 ##### >>> Alice = AdditiveAgent({"a":3, "b":4, "c":6}, name="Alice") >>> Alice.aq_items = [] >>> Bob = AdditiveAgent({"a":4, "b":3, "c":1}, name="Bob") @@ -248,7 +329,18 @@ def cal_Subsidy(agents: Dict[str, AdditiveAgent]): >>> Eve = AdditiveAgent({"a":4, "b":5, "c":1}, name="Eve") >>> Eve.aq_items = [] >>> agents_dict = {x.name():x for x in [Alice,Bob,Eve]} - >>> cal_Subsidy(agents_dict) # no subsidy + >>> Subsidy_calculation(agents_dict) # no subsidy + + ##### test 4 ##### + >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 6, "d": 11, "e": 3, "f": 6}, name="Alice") + >>> Alice.aq_items = [] + >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 5, "e": 3, "f": 6}, name="Bob") + >>> Bob.aq_items = [] + >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") + >>> Eve.aq_items = [] + >>> agents_dict = {x.name():x for x in [Alice,Bob,Eve]} + >>> Subsidy_calculation(agents_dict) + subsidy of: Alice is 1 """ @@ -272,7 +364,7 @@ def cal_Subsidy(agents: Dict[str, AdditiveAgent]): k_value = i.value(k.aq_items) # values of items of agent "k" from eyes of agent "i" if k_value > i_value and check_positive_weight_directed_cycles(create_Envy_Graph(agents), agents) == False: envy_graph.add_edge(i.name(), k.name()) - print("subsidy of: ",i.name(), "is", k_value-i_value) + print("subsidy of:",i.name(), "is", k_value-i_value) @@ -291,13 +383,20 @@ def cal_Subsidy(agents: Dict[str, AdditiveAgent]): # agents5 = AgentList({"Alice": {"a":3, "b":4, "c":6}, "Bob": {"a":4, "b":3, "c":1}, "Max": {"a":4, "b":5, "c":1}}) # allocate_items_with_Subsidy(agents5) - # Alice = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Alice") - # Alice.aq_items = [] - # Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Bob") - # Bob.aq_items = [] - # Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") - # Eve.aq_items = [] - + Alice = AdditiveAgent({"a": 1, "b": 5, "c": 3}, name="Alice") + Alice.aq_items = [] + Bob = AdditiveAgent({"a": 1, "b": 3, "c": 2}, name="Bob") + Bob.aq_items = [] + Eve = AdditiveAgent({"a": 3, "b": 2, "c": 1}, name="Eve") + Eve.aq_items = [] + agents = {x.name():x for x in [Alice,Bob,Eve]} + items_list = list('abc') + # maximizes_allocation(agents,items_list) + # [(x.name(),sorted(x.aq_items)) for x in agents.values()] + # [('Alice', ['b']), ('Bob', ['c']), ('Eve', ['a'])] + + # for i in agents.values(): + # print(Alice.all_items()) # agents_dict = {x.name():x for x in [Alice,Bob,Eve]} From bb80d34002b89ac64f47dc7b3e4404a4441f4b12 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Thu, 12 Jan 2023 11:18:14 +0200 Subject: [PATCH 10/23] Update Bounded_Subsidy_Algorithem.py --- fairpy/items/Bounded_Subsidy_Algorithem.py | 39 +++++++--------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index f1d2a3c3..5048355b 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -9,7 +9,6 @@ #----------------------------------------------------- """ - import networkx import sys import doctest @@ -311,6 +310,15 @@ def Subsidy_calculation(agents: Dict[str, AdditiveAgent]): subsidy of: Bob is 1 ##### tets 2 ##### + >>> Alice = AdditiveAgent({"a": 2, "b": 1}, name="Alice") + >>> Alice.aq_items = [] + >>> Bob = AdditiveAgent({"a": 4, "b": 2}, name="Bob") + >>> Bob.aq_items = [] + >>> agents = {x.name():x for x in [Alice,Bob]} + >>> Subsidy_calculation(agents) + subsidy of: Bob is 2 + + ##### tets 3 ##### >>> Alice = AdditiveAgent({"a": 1, "b": 5, "c": 3}, name="Alice") >>> Alice.aq_items = [] >>> Bob = AdditiveAgent({"a": 1, "b": 3, "c": 2}, name="Bob") @@ -321,7 +329,7 @@ def Subsidy_calculation(agents: Dict[str, AdditiveAgent]): >>> Subsidy_calculation(agents) subsidy of: Bob is 1 - ##### test 3 ##### + ##### test 4 ##### >>> Alice = AdditiveAgent({"a":3, "b":4, "c":6}, name="Alice") >>> Alice.aq_items = [] >>> Bob = AdditiveAgent({"a":4, "b":3, "c":1}, name="Bob") @@ -331,7 +339,7 @@ def Subsidy_calculation(agents: Dict[str, AdditiveAgent]): >>> agents_dict = {x.name():x for x in [Alice,Bob,Eve]} >>> Subsidy_calculation(agents_dict) # no subsidy - ##### test 4 ##### + ##### test 5 ##### >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 6, "d": 11, "e": 3, "f": 6}, name="Alice") >>> Alice.aq_items = [] >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 5, "e": 3, "f": 6}, name="Bob") @@ -367,7 +375,6 @@ def Subsidy_calculation(agents: Dict[str, AdditiveAgent]): print("subsidy of:",i.name(), "is", k_value-i_value) - #### MAIN if __name__ == "__main__": @@ -376,28 +383,6 @@ def Subsidy_calculation(agents: Dict[str, AdditiveAgent]): # logger.setLevel(logging.INFO) (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) print("{} failures, {} tests".format(failures, tests)) - # agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) - # agents2 = AgentList({"Alice": {"a":3, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) - # agents3 = AgentList({"Alice": {"a":3, "b":2}, "Bob": {"a":4, "b":1}}) - # agents4 = AgentList({"Alice": {"a":10, "b":8, "c":5, "d":9, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":1}}) - # agents5 = AgentList({"Alice": {"a":3, "b":4, "c":6}, "Bob": {"a":4, "b":3, "c":1}, "Max": {"a":4, "b":5, "c":1}}) - # allocate_items_with_Subsidy(agents5) - - Alice = AdditiveAgent({"a": 1, "b": 5, "c": 3}, name="Alice") - Alice.aq_items = [] - Bob = AdditiveAgent({"a": 1, "b": 3, "c": 2}, name="Bob") - Bob.aq_items = [] - Eve = AdditiveAgent({"a": 3, "b": 2, "c": 1}, name="Eve") - Eve.aq_items = [] - agents = {x.name():x for x in [Alice,Bob,Eve]} - items_list = list('abc') - # maximizes_allocation(agents,items_list) - # [(x.name(),sorted(x.aq_items)) for x in agents.values()] - # [('Alice', ['b']), ('Bob', ['c']), ('Eve', ['a'])] - - # for i in agents.values(): - # print(Alice.all_items()) - - # agents_dict = {x.name():x for x in [Alice,Bob,Eve]} + From 8cc455a2bf98cd895ce1307767f8a31d62ccffdd Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Sun, 15 Jan 2023 18:43:21 +0200 Subject: [PATCH 11/23] Update Bounded_Subsidy_Algorithem.py --- fairpy/items/Bounded_Subsidy_Algorithem.py | 406 +++++++++++---------- 1 file changed, 210 insertions(+), 196 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index 5048355b..5bc8d231 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -19,6 +19,8 @@ from fairpy.agents import Agent, AdditiveAgent import numpy as np +import matplotlib.pyplot as plt + import logging logger = logging.getLogger(__name__) @@ -64,7 +66,7 @@ def Bounded_Subsidy(agents: AgentList, items: Dict[str,int]=None, weights: Dict[ >>> print(Bounded_Subsidy(agents3)) {'Agent #0': [0, 1], 'Agent #1': [3, 2]} - >>> agents4 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) + >>> agents4 = AgentList({"Alice": {"a":3, "b":6}, "Bob": {"a":5, "b":7}}) >>> print(Bounded_Subsidy(agents4)) {'Alice': ['b'], 'Bob': ['a']} @@ -76,6 +78,10 @@ def Bounded_Subsidy(agents: AgentList, items: Dict[str,int]=None, weights: Dict[ >>> print(Bounded_Subsidy(agents6)) {'Agent #0': [1], 'Agent #1': [0]} + >>> agents7 = AgentList({"Alice": {"a":5, "b":5}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + >>> print(Bounded_Subsidy(agents7)) + {'Alice': ['a'], 'Bob': ['b'], 'Max': [], 'Nancy': []} + """ allTheItems = agents[0].all_items() # list of all items if items is None: @@ -98,7 +104,7 @@ def Bounded_Subsidy(agents: AgentList, items: Dict[str,int]=None, weights: Dict[ for agent_name,item_name in agentsBundle.items(): result[agent_name] += item_name # print(agent_name, item_name) - # print(result) + # print(result) # The items that allocated to the agents in this round allocated_items = sum([item for item in agentsBundle.values()], []) # print(allocated_items) @@ -129,132 +135,175 @@ def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: return {item:newSize for item,newSize in items.items() if newSize > 0} - ##### algorithm 2 ##### -def maximizes_allocation(agents: Dict[str,Agent], item_list: List[Any]): - +def create_Envy_Graph(agents: AgentList)->networkx.DiGraph(): """ - - # Allocate each agent with his highest item that has not been allocated. - - ##### test 1 ##### - >>> Alice = AdditiveAgent({"a": 1, "b": 5, "c": 3}, name="Alice") - >>> Alice.aq_items = [] - >>> Bob = AdditiveAgent({"a": 1, "b": 3, "c": 2}, name="Bob") - >>> Bob.aq_items = [] - >>> Eve = AdditiveAgent({"a": 3, "b": 2, "c": 1}, name="Eve") - >>> Eve.aq_items = [] - >>> agents = {x.name():x for x in [Alice,Bob,Eve]} - >>> items_list = list('abc') - >>> maximizes_allocation(agents,items_list) - >>> [(x.name(),sorted(x.aq_items)) for x in agents.values()] - [('Alice', ['b']), ('Bob', ['c']), ('Eve', ['a'])] - - ##### test 2 ##### - >>> Alice = AdditiveAgent({"a": 1, "b": 5, "c": 3, "d":2}, name="Alice") - >>> Alice.aq_items = [] - >>> Bob = AdditiveAgent({"a": 2, "b": 3, "c": 3, "d":1}, name="Bob") - >>> Bob.aq_items = [] - >>> agents = {x.name():x for x in [Alice,Bob]} - >>> items_list = list('abcd') - >>> maximizes_allocation(agents,items_list) - >>> [(x.name(),sorted(x.aq_items)) for x in agents.values()] - [('Alice', ['b', 'd']), ('Bob', ['a', 'c'])] + The algorithm getting a list of agents, list of goods and array of the weights of the goods + and it returns a bundle of agents each holding the best allocation for their own valuation, + with the subsidy that eliminates envy + + ###### Two agens, one items ###### + >>> agents0 = AgentList({"Alice": {"a":5}, "Bob": {"a":4}}) + >>> allocate_items_with_Subsidy(agents0) + Alice gets ['a'] with no subsidy + Bob gets [] with subsidy of 4 + + ###### Two agens, Two items ###### + >>> agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) + >>> allocate_items_with_Subsidy(agents1) + Alice gets ['b'] with no subsidy + Bob gets ['a'] with subsidy of 1 + + >>> agents2 = AgentList({"Alice": {"a":3, "b":2}, "Bob": {"a":4, "b":1}}) + >>> allocate_items_with_Subsidy(agents2) + Alice gets ['b'] with subsidy of 1 + Bob gets ['a'] with no subsidy + + >>> agents3 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) + >>> allocate_items_with_Subsidy(agents3) + Alice gets ['b', 'c'] with no subsidy + Bob gets ['d', 'a'] with no subsidy + + >>> agents4 = AgentList({"Alice": {"a":10, "b":8, "c":5, "d":9, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":1}}) + >>> allocate_items_with_Subsidy(agents4) + Alice gets ['a', 'b', 'c'] with no subsidy + Bob gets ['e', 'd', 'f'] with no subsidy + + ###### Three agents, Three items ###### + + >>> agents5 = AgentList({"Alice": {"a":3, "b":4, "c":6}, "Bob": {"a":4, "b":3, "c":1}, "Max": {"a":4, "b":5, "c":1}}) + >>> allocate_items_with_Subsidy(agents5) + Alice gets ['c'] with subsidy of 1 + Bob gets ['a'] with no subsidy + Max gets ['b'] with no subsidy + + >>> agents6 = AgentList({"Alice": {"a":1, "b":2, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) + >>> allocate_items_with_Subsidy(agents6) + Alice gets ['c'] with no subsidy + Bob gets ['b'] with no subsidy + Max gets ['a'] with no subsidy + + >>> agents7 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) + >>> allocate_items_with_Subsidy(agents7) + Alice gets ['b'] with no subsidy + Bob gets ['c'] with subsidy of 2 + Max gets ['a'] with no subsidy + + ###### Four agents ###### + # >>> agents8 = AgentList({"Alice": {"a":5, "b":5}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + # >>> allocate_items_with_Subsidy(agents8) + # Alice gets ['a'] with no subsidy + # Bob gets ['b'] with no subsidy + # Max gets [] with subsidy of 2 + # Nancy gets [] with subsidy of 2 + + # >>> agents9 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) - ##### test 3 ##### - >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Alice") - >>> Alice.aq_items = [] - >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Bob") - >>> Bob.aq_items = [] - >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") - >>> Eve.aq_items = [] - >>> agents = {x.name():x for x in [Alice,Bob,Eve]} - >>> items_list = list('abcdef') - >>> maximizes_allocation(agents,items_list) - >>> [(x.name(),sorted(x.aq_items)) for x in agents.values()] - [('Alice', ['d', 'e']), ('Bob', ['a', 'f']), ('Eve', ['b', 'c'])] - """ - agents_items = list(agents.items()) - while len(item_list) > 0: - for name, val in (agents_items): - max_item = max([x for x in val.valuation.desired_items if x[0] in item_list], key=lambda x: val.value(x)) - item_list.remove(max_item) - val.aq_items.append(max_item) - agents_items.reverse() + # list of all items + allTheItems = list(agents[0].all_items()) + + # maximum matching for all the agents + maximum_matching = Bounded_Subsidy(agents) + + # calculate the values of the items that allocate to the agent + agent_names = list(maximum_matching.keys()) # agent names + agent_items_allocated = list(maximum_matching.values()) # The items that allocated for the agent + items_values_for_agent = {} # Dict of the values of the items that allocate to the agent + + # indexes for the loops + i,j = 0,0 + while i < len(agent_names): + item_value = 0 + j = 0 + while j < len(allTheItems): + name = agent_names[i] + if allTheItems[j] in agent_items_allocated[i]: + item_value += agents[i].value(allTheItems[j]) + j += 1 + items_values_for_agent[name] = item_value + i += 1 + + # calculate the values of the edges in the Envy Graph + list_to_create_Envy_Graph = [] # list of values of the edges in the Envy Graph + list_of_subsidy_value = {} # list of subsidy value + + # index for the loop + k = 0 + while k < len(agent_names): + i = 0 + while i < len(items_values_for_agent): + subsidy_value = 0 + j = 0 + while j < len(allTheItems): + name = agent_names[i] + if allTheItems[j] in agent_items_allocated[i]: + subsidy_value += agents[k].value(allTheItems[j]) + j += 1 + list_of_subsidy_value[name] = subsidy_value - list(items_values_for_agent.values())[k] + i += 1 + list_to_create_Envy_Graph.append(list_of_subsidy_value.copy()) + k += 1 + + # create an empty graph + envy_graph = networkx.DiGraph() # DiGraph — Directed graphs with self loops + + # create nodes of the Envy Graph + for name_node in agent_names: + envy_graph.add_node(name_node) + + # create edges to the nodes in the Envy Graph + i=0 + while i < len(agent_names): + j=0 + while j < len(list_to_create_Envy_Graph): + node1 = agent_names[i] + node2 = list(list_to_create_Envy_Graph[i].keys())[j] + if node1 is node2: + j += 1 + continue + envy_graph.add_edge(agent_names[i], list(list_to_create_Envy_Graph[i].keys())[j], weight=list(list_to_create_Envy_Graph[i].values())[j]) + j += 1 + i += 1 + + # Envy Graph show + # # positions for all nodes - seed for reproducibility + # pos = networkx.spring_layout(envy_graph, seed=1) + # # nodes + # networkx.draw_networkx_nodes(envy_graph, pos, node_size=500) -def create_Envy_Graph(agents: Dict[str, AdditiveAgent]) -> networkx.DiGraph: - """ - This function creates an Envy Graph of agents, and maximizes the allocation - for every two nodes representing agent u and v, - there will be an edge from u to v if agent u believes agent vs bundle is worth more then his. + # # edges + # networkx.draw_networkx_edges(envy_graph, pos, connectionstyle="arc3,rad=-0.3") + # networkx.draw_networkx_edges(envy_graph, pos, alpha=0.5, edge_color="b", style="dashed") - ##### test 1 ##### - >>> Alice = AdditiveAgent({"a": 5}, name="Alice") - >>> Alice.aq_items = ['a'] - >>> Bob = AdditiveAgent({"a":4}, name="Bob") - >>> Bob.aq_items = [] - >>> agents = {x.name():x for x in [Alice,Bob]} - >>> list(create_Envy_Graph(agents).nodes) - ['Alice', 'Bob'] - >>> list(create_Envy_Graph(agents).edges) - [('Bob', 'Alice')] + # # node labels + # networkx.draw_networkx_labels(envy_graph, pos, font_size=10, font_family="sans-serif") - ##### test 2 ##### - >>> Alice = AdditiveAgent({"a": 1, "b": 5, "c": 3}, name="Alice") - >>> Alice.aq_items = ['b'] - >>> Bob = AdditiveAgent({"a": 1, "b": 3, "c": 2}, name="Bob") - >>> Bob.aq_items = ['c'] - >>> Eve = AdditiveAgent({"a": 3, "b": 2, "c": 1}, name="Eve") - >>> Eve.aq_items = ['a'] - >>> agents = {x.name():x for x in [Alice,Bob,Eve]} - >>> list(create_Envy_Graph(agents).nodes) - ['Alice', 'Bob', 'Eve'] - >>> list(create_Envy_Graph(agents).edges) - [('Bob', 'Alice')] + # # edge weight labels + # edge_labels = networkx.get_edge_attributes(envy_graph, "weight") + # networkx.draw_networkx_edge_labels(envy_graph, pos, edge_labels) - ##### test 3 ##### - >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Alice") - >>> Alice.aq_items = ['d', 'e'] - >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Bob") - >>> Bob.aq_items = ['a', 'f'] - >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") - >>> Eve.aq_items = ['b', 'c'] - >>> agents = {x.name():x for x in [Alice,Bob,Eve]} - >>> list(create_Envy_Graph(agents).nodes) - ['Alice', 'Bob', 'Eve'] - >>> list(create_Envy_Graph(agents).edges) - [('Alice', 'Bob'), ('Alice', 'Eve')] + # ax = plt.gca() + # ax.margins(0.08) + # plt.axis("off") + # plt.tight_layout() + # plt.show() - """ - - # DiGraph — Directed graphs with self loops - # its stores nodes and edges with optional data, or attributes. - # DiGraphs hold directed edges. Self loops are allowed but multiple (parallel) edges are not. - envy_graph = networkx.DiGraph() - for i in agents.values(): - envy_graph.add_node(i.name()) - i_value = i.value(i.aq_items) # values of items of agent "i" from his eyes - for k in agents.values(): - if i is k: - continue - k_value = i.value(k.aq_items) # values of items of agent "k" from eyes of agent "i" - if k_value > i_value: - envy_graph.add_edge(i.name(), k.name()) return envy_graph +create_Envy_Graph.logger = logger -def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph, agents: Dict[str, AdditiveAgent]) -> bool: +def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph)->bool: """ This function checks if its envy graph does not contain a positive-weight directed cycle ##### test 1 ##### >>> Alice = AdditiveAgent({"a": 5, "b": 3}, name="Alice") >>> Alice.aq_items = ['b'] - >>> Bob = AdditiveAgent({"a": 3, "b": 5}, name="Bob") + >>> Bob = AdditiveAgent({"a": 4, "b": 1}, name="Bob") >>> Bob.aq_items = ['a'] >>> agents = {x.name():x for x in [Alice,Bob]} >>> envy_graph = create_Envy_Graph(agents) @@ -287,93 +336,46 @@ def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph, agents: """ - try: - # The cycle is a list of edges indicating the cyclic path. Orientation of directed edges is controlled - networkx.find_cycle(envy_graph, orientation="original") - return True - - except networkx.NetworkXNoCycle: - return False - - -def Subsidy_calculation(agents: Dict[str, AdditiveAgent]): - """ - This function calculates the subsidy - - ##### tets 1 ##### - >>> Alice = AdditiveAgent({"a": 1, "b": 5}, name="Alice") - >>> Alice.aq_items = [] - >>> Bob = AdditiveAgent({"a": 2, "b": 3}, name="Bob") - >>> Bob.aq_items = [] - >>> agents = {x.name():x for x in [Alice,Bob]} - >>> Subsidy_calculation(agents) - subsidy of: Bob is 1 - - ##### tets 2 ##### - >>> Alice = AdditiveAgent({"a": 2, "b": 1}, name="Alice") - >>> Alice.aq_items = [] - >>> Bob = AdditiveAgent({"a": 4, "b": 2}, name="Bob") - >>> Bob.aq_items = [] - >>> agents = {x.name():x for x in [Alice,Bob]} - >>> Subsidy_calculation(agents) - subsidy of: Bob is 2 - - ##### tets 3 ##### - >>> Alice = AdditiveAgent({"a": 1, "b": 5, "c": 3}, name="Alice") - >>> Alice.aq_items = [] - >>> Bob = AdditiveAgent({"a": 1, "b": 3, "c": 2}, name="Bob") - >>> Bob.aq_items = [] - >>> Eve = AdditiveAgent({"a": 3, "b": 2, "c": 1}, name="Eve") - >>> Eve.aq_items = [] - >>> agents = {x.name():x for x in [Alice,Bob,Eve]} - >>> Subsidy_calculation(agents) - subsidy of: Bob is 1 - - ##### test 4 ##### - >>> Alice = AdditiveAgent({"a":3, "b":4, "c":6}, name="Alice") - >>> Alice.aq_items = [] - >>> Bob = AdditiveAgent({"a":4, "b":3, "c":1}, name="Bob") - >>> Bob.aq_items = [] - >>> Eve = AdditiveAgent({"a":4, "b":5, "c":1}, name="Eve") - >>> Eve.aq_items = [] - >>> agents_dict = {x.name():x for x in [Alice,Bob,Eve]} - >>> Subsidy_calculation(agents_dict) # no subsidy - - ##### test 5 ##### - >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 6, "d": 11, "e": 3, "f": 6}, name="Alice") - >>> Alice.aq_items = [] - >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 5, "e": 3, "f": 6}, name="Bob") - >>> Bob.aq_items = [] - >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") - >>> Eve.aq_items = [] - >>> agents_dict = {x.name():x for x in [Alice,Bob,Eve]} - >>> Subsidy_calculation(agents_dict) - subsidy of: Alice is 1 - - """ - - for i in agents.values(): - all_items = list(i.all_items()) - break - - maximizes_allocation(agents, all_items) - - - # DiGraph — Directed graphs with self loops - # its stores nodes and edges with optional data, or attributes. - # DiGraphs hold directed edges. Self loops are allowed but multiple (parallel) edges are not. - envy_graph = networkx.DiGraph() - for i in agents.values(): - envy_graph.add_node(i.name()) - i_value = i.value(i.aq_items) # values of items of agent "i" from his eyes - for k in agents.values(): - if i is k: - continue - k_value = i.value(k.aq_items) # values of items of agent "k" from eyes of agent "i" - if k_value > i_value and check_positive_weight_directed_cycles(create_Envy_Graph(agents), agents) == False: - envy_graph.add_edge(i.name(), k.name()) - print("subsidy of:",i.name(), "is", k_value-i_value) - + nodes = envy_graph.nodes + edges = envy_graph.edges.data() + G = networkx.DiGraph() + G.add_nodes_from(nodes) + G.add_edges_from(edges) + + cycles = networkx.simple_cycles(G) + weights = networkx.get_edge_attributes(G, 'weight') + for cycle in cycles: + cycle.append(cycle[0]) + cycle_weight = sum([weights[(cycle[i-1], cycle[i])] for i in range(1, len(cycle))]) + print (cycle,cycle_weight) + if cycle_weight > 0: + return True + + return False + + +def cal_the_Subsidy(agents: AgentList): + + envy_graph = create_Envy_Graph(agents) + + if check_positive_weight_directed_cycles(envy_graph): + print("The graph has positive weight directed cycles") + return + + i=0 + flag = False + while i < len(envy_graph.edges.data()): + first_agent = list(envy_graph.edges.data())[i][0] + second_agent = list(envy_graph.edges.data())[i][1] + subside = list(list(envy_graph.edges.data())[i][2].values())[0] + if subside > 0: # יש קנאה + flag = True + print(first_agent, "is envious of", second_agent, "with a subsidy of:", subside) + i += 1 + + if flag == False: + print("There is no envy in this graph") + #### MAIN @@ -381,8 +383,20 @@ def Subsidy_calculation(agents: Dict[str, AdditiveAgent]): import sys # logger.addHandler(logging.StreamHandler(sys.stdout)) # logger.setLevel(logging.INFO) - (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) - print("{} failures, {} tests".format(failures, tests)) + # (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) + # print("{} failures, {} tests".format(failures, tests)) + + agents0 = AgentList({"Alice": {"a":5}, "Bob": {"a":4}}) + agents1 = AgentList({"Alice": {"a":3, "b":6}, "Bob": {"a":5, "b":7}}) + agents2 = AgentList({"Alice": {"a": 4, "b": 10, "c": 8, "d": 7}, "Bob": {"a": 5, "b": 9, "c": 5, "d": 10}}) + + agents7 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) + agents9 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + agents10 = AgentList({"Alice": {"a": 9, "b": 8, "c": 6, "d": 11, "e": 3, "f": 6}, "Bob": {"a": 9, "b": 8, "c": 6, "d": 11, "e": 3, "f": 6}, "Max": {"a": 9, "b": 8, "c": 6, "d": 11, "e": 3, "f": 6}}) + # a=create_Envy_Graph(agents10) + # cal_the_Subsidy(agents10) + # check_positive_weight_directed_cycles(a) + From 35608258f0061b7907111b376310ec5ee6bb98fb Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Sun, 15 Jan 2023 21:18:49 +0200 Subject: [PATCH 12/23] done, the algorithms working very well --- fairpy/items/Bounded_Subsidy_Algorithem.py | 286 +++++++++++++-------- 1 file changed, 177 insertions(+), 109 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index 5bc8d231..a4d8fe9f 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -115,7 +115,7 @@ def Bounded_Subsidy(agents: AgentList, items: Dict[str,int]=None, weights: Dict[ Bounded_Subsidy.logger = logger - +# helping function for algorithm 1 def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: """ # This is help function that Remove the given items from the graph @@ -136,69 +136,87 @@ def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: ##### algorithm 2 ##### - def create_Envy_Graph(agents: AgentList)->networkx.DiGraph(): """ - The algorithm getting a list of agents, list of goods and array of the weights of the goods - and it returns a bundle of agents each holding the best allocation for their own valuation, - with the subsidy that eliminates envy + The algorithm getting a Dict of agents, with Dict of goods and the weights of the goods + and it returns an Envy Graph with maximum matching allocated - ###### Two agens, one items ###### + ###### 2 agens, 1 items ###### >>> agents0 = AgentList({"Alice": {"a":5}, "Bob": {"a":4}}) - >>> allocate_items_with_Subsidy(agents0) - Alice gets ['a'] with no subsidy - Bob gets [] with subsidy of 4 - - ###### Two agens, Two items ###### + >>> print(Bounded_Subsidy(agents0)) + {'Alice': ['a'], 'Bob': []} + >>> print(create_Envy_Graph(agents0)) + DiGraph with 2 nodes and 2 edges + >>> print(create_Envy_Graph(agents0).nodes) + ['Alice', 'Bob'] + >>> print(create_Envy_Graph(agents0).edges.data()) + [('Alice', 'Bob', {'weight': -5}), ('Bob', 'Alice', {'weight': 4})] + + ###### 2 agens, 2 items ###### >>> agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) - >>> allocate_items_with_Subsidy(agents1) - Alice gets ['b'] with no subsidy - Bob gets ['a'] with subsidy of 1 - - >>> agents2 = AgentList({"Alice": {"a":3, "b":2}, "Bob": {"a":4, "b":1}}) - >>> allocate_items_with_Subsidy(agents2) - Alice gets ['b'] with subsidy of 1 - Bob gets ['a'] with no subsidy - - >>> agents3 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) - >>> allocate_items_with_Subsidy(agents3) - Alice gets ['b', 'c'] with no subsidy - Bob gets ['d', 'a'] with no subsidy - - >>> agents4 = AgentList({"Alice": {"a":10, "b":8, "c":5, "d":9, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":1}}) - >>> allocate_items_with_Subsidy(agents4) - Alice gets ['a', 'b', 'c'] with no subsidy - Bob gets ['e', 'd', 'f'] with no subsidy - - ###### Three agents, Three items ###### - - >>> agents5 = AgentList({"Alice": {"a":3, "b":4, "c":6}, "Bob": {"a":4, "b":3, "c":1}, "Max": {"a":4, "b":5, "c":1}}) - >>> allocate_items_with_Subsidy(agents5) - Alice gets ['c'] with subsidy of 1 - Bob gets ['a'] with no subsidy - Max gets ['b'] with no subsidy - - >>> agents6 = AgentList({"Alice": {"a":1, "b":2, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) - >>> allocate_items_with_Subsidy(agents6) - Alice gets ['c'] with no subsidy - Bob gets ['b'] with no subsidy - Max gets ['a'] with no subsidy - - >>> agents7 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) - >>> allocate_items_with_Subsidy(agents7) - Alice gets ['b'] with no subsidy - Bob gets ['c'] with subsidy of 2 - Max gets ['a'] with no subsidy - - ###### Four agents ###### - # >>> agents8 = AgentList({"Alice": {"a":5, "b":5}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) - # >>> allocate_items_with_Subsidy(agents8) - # Alice gets ['a'] with no subsidy - # Bob gets ['b'] with no subsidy - # Max gets [] with subsidy of 2 - # Nancy gets [] with subsidy of 2 - - # >>> agents9 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + >>> print(Bounded_Subsidy(agents1)) + {'Alice': ['b'], 'Bob': ['a']} + >>> print(create_Envy_Graph(agents1)) + DiGraph with 2 nodes and 2 edges + >>> print(create_Envy_Graph(agents1).nodes) + ['Alice', 'Bob'] + >>> print(create_Envy_Graph(agents1).edges.data()) + [('Alice', 'Bob', {'weight': -2}), ('Bob', 'Alice', {'weight': 1})] + + ###### 2 agens, 4 items ###### + >>> agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) + >>> print(Bounded_Subsidy(agents2)) + {'Alice': ['b', 'c'], 'Bob': ['d', 'a']} + >>> print(create_Envy_Graph(agents2)) + DiGraph with 2 nodes and 2 edges + >>> print(create_Envy_Graph(agents2).nodes) + ['Alice', 'Bob'] + >>> print(create_Envy_Graph(agents2).edges.data()) + [('Alice', 'Bob', {'weight': -7}), ('Bob', 'Alice', {'weight': -1})] + + ###### 2 agens, 6 items ###### + >>> agents3 = AgentList({"Alice": {"a":10, "b":8, "c":5, "d":9, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":1}}) + >>> print(Bounded_Subsidy(agents3)) + {'Alice': ['a', 'b', 'c'], 'Bob': ['e', 'd', 'f']} + >>> print(create_Envy_Graph(agents3)) + DiGraph with 2 nodes and 2 edges + >>> print(create_Envy_Graph(agents3).nodes) + ['Alice', 'Bob'] + >>> print(create_Envy_Graph(agents3).edges.data()) + [('Alice', 'Bob', {'weight': -11}), ('Bob', 'Alice', {'weight': -3})] + + ###### 3 agents, 3 items ###### + >>> agents4 = AgentList({"Alice": {"a":3, "b":4, "c":6}, "Bob": {"a":4, "b":3, "c":1}, "Max": {"a":4, "b":5, "c":1}}) + >>> print(Bounded_Subsidy(agents4)) + {'Alice': ['c'], 'Bob': ['a'], 'Max': ['b']} + >>> print(create_Envy_Graph(agents4)) + DiGraph with 3 nodes and 6 edges + >>> print(create_Envy_Graph(agents4).nodes) + ['Alice', 'Bob', 'Max'] + >>> print(create_Envy_Graph(agents4).edges.data()) + [('Alice', 'Bob', {'weight': -3}), ('Alice', 'Max', {'weight': -2}), ('Bob', 'Alice', {'weight': -3}), ('Bob', 'Max', {'weight': -1}), ('Max', 'Alice', {'weight': -4}), ('Max', 'Bob', {'weight': -1})] + + ###### 3 agents, 3 items ###### + >>> agents5 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) + >>> print(Bounded_Subsidy(agents5)) + {'Alice': ['b'], 'Bob': ['c'], 'Max': ['a']} + >>> print(create_Envy_Graph(agents5)) + DiGraph with 3 nodes and 6 edges + >>> print(create_Envy_Graph(agents5).nodes) + ['Alice', 'Bob', 'Max'] + >>> print(create_Envy_Graph(agents5).edges.data()) + [('Alice', 'Bob', {'weight': -2}), ('Alice', 'Max', {'weight': -4}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -1}), ('Max', 'Alice', {'weight': -1}), ('Max', 'Bob', {'weight': -2})] + + ###### 4 agents, 2 items ###### + >>> agents6 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + >>> print(Bounded_Subsidy(agents6)) + {'Alice': ['b'], 'Bob': ['a'], 'Max': [], 'Nancy': []} + >>> print(create_Envy_Graph(agents6)) + DiGraph with 4 nodes and 12 edges + >>> print(create_Envy_Graph(agents6).nodes) + ['Alice', 'Bob', 'Max', 'Nancy'] + >>> print(create_Envy_Graph(agents6).edges.data()) + [('Alice', 'Bob', {'weight': -1}), ('Alice', 'Max', {'weight': -6}), ('Alice', 'Nancy', {'weight': -6}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -3}), ('Bob', 'Nancy', {'weight': -3}), ('Max', 'Alice', {'weight': 2}), ('Max', 'Bob', {'weight': 2}), ('Max', 'Nancy', {'weight': 0}), ('Nancy', 'Alice', {'weight': 1}), ('Nancy', 'Bob', {'weight': 2}), ('Nancy', 'Max', {'weight': 0})] """ @@ -268,7 +286,7 @@ def create_Envy_Graph(agents: AgentList)->networkx.DiGraph(): j += 1 i += 1 - # Envy Graph show + # ########## show Envy Graph ########## # # positions for all nodes - seed for reproducibility # pos = networkx.spring_layout(envy_graph, seed=1) @@ -300,38 +318,46 @@ def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph)->bool: """ This function checks if its envy graph does not contain a positive-weight directed cycle - ##### test 1 ##### - >>> Alice = AdditiveAgent({"a": 5, "b": 3}, name="Alice") - >>> Alice.aq_items = ['b'] - >>> Bob = AdditiveAgent({"a": 4, "b": 1}, name="Bob") - >>> Bob.aq_items = ['a'] - >>> agents = {x.name():x for x in [Alice,Bob]} - >>> envy_graph = create_Envy_Graph(agents) - >>> check_positive_weight_directed_cycles(envy_graph, agents) - True - - ##### test 2 ##### - >>> Alice = AdditiveAgent({"a": 3, "b": 2, "c": 1}, name="Alice") - >>> Alice.aq_items = ['b'] - >>> Bob = AdditiveAgent({"a": 2, "b": 2, "c": 3}, name="Bob") - >>> Bob.aq_items = ['a'] - >>> Eve = AdditiveAgent({"a": 1, "b": 3, "c": 2}, name="Eve") - >>> Eve.aq_items = ['c'] - >>> agents = {x.name():x for x in [Alice,Bob,Eve]} - >>> envy_graph = create_Envy_Graph(agents) - >>> check_positive_weight_directed_cycles(envy_graph, agents) - True - - ##### test 3 ##### - >>> Alice = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Alice") - >>> Alice.aq_items = ['d', 'e'] - >>> Bob = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Bob") - >>> Bob.aq_items = ['a', 'f'] - >>> Eve = AdditiveAgent({"a": 9, "b": 8, "c": 7, "d": 11, "e": 3, "f": 6}, name="Eve") - >>> Eve.aq_items = ['b', 'c'] - >>> agents = {x.name():x for x in [Alice,Bob,Eve]} - >>> envy_graph = create_Envy_Graph(agents) - >>> check_positive_weight_directed_cycles(envy_graph, agents) + ###### 2 agens, 2 items ###### + >>> agents1 = AgentList({"Alice": {"a":5, "b":3}, "Bob": {"a":4, "b":1}}) + >>> print(Bounded_Subsidy(agents1)) + {'Alice': ['b'], 'Bob': ['a']} + >>> envy_graph = create_Envy_Graph(agents1) + >>> print(envy_graph) + DiGraph with 2 nodes and 2 edges + >>> print(envy_graph.nodes) + ['Alice', 'Bob'] + >>> print(envy_graph.edges.data()) + [('Alice', 'Bob', {'weight': 2}), ('Bob', 'Alice', {'weight': -3})] + >>> check_positive_weight_directed_cycles(envy_graph) + False + + ###### 3 agens, 3 items ###### + >>> agents2 = AgentList({"Alice": {"a": 3, "b": 2, "c": 1}, "Bob": {"a": 2, "b": 2, "c": 3}, "Max": {"a": 1, "b": 3, "c": 2}}) + >>> print(Bounded_Subsidy(agents2)) + {'Alice': ['a'], 'Bob': ['c'], 'Max': ['b']} + >>> envy_graph = create_Envy_Graph(agents2) + >>> print(envy_graph) + DiGraph with 3 nodes and 6 edges + >>> print(envy_graph.nodes) + ['Alice', 'Bob', 'Max'] + >>> print(envy_graph.edges.data()) + [('Alice', 'Bob', {'weight': -2}), ('Alice', 'Max', {'weight': -1}), ('Bob', 'Alice', {'weight': -1}), ('Bob', 'Max', {'weight': -1}), ('Max', 'Alice', {'weight': -2}), ('Max', 'Bob', {'weight': -1})] + >>> check_positive_weight_directed_cycles(envy_graph) + False + + ###### 4 agens, 2 items ###### + >>> agents3 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + >>> print(Bounded_Subsidy(agents3)) + {'Alice': ['b'], 'Bob': ['a'], 'Max': [], 'Nancy': []} + >>> envy_graph = create_Envy_Graph(agents3) + >>> print(envy_graph) + DiGraph with 4 nodes and 12 edges + >>> print(envy_graph.nodes) + ['Alice', 'Bob', 'Max', 'Nancy'] + >>> print(envy_graph.edges.data()) + [('Alice', 'Bob', {'weight': -1}), ('Alice', 'Max', {'weight': -6}), ('Alice', 'Nancy', {'weight': -6}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -3}), ('Bob', 'Nancy', {'weight': -3}), ('Max', 'Alice', {'weight': 2}), ('Max', 'Bob', {'weight': 2}), ('Max', 'Nancy', {'weight': 0}), ('Nancy', 'Alice', {'weight': 1}), ('Nancy', 'Bob', {'weight': 2}), ('Nancy', 'Max', {'weight': 0})] + >>> check_positive_weight_directed_cycles(envy_graph) False """ @@ -347,7 +373,7 @@ def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph)->bool: for cycle in cycles: cycle.append(cycle[0]) cycle_weight = sum([weights[(cycle[i-1], cycle[i])] for i in range(1, len(cycle))]) - print (cycle,cycle_weight) + # print (cycle,cycle_weight) if cycle_weight > 0: return True @@ -355,10 +381,63 @@ def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph)->bool: def cal_the_Subsidy(agents: AgentList): + """ + This function calculates the Subsidy of the agentes + ###### 2 agens, 1 items ###### + >>> agents0 = AgentList({"Alice": {"a":5}, "Bob": {"a":4}}) + >>> print(Bounded_Subsidy(agents0)) + {'Alice': ['a'], 'Bob': []} + >>> print(create_Envy_Graph(agents0).edges.data()) + [('Alice', 'Bob', {'weight': -5}), ('Bob', 'Alice', {'weight': 4})] + >>> cal_the_Subsidy(agents0) + Bob is envious of Alice with a subsidy of: 4 + + ###### 2 agens, 2 items ###### + >>> agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) + >>> print(Bounded_Subsidy(agents1)) + {'Alice': ['b'], 'Bob': ['a']} + >>> print(create_Envy_Graph(agents1).edges.data()) + [('Alice', 'Bob', {'weight': -2}), ('Bob', 'Alice', {'weight': 1})] + >>> cal_the_Subsidy(agents1) + Bob is envious of Alice with a subsidy of: 1 + + ###### 2 agens, 4 items ###### + >>> agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) + >>> print(Bounded_Subsidy(agents2)) + {'Alice': ['b', 'c'], 'Bob': ['d', 'a']} + >>> print(create_Envy_Graph(agents2).edges.data()) + [('Alice', 'Bob', {'weight': -7}), ('Bob', 'Alice', {'weight': -1})] + >>> cal_the_Subsidy(agents2) + There is no envy in this graph - envy_graph = create_Envy_Graph(agents) + + ###### 3 agents, 3 items ###### + >>> agents3 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) + >>> print(Bounded_Subsidy(agents3)) + {'Alice': ['b'], 'Bob': ['c'], 'Max': ['a']} + >>> print(create_Envy_Graph(agents3).edges.data()) + [('Alice', 'Bob', {'weight': -2}), ('Alice', 'Max', {'weight': -4}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -1}), ('Max', 'Alice', {'weight': -1}), ('Max', 'Bob', {'weight': -2})] + >>> cal_the_Subsidy(agents3) + Bob is envious of Alice with a subsidy of: 1 + + ###### 4 agents, 2 items ###### + >>> agents4 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + >>> print(Bounded_Subsidy(agents4)) + {'Alice': ['b'], 'Bob': ['a'], 'Max': [], 'Nancy': []} + >>> print(create_Envy_Graph(agents4).edges.data()) + [('Alice', 'Bob', {'weight': -1}), ('Alice', 'Max', {'weight': -6}), ('Alice', 'Nancy', {'weight': -6}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -3}), ('Bob', 'Nancy', {'weight': -3}), ('Max', 'Alice', {'weight': 2}), ('Max', 'Bob', {'weight': 2}), ('Max', 'Nancy', {'weight': 0}), ('Nancy', 'Alice', {'weight': 1}), ('Nancy', 'Bob', {'weight': 2}), ('Nancy', 'Max', {'weight': 0})] + >>> cal_the_Subsidy(agents4) + Bob is envious of Alice with a subsidy of: 1 + Max is envious of Alice with a subsidy of: 2 + Max is envious of Bob with a subsidy of: 2 + Nancy is envious of Alice with a subsidy of: 1 + Nancy is envious of Bob with a subsidy of: 2 + + """ + + envy_graph = create_Envy_Graph(agents) # create Envy Graph - if check_positive_weight_directed_cycles(envy_graph): + if check_positive_weight_directed_cycles(envy_graph): # if the graph have a positive cycles print("The graph has positive weight directed cycles") return @@ -375,7 +454,7 @@ def cal_the_Subsidy(agents: AgentList): if flag == False: print("There is no envy in this graph") - + #### MAIN @@ -383,20 +462,9 @@ def cal_the_Subsidy(agents: AgentList): import sys # logger.addHandler(logging.StreamHandler(sys.stdout)) # logger.setLevel(logging.INFO) - # (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) - # print("{} failures, {} tests".format(failures, tests)) - - agents0 = AgentList({"Alice": {"a":5}, "Bob": {"a":4}}) - agents1 = AgentList({"Alice": {"a":3, "b":6}, "Bob": {"a":5, "b":7}}) - agents2 = AgentList({"Alice": {"a": 4, "b": 10, "c": 8, "d": 7}, "Bob": {"a": 5, "b": 9, "c": 5, "d": 10}}) - - agents7 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) - agents9 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) - agents10 = AgentList({"Alice": {"a": 9, "b": 8, "c": 6, "d": 11, "e": 3, "f": 6}, "Bob": {"a": 9, "b": 8, "c": 6, "d": 11, "e": 3, "f": 6}, "Max": {"a": 9, "b": 8, "c": 6, "d": 11, "e": 3, "f": 6}}) + (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) + print("{} failures, {} tests".format(failures, tests)) - # a=create_Envy_Graph(agents10) - # cal_the_Subsidy(agents10) - # check_positive_weight_directed_cycles(a) From 19fb3daa8ec2d80020ce67e8c14da526002c5cbf Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Mon, 16 Jan 2023 10:24:30 +0200 Subject: [PATCH 13/23] Delete tests_bounded_subsidy.py --- fairpy/items/tests_bounded_subsidy.py | 40 --------------------------- 1 file changed, 40 deletions(-) delete mode 100644 fairpy/items/tests_bounded_subsidy.py diff --git a/fairpy/items/tests_bounded_subsidy.py b/fairpy/items/tests_bounded_subsidy.py deleted file mode 100644 index 30880264..00000000 --- a/fairpy/items/tests_bounded_subsidy.py +++ /dev/null @@ -1,40 +0,0 @@ -import unittest - -from items.Bounded_Subsidy import bounded_subsidy - - -class TestMain(unittest.TestCase): - - def test_goods(self): - """ - This test passes without implementation of Bounded Subsidy algorithem - """ - agents1 = ["Alice", "Bob"] - goods1 = ["a", "b", "c", "d", "e", "f", "g"] - weights1 = {agents1[0]: {"a": 2, "b": 6, "c": 3, "d":1,"e":4,"f":7,"g":12}, - agents1[1]: {"a": 3, "b": 5, "c": 4, "d":1,"e":2,"f":10,"g":15}} - - ans1 = bounded_subsidy(agents1, goods1, weights1) - self.assertEqual(ans1, {"Alice": ["b", "c"], "Bob": ["a", "d"]}) - - - agents2 = ["Alice", "Bob"] - goods2 = ["a", "b", "c", "d", "e", "f"] - weights2 = {agents2[0]: {"a":1, "b":0.8, "c":0.5, "d":1, "e":0.3, "f":0}, agents2[1]: {"a":0.9, "b":0.2, "c":0.4, "d":0.7, "e":1, "f":0}} - - ans2 = bounded_subsidy(agents2, goods2, weights2) - self.assertEqual(ans2, {"Alice": ["a", "b", "c"], "Bob": ["d", "e", "f"]}) - - - ### nothing to allocate - agents3 = ["Alice", "Bob"] - goods3 = [] - weights3 = {agents3[0]: {}, agents3[1]: {}} - - ans3 = bounded_subsidy(agents3, goods3, weights3) - self.assertEqual(ans3, {"Alice": [], "Bob": []}) - - - if __name__ == '__main__': - unittest.main() - From 938670eae6b8340a719be5d2004fcb5c507c9ca2 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Wed, 18 Jan 2023 04:03:51 +0200 Subject: [PATCH 14/23] done --- fairpy/items/Bounded_Subsidy_Algorithem.py | 314 +++++++++++++-------- 1 file changed, 192 insertions(+), 122 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index a4d8fe9f..b7d51516 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -136,7 +136,7 @@ def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: ##### algorithm 2 ##### -def create_Envy_Graph(agents: AgentList)->networkx.DiGraph(): +def create_Envy_Graph(agents: AgentList) -> networkx.DiGraph(): """ The algorithm getting a Dict of agents, with Dict of goods and the weights of the goods and it returns an Envy Graph with maximum matching allocated @@ -197,15 +197,15 @@ def create_Envy_Graph(agents: AgentList)->networkx.DiGraph(): [('Alice', 'Bob', {'weight': -3}), ('Alice', 'Max', {'weight': -2}), ('Bob', 'Alice', {'weight': -3}), ('Bob', 'Max', {'weight': -1}), ('Max', 'Alice', {'weight': -4}), ('Max', 'Bob', {'weight': -1})] ###### 3 agents, 3 items ###### - >>> agents5 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) + >>> agents5 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":2, "b":3, "c":2}, "Max": {"a":3, "b":4, "c":3}}) >>> print(Bounded_Subsidy(agents5)) - {'Alice': ['b'], 'Bob': ['c'], 'Max': ['a']} + {'Alice': ['b'], 'Bob': ['a'], 'Max': ['c']} >>> print(create_Envy_Graph(agents5)) DiGraph with 3 nodes and 6 edges >>> print(create_Envy_Graph(agents5).nodes) ['Alice', 'Bob', 'Max'] >>> print(create_Envy_Graph(agents5).edges.data()) - [('Alice', 'Bob', {'weight': -2}), ('Alice', 'Max', {'weight': -4}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -1}), ('Max', 'Alice', {'weight': -1}), ('Max', 'Bob', {'weight': -2})] + [('Alice', 'Bob', {'weight': -4}), ('Alice', 'Max', {'weight': -2}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': 0}), ('Max', 'Alice', {'weight': 1}), ('Max', 'Bob', {'weight': 0})] ###### 4 agents, 2 items ###### >>> agents6 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) @@ -218,52 +218,48 @@ def create_Envy_Graph(agents: AgentList)->networkx.DiGraph(): >>> print(create_Envy_Graph(agents6).edges.data()) [('Alice', 'Bob', {'weight': -1}), ('Alice', 'Max', {'weight': -6}), ('Alice', 'Nancy', {'weight': -6}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -3}), ('Bob', 'Nancy', {'weight': -3}), ('Max', 'Alice', {'weight': 2}), ('Max', 'Bob', {'weight': 2}), ('Max', 'Nancy', {'weight': 0}), ('Nancy', 'Alice', {'weight': 1}), ('Nancy', 'Bob', {'weight': 2}), ('Nancy', 'Max', {'weight': 0})] + ###### 5 agents, 3 items ###### + >>> agents7 = AgentList({"Alice": {"a":3, "b":5, "c":8}, "Bob": {"a":3, "b":10, "c":5}, "Max": {"a":1, "b":2, "c":10}, "Nancy": {"a":10, "b":10, "c":10}, "Eve": {"a":8, "b":7, "c":2}}) + >>> print(Bounded_Subsidy(agents7)) + {'Alice': [], 'Bob': ['b'], 'Max': ['c'], 'Nancy': ['a'], 'Eve': []} + >>> print(create_Envy_Graph(agents7)) + DiGraph with 5 nodes and 20 edges + >>> print(create_Envy_Graph(agents7).nodes) + ['Alice', 'Bob', 'Max', 'Nancy', 'Eve'] + >>> print(create_Envy_Graph(agents7).edges.data()) + [('Alice', 'Bob', {'weight': 5}), ('Alice', 'Max', {'weight': 8}), ('Alice', 'Nancy', {'weight': 3}), ('Alice', 'Eve', {'weight': 0}), ('Bob', 'Alice', {'weight': -10}), ('Bob', 'Max', {'weight': -5}), ('Bob', 'Nancy', {'weight': -7}), ('Bob', 'Eve', {'weight': -10}), ('Max', 'Alice', {'weight': -10}), ('Max', 'Bob', {'weight': -8}), ('Max', 'Nancy', {'weight': -9}), ('Max', 'Eve', {'weight': -10}), ('Nancy', 'Alice', {'weight': -10}), ('Nancy', 'Bob', {'weight': 0}), ('Nancy', 'Max', {'weight': 0}), ('Nancy', 'Eve', {'weight': -10}), ('Eve', 'Alice', {'weight': 0}), ('Eve', 'Bob', {'weight': 7}), ('Eve', 'Max', {'weight': 2}), ('Eve', 'Nancy', {'weight': 8})] """ - # list of all items - allTheItems = list(agents[0].all_items()) - # maximum matching for all the agents maximum_matching = Bounded_Subsidy(agents) - + + # agent names + agent_names = list(maximum_matching.keys()) + + # The items that allocated for the agent + agent_items_allocated = list(maximum_matching.values()) + + # Dict of the values of the items that allocate to the agent + agent_items_values_allocated = {} + # calculate the values of the items that allocate to the agent - agent_names = list(maximum_matching.keys()) # agent names - agent_items_allocated = list(maximum_matching.values()) # The items that allocated for the agent - items_values_for_agent = {} # Dict of the values of the items that allocate to the agent - - # indexes for the loops - i,j = 0,0 - while i < len(agent_names): - item_value = 0 - j = 0 - while j < len(allTheItems): - name = agent_names[i] - if allTheItems[j] in agent_items_allocated[i]: - item_value += agents[i].value(allTheItems[j]) - j += 1 - items_values_for_agent[name] = item_value + i = 0 + for name in agent_names: + agent_items_values_allocated[name] = agents[i].value(agent_items_allocated[i]) i += 1 + source_agent_edges_values = {} # Dict of Envy Graph edges values by source agent + list_of_all_the_edges = [] # list of values of the edges in the Envy Graph + # calculate the values of the edges in the Envy Graph - list_to_create_Envy_Graph = [] # list of values of the edges in the Envy Graph - list_of_subsidy_value = {} # list of subsidy value - - # index for the loop - k = 0 - while k < len(agent_names): - i = 0 - while i < len(items_values_for_agent): - subsidy_value = 0 - j = 0 - while j < len(allTheItems): - name = agent_names[i] - if allTheItems[j] in agent_items_allocated[i]: - subsidy_value += agents[k].value(allTheItems[j]) - j += 1 - list_of_subsidy_value[name] = subsidy_value - list(items_values_for_agent.values())[k] - i += 1 - list_to_create_Envy_Graph.append(list_of_subsidy_value.copy()) - k += 1 + i = 0 + for agent in agents: + k=0 + for name in agent_names: + source_agent_edges_values[name] = agents[i].value(agent_items_allocated[k]) - list(agent_items_values_allocated.values())[i] + k += 1 + list_of_all_the_edges.append(source_agent_edges_values.copy()) + i += 1 # create an empty graph envy_graph = networkx.DiGraph() # DiGraph — Directed graphs with self loops @@ -273,48 +269,22 @@ def create_Envy_Graph(agents: AgentList)->networkx.DiGraph(): envy_graph.add_node(name_node) # create edges to the nodes in the Envy Graph - i=0 - while i < len(agent_names): - j=0 - while j < len(list_to_create_Envy_Graph): - node1 = agent_names[i] - node2 = list(list_to_create_Envy_Graph[i].keys())[j] + i = 0 + for node1 in agent_names: + k = 0 + for node2 in list_of_all_the_edges[i]: if node1 is node2: - j += 1 + k += 1 continue - envy_graph.add_edge(agent_names[i], list(list_to_create_Envy_Graph[i].keys())[j], weight=list(list_to_create_Envy_Graph[i].values())[j]) - j += 1 + envy_graph.add_edge(node1, node2, weight=list(list_of_all_the_edges[i].values())[k]) + k += 1 i += 1 - - # ########## show Envy Graph ########## - # # positions for all nodes - seed for reproducibility - # pos = networkx.spring_layout(envy_graph, seed=1) - - # # nodes - # networkx.draw_networkx_nodes(envy_graph, pos, node_size=500) - - # # edges - # networkx.draw_networkx_edges(envy_graph, pos, connectionstyle="arc3,rad=-0.3") - # networkx.draw_networkx_edges(envy_graph, pos, alpha=0.5, edge_color="b", style="dashed") - - # # node labels - # networkx.draw_networkx_labels(envy_graph, pos, font_size=10, font_family="sans-serif") - - # # edge weight labels - # edge_labels = networkx.get_edge_attributes(envy_graph, "weight") - # networkx.draw_networkx_edge_labels(envy_graph, pos, edge_labels) - - # ax = plt.gca() - # ax.margins(0.08) - # plt.axis("off") - # plt.tight_layout() - # plt.show() return envy_graph create_Envy_Graph.logger = logger -def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph)->bool: +def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph) -> bool: """ This function checks if its envy graph does not contain a positive-weight directed cycle @@ -359,38 +329,56 @@ def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph)->bool: [('Alice', 'Bob', {'weight': -1}), ('Alice', 'Max', {'weight': -6}), ('Alice', 'Nancy', {'weight': -6}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -3}), ('Bob', 'Nancy', {'weight': -3}), ('Max', 'Alice', {'weight': 2}), ('Max', 'Bob', {'weight': 2}), ('Max', 'Nancy', {'weight': 0}), ('Nancy', 'Alice', {'weight': 1}), ('Nancy', 'Bob', {'weight': 2}), ('Nancy', 'Max', {'weight': 0})] >>> check_positive_weight_directed_cycles(envy_graph) False + + ###### 4 agents, 4 items ###### + >>> agents4 = AgentList({"Alice": {"a":4, "b":3, "c":2, "d":1}, "Bob": {"a":4, "b":3, "c":2, "d":1}, "Max": {"a":4, "b":3, "c":2, "d":1}, "Nancy": {"a":4, "b":3, "c":2, "d":1}}) + >>> print(Bounded_Subsidy(agents4)) + {'Alice': ['d'], 'Bob': ['c'], 'Max': ['b'], 'Nancy': ['a']} + >>> envy_graph = create_Envy_Graph(agents4) + >>> print(envy_graph) + DiGraph with 4 nodes and 12 edges + >>> print(envy_graph.nodes) + ['Alice', 'Bob', 'Max', 'Nancy'] + >>> print(envy_graph.edges.data()) + [('Alice', 'Bob', {'weight': 1}), ('Alice', 'Max', {'weight': 2}), ('Alice', 'Nancy', {'weight': 3}), ('Bob', 'Alice', {'weight': -1}), ('Bob', 'Max', {'weight': 1}), ('Bob', 'Nancy', {'weight': 2}), ('Max', 'Alice', {'weight': -2}), ('Max', 'Bob', {'weight': -1}), ('Max', 'Nancy', {'weight': 1}), ('Nancy', 'Alice', {'weight': -3}), ('Nancy', 'Bob', {'weight': -2}), ('Nancy', 'Max', {'weight': -1})] + >>> check_positive_weight_directed_cycles(envy_graph) + False """ - nodes = envy_graph.nodes - edges = envy_graph.edges.data() - G = networkx.DiGraph() - G.add_nodes_from(nodes) - G.add_edges_from(edges) + copy_envy_graph = envy_graph.copy() + nodes = copy_envy_graph.nodes # nodes + edges = copy_envy_graph.edges.data() # edges + + # multiply by -1 for all the edges + for edge in edges: + edge[2]['weight'] *= -1 + + G = networkx.DiGraph() # create an envy graph + G.add_nodes_from(nodes) # add nodes to the graph + G.add_edges_from(edges) # add edges to the graph - cycles = networkx.simple_cycles(G) - weights = networkx.get_edge_attributes(G, 'weight') - for cycle in cycles: - cycle.append(cycle[0]) - cycle_weight = sum([weights[(cycle[i-1], cycle[i])] for i in range(1, len(cycle))]) - # print (cycle,cycle_weight) - if cycle_weight > 0: - return True + try: + networkx.find_negative_cycle(G,list(nodes)[0]) + return True - return False + except networkx.exception.NetworkXError: + return False -def cal_the_Subsidy(agents: AgentList): +def cal_the_Subsidy(agents: AgentList) -> str: """ This function calculates the Subsidy of the agentes + ###### 2 agens, 1 items ###### >>> agents0 = AgentList({"Alice": {"a":5}, "Bob": {"a":4}}) >>> print(Bounded_Subsidy(agents0)) {'Alice': ['a'], 'Bob': []} >>> print(create_Envy_Graph(agents0).edges.data()) [('Alice', 'Bob', {'weight': -5}), ('Bob', 'Alice', {'weight': 4})] - >>> cal_the_Subsidy(agents0) - Bob is envious of Alice with a subsidy of: 4 + >>> print(cal_the_Subsidy(agents0)) + Alice gets ['a'] with No Subsudy + Bob gets [] and it is envious of Alice with Subsudy of: 4 ###### 2 agens, 2 items ###### >>> agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) @@ -398,8 +386,9 @@ def cal_the_Subsidy(agents: AgentList): {'Alice': ['b'], 'Bob': ['a']} >>> print(create_Envy_Graph(agents1).edges.data()) [('Alice', 'Bob', {'weight': -2}), ('Bob', 'Alice', {'weight': 1})] - >>> cal_the_Subsidy(agents1) - Bob is envious of Alice with a subsidy of: 1 + >>> print(cal_the_Subsidy(agents1)) + Alice gets ['b'] with No Subsudy + Bob gets ['a'] and it is envious of Alice with Subsudy of: 1 ###### 2 agens, 4 items ###### >>> agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) @@ -407,18 +396,20 @@ def cal_the_Subsidy(agents: AgentList): {'Alice': ['b', 'c'], 'Bob': ['d', 'a']} >>> print(create_Envy_Graph(agents2).edges.data()) [('Alice', 'Bob', {'weight': -7}), ('Bob', 'Alice', {'weight': -1})] - >>> cal_the_Subsidy(agents2) - There is no envy in this graph + >>> print(cal_the_Subsidy(agents2)) + Alice gets ['b', 'c'] with No Subsudy + Bob gets ['d', 'a'] with No Subsudy - ###### 3 agents, 3 items ###### >>> agents3 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) >>> print(Bounded_Subsidy(agents3)) {'Alice': ['b'], 'Bob': ['c'], 'Max': ['a']} >>> print(create_Envy_Graph(agents3).edges.data()) [('Alice', 'Bob', {'weight': -2}), ('Alice', 'Max', {'weight': -4}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -1}), ('Max', 'Alice', {'weight': -1}), ('Max', 'Bob', {'weight': -2})] - >>> cal_the_Subsidy(agents3) - Bob is envious of Alice with a subsidy of: 1 + >>> print(cal_the_Subsidy(agents3)) + Alice gets ['b'] with No Subsudy + Bob gets ['c'] and it is envious of Alice with Subsudy of: 1 + Max gets ['a'] with No Subsudy ###### 4 agents, 2 items ###### >>> agents4 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) @@ -426,34 +417,103 @@ def cal_the_Subsidy(agents: AgentList): {'Alice': ['b'], 'Bob': ['a'], 'Max': [], 'Nancy': []} >>> print(create_Envy_Graph(agents4).edges.data()) [('Alice', 'Bob', {'weight': -1}), ('Alice', 'Max', {'weight': -6}), ('Alice', 'Nancy', {'weight': -6}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -3}), ('Bob', 'Nancy', {'weight': -3}), ('Max', 'Alice', {'weight': 2}), ('Max', 'Bob', {'weight': 2}), ('Max', 'Nancy', {'weight': 0}), ('Nancy', 'Alice', {'weight': 1}), ('Nancy', 'Bob', {'weight': 2}), ('Nancy', 'Max', {'weight': 0})] - >>> cal_the_Subsidy(agents4) - Bob is envious of Alice with a subsidy of: 1 - Max is envious of Alice with a subsidy of: 2 - Max is envious of Bob with a subsidy of: 2 - Nancy is envious of Alice with a subsidy of: 1 - Nancy is envious of Bob with a subsidy of: 2 + >>> print(cal_the_Subsidy(agents4)) + Alice gets ['b'] with No Subsudy + Bob gets ['a'] and it is envious of Alice with Subsudy of: 1 + Max gets [] and it is envious of Bob with Subsudy of: 3 + Nancy gets [] and it is envious of Bob with Subsudy of: 3 + + ###### 4 agents, 4 items ###### + >>> agents5 = AgentList({"Alice": {"a":4, "b":3, "c":2, "d":1}, "Bob": {"a":4, "b":3, "c":2, "d":1}, "Max": {"a":4, "b":3, "c":2, "d":1}, "Nancy": {"a":4, "b":3, "c":2, "d":1}}) + >>> print(Bounded_Subsidy(agents5)) + {'Alice': ['d'], 'Bob': ['c'], 'Max': ['b'], 'Nancy': ['a']} + >>> print(create_Envy_Graph(agents5).edges.data()) + [('Alice', 'Bob', {'weight': 1}), ('Alice', 'Max', {'weight': 2}), ('Alice', 'Nancy', {'weight': 3}), ('Bob', 'Alice', {'weight': -1}), ('Bob', 'Max', {'weight': 1}), ('Bob', 'Nancy', {'weight': 2}), ('Max', 'Alice', {'weight': -2}), ('Max', 'Bob', {'weight': -1}), ('Max', 'Nancy', {'weight': 1}), ('Nancy', 'Alice', {'weight': -3}), ('Nancy', 'Bob', {'weight': -2}), ('Nancy', 'Max', {'weight': -1})] + >>> print(cal_the_Subsidy(agents5)) + Alice gets ['d'] and it is envious of Bob with Subsudy of: 3 + Bob gets ['c'] and it is envious of Alice with Subsudy of: 2 + Max gets ['b'] and it is envious of Alice with Subsudy of: 1 + Nancy gets ['a'] with No Subsudy """ envy_graph = create_Envy_Graph(agents) # create Envy Graph + copy_envy_graph = envy_graph.copy() + nodes = copy_envy_graph.nodes # nodes + edges = copy_envy_graph.edges.data() # edges + result = "" if check_positive_weight_directed_cycles(envy_graph): # if the graph have a positive cycles - print("The graph has positive weight directed cycles") - return - - i=0 + result = "The graph has positive weight directed cycles" + return result + + result = "" # to print rhe resulte + num_of_edges_of_source_node = len(nodes) - 1 # The number of edges coming out of the source agent + + ############ calculate the Subsidy ############ + index=0 + stop_the_loop = 0 + max_edge_weight_of_source_node = 0 # The maximum edge weight of the source node + for stop_the_loop in range(len(edges)): + for source_node_edge in edges: + weight_edge = list(source_node_edge[2].values())[0] + if weight_edge > max_edge_weight_of_source_node: + max_edge_weight_of_source_node = weight_edge + index += 1 + stop_the_loop += 1 + + if index == num_of_edges_of_source_node: + if max_edge_weight_of_source_node > 0: # if there is an envy in the graph + for edge in edges: # Give the subsidy to the appropriate agents + if edge[0] is source_node_edge[0]: + edge[2]['weight'] -= max_edge_weight_of_source_node + + if edge[1] is source_node_edge[0]: + edge[2]['weight'] += max_edge_weight_of_source_node + max_edge_weight_of_source_node = 0 + stop_the_loop = 0 + index = 0 + break + else: + index = 0 + # print(edges) + + + ############ print the resultes ############ + maximum_matching = Bounded_Subsidy(agents) # gets the items that allocated to the agents + edges = envy_graph.edges.data() + copy_edges = copy_envy_graph.edges.data() + list_of_max_subsudy = [] + + for i in range(len(edges)): + list_of_max_subsudy.append(list(list(edges)[i][2].values())[0] - list(list(copy_edges)[i][2].values())[0]) + + max_subsudy = list_of_max_subsudy[0] + size = len(list_of_max_subsudy) + j = 0 flag = False - while i < len(envy_graph.edges.data()): - first_agent = list(envy_graph.edges.data())[i][0] - second_agent = list(envy_graph.edges.data())[i][1] - subside = list(list(envy_graph.edges.data())[i][2].values())[0] - if subside > 0: # יש קנאה + for i in range(size): + + if list_of_max_subsudy[i] > max_subsudy: + max_subsudy = list_of_max_subsudy[i] + + if list(list(copy_edges)[i][2].values())[0] == 0 and not flag: + node1 = list(copy_edges)[i][0] + node2 = list(copy_edges)[i][1] flag = True - print(first_agent, "is envious of", second_agent, "with a subsidy of:", subside) - i += 1 + + if ((i+1) % num_of_edges_of_source_node) == 0: + if max_subsudy > 0: + result += (str(node1) + " gets " + str(list(maximum_matching.values())[j]) + " and it is envious of " + str(node2) + " with Subsudy of: " + str(max_subsudy) + "\n") + flag = False + else: + result += (list(maximum_matching.keys())[j] + " gets " + str(list(maximum_matching.values())[j]) + " with No Subsudy" + "\n") + flag = False + max_subsudy = 0 + j += 1 + + return result - if flag == False: - print("There is no envy in this graph") #### MAIN @@ -465,6 +525,16 @@ def cal_the_Subsidy(agents: AgentList): (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) print("{} failures, {} tests".format(failures, tests)) - - - + # agents5 = AgentList({"Alice": {"a":3, "b":4, "c":3}, "Bob": {"a":1, "b":5, "c":3}, "Max": {"a":2, "b":3, "c":2}}) + # agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) + # agents1 = AgentList({"Alice": {"a":2, "b":1}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":5, "b":6}}) + # agents3 = AgentList({"Alice": {"a":6, "b":7}, "Bob": {"a":3, "b":5}}) + # agents6 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + # agents7 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":2, "b":3, "c":2}, "Max": {"a":3, "b":4, "c":3}}) + + # print(list(Bounded_Subsidy(agents6).values())) + # print(create_Envy_Graph(agents6).edges.data()) + # a=check_positive_weight_directed_cycles(G) + # print(a) + # print(cal_the_Subsidy(agents6)) + # check_envy_in_the_graph(create_Envy_Graph(agents1)) From 017ca100bf9c21d44e0d70370bc14cd12cd25057 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Wed, 18 Jan 2023 04:05:21 +0200 Subject: [PATCH 15/23] done tests --- tests/tests_bounded_subsidy.py | 136 +++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 tests/tests_bounded_subsidy.py diff --git a/tests/tests_bounded_subsidy.py b/tests/tests_bounded_subsidy.py new file mode 100644 index 00000000..500bfae3 --- /dev/null +++ b/tests/tests_bounded_subsidy.py @@ -0,0 +1,136 @@ +import unittest +from fairpy.items.Bounded_Subsidy_Algorithem import * +from fairpy.agentlist import AgentList +import random +import string + +class TestMain(unittest.TestCase): + + + def test_Bounded_Subsidy(self): + """ + Bounded Subsidy Algorithem tests + """ + + agents1 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) + ans1 = Bounded_Subsidy(agents1) + self.assertEqual(ans1, {"Alice": ["b", "c"], "Bob": ["d", "a"]}) + + agents2 = AgentList({"Alice": {"a":10, "b":8, "c":5, "d":9, "e":3, "f":0}, "Bob": {"a":9, "b":2, "c":4, "d":7, "e":10, "f":0}}) + ans2 = Bounded_Subsidy(agents2) + self.assertEqual(ans2, {'Alice': ['a', 'b', 'c'], 'Bob': ['e', 'd', 'f']}) + + agents3 = AgentList({"Alice": {"a":5, "b":5}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + ans3 = Bounded_Subsidy(agents3) + self.assertEqual(ans3, {'Alice': ['a'], 'Bob': ['b'], 'Max': [], 'Nancy': []}) + + ### nothing to allocate + agents4 = AgentList({"Alice": {}, "Bob": {}}) + ans4 = Bounded_Subsidy(agents4) + self.assertEqual(ans4, {"Alice": [], "Bob": []}) + + def test_create_Envy_Graph(self): + """ + tests for create_Envy_Graph function, that creates a Envy Graph + """ + + agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) + envy_graph1 = create_Envy_Graph(agents1) + self.assertEqual(list(envy_graph1.edges.data()), [('Alice', 'Bob', {'weight': -2}), ('Bob', 'Alice', {'weight': 1})]) + + agents2 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) + envy_graph2 = create_Envy_Graph(agents2) + self.assertEqual(list(envy_graph2.edges.data()), [('Alice', 'Bob', {'weight': -2}), ('Alice', 'Max', {'weight': -4}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -1}), ('Max', 'Alice', {'weight': -1}), ('Max', 'Bob', {'weight': -2})]) + + agents3 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + envy_graph3 = create_Envy_Graph(agents3) + self.assertEqual(list(envy_graph3.edges.data()), [('Alice', 'Bob', {'weight': -1}), ('Alice', 'Max', {'weight': -6}), ('Alice', 'Nancy', {'weight': -6}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -3}), ('Bob', 'Nancy', {'weight': -3}), ('Max', 'Alice', {'weight': 2}), ('Max', 'Bob', {'weight': 2}), ('Max', 'Nancy', {'weight': 0}), ('Nancy', 'Alice', {'weight': 1}), ('Nancy', 'Bob', {'weight': 2}), ('Nancy', 'Max', {'weight': 0})]) + + agents4 = AgentList({"Alice": {"a":3, "b":5, "c":8}, "Bob": {"a":3, "b":10, "c":5}, "Max": {"a":1, "b":2, "c":10}, "Nancy": {"a":10, "b":10, "c":10}, "Eve": {"a":8, "b":7, "c":2}}) + envy_graph4 = create_Envy_Graph(agents4) + self.assertEqual(list(envy_graph4.edges.data()), [('Alice', 'Bob', {'weight': 5}), ('Alice', 'Max', {'weight': 8}), ('Alice', 'Nancy', {'weight': 3}), ('Alice', 'Eve', {'weight': 0}), ('Bob', 'Alice', {'weight': -10}), ('Bob', 'Max', {'weight': -5}), ('Bob', 'Nancy', {'weight': -7}), ('Bob', 'Eve', {'weight': -10}), ('Max', 'Alice', {'weight': -10}), ('Max', 'Bob', {'weight': -8}), ('Max', 'Nancy', {'weight': -9}), ('Max', 'Eve', {'weight': -10}), ('Nancy', 'Alice', {'weight': -10}), ('Nancy', 'Bob', {'weight': 0}), ('Nancy', 'Max', {'weight': 0}), ('Nancy', 'Eve', {'weight': -10}), ('Eve', 'Alice', {'weight': 0}), ('Eve', 'Bob', {'weight': 7}), ('Eve', 'Max', {'weight': 2}), ('Eve', 'Nancy', {'weight': 8})]) + + def test_check_positive_weight_directed_cycles(self): + """ + tests for check_positive_weight_directed_cycles function, that checks if its envy graph does not contain a positive-weight directed cycle + """ + + agents1 = AgentList({"Alice": {"a":5, "b":3}, "Bob": {"a":4, "b":1}}) + envy_graph1 = create_Envy_Graph(agents1) + res = check_positive_weight_directed_cycles(envy_graph1) + self.assertEqual(res, False) + + agents2 = AgentList({"Alice": {"a": 3, "b": 2, "c": 1}, "Bob": {"a": 2, "b": 2, "c": 3}, "Max": {"a": 1, "b": 3, "c": 2}}) + envy_graph2 = create_Envy_Graph(agents2) + res = check_positive_weight_directed_cycles(envy_graph2) + self.assertEqual(res, False) + + agents3 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + envy_graph3 = create_Envy_Graph(agents3) + res = check_positive_weight_directed_cycles(envy_graph3) + self.assertEqual(res, False) + + agents4 = AgentList({"Alice": {"a":4, "b":3, "c":2, "d":1}, "Bob": {"a":4, "b":3, "c":2, "d":1}, "Max": {"a":4, "b":3, "c":2, "d":1}, "Nancy": {"a":4, "b":3, "c":2, "d":1}}) + envy_graph4 = create_Envy_Graph(agents4) + res = check_positive_weight_directed_cycles(envy_graph4) + self.assertEqual(res, False) + + + def test_cal_the_Subsidy(self): + """ + tests for cal_the_Subsidy function, that calculates the Subsidy of the agentes + """ + + agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) + res = "Alice gets ['b'] with No Subsudy" + "\n" + "Bob gets ['a'] and it is envious of Alice with Subsudy of: 1" + "\n" + self.assertEqual(cal_the_Subsidy(agents1), res) + + agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) + res = "Alice gets ['b', 'c'] with No Subsudy" + "\n" + "Bob gets ['d', 'a'] with No Subsudy" + "\n" + self.assertEqual(cal_the_Subsidy(agents2), res) + + agents3 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) + res = "Alice gets ['b'] with No Subsudy" + "\n" + "Bob gets ['c'] and it is envious of Alice with Subsudy of: 1" + "\n" + "Max gets ['a'] with No Subsudy" + "\n" + self.assertEqual(cal_the_Subsidy(agents3), res) + + agents4 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + res = "Alice gets ['b'] with No Subsudy" + "\n" + "Bob gets ['a'] and it is envious of Alice with Subsudy of: 1" + "\n" + "Max gets [] and it is envious of Bob with Subsudy of: 3" + "\n" + "Nancy gets [] and it is envious of Bob with Subsudy of: 3" + "\n" + self.assertEqual(cal_the_Subsidy(agents4), res) + + agents5 = AgentList({"Alice": {"a":4, "b":3, "c":2, "d":1}, "Bob": {"a":4, "b":3, "c":2, "d":1}, "Max": {"a":4, "b":3, "c":2, "d":1}, "Nancy": {"a":4, "b":3, "c":2, "d":1}}) + res = "Alice gets ['d'] and it is envious of Bob with Subsudy of: 3" + "\n" + "Bob gets ['c'] and it is envious of Alice with Subsudy of: 2" + "\n" + "Max gets ['b'] and it is envious of Alice with Subsudy of: 1" + "\n" + "Nancy gets ['a'] with No Subsudy" + "\n" + self.assertEqual(cal_the_Subsidy(agents5), res) + + ############ random number of agents and items ############ + random_item = random.choice(string.ascii_lowercase) + random_item_weight = random.randint(0, 9) + num_of_agents = random.randint(2, 9) + num_of_items = random.randint(1, 9) + + + # # create a list of random agents name + # list_of_agents = [] + # for i in range(num_of_agents): + # random_agent = random.choice(string.ascii_uppercase) + # if random_agent not in list_of_agents: + # list_of_agents.append(random_agent) + + + # # create a list of Dict of random items with values + # list_of_items = [] + # for i in range(num_of_items): + # random_item = random.choice(string.ascii_lowercase) + # random_item_weight = random.randint(0, 9) + # if random_item not in list_of_items: + # list_of_items.append(dict({random_item:random_item_weight})) + + + # print(list_of_agents) + # print(list_of_items) + + +def main(): + unittest.main() + +if __name__ == "__main__": + main() From 0407fb53727880f2bd5d12a209cbd842a1d86260 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Wed, 18 Jan 2023 04:13:25 +0200 Subject: [PATCH 16/23] Update Bounded_Subsidy_Algorithem.py --- fairpy/items/Bounded_Subsidy_Algorithem.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index b7d51516..b8de94f0 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -522,8 +522,8 @@ def cal_the_Subsidy(agents: AgentList) -> str: import sys # logger.addHandler(logging.StreamHandler(sys.stdout)) # logger.setLevel(logging.INFO) - (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) - print("{} failures, {} tests".format(failures, tests)) + # (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) + # print("{} failures, {} tests".format(failures, tests)) # agents5 = AgentList({"Alice": {"a":3, "b":4, "c":3}, "Bob": {"a":1, "b":5, "c":3}, "Max": {"a":2, "b":3, "c":2}}) # agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) From f9bc8b3ee7f4a21b0e401c09b2961aa9b9a7b5ce Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Wed, 18 Jan 2023 04:18:04 +0200 Subject: [PATCH 17/23] Delete Bounded_Subsidy.py --- fairpy/items/Bounded_Subsidy.py | 50 --------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 fairpy/items/Bounded_Subsidy.py diff --git a/fairpy/items/Bounded_Subsidy.py b/fairpy/items/Bounded_Subsidy.py deleted file mode 100644 index 6fa3a511..00000000 --- a/fairpy/items/Bounded_Subsidy.py +++ /dev/null @@ -1,50 +0,0 @@ - -from ast import Dict, List -from fairpy import AgentList -def bounded_subsidy(agents: List, goods: List, weights: Dict[str, int]): - """ - One Dollar Each Eliminates Envy - by Jack Dippel and Adrian Vetta (Preprint · December 2019) https://www.researchgate.net/publication/337781386_One_Dollar_Each_Eliminates_Envy - Programmer: Eyad Amer - - Algorithem bounded_subsidy: - The algorithm getting a list of agents, goods list and array of the weights of the goods - and it's returns a bundle of agents when each of the holds the best allocation to his valuation of the goods. - - - >>> agents1 = ["Alice", "Bob"] - >>> goods1 = ["a", "b", "c", "d"] - >>> weights1 = {agents[0]: ["a":0.4, "b":1, "c":0.8, "d":0.7], agents[1]: ["a":0.5, "b":0.9, "c":0.5, "d":1]} - >>> print(bounded_subsidy(agents: List, goods: List, weights: Dict[str, int])) - {"Alice": ["b", "c"], "Bob": ["a", "d"]} - - >>> agents1 - ["Alice", "Bob"] - >>> goods1 - ["a", "b", "c", "d"] - >>> weights1 - {agents[0]: ["a":0.4, "b":1, "c":0.8, "d":0.7], agents[1]: ["a":0.5, "b":0.9, "c":0.5, "d":1]} - - >>> agents2 = ["Alice", "Bob"] - >>> goods2 = ["a", "b", "c", "d", "e", "f"] - >>> weights2 = [agents[0]: {"a":1, "b":0.8, "c":0.5, "d":1, "e":0.3, "f":0], agents[1]: ["a":0.9, "b":0.2, "c":0.4, "d":0.7, "e":1, "f":0]} - >>> print(bounded_subsidy(agents: List, goods: List, weights: Dict[str, int])) - {"Alice": ["a", "b", "c"], "Bob": ["d", "e", "f"]} - - >>> agents2 - ["Alice", "Bob"] - >>> goods2 - ["a", "b", "c", "d", "e", "f"] - >>> weights2 - [agents[0]: {"a":1, "b":0.8, "c":0.5, "d":1, "e":0.3, "f":0], agents[1]: ["a":0.9, "b":0.2, "c":0.4, "d":0.7, "e":1, "f":0]} - - - """ - - return 0 - -# main function -if __name__ == "__main__": - import doctest - (failures,tests) = doctest.testmod(report=True) - print ("{} failures, {} tests".format(failures,tests)) \ No newline at end of file From fe65829a323849b62c9f30ba3cb6f77aa1c9e734 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Wed, 18 Jan 2023 04:22:20 +0200 Subject: [PATCH 18/23] Update Bounded_Subsidy_Algorithem.py --- fairpy/items/Bounded_Subsidy_Algorithem.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index b8de94f0..e3eed9ba 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -369,7 +369,7 @@ def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph) -> bool: def cal_the_Subsidy(agents: AgentList) -> str: """ This function calculates the Subsidy of the agentes - + ###### 2 agens, 1 items ###### >>> agents0 = AgentList({"Alice": {"a":5}, "Bob": {"a":4}}) >>> print(Bounded_Subsidy(agents0)) @@ -379,6 +379,7 @@ def cal_the_Subsidy(agents: AgentList) -> str: >>> print(cal_the_Subsidy(agents0)) Alice gets ['a'] with No Subsudy Bob gets [] and it is envious of Alice with Subsudy of: 4 + ###### 2 agens, 2 items ###### >>> agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) @@ -522,8 +523,8 @@ def cal_the_Subsidy(agents: AgentList) -> str: import sys # logger.addHandler(logging.StreamHandler(sys.stdout)) # logger.setLevel(logging.INFO) - # (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) - # print("{} failures, {} tests".format(failures, tests)) + (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) + print("{} failures, {} tests".format(failures, tests)) # agents5 = AgentList({"Alice": {"a":3, "b":4, "c":3}, "Bob": {"a":1, "b":5, "c":3}, "Max": {"a":2, "b":3, "c":2}}) # agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) From 8b7537d2e8be2969a73f54f21661da83a2f7bd39 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Wed, 18 Jan 2023 04:24:53 +0200 Subject: [PATCH 19/23] Update Bounded_Subsidy_Algorithem.py --- fairpy/items/Bounded_Subsidy_Algorithem.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index e3eed9ba..1a994b1b 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -390,6 +390,7 @@ def cal_the_Subsidy(agents: AgentList) -> str: >>> print(cal_the_Subsidy(agents1)) Alice gets ['b'] with No Subsudy Bob gets ['a'] and it is envious of Alice with Subsudy of: 1 + ###### 2 agens, 4 items ###### >>> agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) @@ -400,6 +401,7 @@ def cal_the_Subsidy(agents: AgentList) -> str: >>> print(cal_the_Subsidy(agents2)) Alice gets ['b', 'c'] with No Subsudy Bob gets ['d', 'a'] with No Subsudy + ###### 3 agents, 3 items ###### >>> agents3 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) @@ -411,6 +413,7 @@ def cal_the_Subsidy(agents: AgentList) -> str: Alice gets ['b'] with No Subsudy Bob gets ['c'] and it is envious of Alice with Subsudy of: 1 Max gets ['a'] with No Subsudy + ###### 4 agents, 2 items ###### >>> agents4 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) @@ -423,6 +426,7 @@ def cal_the_Subsidy(agents: AgentList) -> str: Bob gets ['a'] and it is envious of Alice with Subsudy of: 1 Max gets [] and it is envious of Bob with Subsudy of: 3 Nancy gets [] and it is envious of Bob with Subsudy of: 3 + ###### 4 agents, 4 items ###### >>> agents5 = AgentList({"Alice": {"a":4, "b":3, "c":2, "d":1}, "Bob": {"a":4, "b":3, "c":2, "d":1}, "Max": {"a":4, "b":3, "c":2, "d":1}, "Nancy": {"a":4, "b":3, "c":2, "d":1}}) @@ -435,6 +439,7 @@ def cal_the_Subsidy(agents: AgentList) -> str: Bob gets ['c'] and it is envious of Alice with Subsudy of: 2 Max gets ['b'] and it is envious of Alice with Subsudy of: 1 Nancy gets ['a'] with No Subsudy + """ From 5442ff2a2bd98cd2163163a7cc4fb01a9697f1d5 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Mon, 23 Jan 2023 00:24:09 +0200 Subject: [PATCH 20/23] final update --- fairpy/items/Bounded_Subsidy_Algorithem.py | 334 ++++++++------------- 1 file changed, 117 insertions(+), 217 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index 1a994b1b..9af445f3 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -9,7 +9,7 @@ #----------------------------------------------------- """ -import networkx +import networkx as nx import sys import doctest from typing import * @@ -83,6 +83,7 @@ def Bounded_Subsidy(agents: AgentList, items: Dict[str,int]=None, weights: Dict[ {'Alice': ['a'], 'Bob': ['b'], 'Max': [], 'Nancy': []} """ + assert isinstance(agents, AgentList) allTheItems = agents[0].all_items() # list of all items if items is None: items = {item:1 for item in allTheItems} @@ -95,7 +96,7 @@ def Bounded_Subsidy(agents: AgentList, items: Dict[str,int]=None, weights: Dict[ # print(H) logger.info("Graph edges: %s", list(H.edges.data())) # a maximum weight matching in H[I, Jt] - Mt = networkx.max_weight_matching(H, maxcardinality=False) # H חשב התאמה משוקללת מקסימלית של . + Mt = nx.max_weight_matching(H, maxcardinality=False) # H חשב התאמה משוקללת מקסימלית של . # print(Mt) logger.info("Matching: %s", Mt) # if agent i is matched to item j = µti then we allocate item µti to that agent @@ -136,7 +137,8 @@ def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: ##### algorithm 2 ##### -def create_Envy_Graph(agents: AgentList) -> networkx.DiGraph(): +def create_Envy_Graph(agents: AgentList) -> nx.DiGraph(): + """ The algorithm getting a Dict of agents, with Dict of goods and the weights of the goods and it returns an Envy Graph with maximum matching allocated @@ -231,142 +233,96 @@ def create_Envy_Graph(agents: AgentList) -> networkx.DiGraph(): """ # maximum matching for all the agents - maximum_matching = Bounded_Subsidy(agents) - - # agent names - agent_names = list(maximum_matching.keys()) + maximum_matching = Bounded_Subsidy(agents) # The items that allocated for the agent agent_items_allocated = list(maximum_matching.values()) - # Dict of the values of the items that allocate to the agent - agent_items_values_allocated = {} - - # calculate the values of the items that allocate to the agent - i = 0 - for name in agent_names: - agent_items_values_allocated[name] = agents[i].value(agent_items_allocated[i]) - i += 1 - - source_agent_edges_values = {} # Dict of Envy Graph edges values by source agent - list_of_all_the_edges = [] # list of values of the edges in the Envy Graph - - # calculate the values of the edges in the Envy Graph - i = 0 - for agent in agents: - k=0 - for name in agent_names: - source_agent_edges_values[name] = agents[i].value(agent_items_allocated[k]) - list(agent_items_values_allocated.values())[i] - k += 1 - list_of_all_the_edges.append(source_agent_edges_values.copy()) - i += 1 - # create an empty graph - envy_graph = networkx.DiGraph() # DiGraph — Directed graphs with self loops + envy_graph = nx.DiGraph() # DiGraph — Directed graphs with self loops + + # create the nodes of the Envy Graph + for agent_name in agents: + envy_graph.add_node(agent_name.name()) - # create nodes of the Envy Graph - for name_node in agent_names: - envy_graph.add_node(name_node) - # create edges to the nodes in the Envy Graph - i = 0 - for node1 in agent_names: - k = 0 - for node2 in list_of_all_the_edges[i]: - if node1 is node2: - k += 1 + for i,agent_i in enumerate(agents): + for k, agent_k in enumerate(agents): + if agent_i.name() is agent_k.name(): continue - envy_graph.add_edge(node1, node2, weight=list(list_of_all_the_edges[i].values())[k]) - k += 1 - i += 1 + # For any pair of agents i, k ∈ I the weight of arc (i, k) in GA is the envy agent i has for agent k under the allocation A, that is, wA(i, k) = vi(Ak) − vi(Ai). + envy_graph.add_edge(agent_i.name(), agent_k.name(), weight=(agent_i.value(agent_items_allocated[k])) - agent_i.value(agent_items_allocated[i])) return envy_graph create_Envy_Graph.logger = logger -def check_positive_weight_directed_cycles(envy_graph: networkx.DiGraph) -> bool: +def check_positive_weight_directed_cycles(envy_graph: nx.DiGraph) -> bool: """ This function checks if its envy graph does not contain a positive-weight directed cycle - ###### 2 agens, 2 items ###### - >>> agents1 = AgentList({"Alice": {"a":5, "b":3}, "Bob": {"a":4, "b":1}}) - >>> print(Bounded_Subsidy(agents1)) - {'Alice': ['b'], 'Bob': ['a']} - >>> envy_graph = create_Envy_Graph(agents1) - >>> print(envy_graph) - DiGraph with 2 nodes and 2 edges - >>> print(envy_graph.nodes) - ['Alice', 'Bob'] - >>> print(envy_graph.edges.data()) - [('Alice', 'Bob', {'weight': 2}), ('Bob', 'Alice', {'weight': -3})] - >>> check_positive_weight_directed_cycles(envy_graph) + ###### 2 nodes, 1 edges ###### + >>> G = nx.DiGraph() + >>> G.add_edge(1, 2, weight=3) + >>> check_positive_weight_directed_cycles(G) False - ###### 3 agens, 3 items ###### - >>> agents2 = AgentList({"Alice": {"a": 3, "b": 2, "c": 1}, "Bob": {"a": 2, "b": 2, "c": 3}, "Max": {"a": 1, "b": 3, "c": 2}}) - >>> print(Bounded_Subsidy(agents2)) - {'Alice': ['a'], 'Bob': ['c'], 'Max': ['b']} - >>> envy_graph = create_Envy_Graph(agents2) - >>> print(envy_graph) - DiGraph with 3 nodes and 6 edges - >>> print(envy_graph.nodes) - ['Alice', 'Bob', 'Max'] - >>> print(envy_graph.edges.data()) - [('Alice', 'Bob', {'weight': -2}), ('Alice', 'Max', {'weight': -1}), ('Bob', 'Alice', {'weight': -1}), ('Bob', 'Max', {'weight': -1}), ('Max', 'Alice', {'weight': -2}), ('Max', 'Bob', {'weight': -1})] - >>> check_positive_weight_directed_cycles(envy_graph) + ###### 2 nodes, 2 edges ###### + >>> G = nx.DiGraph() + >>> G.add_edge(1, 2, weight=3) + >>> G.add_edge(2, 1, weight=-2) + >>> check_positive_weight_directed_cycles(G) + True + + ###### 3 nodes, 3 edges ###### + >>> G = nx.DiGraph() + >>> G.add_edge(1, 3, weight=3) + >>> G.add_edge(3, 2, weight=2) + >>> G.add_edge(2, 1, weight=-6) + >>> check_positive_weight_directed_cycles(G) False - ###### 4 agens, 2 items ###### - >>> agents3 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) - >>> print(Bounded_Subsidy(agents3)) - {'Alice': ['b'], 'Bob': ['a'], 'Max': [], 'Nancy': []} - >>> envy_graph = create_Envy_Graph(agents3) - >>> print(envy_graph) - DiGraph with 4 nodes and 12 edges - >>> print(envy_graph.nodes) - ['Alice', 'Bob', 'Max', 'Nancy'] - >>> print(envy_graph.edges.data()) - [('Alice', 'Bob', {'weight': -1}), ('Alice', 'Max', {'weight': -6}), ('Alice', 'Nancy', {'weight': -6}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -3}), ('Bob', 'Nancy', {'weight': -3}), ('Max', 'Alice', {'weight': 2}), ('Max', 'Bob', {'weight': 2}), ('Max', 'Nancy', {'weight': 0}), ('Nancy', 'Alice', {'weight': 1}), ('Nancy', 'Bob', {'weight': 2}), ('Nancy', 'Max', {'weight': 0})] - >>> check_positive_weight_directed_cycles(envy_graph) + ###### 4 nodes, 4 edges ###### + >>> G = nx.DiGraph() + >>> G.add_edge(1, 2, weight=1) + >>> G.add_edge(2, 3, weight=-1) + >>> G.add_edge(3, 4, weight=1) + >>> G.add_edge(4, 1, weight=-1) + >>> check_positive_weight_directed_cycles(G) False - ###### 4 agents, 4 items ###### - >>> agents4 = AgentList({"Alice": {"a":4, "b":3, "c":2, "d":1}, "Bob": {"a":4, "b":3, "c":2, "d":1}, "Max": {"a":4, "b":3, "c":2, "d":1}, "Nancy": {"a":4, "b":3, "c":2, "d":1}}) - >>> print(Bounded_Subsidy(agents4)) - {'Alice': ['d'], 'Bob': ['c'], 'Max': ['b'], 'Nancy': ['a']} - >>> envy_graph = create_Envy_Graph(agents4) - >>> print(envy_graph) - DiGraph with 4 nodes and 12 edges - >>> print(envy_graph.nodes) - ['Alice', 'Bob', 'Max', 'Nancy'] - >>> print(envy_graph.edges.data()) - [('Alice', 'Bob', {'weight': 1}), ('Alice', 'Max', {'weight': 2}), ('Alice', 'Nancy', {'weight': 3}), ('Bob', 'Alice', {'weight': -1}), ('Bob', 'Max', {'weight': 1}), ('Bob', 'Nancy', {'weight': 2}), ('Max', 'Alice', {'weight': -2}), ('Max', 'Bob', {'weight': -1}), ('Max', 'Nancy', {'weight': 1}), ('Nancy', 'Alice', {'weight': -3}), ('Nancy', 'Bob', {'weight': -2}), ('Nancy', 'Max', {'weight': -1})] - >>> check_positive_weight_directed_cycles(envy_graph) - False - + ###### 4 nodes, 5 edges ###### + >>> G = nx.DiGraph() + >>> G.add_edge(2, 1, weight=4) + >>> G.add_edge(1, 3, weight=-2) + >>> G.add_edge(2, 3, weight=3) + >>> G.add_edge(3, 4, weight=2) + >>> G.add_edge(4, 2, weight=-1) + >>> check_positive_weight_directed_cycles(G) + True + """ - copy_envy_graph = envy_graph.copy() - nodes = copy_envy_graph.nodes # nodes - edges = copy_envy_graph.edges.data() # edges + # copy_envy_graph = envy_graph.copy() # copy the original graph + nodes = envy_graph.nodes # nodes + edges = envy_graph.edges.data() # edges # multiply by -1 for all the edges for edge in edges: edge[2]['weight'] *= -1 - G = networkx.DiGraph() # create an envy graph - G.add_nodes_from(nodes) # add nodes to the graph - G.add_edges_from(edges) # add edges to the graph + envy_graph.add_nodes_from(nodes) # add nodes to the graph + envy_graph.add_edges_from(edges) # add edges to the graph try: - networkx.find_negative_cycle(G,list(nodes)[0]) + nx.find_negative_cycle(envy_graph,list(nodes)[0]) return True - except networkx.exception.NetworkXError: + except nx.NetworkXError: return False -def cal_the_Subsidy(agents: AgentList) -> str: +def calculate_the_Subsidy(envy_graph: nx.DiGraph) -> list: """ This function calculates the Subsidy of the agentes @@ -376,10 +332,10 @@ def cal_the_Subsidy(agents: AgentList) -> str: {'Alice': ['a'], 'Bob': []} >>> print(create_Envy_Graph(agents0).edges.data()) [('Alice', 'Bob', {'weight': -5}), ('Bob', 'Alice', {'weight': 4})] - >>> print(cal_the_Subsidy(agents0)) - Alice gets ['a'] with No Subsudy - Bob gets [] and it is envious of Alice with Subsudy of: 4 - + >>> print(calculate_the_Subsidy(create_Envy_Graph(agents0))) + ['Alice'] ==> 0 + ['Bob', 'Alice'] ==> 4 + [0, 4] ###### 2 agens, 2 items ###### >>> agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) @@ -387,10 +343,10 @@ def cal_the_Subsidy(agents: AgentList) -> str: {'Alice': ['b'], 'Bob': ['a']} >>> print(create_Envy_Graph(agents1).edges.data()) [('Alice', 'Bob', {'weight': -2}), ('Bob', 'Alice', {'weight': 1})] - >>> print(cal_the_Subsidy(agents1)) - Alice gets ['b'] with No Subsudy - Bob gets ['a'] and it is envious of Alice with Subsudy of: 1 - + >>> print(calculate_the_Subsidy(create_Envy_Graph(agents1))) + ['Alice'] ==> 0 + ['Bob', 'Alice'] ==> 1 + [0, 1] ###### 2 agens, 4 items ###### >>> agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) @@ -398,10 +354,10 @@ def cal_the_Subsidy(agents: AgentList) -> str: {'Alice': ['b', 'c'], 'Bob': ['d', 'a']} >>> print(create_Envy_Graph(agents2).edges.data()) [('Alice', 'Bob', {'weight': -7}), ('Bob', 'Alice', {'weight': -1})] - >>> print(cal_the_Subsidy(agents2)) - Alice gets ['b', 'c'] with No Subsudy - Bob gets ['d', 'a'] with No Subsudy - + >>> print(calculate_the_Subsidy(create_Envy_Graph(agents2))) + ['Alice'] ==> 0 + ['Bob'] ==> 0 + [0, 0] ###### 3 agents, 3 items ###### >>> agents3 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) @@ -409,11 +365,11 @@ def cal_the_Subsidy(agents: AgentList) -> str: {'Alice': ['b'], 'Bob': ['c'], 'Max': ['a']} >>> print(create_Envy_Graph(agents3).edges.data()) [('Alice', 'Bob', {'weight': -2}), ('Alice', 'Max', {'weight': -4}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -1}), ('Max', 'Alice', {'weight': -1}), ('Max', 'Bob', {'weight': -2})] - >>> print(cal_the_Subsidy(agents3)) - Alice gets ['b'] with No Subsudy - Bob gets ['c'] and it is envious of Alice with Subsudy of: 1 - Max gets ['a'] with No Subsudy - + >>> print(calculate_the_Subsidy(create_Envy_Graph(agents3))) + ['Alice'] ==> 0 + ['Bob', 'Alice'] ==> 1 + ['Max'] ==> 0 + [0, 1, 0] ###### 4 agents, 2 items ###### >>> agents4 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) @@ -421,12 +377,12 @@ def cal_the_Subsidy(agents: AgentList) -> str: {'Alice': ['b'], 'Bob': ['a'], 'Max': [], 'Nancy': []} >>> print(create_Envy_Graph(agents4).edges.data()) [('Alice', 'Bob', {'weight': -1}), ('Alice', 'Max', {'weight': -6}), ('Alice', 'Nancy', {'weight': -6}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -3}), ('Bob', 'Nancy', {'weight': -3}), ('Max', 'Alice', {'weight': 2}), ('Max', 'Bob', {'weight': 2}), ('Max', 'Nancy', {'weight': 0}), ('Nancy', 'Alice', {'weight': 1}), ('Nancy', 'Bob', {'weight': 2}), ('Nancy', 'Max', {'weight': 0})] - >>> print(cal_the_Subsidy(agents4)) - Alice gets ['b'] with No Subsudy - Bob gets ['a'] and it is envious of Alice with Subsudy of: 1 - Max gets [] and it is envious of Bob with Subsudy of: 3 - Nancy gets [] and it is envious of Bob with Subsudy of: 3 - + >>> print(calculate_the_Subsidy(create_Envy_Graph(agents4))) + ['Alice'] ==> 0 + ['Bob', 'Alice'] ==> 1 + ['Max', 'Bob', 'Alice'] ==> 3 + ['Nancy', 'Bob', 'Alice'] ==> 3 + [0, 1, 3, 3] ###### 4 agents, 4 items ###### >>> agents5 = AgentList({"Alice": {"a":4, "b":3, "c":2, "d":1}, "Bob": {"a":4, "b":3, "c":2, "d":1}, "Max": {"a":4, "b":3, "c":2, "d":1}, "Nancy": {"a":4, "b":3, "c":2, "d":1}}) @@ -434,92 +390,39 @@ def cal_the_Subsidy(agents: AgentList) -> str: {'Alice': ['d'], 'Bob': ['c'], 'Max': ['b'], 'Nancy': ['a']} >>> print(create_Envy_Graph(agents5).edges.data()) [('Alice', 'Bob', {'weight': 1}), ('Alice', 'Max', {'weight': 2}), ('Alice', 'Nancy', {'weight': 3}), ('Bob', 'Alice', {'weight': -1}), ('Bob', 'Max', {'weight': 1}), ('Bob', 'Nancy', {'weight': 2}), ('Max', 'Alice', {'weight': -2}), ('Max', 'Bob', {'weight': -1}), ('Max', 'Nancy', {'weight': 1}), ('Nancy', 'Alice', {'weight': -3}), ('Nancy', 'Bob', {'weight': -2}), ('Nancy', 'Max', {'weight': -1})] - >>> print(cal_the_Subsidy(agents5)) - Alice gets ['d'] and it is envious of Bob with Subsudy of: 3 - Bob gets ['c'] and it is envious of Alice with Subsudy of: 2 - Max gets ['b'] and it is envious of Alice with Subsudy of: 1 - Nancy gets ['a'] with No Subsudy - + >>> print(calculate_the_Subsidy(create_Envy_Graph(agents5))) + ['Alice', 'Nancy'] ==> 3 + ['Bob', 'Nancy'] ==> 2 + ['Max', 'Nancy'] ==> 1 + ['Nancy'] ==> 0 + [3, 2, 1, 0] """ - envy_graph = create_Envy_Graph(agents) # create Envy Graph - copy_envy_graph = envy_graph.copy() - nodes = copy_envy_graph.nodes # nodes - edges = copy_envy_graph.edges.data() # edges - result = "" + subsedy_list = [] # list of the values of the subsudy of the agents in order + nodes = envy_graph.nodes # nodes if check_positive_weight_directed_cycles(envy_graph): # if the graph have a positive cycles - result = "The graph has positive weight directed cycles" - return result - - result = "" # to print rhe resulte - num_of_edges_of_source_node = len(nodes) - 1 # The number of edges coming out of the source agent - - ############ calculate the Subsidy ############ - index=0 - stop_the_loop = 0 - max_edge_weight_of_source_node = 0 # The maximum edge weight of the source node - for stop_the_loop in range(len(edges)): - for source_node_edge in edges: - weight_edge = list(source_node_edge[2].values())[0] - if weight_edge > max_edge_weight_of_source_node: - max_edge_weight_of_source_node = weight_edge - index += 1 - stop_the_loop += 1 - - if index == num_of_edges_of_source_node: - if max_edge_weight_of_source_node > 0: # if there is an envy in the graph - for edge in edges: # Give the subsidy to the appropriate agents - if edge[0] is source_node_edge[0]: - edge[2]['weight'] -= max_edge_weight_of_source_node - - if edge[1] is source_node_edge[0]: - edge[2]['weight'] += max_edge_weight_of_source_node - max_edge_weight_of_source_node = 0 - stop_the_loop = 0 - index = 0 - break - else: - index = 0 - # print(edges) - - - ############ print the resultes ############ - maximum_matching = Bounded_Subsidy(agents) # gets the items that allocated to the agents - edges = envy_graph.edges.data() - copy_edges = copy_envy_graph.edges.data() - list_of_max_subsudy = [] - - for i in range(len(edges)): - list_of_max_subsudy.append(list(list(edges)[i][2].values())[0] - list(list(copy_edges)[i][2].values())[0]) - - max_subsudy = list_of_max_subsudy[0] - size = len(list_of_max_subsudy) - j = 0 - flag = False - for i in range(size): - - if list_of_max_subsudy[i] > max_subsudy: - max_subsudy = list_of_max_subsudy[i] - - if list(list(copy_edges)[i][2].values())[0] == 0 and not flag: - node1 = list(copy_edges)[i][0] - node2 = list(copy_edges)[i][1] - flag = True - - if ((i+1) % num_of_edges_of_source_node) == 0: - if max_subsudy > 0: - result += (str(node1) + " gets " + str(list(maximum_matching.values())[j]) + " and it is envious of " + str(node2) + " with Subsudy of: " + str(max_subsudy) + "\n") - flag = False - else: - result += (list(maximum_matching.keys())[j] + " gets " + str(list(maximum_matching.values())[j]) + " with No Subsudy" + "\n") - flag = False - max_subsudy = 0 - j += 1 + print("The graph has positive weight directed cycles") + return - return result + for node in nodes: + p = nx.single_source_bellman_ford(envy_graph, source=node, weight='weight') # Compute shortest path length and predecessors on shortest paths in weighted graphs. O(V*E) + # print(p) + path_weight = list(p[0].values()) # The weight of the path + path_nodes = list(p[1].values()) # The nodes of the path + + min_path_weight = path_weight[0] # min path weight + min_path_nodes = path_nodes[0] # min path nodes + for i in range(1, len(p[0])): # search of shortest path of all targets node + if path_weight[i] < min_path_weight: + min_path_weight = path_weight[i] + min_path_nodes = path_nodes[i] + + print(str(min_path_nodes) + " ==> " + str(min_path_weight*(-1))) + subsedy_list.append(min_path_weight*(-1)) + return subsedy_list #### MAIN @@ -531,16 +434,13 @@ def cal_the_Subsidy(agents: AgentList) -> str: (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) print("{} failures, {} tests".format(failures, tests)) - # agents5 = AgentList({"Alice": {"a":3, "b":4, "c":3}, "Bob": {"a":1, "b":5, "c":3}, "Max": {"a":2, "b":3, "c":2}}) + # agents1 = AgentList({"Alice": {"a":3, "b":4, "c":3}, "Bob": {"a":1, "b":5, "c":3}, "Max": {"a":2, "b":3, "c":2}}) # agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) - # agents1 = AgentList({"Alice": {"a":2, "b":1}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":5, "b":6}}) - # agents3 = AgentList({"Alice": {"a":6, "b":7}, "Bob": {"a":3, "b":5}}) - # agents6 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) - # agents7 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":2, "b":3, "c":2}, "Max": {"a":3, "b":4, "c":3}}) - - # print(list(Bounded_Subsidy(agents6).values())) - # print(create_Envy_Graph(agents6).edges.data()) - # a=check_positive_weight_directed_cycles(G) - # print(a) - # print(cal_the_Subsidy(agents6)) - # check_envy_in_the_graph(create_Envy_Graph(agents1)) + # agents3 = AgentList({"Alice": {"a":2, "b":1}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":5, "b":6}}) + # agents4 = AgentList({"Alice": {"a":6, "b":7}, "Bob": {"a":3, "b":5}}) + # agents5 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":2, "b":3, "c":2}, "Max": {"a":3, "b":4, "c":3}}) + # agents6 = AgentList({"Alice": {"a":3, "b":5, "c":8}, "Bob": {"a":3, "b":10, "c":5}, "Max": {"a":1, "b":2, "c":10}, "Nancy": {"a":10, "b":10, "c":10}, "Eve": {"a":8, "b":7, "c":2}}) + # agents7 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":5, "b":6}, "Max": {"a":4, "b":5}, "Nancy": {"a":4, "b":6}}) + # agents8 = AgentList({"Alice": {"a":5, "b":5}, "Bob": {"a":5, "b":5}, "Max": {"a":5, "b":5}, "Nancy": {"a":5, "b":5}}) + # agents9 = AgentList({'Alice': {'a':5, 'b':6}, 'Bob': {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + # agents10 = AgentList({'R': {'a':0, 'b':6}, 'E': {"a":2, "b":2}, "S": {"a":4, "b":8}, "I": {"a":7, "b":1}, "G": {"a":7, "b":2}}) From 09293d99aba7d43d83fac744c83bb3fa9f7babd1 Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Mon, 23 Jan 2023 00:24:48 +0200 Subject: [PATCH 21/23] final update --- tests/tests_bounded_subsidy.py | 146 +++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 32 deletions(-) diff --git a/tests/tests_bounded_subsidy.py b/tests/tests_bounded_subsidy.py index 500bfae3..01b7244a 100644 --- a/tests/tests_bounded_subsidy.py +++ b/tests/tests_bounded_subsidy.py @@ -55,6 +55,34 @@ def test_check_positive_weight_directed_cycles(self): tests for check_positive_weight_directed_cycles function, that checks if its envy graph does not contain a positive-weight directed cycle """ + G1 = nx.DiGraph() + G1.add_edge(1, 2, weight=3) + res = check_positive_weight_directed_cycles(G1) + self.assertEqual(res, False) + + G2 = nx.DiGraph() + G2.add_edge(1, 2, weight=3) + G2.add_edge(2, 1, weight=-2) + res = check_positive_weight_directed_cycles(G2) + self.assertEqual(res, True) + + G3 = nx.DiGraph() + G3.add_edge(1, 2, weight=1) + G3.add_edge(2, 3, weight=-1) + G3.add_edge(3, 4, weight=1) + G3.add_edge(4, 1, weight=-1) + res = check_positive_weight_directed_cycles(G3) + self.assertEqual(res, False) + + G4 = nx.DiGraph() + G4.add_edge(2, 1, weight=4) + G4.add_edge(1, 3, weight=-2) + G4.add_edge(2, 3, weight=3) + G4.add_edge(3, 4, weight=2) + G4.add_edge(4, 2, weight=-1) + res = check_positive_weight_directed_cycles(G4) + self.assertEqual(res, True) + agents1 = AgentList({"Alice": {"a":5, "b":3}, "Bob": {"a":4, "b":1}}) envy_graph1 = create_Envy_Graph(agents1) res = check_positive_weight_directed_cycles(envy_graph1) @@ -76,58 +104,112 @@ def test_check_positive_weight_directed_cycles(self): self.assertEqual(res, False) - def test_cal_the_Subsidy(self): + def test_calculate_the_Subsidy(self): """ tests for cal_the_Subsidy function, that calculates the Subsidy of the agentes """ agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) - res = "Alice gets ['b'] with No Subsudy" + "\n" + "Bob gets ['a'] and it is envious of Alice with Subsudy of: 1" + "\n" - self.assertEqual(cal_the_Subsidy(agents1), res) + envy_graph1 = create_Envy_Graph(agents1) + res = [0, 1] + self.assertEqual(calculate_the_Subsidy(envy_graph1), res) agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) - res = "Alice gets ['b', 'c'] with No Subsudy" + "\n" + "Bob gets ['d', 'a'] with No Subsudy" + "\n" - self.assertEqual(cal_the_Subsidy(agents2), res) + envy_graph2 = create_Envy_Graph(agents2) + res = [0, 0] + self.assertEqual(calculate_the_Subsidy(envy_graph2), res) agents3 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) - res = "Alice gets ['b'] with No Subsudy" + "\n" + "Bob gets ['c'] and it is envious of Alice with Subsudy of: 1" + "\n" + "Max gets ['a'] with No Subsudy" + "\n" - self.assertEqual(cal_the_Subsidy(agents3), res) + envy_graph3 = create_Envy_Graph(agents3) + res = [0, 1, 0] + self.assertEqual(calculate_the_Subsidy(envy_graph3), res) agents4 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) - res = "Alice gets ['b'] with No Subsudy" + "\n" + "Bob gets ['a'] and it is envious of Alice with Subsudy of: 1" + "\n" + "Max gets [] and it is envious of Bob with Subsudy of: 3" + "\n" + "Nancy gets [] and it is envious of Bob with Subsudy of: 3" + "\n" - self.assertEqual(cal_the_Subsidy(agents4), res) + envy_graph4 = create_Envy_Graph(agents4) + res = [0, 1, 3, 3] + self.assertEqual(calculate_the_Subsidy(envy_graph4), res) agents5 = AgentList({"Alice": {"a":4, "b":3, "c":2, "d":1}, "Bob": {"a":4, "b":3, "c":2, "d":1}, "Max": {"a":4, "b":3, "c":2, "d":1}, "Nancy": {"a":4, "b":3, "c":2, "d":1}}) - res = "Alice gets ['d'] and it is envious of Bob with Subsudy of: 3" + "\n" + "Bob gets ['c'] and it is envious of Alice with Subsudy of: 2" + "\n" + "Max gets ['b'] and it is envious of Alice with Subsudy of: 1" + "\n" + "Nancy gets ['a'] with No Subsudy" + "\n" - self.assertEqual(cal_the_Subsidy(agents5), res) + envy_graph5 = create_Envy_Graph(agents5) + res = [3, 2, 1, 0] + self.assertEqual(calculate_the_Subsidy(envy_graph5), res) - ############ random number of agents and items ############ - random_item = random.choice(string.ascii_lowercase) - random_item_weight = random.randint(0, 9) - num_of_agents = random.randint(2, 9) - num_of_items = random.randint(1, 9) - - - # # create a list of random agents name - # list_of_agents = [] - # for i in range(num_of_agents): - # random_agent = random.choice(string.ascii_uppercase) - # if random_agent not in list_of_agents: - # list_of_agents.append(random_agent) + agents6 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":5, "b":6}, "Max": {"a":4, "b":5}, "Nancy": {"a":4, "b":6}}) + envy_graph6 = create_Envy_Graph(agents6) + res = [1, 6, 6, 0] + self.assertEqual(calculate_the_Subsidy(envy_graph6), res) + agents7 = AgentList({"Alice": {"a":5, "b":5}, "Bob": {"a":5, "b":5}, "Max": {"a":5, "b":5}, "Nancy": {"a":5, "b":5}}) + envy_graph7 = create_Envy_Graph(agents7) + res = [5, 5, 0, 0] + self.assertEqual(calculate_the_Subsidy(envy_graph7), res) - # # create a list of Dict of random items with values - # list_of_items = [] - # for i in range(num_of_items): - # random_item = random.choice(string.ascii_lowercase) - # random_item_weight = random.randint(0, 9) - # if random_item not in list_of_items: - # list_of_items.append(dict({random_item:random_item_weight})) + def test_random_calculate_the_Subsidy(self): + """ + tests of random number of agents and items + """ + ############ create random number of agents and items ############ + num_of_agents = random.randint(2, 300) + num_of_items = random.randint(2, 300) + + # create a list of random agents names + list_of_agents = [] + for i in range(num_of_agents): + random_agent = random.choice(string.ascii_uppercase) + if random_agent not in list_of_agents: + list_of_agents.append(str(random_agent)) # print(list_of_agents) - # print(list_of_items) + # create a list of random items names + list_of_items = [] + for i in range(num_of_items): + random_item = random.choice(string.ascii_lowercase) + if random_item not in list_of_items: + list_of_items.append(str(random_item)) + # print(list_of_items) + + # create list of dict of items and the weight + list_of_items_and_values = [] + items_and_values = {} + for i in range(len(list_of_agents)): + for j in range(len(list_of_items)): + random_item_weight = random.randint(0, 9) + items_and_values[str(list_of_items[j])] = random_item_weight + list_of_items_and_values.append(items_and_values.copy()) + # print(list_of_items_and_values) + + # create AgentList + agents = AgentList(dict(zip(list_of_agents,list_of_items_and_values))) + + ############ Checks if the algorithm works correctly and efficiently ############ + + # list of the subsudy + subsudy_list = calculate_the_Subsidy(create_Envy_Graph(agents)) + + # maximum matching for all the agents + maximum_matching = Bounded_Subsidy(agents) + + # The items that allocated for the agent + agent_items_allocated = list(maximum_matching.values()) + + sum_item_and_subsudy = [] # The sum of the items and subsidy allocated to each agent + result = True + + # Here we check if the value of the items that the agent received + the subsidy he received is at least as large as all the others + for i, agent_i in enumerate(agents): + sum_item_and_subsudy.clear() + for k,agent_k in enumerate(agents): + sum_item_and_subsudy.append(agent_i.value(agent_items_allocated[k]) + subsudy_list[k]) # The sum of the items and subsidy allocated to each agent + max_sum = sum_item_and_subsudy[i] + for l in range(len(sum_item_and_subsudy)): + if sum_item_and_subsudy[l] > max_sum: # Check if there is an envy + result = False + break + + self.assertEqual(result, True) + def main(): unittest.main() From a15511be66b8fe0b961135ba1c73444753a1525d Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Mon, 23 Jan 2023 11:36:11 +0200 Subject: [PATCH 22/23] add print_results function --- fairpy/items/Bounded_Subsidy_Algorithem.py | 101 ++++++++++++++------- 1 file changed, 67 insertions(+), 34 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index 9af445f3..ab3e9d19 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -135,7 +135,6 @@ def delete_items(items:Dict[str,int], items_to_remove:List)->Dict[str,int]: return {item:newSize for item,newSize in items.items() if newSize > 0} - ##### algorithm 2 ##### def create_Envy_Graph(agents: AgentList) -> nx.DiGraph(): @@ -255,7 +254,6 @@ def create_Envy_Graph(agents: AgentList) -> nx.DiGraph(): return envy_graph -create_Envy_Graph.logger = logger def check_positive_weight_directed_cycles(envy_graph: nx.DiGraph) -> bool: """ @@ -330,11 +328,10 @@ def calculate_the_Subsidy(envy_graph: nx.DiGraph) -> list: >>> agents0 = AgentList({"Alice": {"a":5}, "Bob": {"a":4}}) >>> print(Bounded_Subsidy(agents0)) {'Alice': ['a'], 'Bob': []} - >>> print(create_Envy_Graph(agents0).edges.data()) + >>> envy_graph = create_Envy_Graph(agents0) + >>> print(envy_graph.edges.data()) [('Alice', 'Bob', {'weight': -5}), ('Bob', 'Alice', {'weight': 4})] - >>> print(calculate_the_Subsidy(create_Envy_Graph(agents0))) - ['Alice'] ==> 0 - ['Bob', 'Alice'] ==> 4 + >>> print(calculate_the_Subsidy(envy_graph)) [0, 4] ###### 2 agens, 2 items ###### @@ -344,8 +341,6 @@ def calculate_the_Subsidy(envy_graph: nx.DiGraph) -> list: >>> print(create_Envy_Graph(agents1).edges.data()) [('Alice', 'Bob', {'weight': -2}), ('Bob', 'Alice', {'weight': 1})] >>> print(calculate_the_Subsidy(create_Envy_Graph(agents1))) - ['Alice'] ==> 0 - ['Bob', 'Alice'] ==> 1 [0, 1] ###### 2 agens, 4 items ###### @@ -355,8 +350,6 @@ def calculate_the_Subsidy(envy_graph: nx.DiGraph) -> list: >>> print(create_Envy_Graph(agents2).edges.data()) [('Alice', 'Bob', {'weight': -7}), ('Bob', 'Alice', {'weight': -1})] >>> print(calculate_the_Subsidy(create_Envy_Graph(agents2))) - ['Alice'] ==> 0 - ['Bob'] ==> 0 [0, 0] ###### 3 agents, 3 items ###### @@ -366,9 +359,6 @@ def calculate_the_Subsidy(envy_graph: nx.DiGraph) -> list: >>> print(create_Envy_Graph(agents3).edges.data()) [('Alice', 'Bob', {'weight': -2}), ('Alice', 'Max', {'weight': -4}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -1}), ('Max', 'Alice', {'weight': -1}), ('Max', 'Bob', {'weight': -2})] >>> print(calculate_the_Subsidy(create_Envy_Graph(agents3))) - ['Alice'] ==> 0 - ['Bob', 'Alice'] ==> 1 - ['Max'] ==> 0 [0, 1, 0] ###### 4 agents, 2 items ###### @@ -378,10 +368,6 @@ def calculate_the_Subsidy(envy_graph: nx.DiGraph) -> list: >>> print(create_Envy_Graph(agents4).edges.data()) [('Alice', 'Bob', {'weight': -1}), ('Alice', 'Max', {'weight': -6}), ('Alice', 'Nancy', {'weight': -6}), ('Bob', 'Alice', {'weight': 1}), ('Bob', 'Max', {'weight': -3}), ('Bob', 'Nancy', {'weight': -3}), ('Max', 'Alice', {'weight': 2}), ('Max', 'Bob', {'weight': 2}), ('Max', 'Nancy', {'weight': 0}), ('Nancy', 'Alice', {'weight': 1}), ('Nancy', 'Bob', {'weight': 2}), ('Nancy', 'Max', {'weight': 0})] >>> print(calculate_the_Subsidy(create_Envy_Graph(agents4))) - ['Alice'] ==> 0 - ['Bob', 'Alice'] ==> 1 - ['Max', 'Bob', 'Alice'] ==> 3 - ['Nancy', 'Bob', 'Alice'] ==> 3 [0, 1, 3, 3] ###### 4 agents, 4 items ###### @@ -391,10 +377,6 @@ def calculate_the_Subsidy(envy_graph: nx.DiGraph) -> list: >>> print(create_Envy_Graph(agents5).edges.data()) [('Alice', 'Bob', {'weight': 1}), ('Alice', 'Max', {'weight': 2}), ('Alice', 'Nancy', {'weight': 3}), ('Bob', 'Alice', {'weight': -1}), ('Bob', 'Max', {'weight': 1}), ('Bob', 'Nancy', {'weight': 2}), ('Max', 'Alice', {'weight': -2}), ('Max', 'Bob', {'weight': -1}), ('Max', 'Nancy', {'weight': 1}), ('Nancy', 'Alice', {'weight': -3}), ('Nancy', 'Bob', {'weight': -2}), ('Nancy', 'Max', {'weight': -1})] >>> print(calculate_the_Subsidy(create_Envy_Graph(agents5))) - ['Alice', 'Nancy'] ==> 3 - ['Bob', 'Nancy'] ==> 2 - ['Max', 'Nancy'] ==> 1 - ['Nancy'] ==> 0 [3, 2, 1, 0] """ @@ -403,12 +385,11 @@ def calculate_the_Subsidy(envy_graph: nx.DiGraph) -> list: nodes = envy_graph.nodes # nodes if check_positive_weight_directed_cycles(envy_graph): # if the graph have a positive cycles - print("The graph has positive weight directed cycles") + logger.info("The graph has positive weight directed cycles") return for node in nodes: p = nx.single_source_bellman_ford(envy_graph, source=node, weight='weight') # Compute shortest path length and predecessors on shortest paths in weighted graphs. O(V*E) - # print(p) path_weight = list(p[0].values()) # The weight of the path path_nodes = list(p[1].values()) # The nodes of the path @@ -419,11 +400,72 @@ def calculate_the_Subsidy(envy_graph: nx.DiGraph) -> list: min_path_weight = path_weight[i] min_path_nodes = path_nodes[i] - print(str(min_path_nodes) + " ==> " + str(min_path_weight*(-1))) + logger.info("maximum path: %s", (str(min_path_nodes) + " ==> " + str(min_path_weight*(-1)))) subsedy_list.append(min_path_weight*(-1)) return subsedy_list +calculate_the_Subsidy.logger = logger + +def print_results(agents: AgentList): + """ + This is the main function, it's received an Agent List and print the result + + ###### 2 agens, 1 items ###### + >>> agents0 = AgentList({"Alice": {"a":5}, "Bob": {"a":4}}) + >>> print_results(agents0) + Alice gets ['a'] with Subsudy of: 0 + Bob gets [] with Subsudy of: 4 + + ###### 2 agens, 2 items ###### + >>> agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) + >>> print_results(agents1) + Alice gets ['b'] with Subsudy of: 0 + Bob gets ['a'] with Subsudy of: 1 + + ###### 2 agens, 4 items ###### + >>> agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) + >>> print_results(agents2) + Alice gets ['b', 'c'] with Subsudy of: 0 + Bob gets ['d', 'a'] with Subsudy of: 0 + + ###### 3 agents, 3 items ###### + >>> agents3 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) + >>> print_results(agents3) + Alice gets ['b'] with Subsudy of: 0 + Bob gets ['c'] with Subsudy of: 1 + Max gets ['a'] with Subsudy of: 0 + + ###### 4 agents, 2 items ###### + >>> agents4 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) + >>> print_results(agents4) + Alice gets ['b'] with Subsudy of: 0 + Bob gets ['a'] with Subsudy of: 1 + Max gets [] with Subsudy of: 3 + Nancy gets [] with Subsudy of: 3 + + ###### 4 agents, 4 items ###### + >>> agents5 = AgentList({"Alice": {"a":4, "b":3, "c":2, "d":1}, "Bob": {"a":4, "b":3, "c":2, "d":1}, "Max": {"a":4, "b":3, "c":2, "d":1}, "Nancy": {"a":4, "b":3, "c":2, "d":1}}) + >>> print_results(agents5) + Alice gets ['d'] with Subsudy of: 3 + Bob gets ['c'] with Subsudy of: 2 + Max gets ['b'] with Subsudy of: 1 + Nancy gets ['a'] with Subsudy of: 0 + + """ + # list of the items that allocated to the agents + items = list(Bounded_Subsidy(agents).values()) + + # create Envy Graph + envy_graph = create_Envy_Graph(agents) + + # calculate the Subsidy + subsidy = calculate_the_Subsidy(envy_graph) + + # print the results + for index,agent in enumerate(agents): + print(str(agent.name()) + " gets " + str(items[index]) + " with Subsudy of: " + str(subsidy[index])) + #### MAIN @@ -434,13 +476,4 @@ def calculate_the_Subsidy(envy_graph: nx.DiGraph) -> list: (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) print("{} failures, {} tests".format(failures, tests)) - # agents1 = AgentList({"Alice": {"a":3, "b":4, "c":3}, "Bob": {"a":1, "b":5, "c":3}, "Max": {"a":2, "b":3, "c":2}}) - # agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) - # agents3 = AgentList({"Alice": {"a":2, "b":1}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":5, "b":6}}) - # agents4 = AgentList({"Alice": {"a":6, "b":7}, "Bob": {"a":3, "b":5}}) - # agents5 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":2, "b":3, "c":2}, "Max": {"a":3, "b":4, "c":3}}) - # agents6 = AgentList({"Alice": {"a":3, "b":5, "c":8}, "Bob": {"a":3, "b":10, "c":5}, "Max": {"a":1, "b":2, "c":10}, "Nancy": {"a":10, "b":10, "c":10}, "Eve": {"a":8, "b":7, "c":2}}) - # agents7 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":5, "b":6}, "Max": {"a":4, "b":5}, "Nancy": {"a":4, "b":6}}) - # agents8 = AgentList({"Alice": {"a":5, "b":5}, "Bob": {"a":5, "b":5}, "Max": {"a":5, "b":5}, "Nancy": {"a":5, "b":5}}) - # agents9 = AgentList({'Alice': {'a':5, 'b':6}, 'Bob': {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) - # agents10 = AgentList({'R': {'a':0, 'b':6}, 'E': {"a":2, "b":2}, "S": {"a":4, "b":8}, "I": {"a":7, "b":1}, "G": {"a":7, "b":2}}) + From 2b810f7070c3fc6b27ce3aee548b3e88b692cf5f Mon Sep 17 00:00:00 2001 From: Eyad-Amer <40535130+Eyad-Amer@users.noreply.github.com> Date: Mon, 23 Jan 2023 17:38:22 +0200 Subject: [PATCH 23/23] done --- fairpy/items/Bounded_Subsidy_Algorithem.py | 35 ++++++++++------------ 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/fairpy/items/Bounded_Subsidy_Algorithem.py b/fairpy/items/Bounded_Subsidy_Algorithem.py index ab3e9d19..05cf06f4 100644 --- a/fairpy/items/Bounded_Subsidy_Algorithem.py +++ b/fairpy/items/Bounded_Subsidy_Algorithem.py @@ -407,52 +407,44 @@ def calculate_the_Subsidy(envy_graph: nx.DiGraph) -> list: calculate_the_Subsidy.logger = logger -def print_results(agents: AgentList): +def print_results(agents: AgentList)->list: """ This is the main function, it's received an Agent List and print the result ###### 2 agens, 1 items ###### >>> agents0 = AgentList({"Alice": {"a":5}, "Bob": {"a":4}}) >>> print_results(agents0) - Alice gets ['a'] with Subsudy of: 0 - Bob gets [] with Subsudy of: 4 + ["Alice gets ['a'] with Subsudy of: 0", 'Bob gets [] with Subsudy of: 4'] ###### 2 agens, 2 items ###### >>> agents1 = AgentList({"Alice": {"a":3, "b":5}, "Bob": {"a":6, "b":7}}) >>> print_results(agents1) - Alice gets ['b'] with Subsudy of: 0 - Bob gets ['a'] with Subsudy of: 1 + ["Alice gets ['b'] with Subsudy of: 0", "Bob gets ['a'] with Subsudy of: 1"] ###### 2 agens, 4 items ###### >>> agents2 = AgentList({"Alice": {"a":4, "b":10, "c":8, "d":7}, "Bob": {"a":5, "b":9, "c":5, "d":10}}) >>> print_results(agents2) - Alice gets ['b', 'c'] with Subsudy of: 0 - Bob gets ['d', 'a'] with Subsudy of: 0 + ["Alice gets ['b', 'c'] with Subsudy of: 0", "Bob gets ['d', 'a'] with Subsudy of: 0"] ###### 3 agents, 3 items ###### >>> agents3 = AgentList({"Alice": {"a":1, "b":5, "c":3}, "Bob": {"a":1, "b":3, "c":2}, "Max": {"a":3, "b":2, "c":1}}) >>> print_results(agents3) - Alice gets ['b'] with Subsudy of: 0 - Bob gets ['c'] with Subsudy of: 1 - Max gets ['a'] with Subsudy of: 0 + ["Alice gets ['b'] with Subsudy of: 0", "Bob gets ['c'] with Subsudy of: 1", "Max gets ['a'] with Subsudy of: 0"] ###### 4 agents, 2 items ###### >>> agents4 = AgentList({"Alice": {"a":5, "b":6}, "Bob": {"a":3, "b":4}, "Max": {"a":2, "b":2}, "Nancy": {"a":2, "b":1}}) >>> print_results(agents4) - Alice gets ['b'] with Subsudy of: 0 - Bob gets ['a'] with Subsudy of: 1 - Max gets [] with Subsudy of: 3 - Nancy gets [] with Subsudy of: 3 + ["Alice gets ['b'] with Subsudy of: 0", "Bob gets ['a'] with Subsudy of: 1", 'Max gets [] with Subsudy of: 3', 'Nancy gets [] with Subsudy of: 3'] ###### 4 agents, 4 items ###### >>> agents5 = AgentList({"Alice": {"a":4, "b":3, "c":2, "d":1}, "Bob": {"a":4, "b":3, "c":2, "d":1}, "Max": {"a":4, "b":3, "c":2, "d":1}, "Nancy": {"a":4, "b":3, "c":2, "d":1}}) - >>> print_results(agents5) - Alice gets ['d'] with Subsudy of: 3 - Bob gets ['c'] with Subsudy of: 2 - Max gets ['b'] with Subsudy of: 1 - Nancy gets ['a'] with Subsudy of: 0 + >>> print(print_results(agents5)) + ["Alice gets ['d'] with Subsudy of: 3", "Bob gets ['c'] with Subsudy of: 2", "Max gets ['b'] with Subsudy of: 1", "Nancy gets ['a'] with Subsudy of: 0"] """ + # The results + results = [] + # list of the items that allocated to the agents items = list(Bounded_Subsidy(agents).values()) @@ -464,7 +456,9 @@ def print_results(agents: AgentList): # print the results for index,agent in enumerate(agents): - print(str(agent.name()) + " gets " + str(items[index]) + " with Subsudy of: " + str(subsidy[index])) + results.append(str(agent.name()) + " gets " + str(items[index]) + " with Subsudy of: " + str(subsidy[index])) + + return results #### MAIN @@ -476,4 +470,5 @@ def print_results(agents: AgentList): (failures, tests) = doctest.testmod(report=True,optionflags=doctest.NORMALIZE_WHITESPACE) print("{} failures, {} tests".format(failures, tests)) +