xopt 3.2.2__tar.gz → 3.3.0__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 (220) hide show
  1. {xopt-3.2.2/xopt.egg-info → xopt-3.3.0}/PKG-INFO +4 -3
  2. {xopt-3.2.2 → xopt-3.3.0}/README.md +3 -2
  3. {xopt-3.2.2 → xopt-3.3.0}/docs/algorithms.md +2 -1
  4. xopt-3.3.0/docs/api/generators/sequential/scipy.md +80 -0
  5. xopt-3.3.0/docs/api/stopping_conditions.md +33 -0
  6. {xopt-3.2.2 → xopt-3.3.0}/docs/index.md +4 -3
  7. {xopt-3.2.2 → xopt-3.3.0}/mkdocs.yml +3 -1
  8. {xopt-3.2.2 → xopt-3.3.0}/pyproject.toml +2 -1
  9. {xopt-3.2.2 → xopt-3.3.0}/xopt/_version.py +3 -3
  10. {xopt-3.2.2 → xopt-3.3.0}/xopt/asynchronous.py +7 -0
  11. {xopt-3.2.2 → xopt-3.3.0}/xopt/base.py +5 -2
  12. xopt-3.3.0/xopt/entrypoint/__init__.py +1 -0
  13. xopt-3.3.0/xopt/entrypoint/mpi.py +172 -0
  14. xopt-3.2.2/xopt/entrypoint.py → xopt-3.3.0/xopt/entrypoint/multiprocessing.py +11 -119
  15. xopt-3.3.0/xopt/entrypoint/utils.py +136 -0
  16. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/__init__.py +5 -1
  17. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/bayesian_generator.py +4 -3
  18. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/utils.py +12 -135
  19. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/visualize.py +15 -22
  20. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/sequential/__init__.py +2 -0
  21. xopt-3.3.0/xopt/generators/sequential/scipy.py +536 -0
  22. xopt-3.3.0/xopt/mpi/run.py +6 -0
  23. {xopt-3.2.2 → xopt-3.3.0}/xopt/stopping_conditions.py +37 -0
  24. xopt-3.3.0/xopt/tests/generators/bayesian/__init__.py +0 -0
  25. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_utils.py +37 -158
  26. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_visualize.py +26 -0
  27. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/ga/test_nsga2.py +36 -1
  28. xopt-3.3.0/xopt/tests/generators/sequential/test_scipy.py +727 -0
  29. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/sequential/test_serialization.py +11 -2
  30. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_asynch_xopt.py +45 -0
  31. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_entrypoint.py +99 -10
  32. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_stopping_condition.py +157 -0
  33. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_utils.py +7 -0
  34. {xopt-3.2.2 → xopt-3.3.0}/xopt/utils.py +7 -5
  35. {xopt-3.2.2 → xopt-3.3.0/xopt.egg-info}/PKG-INFO +4 -3
  36. {xopt-3.2.2 → xopt-3.3.0}/xopt.egg-info/SOURCES.txt +7 -2
  37. xopt-3.3.0/xopt.egg-info/entry_points.txt +3 -0
  38. {xopt-3.2.2 → xopt-3.3.0}/xopt.egg-info/scm_file_list.json +7 -2
  39. xopt-3.3.0/xopt.egg-info/scm_version.json +8 -0
  40. xopt-3.2.2/docs/api/stopping_conditions.md +0 -3
  41. xopt-3.2.2/xopt/generators/scipy/__init__.py +0 -4
  42. xopt-3.2.2/xopt/mpi/run.py +0 -98
  43. xopt-3.2.2/xopt/tests/test_mpi.py +0 -100
  44. xopt-3.2.2/xopt.egg-info/entry_points.txt +0 -2
  45. xopt-3.2.2/xopt.egg-info/scm_version.json +0 -8
  46. {xopt-3.2.2 → xopt-3.3.0}/.pre-commit-config.yaml +0 -0
  47. {xopt-3.2.2 → xopt-3.3.0}/LICENSE +0 -0
  48. {xopt-3.2.2 → xopt-3.3.0}/MANIFEST.in +0 -0
  49. {xopt-3.2.2 → xopt-3.3.0}/benchmarks/__init__.py +0 -0
  50. {xopt-3.2.2 → xopt-3.3.0}/benchmarks/test_mo.py +0 -0
  51. {xopt-3.2.2 → xopt-3.3.0}/benchmarks/test_neldermead.py +0 -0
  52. {xopt-3.2.2 → xopt-3.3.0}/benchmarks/test_ucb.py +0 -0
  53. {xopt-3.2.2 → xopt-3.3.0}/codecov.yml +0 -0
  54. {xopt-3.2.2 → xopt-3.3.0}/docs/api/evaluator.md +0 -0
  55. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/bax/acquisition_functions.md +0 -0
  56. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/bax/algorithms.md +0 -0
  57. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/bax/bax_generator.md +0 -0
  58. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/bax/visualize.md +0 -0
  59. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/bayesian_exploration.md +0 -0
  60. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/bayesian_generator.md +0 -0
  61. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/expected_improvement.md +0 -0
  62. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/mggpo.md +0 -0
  63. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/mobo.md +0 -0
  64. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/models/base_model_constructor.md +0 -0
  65. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/models/standard_model_constructor.md +0 -0
  66. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/models/time_dependent_model_constructor.md +0 -0
  67. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/multi_fidelity.md +0 -0
  68. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/time_dependent.md +0 -0
  69. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/turbo.md +0 -0
  70. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/upper_confidence_bound.md +0 -0
  71. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/bayesian/utils.md +0 -0
  72. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/deduplicated.md +0 -0
  73. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/ga/cnsga.md +0 -0
  74. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/ga/deap_creator.md +0 -0
  75. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/ga/deap_fitness_with_constraints.md +0 -0
  76. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/ga/nsga2.md +0 -0
  77. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/ga/operators.md +0 -0
  78. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/random.md +0 -0
  79. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/sequential/extremumseeking.md +0 -0
  80. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/sequential/neldermead.md +0 -0
  81. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/sequential/rcds.md +0 -0
  82. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/sequential/sequential_generator.md +0 -0
  83. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators/utils.md +0 -0
  84. {xopt-3.2.2 → xopt-3.3.0}/docs/api/generators.md +0 -0
  85. {xopt-3.2.2 → xopt-3.3.0}/docs/api/numerical_optimizer.md +0 -0
  86. {xopt-3.2.2 → xopt-3.3.0}/docs/api/utils.md +0 -0
  87. {xopt-3.2.2 → xopt-3.3.0}/docs/api/vocs.md +0 -0
  88. {xopt-3.2.2 → xopt-3.3.0}/docs/api/xopt.md +0 -0
  89. {xopt-3.2.2 → xopt-3.3.0}/docs/assets/Xopt-logo.png +0 -0
  90. {xopt-3.2.2 → xopt-3.3.0}/docs/assets/xopt_overview.pdf +0 -0
  91. {xopt-3.2.2 → xopt-3.3.0}/docs/hooks/zip_generator.py +0 -0
  92. {xopt-3.2.2 → xopt-3.3.0}/docs/installation.md +0 -0
  93. {xopt-3.2.2 → xopt-3.3.0}/docs/overrides/main.html +0 -0
  94. {xopt-3.2.2 → xopt-3.3.0}/docs/stylesheets/extra.css +0 -0
  95. {xopt-3.2.2 → xopt-3.3.0}/environment.yml +0 -0
  96. {xopt-3.2.2 → xopt-3.3.0}/scripts/execute_notebooks.bash +0 -0
  97. {xopt-3.2.2 → xopt-3.3.0}/scripts/run_benchmarks.py +0 -0
  98. {xopt-3.2.2 → xopt-3.3.0}/scripts/run_examples.py +0 -0
  99. {xopt-3.2.2 → xopt-3.3.0}/scripts/run_tests.py +0 -0
  100. {xopt-3.2.2 → xopt-3.3.0}/setup.cfg +0 -0
  101. {xopt-3.2.2 → xopt-3.3.0}/xopt/__init__.py +0 -0
  102. {xopt-3.2.2 → xopt-3.3.0}/xopt/errors.py +0 -0
  103. {xopt-3.2.2 → xopt-3.3.0}/xopt/evaluator.py +0 -0
  104. {xopt-3.2.2 → xopt-3.3.0}/xopt/generator.py +0 -0
  105. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/__init__.py +0 -0
  106. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/base_model.py +0 -0
  107. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/bax/__init__.py +0 -0
  108. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/bax/acquisition.py +0 -0
  109. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/bax/algorithms.py +0 -0
  110. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/bax/visualize.py +0 -0
  111. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/bax_generator.py +0 -0
  112. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/bayesian_exploration.py +0 -0
  113. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/custom_botorch/__init__.py +0 -0
  114. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/custom_botorch/constrained_acquisition.py +0 -0
  115. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/custom_botorch/hessian_kernel.py +0 -0
  116. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/custom_botorch/heteroskedastic.py +0 -0
  117. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/custom_botorch/log_acquisition_function.py +0 -0
  118. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/custom_botorch/multi_fidelity.py +0 -0
  119. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/expected_improvement.py +0 -0
  120. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/mggpo.py +0 -0
  121. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/mobo.py +0 -0
  122. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/models/__init__.py +0 -0
  123. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/models/approximate.py +0 -0
  124. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/models/prior_mean.py +0 -0
  125. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/models/standard.py +0 -0
  126. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/models/time_dependent.py +0 -0
  127. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/multi_fidelity.py +0 -0
  128. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/objectives.py +0 -0
  129. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/time_dependent.py +0 -0
  130. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/turbo.py +0 -0
  131. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/bayesian/upper_confidence_bound.py +0 -0
  132. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/checkpoints.py +0 -0
  133. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/deduplicated.py +0 -0
  134. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/ga/__init__.py +0 -0
  135. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/ga/base.py +0 -0
  136. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/ga/cnsga.py +0 -0
  137. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/ga/deap_creator.py +0 -0
  138. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/ga/deap_fitness_with_constraints.py +0 -0
  139. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/ga/nsga2.py +0 -0
  140. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/ga/operators.py +0 -0
  141. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/random.py +0 -0
  142. {xopt-3.2.2/xopt/mpi → xopt-3.3.0/xopt/generators/scipy}/__init__.py +0 -0
  143. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/scipy/latin_hypercube.py +0 -0
  144. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/sequential/extremumseeking.py +0 -0
  145. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/sequential/neldermead.py +0 -0
  146. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/sequential/rcds.py +0 -0
  147. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/sequential/sequential_generator.py +0 -0
  148. {xopt-3.2.2 → xopt-3.3.0}/xopt/generators/utils.py +0 -0
  149. {xopt-3.2.2 → xopt-3.3.0}/xopt/log.py +0 -0
  150. {xopt-3.2.2/xopt/resources → xopt-3.3.0/xopt/mpi}/__init__.py +0 -0
  151. {xopt-3.2.2 → xopt-3.3.0}/xopt/numerical_optimizer.py +0 -0
  152. {xopt-3.2.2 → xopt-3.3.0}/xopt/pydantic.py +0 -0
  153. {xopt-3.2.2/xopt/resources/test_functions → xopt-3.3.0/xopt/resources}/__init__.py +0 -0
  154. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/bench_framework.py +0 -0
  155. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/bench_functions/__init__.py +0 -0
  156. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/bench_functions/generators.py +0 -0
  157. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/bench_functions/models.py +0 -0
  158. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/bench_profiler.py +0 -0
  159. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/bench_runner.py +0 -0
  160. {xopt-3.2.2/xopt/tests → xopt-3.3.0/xopt/resources/test_functions}/__init__.py +0 -0
  161. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/test_functions/ackley_20.py +0 -0
  162. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/test_functions/haverly_pooling.py +0 -0
  163. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/test_functions/modified_tnk.py +0 -0
  164. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/test_functions/multi_objective.py +0 -0
  165. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/test_functions/problem.py +0 -0
  166. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/test_functions/rosenbrock.py +0 -0
  167. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/test_functions/sinusoid_1d.py +0 -0
  168. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/test_functions/tnk.py +0 -0
  169. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/test_functions/zdt.py +0 -0
  170. {xopt-3.2.2 → xopt-3.3.0}/xopt/resources/testing.py +0 -0
  171. {xopt-3.2.2/xopt/tests/generators → xopt-3.3.0/xopt/tests}/__init__.py +0 -0
  172. {xopt-3.2.2/xopt/tests/generators/bayesian → xopt-3.3.0/xopt/tests/generators}/__init__.py +0 -0
  173. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/conftest.py +0 -0
  174. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_bax.py +0 -0
  175. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_bax_visualize.py +0 -0
  176. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_bayesian_exploration.py +0 -0
  177. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_bayesian_generator.py +0 -0
  178. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_constraints.py +0 -0
  179. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_contextual_bo.py +0 -0
  180. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_custom_model.py +0 -0
  181. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_discrete_integration.py +0 -0
  182. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_expected_improvement.py +0 -0
  183. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_hessian_kernel.py +0 -0
  184. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_high_level.py +0 -0
  185. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_mggpo.py +0 -0
  186. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_mobo.py +0 -0
  187. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_model_constructor.py +0 -0
  188. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_multi_fidelity.py +0 -0
  189. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_objectives.py +0 -0
  190. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_time_dependent_bo.py +0 -0
  191. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_turbo.py +0 -0
  192. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/bayesian/test_upper_confidence_bound.py +0 -0
  193. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/external/test_aposmm.py +0 -0
  194. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/ga/test_base.py +0 -0
  195. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/ga/test_cnsga.py +0 -0
  196. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/ga/test_deap_creator.py +0 -0
  197. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/sequential/test_extremum_seeking.py +0 -0
  198. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/sequential/test_neldermead.py +0 -0
  199. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/sequential/test_rcds.py +0 -0
  200. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/sequential/test_sequential.py +0 -0
  201. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/test_checkpoints.py +0 -0
  202. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/test_deduplicated.py +0 -0
  203. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/test_latin_hypercube.py +0 -0
  204. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/test_operators.py +0 -0
  205. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/test_random.py +0 -0
  206. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/generators/test_utils.py +0 -0
  207. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_evaluator.py +0 -0
  208. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_generator.py +0 -0
  209. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_io.py +0 -0
  210. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_log.py +0 -0
  211. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_numerical_optimizer.py +0 -0
  212. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_perf.py +0 -0
  213. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_pydantic.py +0 -0
  214. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_resources.py +0 -0
  215. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_vocs.py +0 -0
  216. {xopt-3.2.2 → xopt-3.3.0}/xopt/tests/test_xopt.py +0 -0
  217. {xopt-3.2.2 → xopt-3.3.0}/xopt/vocs.py +0 -0
  218. {xopt-3.2.2 → xopt-3.3.0}/xopt.egg-info/dependency_links.txt +0 -0
  219. {xopt-3.2.2 → xopt-3.3.0}/xopt.egg-info/requires.txt +0 -0
  220. {xopt-3.2.2 → xopt-3.3.0}/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.2
