xopt 3.2.1__tar.gz → 3.2.2__tar.gz

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 (270) hide show
  1. {xopt-3.2.1 → xopt-3.2.2}/PKG-INFO +1 -1
  2. {xopt-3.2.1 → xopt-3.2.2}/environment.yml +2 -0
  3. {xopt-3.2.1 → xopt-3.2.2}/xopt/_version.py +3 -3
  4. {xopt-3.2.1 → xopt-3.2.2}/xopt/base.py +87 -14
  5. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/turbo.py +4 -3
  6. xopt-3.2.2/xopt/generators/checkpoints.py +123 -0
  7. xopt-3.2.2/xopt/generators/ga/base.py +239 -0
  8. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/ga/cnsga.py +3 -1
  9. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/ga/nsga2.py +11 -204
  10. {xopt-3.2.1 → xopt-3.2.2}/xopt/pydantic.py +14 -1
  11. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_high_level.py +3 -3
  12. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_turbo.py +25 -1
  13. xopt-3.2.2/xopt/tests/generators/ga/test_base.py +474 -0
  14. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/ga/test_cnsga.py +2 -2
  15. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/ga/test_nsga2.py +2 -8
  16. xopt-3.2.2/xopt/tests/generators/test_checkpoints.py +122 -0
  17. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_log.py +1 -0
  18. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_xopt.py +125 -6
  19. {xopt-3.2.1 → xopt-3.2.2}/xopt.egg-info/PKG-INFO +1 -1
  20. {xopt-3.2.1 → xopt-3.2.2}/xopt.egg-info/SOURCES.txt +4 -60
  21. {xopt-3.2.1 → xopt-3.2.2}/xopt.egg-info/scm_file_list.json +174 -230
  22. xopt-3.2.2/xopt.egg-info/scm_version.json +8 -0
  23. xopt-3.2.1/.github/workflows/gh-pages.yml +0 -353
  24. xopt-3.2.1/.github/workflows/lint.yml +0 -64
  25. xopt-3.2.1/.github/workflows/pypi_upload.yml +0 -36
  26. xopt-3.2.1/.github/workflows/test-notebooks.yml +0 -265
  27. xopt-3.2.1/.github/workflows/tests.yml +0 -62
  28. xopt-3.2.1/docs/examples/basic/checkpointing_and_restarts.ipynb +0 -155
  29. xopt-3.2.1/docs/examples/basic/xopt_basic.ipynb +0 -532
  30. xopt-3.2.1/docs/examples/basic/xopt_cli.md +0 -77
  31. xopt-3.2.1/docs/examples/basic/xopt_evaluator.ipynb +0 -448
  32. xopt-3.2.1/docs/examples/basic/xopt_generator.ipynb +0 -222
  33. xopt-3.2.1/docs/examples/basic/xopt_parallel.ipynb +0 -584
  34. xopt-3.2.1/docs/examples/basic/xopt_stopping_condition.ipynb +0 -791
  35. xopt-3.2.1/docs/examples/basic/xopt_vocs.ipynb +0 -506
  36. xopt-3.2.1/docs/examples/bayes_exp/bayesian_exploration.ipynb +0 -261
  37. xopt-3.2.1/docs/examples/bayes_exp/bayesian_exploration_from_yaml.ipynb +0 -169
  38. xopt-3.2.1/docs/examples/bayes_exp/bayesian_exploration_w_interpolation.ipynb +0 -299
  39. xopt-3.2.1/docs/examples/bayes_exp/bayesian_exploration_with_nans.ipynb +0 -191
  40. xopt-3.2.1/docs/examples/developer/benchmarking.md +0 -87
  41. xopt-3.2.1/docs/examples/ga/cnsga_tnk.ipynb +0 -537
  42. xopt-3.2.1/docs/examples/ga/nsga2/assets/benchmarking.pdf +0 -0
  43. xopt-3.2.1/docs/examples/ga/nsga2/assets/zdt3_pf.png +0 -0
  44. xopt-3.2.1/docs/examples/ga/nsga2/genetic_operators.ipynb +0 -165
  45. xopt-3.2.1/docs/examples/ga/nsga2/index.md +0 -40
  46. xopt-3.2.1/docs/examples/ga/nsga2/nsga2_python.ipynb +0 -379
  47. xopt-3.2.1/docs/examples/ga/nsga2/nsga2_to_cnsga.ipynb +0 -276
  48. xopt-3.2.1/docs/examples/ga/nsga2/yaml_interface/assets/yaml_runner_example/eval_fun.py +0 -41
  49. xopt-3.2.1/docs/examples/ga/nsga2/yaml_interface/assets/yaml_runner_example/nsga2_from_checkpoint.yml +0 -71
  50. xopt-3.2.1/docs/examples/ga/nsga2/yaml_interface/assets/yaml_runner_example/nsga2_zdt3.yml +0 -72
  51. xopt-3.2.1/docs/examples/ga/nsga2/yaml_interface/index.md +0 -297
  52. xopt-3.2.1/docs/examples/ga/nsga2/yaml_interface/nsga2_yaml.ipynb +0 -201
  53. xopt-3.2.1/docs/examples/gp_model_creation/approximate.ipynb +0 -186
  54. xopt-3.2.1/docs/examples/gp_model_creation/batched_model.ipynb +0 -264
  55. xopt-3.2.1/docs/examples/gp_model_creation/model_creation.ipynb +0 -243
  56. xopt-3.2.1/docs/examples/multi_objective_bayes_opt/mggpo.ipynb +0 -205
  57. xopt-3.2.1/docs/examples/multi_objective_bayes_opt/mobo.ipynb +0 -220
  58. xopt-3.2.1/docs/examples/multi_objective_bayes_opt/multi_fidelity_mobo.ipynb +0 -335
  59. xopt-3.2.1/docs/examples/scipy/latin_hypercube.ipynb +0 -190
  60. xopt-3.2.1/docs/examples/sequential/extremum_seeking.ipynb +0 -962
  61. xopt-3.2.1/docs/examples/sequential/neldermead.ipynb +0 -653
  62. xopt-3.2.1/docs/examples/sequential/rcds.ipynb +0 -862
  63. xopt-3.2.1/docs/examples/single_objective_bayes_opt/bax_tutorial.ipynb +0 -378
  64. xopt-3.2.1/docs/examples/single_objective_bayes_opt/benchmarking.ipynb +0 -280
  65. xopt-3.2.1/docs/examples/single_objective_bayes_opt/bo_tutorial.ipynb +0 -313
  66. xopt-3.2.1/docs/examples/single_objective_bayes_opt/constrained_bo_tutorial.ipynb +0 -383
  67. xopt-3.2.1/docs/examples/single_objective_bayes_opt/contextual_bo.ipynb +0 -380
  68. xopt-3.2.1/docs/examples/single_objective_bayes_opt/custom_model.ipynb +0 -270
  69. xopt-3.2.1/docs/examples/single_objective_bayes_opt/custom_objective.ipynb +0 -231
  70. xopt-3.2.1/docs/examples/single_objective_bayes_opt/fast_model_eval.ipynb +0 -160
  71. xopt-3.2.1/docs/examples/single_objective_bayes_opt/fixed_features.ipynb +0 -309
  72. xopt-3.2.1/docs/examples/single_objective_bayes_opt/hessian_kernel.ipynb +0 -157
  73. xopt-3.2.1/docs/examples/single_objective_bayes_opt/heteroskedastic_noise_tutorial.ipynb +0 -314
  74. xopt-3.2.1/docs/examples/single_objective_bayes_opt/interpolate_tutorial.ipynb +0 -298
  75. xopt-3.2.1/docs/examples/single_objective_bayes_opt/mixed_discrete.ipynb +0 -274
  76. xopt-3.2.1/docs/examples/single_objective_bayes_opt/multi_fidelity_simple.ipynb +0 -339
  77. xopt-3.2.1/docs/examples/single_objective_bayes_opt/noisy_bo_tutorial.ipynb +0 -312
  78. xopt-3.2.1/docs/examples/single_objective_bayes_opt/time_dependent_bo.ipynb +0 -425
  79. xopt-3.2.1/docs/examples/single_objective_bayes_opt/upper_confidence_bound.ipynb +0 -153
  80. xopt-3.2.1/docs/examples/trust_region_bo/turbo_basics.ipynb +0 -222
  81. xopt-3.2.1/docs/examples/trust_region_bo/turbo_optimize.ipynb +0 -361
  82. xopt-3.2.1/docs/examples/trust_region_bo/turbo_safety.ipynb +0 -368
  83. xopt-3.2.1/xopt.egg-info/scm_version.json +0 -8
  84. {xopt-3.2.1 → xopt-3.2.2}/.pre-commit-config.yaml +0 -0
  85. {xopt-3.2.1 → xopt-3.2.2}/LICENSE +0 -0
  86. {xopt-3.2.1 → xopt-3.2.2}/MANIFEST.in +0 -0
  87. {xopt-3.2.1 → xopt-3.2.2}/README.md +0 -0
  88. {xopt-3.2.1 → xopt-3.2.2}/benchmarks/__init__.py +0 -0
  89. {xopt-3.2.1 → xopt-3.2.2}/benchmarks/test_mo.py +0 -0
  90. {xopt-3.2.1 → xopt-3.2.2}/benchmarks/test_neldermead.py +0 -0
  91. {xopt-3.2.1 → xopt-3.2.2}/benchmarks/test_ucb.py +0 -0
  92. {xopt-3.2.1 → xopt-3.2.2}/codecov.yml +0 -0
  93. {xopt-3.2.1 → xopt-3.2.2}/docs/algorithms.md +0 -0
  94. {xopt-3.2.1 → xopt-3.2.2}/docs/api/evaluator.md +0 -0
  95. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/bax/acquisition_functions.md +0 -0
  96. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/bax/algorithms.md +0 -0
  97. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/bax/bax_generator.md +0 -0
  98. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/bax/visualize.md +0 -0
  99. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/bayesian_exploration.md +0 -0
  100. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/bayesian_generator.md +0 -0
  101. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/expected_improvement.md +0 -0
  102. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/mggpo.md +0 -0
  103. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/mobo.md +0 -0
  104. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/models/base_model_constructor.md +0 -0
  105. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/models/standard_model_constructor.md +0 -0
  106. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/models/time_dependent_model_constructor.md +0 -0
  107. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/multi_fidelity.md +0 -0
  108. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/time_dependent.md +0 -0
  109. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/turbo.md +0 -0
  110. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/upper_confidence_bound.md +0 -0
  111. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/bayesian/utils.md +0 -0
  112. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/deduplicated.md +0 -0
  113. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/ga/cnsga.md +0 -0
  114. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/ga/deap_creator.md +0 -0
  115. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/ga/deap_fitness_with_constraints.md +0 -0
  116. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/ga/nsga2.md +0 -0
  117. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/ga/operators.md +0 -0
  118. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/random.md +0 -0
  119. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/sequential/extremumseeking.md +0 -0
  120. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/sequential/neldermead.md +0 -0
  121. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/sequential/rcds.md +0 -0
  122. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/sequential/sequential_generator.md +0 -0
  123. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators/utils.md +0 -0
  124. {xopt-3.2.1 → xopt-3.2.2}/docs/api/generators.md +0 -0
  125. {xopt-3.2.1 → xopt-3.2.2}/docs/api/numerical_optimizer.md +0 -0
  126. {xopt-3.2.1 → xopt-3.2.2}/docs/api/stopping_conditions.md +0 -0
  127. {xopt-3.2.1 → xopt-3.2.2}/docs/api/utils.md +0 -0
  128. {xopt-3.2.1 → xopt-3.2.2}/docs/api/vocs.md +0 -0
  129. {xopt-3.2.1 → xopt-3.2.2}/docs/api/xopt.md +0 -0
  130. {xopt-3.2.1 → xopt-3.2.2}/docs/assets/Xopt-logo.png +0 -0
  131. {xopt-3.2.1 → xopt-3.2.2}/docs/assets/xopt_overview.pdf +0 -0
  132. {xopt-3.2.1 → xopt-3.2.2}/docs/hooks/zip_generator.py +0 -0
  133. {xopt-3.2.1 → xopt-3.2.2}/docs/index.md +0 -0
  134. {xopt-3.2.1 → xopt-3.2.2}/docs/installation.md +0 -0
  135. {xopt-3.2.1 → xopt-3.2.2}/docs/overrides/main.html +0 -0
  136. {xopt-3.2.1 → xopt-3.2.2}/docs/stylesheets/extra.css +0 -0
  137. {xopt-3.2.1 → xopt-3.2.2}/mkdocs.yml +0 -0
  138. {xopt-3.2.1 → xopt-3.2.2}/pyproject.toml +0 -0
  139. {xopt-3.2.1 → xopt-3.2.2}/scripts/execute_notebooks.bash +0 -0
  140. {xopt-3.2.1 → xopt-3.2.2}/scripts/run_benchmarks.py +0 -0
  141. {xopt-3.2.1 → xopt-3.2.2}/scripts/run_examples.py +0 -0
  142. {xopt-3.2.1 → xopt-3.2.2}/scripts/run_tests.py +0 -0
  143. {xopt-3.2.1 → xopt-3.2.2}/setup.cfg +0 -0
  144. {xopt-3.2.1 → xopt-3.2.2}/xopt/__init__.py +0 -0
  145. {xopt-3.2.1 → xopt-3.2.2}/xopt/asynchronous.py +0 -0
  146. {xopt-3.2.1 → xopt-3.2.2}/xopt/entrypoint.py +0 -0
  147. {xopt-3.2.1 → xopt-3.2.2}/xopt/errors.py +0 -0
  148. {xopt-3.2.1 → xopt-3.2.2}/xopt/evaluator.py +0 -0
  149. {xopt-3.2.1 → xopt-3.2.2}/xopt/generator.py +0 -0
  150. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/__init__.py +0 -0
  151. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/__init__.py +0 -0
  152. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/base_model.py +0 -0
  153. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/bax/__init__.py +0 -0
  154. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/bax/acquisition.py +0 -0
  155. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/bax/algorithms.py +0 -0
  156. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/bax/visualize.py +0 -0
  157. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/bax_generator.py +0 -0
  158. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/bayesian_exploration.py +0 -0
  159. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/bayesian_generator.py +0 -0
  160. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/custom_botorch/__init__.py +0 -0
  161. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/custom_botorch/constrained_acquisition.py +0 -0
  162. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/custom_botorch/hessian_kernel.py +0 -0
  163. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/custom_botorch/heteroskedastic.py +0 -0
  164. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/custom_botorch/log_acquisition_function.py +0 -0
  165. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/custom_botorch/multi_fidelity.py +0 -0
  166. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/expected_improvement.py +0 -0
  167. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/mggpo.py +0 -0
  168. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/mobo.py +0 -0
  169. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/models/__init__.py +0 -0
  170. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/models/approximate.py +0 -0
  171. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/models/prior_mean.py +0 -0
  172. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/models/standard.py +0 -0
  173. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/models/time_dependent.py +0 -0
  174. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/multi_fidelity.py +0 -0
  175. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/objectives.py +0 -0
  176. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/time_dependent.py +0 -0
  177. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/upper_confidence_bound.py +0 -0
  178. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/utils.py +0 -0
  179. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/bayesian/visualize.py +0 -0
  180. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/deduplicated.py +0 -0
  181. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/ga/__init__.py +0 -0
  182. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/ga/deap_creator.py +0 -0
  183. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/ga/deap_fitness_with_constraints.py +0 -0
  184. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/ga/operators.py +0 -0
  185. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/random.py +0 -0
  186. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/scipy/__init__.py +0 -0
  187. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/scipy/latin_hypercube.py +0 -0
  188. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/sequential/__init__.py +0 -0
  189. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/sequential/extremumseeking.py +0 -0
  190. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/sequential/neldermead.py +0 -0
  191. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/sequential/rcds.py +0 -0
  192. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/sequential/sequential_generator.py +0 -0
  193. {xopt-3.2.1 → xopt-3.2.2}/xopt/generators/utils.py +0 -0
  194. {xopt-3.2.1 → xopt-3.2.2}/xopt/log.py +0 -0
  195. {xopt-3.2.1 → xopt-3.2.2}/xopt/mpi/__init__.py +0 -0
  196. {xopt-3.2.1 → xopt-3.2.2}/xopt/mpi/run.py +0 -0
  197. {xopt-3.2.1 → xopt-3.2.2}/xopt/numerical_optimizer.py +0 -0
  198. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/__init__.py +0 -0
  199. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/bench_framework.py +0 -0
  200. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/bench_functions/__init__.py +0 -0
  201. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/bench_functions/generators.py +0 -0
  202. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/bench_functions/models.py +0 -0
  203. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/bench_profiler.py +0 -0
  204. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/bench_runner.py +0 -0
  205. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/test_functions/__init__.py +0 -0
  206. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/test_functions/ackley_20.py +0 -0
  207. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/test_functions/haverly_pooling.py +0 -0
  208. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/test_functions/modified_tnk.py +0 -0
  209. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/test_functions/multi_objective.py +0 -0
  210. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/test_functions/problem.py +0 -0
  211. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/test_functions/rosenbrock.py +0 -0
  212. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/test_functions/sinusoid_1d.py +0 -0
  213. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/test_functions/tnk.py +0 -0
  214. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/test_functions/zdt.py +0 -0
  215. {xopt-3.2.1 → xopt-3.2.2}/xopt/resources/testing.py +0 -0
  216. {xopt-3.2.1 → xopt-3.2.2}/xopt/stopping_conditions.py +0 -0
  217. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/__init__.py +0 -0
  218. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/__init__.py +0 -0
  219. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/__init__.py +0 -0
  220. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/conftest.py +0 -0
  221. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_bax.py +0 -0
  222. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_bax_visualize.py +0 -0
  223. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_bayesian_exploration.py +0 -0
  224. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_bayesian_generator.py +0 -0
  225. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_constraints.py +0 -0
  226. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_contextual_bo.py +0 -0
  227. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_custom_model.py +0 -0
  228. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_discrete_integration.py +0 -0
  229. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_expected_improvement.py +0 -0
  230. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_hessian_kernel.py +0 -0
  231. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_mggpo.py +0 -0
  232. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_mobo.py +0 -0
  233. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_model_constructor.py +0 -0
  234. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_multi_fidelity.py +0 -0
  235. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_objectives.py +0 -0
  236. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_time_dependent_bo.py +0 -0
  237. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_upper_confidence_bound.py +0 -0
  238. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_utils.py +0 -0
  239. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/bayesian/test_visualize.py +0 -0
  240. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/external/test_aposmm.py +0 -0
  241. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/ga/test_deap_creator.py +0 -0
  242. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/sequential/test_extremum_seeking.py +0 -0
  243. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/sequential/test_neldermead.py +0 -0
  244. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/sequential/test_rcds.py +0 -0
  245. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/sequential/test_sequential.py +0 -0
  246. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/sequential/test_serialization.py +0 -0
  247. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/test_deduplicated.py +0 -0
  248. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/test_latin_hypercube.py +0 -0
  249. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/test_operators.py +0 -0
  250. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/test_random.py +0 -0
  251. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/generators/test_utils.py +0 -0
  252. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_asynch_xopt.py +0 -0
  253. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_entrypoint.py +0 -0
  254. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_evaluator.py +0 -0
  255. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_generator.py +0 -0
  256. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_io.py +0 -0
  257. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_mpi.py +0 -0
  258. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_numerical_optimizer.py +0 -0
  259. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_perf.py +0 -0
  260. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_pydantic.py +0 -0
  261. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_resources.py +0 -0
  262. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_stopping_condition.py +0 -0
  263. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_utils.py +0 -0
  264. {xopt-3.2.1 → xopt-3.2.2}/xopt/tests/test_vocs.py +0 -0
  265. {xopt-3.2.1 → xopt-3.2.2}/xopt/utils.py +0 -0
  266. {xopt-3.2.1 → xopt-3.2.2}/xopt/vocs.py +0 -0
  267. {xopt-3.2.1 → xopt-3.2.2}/xopt.egg-info/dependency_links.txt +0 -0
  268. {xopt-3.2.1 → xopt-3.2.2}/xopt.egg-info/entry_points.txt +0 -0
  269. {xopt-3.2.1 → xopt-3.2.2}/xopt.egg-info/requires.txt +0 -0
  270. {xopt-3.2.1 → xopt-3.2.2}/xopt.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xopt
