dfbench 0.3.0__tar.gz → 0.3.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 (185) hide show
  1. {dfbench-0.3.0 → dfbench-0.3.2}/PKG-INFO +8 -7
  2. {dfbench-0.3.0 → dfbench-0.3.2}/README.md +7 -4
  3. {dfbench-0.3.0 → dfbench-0.3.2}/docs/Algorithms.md +1 -1
  4. {dfbench-0.3.0 → dfbench-0.3.2}/docs/Architecture-Overview.md +23 -17
  5. {dfbench-0.3.0 → dfbench-0.3.2}/docs/Implementing-a-New-Algorithm.md +24 -5
  6. {dfbench-0.3.0 → dfbench-0.3.2}/docs/Installation.md +4 -4
  7. {dfbench-0.3.0 → dfbench-0.3.2}/docs/Objective-API-Reference.md +60 -42
  8. {dfbench-0.3.0 → dfbench-0.3.2}/docs/Problems.md +2 -2
  9. {dfbench-0.3.0 → dfbench-0.3.2}/docs/Storage-and-Checkpointing.md +23 -6
  10. {dfbench-0.3.0 → dfbench-0.3.2}/docs/Testing.md +3 -2
  11. {dfbench-0.3.0 → dfbench-0.3.2}/pyproject.toml +1 -3
  12. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/__init__.py +1 -1
  13. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/hebo_bo.py +13 -5
  14. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/objective.py +378 -670
  15. dfbench-0.3.2/src/dfbench/core/storage/saveconfig.py +194 -0
  16. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/storage/state.py +12 -11
  17. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/problems/base_problem.py +16 -12
  18. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/problems/voyager/constrained_voyager_problem.py +1 -1
  19. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_bo_batch.py +5 -5
  20. dfbench-0.3.2/tests/test_hebo_packaging.py +53 -0
  21. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_objective_invariants.py +48 -3
  22. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_objective_penalty_fn.py +405 -35
  23. dfbench-0.3.0/src/dfbench/core/storage/saveconfig.py +0 -312
  24. {dfbench-0.3.0 → dfbench-0.3.2}/.gitignore +0 -0
  25. {dfbench-0.3.0 → dfbench-0.3.2}/LICENSE +0 -0
  26. {dfbench-0.3.0 → dfbench-0.3.2}/docs/Algorithm-Status.md +0 -0
  27. {dfbench-0.3.0 → dfbench-0.3.2}/docs/Benchmarking.md +0 -0
  28. {dfbench-0.3.0 → dfbench-0.3.2}/docs/FAQ.md +0 -0
  29. {dfbench-0.3.0 → dfbench-0.3.2}/docs/Home.md +0 -0
  30. {dfbench-0.3.0 → dfbench-0.3.2}/docs/Metrics-Reference.md +0 -0
  31. {dfbench-0.3.0 → dfbench-0.3.2}/docs/Utilities-and-Helpers.md +0 -0
  32. {dfbench-0.3.0 → dfbench-0.3.2}/docs/_Sidebar.md +0 -0
  33. {dfbench-0.3.0 → dfbench-0.3.2}/docs/algorithm-status/main.typ +0 -0
  34. {dfbench-0.3.0 → dfbench-0.3.2}/docs/algorithm-status/template.typ +0 -0
  35. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/__init__.py +0 -0
  36. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/__init__.py +0 -0
  37. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/_dfo_common.py +0 -0
  38. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/_scipy_common.py +0 -0
  39. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/nelder_mead.py +0 -0
  40. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/omads_mads.py +0 -0
  41. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/pdfo/__init__.py +0 -0
  42. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/pdfo/lincoa.py +0 -0
  43. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/pdfo/newuoa.py +0 -0
  44. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/pdfo/uobyqa.py +0 -0
  45. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/powell.py +0 -0
  46. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/pybobyqa.py +0 -0
  47. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/__init__.py +0 -0
  48. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/cmaes_sep_cma.py +0 -0
  49. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/evosax_es.py +0 -0
  50. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/evox_es.py +0 -0
  51. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/evox_pso.py +0 -0
  52. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/jax_es.py +0 -0
  53. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/nevergrad/__init__.py +0 -0
  54. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/nevergrad/_common.py +0 -0
  55. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/nevergrad/ngopt.py +0 -0
  56. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/nevergrad/oneplusone.py +0 -0
  57. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/nevergrad/tbpsa.py +0 -0
  58. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/pycma_cmaes.py +0 -0
  59. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/generative/vae_sampling.py +0 -0
  60. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/global_search/__init__.py +0 -0
  61. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/global_search/basin_hopping.py +0 -0
  62. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/global_search/dual_annealing.py +0 -0
  63. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/global_search/random_search.py +0 -0
  64. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/__init__.py +0 -0
  65. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/adam_gd.py +0 -0
  66. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/custom_jax.py +0 -0
  67. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/lbfgs_gd.py +0 -0
  68. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/na_adam_gd.py +0 -0
  69. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/__init__.py +0 -0
  70. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/_common.py +0 -0
  71. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adabelief.py +0 -0
  72. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adadelta.py +0 -0
  73. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adafactor.py +0 -0
  74. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adagrad.py +0 -0
  75. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adam.py +0 -0
  76. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adamax.py +0 -0
  77. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adamaxw.py +0 -0
  78. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adamw.py +0 -0
  79. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adan.py +0 -0
  80. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/amsgrad.py +0 -0
  81. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/lamb.py +0 -0
  82. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/lion.py +0 -0
  83. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/lookahead.py +0 -0
  84. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/nadam.py +0 -0
  85. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/nadamw.py +0 -0
  86. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/noisy_sgd.py +0 -0
  87. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/novograd.py +0 -0
  88. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/oadam.py +0 -0
  89. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/ogd.py +0 -0
  90. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/polyak_sgd.py +0 -0
  91. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/radam.py +0 -0
  92. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/rmsprop.py +0 -0
  93. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/rprop.py +0 -0
  94. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/sam.py +0 -0
  95. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/schedule_free_adam.py +0 -0
  96. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/sgd.py +0 -0
  97. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/sign.py +0 -0
  98. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/sm3.py +0 -0
  99. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/sophia.py +0 -0
  100. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/yogi.py +0 -0
  101. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax_lbfgs.py +0 -0
  102. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/sa_gd.py +0 -0
  103. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/__init__.py +0 -0
  104. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/_common.py +0 -0
  105. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/bfgs.py +0 -0
  106. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/cobyla.py +0 -0
  107. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/cobyqa.py +0 -0
  108. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/dogleg.py +0 -0
  109. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/lbfgsb.py +0 -0
  110. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/newton_cg.py +0 -0
  111. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/nonlinear_cg.py +0 -0
  112. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/slsqp.py +0 -0
  113. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/sr1.py +0 -0
  114. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/tnc.py +0 -0
  115. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/trust_constr.py +0 -0
  116. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/trust_krylov.py +0 -0
  117. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/trust_ncg.py +0 -0
  118. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/__init__.py +0 -0
  119. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/ax_baxus.py +0 -0
  120. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/ax_saasbo.py +0 -0
  121. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/__init__.py +0 -0
  122. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/_botorch_common.py +0 -0
  123. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_bo.py +0 -0
  124. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_gebo.py +0 -0
  125. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_linebo.py +0 -0
  126. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_qkg.py +0 -0
  127. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_qnei.py +0 -0
  128. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_rembo.py +0 -0
  129. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_turbo.py +0 -0
  130. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/restir.py +0 -0
  131. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/smac_bo.py +0 -0
  132. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/turbo_lbfgs.py +0 -0
  133. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/utils/__init__.py +0 -0
  134. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/utils/gp.py +0 -0
  135. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/utils/initial_design.py +0 -0
  136. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/utils/misc.py +0 -0
  137. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/algorithms/utils/weighted_acq.py +0 -0
  138. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/benchmark/__init__.py +0 -0
  139. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/benchmark/benchmark.py +0 -0
  140. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/benchmark/metrics.py +0 -0
  141. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/_init_env.py +0 -0
  142. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/algorithm.py +0 -0
  143. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/config.py +0 -0
  144. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/display.py +0 -0
  145. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/problem.py +0 -0
  146. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/storage/__init__.py +0 -0
  147. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/storage/backends.py +0 -0
  148. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/storage/exporter.py +0 -0
  149. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/storage/manager.py +0 -0
  150. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/storage/resolver.py +0 -0
  151. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/storage/serializers.py +0 -0
  152. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/core/utils.py +0 -0
  153. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/problems/__init__.py +0 -0
  154. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/problems/uifo/__init__.py +0 -0
  155. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/problems/uifo/uifo_problem.py +0 -0
  156. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/problems/voyager/__init__.py +0 -0
  157. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/problems/voyager/voyager_problem.py +0 -0
  158. {dfbench-0.3.0 → dfbench-0.3.2}/src/dfbench/problems/voyager/voyager_tuning_problem.py +0 -0
  159. {dfbench-0.3.0 → dfbench-0.3.2}/tests/__init__.py +0 -0
  160. {dfbench-0.3.0 → dfbench-0.3.2}/tests/conftest.py +0 -0
  161. {dfbench-0.3.0 → dfbench-0.3.2}/tests/slow/__init__.py +0 -0
  162. {dfbench-0.3.0 → dfbench-0.3.2}/tests/slow/test_algorithms_integration.py +0 -0
  163. {dfbench-0.3.0 → dfbench-0.3.2}/tests/slow/test_benchmark_full.py +0 -0
  164. {dfbench-0.3.0 → dfbench-0.3.2}/tests/slow/test_problem_bounds_gradients.py +0 -0
  165. {dfbench-0.3.0 → dfbench-0.3.2}/tests/slow/test_problems_full.py +0 -0
  166. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_algorithm_protocol.py +0 -0
  167. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_algorithms_uniform.py +0 -0
  168. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_algorithms_unit.py +0 -0
  169. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_api_imports.py +0 -0
  170. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_benchmark_smoke.py +0 -0
  171. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_cma_family.py +0 -0
  172. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_config.py +0 -0
  173. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_custom_jax_batch.py +0 -0
  174. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_dfo_algorithms.py +0 -0
  175. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_display.py +0 -0
  176. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_init_env.py +0 -0
  177. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_metrics.py +0 -0
  178. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_objective_randomness.py +0 -0
  179. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_objective_space_mode.py +0 -0
  180. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_problem_bounds_overrides.py +0 -0
  181. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_problem_protocol.py +0 -0
  182. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_problem_spec.py +0 -0
  183. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_scipy_wrapper.py +0 -0
  184. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_storage.py +0 -0
  185. {dfbench-0.3.0 → dfbench-0.3.2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dfbench
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: dfbench: A Black-Box Optimization Framework for JAX-Differentiable Gravitational Wave Detector Discovery
5
5
  Project-URL: Homepage, https://github.com/artificial-scientist-lab/Differometor-Benchmark
6
6
  Project-URL: Repository, https://github.com/artificial-scientist-lab/Differometor-Benchmark
@@ -34,7 +34,6 @@ Requires-Dist: cmaes>=0.10.0; extra == 'all'
34
34
  Requires-Dist: evosax>=0.1.6; extra == 'all'
35
35
  Requires-Dist: evox>=1.3.0; extra == 'all'
36
36
  Requires-Dist: gpytorch>=1.14; extra == 'all'
37
- Requires-Dist: hebo>=0.3.2; extra == 'all'
38
37
  Requires-Dist: nevergrad>=1.0.12; extra == 'all'
39
38
  Requires-Dist: omads>=2408.0; extra == 'all'
40
39
  Requires-Dist: optax>=0.2.6; extra == 'all'
@@ -55,7 +54,6 @@ Provides-Extra: bo
55
54
  Requires-Dist: ax-platform>=1.2.4; extra == 'bo'
56
55
  Requires-Dist: botorch>=0.16.1; extra == 'bo'
57
56
  Requires-Dist: gpytorch>=1.14; extra == 'bo'
58
- Requires-Dist: hebo>=0.3.2; extra == 'bo'
59
57
  Requires-Dist: torch>=2.9.1; extra == 'bo'
60
58
  Provides-Extra: cuda12
61
59
  Requires-Dist: jax[cuda12]==0.9.0.1; extra == 'cuda12'
@@ -179,7 +177,7 @@ This adds negligible overhead compared to the objective function itself.
179
177
 
180
178
  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. The penalty function can also be swapped after construction via `obj.set_penalty_fn(fn)` (before `obj.start_logging()`), which re-traces the objective so the change takes effect. The unconstrained Voyager problems reject this call because they have no power-constraint path.
181
179
 
182
- Constrained problems also expose aux diagnostics. `obj.value_aux(params)` and `obj.vmap_value_aux(batch)` return `(loss, aux)` where `aux` carries the loss decomposition, a physical `is_feasible` flag, per-constraint violations, and the raw per-group power arrays. Enable `save` tokens like `is_feasible`, `power_values`, or the `aux` alias and the standard `obj.value` / `obj.value_and_grad` loop records the enabled aux fields in the same forward pass, with no code change. See [Problems](https://github.com/artificial-scientist-lab/Differometor-Benchmark/wiki/Problems) for the aux schema and [Objective API Reference](https://github.com/artificial-scientist-lab/Differometor-Benchmark/wiki/Objective-API-Reference) for the full method set.
180
+ Constrained problems also expose aux diagnostics. `obj.value_aux(params)` and `obj.vmap_value_aux(batch)` return `(loss, aux)` where `aux` carries the loss decomposition, a physical `is_feasible` flag, per-constraint violations, and the raw per-group power arrays. Enable `save` tokens like `is_feasible`, `power_values`, or the `aux` alias and standard value-bearing calls such as `obj.value` / `obj.value_and_grad` record the enabled aux fields in the same forward pass, with no code change. Derivative-only `grad` / `hessian` calls do not produce aux and append aligned `None` entries when aux histories are enabled. See [Problems](https://github.com/artificial-scientist-lab/Differometor-Benchmark/wiki/Problems) for the aux schema and [Objective API Reference](https://github.com/artificial-scientist-lab/Differometor-Benchmark/wiki/Objective-API-Reference) for the full method set.
183
181
 
184
182
  All problems also support `bounds_overrides` (e.g. `{"tuning": (0, 45)}`) to narrow default property bounds and `signal_floor` to floor detector signal magnitudes before sensitivity normalization. `signal_floor` defaults to `1e-20`. Use `problem.print_bounds()` to inspect effective bounds.
185
183
 
@@ -197,11 +195,13 @@ pip install "dfbench[optax,scipy]" # Common local optimizers
197
195
  pip install "dfbench[evolution]" # CMA, EvoX, Nevergrad, Evosax
198
196
  pip install "dfbench[bo]" # BoTorch/Ax surrogate optimizers
199
197
  pip install "dfbench[dfo,smac]" # Derivative-free and SMAC optimizers
200
- pip install "dfbench[all]" # All optimizer backends
198
+ pip install "dfbench[all]" # All packaged optimizer backends
201
199
  pip install "dfbench[cuda13]" # CUDA 13 JAX support
202
200
  pip install "dfbench[analysis]" # Notebook/profiling tools
203
201
  ```
204
202
 
203
+ The HEBO adapter is available in the API, but no dfbench extra installs HEBO because its dependency stack conflicts with dfbench's NumPy 2.x stack. Use it only with a separately managed compatible HEBO installation.
204
+
205
205
  ### From Source With `uv` (recommended for development)
206
206
 
207
207
  [uv](https://uv.dev/) handles virtual environments and dependency resolution automatically.
@@ -217,7 +217,7 @@ uv sync --group cuda13 --group analysis # Everything
217
217
 
218
218
  ```bash
219
219
  pip install -e . # CPU-only editable install
220
- pip install -e ".[all,cuda13,analysis]" # All backends, CUDA 13, and analysis extras
220
+ pip install -e ".[all,cuda13,analysis]" # Packaged backends, CUDA 13, and analysis extras
221
221
  ```
222
222
 
223
223
  See [Installation](https://github.com/artificial-scientist-lab/Differometor-Benchmark/wiki/Installation) for GPU setup details and HPC notes.
@@ -473,7 +473,8 @@ class MyAlgorithm(OptimizationAlgorithm):
473
473
  | `obj.vmap_value_and_grad(batch)` | Batched gradient methods | batch losses, grads, params |
474
474
  | `obj.vmap_hessian(batch)` | Batched second-order methods | batch hessians, batch params |
475
475
  | `obj.vmap_value_grad_and_hessian(batch)` | Batched second-order methods | batch losses, grads, hessians, params |
476
- | `obj.log_evaluation(...)` | Custom JIT'd loop | whatever you pass, including optional Hessians |
476
+ | `obj.value_function_aux(...)` | Raw aux-aware callable for custom JIT loops | nothing; use `log_evaluation` afterwards |
477
+ | `obj.log_evaluation(...)` | Custom JIT'd loop | supplied values; aux only for matching save tokens |
477
478
 
478
479
  ### Register It
479
480
 
@@ -87,7 +87,7 @@ This adds negligible overhead compared to the objective function itself.
87
87
 
88
88
  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. The penalty function can also be swapped after construction via `obj.set_penalty_fn(fn)` (before `obj.start_logging()`), which re-traces the objective so the change takes effect. The unconstrained Voyager problems reject this call because they have no power-constraint path.
89
89
 
90
- Constrained problems also expose aux diagnostics. `obj.value_aux(params)` and `obj.vmap_value_aux(batch)` return `(loss, aux)` where `aux` carries the loss decomposition, a physical `is_feasible` flag, per-constraint violations, and the raw per-group power arrays. Enable `save` tokens like `is_feasible`, `power_values`, or the `aux` alias and the standard `obj.value` / `obj.value_and_grad` loop records the enabled aux fields in the same forward pass, with no code change. See [Problems](https://github.com/artificial-scientist-lab/Differometor-Benchmark/wiki/Problems) for the aux schema and [Objective API Reference](https://github.com/artificial-scientist-lab/Differometor-Benchmark/wiki/Objective-API-Reference) for the full method set.
90
+ Constrained problems also expose aux diagnostics. `obj.value_aux(params)` and `obj.vmap_value_aux(batch)` return `(loss, aux)` where `aux` carries the loss decomposition, a physical `is_feasible` flag, per-constraint violations, and the raw per-group power arrays. Enable `save` tokens like `is_feasible`, `power_values`, or the `aux` alias and standard value-bearing calls such as `obj.value` / `obj.value_and_grad` record the enabled aux fields in the same forward pass, with no code change. Derivative-only `grad` / `hessian` calls do not produce aux and append aligned `None` entries when aux histories are enabled. See [Problems](https://github.com/artificial-scientist-lab/Differometor-Benchmark/wiki/Problems) for the aux schema and [Objective API Reference](https://github.com/artificial-scientist-lab/Differometor-Benchmark/wiki/Objective-API-Reference) for the full method set.
91
91
 
92
92
  All problems also support `bounds_overrides` (e.g. `{"tuning": (0, 45)}`) to narrow default property bounds and `signal_floor` to floor detector signal magnitudes before sensitivity normalization. `signal_floor` defaults to `1e-20`. Use `problem.print_bounds()` to inspect effective bounds.
93
93
 
@@ -105,11 +105,13 @@ pip install "dfbench[optax,scipy]" # Common local optimizers
105
105
  pip install "dfbench[evolution]" # CMA, EvoX, Nevergrad, Evosax
106
106
  pip install "dfbench[bo]" # BoTorch/Ax surrogate optimizers
107
107
  pip install "dfbench[dfo,smac]" # Derivative-free and SMAC optimizers
108
- pip install "dfbench[all]" # All optimizer backends
108
+ pip install "dfbench[all]" # All packaged optimizer backends
109
109
  pip install "dfbench[cuda13]" # CUDA 13 JAX support
110
110
  pip install "dfbench[analysis]" # Notebook/profiling tools
111
111
  ```
112
112
 
113
+ The HEBO adapter is available in the API, but no dfbench extra installs HEBO because its dependency stack conflicts with dfbench's NumPy 2.x stack. Use it only with a separately managed compatible HEBO installation.
114
+
113
115
  ### From Source With `uv` (recommended for development)
114
116
 
115
117
  [uv](https://uv.dev/) handles virtual environments and dependency resolution automatically.
@@ -125,7 +127,7 @@ uv sync --group cuda13 --group analysis # Everything
125
127
 
126
128
  ```bash
127
129
  pip install -e . # CPU-only editable install
128
- pip install -e ".[all,cuda13,analysis]" # All backends, CUDA 13, and analysis extras
130
+ pip install -e ".[all,cuda13,analysis]" # Packaged backends, CUDA 13, and analysis extras
129
131
  ```
130
132
 
131
133
  See [Installation](https://github.com/artificial-scientist-lab/Differometor-Benchmark/wiki/Installation) for GPU setup details and HPC notes.
@@ -381,7 +383,8 @@ class MyAlgorithm(OptimizationAlgorithm):
381
383
  | `obj.vmap_value_and_grad(batch)` | Batched gradient methods | batch losses, grads, params |
382
384
  | `obj.vmap_hessian(batch)` | Batched second-order methods | batch hessians, batch params |
383
385
  | `obj.vmap_value_grad_and_hessian(batch)` | Batched second-order methods | batch losses, grads, hessians, params |
384
- | `obj.log_evaluation(...)` | Custom JIT'd loop | whatever you pass, including optional Hessians |
386
+ | `obj.value_function_aux(...)` | Raw aux-aware callable for custom JIT loops | nothing; use `log_evaluation` afterwards |
387
+ | `obj.log_evaluation(...)` | Custom JIT'd loop | supplied values; aux only for matching save tokens |
385
388
 
386
389
  ### Register It
387
390
 
@@ -942,7 +942,7 @@ optimizer.optimize(
942
942
 
943
943
  ### HEBO (Heteroscedastic Evolutionary BO)
944
944
 
945
- Winner of the NeurIPS 2020 BBO challenge. Uses a heteroscedastic GP, input warping, and multi-objective acquisition. Requires the `dfbench[bo]` extra.
945
+ Winner of the NeurIPS 2020 BBO challenge. Uses a heteroscedastic GP, input warping, and multi-objective acquisition. HEBO is not installed by a dfbench extra because its dependency stack conflicts with dfbench's NumPy 2.x stack; using this adapter requires a separately managed compatible installation.
946
946
 
947
947
  Reference: Cowen-Rivers et al., *An Empirical Study of Assumptions in Bayesian Optimisation*, 2020.
948
948
 
@@ -67,7 +67,7 @@ A problem defines *what* is being optimised. Every problem subclasses `Continuou
67
67
 
68
68
  - Maps unbounded coordinates into problem bounds when needed, then evaluates the bounded problem objective
69
69
  - Prepares `jax.grad`, `jax.hessian`, `jax.value_and_grad`, and `jax.vmap` variants
70
- - Records every evaluation with aligned loss / gradient / Hessian / params / timestamp histories
70
+ - Records every admitted call with aligned loss / gradient / Hessian / params / timestamp histories
71
71
  - Enforces wall-clock time and evaluation-count budgets
72
72
  - Provides deterministic random sampling via a splittable JAX PRNG
73
73
  - Delegates all file I/O to the modular `dfbench.core.storage` layer (see [Storage & Checkpointing](Storage-and-Checkpointing))
@@ -114,39 +114,45 @@ See [Storage & Checkpointing](Storage-and-Checkpointing) for the full reference.
114
114
  │ │ │ │
115
115
  └────────────┴───────┬───────┴──────────────────────┘
116
116
 
117
- Objective._func / _value_and_grad_func / _hessian_func / _vmap_func
117
+ Objective._value_func / derivative transforms / vmapped transforms
118
118
 
119
119
 
120
120
  ┌──────────────────────────────┐
121
121
  │ optional Objective mapping │
122
- problem.objective_function
122
+ │ objective_function or
123
+ │ objective_function_aux │
123
124
  └──────────────┬───────────────┘
124
125
 
125
126
 
126
127
  Differometor.simulate()
127
128
 
128
129
 
129
- scalar loss value
130
+ value / derivatives + optional aux
130
131
 
132
+
133
+ _log(params, loss, grad, hessian, aux)
134
+
135
+
136
+ _log_evals(..., aux)
131
137
 
138
+ ┌───────────┴────────────┐
139
+ │ admitted │ rejected
140
+ ▼ ▼
141
+ time + standard histories no history mutation
142
+ + best/stagnation + selected aux histories
143
+ │ │
144
+ └───────────┬────────────┘
132
145
 
133
- _log(params, loss, grad, hessian)
146
+ _log_to_file()
134
147
 
135
- ┌───────────┼───────────────────┐
136
- │ │ │
137
- time_steps _log_evals() _log_to_file()
138
- (append) │ │
139
- ▼ ▼ ▼
140
- _time_steps _loss_history periodic
141
- _params_history checkpoint
142
- _grad_history via CheckpointManager
143
- _hessian_history -> StorageBackend
144
- _best_loss / _best_params
148
+
149
+ periodic checkpoint via
150
+ CheckpointManager -> StorageBackend
145
151
  ```
146
152
 
147
- Every call to `obj.value()`, `obj.value_and_grad()`, `obj.hessian()`, `obj.value_grad_and_hessian()`, or any `vmap_*` variant follows this exact pipeline. The internal `_log()` coordinator handles time-step recording, delegates to `_log_evals()` for history tracking, and triggers `_log_to_file()` for periodic checkpoints. `_log_to_file()` calls `CheckpointManager.tick()`, which checks the cadence (`save_every`), lazily builds a `RunState` only when a checkpoint is due, saves it through the internal `StorageBackend`, and returns the save duration so the Objective can exclude it from the elapsed-time clock. The algorithm receives the computed result; the logging is a side-effect invisible to the caller.
153
+ Every call to `obj.value()`, `obj.value_and_grad()`, `obj.hessian()`, `obj.value_grad_and_hessian()`, or any `vmap_*` variant follows this pipeline. Value-bearing methods carry one primal aux pytree when aux storage is selected; derivative-only methods carry no aux and contribute `None` to selected aux histories. The internal `_log()` coordinator takes one time snapshot, delegates atomic admission and history tracking to `_log_evals()`, appends the timestamp only for an admitted call, and triggers `_log_to_file()` for periodic checkpoints. `_log_to_file()` calls `CheckpointManager.tick()`, which checks the cadence (`save_every`), lazily builds a `RunState` only when a checkpoint is due, saves it through the internal `StorageBackend`, and returns the save duration so the Objective can exclude it from the elapsed-time clock. The algorithm receives the computed result; logging is a side effect invisible to the caller.
148
154
 
149
- For algorithms with custom JIT-compiled evaluation loops (e.g. L-BFGS with line-search), `obj.value_function(...)` provides the same Objective-owned bounded/unbounded mapping without Python-side logging, and `obj.log_evaluation(params, loss, grad, hessian=None)` records the completed evaluation through the same logging pipeline. Do not call the private methods directly.
155
+ For algorithms with custom JIT-compiled evaluation loops (e.g. L-BFGS with line-search), `obj.value_function(...)` and `obj.value_function_aux(...)` provide the same Objective-owned bounded/unbounded mapping without Python-side logging. The latter returns an aux-aware callable whose invocation yields `(loss, aux)`, or `None` when unsupported. After logging has started, `obj.log_evaluation(params, loss, grad=None, hessian=None, aux=None)` records the completed evaluation through the same logging pipeline. Manual logging never manufactures aux; omitting it appends `None` to each enabled aux history. Do not call the private methods directly.
150
156
 
151
157
  ---
152
158
 
@@ -271,19 +271,38 @@ while not obj.budget_exceeded:
271
271
  | `obj.vmap_hessian(batch)` | Batched second-order optimization | batch hessians, batch params |
272
272
  | `obj.vmap_value_grad_and_hessian(batch)` | Batched second-order optimization | batch losses, grads, hessians, params |
273
273
  | `obj.value_function(...)` | Raw JAX callable for custom JIT loops | nothing; use `log_evaluation` afterwards |
274
- | `obj.log_evaluation(...)` | Custom JIT'd loop | whatever you pass, including optional Hessians |
274
+ | `obj.value_function_aux(...)` | Raw `(loss, aux)` JAX callable for custom JIT loops | nothing; use `log_evaluation` afterwards |
275
+ | `obj.log_evaluation(...)` | Custom JIT'd loop | supplied values; aux only for matching save tokens |
275
276
 
276
- **Important:** `obj.grad()` and `obj.hessian()` do **not** log a loss value. If you need the loss too, use `obj.value_and_grad()` or `obj.value_grad_and_hessian()`.
277
+ **Important:** `obj.grad()` and `obj.hessian()` do **not** log a loss value or produce aux diagnostics. If aux histories are enabled, derivative-only methods append aligned `None` entries. With an aux save token, `obj.value_and_grad()` and `obj.value_grad_and_hessian()` auto-log primal aux while retaining their standard return signatures. Use `obj.value_and_grad_aux()` when the algorithm itself must receive aux.
277
278
 
278
279
  ### Custom JIT-compiled loops with `log_evaluation()`
279
280
 
280
281
  Some optimizers (e.g. Optax's L-BFGS) need to call `value_and_grad` *inside* a JIT-compiled function, for instance because the optimizer's line-search requires the raw value function. In that case you can't use `obj.value_and_grad()` (which has Python-side logging). Instead:
281
282
 
282
- 1. Get an unlogged raw value function from `obj.value_function(...)`
283
+ 1. Get an unlogged scalar callable from `obj.value_function(...)`, or an aux-aware callable from `obj.value_function_aux(...)` whose invocation yields `(loss, aux)`
283
284
  2. Build your own JIT-compiled step
284
- 3. After each step, call `obj.log_evaluation(params, loss, grad, hessian=None)` to record the results
285
+ 3. After each step, call `obj.log_evaluation(params, loss, grad, hessian=None, aux=None)` to record the results
285
286
 
286
- `obj.value_function(unbounded=None)` follows the Objective's active space mode by default. Pass `unbounded=True` when the JIT loop works in unbounded coordinates and needs Objective's mapping into problem bounds; pass `unbounded=False` for bounded coordinates. The callable deliberately does not log anything.
287
+ `obj.value_function(unbounded=None)` follows the Objective's active space mode by default. Pass `unbounded=True` when the JIT loop works in unbounded coordinates and needs Objective's mapping into problem bounds; pass `unbounded=False` for bounded coordinates. `obj.value_function_aux(...)` follows the same mapping rules and returns an unlogged callable whose invocation yields `(loss, aux)`, or `None` when the problem has no aux objective. Neither callable logs anything.
288
+
289
+ `log_evaluation()` never computes missing aux diagnostics. If the Objective has aux save tokens and the custom loop does not pass `aux`, each selected aux history receives `None` for that call. A custom loop that already computed a conforming aux pytree may pass it explicitly.
290
+
291
+ To compute mapped aux inside the custom loop, preserve it as auxiliary output during differentiation:
292
+
293
+ ```python
294
+ value_aux_fn = obj.value_function_aux()
295
+ if value_aux_fn is None:
296
+ raise RuntimeError("this problem has no aux objective")
297
+ value_and_grad_aux_fn = jax.jit(jax.value_and_grad(value_aux_fn, has_aux=True))
298
+
299
+ _ = value_and_grad_aux_fn(params) # JIT warmup before timing
300
+ obj.start_logging()
301
+ (loss, aux), grads = value_and_grad_aux_fn(params)
302
+ obj.log_evaluation(params, loss, grads, aux=aux)
303
+ ```
304
+
305
+ Only aux fields selected in the Objective's `save` configuration are persisted.
287
306
 
288
307
  ```python
289
308
  # Get the raw function for JIT compilation
@@ -21,15 +21,15 @@ The base install keeps heavyweight optimizer backends optional. Add extras for t
21
21
  ```bash
22
22
  pip install "dfbench[optax,scipy]" # common local optimizers
23
23
  pip install "dfbench[evolution]" # CMA, EvoX, Nevergrad, Evosax
24
- pip install "dfbench[bo]" # BoTorch/Ax/HEBO surrogate optimizers
24
+ pip install "dfbench[bo]" # BoTorch/Ax surrogate optimizers
25
25
  pip install "dfbench[dfo,smac]" # derivative-free and SMAC optimizers
26
- pip install "dfbench[all]" # all optimizer backends
26
+ pip install "dfbench[all]" # all packaged optimizer backends
27
27
  pip install "dfbench[cuda13]" # CUDA 13 JAX support
28
28
  pip install "dfbench[cuda12]" # CUDA 12 JAX support
29
29
  pip install "dfbench[analysis]" # notebooks, profiling, plotting helpers
30
30
  ```
31
31
 
32
- `HEBO` is part of the `bo` and `all` extras. The optional backends are imported lazily: `import dfbench` succeeds even when an extra is not installed, and importing an algorithm whose backend is missing raises an `ImportError` pointing to the extra to install (e.g. `uv add 'dfbench[bo]'`).
32
+ `HEBO` is intentionally not exposed through a project extra because its dependency stack is incompatible with dfbench's NumPy 2.x stack. The guarded wrapper remains available for users who provide and test a compatible HEBO installation themselves. Other optional backends are imported lazily: `import dfbench` succeeds when their extras are not installed.
33
33
 
34
34
  ## Development Install with `uv`
35
35
 
@@ -78,7 +78,7 @@ pip install -e .
78
78
  # With CUDA GPU support
79
79
  pip install -e ".[cuda12]"
80
80
 
81
- # With all optimizer backends and analysis tools
81
+ # With all packaged optimizer backends and analysis tools (HEBO excluded)
82
82
  pip install -e ".[all,analysis]"
83
83
  ```
84
84
 
@@ -48,7 +48,7 @@ Objective(
48
48
  | `save_time_steps` | `bool` | `True` | Record elapsed-time timestamp for each evaluation. |
49
49
  | `save_params_history` | `bool` | `True` | Record the parameter vector at each evaluation. |
50
50
  | `save_batched_params_history` | `bool` | `False` | Store full `(batch, n_params)` parameter arrays for batched evals instead of the reduced representative point. |
51
- | `save` | `list[str] \| None` | `None` | List of advanced save tokens for recording additional / batched histories. Standard tokens: `"grad"`, `"hessian"`, `"eval_type"`, `"batched_loss"`, `"batched_grad"`, `"batched_hessian"`, `"batched"` (convenience alias expanding to the three batched tokens above). Aux diagnostics tokens (recorded by the `*_aux` evaluation methods on problems that opt into the power-penalty contract): `"sensitivity_loss"`, `"penalty"`, `"is_feasible"`, `"power_values"`, `"violations"`, `"aux"` (convenience alias expanding to all five), plus per-field `batched_*` variants and `"batched_aux"` (see Choosing what to save). The active configuration is recorded as a `SaveConfig` and embedded in every checkpoint so a resumed run can detect mismatches. |
51
+ | `save` | `list[str] \| None` | `None` | List of advanced save tokens for recording additional / batched histories. Standard tokens: `"grad"`, `"hessian"`, `"eval_type"`, `"batched_loss"`, `"batched_grad"`, `"batched_hessian"`, `"batched"` (convenience alias expanding to the three batched tokens above). Aux diagnostics tokens: `"sensitivity_loss"`, `"penalty"`, `"is_feasible"`, `"power_values"`, `"violations"`, `"aux"` (convenience alias expanding to all five), plus per-field `batched_*` variants and `"batched_aux"`. On a problem exposing `objective_function_aux`, these tokens persist diagnostics from explicit `*_aux` methods and standard value-bearing methods. Derivative-only calls append aligned `None` entries. On a problem without `objective_function_aux`, aux tokens emit `RuntimeWarning` and automatic aux logging remains disabled; explicit aux methods still raise `RuntimeError`. The active configuration is recorded as a `SaveConfig` and restored from checkpoints so a resumed run keeps the original history schema. |
52
52
  | `verbose` | `int` | `0` | Verbosity level. `0` = silent; `1` = periodic progress prints; `2` is WIP. |
53
53
  | `print_every` | `int` | `100` | When `verbose ≥ 1`, print a progress summary every N evaluations. |
54
54
  | `algorithm_str` | `str \| None` | `None` | If `None`, this is set by the algorithm via `prepare()` of `OptimizationAlgorithm`. Optional identifier string used in file names and logs. |
@@ -127,11 +127,11 @@ You do **not** need to handle bounds scaling; the Objective does that automatica
127
127
 
128
128
  ### Choosing what to save
129
129
 
130
- The Objective always records losses. Three standard boolean flags control the most commonly toggled histories:
130
+ The Objective always maintains an aligned `loss_history`: value-bearing calls store their loss, while derivative-only calls store a NaN placeholder because they do not return a primal loss. Three standard boolean flags control the most commonly toggled histories:
131
131
 
132
132
  | Flag | Default | Effect |
133
133
  |------|---------|--------|
134
- | `save_time_steps` | `True` | Record elapsed-time timestamps per evaluation |
134
+ | `save_time_steps` | `True` | Record one elapsed-time timestamp per admitted logged call |
135
135
  | `save_params_history` | `True` | Record parameter vectors (reduced for batches) |
136
136
  | `save_batched_params_history` | `False` | Store full `(batch, n_params)` parameter arrays instead of the reduced representative point |
137
137
 
@@ -139,23 +139,23 @@ For advanced combinations (gradients, Hessians, eval types, full batched arrays)
139
139
 
140
140
  | Token | Effect |
141
141
  |-------|--------|
142
- | `"grad"` | Record gradient history (reduced to one entry per eval for batches) |
143
- | `"hessian"` | Record Hessian history (reduced to one entry per eval for batches) |
144
- | `"eval_type"` | Record per-eval type bitmask history |
142
+ | `"grad"` | Record gradients (one entry per logged call; batches reduced) |
143
+ | `"hessian"` | Record Hessians (one entry per logged call; batches reduced) |
144
+ | `"eval_type"` | Record one call-type bitmask per logged call |
145
145
  | `"batched_loss"` | Store full `(batch,)` loss vectors instead of batch min |
146
146
  | `"batched_grad"` | Store full `(batch, n_params)` gradient arrays |
147
147
  | `"batched_hessian"` | Store full `(batch, n_params, n_params)` Hessian arrays |
148
148
  | `"batched"` | Convenience alias expanding to the three `batched_*` tokens above |
149
149
 
150
- Aux diagnostics tokens are recorded by the `*_aux` evaluation methods, and also by the standard loss-bearing methods (`value`, `value_and_grad`, `vmap_value`, `vmap_value_and_grad`, `value_grad_and_hessian`, `vmap_value_grad_and_hessian`) when auto-logging is active. Auto-logging turns on when at least one aux token is in the `save` list and the problem opts into the power-penalty contract (`ConstrainedVoyagerProblem`, `UIFOProblem`); the standard methods then run the aux objective in the same forward pass and populate the aux histories without changing their return signatures (see [Auto-logging aux](#auto-logging-aux-from-the-standard-methods)). Each token controls one aux field, so enabling `is_feasible` does not force storing the bulky `power_values` arrays.
150
+ Aux diagnostics tokens are recorded by the explicit `*_aux` evaluation methods and by the standard value-bearing methods (`value`, `value_and_grad`, `vmap_value`, `vmap_value_and_grad`, `value_grad_and_hessian`, `vmap_value_grad_and_hessian`). Auto-logging turns on when at least one aux token is in the `save` list and the problem exposes `objective_function_aux` (the built-in examples are `ConstrainedVoyagerProblem` and `UIFOProblem`). The standard methods then run the aux objective in the same forward pass and populate the aux histories without changing their return signatures (see [Auto-logging aux](#auto-logging-aux-from-standard-value-bearing-methods)). Each token controls one aux field, so enabling `is_feasible` does not force storing the bulky `power_values` arrays. On a problem without `objective_function_aux`, construction emits `RuntimeWarning`, standard methods continue through the scalar objective, and aux histories remain empty.
151
151
 
152
152
  | Token | Effect |
153
153
  |-------|--------|
154
- | `"sensitivity_loss"` | Record the unpenalised sensitivity loss per aux eval (reduced for batches) |
155
- | `"penalty"` | Record the summed penalty per aux eval (reduced for batches) |
156
- | `"is_feasible"` | Record the physical feasibility flag per aux eval (reduced for batches) |
157
- | `"power_values"` | Record per-group powers (hard, soft, detector) per aux eval (reduced for batches) |
158
- | `"violations"` | Record per-constraint penalty values per aux eval (reduced for batches) |
154
+ | `"sensitivity_loss"` | Record the unpenalised sensitivity loss per logged call (reduced for batches; `None` when no aux is produced) |
155
+ | `"penalty"` | Record the summed penalty per logged call (reduced for batches; `None` when no aux is produced) |
156
+ | `"is_feasible"` | Record the physical feasibility flag per logged call (reduced for batches; `None` when no aux is produced) |
157
+ | `"power_values"` | Record per-group powers (hard, soft, detector) per logged call (reduced for batches; `None` when no aux is produced) |
158
+ | `"violations"` | Record per-constraint penalty values per logged call (reduced for batches; `None` when no aux is produced) |
159
159
  | `"aux"` | Convenience alias expanding to the five non-batched aux tokens above |
160
160
  | `"batched_sensitivity_loss"` | Store full batched sensitivity loss arrays |
161
161
  | `"batched_penalty"` | Store full batched penalty arrays |
@@ -164,7 +164,7 @@ Aux diagnostics tokens are recorded by the `*_aux` evaluation methods, and also
164
164
  | `"batched_violations"` | Store full batched per-constraint violation arrays |
165
165
  | `"batched_aux"` | Convenience alias expanding to the five `batched_*` aux tokens above |
166
166
 
167
- When a `batched_*` aux token is off and the corresponding non-batched token is on, batched aux entries are reduced to the representative point (the index of the best loss within the batch), so the recorded `is_feasible` and `violations` reflect that best point. This matches the reduction rule used for gradients and Hessians.
167
+ When a `batched_*` aux token is off and the corresponding non-batched token is on, aux from every batched value-bearing call—including a singleton batch—is reduced to the representative point. Value-bearing calls select the index of the best loss, so the recorded `is_feasible` and `violations` reflect that best point. This matches the representative used for parameters, gradients, and Hessians.
168
168
 
169
169
  ```python
170
170
  # Record gradients and full batched losses
@@ -178,7 +178,7 @@ obj = Objective(problem, save=["grad", "hessian", "eval_type", "batched"])
178
178
  obj = Objective(problem, save=["aux", "batched_is_feasible"])
179
179
  ```
180
180
 
181
- The active configuration is stored as a `SaveConfig` and embedded in every checkpoint's `RunMetadata`. On `load_run_data`, the Objective warns if the checkpoint's save config differs from the current Objective's, preventing silent inconsistency.
181
+ The active configuration is stored as a `SaveConfig` and embedded in every checkpoint's `RunMetadata`. On `load_run_data`, the Objective warns if the checkpoint config differs and adopts the stored config before restoring state, so resumed evaluations keep the run's original history schema.
182
182
 
183
183
  ### Storage (internal)
184
184
 
@@ -203,7 +203,7 @@ obj.value_grad_and_hessian(params) # -> (float, Array[n_params], Array[n_params
203
203
  ```
204
204
 
205
205
  - `value(params)`: Evaluates the loss at `params`. Logs loss and params.
206
- - `grad(params)`: Computes the gradient. Logs grad and params, but **not** a loss value (the loss is not computed).
206
+ - `grad(params)`: Computes the gradient. The scalar primal is evaluated as part of differentiation, but its value is not returned or logged; `loss_history` receives a NaN placeholder.
207
207
  - `hessian(params)`: Computes the exact Hessian. Logs Hessian and params, but **not** a loss value.
208
208
  - `value_and_grad(params)`: Computes both in a single forward+backward pass. Logs all three. **Preferred when you need both loss and gradient** because it is more efficient than calling `value` and `grad` separately and it logs the loss.
209
209
  - `value_grad_and_hessian(params)`: Computes loss, gradient, and Hessian together and logs all four.
@@ -233,7 +233,7 @@ Batched methods use `jax.vmap` and evaluate the entire batch as **one** history
233
233
 
234
234
  ### Aux evaluation
235
235
 
236
- Available on problems that opt into the power-penalty contract (`ConstrainedVoyagerProblem`, `UIFOProblem`). These methods return the loss plus an `aux` pytree dict carrying the loss decomposition, a physical `is_feasible` flag, per-constraint violations, and the raw per-group power arrays. See the [Power thresholds and aux diagnostics](#power-thresholds-and-aux-diagnostics) section for the aux schema.
236
+ Available on problems that expose `objective_function_aux` (`ConstrainedVoyagerProblem` and `UIFOProblem` are the built-in examples). These methods return the loss plus an `aux` pytree dict carrying the loss decomposition, a physical `is_feasible` flag, per-constraint violations, and the raw per-group power arrays. See the [Power thresholds and aux diagnostics](#power-thresholds-and-aux-diagnostics) section for the aux schema.
237
237
 
238
238
  ```python
239
239
  obj.value_aux(params) # -> (float, dict)
@@ -243,21 +243,21 @@ obj.vmap_value_and_grad_aux(params_batch) # -> (Array[batch], Array[batch, n_par
243
243
  ```
244
244
 
245
245
  - `value_aux(params)` returns `(loss, aux)`. The loss is logged into the standard loss history; aux fields are recorded into the per-field aux histories only when the matching save token is enabled.
246
- - `value_and_grad_aux(params)` computes loss, gradient, and aux in one forward+backward pass via `jax.value_and_grad(..., has_aux=True)`. The gradient is taken with respect to the loss (the penalty preset does not affect the gradient because the powers are intermediate simulation outputs, not parameters).
246
+ - `value_and_grad_aux(params)` computes loss, gradient, and aux in one forward+backward pass via `jax.value_and_grad(..., has_aux=True)`. The gradient is taken with respect to the total returned loss, including any parameter-dependent penalty. `has_aux=True` carries the aux pytree through unchanged; derivatives of aux are neither returned nor logged.
247
247
  - `vmap_value_aux` and `vmap_value_and_grad_aux` are the batched variants. Because `aux` is a JAX pytree, a batched call adds a leading batch dim to every leaf, including the `power_values` sub-arrays.
248
- - The aux methods raise `RuntimeError` on problems that do not expose `objective_function_aux` (for example `VoyagerProblem`, `VoyagerTuningProblem`, or any non-optical `ContinuousProblem`).
248
+ - The explicit aux methods raise `RuntimeError` when the wrapped problem does not expose `objective_function_aux` (for example `VoyagerProblem` and `VoyagerTuningProblem`). A custom `ContinuousProblem` may opt in by implementing the same aux objective contract.
249
249
 
250
250
  Warmup helpers `warmup_value_aux`, `warmup_value_and_grad_aux`, `warmup_vmap_value_aux`, and `warmup_vmap_value_and_grad_aux` compile the aux callables before `start_logging()`. On problems without an aux objective they are a no-op (with a notice at `verbose >= 1`) rather than raising, so an algorithm that unconditionally warms up aux does not break on a non-constrained problem.
251
251
 
252
- ### Auto-logging aux from the standard methods
252
+ ### Auto-logging aux from standard value-bearing methods
253
253
 
254
- When one or more aux save tokens are enabled and the problem exposes `objective_function_aux`, the standard loss-bearing methods (`value`, `value_and_grad`, `vmap_value`, `vmap_value_and_grad`, `value_grad_and_hessian`, `vmap_value_grad_and_hessian`) run the aux objective in the same forward pass and record the enabled aux diagnostics. No code change is needed in the optimization loop: a plain `obj.value(params)` call populates `is_feasible_history`, `sensitivity_loss_history`, and so on, in addition to `loss_history`.
254
+ When one or more aux save tokens are enabled and the problem exposes `objective_function_aux`, the standard value-bearing methods (`value`, `value_and_grad`, `vmap_value`, `vmap_value_and_grad`, `value_grad_and_hessian`, `vmap_value_grad_and_hessian`) run the aux objective in the same forward pass and record the enabled aux diagnostics. No code change is needed in the optimization loop: a plain `obj.value(params)` call populates `is_feasible_history`, `sensitivity_loss_history`, and so on, in addition to `loss_history`.
255
255
 
256
- This rebinds the internal loss-bearing callables to the aux variants at bind time, so the aux pytree comes out of the same simulation that produced the loss. There is no second forward pass. The returned values keep their usual shapes (`value` still returns a scalar, `value_and_grad` still returns `(loss, grad)`); the aux pytree is stashed internally and fed to `_log_aux` without changing the public signatures.
256
+ This rebinds the internal value-bearing callables to the aux variants at bind time, so the aux pytree comes out of the same simulation that produced the loss. There is no second forward pass. The returned values keep their usual shapes (`value` still returns a scalar, `value_and_grad` still returns `(loss, grad)`); internally, exactly one aux pytree travels alongside the value result and is passed directly to `_log(..., aux=aux)`.
257
257
 
258
- Grad-only and Hessian-only calls (`grad`, `hessian`, `vmap_grad`, `vmap_hessian`) do not compute a loss, so they have no aux to record. They append `None` placeholders to the enabled aux histories so the aux histories stay length-aligned with `loss_history`. `best_is_feasible` and the aux history properties treat `None` entries as missing.
258
+ Grad-only and Hessian-only calls (`grad`, `hessian`, `vmap_grad`, `vmap_hessian`) differentiate the scalar objective but do not return or carry a primal loss/aux result. They therefore append `None` placeholders to enabled aux histories so those histories stay length-aligned with `loss_history`. The history properties preserve these `None` entries; `best_is_feasible` interprets one at the best-loss index as unavailable.
259
259
 
260
- Auto-logging is active only when both conditions hold: at least one aux token is in the `save` list, and the problem opts into the power-penalty contract. On problems without an aux objective, or when no aux token is enabled, the standard methods use the scalar primal and the aux histories stay empty, so non-aux runs pay no overhead. Toggling save tokens or calling `set_penalty_fn` (which retraces) re-evaluates the condition, so auto-logging stays in sync after a penalty swap.
260
+ Auto-logging is active only when both conditions hold: at least one aux token is in the construction-time `save` list, and the problem exposes `objective_function_aux`. With no aux token, standard methods use the scalar primal and aux histories stay empty, so non-aux runs pay no aux-computation overhead. Supplying an aux token for a problem without an aux objective emits `RuntimeWarning` and falls back to the same scalar path; explicit aux methods still raise `RuntimeError`. Calling `set_penalty_fn` rebinds the cached callables so the selected value family stays in sync after a penalty swap.
261
261
 
262
262
  ```python
263
263
  obj = Objective(problem, save=["is_feasible"])
@@ -289,13 +289,31 @@ When `unbounded=True`, the returned callable maps unbounded parameters into the
289
289
 
290
290
  Because this callable is intentionally unlogged, pair it with `obj.log_evaluation(...)` after each completed optimizer step if the evaluation should count toward benchmark histories. For ordinary algorithm loops, prefer `obj.value(...)`, `obj.value_and_grad(...)`, or the batched evaluation methods.
291
291
 
292
+ ### Unlogged raw value-and-aux function
293
+
294
+ ```python
295
+ aux_value_fn = obj.value_function_aux() # follows obj.unbounded
296
+ if aux_value_fn is None:
297
+ raise RuntimeError("this problem has no aux objective")
298
+
299
+ value_and_grad_aux_fn = jax.jit(
300
+ jax.value_and_grad(aux_value_fn, has_aux=True)
301
+ )
302
+ _ = value_and_grad_aux_fn(params) # JIT warmup before timing
303
+ obj.start_logging()
304
+ (loss, aux), grad = value_and_grad_aux_fn(params)
305
+ obj.log_evaluation(params=params, loss=loss, grad=grad, aux=aux)
306
+ ```
307
+
308
+ `value_function_aux(unbounded=None)` is the mapped, JAX-compatible counterpart to `value_function()`. It returns an unlogged callable whose invocation yields `(loss, aux)`, follows the same `unbounded` argument semantics, and returns `None` when the problem does not expose `objective_function_aux`. This is the safe way for a custom JIT loop to obtain aux without bypassing the Objective's space mapping. `log_evaluation` persists only fields selected by aux save tokens.
309
+
292
310
  ### Manual logging
293
311
 
294
312
  ```python
295
- obj.log_evaluation(params=..., loss=..., grad=..., hessian=...)
313
+ obj.log_evaluation(params=..., loss=..., grad=..., hessian=..., aux=...)
296
314
  ```
297
315
 
298
- For algorithms with custom JIT-compiled evaluation loops that use `obj.value_function(...)` instead of calling `obj.value()` directly. Accepts the same `params`, `loss`, `grad`, `hessian` arguments and performs identical history recording.
316
+ For algorithms with custom JIT-compiled evaluation loops that use `obj.value_function(...)` or `obj.value_function_aux(...)` instead of calling `obj.value()` directly. Accepts `params`, `loss`, `grad`, `hessian`, and optional `aux` results and performs the same history recording. Supplied aux is persisted only for matching save tokens. In an aux-enabled run, omitting `aux` records `None` in each selected aux history; manual logging never manufactures aux diagnostics.
299
317
 
300
318
  ---
301
319
 
@@ -376,7 +394,7 @@ obj.set_space_mode(
376
394
 
377
395
  Sets the wrapped problem's penalty function and re-binds all internal JAX evaluation paths.
378
396
 
379
- For problems that opt into the power-penalty contract (`ConstrainedVoyagerProblem`, `UIFOProblem`), this forwards to `problem.set_penalty_fn(fn)`, which updates the problem's penalty callable and re-traces its JIT-compiled `objective_function` so the new penalty actually takes effect. The Objective then re-binds its own cached `value` / `grad` / `hessian` / `vmap_*` callables, mirroring the tail of `set_space_mode`.
397
+ For problems that opt into the power-penalty contract (`ConstrainedVoyagerProblem`, `UIFOProblem`), this forwards to `problem.set_penalty_fn(fn)`, which updates the problem's penalty callable and rebuilds both its JIT-compiled scalar and aux objectives. The Objective then re-binds its own cached `value` / `grad` / `hessian` / `vmap_*` callables, mirroring the tail of `set_space_mode`.
380
398
 
381
399
  - Must be called before `start_logging()`
382
400
  - Raises `RuntimeError` if the wrapped problem does not opt into the power-penalty contract. The opt-in marker is the class attribute `_supports_power_penalty`; problems without a power-constraint path (`VoyagerProblem`, `VoyagerTuningProblem`, and any non-optical `ContinuousProblem`) leave it `False` and reject the call rather than silently rebuilding, even though they inherit the method from `OpticalSetupProblem`
@@ -402,10 +420,10 @@ The constrained problems also expose a JIT-compiled `objective_function_aux(para
402
420
  | `sensitivity_loss` | scalar | The unpenalised sensitivity loss. |
403
421
  | `penalty` | scalar | The summed penalty contribution. |
404
422
  | `is_feasible` | scalar bool | `True` iff every per-group power is at or below its threshold. This is a physical check, independent of the active `power_penalty_fn` preset. |
405
- | `violations` | `(n_constraints, n_freq)` | Per-constraint penalty values. |
423
+ | `violations` | `(n_constraints,)` | Per-constraint penalty values. |
406
424
  | `power_values` | dict with `hard`, `soft`, `detector` leaves | Raw per-group power arrays. |
407
425
 
408
- `aux` is a JAX pytree, so `objective_function_aux` vmapps cleanly: a batched call adds a leading batch dim to every leaf, including the `power_values` sub-arrays. The Objective-level `value_aux` / `value_and_grad_aux` / `vmap_*_aux` wrappers thread aux through logging and the save-token system; see the [Aux evaluation](#aux-evaluation) subsection and the aux tokens in [Choosing what to save](#choosing-what-to-save).
426
+ `aux` is a JAX pytree, so `objective_function_aux` vmapps cleanly: a batched call adds a leading batch dim to every leaf, including the `power_values` sub-arrays. The Objective-level explicit `*_aux` wrappers and standard value-bearing methods thread aux through logging and the save-token system; see the [Aux evaluation](#aux-evaluation) subsection and the aux tokens in [Choosing what to save](#choosing-what-to-save).
409
427
 
410
428
  ---
411
429
 
@@ -479,7 +497,7 @@ bounded ≈ lb + (ub - lb) * forward(random_params_unbounded(...))
479
497
  | `best_params_bounded` | `Array \| None` | Best parameters mapped to bounded space via the active mapping (custom mapping if configured, otherwise sigmoid). **Use this for final output.** |
480
498
  | `best_eval_index` | `int \| None` | Index into the loss history holding the best loss, or `None` before the first improvement. |
481
499
  | `best_batch_index` | `int \| None` | Within-batch index of the best loss when it came from a batched evaluation, or `None` for single-point evals. |
482
- | `best_is_feasible` | `bool \| None` | Feasibility of the best-loss point, or `None` when the `is_feasible` save token was never enabled, no evaluation has improved yet, or the best point came from a non-aux evaluation. Uses the physical `power <= threshold` check, so it stays meaningful even when the penalty is disabled with `zero_penalty`. For batched best losses, the feasibility of the winning batch element is returned when `batched_is_feasible` storage is on; otherwise the per-call reduced entry is used. |
500
+ | `best_is_feasible` | `bool \| None` | Feasibility of the best-loss point, or `None` when neither `is_feasible` nor `batched_is_feasible` was enabled, no evaluation has improved yet, or a manually logged best point omitted aux. Uses the physical `power <= threshold` check, so it stays meaningful even when the penalty is disabled with `zero_penalty`. For batched best losses, the feasibility of the winning batch element is returned when `batched_is_feasible` storage is on; otherwise the per-call reduced entry is used. |
483
501
 
484
502
  ### Current State
485
503
 
@@ -500,15 +518,15 @@ These properties return **copies** to prevent external mutation.
500
518
  | `params_history` | `list` | All recorded parameter vectors (raw space, i.e. as it was given to the `Objective`). |
501
519
  | `params_history_bounded` | `list` | Params history mapped to bounded space. |
502
520
  | `time_steps` | `list[float]` | Elapsed time at each recorded evaluation. |
503
- | `sensitivity_loss_history` | `list` | Per-eval unpenalised sensitivity loss (aux evals only, when `sensitivity_loss` or `batched_sensitivity_loss` is enabled). |
504
- | `penalty_history` | `list` | Per-eval summed penalty (aux evals only, when `penalty` or `batched_penalty` is enabled). |
505
- | `is_feasible_history` | `list` | Per-eval physical feasibility flag (aux evals only, when `is_feasible` or `batched_is_feasible` is enabled). |
506
- | `violations_history` | `list` | Per-eval per-constraint violation arrays (aux evals only, when `violations` or `batched_violations` is enabled). |
507
- | `power_hard_history` | `list` | Per-eval hard-group power arrays (aux evals only, when `power_values` or `batched_power_values` is enabled). |
508
- | `power_soft_history` | `list` | Per-eval soft-group power arrays (aux evals only, when `power_values` or `batched_power_values` is enabled). |
509
- | `power_detector_history` | `list` | Per-eval detector-group power arrays (aux evals only, when `power_values` or `batched_power_values` is enabled). |
521
+ | `sensitivity_loss_history` | `list` | Per-logged-call unpenalised sensitivity loss when selected; `None` for calls without aux. |
522
+ | `penalty_history` | `list` | Per-logged-call summed penalty when selected; `None` for calls without aux. |
523
+ | `is_feasible_history` | `list` | Per-logged-call physical feasibility flag when selected; `None` for calls without aux. |
524
+ | `violations_history` | `list` | Per-logged-call constraint violation arrays when selected; `None` for calls without aux. |
525
+ | `power_hard_history` | `list` | Per-logged-call hard-group power arrays when `power_values` storage is selected; `None` for calls without aux. |
526
+ | `power_soft_history` | `list` | Per-logged-call soft-group power arrays when `power_values` storage is selected; `None` for calls without aux. |
527
+ | `power_detector_history` | `list` | Per-logged-call detector-group power arrays when `power_values` storage is selected; `None` for calls without aux. |
510
528
 
511
- The aux histories are aligned with the standard histories by index. Non-aux evaluations (`value`, `grad`, `hessian`, `vmap_*`) do not append to them, so an aux history may be shorter than `loss_history` when a run mixes aux and non-aux calls.
529
+ Each enabled aux history is index-aligned with `loss_history`: value-bearing standard and explicit aux calls append the selected diagnostics, while derivative-only calls and `log_evaluation(..., aux=None)` append `None`. Aux histories whose save token is disabled remain empty.
512
530
 
513
531
  ### Reduced History
514
532
 
@@ -552,7 +570,7 @@ The first save without explicit overrides caches the path; subsequent periodic s
552
570
 
553
571
  ### `load_run_data(filepath)`
554
572
 
555
- Restores all tracking state from a checkpoint via `CheckpointManager.load()` -> `Objective._apply_run_state()`. Adjusts `start_time` so that `time_elapsed` continues seamlessly from where the checkpoint left off. The loaded path is cached so a later `save_run_data()` overwrites the same file. If the checkpoint's `SaveConfig` differs from the current Objective's, a warning is printed (when `verbose >= 1`).
573
+ Restores all tracking state from a checkpoint via `CheckpointManager.load()` -> `Objective._apply_run_state()`. Adjusts `start_time` so that `time_elapsed` continues seamlessly from where the checkpoint left off. The loaded path is cached so a later `save_run_data()` overwrites the same file. If the checkpoint's `SaveConfig` differs from the constructor configuration, `RuntimeWarning` is emitted and the checkpoint configuration is adopted before state is applied. When the problem supports aux logging, empty legacy aux histories selected by that config are backfilled with one `None` entry per prior logged call before evaluation resumes.
556
574
 
557
575
  The originating `Problem` can be rebuilt from the embedded `problem_spec`:
558
576
 
@@ -603,12 +621,12 @@ Returns a snapshot dictionary:
603
621
  Every evaluation method follows the same pipeline internally:
604
622
 
605
623
  1. **Execute** the JAX function (`_func`, `_value_and_grad_func`, `_vmap_func`, etc.)
606
- 2. **`_log(params, loss, grad, hessian)`**: the coordinator: checks `time_exceeded`, appends to `_time_steps`, then delegates to `_log_evals()` and `_log_to_file()`.
607
- 3. **`_log_evals(params, loss, grad, hessian, time_exceeded)`**: record histories; update `best_loss` / `best_params`; update `improvement_count` / `evals_since_improvement`; check eval budget. Receives `time_exceeded` as an explicit parameter from `_log()` to ensure a consistent time snapshot.
624
+ 2. **`_log(params, loss, grad, hessian, aux)`**: takes one elapsed-time snapshot, asks `_log_evals()` to admit and atomically record the call, appends the timestamp only when admitted, then invokes `_log_to_file()`.
625
+ 3. **`_log_evals(params, loss, grad, hessian, aux, time_exceeded)`**: checks the evaluation/time budget, resolves selected aux leaves before mutating histories, records all aligned histories, updates best/stagnation state, and returns whether the call was admitted.
608
626
  4. **`_log_to_file()`**: calls `CheckpointManager.tick(eval_count, state_factory)`, which checks the cadence (`save_every`, set from `save_to_file_every`), lazily builds a `RunState` only when a checkpoint is due, saves it through the internal `StorageBackend`, and returns the wall-clock duration of the save. The Objective advances `_start_time` by that duration so the checkpoint write does not consume wall-clock budget.
609
627
 
610
- > **Important:** These are private methods; do not call `_log()`, `_log_evals()`, or `_log_to_file()` directly from algorithm code. If you want manual logging, use the public `log_evaluation(params, loss, grad, hessian=None)` method instead, which delegates to `_log()`. See the [JIT-compiled loop guide](Implementing-a-New-Algorithm#custom-jit-compiled-loops-with-log_evaluation) for details.
628
+ > **Important:** These are private methods; do not call `_log()`, `_log_evals()`, or `_log_to_file()` directly from algorithm code. If you want manual logging, use the public `log_evaluation(params, loss, grad=None, hessian=None, aux=None)` method instead, which delegates to `_log()`. See the [JIT-compiled loop guide](Implementing-a-New-Algorithm#custom-jit-compiled-loops-with-log_evaluation) for details.
611
629
 
612
630
  Budget enforcement happens *after* the evaluation returns. This means the algorithm always receives a valid result, but once any budget is exceeded the history stops growing and `budget_exceeded` becomes `True`.
613
631
 
614
- When a batch evaluation (`vmap_*`) would push `eval_count` past `max_evals`, the evaluations are counted but *not logged*, preserving history alignment and setting the `budget_exceeded` flag to `True`. The `time_steps` entry added by `_log()` is also removed to keep all lists in sync. This may be subject to change but in the current setting, this is the most straight-forward way and irrelevant if budged is planned well (reducing population as `evals_left` nears zero).
632
+ When a batch evaluation (`vmap_*`) would push `eval_count` past `max_evals`, the evaluations are counted but *not logged*, preserving history alignment and setting the `budget_exceeded` flag to `True`. Because admission happens before history mutation, no loss, parameter, derivative, aux, or time entry needs to be rolled back. Reducing population as `evals_left` nears zero avoids evaluating an unrecorded batch.
@@ -197,7 +197,7 @@ problem = ConstrainedVoyagerProblem(n_frequencies=50, signal_floor=1e-20)
197
197
  problem = ConstrainedVoyagerProblem(power_penalty_fn=my_quadratic_penalty)
198
198
  ```
199
199
 
200
- The penalty function can also be swapped **after** the problem has been constructed (e.g. after wrapping it in an `Objective`), via `Objective.set_penalty_fn(fn)`. This re-traces the problem's JIT-compiled `objective_function` and re-binds the Objective's cached evaluation callables, so the new penalty takes effect on subsequent evaluations. It must be called before `Objective.start_logging()`:
200
+ The penalty function can also be swapped **after** the problem has been constructed (e.g. after wrapping it in an `Objective`), via `Objective.set_penalty_fn(fn)`. This rebuilds the problem's JIT-compiled scalar and aux objectives and re-binds the Objective's cached evaluation callables, so the new penalty takes effect on subsequent evaluations. It must be called before `Objective.start_logging()`:
201
201
 
202
202
  ```python
203
203
  from dfbench import Objective
@@ -229,7 +229,7 @@ The constrained problems also expose a JIT-compiled `objective_function_aux(para
229
229
 
230
230
  Because `aux` is a JAX pytree, `objective_function_aux` vmapps cleanly: a batched call adds a leading batch dim to every leaf, including the `power_values` sub-arrays.
231
231
 
232
- The `Objective` wraps this with `value_aux`, `value_and_grad_aux`, `vmap_value_aux`, and `vmap_value_and_grad_aux`. These thread aux through logging and the save-token system: each aux field has its own token (`sensitivity_loss`, `penalty`, `is_feasible`, `power_values`, `violations`) plus a `batched_*` variant and `aux` / `batched_aux` convenience aliases. When a `batched_*` token is off and the non-batched token is on, batched aux entries are reduced to the representative point picked by the loss minimum, so the recorded `is_feasible` and `violations` reflect that best point. `Objective.best_is_feasible` reports the feasibility of the best-loss point from that recorded history. Full reference in the [Objective API Reference](Objective-API-Reference).
232
+ The `Objective` wraps this with `value_aux`, `value_and_grad_aux`, `vmap_value_aux`, and `vmap_value_and_grad_aux`. These explicit methods—and standard value-bearing methods when an aux save token is selected—thread aux through logging without a second forward pass. Each aux field has its own token (`sensitivity_loss`, `penalty`, `is_feasible`, `power_values`, `violations`) plus a `batched_*` variant and `aux` / `batched_aux` convenience aliases. Derivative-only calls do not produce a primal aux pytree and append `None` to enabled aux histories. When a `batched_*` token is off and the non-batched token is on, aux from every batched value-bearing call, including a singleton batch, is reduced to the representative point picked by the loss minimum. `Objective.best_is_feasible` reports the feasibility of the best-loss point from that recorded history. Full reference in the [Objective API Reference](Objective-API-Reference).
233
233
 
234
234
  ---
235
235