3
+ Version: 3.3.0
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
@@ -305,11 +305,12 @@ Currenty **Xopt** provides:
305
305
  - `extremum_seeking` Extremum seeking time-dependent optimization
306
306
  - `rcds` Robust Conjugate Direction Search (RCDS)
307
307
  - `neldermead` Nelder-Mead Simplex
308
+ - `scipy` Scipy-based optimization algorithms (Powell, L-BFGS-B, etc.)
308
309
  - Sampling algorithms:
309
310
  - `random` Uniform random sampling
310
311
  - Convenient YAML/JSON based input format
311
312
  - Driver programs:
312
- - `xopt.mpi.run` Parallel MPI execution using this input format
313
+ - `xopt-mpirun` Parallel MPI execution using this input format
313
314
 
314
315
  Xopt does **not** provide:
315
316
  - your custom simulation or experimental measurement via an `evaluate` function.
@@ -428,7 +429,7 @@ Using MPI
428
429
  ===============
429
430
  Example MPI run, with `xopt.yaml` as the only user-defined file:
430
431
  ```b
431
- mpirun -n 64 python -m mpi4py.futures -m xopt.mpi.run xopt.yaml
432
+ mpirun -n 64 xopt-mpirun xopt.yaml
432
433
  ```
433
434
 
434
435
 