3
- Version: 3.2.1
3
+ Version: 3.2.2
4
4
  Summary: Flexible optimization of arbitrary problems in Python.
5
5
  Author: Christopher Mayes, Ryan Roussel, Nikita Kuklev, Christopher Pierce, Sara Miskovich
6
6
  License: Apache License
@@ -15,6 +15,7 @@ dependencies:
15
15
  - tqdm
16
16
  - orjson
17
17
  - matplotlib
18
+ - gest-api>=0.2
18
19
  # parallel
19
20
  - mpi4py
20
21
  - dask
@@ -33,3 +34,4 @@ dependencies:
33
34
  - mkdocstrings-python
34
35
  - ruff
35
36
  - typing-extensions
37
+ - gest-api
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '3.2.1'
22
- __version_tuple__ = version_tuple = (3, 2, 1)
21
+ __version__ = version = '3.2.2'
22
+ __version_tuple__ = version_tuple = (3, 2, 2)
23
23
 
24
- __commit_id__ = commit_id = 'g46cc86a6b'
24
+ __commit_id__ = commit_id = 'gd4c488f75'
@@ -1,5 +1,6 @@
1
1
  import json
2
2
  import logging
3
+ import os
3
4
  from copy import deepcopy
4
5
  from typing import Any, Optional, Union
