diff --git a/README.md b/README.md index 80b065f..7f0c5a1 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ The schema has been provided below: ```toml simulation_id = "name of simulation" algorithms_directory = "/path/to/algorithms/" -nodes = [ { node_id = "node_1", algorithm = { file = "foo.py", object = "Foo" } }, +nodes = [ { node_id = "node_1", algorithm = { file = "foo.py", object = "Foo" }, quantity = 11 }, { node_id = "node_2", algorithm = { file = "bar/baz.py", object = "Baz" } } ] simulation = { file = "foobar.py", object = "GenerationalFooBar" } generational_simulation = { file = "foobar.py", object = "FooBar" } @@ -54,7 +54,11 @@ simulations_directory = "/path/to/simulations/" * generational_simulation * The simulation to run for each generation in a generational simulation as a [Dynamic Import](#dynamic-imports) * nodes - * An array of tables that specify a node id and an algorithm, as defined in the [Dynamic Imports](#dynamic-imports) + * An array of tables that specify: + * node id + * algorithm, as defined in the [Dynamic Imports](#dynamic-imports) + * quantity, if not specified then 1 node is assumed + * Note: the node index will be appended to the node_id section * simulation * The simulation to run as a [Dynamic Import](#dynamic-imports) diff --git a/docs/simulations.md b/docs/simulations.md index 6f7d8bf..446bedd 100644 --- a/docs/simulations.md +++ b/docs/simulations.md @@ -45,3 +45,5 @@ points per algorithm to the average points per algorithm. This simulation accepts one additional argument: * generations | int * The number of generations to run + +**WARNING: USING A LOT OF GENERATIONS, ROUNDS, AND NODES CAN CAUSE THIS SIMULATION TO USE A LOT OF PROCESSING POWER** diff --git a/examples/config/complete_generational_mss.toml b/examples/config/complete_generational_mss.toml index 3d0f468..ebcc70e 100644 --- a/examples/config/complete_generational_mss.toml +++ b/examples/config/complete_generational_mss.toml @@ -1,14 +1,14 @@ simulation_id = "Complete StandardGenerationalSimulation for MultiprocessStandardSimulation" algorithms_directory = "examples/algorithms/" -nodes = [ { node_id = "always_cooperate", algorithm = { file = "simple.py", object = "AlwaysCooperate" } }, - { node_id = "always_defect", algorithm = { file = "simple.py", object = "AlwaysDefect" } }, - { node_id = "grim_trigger", algorithm = { file = "grudge.py", object = "GrimTrigger" } }, - { node_id = "random_cooperation", algorithm = { file = "simple.py", object = "RandomCooperation" } }, - { node_id = "tit_for_tat", algorithm = { file = "tit_for_tat.py", object = "TitForTat" } }, - { node_id = "tit_for_two_tats", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" } }, - { node_id = "two_tits_for_tat", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" } } ] +nodes = [ { node_id = "always_cooperate_", algorithm = { file = "simple.py", object = "AlwaysCooperate"}, quantity = 10 }, + { node_id = "always_defect_", algorithm = { file = "simple.py", object = "AlwaysDefect" }, quantity = 10 }, + { node_id = "grim_trigger_", algorithm = { file = "grudge.py", object = "GrimTrigger" }, quantity = 10 }, + { node_id = "random_cooperation_", algorithm = { file = "simple.py", object = "RandomCooperation" }, quantity = 10 }, + { node_id = "tit_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TitForTat" }, quantity = 10 }, + { node_id = "tit_for_two_tats_", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" }, quantity = 10 }, + { node_id = "two_tits_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" }, quantity = 10 } ] simulation = { object = "StandardGenerationalSimulation" } generational_simulation = { object = 'MultiprocessStandardSimulation' } -simulation_arguments = { generations = 10, rounds = 200 } +simulation_arguments = { generations = 10, rounds = 200, pool_size = 4 } simulation_data_output = "examples/rounds/complete_generational_mss.json" simulation_results_output = "examples/results/complete_generational_mss.json" \ No newline at end of file diff --git a/examples/config/complete_generational_ss.toml b/examples/config/complete_generational_ss.toml index 2d3dfeb..4206876 100644 --- a/examples/config/complete_generational_ss.toml +++ b/examples/config/complete_generational_ss.toml @@ -1,12 +1,12 @@ simulation_id = "Complete StandardGenerationalSimulation for StandardSimulation" algorithms_directory = "examples/algorithms/" -nodes = [ { node_id = "always_cooperate", algorithm = { file = "simple.py", object = "AlwaysCooperate" } }, - { node_id = "always_defect", algorithm = { file = "simple.py", object = "AlwaysDefect" } }, - { node_id = "grim_trigger", algorithm = { file = "grudge.py", object = "GrimTrigger" } }, - { node_id = "random_cooperation", algorithm = { file = "simple.py", object = "RandomCooperation" } }, - { node_id = "tit_for_tat", algorithm = { file = "tit_for_tat.py", object = "TitForTat" } }, - { node_id = "tit_for_two_tats", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" } }, - { node_id = "two_tits_for_tat", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" } } ] +nodes = [ { node_id = "always_cooperate_", algorithm = { file = "simple.py", object = "AlwaysCooperate"}, quantity = 10 }, + { node_id = "always_defect_", algorithm = { file = "simple.py", object = "AlwaysDefect" }, quantity = 10 }, + { node_id = "grim_trigger_", algorithm = { file = "grudge.py", object = "GrimTrigger" }, quantity = 10 }, + { node_id = "random_cooperation_", algorithm = { file = "simple.py", object = "RandomCooperation" }, quantity = 10 }, + { node_id = "tit_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TitForTat" }, quantity = 10 }, + { node_id = "tit_for_two_tats_", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" }, quantity = 10 }, + { node_id = "two_tits_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" }, quantity = 10 } ] simulation = { object = "StandardGenerationalSimulation" } generational_simulation = { object = 'StandardSimulation' } simulation_arguments = { generations = 10, rounds = 200 } diff --git a/examples/config/mutable_complete_generational_mss.toml b/examples/config/mutable_complete_generational_mss.toml index 9e12fa9..d2df568 100644 --- a/examples/config/mutable_complete_generational_mss.toml +++ b/examples/config/mutable_complete_generational_mss.toml @@ -1,14 +1,14 @@ simulation_id = "Mutable Complete StandardGenerationalSimulation for MultiprocessStandardSimulation" algorithms_directory = "examples/algorithms/" -nodes = [ { node_id = "always_cooperate", algorithm = { file = "simple.py", object = "AlwaysCooperate" } }, - { node_id = "always_defect", algorithm = { file = "simple.py", object = "AlwaysDefect" } }, - { node_id = "grim_trigger", algorithm = { file = "grudge.py", object = "GrimTrigger" } }, - { node_id = "random_cooperation", algorithm = { file = "simple.py", object = "RandomCooperation" } }, - { node_id = "tit_for_tat", algorithm = { file = "tit_for_tat.py", object = "TitForTat" } }, - { node_id = "tit_for_two_tats", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" } }, - { node_id = "two_tits_for_tat", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" } } ] +nodes = [ { node_id = "always_cooperate_", algorithm = { file = "simple.py", object = "AlwaysCooperate"}, quantity = 10 }, + { node_id = "always_defect_", algorithm = { file = "simple.py", object = "AlwaysDefect" }, quantity = 10 }, + { node_id = "grim_trigger_", algorithm = { file = "grudge.py", object = "GrimTrigger" }, quantity = 10 }, + { node_id = "random_cooperation_", algorithm = { file = "simple.py", object = "RandomCooperation" }, quantity = 10 }, + { node_id = "tit_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TitForTat" }, quantity = 10 }, + { node_id = "tit_for_two_tats_", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" }, quantity = 10 }, + { node_id = "two_tits_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" }, quantity = 10 } ] simulation = { object = "StandardGenerationalSimulation" } generational_simulation = { object = 'MultiprocessStandardSimulation' } -simulation_arguments = { generations = 10, rounds = 200, simulation_mutations = true, mutations_per_mille = 100 } +simulation_arguments = { generations = 10, rounds = 200, simulation_mutations = true, mutations_per_mille = 100, pool_size = 4 } simulation_data_output = "examples/rounds/mutable_complete_generational_mss.json" simulation_results_output = "examples/results/mutable_complete_generational_mss.json" \ No newline at end of file diff --git a/examples/config/mutable_complete_generational_ss.toml b/examples/config/mutable_complete_generational_ss.toml index d826079..3a8a0d5 100644 --- a/examples/config/mutable_complete_generational_ss.toml +++ b/examples/config/mutable_complete_generational_ss.toml @@ -1,12 +1,12 @@ simulation_id = "Mutable Complete StandardGenerationalSimulation for StandardSimulation" algorithms_directory = "examples/algorithms/" -nodes = [ { node_id = "always_cooperate", algorithm = { file = "simple.py", object = "AlwaysCooperate" } }, - { node_id = "always_defect", algorithm = { file = "simple.py", object = "AlwaysDefect" } }, - { node_id = "grim_trigger", algorithm = { file = "grudge.py", object = "GrimTrigger" } }, - { node_id = "random_cooperation", algorithm = { file = "simple.py", object = "RandomCooperation" } }, - { node_id = "tit_for_tat", algorithm = { file = "tit_for_tat.py", object = "TitForTat" } }, - { node_id = "tit_for_two_tats", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" } }, - { node_id = "two_tits_for_tat", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" } } ] +nodes = [ { node_id = "always_cooperate_", algorithm = { file = "simple.py", object = "AlwaysCooperate"}, quantity = 10 }, + { node_id = "always_defect_", algorithm = { file = "simple.py", object = "AlwaysDefect" }, quantity = 10 }, + { node_id = "grim_trigger_", algorithm = { file = "grudge.py", object = "GrimTrigger" }, quantity = 10 }, + { node_id = "random_cooperation_", algorithm = { file = "simple.py", object = "RandomCooperation" }, quantity = 10 }, + { node_id = "tit_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TitForTat" }, quantity = 10 }, + { node_id = "tit_for_two_tats_", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" }, quantity = 10 }, + { node_id = "two_tits_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" }, quantity = 10 } ] simulation = { object = "StandardGenerationalSimulation" } generational_simulation = { object = 'StandardSimulation' } simulation_arguments = { generations = 10, rounds = 200, simulation_mutations = true, mutations_per_mille = 100 } diff --git a/examples/config/mutable_noisy_complete_generational_mss.toml b/examples/config/mutable_noisy_complete_generational_mss.toml index 09ceb4c..80227e3 100644 --- a/examples/config/mutable_noisy_complete_generational_mss.toml +++ b/examples/config/mutable_noisy_complete_generational_mss.toml @@ -1,14 +1,14 @@ simulation_id = "Mutable Noisy Complete StandardGenerationalSimulation for MultiprocessStandardSimulation" algorithms_directory = "examples/algorithms/" -nodes = [ { node_id = "always_cooperate", algorithm = { file = "simple.py", object = "AlwaysCooperate" } }, - { node_id = "always_defect", algorithm = { file = "simple.py", object = "AlwaysDefect" } }, - { node_id = "grim_trigger", algorithm = { file = "grudge.py", object = "GrimTrigger" } }, - { node_id = "random_cooperation", algorithm = { file = "simple.py", object = "RandomCooperation" } }, - { node_id = "tit_for_tat", algorithm = { file = "tit_for_tat.py", object = "TitForTat" } }, - { node_id = "tit_for_two_tats", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" } }, - { node_id = "two_tits_for_tat", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" } } ] +nodes = [ { node_id = "always_cooperate_", algorithm = { file = "simple.py", object = "AlwaysCooperate"}, quantity = 10 }, + { node_id = "always_defect_", algorithm = { file = "simple.py", object = "AlwaysDefect" }, quantity = 10 }, + { node_id = "grim_trigger_", algorithm = { file = "grudge.py", object = "GrimTrigger" }, quantity = 10 }, + { node_id = "random_cooperation_", algorithm = { file = "simple.py", object = "RandomCooperation" }, quantity = 10 }, + { node_id = "tit_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TitForTat" }, quantity = 10 }, + { node_id = "tit_for_two_tats_", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" }, quantity = 10 }, + { node_id = "two_tits_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" }, quantity = 10 } ] simulation = { object = "StandardGenerationalSimulation" } generational_simulation = { object = 'MultiprocessStandardSimulation' } -simulation_arguments = { generations = 10, rounds = 200, noise = true, noise_per_mille = 250, simulation_mutations = true, mutations_per_mille = 100 } +simulation_arguments = { generations = 10, rounds = 200, noise = true, noise_per_mille = 250, simulation_mutations = true, mutations_per_mille = 100, pool_size = 4 } simulation_data_output = "examples/rounds/mutable_noisy_complete_generational_mss.json" simulation_results_output = "examples/results/mutable_noisy_complete_generational_mss.json" \ No newline at end of file diff --git a/examples/config/mutable_noisy_complete_generational_ss.toml b/examples/config/mutable_noisy_complete_generational_ss.toml index 394b2f5..56d12bf 100644 --- a/examples/config/mutable_noisy_complete_generational_ss.toml +++ b/examples/config/mutable_noisy_complete_generational_ss.toml @@ -1,12 +1,12 @@ simulation_id = "Mutable Noisy Complete StandardGenerationalSimulation for StandardSimulation" algorithms_directory = "examples/algorithms/" -nodes = [ { node_id = "always_cooperate", algorithm = { file = "simple.py", object = "AlwaysCooperate" } }, - { node_id = "always_defect", algorithm = { file = "simple.py", object = "AlwaysDefect" } }, - { node_id = "grim_trigger", algorithm = { file = "grudge.py", object = "GrimTrigger" } }, - { node_id = "random_cooperation", algorithm = { file = "simple.py", object = "RandomCooperation" } }, - { node_id = "tit_for_tat", algorithm = { file = "tit_for_tat.py", object = "TitForTat" } }, - { node_id = "tit_for_two_tats", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" } }, - { node_id = "two_tits_for_tat", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" } } ] +nodes = [ { node_id = "always_cooperate_", algorithm = { file = "simple.py", object = "AlwaysCooperate"}, quantity = 10 }, + { node_id = "always_defect_", algorithm = { file = "simple.py", object = "AlwaysDefect" }, quantity = 10 }, + { node_id = "grim_trigger_", algorithm = { file = "grudge.py", object = "GrimTrigger" }, quantity = 10 }, + { node_id = "random_cooperation_", algorithm = { file = "simple.py", object = "RandomCooperation" }, quantity = 10 }, + { node_id = "tit_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TitForTat" }, quantity = 10 }, + { node_id = "tit_for_two_tats_", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" }, quantity = 10 }, + { node_id = "two_tits_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" }, quantity = 10 } ] simulation = { object = "StandardGenerationalSimulation" } generational_simulation = { object = 'StandardSimulation' } simulation_arguments = { generations = 10, rounds = 200, noise = true, noise_per_mille = 250, simulation_mutations = true, mutations_per_mille = 100 } diff --git a/examples/config/noisy_complete_generational_mss.toml b/examples/config/noisy_complete_generational_mss.toml index 209b67d..23949d2 100644 --- a/examples/config/noisy_complete_generational_mss.toml +++ b/examples/config/noisy_complete_generational_mss.toml @@ -1,14 +1,14 @@ simulation_id = "Noisy Complete StandardGenerationalSimulation for MultiprocessStandardSimulation" algorithms_directory = "examples/algorithms/" -nodes = [ { node_id = "always_cooperate", algorithm = { file = "simple.py", object = "AlwaysCooperate" } }, - { node_id = "always_defect", algorithm = { file = "simple.py", object = "AlwaysDefect" } }, - { node_id = "grim_trigger", algorithm = { file = "grudge.py", object = "GrimTrigger" } }, - { node_id = "random_cooperation", algorithm = { file = "simple.py", object = "RandomCooperation" } }, - { node_id = "tit_for_tat", algorithm = { file = "tit_for_tat.py", object = "TitForTat" } }, - { node_id = "tit_for_two_tats", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" } }, - { node_id = "two_tits_for_tat", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" } } ] +nodes = [ { node_id = "always_cooperate_", algorithm = { file = "simple.py", object = "AlwaysCooperate"}, quantity = 10 }, + { node_id = "always_defect_", algorithm = { file = "simple.py", object = "AlwaysDefect" }, quantity = 10 }, + { node_id = "grim_trigger_", algorithm = { file = "grudge.py", object = "GrimTrigger" }, quantity = 10 }, + { node_id = "random_cooperation_", algorithm = { file = "simple.py", object = "RandomCooperation" }, quantity = 10 }, + { node_id = "tit_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TitForTat" }, quantity = 10 }, + { node_id = "tit_for_two_tats_", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" }, quantity = 10 }, + { node_id = "two_tits_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" }, quantity = 10 } ] simulation = { object = "StandardGenerationalSimulation" } generational_simulation = { object = 'MultiprocessStandardSimulation' } -simulation_arguments = { generations = 10, rounds = 200, noise = true, noise_per_mille = 250 } +simulation_arguments = { generations = 10, rounds = 200, noise = true, noise_per_mille = 250, pool_size = 4 } simulation_data_output = "examples/rounds/noisy_complete_generational_mss.json" simulation_results_output = "examples/results/noisy_complete_generational_mss.json" \ No newline at end of file diff --git a/examples/config/noisy_complete_generational_ss.toml b/examples/config/noisy_complete_generational_ss.toml index f83c0b8..fdfb264 100644 --- a/examples/config/noisy_complete_generational_ss.toml +++ b/examples/config/noisy_complete_generational_ss.toml @@ -1,12 +1,12 @@ simulation_id = "Noisy Complete StandardGenerationalSimulation for StandardSimulation" algorithms_directory = "examples/algorithms/" -nodes = [ { node_id = "always_cooperate", algorithm = { file = "simple.py", object = "AlwaysCooperate" } }, - { node_id = "always_defect", algorithm = { file = "simple.py", object = "AlwaysDefect" } }, - { node_id = "grim_trigger", algorithm = { file = "grudge.py", object = "GrimTrigger" } }, - { node_id = "random_cooperation", algorithm = { file = "simple.py", object = "RandomCooperation" } }, - { node_id = "tit_for_tat", algorithm = { file = "tit_for_tat.py", object = "TitForTat" } }, - { node_id = "tit_for_two_tats", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" } }, - { node_id = "two_tits_for_tat", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" } } ] +nodes = [ { node_id = "always_cooperate_", algorithm = { file = "simple.py", object = "AlwaysCooperate"}, quantity = 10 }, + { node_id = "always_defect_", algorithm = { file = "simple.py", object = "AlwaysDefect" }, quantity = 10 }, + { node_id = "grim_trigger_", algorithm = { file = "grudge.py", object = "GrimTrigger" }, quantity = 10 }, + { node_id = "random_cooperation_", algorithm = { file = "simple.py", object = "RandomCooperation" }, quantity = 10 }, + { node_id = "tit_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TitForTat" }, quantity = 10 }, + { node_id = "tit_for_two_tats_", algorithm = { file = "tit_for_tat.py", object = "TitForTwoTats" }, quantity = 10 }, + { node_id = "two_tits_for_tat_", algorithm = { file = "tit_for_tat.py", object = "TwoTitsForTat" }, quantity = 10 } ] simulation = { object = "StandardGenerationalSimulation" } generational_simulation = { object = 'StandardSimulation' } simulation_arguments = { generations = 10, rounds = 200, noise = true, noise_per_mille = 250 } diff --git a/src/project_dilemma/__init__.py b/src/project_dilemma/__init__.py index c528b9d..a43fd51 100644 --- a/src/project_dilemma/__init__.py +++ b/src/project_dilemma/__init__.py @@ -13,6 +13,6 @@ See the License for the specific language governing permissions and limitations under the License. """ -__version__ = '1.0.0' +__version__ = '1.1.0' __all__ = ['config', 'interfaces', 'object_loaders', 'simulations'] diff --git a/src/project_dilemma/config.py b/src/project_dilemma/config.py index 64f0aa0..39a0c65 100644 --- a/src/project_dilemma/config.py +++ b/src/project_dilemma/config.py @@ -17,6 +17,7 @@ class DynamicImport(TypedDict): class NodeConfig(TypedDict): node_id: str algorithm: DynamicImport + quantity: NotRequired[int] class ProjectDilemmaConfig(TypedDict): diff --git a/src/project_dilemma/object_loaders.py b/src/project_dilemma/object_loaders.py index fa7a1d7..6006f9d 100644 --- a/src/project_dilemma/object_loaders.py +++ b/src/project_dilemma/object_loaders.py @@ -22,7 +22,12 @@ def create_nodes(config: ProjectDilemmaConfig, algorithms_map: Dict[str, type[Al nodes = [] for node in config['nodes']: - nodes.append(Node(node['node_id'], algorithms_map[node['algorithm']['object']])) + if not node.get('quantity'): + nodes.append(Node(node["node_id"], algorithms_map[node['algorithm']['object']])) + continue + + for i in range(node['quantity']): + nodes.append(Node(f'{node["node_id"]}{i}', algorithms_map[node['algorithm']['object']])) return nodes