source: CSE3210/agent18/optimizer.py

Last change on this file was 74, checked in by wouter, 21 months ago

#6 Added CSE3210 parties

File size: 10.6 KB
Line 
1import curses
2import itertools
3import os
4import random
5import time
6from multiprocessing import Process, Manager
7
8from Group18_NegotiationAssignment_Agent import Group18_NegotiationAssignment_Agent
9from utils.runners import run_tournament
10
11from Group18_NegotiationAssignment_Project.Group18_NegotiationAssignment_Agent.ranker import *
12
13class AgentProcess:
14 def __init__(self, id, process, return_dict):
15 self.id = id
16 self.process = process
17 self.return_dict = return_dict
18 return_dict[f"status_{self.id}"] = self.get_starting()
19
20 def get_score(self):
21 return return_dict[f"score_{self.id}"]
22
23 def get_status(self):
24 return return_dict[f"status_{self.id}"]
25
26 @staticmethod
27 def get_finished():
28 return f"Process --: finished!"
29
30 @staticmethod
31 def get_starting():
32 return f"Process --: starting process..."
33
34 @staticmethod
35 def get_waiting():
36 return f"Process --: waiting for process..."
37
38 def start(self):
39 return self.process.start()
40
41 def join(self):
42 return self.process.join()
43
44 def is_alive(self):
45 return self.process.is_alive()
46
47
48class HiddenPrints:
49 def __enter__(self):
50 self._original_stdout = sys.stdout
51 sys.stdout = open(os.devnull, 'w')
52
53 def __exit__(self, exc_type, exc_val, exc_tb):
54 sys.stdout.close()
55 sys.stdout = self._original_stdout
56
57
58def mutant_filename(i, my_agent):
59 split_agent_string = my_agent.split('.')
60 split_agent_string[2] = split_agent_string[2] + f"_calibration_temp_{i}"
61 return '.'.join(split_agent_string)
62
63
64def agent_worker(i, my_file, my_agent, deadline_rounds, sample_size, num_domains, agent_pool, domains, thresholds,
65 counter, start, return_dict):
66 proc_num = i + 1
67 start_agent = time.time()
68 out = open(my_file[:len(my_file) - 3] + f"_calibration_temp_{i}.py", 'w')
69 with open(my_file, "r") as f:
70 lines = f.readlines()
71 for index, line in enumerate(lines):
72 if "self.thresholds: [float] = [" in line:
73 lines[index] = f" self.thresholds: [float] = {thresholds[i]}\n"
74 break
75 out.writelines(lines)
76 out.close()
77 new_agent = mutant_filename(i, my_agent)
78 results = []
79 agent_iter = itertools.cycle(agent_pool)
80 for j in range(sample_size):
81 pick = [new_agent, next(agent_iter)]
82 settings = {
83 "agents": pick,
84 "profile_sets": random.sample(domains, k=num_domains),
85 "deadline_rounds": deadline_rounds,
86 }
87 with HiddenPrints():
88 results_trace, results_summary = run_tournament(settings, new_agent, verbose=False)
89 results.append(results_summary)
90 # add the result of the process to the return data structure
91 return_dict[f"status_{i}"] = \
92 f"Thresholds {int(proc_num):-2}: [{''.join(['=' if k <= j else '_' for k in range(sample_size)])}] |" \
93 f" process runtime: {int(time.time() - start_agent):-3}s"
94 return_dict[f"status_{i}"] = AgentProcess.get_finished()
95 score = metric(results)
96 return_dict[f"score_{i}"] = score[new_agent.split('.')[-1]]
97
98
99def report_progress(stdscr, outs):
100 stdscr.clear()
101 # If the programme crashes with "_curses.error: addwstr() returned ERR", resize the console bigger
102 for n, out in enumerate(outs):
103 stdscr.addstr(n, 0, out)
104 stdscr.refresh()
105
106
107def refresh_console_output(stdscr, active_processes, num_processes_left, num_total, epoch, number_of_epochs):
108 output = [f"[Epoch {epoch+1} / {number_of_epochs}] Processes [remaining/active/finished/total]: "
109 f"[{num_processes_left}/{len(active_processes)}/{num_total - num_processes_left - len(active_processes)}/{num_total}]"]
110 for id, process in enumerate(active_processes):
111 try:
112 if process:
113 output.append(process.get_status())
114 else:
115 raise KeyError
116 except KeyError:
117 output.append(AgentProcess.get_waiting())
118 output.append(f"Overall runtime: {int(time.time() - start):-3}s")
119 report_progress(stdscr, output)
120
121
122def pick_thresholds(number_of_agents, reff):
123 thresholds = []
124 number_of_thresholds = len(reff.thresholds)
125 for _ in range(number_of_agents):
126 temp = []
127 i = 0
128 while len(temp) != number_of_thresholds:
129 pick = random.uniform(reff.threshold_checks[i][0], reff.threshold_checks[i][1])
130 temp.append(pick)
131 i += 1
132 thresholds.append(temp)
133 return thresholds
134
135
136if __name__ == '__main__':
137 # create results directory if it does not exist
138 if not os.path.exists("results"):
139 os.mkdir("results")
140
141 agent_pool = {
142 "Shreker": "agents.shreker.shreker.Shreker",
143 "AveragedTitForTat": "agents.averaged_tit_for_tat_agent.averaged_tit_for_tat_agent.AveragedTitForTat",
144 "TradeOffAgent": "agents.trade_off_agent.trade_off_agent.TradeOffAgent",
145 "SocialWelfareAgent": "agents.social_welfare_agent.social_welfare_agent.SocialWelfareAgent",
146 "BoulwareAgent": "agents.boulware_agent.boulware_agent.BoulwareAgent",
147 "ConcederAgent": "agents.conceder_agent.conceder_agent.ConcederAgent",
148 "HardlinerAgent": "agents.hardliner_agent.hardliner_agent.HardlinerAgent",
149 "ConcedeOneAgent": "agents.concede_one_agent.concede_one_agent.ConcedeOneAgent",
150 "LinearAgent": "agents.linear_agent.linear_agent.LinearAgent",
151 "RandomAgent": "agents.random_agent.random_agent.RandomAgent",
152 "TimeDependentAgent": "agents.time_dependent_agent.time_dependent_agent.TimeDependentAgent",
153 "AgreeableAgent": "agents.agreeable_agent.agreeable_agent.AgreeableAgent"
154 }
155 domains = [
156 ["domains/domain00/profileA.json", "domains/domain00/profileB.json"],
157 ["domains/domain01/profileA.json", "domains/domain01/profileB.json"],
158 ["domains/domain02/profileA.json", "domains/domain02/profileB.json"],
159 ["domains/domain03/profileA.json", "domains/domain03/profileB.json"],
160 ["domains/domain04/profileA.json", "domains/domain04/profileB.json"],
161 ["domains/domain05/profileA.json", "domains/domain05/profileB.json"],
162 ["domains/domain06/profileA.json", "domains/domain06/profileB.json"],
163 ["domains/domain07/profileA.json", "domains/domain07/profileB.json"],
164 ["domains/domain08/profileA.json", "domains/domain08/profileB.json"],
165 ["domains/domain09/profileA.json", "domains/domain09/profileB.json"],
166 ]
167 sample_size = 50 # How many times to run your agent against another random agent in several random domains
168 number_of_agents = 20 # How many times to generate random thresholds for your agent
169 max_num_processes = 10 # How many processes to run at once
170 num_domains = 10 # How many unique domains within which to run the agents.
171 number_of_epochs = 5 # How many epochs between sets of agents will take place
172 # All data needed to create an agent mutant
173 deadline_rounds = 100
174 references = {
175 "agents.shreker.shreker.Shreker": [Group18_NegotiationAssignment_Agent(), "agents/shreker/shreker.py"],
176 }
177
178 counter = 1
179 start = time.time()
180 manager = Manager()
181 return_dict = manager.dict() # For getting scores out of the processes
182 results = None
183
184 # Displaying multiline output
185 stdscr = curses.initscr()
186 curses.noecho()
187 curses.cbreak()
188 # Iterate over all epochs
189 for epoch in range(number_of_epochs):
190 # Fill process queue with all processes
191 process_queue = []
192 ranking = dict()
193 id_to_agent = dict()
194
195 for index, my_agent in enumerate(references):
196 thresholds = pick_thresholds(len(references) * number_of_agents, references[my_agent][0])
197 for n in range(number_of_agents):
198 id_to_agent[index * number_of_agents + n] = mutant_filename(index * number_of_agents + n, my_agent)
199 python_process = Process(
200 target=agent_worker,
201 args=(index * number_of_agents + n, references[my_agent][1], my_agent, deadline_rounds, sample_size,
202 num_domains, list(agent_pool.values()), domains, thresholds, counter, start, return_dict)
203 )
204 agent_process = AgentProcess(index * number_of_agents + n, python_process, return_dict)
205 process_queue.append(agent_process)
206
207 active_processes = np.empty(np.min([max_num_processes, len(references) * number_of_agents]), dtype=Process)
208 process_queue.reverse()
209 processes = []
210 while len(process_queue) != 0 or any(map(lambda p: not p or p.is_alive(), active_processes)):
211 refresh_console_output(stdscr, active_processes, len(process_queue), number_of_agents, epoch, number_of_epochs)
212 for i in range(10):
213 time.sleep(0.5)
214 if len(process_queue) != 0:
215 for i in range(len(active_processes)):
216 if not active_processes[i] or not active_processes[i].is_alive():
217 next_process = process_queue.pop()
218 next_process.start()
219 active_processes[i] = next_process
220 processes.append(next_process)
221 break
222 for process in processes:
223 ranking[id_to_agent[process.id]] = process.get_score()
224 # Prepare agent pool for the next epoch by replacing with calibrated agents
225 results = sorted([agent for agent in ranking], key=lambda agent: ranking[agent])[:10]
226 visited = []
227 for agent in results:
228 if agent in visited:
229 continue
230 temp = agent.split('.')
231 my_file = '/'.join(temp[:-1]) + '.py'
232 out = open(temp[0] + '/' + temp[1] + f"/{temp[-1]}_calibration_saved_epoch_{epoch}.py", 'w')
233 with open(my_file, "r") as f:
234 lines = f.readlines()
235 out.writelines(lines)
236 out.close()
237 temp[-2] = f"{temp[-1]}_calibration_saved_epoch_{epoch}"
238 agent_pool[agent.split('.')[-1]] = '.'.join(temp)
239 visited.append(agent)
240
241 curses.echo()
242 curses.nocbreak()
243 curses.endwin()
244
245 print(f"Total time taken: {int(time.time() - start):-3}s")
246 # Pick the top 10 scores
247 time_str = time.strftime("%Y%m%d-%H%M%S")
248 w = open(f"metric_{time_str}.log", "w")
249 w.write(f"Top 10 metric agents: \n")
250 [w.write(str(tup) + "\n") for tup in results]
251 w.close()
Note: See TracBrowser for help on using the repository browser.