5
6
 
@@ -40,6 +41,11 @@ from .errors import DataError
40
41
 
41
42
  logger = logging.getLogger(__name__)
42
43
 
44
+ DUMP_FILE_RENAME_MESSAGE = (
45
+ "The attribute `dump_file` in `Xopt` has been renamed to `xopt_dump_file`. "
46
+ "Support for the old name will be removed in later versions of the Xopt library."
47
+ )
48
+
43
49
 
44
50
  class Xopt(XoptBaseModel):
45
51
  """
@@ -59,9 +65,13 @@ class Xopt(XoptBaseModel):
59
65
  strict : bool, optional
60
66
  A flag indicating whether exceptions raised during evaluation should stop the
61
67
  optimization process.
62
- dump_file : str, optional
68
+ xopt_dump_file : str, optional
63
69
  An optional file path for dumping attributes of the xopt object and the
64
- results of evaluations.
70
+ results of evaluations. Environment variables and `~` are expanded when
71
+ dumping.
72
+ data_dump_file : str, optional
73
+ An optional file path for dumping the evaluation data as a CSV file.
74
+ Environment variables and `~` are expanded when dumping.
65
75
  data : DataFrame, optional
66
76
  An optional DataFrame object for storing internal data related to the optimization
67
77
  process.
@@ -98,6 +108,8 @@ class Xopt(XoptBaseModel):
98
108
  Serializes the Xopt configuration to a YAML string.
99
109
  dump(file: str = None, **kwargs)
100
110
  Dumps the Xopt configuration to a specified file.
111
+ dump_data()
112
+ Dumps the evaluation data to the file given by `data_dump_file`.
101
113
  dict(**kwargs) -> dict
102
114
  Provides a custom dictionary representation of the Xopt configuration.
103
115
  json(**kwargs) -> str
@@ -115,8 +127,11 @@ class Xopt(XoptBaseModel):
115
127
  description="flag to indicate if exceptions raised during evaluation "
116
128
  "should stop Xopt",
117
129
  )
118
- dump_file: Optional[str] = Field(
119
- None, description="file to dump the results of the evaluations"
130
+ xopt_dump_file: Optional[str] = Field(
131
+ None, description="file to dump the serialized Xopt object to"
132
+ )
133
+ data_dump_file: Optional[str] = Field(
134
+ None, description="file to dump the evaluation data to as CSV"
120
135
  )
121
136
  data: Optional[DataFrame] = Field(None, description="internal DataFrame object")
122
137
  serialize_torch: bool = Field(
@@ -243,6 +258,35 @@ class Xopt(XoptBaseModel):
243
258
  )
244
259
  return data
245
260
 
261
+ @model_validator(mode="before")
262
+ @classmethod
263
+ def dump_file_legacy(cls, data: Any):
264
+ """
265
+ Handle backward compatibility: convert the old dump_file parameter to
266
+ xopt_dump_file.
267
+ """
268
+ if isinstance(data, dict) and "dump_file" in data:
269
+ warnings.warn(DUMP_FILE_RENAME_MESSAGE, DeprecationWarning, stacklevel=2)
270
+ dump_file = data.pop("dump_file")
271
+ if dump_file is not None:
272
+ if data.get("xopt_dump_file") is not None:
273
+ raise ValueError(
274
+ "Cannot specify both 'dump_file' and 'xopt_dump_file'. "
275
+ "Use 'xopt_dump_file' instead."
276
+ )
277
+ data["xopt_dump_file"] = dump_file
278
+ return data
279
+
280
+ @property
281
+ def dump_file(self) -> Optional[str]:
282
+ warnings.warn(DUMP_FILE_RENAME_MESSAGE, DeprecationWarning, stacklevel=2)
283
+ return self.xopt_dump_file
284
+
285
+ @dump_file.setter
286
+ def dump_file(self, value: Optional[str]):
287
+ warnings.warn(DUMP_FILE_RENAME_MESSAGE, DeprecationWarning, stacklevel=2)
288
+ self.xopt_dump_file = value
289
+
246
290
  @property
247
291
  def n_data(self) -> int:
248
292
  if self.data is None:
@@ -440,9 +484,11 @@ class Xopt(XoptBaseModel):
440
484
 
441
485
  self.add_data(output_data)
442
486
 
443
- # dump data to file if specified
444
- if self.dump_file is not None:
487
+ # dump to file(s) if specified
488
+ if self.xopt_dump_file is not None:
445
489
  self.dump()
490
+ if self.data_dump_file is not None:
491
+ self.dump_data()
446
492
 
447
493
  return output_data
448
494
 
@@ -624,31 +670,58 @@ class Xopt(XoptBaseModel):
624
670
 
625
671
  def dump(self, file: str = None, **kwargs):
626
672
  """
