Skip to content

Commit 099b923

Browse files
committed
adding experiments
1 parent be5a5f3 commit 099b923

9 files changed

+223
-54
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ share/python-wheels/
2626
.installed.cfg
2727
*.egg
2828
MANIFEST
29+
data
2930

3031
# PyInstaller
3132
# Usually these files are written by a python script from a template

Game_data.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
class Game_data:
2-
def __init__(self, epoch, player_id, opponent_id, player_decision, opponent_decision, player_strategy, other_strategy, player_util, opponent_util, data) -> None:
2+
def __init__(self, epoch, player_id, opponent_id, player_class, opponent_class, player_decision, opponent_decision, player_strategy, other_strategy, player_util, opponent_util, data) -> None:
33
"""Game data
44
55
Args:
66
epoch (int) : epoch of the game
77
player_id (int) : id of the player
88
opponent_id (int) : id of the opponent
9+
player_class (str) : class of the player
10+
opponent_class (str) : class of the opponent
911
player_decision : decision of the player
1012
opponent_decision : decision of the opponent
1113
player_strategy : strategy the player is currently following
@@ -17,6 +19,8 @@ def __init__(self, epoch, player_id, opponent_id, player_decision, opponent_deci
1719
self.epoch = epoch
1820
self.player_id = player_id
1921
self.opponent_id = opponent_id
22+
self.player_class = player_class
23+
self.opponent_class = opponent_class
2024
self.player_decision = player_decision
2125
self.opponent_decision = opponent_decision
2226
self.player_strategy = player_strategy

Player.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66

77
class Player:
88

9-
def __init__(self, id: int, loc, init_util: float,
9+
def __init__(self, id: int, player_class: str, loc, init_util: float,
1010
play_window: int, migrate_window: int,
1111
imit_prob: float, migrate_prob: float,
1212
sim_state, strategy: Strategy, omega:float) -> None:
1313
"""Base player model
1414
1515
Args:
1616
id (int): Unique identifier of the player
17+
class (str): class name of players with same start parameters
1718
loc ([type]): Current location of the player on the game grid
1819
init_util (float): Initial utility that the player has
1920
play_window (int): Size of the 2-D window in which the player plays against other players - For performance we should keep this equal in all cases
@@ -24,8 +25,9 @@ def __init__(self, id: int, loc, init_util: float,
2425
strategy (Strategy): Strategy that this player follows
2526
omega (float): Shadow of the future
2627
"""
27-
self.id = id
28-
self.loc = loc
28+
self.id = id
29+
self.player_class = player_class
30+
self.loc = loc
2931
self.total_util = init_util
3032
self.play_window = play_window
3133
self.migrate_window = migrate_window
@@ -105,17 +107,18 @@ def _reset(self):
105107
"""
106108
self.latest_util = 0
107109

108-
def add_to_history(self, epoch, opponent_id, player_decision, opponent_decision, player_strategy, other_strategy, opponent_util, data_dict):
110+
def add_to_history(self, epoch, opponent_id, other_class, player_decision, opponent_decision, player_strategy, other_strategy, opponent_util, data_dict):
109111
"""Player adds game to history
110112
111113
Args:
112114
epoch (int) : epoch of the game
113115
other_id (int) : id of the opponent
116+
other_class (str) : class of the opponent
114117
player_decision (0/1) : decision of the player
115118
other_decision (0/1) : decision of the opponent
116119
player_strategy : strategy the player is currently following
117120
other_strategy : strategy the other player is currently following
118121
other_util (float) : utility of the opponent
119122
data_dict : additional data dictionary
120123
"""
121-
self.history.add_game(Game_data(epoch, self.id, opponent_id, player_decision, opponent_decision, player_strategy, other_strategy, self.latest_util, opponent_util, data_dict))
124+
self.history.add_game(Game_data(epoch, self.id, opponent_id, self.player_class, other_class, player_decision, opponent_decision, player_strategy, other_strategy, self.latest_util, opponent_util, data_dict))

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
# CGT21_pd_simulation
1+
# CGT21_pd_simulation
2+
Experiments in experiments.csv can handle two special cases:
3+
1. sets of the form a:b:c -> one experiment for each of the values
4+
2. ranges of the form a;b;c -> one experiment for each of the values in range(a,b,c) where a is the start b is the end and c is the step size

Simulator.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def __init__(self, grid_x: int, grid_y: int,
6868

6969
for idx, p_cfg in enumerate(players):
7070
p_id = idx + 1 # We use this one-time offset to get player ids starting at 1. This allows to use 0 as an empty cell
71-
player = Player(p_id, select_locs[idx], 0, p_cfg["play_window"], p_cfg["migrate_window"],
71+
player = Player(p_id, p_cfg["class"], select_locs[idx], 0, p_cfg["play_window"], p_cfg["migrate_window"],
7272
p_cfg["imit_prob"], p_cfg["migrate_prob"],
7373
self, p_cfg["strategy"], p_cfg["omega"])
7474

@@ -79,7 +79,7 @@ def __init__(self, grid_x: int, grid_y: int,
7979
# Setup policies
8080
self.migration_order_policy = lambda x: x # Identity migration
8181

82-
print("Created Simulator")
82+
#print("Created Simulator")
8383

8484
def _update_location(self, take: int, loc, id: int = None):
8585
""" Updates a location on the grid based on whether it is taken or not.
@@ -223,8 +223,8 @@ def play(self, epoch):
223223
games_played += 1
224224

225225
#add to histories
226-
player_one.add_to_history(epoch, player_two.id, p1_dec, p2_dec, player_one.strategy.name, player_two.strategy.name, player_two.latest_util, {})
227-
player_two.add_to_history(epoch, player_one.id, p2_dec, p1_dec, player_two.strategy.name, player_one.strategy.name, player_one.latest_util, {})
226+
player_one.add_to_history(epoch, player_two.id, player_two.player_class, p1_dec, p2_dec, player_one.strategy.name, player_two.strategy.name, player_two.latest_util, {})
227+
player_two.add_to_history(epoch, player_one.id, player_one.player_class, p2_dec, p1_dec, player_two.strategy.name, player_one.strategy.name, player_one.latest_util, {})
228228

229229

230230
#print(f"Total games: {games_played}")

Taskrunner.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from queue import Empty
55
import time
66
from Simulator import Simulator
7-
from test_simulator import generate_players
7+
from test_simulator import generate_simple_players
88

99
class SimulatorProcess(mp.Process):
1010

@@ -31,7 +31,7 @@ def run(self):
3131
self.strats = next_task.msg_content['strategies']
3232
self.step_size =next_task.msg_content['step-size']
3333
# Reset the simulation here
34-
player_cfgs = generate_players( next_task.msg_content['strategies'],
34+
player_cfgs = generate_simple_players( next_task.msg_content['strategies'],
3535
next_task.msg_content['counts'],
3636
next_task.msg_content['play_window'],
3737
next_task.msg_content['migrate_window'],

experiments.csv

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#test1
2+
T, R, S, P, runs, epochs, grid_x, grid_y
3+
1, 1, 1, 1, 10, 100, 10, 10
4+
nr, strat, imit_prob, migrate_prob, omega
5+
1;2;1, RANDOM:TFT, .8, .8, .5
6+
1, TF2T, .8, .8, .5
7+
8+
#test2
9+
T, R, S, P, runs, epochs, grid_x, grid_y
10+
1, 1, 1, 1, 10, 100, 10, 10
11+
nr, strat, imit_prob, migrate_prob, omega
12+
1:3, RANDOM, .5;.7;.1, .8, .5

run_experiments.py

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import numpy as np
2+
import test_simulator
3+
from Simulator import Simulator
4+
import os
5+
from tqdm.contrib.concurrent import process_map
6+
7+
def read_file(file_name):
8+
experiments = []
9+
nr_experiments = 0
10+
with open(file_name, mode='r') as csv_file:
11+
lines = csv_file.read().splitlines()
12+
for line in lines:
13+
if len(line) == 0:
14+
continue
15+
elif line[0] == '#':
16+
experiments.append({'name': line[1:], 'params': {}, 'players': [], 'changed_keys': {}})
17+
read_ind = 1
18+
nr_experiments = nr_experiments + 1
19+
nr_players = 0
20+
elif read_ind == 1:
21+
param_keys = line.split(', ')
22+
read_ind = read_ind + 1
23+
elif read_ind == 2:
24+
param_values = line.split(', ')
25+
assert len(param_keys)==len(param_values), f"Missing values in parameters of experiment {nr_experiments}"
26+
for key_i in range(len(param_keys)):
27+
experiments[-1]['params'][param_keys[key_i]] = param_values[key_i]
28+
read_ind = read_ind + 1
29+
elif read_ind == 3:
30+
read_ind = 0
31+
keys = line.split(', ')
32+
nr_keys = len(keys)
33+
else:
34+
values = line.split(', ')
35+
assert len(values)==nr_keys, f"Missing values in player {nr_players} of experiment {nr_experiments}"
36+
params = {}
37+
for i in range(nr_keys):
38+
params[keys[i]] = values[i]
39+
params['id'] = nr_players
40+
experiments[-1]['players'].append(params)
41+
nr_players = nr_players + 1
42+
return experiments
43+
44+
def expand_players(experiments):
45+
for exp_i in range(len(experiments)):
46+
keys = list(experiments[exp_i]['players'][0].keys())
47+
for pl_i in range(len(experiments[exp_i]['players'])):
48+
for key_i in range(len(keys)):
49+
param = experiments[exp_i]['players'][pl_i][keys[key_i]]
50+
if isinstance(param, str) and (';' in param or ':' in param):
51+
expanded_exp = []
52+
if ':' in param:
53+
values = param.split(':')
54+
else:
55+
start, end, step = param.split(';')
56+
values = np.arange(float(start), float(end)+float(step), float(step))
57+
for value in values:
58+
temp_exp = experiments[exp_i].copy()
59+
temp_exp['players'] = experiments[exp_i]['players'].copy()
60+
temp_exp['players'][pl_i] = experiments[exp_i]['players'][pl_i].copy()
61+
if not pl_i in temp_exp['changed_keys']:
62+
temp_exp['changed_keys'][pl_i] = []
63+
if not keys[key_i] in temp_exp['changed_keys'][pl_i]:
64+
temp_exp['changed_keys'][pl_i].append(keys[key_i])
65+
temp_exp['players'][pl_i][keys[key_i]] = value
66+
expanded_exp.append(temp_exp)
67+
if exp_i != 0:
68+
expanded_exp = experiments[:exp_i] + expanded_exp
69+
if exp_i != len(experiments)-1:
70+
expanded_exp = expanded_exp + experiments[exp_i+1:]
71+
return expand_players(expanded_exp)
72+
return experiments
73+
74+
def convert_values(experiments):
75+
for exp in experiments:
76+
for param in exp['params']:
77+
if param in ['T', 'R', 'S', 'P']:
78+
exp['params'][param] = float(exp['params'][param])
79+
elif param in ['grid_x', 'grid_y', 'epochs', 'runs']:
80+
exp['params'][param] = int(float(exp['params'][param]))
81+
else:
82+
assert False, f"Parameter {key} not implemented for experiments"
83+
for player in exp['players']:
84+
for key in player.keys():
85+
if key in ['strat']:
86+
continue
87+
elif key in ['id', 'nr']:
88+
player[key] = int(float(player[key]))
89+
elif key in ['imit_prob', 'migrate_prob', 'omega']:
90+
player[key] = float(player[key])
91+
else:
92+
assert False, f"Key {key} not implemented for experiments"
93+
#add changed keys to name
94+
player_changes = []
95+
for p_i in range(len(exp['players'])):
96+
changes = []
97+
if p_i in exp['changed_keys']:
98+
for key in exp['changed_keys'][p_i]:
99+
changes.append(f'{key}-{exp["players"][p_i][key]}')
100+
player_changes.append(f"{p_i}:{'_'.join(changes)}")
101+
exp['name'] = exp['name'] + ''.join([f'_({change})' for change in player_changes])
102+
103+
return experiments
104+
105+
def class_name(player):
106+
return f"{player['strat']}_imitP-{player['imit_prob']}_migrateP-{player['migrate_prob']}_omega-{player['omega']}"
107+
108+
def run_experiment(experiment):
109+
player_cfgs = []
110+
classes = []
111+
num_players = 0
112+
for player in experiment['players']:
113+
player_class = class_name(player)
114+
for i in range(player['nr']):
115+
player_cfgs.append(test_simulator.generate_player(player['strat'], player_class, 1, 3, player['imit_prob'], player['migrate_prob'], player['omega']))
116+
num_players = num_players + player['nr']
117+
if player_class not in classes:
118+
classes.append(player_class)
119+
120+
results = {''}
121+
for r in range(experiment['params']['runs']):
122+
sim = Simulator(experiment['params']['grid_x'], experiment['params']['grid_y'], num_players, 1, 3, player_cfgs, experiment['params']['T'], experiment['params']['R'], experiment['params']['S'], experiment['params']['P'])
123+
sim.simulate(experiment['params']['epochs'], visualize=False)
124+
state = sim.get_state()
125+
126+
127+
if not os.path.exists('data'):
128+
os.makedirs('data')
129+
with open(f"data/{experiment['name']}.csv", "w") as file:
130+
#Waiting for analysis rework --> no results saved yet
131+
file.write("Done\n")
132+
133+
134+
if __name__ == "__main__":
135+
experiments = read_file('experiments.csv')
136+
experiments = expand_players(experiments)
137+
experiments = convert_values(experiments)
138+
if False:
139+
for exp in experiments:
140+
print(exp)
141+
142+
process_map(run_experiment, experiments) #max_workers=8
143+
144+

0 commit comments

Comments
 (0)