mg-pso-gui 0.2.125__py3-none-any.whl → 0.2.126__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mg-pso-gui
3
- Version: 0.2.125
3
+ Version: 0.2.126
4
4
  Summary: GUI for MG-PSO
5
5
  Author: Robert Cordingly
6
6
  Author-email: <rcording@uw.ed>
@@ -1,7 +1,7 @@
1
1
  mgpsogui/__init__.py,sha256=q7AfBjeJABnFtbsZnsObpUwaXKPDVYtz46G6MKXLF74,42
2
2
  mgpsogui/mgpsogui.py,sha256=NIZmyNcbwC8EgSwf1ubdMUSJscrIEgoD4jLYziqHQ-k,148
3
3
  mgpsogui/start.yaml,sha256=ZjCVLb-MLqAxrGRm9kA7_SDpa-45EuKIELNQ2QqCAiU,4713
4
- mgpsogui/gui/HomePage.py,sha256=N_0FGZ8R6fiMBHiNWYNMM8h3QvudteaJ_Fq5GDxoPug,26053
4
+ mgpsogui/gui/HomePage.py,sha256=fTGAuCUBWaydSe0t7HO95snJ1B6j2xa5GJcEJSLymBA,25974
5
5
  mgpsogui/gui/OptionManager.py,sha256=t0aXOeBo48qQ-P8OykpP2v_3KJoaJtUPSkYtacjloCc,22844
6
6
  mgpsogui/gui/OptionManager_backup.py,sha256=TCWfPnHL2foN5id47jsi267lamRG6yGU6y_M29eOOJk,18530
7
7
  mgpsogui/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -19,7 +19,7 @@ mgpsogui/gui/SetupTab/CustomFunctionEditorWindow.py,sha256=lZ9a20YucwhCDiUN3eGA6
19
19
  mgpsogui/gui/SetupTab/CustomFunctionMetrics.py,sha256=vOJpElbTgz043m6JYwe9xz_2MBHg985S6KdbJkJERW4,5923
20
20
  mgpsogui/gui/SetupTab/FunctionsList.py,sha256=wmYmppyB5y8QADe3X_FQ5mAYVDC0HAPQgqtkegNwmLA,7007
21
21
  mgpsogui/gui/SetupTab/ListEditor.py,sha256=nin7Pl8z7d_yfKoAxM-yVS34uhj-LnprJ2mNRSB7Z0A,3197
22
- mgpsogui/gui/SetupTab/ListParametersView.py,sha256=mkGaC5cXhEOy5oD0MbTyK9z7VGZp019oK2Y8Ay-n05Q,7460
22
+ mgpsogui/gui/SetupTab/ListParametersView.py,sha256=CdK7OVdccwk0_OLgrwwNFTHuV2hMvETsocQIKndZoV4,7459
23
23
  mgpsogui/gui/SetupTab/OverrideParameterMetrics.py,sha256=rBfaSitYDOajbHvyi2TfoXAHYlz1cCt028UVpIJ_Dc0,3369
24
24
  mgpsogui/gui/SetupTab/OverrideParameterWindow.py,sha256=1UJHel0BH4sYa5WQnuSaFd3cdpRwAIwOpFIbhDS30IY,1824
25
25
  mgpsogui/gui/SetupTab/SamplingListView.py,sha256=DhZBAhDcrqZn1XioCs1gTe_v-8W10C0UfPm0fLAbeXM,5260
@@ -58,7 +58,9 @@ mgpsogui/util/CTkToolTip/ctk_tooltip.py,sha256=SZMovpQIGvdpDRbqCKl9SHs92DrFCO2MO
58
58
  mgpsogui/util/recosu/__init__.py,sha256=pPR0lB6clIi6q73H1W8eT5u0dd3bIemwa9-XFmOaVVk,279
59
59
  mgpsogui/util/recosu/pso/__init__.py,sha256=PQ548aEKVOk6MMzxxDg7yMO_1hHfoEoYLLkGLeij73Y,247
60
60
  mgpsogui/util/recosu/pso/csip_access.py,sha256=_oA71d6CSwhKSa3pgywIW7mXRJtgJTNu1X2DiBkQkuA,4152