627
- Dump data to a file.
673
+ Dump the Xopt configuration and data to a YAML file.
674
+
675
+ Environment variables and `~` in the path are expanded.
628
676
 
629
677
  Parameters
630
678
  ----------
631
679
  file : str, optional
632
680
  The path to the file where the Xopt configuration will be dumped.
681
+ Defaults to the `xopt_dump_file` attribute.
633
682
  **kwargs
634
683
  Additional keyword arguments for customizing the dump.
635
684
 
636
685
  Raises
637
686
  ------
638
687
  ValueError
639
- If no dump file is specified via argument or in the `dump_file` attribute.
688
+ If no dump file is specified via argument or in the `xopt_dump_file`
689
+ attribute.
640
690
 
641
691
  """
642
- fname = file if file is not None else self.dump_file
692
+ fname = file if file is not None else self.xopt_dump_file
643
693
 
644
694
  if fname is None:
645
695
  raise ValueError(
646
- "no dump file specified via argument or in `dump_file` attribute"
696
+ "no dump file specified via argument or in `xopt_dump_file` attribute"
647
697
  )
648
- else:
649
- with open(fname, "w") as f:
650
- f.write(self.yaml(**kwargs))
651
- logger.debug(f"Dumped state to YAML file: {fname}")
698
+
699
+ fname = os.path.expanduser(os.path.expandvars(fname))
700
+ with open(fname, "w") as f:
701
+ f.write(self.yaml(**kwargs))
702
+ logger.debug(f"Dumped state to YAML file: {fname}")
703
+
704
+ def dump_data(self):
705
+ """
706
+ Dump the evaluation data to the CSV file given by `data_dump_file`.
707
+
708
+ Environment variables and `~` in the path are expanded.
709
+
710
+ Raises
711
+ ------
712
+ ValueError
713
+ If no data dump file is specified in the `data_dump_file` attribute.
714
+
715
+ """
716
+ if self.data_dump_file is None:
717
+ raise ValueError(
718
+ "no data dump file specified in `data_dump_file` attribute"
719
+ )
720
+
721
+ fname = os.path.expanduser(os.path.expandvars(self.data_dump_file))
722
+ data = self.data if self.data is not None else pd.DataFrame()
723
+ data.to_csv(fname, index_label="xopt_index")
724
+ logger.debug(f"Dumped data to CSV file: {fname}")
652
725
 
653
726
  def dict(self, **kwargs) -> dict:
654
727
  """
