physbo 2.0.0__cp310-cp310-macosx_12_0_arm64.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.
Files changed (61) hide show
  1. physbo/__init__.py +17 -0
  2. physbo/blm/__init__.py +17 -0
  3. physbo/blm/basis/__init__.py +8 -0
  4. physbo/blm/basis/fourier.py +148 -0
  5. physbo/blm/core/__init__.py +8 -0
  6. physbo/blm/core/model.py +257 -0
  7. physbo/blm/inf/__init__.py +8 -0
  8. physbo/blm/inf/exact.py +192 -0
  9. physbo/blm/lik/__init__.py +10 -0
  10. physbo/blm/lik/_src/__init__.py +8 -0
  11. physbo/blm/lik/_src/cov.py +113 -0
  12. physbo/blm/lik/gauss.py +136 -0
  13. physbo/blm/lik/linear.py +117 -0
  14. physbo/blm/predictor.py +238 -0
  15. physbo/blm/prior/__init__.py +8 -0
  16. physbo/blm/prior/gauss.py +215 -0
  17. physbo/gp/__init__.py +15 -0
  18. physbo/gp/core/__init__.py +11 -0
  19. physbo/gp/core/learning.py +364 -0
  20. physbo/gp/core/model.py +420 -0
  21. physbo/gp/core/prior.py +207 -0
  22. physbo/gp/cov/__init__.py +8 -0
  23. physbo/gp/cov/_src/__init__.py +1 -0
  24. physbo/gp/cov/_src/enhance_gauss.cpython-310-darwin.so +0 -0
  25. physbo/gp/cov/gauss.py +393 -0
  26. physbo/gp/inf/__init__.py +8 -0
  27. physbo/gp/inf/exact.py +231 -0
  28. physbo/gp/lik/__init__.py +8 -0
  29. physbo/gp/lik/gauss.py +179 -0
  30. physbo/gp/mean/__init__.py +9 -0
  31. physbo/gp/mean/const.py +150 -0
  32. physbo/gp/mean/zero.py +66 -0
  33. physbo/gp/predictor.py +170 -0
  34. physbo/misc/__init__.py +15 -0
  35. physbo/misc/_src/__init__.py +1 -0
  36. physbo/misc/_src/cholupdate.cpython-310-darwin.so +0 -0
  37. physbo/misc/_src/diagAB.cpython-310-darwin.so +0 -0
  38. physbo/misc/_src/logsumexp.cpython-310-darwin.so +0 -0
  39. physbo/misc/_src/traceAB.cpython-310-darwin.so +0 -0
  40. physbo/misc/centering.py +28 -0
  41. physbo/misc/gauss_elim.py +35 -0
  42. physbo/misc/set_config.py +299 -0
  43. physbo/opt/__init__.py +8 -0
  44. physbo/opt/adam.py +107 -0
  45. physbo/predictor.py +261 -0
  46. physbo/search/__init__.py +11 -0
  47. physbo/search/discrete/__init__.py +11 -0
  48. physbo/search/discrete/policy.py +804 -0
  49. physbo/search/discrete/results.py +192 -0
  50. physbo/search/discrete_multi/__init__.py +11 -0
  51. physbo/search/discrete_multi/policy.py +552 -0
  52. physbo/search/discrete_multi/results.py +128 -0
  53. physbo/search/pareto.py +206 -0
  54. physbo/search/score.py +155 -0
  55. physbo/search/score_multi.py +197 -0
  56. physbo/search/utility.py +101 -0
  57. physbo/variable.py +222 -0
  58. physbo-2.0.0.dist-info/METADATA +110 -0
  59. physbo-2.0.0.dist-info/RECORD +61 -0
  60. physbo-2.0.0.dist-info/WHEEL +5 -0
  61. physbo-2.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,552 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (C) 2020- The University of Tokyo