61
- mgpsogui/util/recosu/pso/pso.py,sha256=qUwpp6gjhCTXA6twKGAda84HIeQebKGB6MJ4K9GfcdM,23181
61
+ mgpsogui/util/recosu/pso/pso modified.py,sha256=sFY1csASu5Os5SSheWWdpVcjpPwJeBqZKsv89DLXdxk,21648
62
+ mgpsogui/util/recosu/pso/pso.py,sha256=iPqT6aI1vi8LYuWmtxuHkLEM9sQwhUznPInBgps7ANI,13708
63
+ mgpsogui/util/recosu/pso/pso_new.py,sha256=qUwpp6gjhCTXA6twKGAda84HIeQebKGB6MJ4K9GfcdM,23181
62
64
  mgpsogui/util/recosu/sampling/__init__.py,sha256=dWs1MPx0o2UFmOmUfFaomQWBTIZAwALsVJzZQNZePZU,252
63
65
  mgpsogui/util/recosu/sampling/sample_trace_writer.py,sha256=M9w-POLlZgjL5a7J7yxr73OG6mCsS2aUuP9d3HKfkbA,1966
64
66
  mgpsogui/util/recosu/sampling/sampler_task.py,sha256=uZobpR83u6xEaUzIknvW9FbB84c2AL7T-5T8O8QIhzY,2776
@@ -73,8 +75,8 @@ mgpsogui/util/recosu/utils/trace_writer.py,sha256=V9BJlOjCbNYGoXGEk3CF5wjifBxvar
73
75
  mgpsogui/util/recosu/utils/utils.py,sha256=6MIoJb0nhIa4tNv7qhBfZi-AtL3L95CgJf6eAf12NQs,4140
74
76
  mgpsogui/util/recosu/utils/plot/__init__.py,sha256=h1KjM7_tNDv351pcwt8A6Ibb1jhwWyx5Gbu-zj-sI3Q,71
75
77
  mgpsogui/util/recosu/utils/plot/cost_steps.py,sha256=1Ce11AJyweWkmvjXPxEygzS-h8yVLmQEDLS53yjPLqQ,3779
76
- mg_pso_gui-0.2.125.dist-info/METADATA,sha256=1cfBNFu2xvNbvbzQQKz2JtmCFVC5Z49qKHPxNW0oWB4,9542
77
- mg_pso_gui-0.2.125.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
78
- mg_pso_gui-0.2.125.dist-info/entry_points.txt,sha256=jg82VOFjR1XDGrchs1wJSCqKYE4Ozv12aBcCSp--koA,117
79
- mg_pso_gui-0.2.125.dist-info/top_level.txt,sha256=y7JuS9xJN5YdxUsQ3PSVjN8MzQAnR146bP3ZN3PYWdE,9
80
- mg_pso_gui-0.2.125.dist-info/RECORD,,
78
+ mg_pso_gui-0.2.126.dist-info/METADATA,sha256=WoBCQFVK_l0TIamnui7_FpcDK8hr6Tc0-a5kYKXAQV0,9542
79
+ mg_pso_gui-0.2.126.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
80
+ mg_pso_gui-0.2.126.dist-info/entry_points.txt,sha256=jg82VOFjR1XDGrchs1wJSCqKYE4Ozv12aBcCSp--koA,117
81
+ mg_pso_gui-0.2.126.dist-info/top_level.txt,sha256=y7JuS9xJN5YdxUsQ3PSVjN8MzQAnR146bP3ZN3PYWdE,9
82
+ mg_pso_gui-0.2.126.dist-info/RECORD,,
mgpsogui/gui/HomePage.py CHANGED
@@ -145,7 +145,7 @@ class App(customtkinter.CTk):
145
145
  self.sidebar_frame.grid_columnconfigure(4, weight=1)
146
146
  self.logo_label = customtkinter.CTkLabel(self.sidebar_frame, text="COSU Manager (" + version + ")", font=customtkinter.CTkFont(size=20, weight="bold"))
147
147
  self.logo_label.grid(row=0, column=0, padx=(20, 10), pady=header_padding_y)
148
- self.save_button = customtkinter.CTkButton(self.sidebar_frame, text="Save", width=60, command=self.save_project)
148
+ self.save_button = customtkinter.CTkButton(self.sidebar_frame, text="Save As", width=60, command=self.save_project)
149
149
  self.save_button.grid(row=0, column=1, padx=header_padding_x, pady=header_padding_y)
150
150
  self.load_button = customtkinter.CTkButton(self.sidebar_frame, text="Load", width=60, command=self.load_project)
151
151
  self.load_button.grid(row=0, column=2, padx=header_padding_x, pady=header_padding_y)
@@ -258,11 +258,11 @@ class App(customtkinter.CTk):
258
258
  os.makedirs(os.path.join(folder, "results"))
259
259
 
260
260
  self.save_button.configure(text="Saved!")