@@ -53,11 +53,12 @@ Currenty **Xopt** provides:
53
53
  - `extremum_seeking` Extremum seeking time-dependent optimization
54
54
  - `rcds` Robust Conjugate Direction Search (RCDS)
55
55
  - `neldermead` Nelder-Mead Simplex
56
+ - `scipy` Scipy-based optimization algorithms (Powell, L-BFGS-B, etc.)
56
57
  - Sampling algorithms:
57
58
  - `random` Uniform random sampling
58
59
  - Convenient YAML/JSON based input format
59
60
  - Driver programs:
60
- - `xopt.mpi.run` Parallel MPI execution using this input format
61
+ - `xopt-mpirun` Parallel MPI execution using this input format
61
62
 
62
63
  Xopt does **not** provide:
63
64
  - your custom simulation or experimental measurement via an `evaluate` function.
@@ -176,7 +177,7 @@ Using MPI
176
177
  ===============
177
178
  Example MPI run, with `xopt.yaml` as the only user-defined file:
178
179
  ```b
179
- mpirun -n 64 python -m mpi4py.futures -m xopt.mpi.run xopt.yaml
180
+ mpirun -n 64 xopt-mpirun xopt.yaml
180
181
  ```
181
182
 
182
183
 
@@ -65,7 +65,8 @@ Scipy Generators
65
65
  These generators serve as wrappers for algorithms implemented in scipy.