3
+ #
4
+ # This Source Code Form is subject to the terms of the Mozilla Public
5
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ # file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+
8
+ import numpy as np
9
+ import copy
10
+ import pickle as pickle
11
+ import time
12
+
13
+ from .results import history
14
+ from .. import discrete
15
+ from .. import utility
16
+ from .. import score_multi as search_score
17
+ from ...gp import predictor as gp_predictor
18
+ from ...blm import predictor as blm_predictor
19
+ from ...misc import set_config
20
+ from ...variable import variable
21
+
22
+ from typing import List, Optional
23
+
24
+
25
+ class policy(discrete.policy):
26
+ new_data_list: List[Optional[variable]]
27
+
28
+ def __init__(
29
+ self, test_X, num_objectives, comm=None, config=None, initial_data=None
30
+ ):
31
+ self.num_objectives = num_objectives
32
+ self.history = history(num_objectives=self.num_objectives)
33
+
34
+ self.training_list = [variable() for _ in range(self.num_objectives)]
35
+ self.predictor_list = [None for _ in range(self.num_objectives)]
36
+ self.test_list = [
37
+ self._make_variable_X(test_X) for _ in range(self.num_objectives)
38
+ ]
39
+ self.new_data_list = [None for _ in range(self.num_objectives)]
40
+
41
+ self.actions = np.arange(0, test_X.shape[0])
42
+ if config is None:
43
+ self.config = set_config()
44
+ else:
45
+ self.config = config
46
+
47
+ self.TS_candidate_num = None
48
+
49
+ if initial_data is not None:
50
+ if len(initial_data) != 2:
51
+ msg = "ERROR: initial_data should be 2-elements tuple or list (actions and objectives)"
52
+ raise RuntimeError(msg)
53
+ actions, fs = initial_data
54
+ if fs.shape[1] != self.num_objectives:
55
+ msg = "ERROR: initial_data[1].shape[1] != num_objectives"
56
+ raise RuntimeError(msg)
57
+ if len(actions) != fs.shape[0]:
58
+ msg = "ERROR: len(initial_data[0]) != initial_data[1].shape[0]"
59
+ raise RuntimeError(msg)
60
+ self.write(actions, fs)
61
+ self.actions = sorted(list(set(self.actions) - set(actions)))
62
+
63
+ if comm is None:
64
+ self.mpicomm = None
65
+ self.mpisize = 1
66
+ self.mpirank = 0
67
+ else:
68
+ self.mpicomm = comm
69
+ self.mpisize = comm.size
70
+ self.mpirank = comm.rank
71
+ self.actions = np.array_split(self.actions, self.mpisize)[self.mpirank]
72
+
73
+ def write(
74
+ self,
75
+ action,
76
+ t,
77
+ X=None,
78
+ time_total=None,
79
+ time_update_predictor=None,
80
+ time_get_action=None,
81
+ time_run_simulator=None,
82
+ ):
83
+ self.history.write(
84
+ t,
85
+ action,
86
+ time_total=time_total,
87
+ time_update_predictor=time_update_predictor,
88
+ time_get_action=time_get_action,
89
+ time_run_simulator=time_run_simulator,
90
+ )
91
+ action = np.array(action)
92
+ t = np.array(t)
93
+
94
+ for i in range(self.num_objectives):
95
+ test = self.test_list[i]
96
+ predictor = self.predictor_list[i]
97
+
98
+ if X is None:
99
+ X = test.X[action, :]
100
+ Z = test.Z[action, :] if test.Z is not None else None
101
+ else:
102
+ Z = predictor.get_basis(X) if predictor is not None else None
103
+
104
+ if self.new_data_list[i] is None:
105
+ self.new_data_list[i] = variable(X, t[:, i], Z)
106
+ else:
107
+ self.new_data_list[i].add(X=X, t=t[:, i], Z=Z)
108
+ self.training_list[i].add(X=X, t=t[:, i], Z=Z)
109
+ local_index = np.searchsorted(self.actions, action)
110
+ local_index = local_index[
111
+ np.take(self.actions, local_index, mode="clip") == action
112
+ ]
113
+ self.actions = self._delete_actions(local_index)
114
+
115
+ def _model(self, i):
116
+ training = self.training_list[i]
117
+ predictor = self.predictor_list[i]
118
+ test = self.test_list[i]
119
+ new_data = self.new_data_list[i]
120
+ return {
121
+ "training": training,
122
+ "predictor": predictor,
123
+ "test": test,
124
+ "new_data": new_data,
125
+ }
126
+
127
+ def random_search(
128
+ self,
129
+ max_num_probes,
130
+ num_search_each_probe=1,
131
+ simulator=None,
132
+ is_disp=True,
133
+ disp_pareto_set=False,
134
+ ):
135
+ if self.mpirank != 0:
136
+ is_disp = False
137
+
138
+ N = int(num_search_each_probe)
139
+
140
+ if is_disp:
141
+ utility.show_interactive_mode(simulator, self.history)
142
+
143
+ for n in range(0, max_num_probes):
144
+ time_total = time.time()
145
+ if is_disp and N > 1:
146
+ utility.show_start_message_multi_search(
147
+ self.history.num_runs, score="random"
148
+ )
149
+
150
+ time_get_action = time.time()
151
+ action = self._get_random_action(N)
152
+ time_get_action = time.time() - time_get_action
153
+
154
+ if simulator is None:
155
+ return action
156
+
157
+ time_run_simulator = time.time()
158
+ t = _run_simulator(simulator, action, self.mpicomm)
159
+ time_run_simulator = time.time() - time_run_simulator
160
+
161
+ time_total = time.time() - time_total
162
+ self.write(
163
+ action,
164
+ t,
165
+ time_total=[time_total] * N,
166
+ time_update_predictor=np.zeros(N, dtype=float),
167
+ time_get_action=[time_get_action] * N,
168
+ time_run_simulator=[time_run_simulator] * N,
169
+ )
170
+
171
+ if is_disp:
172
+ utility.show_search_results_mo(
173
+ self.history, N, disp_pareto_set=disp_pareto_set
174
+ )
175
+
176
+ return copy.deepcopy(self.history)
177
+
178
+ def bayes_search(
179
+ self,
180
+ training_list=None,
181
+ max_num_probes=None,
182
+ num_search_each_probe=1,
183
+ predictor_list=None,
184
+ is_disp=True,
185
+ disp_pareto_set=False,
186
+ simulator=None,
187
+ score="HVPI",
188
+ interval=0,
189
+ num_rand_basis=0,
190
+ ):
191
+ if self.mpirank != 0:
192
+ is_disp = False
193
+
194
+ old_disp = self.config.learning.is_disp
195
+ self.config.learning.is_disp = is_disp
196
+
197
+ if max_num_probes is None:
198
+ max_num_probes = 1
199
+ simulator = None
200
+
201
+ is_rand_expans = False if num_rand_basis == 0 else True
202
+
203
+ if training_list is not None:
204
+ self.training_list = training_list
205
+
206
+ if predictor_list is None:
207
+ if is_rand_expans:
208
+ self.predictor_list = [
209
+ blm_predictor(self.config) for i in range(self.num_objectives)
210
+ ]
211
+ else:
212
+ self.predictor_list = [
213
+ gp_predictor(self.config) for i in range(self.num_objectives)
214
+ ]
215
+ else:
216
+ self.predictor_list = predictor_list
217
+
218
+ if max_num_probes == 0 and interval >= 0:
219
+ self._learn_hyperparameter(num_rand_basis)
220
+
221
+ N = int(num_search_each_probe)
222
+
223
+ for n in range(max_num_probes):
224
+ time_total = time.time()
225
+ time_update_predictor = time.time()
226
+ if utility.is_learning(n, interval):
227
+ self._learn_hyperparameter(num_rand_basis)
228
+ else:
229
+ self._update_predictor()
230
+ time_update_predictor = time.time() - time_update_predictor
231
+
232
+ if num_search_each_probe != 1:
233
+ utility.show_start_message_multi_search(self.history.num_runs, score)
234
+
235
+ time_get_action = time.time()
236
+ K = self.config.search.multi_probe_num_sampling
237
+ alpha = self.config.search.alpha
238
+ action = self._get_actions(score, N, K, alpha)
239
+ time_get_action = time.time() - time_get_action
240
+
241
+ N_indeed = len(action)
242
+ if N_indeed == 0:
243
+ if self.mpirank == 0:
244
+ print("WARNING: All actions have already searched.")
245
+ self.config.learning.is_disp = old_disp
246
+ return copy.deepcopy(self.history)
247
+
248
+ if simulator is None:
249
+ self.config.learning.is_disp = old_disp
250
+ return action
251
+
252
+ time_run_simulator = time.time()
253
+ t = _run_simulator(simulator, action, self.mpicomm)
254
+ time_run_simulator = time.time() - time_run_simulator
255
+
256
+ time_total = time.time() - time_total
257
+ self.write(
258
+ action,
259
+ t,
260
+ time_total=[time_total] * N_indeed,
261
+ time_update_predictor=[time_update_predictor] * N_indeed,
262
+ time_get_action=[time_get_action] * N_indeed,
263
+ time_run_simulator=[time_run_simulator] * N_indeed,
264
+ )
265
+
266
+ if is_disp:
267
+ utility.show_search_results_mo(
268
+ self.history, N, disp_pareto_set=disp_pareto_set
269
+ )
270
+ self._update_predictor()
271
+ self.config.learning.is_disp = old_disp
272
+ return copy.deepcopy(self.history)
273
+
274
+ def _get_actions(self, mode, N, K, alpha):
275
+ f = self.get_score(mode=mode, alpha=alpha, parallel=False)
276
+ champion, local_champion, local_index = self._find_champion(f)
277
+ if champion == -1:
278
+ return np.zeros(0, dtype=int)
279
+ if champion == local_champion:
280
+ self.actions = self._delete_actions(local_index)
281
+
282
+ chosen_actions = [champion]
283
+ for n in range(1, N):
284
+ f = self._get_marginal_score(mode, chosen_actions[0:n], K, alpha)
285
+ champion, local_champion, local_index = self._find_champion(f)
286
+ if champion == -1:
287
+ break
288
+ if champion == local_champion:
289
+ self.actions = self._delete_actions(local_index)
290
+ chosen_actions.append(champion)
291
+ return np.array(chosen_actions)
292
+
293
+ def get_post_fmean(self, xs):
294
+ if self.predictor_list == [None] * self.num_objectives:
295
+ self._warn_no_predictor("get_post_fmean()")
296
+ predictor_list = []
297
+ for i in range(self.num_objectives):
298
+ predictor = gp_predictor(self.config)
299
+ predictor.fit(self.training_list[i], 0)
300
+ predictor.prepare(self.training_list[i])
301
+ predictor_list.append(predictor)
302
+ else:
303
+ self._update_predictor()
304
+ predictor_list = self.predictor_list[:]
305
+ X = self._make_variable_X(xs)
306
+ fmean = [
307
+ predictor.get_post_fmean(training, X)
308
+ for predictor, training in zip(predictor_list, self.training_list)
309
+ ]
310
+ return np.array(fmean).T
311
+
312
+ def get_post_fcov(self, xs):
313
+ if self.predictor_list == [None] * self.num_objectives:
314
+ self._warn_no_predictor("get_post_fcov()")
315
+ predictor_list = []
316
+ for i in range(self.num_objectives):
317
+ predictor = gp_predictor(self.config)
318
+ predictor.fit(self.training_list[i], 0)
319
+ predictor.prepare(self.training_list[i])
320
+ predictor_list.append(predictor)
321
+ else:
322
+ self._update_predictor()
323
+ predictor_list = self.predictor_list[:]
324
+ X = self._make_variable_X(xs)
325
+ fcov = [
326
+ predictor.get_post_fcov(training, X)
327
+ for predictor, training in zip(predictor_list, self.training_list)
328
+ ]
329
+ return np.array(fcov).T
330
+
331
+ def get_score(
332
+ self,
333
+ mode,
334
+ actions=None,
335
+ xs=None,
336
+ predictor_list=None,
337
+ training_list=None,
338
+ pareto=None,
339
+ parallel=True,
340
+ alpha=1,
341
+ ):
342
+ if training_list is None:
343
+ training_list = self.training_list
344
+ if pareto is None:
345
+ pareto = self.history.pareto
346
+
347
+ if training_list[0].X is None or training_list[0].X.shape[0] == 0:
348
+ msg = "ERROR: No training data is registered."
349
+ raise RuntimeError(msg)
350
+
351
+ if predictor_list is None:
352
+ if self.predictor_list == [None] * self.num_objectives:
353
+ self._warn_no_predictor("get_score()")
354
+ predictor_list = []
355
+ for i in range(self.num_objectives):
356
+ predictor = gp_predictor(self.config)
357
+ predictor.fit(training_list[i], 0)
358
+ predictor.prepare(training_list[i])
359
+ predictor_list.append(predictor)
360
+ else:
361
+ self._update_predictor()
362
+ predictor_list = self.predictor_list
363
+
364
+ if xs is not None:
365
+ if actions is not None:
366
+ raise RuntimeError("ERROR: both actions and xs are given")
367
+ if isinstance(xs, variable):
368
+ test = xs
369
+ else:
370
+ test = variable(X=xs)
371
+ if parallel and self.mpisize > 1:
372
+ actions = np.array_split(np.arange(test.X.shape[0]), self.mpisize)
373
+ test = test.get_subset(actions[self.mpirank])
374
+ else:
375
+ if actions is None:
376
+ actions = self.actions
377
+ else:
378
+ if isinstance(actions, int):
379
+ actions = [actions]
380
+ if parallel and self.mpisize > 1:
381
+ actions = np.array_split(actions, self.mpisize)[self.mpirank]
382
+ test = self.test_list[0].get_subset(actions)
383
+
384
+ f = search_score.score(
385
+ mode,
386
+ predictor_list=predictor_list,
387
+ training_list=training_list,
388
+ test=test,
389
+ pareto=pareto,
390
+ reduced_candidate_num=self.TS_candidate_num,
391
+ alpha=alpha,
392
+ )
393
+ if parallel and self.mpisize > 1:
394
+ fs = self.mpicomm.allgather(f)
395
+ f = np.hstack(fs)
396
+ return f
397
+
398
+ def _get_marginal_score(self, mode, chosen_actions, K, alpha):
399
+ """
400
+ Getting marginal scores.
401
+
402
+ Parameters
403
+ ----------
404
+ mode: str
405
+ The type of aquision funciton.
406
+ TS (Thompson Sampling), EI (Expected Improvement) and PI (Probability of Improvement) are available.
407
+ These functions are defined in score.py.
408
+ chosen_actions: numpy.ndarray
409
+ Array of selected actions.
410
+ K: int
411
+ The total number of search candidates.
412
+ alpha: float
413
+ not used.
414
+
415
+ Returns
416
+ -------
417
+ f: list
418
+ N dimensional scores (score is defined in each mode)
419
+ """
420
+ f = np.zeros((K, len(self.actions)), dtype=float)
421
+
422
+ # draw K samples of the values of objective function of chosen actions
423
+ new_test_list = [variable() for _ in range(self.num_objectives)]
424
+ virtual_t_list = [np.zeros((K, 0)) for _ in range(self.num_objectives)]
425
+ for i in range(self.num_objectives):
426
+ new_test_local = self.test_list[i].get_subset(chosen_actions)
427
+ virtual_t_local = self.predictor_list[i].get_predict_samples(
428
+ self.training_list[i], new_test_local, K
429
+ )
430
+ if self.mpisize == 1:
431
+ new_test_list[i] = new_test_local
432
+ virtual_t_list[i] = virtual_t_local
433
+ else:
434
+ for nt in self.mpicomm.allgather(new_test_local):
435
+ new_test_list[i].add(X=nt.X, t=nt.t, Z=nt.Z)
436
+ virtual_t_list[i] = np.concatenate(
437
+ self.mpicomm.allgather(virtual_t_local), axis=1
438
+ )
439
+
440
+ for k in range(K):
441
+ predictor_list = [copy.deepcopy(p) for p in self.predictor_list]
442
+ training_list = [copy.deepcopy(t) for t in self.training_list]
443
+
444
+ for i in range(self.num_objectives):
445
+ virtual_train = new_test_list[i]
446
+ virtual_train.t = virtual_t_list[i][k, :]
447
+
448
+ if virtual_train.Z is None:
449
+ training_list[i].add(virtual_train.X, virtual_train.t)
450
+ else:
451
+ training_list[i].add(
452
+ virtual_train.X, virtual_train.t, virtual_train.Z
453
+ )
454
+
455
+ predictor_list[i].update(training_list[i], virtual_train)
456
+
457
+ f[k, :] = self.get_score(
458
+ mode,
459
+ predictor_list=predictor_list,
460
+ training_list=training_list,
461
+ parallel=False,
462
+ )
463
+ return np.mean(f, axis=0)
464
+
465
+ def save(self, file_history, file_training_list=None, file_predictor_list=None):
466
+ if self.mpirank == 0:
467
+ self.history.save(file_history)
468
+ if file_training_list is not None:
469
+ self.save_training_list(file_training_list)
470
+ if file_predictor_list is not None:
471
+ self.save_predictor_list(file_predictor_list)
472
+
473
+ def load(self, file_history, file_training_list=None, file_predictor_list=None):
474
+ self.history.load(file_history)
475
+
476
+ if file_training_list is None:
477
+ N = self.history.total_num_search
478
+ X = self.test_list[0].X[self.history.chosen_actions[0:N], :]
479
+ t = self.history.fx[0:N]
480
+ self.training_list = [
481
+ variable(X=X, t=t[:, i]) for i in range(self.num_objectives)
482
+ ]
483
+ else:
484
+ self.load_training_list(file_training_list)
485
+
486
+ if file_predictor_list is not None:
487
+ self.load_predictor_list(file_predictor_list)
488
+
489
+ N = self.history.total_num_search
490
+ self.actions = self._delete_actions(self.history.chosen_actions[:N])
491
+
492
+ def save_predictor_list(self, file_name):
493
+ with open(file_name, "wb") as f:
494
+ pickle.dump(self.predictor_list, f, 2)
495
+
496
+ def save_training_list(self, file_name):
497
+ obj = [
498
+ {"X": training.X, "t": training.t, "Z": training.Z}
499
+ for training in self.training_list
500
+ ]
501
+ with open(file_name, "wb") as f:
502
+ pickle.dump(obj, f, 2)
503
+
504
+ def load_predictor_list(self, file_name):
505
+ with open(file_name, "rb") as f:
506
+ self.predictor_list = pickle.load(f)
507
+
508
+ def load_training_list(self, file_name):
509
+ with open(file_name, "rb") as f:
510
+ data_list = pickle.load(f)
511
+
512
+ self.training_list = [variable() for i in range(self.num_objectives)]
513
+ for data, training in zip(data_list, self.training_list):
514
+ training.X = data["X"]
515
+ training.t = data["t"]
516
+ training.Z = data["Z"]
517
+
518
+ def _learn_hyperparameter(self, num_rand_basis):
519
+ for i in range(self.num_objectives):
520
+ m = self._model(i)
521
+ predictor = m["predictor"]
522
+ training = m["training"]
523
+ test = m["test"]
524
+
525
+ predictor.fit(training, num_rand_basis)
526
+ test.Z = predictor.get_basis(test.X)
527
+ training.Z = predictor.get_basis(training.X)
528
+ predictor.prepare(training)
529
+ self.new_data_list[i] = None
530
+ # self.predictor_list[i].fit(self.training_list[i], num_rand_basis)
531
+ # self.test_list[i].Z = self.predictor_list[i].get_basis(self.test_list[i].X)
532
+ # self.training_list[i].Z = self.predictor_list[i].get_basis(self.training_list[i].X)
533
+ # self.predictor_list[i].prepare(self.training_list[i])
534
+ # self.new_data_list[i] = None
535
+
536
+ def _update_predictor(self):
537
+ for i in range(self.num_objectives):
538
+ if self.new_data_list[i] is not None:
539
+ self.predictor_list[i].update(
540
+ self.training_list[i], self.new_data_list[i]
541
+ )
542
+ self.new_data_list[i] = None
543
+
544
+
545
+ def _run_simulator(simulator, action, comm=None):
546
+ if comm is None:
547
+ return simulator(action)
548
+ if comm.rank == 0:
549
+ t = simulator(action)
550
+ else:
551
+ t = 0.0
552
+ return comm.bcast(t, root=0)
@@ -0,0 +1,128 @@
1
+ # SPDX-License-Identifier: MPL-2.0
2
+ # Copyright (C) 2020- The University of Tokyo
3
+ #
4
+ # This Source Code Form is subject to the terms of the Mozilla Public
5
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ # file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+
8
+ import numpy as np
9
+ import pickle
10
+ import copy
11
+
12
+ from .. import pareto
13
+
14
+ MAX_SEARCH = int(30000)
15
+
16
+
17
+ class history(object):
18
+ def __init__(self, num_objectives):
19
+ self.num_objectives = num_objectives
20
+ self.pareto = pareto.Pareto(num_objectives=self.num_objectives)
21
+
22
+ self.num_runs = int(0)
23
+ self.total_num_search = int(0)
24
+ self.fx = np.zeros((MAX_SEARCH, self.num_objectives), dtype=float)
25
+ self.chosen_actions = np.zeros(MAX_SEARCH, dtype=int)
26
+ self.terminal_num_run = np.zeros(MAX_SEARCH, dtype=int)
27
+
28
+ self._time_total = np.zeros(MAX_SEARCH, dtype=float)
29
+ self._time_update_predictor = np.zeros(MAX_SEARCH, dtype=float)
30
+ self._time_get_action = np.zeros(MAX_SEARCH, dtype=float)
31
+ self._time_run_simulator = np.zeros(MAX_SEARCH, dtype=float)
32
+
33
+ @property
34
+ def time_total(self):
35
+ return copy.copy(self._time_total[0 : self.num_runs])
36
+
37
+ @property
38
+ def time_update_predictor(self):
39
+ return copy.copy(self._time_update_predictor[0 : self.num_runs])
40
+
41
+ @property
42
+ def time_get_action(self):
43
+ return copy.copy(self._time_get_action[0 : self.num_runs])
44
+
45
+ @property
46
+ def time_run_simulator(self):
47
+ return copy.copy(self._time_run_simulator[0 : self.num_runs])
48
+
49
+ def write(
50
+ self,
51
+ t,
52
+ action,
53
+ time_total=None,
54
+ time_update_predictor=None,
55
+ time_get_action=None,
56
+ time_run_simulator=None,
57
+ ):
58
+ t = np.array(t)
59
+ action = np.array(action)
60
+
61
+ if t.ndim == 1:
62
+ N = 1
63
+ if len(t) != self.num_objectives:
64
+ raise ValueError("t does not match the number of objectives")
65
+ else:
66
+ N = t.shape[0]
67
+ if t.shape[1] != self.num_objectives:
68
+ raise ValueError("t does not match the number of objectives")
69
+
70
+ st = self.total_num_search
71
+ en = st + N
72
+
73
+ self.terminal_num_run[self.num_runs] = en
74
+ self.fx[st:en] = t
75
+ self.chosen_actions[st:en] = action
76
+ self.num_runs += 1
77
+ self.total_num_search += N
78
+
79
+ # update Pareto set
80
+ self.pareto.update_front(t)
81
+
82
+ if time_total is None:
83
+ time_total = np.zeros(N, dtype=float)
84
+ self._time_total[st:en] = time_total
85
+
86
+ if time_update_predictor is None:
87
+ time_update_predictor = np.zeros(N, dtype=float)
88
+ self._time_update_predictor[st:en] = time_update_predictor
89
+
90
+ if time_get_action is None:
91
+ time_get_action = np.zeros(N, dtype=float)
92
+ self._time_get_action[st:en] = time_get_action
93
+
94
+ if time_run_simulator is None:
95
+ time_run_simulator = np.zeros(N, dtype=float)
96
+ self._time_run_simulator[st:en] = time_run_simulator
97
+
98
+ def export_pareto_front(self):
99
+ return self.pareto.export_front()
100
+
101
+ def save(self, filename):
102
+ N = self.total_num_search
103
+ M = self.num_runs
104
+
105
+ obj = {
106
+ "num_runs": M,
107
+ "total_num_search": N,
108
+ "fx": self.fx[0:N],
109
+ "chosen_actions": self.chosen_actions[0:N],
110
+ "terminal_num_run": self.terminal_num_run[0:M],
111
+ "pareto": self.pareto,
112
+ }
113
+
114
+ with open(filename, "wb") as f:
115
+ pickle.dump(obj, f)
116
+
117
+ def load(self, filename):
118
+ with open(filename, "rb") as f:
119
+ data = pickle.load(f)
120
+
121
+ M = data["num_runs"]
122
+ N = data["total_num_search"]
123
+ self.num_runs = M
124
+ self.total_num_search = N
125
+ self.fx[0:N] = data["fx"]
126
+ self.chosen_actions[0:N] = data["chosen_actions"]
127
+ self.terminal_num_run[0:M] = data["terminal_num_run"]
128
+ self.pareto = data["pareto"]