261
- self.after(3000, lambda: self.save_button.configure(text="Save"))
261
+ self.after(3000, lambda: self.save_button.configure(text="Save As"))
262
262
  except Exception as e:
263
263
  self.save_button.configure(text="Error!")
264
264
  print(e)
265
- self.after(3000, lambda: self.save_button.configure(text="Save"))
265
+ self.after(3000, lambda: self.save_button.configure(text="Save As"))
266
266
 
267
267
  def auto_save_project(self):
268
268
  data = self.option_manager.get_project_data()
@@ -281,8 +281,6 @@ class App(customtkinter.CTk):
281
281
  if not os.path.exists(os.path.join(folder, "results")):
282
282
  os.makedirs(os.path.join(folder, "results"))
283
283
 
284
- self.save_button.configure(text="Saved!")
285
- self.after(1000, lambda: self.save_button.configure(text="Save"))
286
284
  except Exception as e:
287
285
  self.save_button.configure(text="Error!")
288
286
  print(e)
@@ -445,6 +443,8 @@ class App(customtkinter.CTk):
445
443
  NW(title="Error", message="A process is already running!", x = 400, y = 200)
446
444
  return 0
447
445
 
446
+ self.auto_save_project()
447
+
448
448
  data = self.option_manager.get_all_data()
449
449
  mode = self.option_manager.get_mode()
450
450
  data = data[mode]
@@ -138,7 +138,7 @@ class ListParametersView(CTkScrollableFrame):
138
138
  row += 1
139
139
 
140
140
  CTkButton(self.containerFrame, text="Open", command=self.open_csv).grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="ew")
141
- CTkButton(self.containerFrame, text="Import", command=self.import_csv).grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="ew")
141
+ CTkButton(self.containerFrame, text="Paste", command=self.import_csv).grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="ew")
142
142
  row += 1
143
143
 
144
144
 
