dfbench 0.1.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 (165) hide show
  1. dfbench-0.1.0/.gitignore +25 -0
  2. dfbench-0.1.0/LICENSE +21 -0
  3. dfbench-0.1.0/PKG-INFO +554 -0
  4. dfbench-0.1.0/README.md +491 -0
  5. dfbench-0.1.0/docs/Algorithm-Status.md +259 -0
  6. dfbench-0.1.0/docs/Algorithms.md +1503 -0
  7. dfbench-0.1.0/docs/Architecture-Overview.md +166 -0
  8. dfbench-0.1.0/docs/Benchmarking.md +296 -0
  9. dfbench-0.1.0/docs/FAQ.md +112 -0
  10. dfbench-0.1.0/docs/Home.md +96 -0
  11. dfbench-0.1.0/docs/Implementing-a-New-Algorithm.md +394 -0
  12. dfbench-0.1.0/docs/Installation.md +142 -0
  13. dfbench-0.1.0/docs/Metrics-Reference.md +189 -0
  14. dfbench-0.1.0/docs/Objective-API-Reference.md +430 -0
  15. dfbench-0.1.0/docs/Problems.md +267 -0
  16. dfbench-0.1.0/docs/Testing.md +233 -0
  17. dfbench-0.1.0/docs/Utilities-and-Helpers.md +137 -0
  18. dfbench-0.1.0/docs/_Sidebar.md +26 -0
  19. dfbench-0.1.0/docs/algorithm-status/main.typ +159 -0
  20. dfbench-0.1.0/docs/algorithm-status/template.typ +104 -0
  21. dfbench-0.1.0/pyproject.toml +155 -0
  22. dfbench-0.1.0/src/dfbench/__init__.py +48 -0
  23. dfbench-0.1.0/src/dfbench/algorithms/__init__.py +219 -0
  24. dfbench-0.1.0/src/dfbench/algorithms/derivative_free/__init__.py +23 -0
  25. dfbench-0.1.0/src/dfbench/algorithms/derivative_free/_dfo_common.py +150 -0
  26. dfbench-0.1.0/src/dfbench/algorithms/derivative_free/_scipy_common.py +124 -0
  27. dfbench-0.1.0/src/dfbench/algorithms/derivative_free/nelder_mead.py +97 -0
  28. dfbench-0.1.0/src/dfbench/algorithms/derivative_free/omads_mads.py +385 -0
  29. dfbench-0.1.0/src/dfbench/algorithms/derivative_free/pdfo/__init__.py +11 -0
  30. dfbench-0.1.0/src/dfbench/algorithms/derivative_free/pdfo/lincoa.py +139 -0
  31. dfbench-0.1.0/src/dfbench/algorithms/derivative_free/pdfo/newuoa.py +127 -0
  32. dfbench-0.1.0/src/dfbench/algorithms/derivative_free/pdfo/uobyqa.py +122 -0
  33. dfbench-0.1.0/src/dfbench/algorithms/derivative_free/powell.py +94 -0
  34. dfbench-0.1.0/src/dfbench/algorithms/derivative_free/pybobyqa.py +170 -0
  35. dfbench-0.1.0/src/dfbench/algorithms/evolutionary/__init__.py +35 -0
  36. dfbench-0.1.0/src/dfbench/algorithms/evolutionary/cmaes_sep_cma.py +192 -0
  37. dfbench-0.1.0/src/dfbench/algorithms/evolutionary/evosax_es.py +336 -0
  38. dfbench-0.1.0/src/dfbench/algorithms/evolutionary/evox_es.py +307 -0
  39. dfbench-0.1.0/src/dfbench/algorithms/evolutionary/evox_pso.py +198 -0
  40. dfbench-0.1.0/src/dfbench/algorithms/evolutionary/jax_es.py +361 -0
  41. dfbench-0.1.0/src/dfbench/algorithms/evolutionary/nevergrad/__init__.py +11 -0
  42. dfbench-0.1.0/src/dfbench/algorithms/evolutionary/nevergrad/_common.py +66 -0
  43. dfbench-0.1.0/src/dfbench/algorithms/evolutionary/nevergrad/ngopt.py +126 -0
  44. dfbench-0.1.0/src/dfbench/algorithms/evolutionary/nevergrad/oneplusone.py +130 -0
  45. dfbench-0.1.0/src/dfbench/algorithms/evolutionary/nevergrad/tbpsa.py +143 -0
  46. dfbench-0.1.0/src/dfbench/algorithms/evolutionary/pycma_cmaes.py +599 -0
  47. dfbench-0.1.0/src/dfbench/algorithms/evolutionary/random_search.py +92 -0
  48. dfbench-0.1.0/src/dfbench/algorithms/generative/vae_sampling.py +488 -0
  49. dfbench-0.1.0/src/dfbench/algorithms/global_search/__init__.py +12 -0
  50. dfbench-0.1.0/src/dfbench/algorithms/global_search/basin_hopping.py +142 -0
  51. dfbench-0.1.0/src/dfbench/algorithms/global_search/dual_annealing.py +133 -0
  52. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/__init__.py +151 -0
  53. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/adam_gd.py +87 -0
  54. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/custom_jax.py +867 -0
  55. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/lbfgs_gd.py +157 -0
  56. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/na_adam_gd.py +266 -0
  57. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/__init__.py +68 -0
  58. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/_common.py +198 -0
  59. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/adabelief.py +32 -0
  60. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/adadelta.py +31 -0
  61. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/adafactor.py +31 -0
  62. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/adagrad.py +30 -0
  63. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/adam.py +28 -0
  64. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/adamax.py +32 -0
  65. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/adamaxw.py +33 -0
  66. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/adamw.py +33 -0
  67. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/adan.py +35 -0
  68. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/amsgrad.py +32 -0
  69. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/lamb.py +33 -0
  70. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/lion.py +33 -0
  71. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/lookahead.py +129 -0
  72. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/nadam.py +32 -0
  73. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/nadamw.py +33 -0
  74. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/noisy_sgd.py +33 -0
  75. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/novograd.py +35 -0
  76. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/oadam.py +33 -0
  77. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/ogd.py +28 -0
  78. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/polyak_sgd.py +111 -0
  79. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/radam.py +33 -0
  80. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/rmsprop.py +33 -0
  81. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/rprop.py +35 -0
  82. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/sam.py +147 -0
  83. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/schedule_free_adam.py +45 -0
  84. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/sgd.py +73 -0
  85. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/sign.py +56 -0
  86. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/sm3.py +28 -0
  87. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/sophia.py +140 -0
  88. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax/yogi.py +34 -0
  89. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/optax_lbfgs.py +121 -0
  90. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/sa_gd.py +241 -0
  91. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/__init__.py +31 -0
  92. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/_common.py +398 -0
  93. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/bfgs.py +54 -0
  94. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/cobyla.py +65 -0
  95. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/cobyqa.py +65 -0
  96. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/dogleg.py +70 -0
  97. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/lbfgsb.py +62 -0
  98. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/newton_cg.py +58 -0
  99. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/nonlinear_cg.py +52 -0
  100. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/slsqp.py +52 -0
  101. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/sr1.py +82 -0
  102. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/tnc.py +62 -0
  103. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/trust_constr.py +75 -0
  104. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/trust_krylov.py +68 -0
  105. dfbench-0.1.0/src/dfbench/algorithms/gradient_based/scipy/trust_ncg.py +71 -0
  106. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/__init__.py +46 -0
  107. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/ax_baxus.py +237 -0
  108. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/ax_saasbo.py +162 -0
  109. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/botorch/__init__.py +24 -0
  110. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/botorch/_botorch_common.py +179 -0
  111. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/botorch/botorch_bo.py +295 -0
  112. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/botorch/botorch_gebo.py +225 -0
  113. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/botorch/botorch_linebo.py +217 -0
  114. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/botorch/botorch_qkg.py +160 -0
  115. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/botorch/botorch_qnei.py +167 -0
  116. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/botorch/botorch_rembo.py +181 -0
  117. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/botorch/botorch_turbo.py +489 -0
  118. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/hebo_bo.py +118 -0
  119. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/restir.py +371 -0
  120. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/smac_bo.py +131 -0
  121. dfbench-0.1.0/src/dfbench/algorithms/surrogate_based/turbo_lbfgs.py +276 -0
  122. dfbench-0.1.0/src/dfbench/benchmark/__init__.py +8 -0
  123. dfbench-0.1.0/src/dfbench/benchmark/benchmark.py +923 -0
  124. dfbench-0.1.0/src/dfbench/benchmark/metrics.py +369 -0
  125. dfbench-0.1.0/src/dfbench/core/_init_env.py +16 -0
  126. dfbench-0.1.0/src/dfbench/core/algorithm.py +205 -0
  127. dfbench-0.1.0/src/dfbench/core/config.py +51 -0
  128. dfbench-0.1.0/src/dfbench/core/display.py +526 -0
  129. dfbench-0.1.0/src/dfbench/core/objective.py +2110 -0
  130. dfbench-0.1.0/src/dfbench/core/problem.py +66 -0
  131. dfbench-0.1.0/src/dfbench/core/utils.py +44 -0
  132. dfbench-0.1.0/src/dfbench/problems/__init__.py +34 -0
  133. dfbench-0.1.0/src/dfbench/problems/base_problem.py +334 -0
  134. dfbench-0.1.0/src/dfbench/problems/uifo/__init__.py +15 -0
  135. dfbench-0.1.0/src/dfbench/problems/uifo/uifo_problem.py +589 -0
  136. dfbench-0.1.0/src/dfbench/problems/voyager/__init__.py +13 -0
  137. dfbench-0.1.0/src/dfbench/problems/voyager/constrained_voyager_problem.py +258 -0
  138. dfbench-0.1.0/src/dfbench/problems/voyager/voyager_problem.py +197 -0
  139. dfbench-0.1.0/src/dfbench/problems/voyager/voyager_tuning_problem.py +183 -0
  140. dfbench-0.1.0/tests/__init__.py +0 -0
  141. dfbench-0.1.0/tests/conftest.py +104 -0
  142. dfbench-0.1.0/tests/slow/__init__.py +0 -0
  143. dfbench-0.1.0/tests/slow/test_algorithms_integration.py +60 -0
  144. dfbench-0.1.0/tests/slow/test_benchmark_full.py +90 -0
  145. dfbench-0.1.0/tests/slow/test_problems_full.py +188 -0
  146. dfbench-0.1.0/tests/test_algorithm_protocol.py +95 -0
  147. dfbench-0.1.0/tests/test_algorithms_uniform.py +498 -0
  148. dfbench-0.1.0/tests/test_algorithms_unit.py +407 -0
  149. dfbench-0.1.0/tests/test_api_imports.py +62 -0
  150. dfbench-0.1.0/tests/test_benchmark_smoke.py +290 -0
  151. dfbench-0.1.0/tests/test_bo_batch.py +105 -0
  152. dfbench-0.1.0/tests/test_cma_family.py +302 -0
  153. dfbench-0.1.0/tests/test_config.py +77 -0
  154. dfbench-0.1.0/tests/test_custom_jax_batch.py +22 -0
  155. dfbench-0.1.0/tests/test_dfo_algorithms.py +244 -0
  156. dfbench-0.1.0/tests/test_display.py +159 -0
  157. dfbench-0.1.0/tests/test_init_env.py +27 -0
  158. dfbench-0.1.0/tests/test_metrics.py +312 -0
  159. dfbench-0.1.0/tests/test_objective_invariants.py +802 -0
  160. dfbench-0.1.0/tests/test_objective_randomness.py +150 -0
  161. dfbench-0.1.0/tests/test_objective_space_mode.py +94 -0
  162. dfbench-0.1.0/tests/test_problem_bounds_overrides.py +148 -0
  163. dfbench-0.1.0/tests/test_problem_protocol.py +32 -0
  164. dfbench-0.1.0/tests/test_scipy_wrapper.py +114 -0
  165. dfbench-0.1.0/tests/test_utils.py +105 -0