66
66
 
67
67
  - [`NelderMeadGenerator`](examples/sequential/neldermead.ipynb): implements Nelder-Mead (simplex) optimization.
68
- - [`LatinHypercubeGenerator`](examples/scipy/latin_hypercube.ipynb): perform latin hypercube sampling of the evaluation function.
68
+ - [`ScipyGenerator`](examples/sequential/scipy.ipynb): generic wrapper around `scipy.optimize.minimize` methods.
69
+ - [`LatinHypercubeGenerator`](examples/other/latin_hypercube.ipynb): performs latin hypercube sampling of the evaluation function.
69
70
 
70
71
  RCDS Generators
71
72
  ===
@@ -0,0 +1,80 @@
1
+ # Scipy Minimize Generator
2
+
3
+ `ScipyGenerator` exposes scipy's `optimize.minimize` methods through Xopt's sequential ingest/suggest interface.
4
+
5
+ ## Integration Model
6
+
7
+ Xopt evaluates objective functions externally, one point at a time. `scipy.optimize.minimize` expects an in-process callable objective. `ScipyGenerator` bridges this mismatch by running one persistent scipy session in a worker thread:
8
+
9
+ 1. A cache is built from prior evaluations (`data`) keyed by rounded variable values.
10
+ 2. A single `minimize` call starts in a background thread.
11
+ 3. The objective callback first checks the cache.
12
+ 4. For an uncached point, that point is pushed to Xopt via a request queue.
13
+ 5. Xopt evaluates the point externally and calls `add_data`.
14
+ 6. The objective value is sent back through a response queue, and the same scipy run continues from in-memory state.
15
+
16
+ Only the first `add_data` call answering a pending request sends a response to
17
+ scipy. Repeated submissions of the same candidate remain in the data history,
18
+ but cannot answer a later request. Values are also cached under the requested
19
+ coordinates, so small readback differences accepted by sequential point
20
+ validation do not cause cache misses after a session restart.
21
+
22
+ ## Performance Notes
23
+
24
+ - Cache reconstruction is O(N) when a session starts or data is reloaded.
25
+ - The active scipy run is maintained between `step` calls; `minimize` is not restarted each step.
26
+ - Keys are rounded to 12 decimals before cache lookup to reduce floating-point key mismatch issues.
27
+
28
+ ## Supported Methods
29
+
30
+ `method` is validated against bounded scipy methods supported by this wrapper:
31
+
32
+ - `Nelder-Mead`
33
+ - `Powell`
34
+ - `L-BFGS-B`
35
+ - `TNC`
36
+ - `SLSQP`
37
+ - `trust-constr`
38
+ - `COBYLA`
39
+ - `COBYQA`
40
+
41
+ Invalid or empty method names fail validation.
42
+
43
+ ## Session Lifecycle and Errors
44
+
45
+ - `reset()` stops the active worker session and clears the result and completion state.
46
+ - `set_data(...)` stops any active session, clears completion state, reloads data, and rebuilds the cache.
47
+ - Each worker retains its own stop event, queues, and cache. Shutdown waits up to two seconds and warns if the worker is still running in scipy; that worker cannot consume responses or publish requests, results, or errors into a subsequent session.
48
+ - `result` exposes scipy's `OptimizeResult` after termination, including `success`, `message`, and solver-specific fields such as `nit`. It is `None` before termination.
49
+ - `is_done` is true once scipy terminates, including unsuccessful termination (for example, reaching an iteration limit). Check `result.success` to distinguish successful convergence.
50
+ - Once terminated, later `generate()` calls do not restart scipy or rebuild the cache. For compatibility, they still return the latest known data row, with a `RuntimeWarning` emitted once per session on this fallback path. Further explicit `Xopt.step()` calls will re-evaluate and append this duplicate; stop stepping when `generator.is_done` is true.
51
+ - Common scipy `ValueError` messages are remapped to clearer runtime errors (for example unsupported solver availability or bound handling).
52
+
53
+ ## State Restoration
54
+
55
+ For model-level roundtrips, use pydantic serialization:
56
+
57
+ - `model_dump()`
58
+ - `model_validate(...)`
59
+
60
+ Then restore the evaluation history with `set_data(...)` so the cache and last outcome are reconstructed before continuing optimization.
61
+
62
+ The class also defines `__getstate__` and `__setstate__` for explicit state handling of non-picklable runtime thread objects.
63
+ Pickling does not stop the original worker. Pickle and deep-copy roundtrips retain
64
+ completed results and the completion latch without sharing runtime thread objects;
65
+ model-level roundtrips restart from the restored evaluation history instead.
66
+ Requested-coordinate cache entries are retained through `reset()`, pickle, and
67
+ deep-copy roundtrips. Replacing the dataset with `set_data(...)` clears these
68
+ entries; model-level roundtrips rebuild from observed coordinates in the restored
69
+ history.
70
+
71
+ ## Configuration
72
+
73
+ Typical fields:
74
+
75
+ - `method`: scipy minimization method name, e.g. `Powell`, `Nelder-Mead`, `L-BFGS-B`.
76
+ - `initial_point`: optional starting point dictionary.
77
+ - `tol`, `options`: passed directly to `scipy.optimize.minimize`.
78
+ - `scipy_kwargs`: additional keyword arguments forwarded to scipy.
79
+
80
+ ::: xopt.generators.sequential.scipy
@@ -0,0 +1,33 @@
1
+ # Stopping Conditions
2
+
3
+ ## Maximum elapsed time
4
+
5
+ Use `MaxTimeCondition` to stop after a positive, finite number of wall-clock
6
+ seconds:
7
+
8
+ ```python
9
+ from xopt.stopping_conditions import MaxTimeCondition
10
+
11
+ X.stopping_condition = MaxTimeCondition(max_time=60.0)
12
+ X.run()
13
+ ```
14
+
15
+ The timer starts when `should_stop()` is first called, normally at the start of
16
+ `run()`, and uses a monotonic clock. Time before that first check is not counted.
17
+ Conditions are checked between optimization steps, so an
18
+ in-progress evaluation is allowed to finish and the time limit may be exceeded.
19
+ The condition also works without evaluation data and can be nested inside a
20
+ `CompositeCondition`.
21
+
22
+ For YAML configuration:
23
+
24
+ ```yaml
25
+ stopping_condition:
26
+ name: MaxTimeCondition
27
+ max_time: 60.0
28
+ ```
29
+
30
+ Only the time limit is serialized. Loading a saved configuration resets the
31
+ timer; the full time budget starts at the first check.
32
+
33
+ ::: xopt.stopping_conditions
@@ -42,12 +42,13 @@ Currenty **Xopt** provides:
42
42
  - [`extremum_seeking`](examples/sequential/extremum_seeking.ipynb) Extremum seeking time-dependent optimization