@@ -256,10 +256,11 @@ class TurboController(XoptBaseModel, ABC):
256
256
  if active_indices:
257
257
  lengthscales = lengthscales[active_indices]
258
258
 
259
- # calculate the ratios of lengthscales for each axis
259
+ # Normalize by the geometric mean without forming the raw
260
+ # product, which can overflow or underflow.
260
261
  active_dim = len(active_variable_names)
261
- weights = lengthscales / torch.prod(lengthscales) ** (
262
- 1 / active_dim
262
+ weights = lengthscales / torch.prod(
263
+ lengthscales ** (1 / active_dim)
263
264
  )
264
265
 
265
266
  # calculate the tr bounding box
@@ -0,0 +1,123 @@
1
+ from datetime import datetime
2
+ from pydantic import BaseModel, Field, model_validator
3
+ import json
4
+ import os
5
+
6
+ from ..vocs import VOCS
7
+
8
+
9
+ class CheckpointMixin(BaseModel):
10
+ """
11
+ Mix-in class adding checkpoint saving and loading to a generator.
12
+
13
+ Checkpoints are written to a caller-supplied directory. The VOCS object is
14
+ serialized into the checkpoint itself. Legacy checkpoints which predate this
15
+ instead carry the VOCS object in a "vocs.txt" file one level above the
16
+ directory holding the checkpoints and are still supported when loading.
17
+
18
+ The host class must provide a ``vocs`` attribute and a ``to_json`` method.
19
+ Writing of the checkpoint file is the responsibility of the concrete class
20
+ as it will be implementation dependent.
21
+
22
+ Parameters
23
+ ----------
24
+ checkpoint_file : str, optional
25
+ Path to checkpoint file to load from. If provided, the generator will be
26
+ initialized from the checkpoint state. User-specified parameters will
27
+ override checkpoint values.
28
+ """
29
+
30
+ checkpoint_file: str | None = Field(
31
+ None, description="Path to checkpoint file to load from", exclude=True
32
+ )
33
+
34
+ @staticmethod
35
+ def _load_checkpoint_data(fname: str) -> dict:
36
+ """
37
+ Internal function to load generator data from checkpoint file as well as VOCS object.
38
+
39
+ Parameters
40
+ ----------
41
+ fname : str
42
+ Path to the checkpoint file
43
+
44
+ Returns
45
+ -------
46
+ dict
47
+ Dictionary containing VOCS and checkpoint data
48
+ """
49
+ # Load the checkpoint
50
+ with open(fname) as f:
51
+ checkpoint_data = json.load(f)
52
+
53
+ if "vocs" in checkpoint_data:
54
+ return checkpoint_data
55
+
56
+ # Legacy checkpoints w/o VOCS
57
+ vocs_fname = os.path.join(os.path.dirname(fname), "../vocs.txt")
58
+ if not os.path.exists(vocs_fname):
59
+ raise ValueError(
60
+ f'Checkpoint "{fname}" does not contain a VOCS object and no '
61
+ f'VOCS file was found at "{vocs_fname}".'
62
+ )
63
+
64
+ with open(vocs_fname) as f:
65
+ vocs = VOCS(**json.load(f))
66
+
67
+ return {"vocs": vocs, **checkpoint_data}
68
+
69
+ @model_validator(mode="before")
70
+ @classmethod
71
+ def load_from_checkpoint(cls, values):
72
+ """
73
+ Load from checkpoint file if checkpoint_file is provided.
74
+ """
75
+ # Case when a checkpoint file has been supplied
76
+ if isinstance(values, dict) and "checkpoint_file" in values:
77
+ checkpoint_file = values.pop("checkpoint_file")
78
+ if checkpoint_file is not None:
79
+ # Load checkpoint data
80
+ checkpoint_data = cls._load_checkpoint_data(checkpoint_file)
81
+
82
+ # Merge with user data precedence
83
+ merged_data = {**checkpoint_data, **values}
84
+ return merged_data
85
+
86
+ # No checkpoint
87
+ return values
88
+
89
+ def _save_checkpoint(self, path: str | os.PathLike) -> str:
90
+ """
91
+ Write a checkpoint of the generator state to disk.
92
+
93
+ Parameters
94
+ ----------
95
+ path : str or os.PathLike
96
+ Directory into which the checkpoint file is written. Created if it
97
+ does not already exist.
98
+
99
+ Returns
100
+ -------
101
+ str
102
+ Path to the checkpoint file which was written.
103
+ """
104
+ # Set up the output directory
105
+ os.makedirs(path, exist_ok=True)
106
+
107
+ # Create a base filename
108
+ base_checkpoint_filename = datetime.now().strftime("%Y%m%d_%H%M%S")
109
+ checkpoint_path = os.path.join(path, f"{base_checkpoint_filename}_1.txt")
110
+
111
+ # Check if file exists and increment counter until we find a free filename
112
+ counter = 2
113
+ while os.path.exists(checkpoint_path):
114
+ checkpoint_path = os.path.join(
115
+ path, f"{base_checkpoint_filename}_{counter}.txt"
116
+ )
117
+ counter += 1
118
+
119
+ # Now we have a unique filename
120
+ with open(checkpoint_path, "w") as f:
121
+ f.write(self.to_json())
122
+
123
+ return checkpoint_path
@@ -0,0 +1,239 @@
1
+ from pydantic import BaseModel, Field, computed_field, field_validator, model_validator
2
+ import logging
3
+ import os
4
+ import pandas as pd
5
+ import time
6
+
7
+ from ..checkpoints import CheckpointMixin
8
+ from ..deduplicated import DeduplicatedGeneratorBase
9
+
10
+ POPULATION_METADATA_COLUMNS = [
11
+ "xopt_generation",
12
+ "xopt_candidate_idx",
13
+ "xopt_runtime",
14
+ "xopt_error",
15
+ ]
16
+
17
+
18
+ class _InstanceLogger(logging.Logger):
19
+ """
20
+ Logger owned by a single object. Used for per-object logging in generator.
21
+ """
22
+
23
+ def __reduce__(self):
24
+ return _make_instance_logger, (self.name, self.parent.name, self.level)
25
+
26
+
27
+ def _make_instance_logger(name: str, parent_name: str, level: int) -> logging.Logger:
28
+ """
29
+ Build an unregistered logger which propagates to an existing named logger.
30
+
31
+ Parameters
32
+ ----------
33
+ name : str
34
+ Name recorded on emitted records.
35
+ parent_name : str
36
+ Name of the logger records propagate to.
37
+ level : int
38
+ Level of the new logger.
39
+
40
+ Returns
41
+ -------
42
+ logging.Logger
43
+ """
44
+ logger = _InstanceLogger(name, level)
45
+ logger.parent = logging.getLogger(parent_name)
46
+ return logger
47
+
48
+
49
+ class _ResolvedOutputDirMixin(BaseModel):
50
+ """
51
+ This mixin just adds a validator to strip the parameter `output_dir_resolved` from input.
52
+ This is saved as a computed field by the model, but will error on loading from checkpoint
53
+ due to extra fields being disallows. It has to be a mixin here to get run before the
54
+ `CheckpointMixin` is fired.
55
+ """
56
+
57
+ @model_validator(mode="before")
58
+ @classmethod
59
+ def drop_resolved_output_dir(cls, values):
60
+ """Discard "output_dir_resolved" so a reloaded generator resolves its own."""
61
+ if isinstance(values, dict) and "output_dir_resolved" in values:
62
+ values = dict(values)
63
+ values.pop("output_dir_resolved")
64
+ return values
65
+
66
+
67
+ class GAGeneratorBase(
68
+ CheckpointMixin, _ResolvedOutputDirMixin, DeduplicatedGeneratorBase
69
+ ):
70
+ """
71
+ Base class for genetic algorithm generators which write output and checkpoints.
72
+
73
+ Handles the output directory, log file, and periodic checkpointing on behalf of
74
+ subclasses. Subclasses call `end_generation` once each time a generation is
75
+ completed and everything else is taken care of.
76
+
77
+ Nothing is written to disk until the generator is used, so building or
78
+ deserializing one never touches the filesystem. Each generator owns its logger.
79
+
80
+ Parameters
81
+ ----------
82
+ output_dir : str or os.PathLike, optional
83
+ Directory to save algorithm state and population history, or None to write
84
+ nothing. Stored as a string and never modified; environment variables and "~"
85
+ are expanded when the path is used. If the directory already contains data, a
86
+ number is appended to avoid overwriting it.
87
+ checkpoint_freq : int, default=1
88
+ Frequency (in generations) at which checkpoints are saved. Set to -1 to
89
+ disable checkpointing.
90
+ log_level : int
91
+ Level of log messages written to "log.txt".
92
+
93
+ Attributes
94
+ ----------
95
+ output_dir_resolved : str
96
+ Expanded, collision free path `output_dir` was resolved to. All file writes go
97
+ here. Empty until the directory has been created.
98
+ """
99
+
100
+ output_dir: str | None = Field(
101
+ None,
102
+ description="Directory to save algorithm state and population history, or None "
103
+ "to write nothing. Environment variables and a leading '~' are expanded when "
104
+ "it is used and a number is appended if it already contains data",
105
+ )
106
+ checkpoint_freq: int = Field(
107
+ 1,
108
+ description="How often (in generations) to save checkpoints (set to -1 to disable)",
109
+ )
110
+ log_level: int = Field(
111
+ logging.INFO, description="Log message level output to log.txt"
112
+ )
113
+ _output_dir_resolved: str = "" # Empty until the output directory has been created
114
+
115
+ @field_validator("output_dir", mode="before")
116
+ @classmethod
117
+ def validate_output_dir(cls, value):
118
+ """Accept any os.PathLike, storing it as a string."""
119
+ if isinstance(value, os.PathLike):
120
+ return os.fspath(value)
121
+ return value
122
+
123
+ @computed_field
124
+ @property
125
+ def output_dir_resolved(self) -> str:
126
+ """Directory output is written to, empty until it has been created."""
127
+ return self._output_dir_resolved
128
+
129
+ def model_post_init(self, context):
130
+ # Get a unique logger owned by this instance.
131
+ self._logger = _make_instance_logger(
132
+ f"{type(self).__module__}.{type(self).__name__}",
133
+ type(self).__module__,
134
+ self.log_level,
135
+ )
136
+
137
+ def _prepare_output(self) -> None:
138
+ """
139
+ Resolve and create the output directory and begin logging to file.
140
+
141
+ Repeated calls do nothing. The requested path is expanded and, if it already
142
+ holds data, a number is appended. The result is kept in `output_dir_resolved`.
143
+ """
144
+ if (self.output_dir is None) or self._output_dir_resolved:
145
+ return
146
+
147
+ # Check if directory exists and do collision avoidance. Suffixes are applied to
148
+ # the expanded path so that they cannot land inside an environment variable or
149
+ # "~". The path is normalized first so that a trailing separator does not put
150
+ # the suffixed directory inside the one being protected.
151
+ requested = os.path.normpath(
152
+ os.path.expanduser(os.path.expandvars(self.output_dir))
153
+ )
154
+ resolved = requested
155
+ counter = 2
156
+ while os.path.exists(resolved) and os.listdir(resolved):
157
+ resolved = f"{requested}_{counter}"
158
+ counter += 1
159
+ if resolved != requested:
160
+ self._logger.info(
161
+ f'detected existing output_dir "{requested}" and corrected '
162
+ f'to "{resolved}" to avoid overwriting'
163
+ )
164
+
165
+ # We are now setup
166
+ os.makedirs(resolved, exist_ok=True)
167
+ self._output_dir_resolved = resolved
168
+
169
+ # Set up file logging
170
+ log_file_path = os.path.join(resolved, "log.txt")
171
+ file_handler = logging.FileHandler(log_file_path, mode="w")
172
+ file_handler.setLevel(self.log_level)
173
+ file_handler.setFormatter(
174
+ logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
175
+ )
176
+ self._logger.addHandler(file_handler)
177
+ self._logger.info(f"routing log output to file: {log_file_path}")
178
+
179
+ # Record the problem definition alongside the data
180
+ # Note: this is necessary to include in output for users running analysis on the results
181
+ # ie to plot Pareto front, you need to know the names and direction of the objectives
182
+ with open(os.path.join(resolved, "vocs.txt"), "w") as f:
183
+ f.write(self.vocs.model_dump_json())
184
+
185
+ def end_generation(self, generation_index: int, population: list[dict]) -> None:
186
+ """
187
+ Record a completed generation, writing output and checkpoints as configured.
188
+
189
+ Parameters
190
+ ----------
191
+ generation_index : int
192
+ Index of the generation which was just completed.
193
+ population : list of dict
194
+ The individuals making up the completed population.
195
+ """
196
+ self._prepare_output()
197
+ if not self._output_dir_resolved:
198
+ return
199
+ output_dir = self._output_dir_resolved
200
+ save_start_t = time.perf_counter()
201
+
202
+ # Save all Xopt data
203
+ self.data.to_csv(os.path.join(output_dir, "data.csv"), index=False)
204
+
205
+ # Construct the DataFrame for this population
206
+ pop_df = pd.DataFrame(population)
207
+ pop_df["xopt_generation"] = generation_index
208
+
209
+ # Normalize the columns in the DataFrame
210
+ # Avoid schema changing part way through optimization so we can write CSV in append mode
211
+ pop_df = pop_df.reindex(
212
+ columns=self.vocs.all_names + POPULATION_METADATA_COLUMNS
213
+ )
214
+
215
+ # Write population DataFrame to file
216
+ csv_path = os.path.join(output_dir, "populations.csv")
217
+ pop_df.to_csv(
218
+ csv_path, index=False, mode="a", header=not os.path.isfile(csv_path)
219
+ )
220
+ self._logger.debug(
221
+ f'saved optimization data to "{output_dir}" '
222
+ f"in {1000 * (time.perf_counter() - save_start_t):.2f}ms"
223
+ )
224
+
225
+ # Save a checkpoint if one is due
226
+ if self.checkpoint_freq > 0 and (generation_index % self.checkpoint_freq == 0):
227
+ checkpoint_path = self._save_checkpoint(
228
+ os.path.join(output_dir, "checkpoints")
229
+ )
230
+ self._logger.debug(f'saved checkpoint file "{checkpoint_path}"')
231
+
232
+ def close_log_file(self):
233
+ """
234
+ Closes out the log file (if used)
235
+ """
236
+ for handler in list(self._logger.handlers):
237
+ if isinstance(handler, logging.FileHandler):
238
+ handler.close()
239
+ self._logger.removeHandler(handler)
@@ -2,7 +2,7 @@ import array
2
2
  import logging
3
3
  import os
4
4
  import random
5
- from typing import Dict, List, Optional
5
+ from typing import Any, Dict, List, Optional
6
6
 
7
7
  import pandas as pd
8
8
  from deap import algorithms as deap_algorithms, base as deap_base, tools as deap_tools
@@ -88,6 +88,8 @@ class CNSGAGenerator(Generator):
88
88
  )
89
89
  _children: List[Dict] = PrivateAttr([])
90
90
  _offspring: Optional[pd.DataFrame] = PrivateAttr(None)
91
+ _loaded_population: pd.DataFrame | None = PrivateAttr(None)
92
+ _toolbox: Any = PrivateAttr(None)
91
93
  population: Optional[pd.DataFrame] = Field(None)
92
94
 
93
95
  model_config = ConfigDict(extra="allow")