@@ -0,0 +1,585 @@
1
+ #
2
+ # $Id:$
3
+ #
4
+ # This file is part of the Cloud Services Integration Platform (CSIP),
5
+ # a Model-as-a-Service framework, API, and application suite.
6
+ #
7
+ # 2012-2020, OMSLab, Colorado State University.
8
+ #
9
+ # OMSLab licenses this file to you under the MIT license.
10
+ # See the LICENSE file in the project root for more information.
11
+ #
12
+ import numpy
13
+
14
+ from ..utils import utils
15
+ from .csip_access import csip_worker
16
+ from pyswarms.single.global_best import GlobalBestPSO
17
+ from os import path
18
+ from threading import Thread
19
+ from typing import Dict, List, Set, Tuple
20
+ import numpy as np
21
+ import copy
22
+ import datetime
23
+ import queue
24
+ import json
25
+ import os
26
+
27
+ cost2 = {}
28
+
29
+
30
+ def eval_cost(x, iteration, step_param, step_objfunc, calib_params, req_queue, files, url, param, conf: Dict, rnd,
31
+ step):
32
+ particles = len(x[:, 0])
33
+
34
+ pfail_count = conf.get('particles_fail', 1) # Number of particles allowed to fail.
35
+ pfail_retry = conf.get('particles_retry', 3) # retry number of times if more than allowed fail
36
+
37
+ while pfail_retry > 0:
38
+ cost = np.ones(particles)
39
+ res_queue = queue.Queue()
40
+
41
+ print(' ', end='', flush=True)
42
+
43
+ # submit for processing
44
+ # for i_particle, v in enumerate(x[:, 0]):
45
+ for particle in range(particles):
46
+ req_queue.put((rnd, step, iteration, particle, x, step_param, calib_params, step_objfunc, res_queue))
47
+ # print(' rnd: ', rnd)
48
+ # print(' step: ', step)
49
+ # print(' interation: ', iteration)
50
+ # print(' particle: ', particle)
51
+ # print(' x[particle,:]: ', x[particle,:])
52
+
53
+ # req_queue.put((i_particle, x[i_particle,:], step_param_names, calib_params, step_objfunc, res_queue))
54
+
55
+ # wait for the cost value to come back
56
+ # for i, v in enumerate(x[:, 0]):
57
+ for idx in range(particles):
58
+ (particle, p_cost) = res_queue.get()
59
+ cost[particle] = p_cost
60
+ cost1 = []
61
+ cost1.append(iteration)
62
+ cost1.append(p_cost)
63
+ cost1.append(str('r{}s{}i{}p{}.json'.format(rnd, step, iteration, particle)))
64
+
65
+ if particle not in cost2:
66
+ cost2[particle] = []
67
+
68
+ cost2[particle].append(cost1)
69
+
70
+ res_queue.task_done()
71
+
72
+ res_queue.join()
73
+
74
+ # replace the 'nan' cost values (failed/missing runs) with the mean of the
75
+ # rest of the cost values, hence ignore it
76
+
77
+ # print("cost ", cost)
78
+ nan_idx = np.where(np.isnan(cost))
79
+ failed_particles = len(nan_idx[0])
80
+
81
+ # leave the loop if fails acceptable
82
+ if failed_particles <= pfail_count:
83
+ break
84
+ print("Re-running particles, since ", failed_particles, ' out of ', particles, ' particles failed.')
85
+ pfail_retry -= 1
86
+
87
+ if pfail_retry == 0:
88
+ print('Particle evaluation failed ', conf.get('particles_retry', 3), ' times. PSO stopped.')
89
+ return None
90
+
91
+ # print("mean ", mean)
92
+ # assign the mean value to all failed runs.
93
+ mean = np.nanmean(cost)
94
+ cost[nan_idx[0]] = mean
95
+
96
+ for key in cost2:
97
+ # print(key, ' - ', cost2[key])
98
+ cost2[key][iteration][1] = cost[key]
99
+ # print(key, ' - ', cost2[key])
100
+
101
+ print(flush=True)
102
+ return cost
103
+
104
+
105
+ def global_best(steps: Dict, rounds: Tuple, args: Dict, n_particles: int, iters: int, options: Dict,
106
+ oh_strategy: Dict = None, n_threads: int = 4, rtol: float = 0.001, ftol: float = -np.inf,
107
+ ftol_iter: int = 1, full_trace: List = None, rtol_iter: int = 1,
108
+ conf: Dict = None, metainfo: Dict = None, cost_target: float = -np.inf) -> Tuple:
109
+ """Performs a stepwise particle swarm optimization PSO using a global best approach.
110
+
111
+ Parameters
112
+ ----------
113
+ steps : Dict
114
+ step definitions
115
+ rounds : tuple
116
+ round definition, (min,max) or max
117
+ args : Dict
118
+ static service args
119
+ n_particles : int
120
+ number of particles
121
+ iters : int
122
+ number of iterations
123
+ options : Dict
124
+ PSO options (see pyswarms)
125
+ oh_strategy : Dict
126
+ PSO Option handling strategy (see pyswarms)
127
+ n_threads : int
128
+ size of thread pool (default: 4)
129
+ rtol : float
130
+ percentage of change of sum(best_cost) between rounds for
131
+ convergence. (Default is 0.001 0.1%)
132
+ ftol : float
133
+ PSO tolerance (default: -np.inf)
134
+ ftol_iter : float
135
+ number of iterations over which the relative error in
136
+ objective_func is acceptable for convergence. (default: 1)
137
+ full_trace : List
138
+ trace of all runs, list of tuples
139
+ first is dictionary of parameter names to parameter values
140
+ second is the cost value (default: None)
141
+ rtol_iter : int
142
+ the number of subsequent rounds with sum(best_cost) < rtol
143
+ (default: 1)
144
+ conf : Dict
145
+ configuration settings (default: {} )
146
+ metainfo : Dict
147
+ additional metainfo for the csip client (default: {} )
148
+ cost_target: float
149
+ the cost target (default: -np.inf)
150
+ Returns
151
+ -------
152
+ Tuple
153
+ optimizer: List, step_trace: Dict
154
+
155
+ """
156
+
157
+ utils.check_url(args['url'])
158
+
159
+ step_file = conf.get('step_trace', None)
160
+
161
+ min_rounds = 1
162
+ if type(rounds) == tuple:
163
+ min_rounds = rounds[0]
164
+ max_rounds = rounds[1]
165
+ else:
166
+ max_rounds = rounds
167
+
168
+ if min_rounds < 1:
169
+ raise Exception('min rounds >= 1 expected, was "{}"'.format(min_rounds))
170
+
171
+ if max_rounds > 20:
172
+ raise Exception('max rounds <= 20 expected, was "{}"'.format(max_rounds))
173
+
174
+ if n_threads < 1:
175
+ raise Exception('n_threads >= 1, was "{}"'.format(n_threads))
176
+
177
+ if rtol_iter < 1:
178
+ raise Exception('rtol_iter >= 1, was "{}"'.format(rtol_iter))
179
+
180
+ if full_trace is not None and not isinstance(full_trace, list):
181
+ raise Exception('full_trace must be of type, was "{}"'.format(type(full_trace)))
182
+
183
+ best_cost = np.ones(len(steps)) * np.inf
184
+ optimizer = np.empty(len(steps), dtype=object)
185
+
186
+ # best_pos = {}
187
+ #
188
+ # best_pos[0] = numpy.array([1.18792343e+02, 5.43472746e+01, 7.10091373e+01, 1.80144959e+00,
189
+ # 2.63979951e+00, 4.61775754e+00, 4.84808030e-01, 3.97179059e+00,
190
+ # 4.12612823e+00, 2.29275033e-01, 5.86661573e+01, 4.33933491e-01,
191
+ # 3.80515317e-01, 2.32299702e+01, 1.29697400e+01, 3.94149865e+01,
192
+ # 2.78110081e+01, 1.71484176e+01, 4.59081223e+01, 3.25059995e+01,
193
+ # 3.03662465e+01, 4.15040920e-01, 4.21613876e-01, 4.07747156e-01,
194
+ # 4.32604236e-01, 4.19428929e-01, 4.01926017e-01, 4.36295072e-01,
195
+ # 4.37658392e-01, 4.14423735e-01, 4.39537540e-01, 2.65952198e-01,
196
+ # 2.63096106e-01, 2.24934845e-01, 1.66953435e-01, 2.32302802e-01,
197
+ # 2.55939246e-01, 2.42916828e-01, 2.39205412e-01, 2.79600625e-01,
198
+ # 9.58733328e-02, 8.08481274e-02, 7.34124368e-02, 1.04667432e-01,
199
+ # 1.26246347e-01, 1.14700200e-01, 1.22694002e-01, 7.86003659e-02,
200
+ # 1.34393803e-01])
201
+
202
+ # trace of steps info
203
+ step_trace = {}
204
+
205
+ step_trace['dir'] = os.getcwd()
206
+ step_trace['start'] = str(datetime.datetime.now())
207
+ step_trace['min_rounds'] = min_rounds
208
+ step_trace['max_rounds'] = max_rounds
209
+ step_trace['iters'] = iters
210
+ step_trace['ftol'] = ftol
211
+ step_trace['ftol_iter'] = ftol_iter
212
+ step_trace['rtol'] = rtol
213
+ step_trace['rtol_iter'] = rtol_iter
214
+ step_trace['n_threads'] = n_threads
215
+ step_trace['n_particles'] = n_particles
216
+ step_trace['n_steps'] = len(steps)
217
+ step_trace['steps'] = copy.deepcopy(steps)
218
+ step_trace['args'] = args
219
+
220
+ if step_file is not None:
221
+ with open(step_file, "w") as fo:
222
+ json.dump(step_trace, fo)
223
+
224
+ # best round cost
225
+ best_round_cost = np.inf
226
+
227
+ # request queue for worker
228
+ req_queue = queue.Queue()
229
+
230
+ conf = conf or {}
231
+ done = False
232
+ thread_pool = []
233
+ for thread_no in range(n_threads):
234
+ worker = Thread(target=csip_worker, args=(req_queue, thread_no, lambda: done,
235
+ full_trace, args['url'], args.get('files', None), args['param'],
236
+ conf, metainfo)
237
+ )
238
+ thread_pool.append(worker)
239
+ worker.start()
240
+
241
+ r_below = 0
242
+ early_exit = False
243
+ start_time = datetime.datetime.now()
244
+ for r in range(max_rounds):
245
+ no_improvement = np.full(len(steps), True)
246
+ best_step_request = None
247
+ for s, step in enumerate(steps):
248
+
249
+ # check if forced exit.
250
+ if path.exists("stop"):
251
+ print('\n>>>>> stop file found, exit now.')
252
+ early_exit = True
253
+ break
254
+
255
+ param_names, bounds, objfunc = utils.get_step_info(steps, s)
256
+ # maybe clone args?
257
+ # args['step_param_names'] = param_names
258
+ args['step_param'] = step['param']
259
+ args['step_objfunc'] = objfunc
260
+ # get calibrated parameter from all other steps
261
+ args['calib_params'] = utils.get_calibrated_params(steps, s)
262
+
263
+ args['req_queue'] = req_queue
264
+ args['conf'] = conf
265
+
266
+ # if r < 1:
267
+ # best_pos[s] = np.full(len(param_names), True)
268
+ # best_pos[s] = np.empty(len(param_names), dtype=object)
269
+ # best_pos[s] = None
270
+
271
+ # create optimizer in the first round.
272
+ if optimizer[s] is None:
273
+ # if r <= 1:
274
+ optimizer[s] = GlobalBestPSO(step.get('n_particles', n_particles),
275
+ len(param_names),
276
+ oh_strategy=step.get('oh_strategy', oh_strategy),
277
+ options=step.get('options', options),
278
+ bounds=bounds,
279
+ ftol=step.get('ftol', ftol),
280
+ ftol_iter=step.get('ftol_iter', ftol_iter),
281
+ cost_target=step.get('cost_target', cost_target),
282
+ init_pos=None)
283
+ print('\n>>>>> R{}/S{} particle params: {} calibrated params: {}\n'.format(r + 1, s + 1, param_names,
284
+ args['calib_params']))
285
+
286
+ args['rnd'] = r + 1
287
+ args['step'] = s + 1
288
+
289
+ # perform optimization
290
+ cost, pos = optimizer[s].optimize(eval_cost, iters=step.get('iters', iters), **args)
291
+
292
+ for key in cost2:
293
+ # print(key, ' - ', cost2[key])
294
+ inner_arrays = cost2[key]
295
+ for arrays_part in inner_arrays:
296
+ if arrays_part[1] == cost:
297
+ print(' best-file ', arrays_part[2])
298
+
299
+ cost2.clear()
300
+ print(' cost: ', cost, ' pos: ', pos)
301
+ if cost is None:
302
+ early_exit = True
303
+ break
304
+
305
+ if cost == best_cost[s]:
306
+ print(' !! equal cost !!!')
307
+
308
+ # # capture the best cost
309
+ # # if cost < best_cost[s] and np.abs(cost - best_cost[s]) > rtol:
310
+ # if cost < best_cost[s]:
311
+ # best_cost[s] = cost
312
+ # no_improvement[s] = False
313
+ # utils.annotate_step(best_cost[s], pos, steps, s)
314
+
315
+ print('\n Step summary, best particle values: {} '.format(pos))
316
+
317
+ key = "r{}s{}".format(r + 1, s + 1)
318
+ step_trace[key] = {}
319
+ step_trace[key]['time'] = str(datetime.datetime.now())
320
+ step_trace[key]['best_costs'] = best_cost
321
+ step_trace[key]['steps'] = copy.deepcopy(steps)
322
+
323
+ # capture the best cost
324
+ # if cost < best_cost[s] and np.abs(cost - best_cost[s]) > rtol:
325
+ if cost < best_cost[s]:
326
+ best_cost[s] = cost
327
+ no_improvement[s] = False
328
+ utils.annotate_step(best_cost[s], pos, steps, s)
329
+ best_step_request = key
330
+ # best_pos[s] = pos
331
+
332
+ if step_file is not None:
333
+ with open(step_file, "w") as fo:
334
+ json.dump(step_trace, fo)
335
+
336
+ # print(json.dumps(steps, sort_keys=False, indent=2))
337
+
338
+ if early_exit:
339
+ step_trace['exit'] = '1'
340
+ break
341
+
342
+ round_cost = np.sum(best_cost)
343
+
344
+ # if no improvement in all steps, break out of rounds prematurely
345
+ # but start checking only after min_rounds
346
+ # if (r + 1 >= min_rounds) and all(no_improvement):
347
+ rel_round_tol = 1 - round_cost / best_round_cost
348
+
349
+ print('\n Round summary - round_cost:{}, step_costs: {}, step improvement:{}'
350
+ .format(round_cost, best_cost, np.invert(no_improvement)))
351
+ print('\n Progress - best_round_cost:{}, rel_round_tol:{}, rtol:{}'
352
+ .format(best_round_cost, rel_round_tol, rtol))
353
+ print('\n Progress - best_step_request:{}'.format(best_step_request))
354
+
355
+ key = "r{}".format(r + 1)
356
+ step_trace[key] = {}
357
+ step_trace[key]['time'] = str(datetime.datetime.now())
358
+ step_trace[key]['round_cost'] = round_cost
359
+ step_trace[key]['best_costs'] = best_cost
360
+ step_trace[key]['improvements'] = no_improvement
361
+ if step_file is not None:
362
+ with open(step_file, "w") as fo:
363
+ json.dump(step_trace, fo)
364
+
365
+ if (r + 1 >= min_rounds) and 0 <= rel_round_tol < rtol:
366
+ r_below += 1
367
+ if r_below >= rtol_iter:
368
+ break
369
+ else:
370
+ # reset
371
+ r_below = 0
372
+
373
+ if round_cost < best_round_cost:
374
+ best_round_cost = round_cost
375
+
376
+ end_time = datetime.datetime.now()
377
+ elapsed = str(end_time - start_time)
378
+
379
+ print('Done in {} after {} out of {} rounds'.format(elapsed, r + 1, max_rounds))
380
+
381
+ done = True
382
+ for worker in thread_pool:
383
+ worker.join()
384
+
385
+ step_trace['rounds'] = r + 1
386
+ step_trace['end'] = str(datetime.datetime.now())
387
+ step_trace['time'] = elapsed
388
+
389
+ if step_file is not None:
390
+ with open(step_file, "w") as fo:
391
+ json.dump(step_trace, fo)
392
+
393
+ return optimizer, step_trace
394
+
395
+ # def p_global_best(steps: Dict, rounds: Tuple, args: Dict, n_particles: int, iters: int, options: Dict,
396
+ # n_threads: int = 4, rtol: float = 0.001, ftol: float = -np.inf,
397
+ # full_trace: List = None, rounds_below: int = 1) -> Tuple:
398
+ # """Performs a parallel stepwise particle swarm optimization PSO using a global best approach.
399
+ #
400
+ # Parameters
401
+ # ----------
402
+ # steps : Dict
403
+ # step definitions
404
+ # rounds : tuple
405
+ # round definition, (min,max) or max
406
+ # args : Dict
407
+ # static service args
408
+ # n_particles : int
409
+ # number of particles
410
+ # iters : int
411
+ # number of iterations
412
+ # options : Dict
413
+ # PSO options (see pyswarms)
414
+ # n_threads : int
415
+ # size of thread pool (default: 4)
416
+ # rtol : float
417
+ # percentage of change of sum(best_cost) between rounds for
418
+ # convergence. (Default is 0.001 0.1%)
419
+ # ftol : float
420
+ # PSO tolerance (default: -np.inf)
421
+ # full_trace : List
422
+ # trace of all runs, list of tuples
423
+ # first is dictionary of parameter names to parameter values
424
+ # second is the cost value (default: None)
425
+ # rounds_below : int
426
+ # the number of subsequent rounds with sum(best_cost) < rtol
427
+ # (default: 1)
428
+ # Returns
429
+ # -------
430
+ # Tuple
431
+ # optimizer: List, step_trace: Dict
432
+ # """
433
+ #
434
+ # utils.check_url(args['url'])
435
+ #
436
+ # min_rounds = 1
437
+ # if type(rounds) == tuple:
438
+ # min_rounds = rounds[0]
439
+ # max_rounds = rounds[1]
440
+ # else:
441
+ # max_rounds = rounds
442
+ #
443
+ # if min_rounds < 1:
444
+ # raise Exception('min rounds >= 1 expected, was "{}"'.format(min_rounds))
445
+ #
446
+ # if max_rounds > 20:
447
+ # raise Exception('max rounds <= 20 expected, was "{}"'.format(max_rounds))
448
+ #
449
+ # if n_threads < 1:
450
+ # raise Exception('n_threads >= 1, was "{}"'.format(n_threads))
451
+ #
452
+ # if rounds_below < 1:
453
+ # raise Exception('rounds_below >= 1, was "{}"'.format(rounds_below))
454
+ #
455
+ # if full_trace is not None and not isinstance(full_trace, list):
456
+ # raise Exception('full_trace must be of type, was "{}"'.format(type(full_trace)))
457
+ #
458
+ # best_cost = np.ones(len(steps))
459
+ # cost = np.ones(len(steps))
460
+ # optimizer = np.empty(len(steps), dtype=object)
461
+ # pos = np.empty(len(steps), dtype=object)
462
+ # args_s = np.empty(len(steps), dtype=object)
463
+ #
464
+ # # trace of steps info
465
+ # step_trace = {}
466
+ #
467
+ # # best round cost
468
+ # best_round_cost = 1000
469
+ #
470
+ # # request queue for worker
471
+ # req_queue = queue.Queue()
472
+ #
473
+ # # Threadpool management
474
+ # done = False
475
+ # thread_pool = []
476
+ # for thread_no in range(n_threads):
477
+ # worker = Thread(target=csip_worker, args=(req_queue, thread_no, lambda: done,
478
+ # full_trace, args['url'], args['files'], args['param']))
479
+ # thread_pool.append(worker)
480
+ # worker.start()
481
+ #
482
+ # start_time = datetime.datetime.now()
483
+ #
484
+ # # setup Step PSOs
485
+ # for s, step in enumerate(steps):
486
+ # param_names, bounds, objfunc = utils.get_step_info(steps, s)
487
+ # optimizer[s] = GlobalBestPSO(n_particles,
488
+ # len(param_names),
489
+ # options=options,
490
+ # bounds=bounds,
491
+ # ftol=ftol)
492
+ #
493
+ # def step_thread(s, args):
494
+ # cost[s], pos[s] = optimizer[s].optimize(eval_cost, iters=iters, **args)
495
+ #
496
+ # # Run PSOs in parallel
497
+ # r_below = 0
498
+ # for r in range(max_rounds):
499
+ # no_improvement = np.full(len(steps), True)
500
+ # # check if forced exit.
501
+ # if path.exists("stop"):
502
+ # print('\n>>>>> stop file found, exit now.')
503
+ # break
504
+ #
505
+ # # cross copy calibrated parameter, setup the arguments
506
+ # for s, step in enumerate(steps):
507
+ # param_names, bounds, objfunc = utils.get_step_info(steps, s)
508
+ # # maybe clone args?
509
+ # args_s[s] = args
510
+ # args_s[s]['step_param_names'] = param_names
511
+ # args_s[s]['step_objfunc'] = objfunc
512
+ # # get calibrated parameter from all other steps
513
+ # args_s[s]['calib_params'] = utils.get_calibrated_params(steps, s)
514
+ #
515
+ # args_s[s]['req_queue'] = req_queue
516
+ #
517
+ # # create optimizer in the first round.
518
+ # print('\n>>>>> R{}/S{} particle params: {} calibrated params: {}\n'.format(r + 1, s + 1, param_names,
519
+ # args_s[s]['calib_params']))
520
+ #
521
+ # # perform optimization
522
+ # s_threads = []
523
+ # for s, step in enumerate(steps):
524
+ # s_thread = threading.Thread(target=step_thread, args=(s, args_s[s]))
525
+ # s_threads.append(s_thread)
526
+ # s_thread.start()
527
+ #
528
+ # for t in s_threads:
529
+ # t.join()
530
+ #
531
+ # # eval cost
532
+ # for s, step in enumerate(steps):
533
+ # # capture the best cost
534
+ # # if cost < best_cost[s] and np.abs(cost - best_cost[s]) > rtol:
535
+ # if cost[s] < best_cost[s]:
536
+ # best_cost[s] = cost[s]
537
+ # no_improvement[s] = False
538
+ # utils.annotate_step(best_cost[s], pos[s], steps, s)
539
+ #
540
+ # print('\n Step {} summary, best particle values: {} '.format(s, pos[s]))
541
+ #
542
+ # key = "r{}s{}".format(r + 1, s + 1)
543
+ # step_trace[key] = copy.deepcopy(steps)
544
+ #
545
+ # # print(json.dumps(steps, sort_keys=False, indent=2))
546
+ #
547
+ # round_cost = np.sum(best_cost)
548
+ #
549
+ # # if no improvement in all steps, break out of rounds prematurely
550
+ # # but start checking only after min_rounds
551
+ # # if (r + 1 >= min_rounds) and all(no_improvement):
552
+ # rel_round_tol = 1 - round_cost / best_round_cost
553
+ #
554
+ # print('\n Round summary - round_cost:{}, step_costs: {}, step improvement:{}'
555
+ # .format(round_cost, best_cost, np.invert(no_improvement)))
556
+ # print('\n Progress - best_round_cost:{}, rel_round_tol:{}, rtol:{}'
557
+ # .format(best_round_cost, rel_round_tol, rtol))
558
+ #
559
+ # if (r + 1 >= min_rounds) and 0 <= rel_round_tol < rtol:
560
+ # r_below += 1
561
+ # if r_below == rounds_below:
562
+ # break
563
+ # else:
564
+ # # reset
565
+ # r_below = 0
566
+ #
567
+ # if round_cost < best_round_cost:
568
+ # best_round_cost = round_cost
569
+ #
570
+ # end_time = datetime.datetime.now()
571
+ # elapsed = str(end_time - start_time)
572
+ #
573
+ # print('Done in {} after {} out of {} rounds'.format(elapsed, r + 1, max_rounds))
574
+ #
575
+ # done = True
576
+ # for worker in thread_pool:
577
+ # worker.join()
578
+ #
579
+ # step_trace['rounds'] = r + 1
580
+ # step_trace['steps'] = len(steps)
581
+ # step_trace['iters'] = iters
582
+ # step_trace['particles'] = n_particles
583
+ # step_trace['time'] = elapsed
584
+ #
585
+ # return optimizer, step_trace