@@ -0,0 +1,25 @@
1
+ venv
2
+ .venv
3
+ .github
4
+
5
+ __pycache__
6
+ *.egg-info
7
+
8
+ dist
9
+ uv.lock
10
+ .vscode/settings.json
11
+ jobfiles_*
12
+ uninstall.txt
13
+ .python-version
14
+ examples/voyager
15
+ data/*
16
+ run_data
17
+ batch-script.sh
18
+ tmp*
19
+ *scratch*
20
+ notes.md
21
+ temp/
22
+ *.slurm
23
+ results/
24
+ notebooks/
25
+ .DS_Store
dfbench-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Artificial Scientist Lab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
dfbench-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,554 @@
1
+ Metadata-Version: 2.4
2
+ Name: dfbench
3
+ Version: 0.1.0
4
+ Summary: Differometor Benchmark - Optimization algorithms and problem definitions
5
+ Project-URL: Homepage, https://github.com/artificial-scientist-lab/Differometor-Benchmark
6
+ Project-URL: Repository, https://github.com/artificial-scientist-lab/Differometor-Benchmark
7
+ Project-URL: Documentation, https://github.com/artificial-scientist-lab/Differometor-Benchmark/tree/main/docs
8
+ Project-URL: Issues, https://github.com/artificial-scientist-lab/Differometor-Benchmark/issues
9
+ Author: Artificial Scientist Lab
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: benchmark,differentiable-simulation,gravitational-wave-detectors,jax,optimization
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Scientific/Engineering
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: ax-platform>=1.2.4
24
+ Requires-Dist: beartype>=0.22.8
25
+ Requires-Dist: botorch>=0.16.1
26
+ Requires-Dist: cma>=3.3.0
27
+ Requires-Dist: cmaes>=0.10.0
28
+ Requires-Dist: differometor==0.0.5
29
+ Requires-Dist: evosax>=0.1.6
30
+ Requires-Dist: evox>=1.3.0
31
+ Requires-Dist: gpytorch>=1.14
32
+ Requires-Dist: jax==0.9.0.1
33
+ Requires-Dist: jaxlib>=0.5.0
34
+ Requires-Dist: jaxtyping>=0.3.3
35
+ Requires-Dist: matplotlib>=3.8
36
+ Requires-Dist: nevergrad>=1.0.12
37
+ Requires-Dist: numpy>=2.0
38
+ Requires-Dist: omads>=2408.0
39
+ Requires-Dist: optax>=0.2.6
40
+ Requires-Dist: pdfo>=2.2.0
41
+ Requires-Dist: scipy>=1.15
42
+ Requires-Dist: torch>=2.9.1
43
+ Provides-Extra: analysis
44
+ Requires-Dist: equinox>=0.13.2; extra == 'analysis'
45
+ Requires-Dist: ipykernel>=7.1.0; extra == 'analysis'
46
+ Requires-Dist: ipywidgets>=8.1.8; extra == 'analysis'
47
+ Requires-Dist: jupytext>=1.19.1; extra == 'analysis'
48
+ Requires-Dist: papermill>=2.7.0; extra == 'analysis'
49
+ Requires-Dist: snakeviz>=2.2.2; extra == 'analysis'
50
+ Requires-Dist: tueplots>=0.2.1; extra == 'analysis'
51
+ Provides-Extra: cuda12
52
+ Requires-Dist: jax[cuda12]==0.9.0.1; extra == 'cuda12'
53
+ Provides-Extra: cuda13
54
+ Requires-Dist: jax[cuda13]==0.9.0.1; extra == 'cuda13'
55
+ Provides-Extra: pybobyqa
56
+ Requires-Dist: py-bobyqa>=1.5.0; extra == 'pybobyqa'
57
+ Provides-Extra: smac
58
+ Requires-Dist: smac>=2.4.0; extra == 'smac'
59
+ Provides-Extra: test
60
+ Requires-Dist: pytest-timeout>=2.2; extra == 'test'
61
+ Requires-Dist: pytest>=8.0; extra == 'test'
62
+ Description-Content-Type: text/markdown
63
+
64
+ # Differometor Benchmark
65
+
66
+ A benchmarking framework for optimization algorithms on gravitational-wave detector design problems, built on top of the [Differometor](https://github.com/artificial-scientist-lab/Differometor) simulator.
67
+
68
+ > **For detailed documentation, see the [Wiki](docs/Home.md).**
69
+
70
+ ---
71
+
72
+ ## Please Read
73
+ I want to keep the process of implementing an algorithm as intuitive as possible. Questions (and ideas) help me figure out where unclarities come up.
74
+
75
+ If you have *any* questions, don't hesitate to ask me via Slack (Laurin Sefa) or an Issue!
76
+
77
+
78
+
79
+ ---
80
+
81
+ ## TL;DR (I want to try my own algorithm)
82
+
83
+ This is how to create a raw script that tests your algorithm logic on a problem. Adding an algorithm as a class to the codebase is really not harder than this which would result in easier hyperparam testing (through short scripts you could then create) and the ability to add it to the benchmarking tool. But start from a script like that as you can copy that logic into the class later on.
84
+
85
+ All you need is the `Objective` wrapper. It handles evaluation tracking, budget enforcement, and history logging, you just write the optimization logic.
86
+
87
+ ```python
88
+ from dfbench import Objective
89
+ from dfbench.problems import VoyagerProblem
90
+
91
+ # Pick a problem
92
+ problem = VoyagerProblem()
93
+
94
+ # Wrap that problem inside the Objective wrapper for loss and time tracking
95
+ obj = Objective(problem, unbounded=True, max_time=120, max_evals=1000)
96
+
97
+ # JIT warmup (doesn't count against budget)
98
+ obj.warmup_value_and_grad()
99
+
100
+ # Start logging loss and time
101
+ obj.start_logging()
102
+
103
+ # Your optimization loop, that's it.
104
+ params = obj.random_params_unbounded()
105
+ while not obj.budget_exceeded:
106
+
107
+ # --- Your Optimization here ---
108
+ loss, grad = obj.value_and_grad(params) # for example
109
+ params = params - 0.1 * grad # or any update rule
110
+
111
+ # No need to log losses or params.
112
+
113
+ print(f"Best loss: {obj.best_loss}")
114
+ print(f"Best params: {obj.best_params_bounded}")
115
+ obj.plot_loss()
116
+ obj.save_run_to_file("my_run.npz")
117
+ ```
118
+
119
+ **A loss below 0 means your solution beats the real Voyager detector's sensitivity.** (On `VoyagerProblem` without physical constraints — you might be burning mirrors.)
120
+
121
+ ### Evaluation Methods
122
+
123
+ The problems are JAX-based and differentiable up to second order. Use whichever method fits your algorithm:
124
+
125
+ - `obj.value(params)`
126
+ - `obj.value_and_grad(params)`
127
+ - `obj.grad(params)`
128
+ - `obj.hessian(params)`
129
+ - `obj.value_grad_and_hessian(params)`
130
+ - `obj.vmap_value(batch)`
131
+ - `obj.vmap_value_and_grad(batch)`
132
+ - `obj.vmap_grad(batch)`
133
+ - `obj.vmap_hessian(batch)`
134
+ - `obj.vmap_value_grad_and_hessian(batch)`
135
+
136
+ ### PyTorch Users
137
+
138
+ ```python
139
+ from dfbench import t2j, j2t
140
+
141
+ params_jax = t2j(params_torch) # Torch → JAX
142
+ losses_torch = j2t(obj.vmap_value(params_jax)) # JAX → Torch
143
+ ```
144
+
145
+ This adds negligible overhead compared to the objective function itself.
146
+
147
+ ### Available Problems
148
+
149
+ | Problem | Speed | Notes |
150
+ |---------|-------|-------|
151
+ | `VoyagerProblem` | ~12 ms/eval (A100) | Lightweight optimization of the Voyager Setup, good for prototyping, not physics-constrained. Loss < 0 achievable. |
152
+ | `VoyagerTuningProblem` | ~12 ms/eval (A100) | Tuning-only Voyager optimization (6 parameters on key mirrors). Lightweight and good for quick experiments. |
153
+ | `ConstrainedVoyagerProblem` | ~25 ms/eval (A100) | The same setup but physically constrained. Loss < 0 very difficult. |
154
+ | `UIFOProblem` | ~500 ms/eval (A100) | Full 3x3 UIFO setup (constrained). Loss < 0 hard but doable. |
155
+
156
+ Both constrained problems accept a `power_penalty_fn(value, threshold)` callable to control how power-constraint violations are penalized. Built-in presets: `squashed_relu_penalty` (default), `relu_penalty`, `zero_penalty`. Feel free to try own ones.
157
+
158
+ All problems also support `bounds_overrides` (e.g. `{"tuning": (0, 45)}`) to narrow default property bounds, and expose `problem.print_bounds()` to inspect effective bounds.
159
+
160
+ See [Problems](docs/Problems.md) for details on loss computation, parameter meanings, and constraints.
161
+
162
+ ---
163
+
164
+ ## Installation
165
+
166
+ ### From PyPI
167
+
168
+ ```bash
169
+ pip install dfbench # CPU-only core package
170
+ pip install "dfbench[cuda13]" # CUDA 13 JAX support
171
+ pip install "dfbench[analysis]" # Notebook/profiling tools
172
+ pip install "dfbench[smac,pybobyqa]" # Optional external optimizers
173
+ ```
174
+
175
+ ### From Source With `uv` (recommended for development)
176
+
177
+ [uv](https://uv.dev/) handles virtual environments and dependency resolution automatically.
178
+
179
+ ```bash
180
+ uv sync # CPU-only
181
+ uv sync --group cuda13 # With GPU support (cuda12 also possible)
182
+ uv sync --group analysis # With analysis tools (profiling, notebooks)
183
+ uv sync --group cuda13 --group analysis # Everything
184
+ ```
185
+
186
+ ### From Source With `pip`
187
+
188
+ ```bash
189
+ pip install -e . # CPU-only editable install
190
+ pip install -e ".[cuda13,analysis]" # CUDA 13 plus analysis extras
191
+ pip install -e ".[smac,pybobyqa]" # Optional external optimizers
192
+ ```
193
+
194
+ See [Installation](docs/Installation.md) for GPU setup details and HPC notes.
195
+
196
+ ---
197
+
198
+ ## Architecture
199
+
200
+ ```
201
+ OptimizationAlgorithm.optimize()
202
+
203
+
204
+ ┌───────────┐ records losses, params, grads, timestamps
205
+ │ Objective │ ──► enforces time / eval budgets
206
+ └─────┬─────┘ bounded ↔ unbounded sigmoid transform
207
+
208
+
209
+ ContinuousProblem (VoyagerProblem, VoyagerTuningProblem, ConstrainedVoyagerProblem, UIFOProblem)
210
+
211
+
212
+ Differometor Simulator (JAX-based interferometer physics)
213
+ ```
214
+
215
+ **Design Idea:** Algorithms never create their own `Objective`, they receive a pre-configured one. This lets the benchmark harness (or user script) control budgets, seeds, and history settings uniformly. The algorithm only has to implement its optimization logic.
216
+
217
+ See [Architecture Overview](docs/Architecture-Overview.md) for full design details.
218
+
219
+ ---
220
+
221
+ ## Project Structure
222
+
223
+ ```
224
+ src/dfbench/
225
+ ├── core/
226
+ │ ├── problem.py # ContinuousProblem ABC
227
+ │ ├── algorithm.py # OptimizationAlgorithm ABC + AlgorithmType enum
228
+ │ ├── objective.py # Objective wrapper (central piece)
229
+ │ └── utils.py # torch↔jax conversion, inverse sigmoid
230
+ ├── algorithms/
231
+ │ ├── derivative_free/ # OMADS + Powell DFO + SciPy (NelderMead, Powell)
232
+ │ ├── global_search/ # SciPy BasinHopping, DualAnnealing
233
+ │ ├── evolutionary/ # RandomSearch, EvoxPSO, EvoxES, Nevergrad, CMA family
234
+ │ ├── gradient_based/
235
+ │ │ ├── optax/ # 30 Optax-based optimizers (OptaxAdam, OptaxLAMB, …)
236
+ │ │ ├── scipy/ # 13 SciPy-based optimizers (BFGS, TNC, SLSQP, …)
237
+ │ │ ├── custom_jax.py # Native-JAX custom/hybrid batch (SGLD, ASAM, GD→L-BFGS, …)
238
+ │ │ └── *.py # Custom-loop algorithms (AdamGD, LBFGSGD, SAGD, NAAdamGD, OptaxLBFGS)
239
+ │ ├── surrogate_based/
240
+ │ │ ├── botorch/ # BotorchBO, BotorchTuRBO, BotorchqNEI, BotorchqKG,
241
+ │ │ │ # REMBO, GEBO, LineBO (+ shared _botorch_common.py)
242
+ │ │ ├── ax_baxus.py / ax_saasbo.py # Ax/BoTorch high-dim BO
243
+ │ │ ├── hebo_bo.py / smac_bo.py # External BO packages
244
+ │ │ ├── turbo_lbfgs.py # TuRBO + L-BFGS refinement
245
+ │ │ └── restir.py # GPU-native kNN surrogate
246
+ │ └── generative/ # VAESampling
247
+ ├── problems/
248
+ │ ├── voyager/ # VoyagerProblem, VoyagerTuningProblem, ConstrainedVoyagerProblem
249
+ └── uifo/ # UIFOProblem
250
+ └── benchmark/
251
+ ├── benchmark.py # Benchmark orchestrator
252
+ └── metrics.py # Metric computation functions
253
+ ```
254
+
255
+ ---
256
+
257
+ ## Quick Start
258
+
259
+ ### Running a Single Algorithm
260
+
261
+ ```python
262
+ from dfbench import Objective
263
+ from dfbench.problems import VoyagerProblem
264
+ from dfbench.algorithms import AdamGD
265
+
266
+ problem = VoyagerProblem()
267
+
268
+ # The caller creates the Objective with budget and tracking settings
269
+ obj = Objective(problem, max_time=120, max_evals=50000, verbose=1)
270
+
271
+ # The algorithm receives the Objective and mutates it in place
272
+ optimizer = AdamGD()
273
+ optimizer.optimize(
274
+ problem_objective=obj,
275
+ learning_rate=0.1,
276
+ patience=1000,
277
+ random_seed=42,
278
+ )
279
+
280
+ # Access results
281
+ print(f"Best loss: {obj.best_loss}")
282
+ print(f"Best params: {obj.best_params_bounded}")
283
+ print(f"Evaluations: {obj.eval_count}")
284
+ obj.plot_loss() # Also saves JSONs of losses and best params
285
+ ```
286
+
287
+ ### Running a Benchmark
288
+
289
+ The `Benchmark` class handles `Objective` creation, seed management, and metric computation automatically.
290
+
291
+ ```python
292
+ from dfbench.problems import VoyagerProblem
293
+ from dfbench.benchmark import Benchmark, AlgorithmConfig
294
+ from dfbench.algorithms import AdamGD, RandomSearch, EvoxES
295
+
296
+ problem = VoyagerProblem()
297
+
298
+ configs = [
299
+ AlgorithmConfig(AdamGD(), {"learning_rate": 0.1}, name="Adam"),
300
+ AlgorithmConfig(RandomSearch(batch_size=100), name="Random"),
301
+ AlgorithmConfig(EvoxES(variant="CMAES"), {"pop_size": 100}, name="CMA-ES"),
302
+ ]
303
+
304
+ benchmark = Benchmark(
305
+ problem=problem,
306
+ success_loss=0.1,
307
+ configs=configs,
308
+ n_runs=20,
309
+ max_time=300,
310
+ )
311
+
312
+ results = benchmark.run(save_csv=True, save_run_data=True)
313
+ benchmark.print_summary(results)
314
+ ```
315
+
316
+ - `save_csv`: Writes a CSV with all metrics computed at evenly-spaced time points.
317
+ - `save_run_data`: Persists raw loss/params/time histories to NPZ files for later re-evaluation.
318
+
319
+ See [Benchmarking](docs/Benchmarking.md) for full configuration options and [Metrics Reference](docs/Metrics-Reference.md) for what gets computed.
320
+
321
+ ### Native-JAX Custom/Hybrid Batch
322
+
323
+ The gradient-based package now also includes native-JAX custom/hybrid classes:
324
+
325
+ - `SGLDJAX`, `ASAMJAX`, `AdamToLBFGSJAX`, `EntropySGDJAX`, `SGHMCJAX`
326
+ - `OGDJAX`, `OAdamJAX`, `PerturbedGDJAX`, `NoisyAdamJAX`
327
+ - `GDRestartsJAX`, `GaussianSmoothingGDJAX`
328
+
329
+ `ARCJAX` is currently exposed but intentionally raises `NotImplementedError`
330
+ to fail loudly until a stable, benchmark-fair ARC implementation is available.
331
+
332
+ All of the above default to unbounded optimization mode and rely on
333
+ `Objective` for logging/budget tracking. For a ready-to-run benchmark example,
334
+ see `scripts/voyager_native_jax_custom_batch.py`.
335
+
336
+ ---
337
+
338
+ ## How to Add an Algorithm (as a Class)
339
+
340
+ The interface is designed to make this as simple as possible. You write the optimization logic; `Objective` handles everything else (timing, logging, budget enforcement, file I/O).
341
+
342
+ > **Full step-by-step tutorial:** [Implementing a New Algorithm](docs/Implementing-a-New-Algorithm.md)
343
+
344
+ ### The Contract
345
+
346
+ 1. Subclass `OptimizationAlgorithm`
347
+ 2. Declare `algorithm_str` and `algorithm_type`
348
+ 3. Implement `optimize(problem_objective, ...) → None`
349
+ 4. Use `Objective` for all function evaluations
350
+ 5. The `Objective` is mutated in place, thereby no return is needed
351
+
352
+ Please create a branch called `algorithm/my-algo` for the pull request.
353
+
354
+ ### Minimal Template
355
+
356
+ ```python
357
+ import secrets
358
+ import numpy as np
359
+ import jax
360
+ import jax.numpy as jnp
361
+ from jaxtyping import Array, Float
362
+
363
+ from dfbench.core.algorithm import OptimizationAlgorithm, AlgorithmType
364
+ from dfbench import Objective
365
+
366
+
367
+ class MyAlgorithm(OptimizationAlgorithm):
368
+ """My optimization algorithm."""
369
+
370
+ algorithm_str = "my_algorithm"
371
+ algorithm_type = AlgorithmType.EVOLUTIONARY # or GRADIENT_BASED, SURROGATE_BASED, GENERATIVE
372
+
373
+ def __init__(self, batch_size: int = 50) -> None:
374
+ """Algorithm-level meta-parameters that don't change between runs."""
375
+ self.batch_size = batch_size
376
+
377
+ def optimize(
378
+ self,
379
+ problem_objective: Objective,
380
+ max_iterations: int | None = None,
381
+ init_params: Float[Array, "..."] | None = None,
382
+ random_seed: int | None = None,
383
+ patience: int = 1000,
384
+ **kwargs,
385
+ ) -> None:
386
+ # 1. Setup + seed all RNGs
387
+ obj = problem_objective
388
+ random_seed, key = self.prepare(obj, unbounded=False, random_seed=random_seed)
389
+ torch.manual_seed(random_seed) # for frameworks beyond np/jax
390
+
391
+ # 3. Initialize parameters
392
+ if init_params is None:
393
+ params = obj.random_params_bounded(n_samples=self.batch_size)
394
+ else:
395
+ params = init_params
396
+
397
+ # 4. JIT warmup (before start_logging, compilation time is free)
398
+ _ = obj.vmap_value(params)
399
+
400
+ # 5. Start the clock
401
+ obj.start_logging()
402
+
403
+ # 6. Optimization loop
404
+ iteration = 0
405
+ while not obj.budget_exceeded:
406
+ if max_iterations is not None and iteration >= max_iterations:
407
+ break
408
+
409
+ losses = obj.vmap_value(params) # automatically logged
410
+
411
+ # ... your update logic here ...
412
+ key, subkey = jax.random.split(key)
413
+
414
+ if obj.evals_since_improvement > patience:
415
+ break
416
+ iteration += 1
417
+
418
+ # 7. Done, Objective is mutated in place
419
+ ```
420
+
421
+ ### Key Points
422
+
423
+ - **`__init__` takes only algorithm meta-parameters** (batch size, network architecture, etc.), not the problem, not the budget.
424
+ - **`optimize()` receives a pre-configured `Objective`**, the algorithm does not create it.
425
+ - **`prepare()`** configures `unbounded`, `algorithm_str`, seeds `np.random` and JAX, and returns `(random_seed, key)`. For PyTorch-based algorithms, call `torch.manual_seed(random_seed)` afterwards.
426
+ - **Choose `unbounded`:** Set to `True` if your algorithm benefits from smooth unconstrained space (via sigmoid transform). Most evolutionary and surrogate methods use `False` (bounded space).
427
+ - **JIT warmup before `start_logging()`**, compilation time doesn't count against the budget. The no-arg `warmup_*()` helpers run the matching path twice on deterministic params.
428
+ - **`budget_exceeded`** checks both time and eval limits, please use it as your loop condition.
429
+
430
+ ### Evaluation Methods
431
+
432
+ | Method | When to use | What gets logged |
433
+ |--------|-------------|------------------|
434
+ | `obj.value(params)` | Loss only | loss, params |
435
+ | `obj.value_and_grad(params)` | Gradient-based optimization | loss, grad, params |
436
+ | `obj.grad(params)` | Gradient only (rare) | grad, params, **no loss** |
437
+ | `obj.hessian(params)` | Exact second-order information | hessian, params, **no loss** |
438
+ | `obj.value_grad_and_hessian(params)` | Newton-style / second-order methods | loss, grad, hessian, params |
439
+ | `obj.vmap_value(batch)` | Population evaluation | batch losses, batch params |
440
+ | `obj.vmap_value_and_grad(batch)` | Batched gradient methods | batch losses, grads, params |
441
+ | `obj.vmap_hessian(batch)` | Batched second-order methods | batch hessians, batch params |
442
+ | `obj.vmap_value_grad_and_hessian(batch)` | Batched second-order methods | batch losses, grads, hessians, params |
443
+ | `obj.log_evaluation(...)` | Custom JIT'd loop | whatever you pass, including optional Hessians |
444
+
445
+ ### Register It
446
+
447
+ Add your import to `src/dfbench/algorithms/<category>/__init__.py` and `src/dfbench/algorithms/__init__.py`.
448
+
449
+ ### The Objective Wrapper
450
+
451
+ `Objective` handles all tracking transparently. Here's what's available:
452
+
453
+ ```python
454
+ # Budget checking
455
+ while not obj.budget_exceeded: # main loop condition
456
+ if obj.evals_since_improvement > patience:
457
+ break # early stopping
458
+
459
+ # Random parameter generation
460
+ params = obj.random_params() # active bounded/unbounded space
461
+ params = obj.random_params_bounded() # shape: (n_params,)
462
+ batch = obj.random_params_bounded(n_samples=100) # shape: (100, n_params)
463
+ params = obj.random_params_unbounded() # for unbounded space
464
+
465
+ # Results
466
+ obj.best_loss # best (minimum) loss found
467
+ obj.best_params_bounded # best params in physical (bounded) space
468
+ obj.eval_count # total evaluations performed
469
+ obj.loss_history # full loss history
470
+ obj.time_steps # elapsed time at each evaluation
471
+ ```
472
+
473
+ See [Objective API Reference](docs/Objective-API-Reference.md) for the complete interface.
474
+
475
+ ---
476
+
477
+ ## Built-in Algorithms
478
+
479
+ | Algorithm | Type | Key Strength |
480
+ |-----------|------|-------------|
481
+ | `AdamGD` | Gradient | Fast convergence on smooth landscapes |
482
+ | `SAGD` | Gradient | Escapes local minima via stochastic ascent |
483
+ | `NAAdamGD` | Gradient | Noise-based exploration with annealing |
484
+ | `LBFGSGD` | Gradient | Second-order curvature information |
485
+ | `BFGS`, `LBFGSB`, `NonlinearCG`, `NewtonCG` | Gradient | Classical SciPy gradient and quasi-Newton methods |
486
+ | `TrustNCG`, `TrustKrylov`, `TrustConstr`, `Dogleg`, `SR1` | Gradient | Trust-region and constrained SciPy methods |
487
+ | `TNC`, `SLSQP`, `COBYQA`, `COBYLA` | Gradient | Bounded physical-space SciPy solvers |
488
+ | `RandomSearch` | Evolutionary | Unbiased baseline, no hyperparameters |
489
+ | `EvoxPSO` | Evolutionary | Swarm intelligence, many variants (CLPSO, CSO, ...) |
490
+ | `EvoxES` | Evolutionary | CMA-ES, OpenES, XNES, and more (EvoX backend) |
491
+ | `PyCMACMAES` | Evolutionary | Vanilla CMA-ES (pycma backend) |
492
+ | `PyCMAActiveCMAES` | Evolutionary | Active CMA-ES with negative weight updates (pycma) |
493
+ | `PyCMAIPOP` | Evolutionary | IPOP-CMA-ES: increasing-population restarts (pycma) |
494
+ | `PyCMABIPOP` | Evolutionary | BIPOP-CMA-ES: bi-population restart strategy (pycma) |
495
+ | `CMAESSepCMA` | Evolutionary | sep-CMA-ES with diagonal covariance (cmaes package) |
496
+ | `EvosaxMAES` | Evolutionary | Matrix Adaptation ES (evosax backend) |
497
+ | `EvosaxLMMAES` | Evolutionary | Limited-Memory MA-ES for high dimensions (evosax) |
498
+ | `JAXOnePlusOneES` | Evolutionary | (1+1)-ES with 1/5 rule, native JAX |
499
+ | `JAXMuLambdaES` | Evolutionary | (μ,λ)-ES with truncation selection, native JAX |
500
+ | `OmadsMADS`, `OmadsOrthoMADS` | Derivative-Free | MADS / OrthoMADS direct search (OMADS) |
501
+ | `PDFOUOBYQA`, `PDFONEWUOA`, `PDFOLINCOA`, `PyBOBYQA` | Derivative-Free | Powell-style trust-region DFO (PDFO + Py-BOBYQA) |
502
+ | `NelderMead`, `Powell` | Derivative-Free | SciPy classical simplex / direction-set search |
503
+ | `BasinHopping`, `DualAnnealing` | Global Search | SciPy stochastic global optimization |
504
+ | `NevergradOnePlusOne`, `NevergradTBPSA`, `NevergradNGOpt` | Evolutionary | Nevergrad rugged-landscape baselines |
505
+ | `BotorchBO` | Surrogate | Sample-efficient Bayesian Optimization |
506
+ | `BotorchTuRBO` | Surrogate | Trust-region BO for high dimensions |
507
+ | `BotorchqNEI`, `BotorchqKG` | Surrogate | Noise-aware / lookahead BoTorch acquisitions |
508
+ | `BAxUS`, `AxSAASBO` | Surrogate | High-dim Ax/BoTorch BO (subspace / sparse-axis) |
509
+ | `REMBO`, `GEBO`, `LineBO` | Surrogate | Embedding / gradient / line-search BO variants |
510
+ | `TuRBOLBFGS` | Surrogate | TuRBO basin-finding + L-BFGS refinement |
511
+ | `HEBO`, `SMAC` | Surrogate | External BO packages (HEBO, SMAC3) |
512
+ | `ReSTIR` | Surrogate | GPU-native kNN surrogate, scales to 100k+ candidates |
513
+ | `VAESampling` | Generative | Latent-space compression + BO |
514
+
515
+ See [Algorithms](docs/Algorithms.md) for hyperparameter details and usage examples.
516
+
517
+ ---
518
+
519
+ ## Examples
520
+
521
+ Execution scripts in `./scripts/`:
522
+ - `voyager_adam_gd.py`: single-algorithm run
523
+ - `voyager_benchmark.py`: full benchmark with multiple algorithms
524
+ - `voyager_cma_family.py`: all nine CMA-family algorithms on VoyagerProblem
525
+ - `voyager_scipy_benchmark.py`: SciPy gradient / trust / constrained batch
526
+
527
+ Reference implementations worth reading:
528
+ - `gradient_based/adam_gd.py`: gradient-based pattern (custom loop)
529
+ - `gradient_based/optax/adam.py`: Optax wrapper pattern (minimal subclass)
530
+ - `gradient_based/scipy/_common.py`: shared SciPy wrapper, caching, and budget handling
531
+ - `evolutionary/random_search.py`: simplest batched example
532
+ - `evolutionary/evox_es.py`: wrapping an external library (EvoX/PyTorch)
533
+ - `evolutionary/pycma_cmaes.py`: wrapping pycma (ask/tell, restart strategies)
534
+ - `evolutionary/jax_es.py`: native JAX ES without external library
535
+ - `surrogate_based/botorch/botorch_bo.py`: surrogate-based with BoTorch
536
+
537
+ ---
538
+
539
+ ## Wiki
540
+
541
+ For in-depth documentation beyond this README:
542
+
543
+ | Page | Content |
544
+ |------|---------|
545
+ | [Architecture Overview](docs/Architecture-Overview.md) | Design, module map, data-flow diagrams |
546
+ | [Objective API Reference](docs/Objective-API-Reference.md) | Complete `Objective` class reference |
547
+ | [Problems](docs/Problems.md) | Loss computation, parameter meanings, constraints |
548
+ | [Algorithms](docs/Algorithms.md) | All built-in algorithms with hyperparameters |
549
+ | [Implementing a New Algorithm](docs/Implementing-a-New-Algorithm.md) | Full step-by-step contributor tutorial |
550
+ | [Benchmarking](docs/Benchmarking.md) | Running benchmarks, saving/loading results |
551
+ | [Metrics Reference](docs/Metrics-Reference.md) | Every benchmark metric explained |
552
+ | [Utilities & Helpers](docs/Utilities-and-Helpers.md) | `t2j`/`j2t`, CLI config, inverse sigmoid |
553
+ | [Installation](docs/Installation.md) | Environment setup, GPU support, HPC notes |
554
+ | [FAQ](docs/FAQ.md) | Common pitfalls and troubleshooting |