43
43
  - [`rcds`](examples/sequential/rcds.ipynb) Robust Conjugate Direction Search (RCDS)
44
44
  - [`neldermead`](examples/sequential/neldermead.ipynb) Nelder-Mead Simplex
45
+ - [`scipy`](examples/sequential/scipy.ipynb) Scipy-based optimization algorithms (Powell, L-BFGS-B, etc.)
45
46
  - Sampling algorithms:
46
47
  - `random` Uniform random sampling
47
48
  - Convenient YAML/JSON based input format
48
49
  - Driver programs:
49
- - [`xopt-run`](examples/basic/xopt_cli.md) Run Xopt from the command line using a YAML config file
50
- - `xopt.mpi.run` Parallel MPI execution using this input format
50
+ - [`xopt-run`](examples/basic/xopt_cli.md#xopt-run-usage) Run Xopt from the command line using a YAML config file
51
+ - [`xopt-mpirun`](examples/basic/xopt_cli.md#xopt-mpirun-usage) Parallel MPI execution using this input format
51
52
 
52
53
  **Xopt** does **not** provide:
53
54
  - your custom simulation via an `evaluate` function.
@@ -151,7 +152,7 @@ Using MPI
151
152
  ===============
152
153
  Example MPI run, with `xopt.yaml` as the only user-defined file:
153
154
  ```b
154
- mpirun -n 64 python -m mpi4py.futures -m xopt.mpi.run xopt.yaml
155
+ mpirun -n 64 xopt-mpirun xopt.yaml
155
156
  ```
156
157
 
157
158
 
@@ -63,11 +63,12 @@ nav:
63
63
  - Genetic operators: examples/ga/nsga2/genetic_operators.ipynb
64
64
 
65
65
  - Sequential:
66
+ - Scipy Minimize: examples/sequential/scipy.ipynb
66
67
  - Nelder-Mead: examples/sequential/neldermead.ipynb
67
68
  - Extremum seeking: examples/sequential/extremum_seeking.ipynb
68
69
  - RCDS: examples/sequential/rcds.ipynb
69
70
  - Other:
70
- - Latin Hypercube: examples/scipy/latin_hypercube.ipynb
71
+ - Latin Hypercube: examples/other/latin_hypercube.ipynb
71
72
  - Developer:
72
73
  - Benchmarking & Profiling: examples/developer/benchmarking.md
73
74
 
@@ -105,6 +106,7 @@ nav:
105
106
  - Genetic Operators: api/generators/ga/operators.md
106
107
  - Sequential generators:
107
108
  - Sequential Base Class: api/generators/sequential/sequential_generator.md
109
+ - Scipy Minimize: api/generators/sequential/scipy.md
108
110
  - RCDS: api/generators/sequential/rcds.md
109
111
  - Extremum Seeking: api/generators/sequential/extremumseeking.md
110
112
  - Nelder-Mead: api/generators/sequential/neldermead.md
@@ -71,7 +71,8 @@ doc = [
71
71
  Homepage = "https://github.com/xopt-org/xopt"
72
72
 
73
73
  [project.scripts]
74
- xopt-run = "xopt.entrypoint:main"
74
+ xopt-run = "xopt.entrypoint.multiprocessing:main"
75
+ xopt-mpirun = "xopt.entrypoint.mpi:main"
75
76
 
76
77
  [options]
77
78
  zip_safe = false
@@ -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.2'
22
- __version_tuple__ = version_tuple = (3, 2, 2)
21
+ __version__ = version = '3.3.0'
22
+ __version_tuple__ = version_tuple = (3, 3, 0)
23
23
 
24
- __commit_id__ = commit_id = 'gd4c488f75'
24
+ __commit_id__ = commit_id = 'gf13d21cd6'
@@ -159,6 +159,13 @@ class AsynchronousXopt(Xopt):
159
159
 
160
160
  self.add_data(new_data)
161
161
 
162
+ # dump to file(s) if specified
163
+ if len(new_data):
164
+ if self.xopt_dump_file is not None:
165
+ self.dump()
166
+ if self.data_dump_file is not None:
167
+ self.dump_data()
168
+
162
169
  # Cleanup
163
170
  self._input_data.drop(index, inplace=True)
164
171
 
@@ -391,8 +391,8 @@ class Xopt(XoptBaseModel):
391
391
  while True:
392
392
  # Check custom stopping condition
393
393
  if self.stopping_condition is not None:
394
- if self.data is not None and self.stopping_condition.should_stop(
395
- self.data, self.vocs
394
+ if self.stopping_condition.should_stop(
395
+ self.data if self.data is not None else pd.DataFrame(), self.vocs
396
396
  ):
397
397
  logger.info("Xopt is done. Stopping condition met.")
398
398
  break
@@ -539,6 +539,9 @@ class Xopt(XoptBaseModel):
539
539
  except DataError as exc:
540
540
  if self.strict:
541
541
  raise exc
542
+ warnings.warn(
543
+ f"Generator rejected {len(new_data)} new data point(s) (strict=False): {exc}"
544
+ )
542
545
 
543
546
  def reset_data(self):
544
547
  """
@@ -0,0 +1 @@
1
+ __all__ = []
@@ -0,0 +1,172 @@
1
+ from mpi4py import MPI
2
+ from mpi4py.futures import MPICommExecutor
3
+ import argparse
4
+ import logging
5
+ import os
6
+ import pandas as pd
7
+ import sys
8
+ import yaml
9
+
10
+ from xopt import AsynchronousXopt
11
+ from xopt.base import Xopt
12
+ from xopt.entrypoint.utils import (
13
+ merge_dicts,
14
+ normalize_initial_data,
15
+ override_to_dict,
16
+ setup_import_paths,
17
+ )
18
+ from xopt.log import set_handler_with_logger
19
+ from xopt.pydantic import remove_none_values
20
+
21
+
22
+ comm = MPI.COMM_WORLD
23
+ mpi_rank = comm.Get_rank()
24
+ mpi_size = comm.Get_size()
25
+
26
+ logger = logging.getLogger("xopt")
27
+
28
+
29
+ def run_mpi(
30
+ config,
31
+ verbosity=None,
32
+ asynchronous=True,
33
+ logfile=None,
34
+ python_path=None,
35
+ initial_data=None,
36
+ ):
37
+ """
38
+ Xopt MPI driver
39
+
40
+ Basic usage:
41
+
42
+ mpirun -n 4 xopt-mpirun xopt.yaml
43
+
44
+ Parameters
45
+ ----------
46
+ config : dict
47
+ Xopt configuration.
48
+ verbosity : int, optional
49
+ Verbosity count controlling the log level.
50
+ asynchronous : bool, default=True
51
+ Run with AsynchronousXopt instead of Xopt.
52
+ logfile : str, optional
53
+ File log messages are written to.
54
+ python_path : list of str, optional
55
+ Directories added to the module search path on every rank. Worker ranks import
56
+ the evaluation function themselves, so this must run before the Xopt object is
57
+ built.
58
+ initial_data : str, optional
59
+ CSV file of existing data used to seed the generator, read on the root rank.
60
+ """
61
+
62
+ level = "WARN"
63
+ if verbosity:
64
+ iv = verbosity
65
+ if iv == 1:
66
+ level = "WARN"
67
+ elif iv == 2:
68
+ level = "INFO"
69
+ elif iv >= 3:
70
+ level = "DEBUG"
71
+
72
+ set_handler_with_logger(level=level)
73
+
74
+ if logfile:
75
+ set_handler_with_logger(file=logfile, level=level)
76
+
77
+ setup_import_paths(python_path or [])
78
+
79
+ # logger.info(xopt_logo)
80
+ # logger.info('_________________________________')
81
+ logger.info(f"Parallel execution with {mpi_size} workers")
82
+
83
+ if asynchronous:
84
+ logger.info("Enabling async mode")
85
+ X = AsynchronousXopt(**config)
86
+ else:
87
+ X = Xopt(**config)
88
+
89
+ if mpi_rank == 0:
90
+ print(X)
91
+ sys.stdout.flush()
92
+
93
+ # Launch MPI executor (it is None for the workers)
94
+ with MPICommExecutor(MPI.COMM_WORLD, root=0) as executor:
95
+ if executor is not None:
96
+ X.evaluator.executor = executor
97
+ X.evaluator.max_workers = mpi_size
98
+
99
+ if initial_data is not None:
100
+ logger.info(f"Loading initial data from {initial_data}")
101
+ X.add_data(normalize_initial_data(pd.read_csv(initial_data), X.vocs))
102
+
103
+ X.run()
104
+
105
+
106
+ def main():
107
+ parser = argparse.ArgumentParser(description="Configure xopt")
108
+ parser.add_argument("input_file", help="input_file")
109
+ parser.add_argument("--logfile", "-l", help="Log file to write to")
110
+ parser.add_argument("--verbose", "-v", action="count", help="Show more log output")
111
+ parser.add_argument(
112
+ "--asynchronous",
113
+ "-a",
114
+ action=argparse.BooleanOptionalAction,
115
+ help="Use asynchronous execution",
116
+ default=True,
117
+ )
118
+ parser.add_argument(
119
+ "--python_path",
120
+ help="Additional path to add to Python import path for evaluation function module search",
121
+ action="append",
122
+ default=[],
123
+ )
124
+ parser.add_argument(
125
+ "--override",
126
+ help="Override config values using dot notation (e.g., generator.mutation_operator.eta_m=20)",
127
+ action="append",
128
+ default=[],
129
+ )
130
+ parser.add_argument(
131
+ "--initial_data",
132
+ help="CSV file with initial data to seed the generator before running",
133
+ type=str,
134
+ default=None,
135
+ )
136
+
137
+ args = parser.parse_args()
138
+ if mpi_rank == 0:
139
+ print(args)
140
+
141
+ input_file = args.input_file
142
+ logfile = args.logfile
143
+ verbosity = args.verbose
144
+ asynchronous = args.asynchronous
145
+
146
+ if not os.path.exists(input_file):
147
+ if mpi_rank == 0:
148
+ print(f"Input file does not exist: {input_file}", file=sys.stderr)
149
+ sys.exit(1)
150
+
151
+ with open(input_file) as f:
152
+ config = yaml.safe_load(f)
153
+ config = remove_none_values(config)
154
+
155
+ if args.override:
156
+ logger.info("Applying config file overrides:")
157
+ for override in args.override:
158
+ logger.info(f" {override}")
159
+ config = merge_dicts(config, override_to_dict(override))
160
+
161
+ run_mpi(
162
+ config,
163
+ verbosity=verbosity,
164
+ logfile=logfile,
165
+ asynchronous=asynchronous,
166
+ python_path=[os.getcwd()] + args.python_path,
167
+ initial_data=args.initial_data,
168
+ )
169
+
170
+
171
+ if __name__ == "__main__":
172
+ main()
@@ -1,61 +1,23 @@
1
- from .base import Xopt
2
- from .evaluator import DummyExecutor
3
- from .pydantic import remove_none_values
1
+ from ..base import Xopt
2
+ from ..evaluator import DummyExecutor
3
+ from ..pydantic import remove_none_values
4
+ from .utils import (
5
+ merge_dicts,
6
+ normalize_initial_data,
7
+ override_to_dict,
8
+ setup_import_paths,
9
+ )
4
10
  from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
5
11
  from contextlib import contextmanager
6
12
  import argparse
7
13
  import logging
8
14
  import os
9
15
  import pandas as pd
10
- import sys
11
16
  import yaml
12
17
 
13
18
 
14
19
  logger = logging.getLogger(__name__)
15
20
 
16
- _XOPT_INITIAL_COLS = ["xopt_candidate_idx", "xopt_runtime", "xopt_error"]
17
-
18
-
19
- def normalize_initial_data(df: pd.DataFrame, vocs) -> pd.DataFrame:
20
- """
21
- Validate and normalize a user-supplied initial-data DataFrame before
22
- passing it to Xopt.add_data.
23
-
24
- Parameters
25
- ----------
26
- df : pd.DataFrame
27
- Raw DataFrame loaded from the user's CSV.
28
- vocs : VOCS
29
- The VOCS object from the Xopt instance.
30
-
31
- Returns
32
- -------
33
- pd.DataFrame
34
- Normalized DataFrame with required VOCS columns present, xopt metadata
35
- columns filled with defaults if absent, and unrecognized columns dropped.
36
- """
37
- missing = set(vocs.all_names) - set(df.columns)
38
- if missing:
39
- raise ValueError(
40
- f"Initial data is missing required VOCS columns: {sorted(missing)}"
41
- )
42
-
43
- df = df.copy()
44
- if "xopt_candidate_idx" not in df.columns:
45
- df["xopt_candidate_idx"] = range(len(df))
46
- if "xopt_runtime" not in df.columns:
47
- df["xopt_runtime"] = 0.0
48
- if "xopt_error" not in df.columns:
49
- df["xopt_error"] = False
50
-
51
- keep = list(vocs.all_names) + _XOPT_INITIAL_COLS
52
- if "xopt_error_str" in df.columns:
53
- keep = keep + ["xopt_error_str"]
54
- extra = sorted(set(df.columns) - set(keep))
55
- if extra:
56
- logger.warning(f"Dropping unrecognized columns from initial data: {extra}")
57
- return df[[c for c in keep if c in df.columns]]
58
-
59
21
 
60
22
  @contextmanager
61
23
  def get_executor(name, max_workers=1):
@@ -88,59 +50,6 @@ def get_executor(name, max_workers=1):
88
50
  raise ValueError(f"Unknown executor: {name}")
89
51
 
90
52
 
91
- def override_to_dict(override: str) -> dict:
92
- """
93
- Convert strings of form "class_a.class_b.class_c.param=1" to
94
- {'class_a': {'class_b': {'class_c': {'param': 1}}}}.
95
-
96
- Uses yaml library for consistent type conversion of values following
97
- same convention as in config files.
98
-
99
- Parameters
100
- ----------
101
- override : str
102
- The override string
103
-
104
- Returns
105
- -------
106
- dict
107
- The nested dictionary containing the value.
108
- """
109
- path, value = override.split("=", 1)
110
- yaml_str = (
111
- "\n".join([" " * idx + x + ":" for idx, x in enumerate(path.split("."))])
112
- + " "
113
- + value.strip()
114
- )
115
- return yaml.safe_load(yaml_str)
116
-
117
-
118
- def merge_dicts(dict1: dict, dict2: dict) -> dict:
119
- """
120
- Nested merging of dicts. Will combine nested dicts keeping keys in both with
121
- the values in dict2 overriding those in dict1.
122
-
123
- Parameters
124
- ----------
125
- dict1 : dict
126
- Parameters to override
127
- dict2 : dict
128
- Parameters used to override those in dict1
129
-
130
- Returns
131
- -------
132
- dict
133
- Values from dict1 with overrides from dict2
134
- """
135
- result = dict1.copy()
136
- for key, value in dict2.items():
137
- if key in result and isinstance(result[key], dict) and isinstance(value, dict):
138
- result[key] = merge_dicts(result[key], value)
139
- else:
140
- result[key] = value
141
- return result
142
-
143
-
144
53
  def main():
145
54
  # Handle the CLI arguments
146
55
  parser = argparse.ArgumentParser()
@@ -187,18 +96,7 @@ def main():
187
96
  format="%(asctime)s - %(levelname)s - %(message)s",
188
97
  )
189
98
 
190
- # Add specified paths and CWD to sys.path
191
- import_paths = [os.getcwd()]
192
- import_paths.extend(
193
- [os.path.expanduser(os.path.expandvars(x)) for x in args.python_path]
194
- )
195
- if len(import_paths) > 1:
196
- logger.info("Python path additions:")
197
- for idx, import_path in enumerate(import_paths):
198
- if idx:
199
- logger.info(f" {import_path}")
200
- if import_path not in sys.path:
201
- sys.path.insert(0, import_path)
99
+ setup_import_paths([os.getcwd()] + args.python_path)
202
100
 
203
101
  # Create xopt
204
102
  with open(args.config) as f:
@@ -212,14 +110,8 @@ def main():
212
110
  if args.override:
213
111
  logger.info("Applying config file overrides:")
214
112
  for override in args.override:
215
- logger.info(f" {override}")
216
- # Sanity check
217
- if "=" not in override:
218
- raise ValueError(
219
- f'Invalid override format: "{override}". Expected key=value'
220
- )
221
-
222
113
  # Merge in the config override
114
+ logger.info(f" {override}")
223
115
  config = merge_dicts(config, override_to_dict(override))
224
116
 
225
117
  # Construct Xopt object