dfbench 0.3.1__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.
- {dfbench-0.3.1 → dfbench-0.3.2}/.gitignore +1 -5
- {dfbench-0.3.1 → dfbench-0.3.2}/PKG-INFO +4 -3
- {dfbench-0.3.1 → dfbench-0.3.2}/README.md +3 -2
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/Architecture-Overview.md +23 -17
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/Implementing-a-New-Algorithm.md +24 -5
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/Objective-API-Reference.md +60 -42
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/Problems.md +2 -2
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/Storage-and-Checkpointing.md +23 -6
- {dfbench-0.3.1 → dfbench-0.3.2}/pyproject.toml +1 -1
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/objective.py +378 -670
- dfbench-0.3.2/src/dfbench/core/storage/saveconfig.py +194 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/storage/state.py +12 -11
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/problems/base_problem.py +16 -12
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/problems/voyager/constrained_voyager_problem.py +1 -1
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_objective_invariants.py +48 -3
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_objective_penalty_fn.py +405 -35
- dfbench-0.3.1/src/dfbench/core/storage/saveconfig.py +0 -312
- {dfbench-0.3.1 → dfbench-0.3.2}/LICENSE +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/Algorithm-Status.md +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/Algorithms.md +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/Benchmarking.md +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/FAQ.md +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/Home.md +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/Installation.md +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/Metrics-Reference.md +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/Testing.md +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/Utilities-and-Helpers.md +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/_Sidebar.md +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/algorithm-status/main.typ +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/docs/algorithm-status/template.typ +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/_dfo_common.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/_scipy_common.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/nelder_mead.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/omads_mads.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/pdfo/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/pdfo/lincoa.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/pdfo/newuoa.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/pdfo/uobyqa.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/powell.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/derivative_free/pybobyqa.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/cmaes_sep_cma.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/evosax_es.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/evox_es.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/evox_pso.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/jax_es.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/nevergrad/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/nevergrad/_common.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/nevergrad/ngopt.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/nevergrad/oneplusone.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/nevergrad/tbpsa.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/evolutionary/pycma_cmaes.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/generative/vae_sampling.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/global_search/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/global_search/basin_hopping.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/global_search/dual_annealing.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/global_search/random_search.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/adam_gd.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/custom_jax.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/lbfgs_gd.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/na_adam_gd.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/_common.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adabelief.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adadelta.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adafactor.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adagrad.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adam.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adamax.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adamaxw.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adamw.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/adan.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/amsgrad.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/lamb.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/lion.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/lookahead.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/nadam.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/nadamw.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/noisy_sgd.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/novograd.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/oadam.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/ogd.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/polyak_sgd.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/radam.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/rmsprop.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/rprop.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/sam.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/schedule_free_adam.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/sgd.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/sign.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/sm3.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/sophia.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax/yogi.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/optax_lbfgs.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/sa_gd.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/_common.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/bfgs.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/cobyla.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/cobyqa.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/dogleg.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/lbfgsb.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/newton_cg.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/nonlinear_cg.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/slsqp.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/sr1.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/tnc.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/trust_constr.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/trust_krylov.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/gradient_based/scipy/trust_ncg.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/ax_baxus.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/ax_saasbo.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/_botorch_common.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_bo.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_gebo.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_linebo.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_qkg.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_qnei.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_rembo.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/botorch/botorch_turbo.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/hebo_bo.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/restir.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/smac_bo.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/surrogate_based/turbo_lbfgs.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/utils/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/utils/gp.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/utils/initial_design.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/utils/misc.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/algorithms/utils/weighted_acq.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/benchmark/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/benchmark/benchmark.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/benchmark/metrics.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/_init_env.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/algorithm.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/config.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/display.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/problem.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/storage/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/storage/backends.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/storage/exporter.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/storage/manager.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/storage/resolver.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/storage/serializers.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/core/utils.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/problems/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/problems/uifo/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/problems/uifo/uifo_problem.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/problems/voyager/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/problems/voyager/voyager_problem.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/src/dfbench/problems/voyager/voyager_tuning_problem.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/conftest.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/slow/__init__.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/slow/test_algorithms_integration.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/slow/test_benchmark_full.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/slow/test_problem_bounds_gradients.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/slow/test_problems_full.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_algorithm_protocol.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_algorithms_uniform.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_algorithms_unit.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_api_imports.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_benchmark_smoke.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_bo_batch.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_cma_family.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_config.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_custom_jax_batch.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_dfo_algorithms.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_display.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_hebo_packaging.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_init_env.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_metrics.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_objective_randomness.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_objective_space_mode.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_problem_bounds_overrides.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_problem_protocol.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_problem_spec.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_scipy_wrapper.py +0 -0
- {dfbench-0.3.1 → dfbench-0.3.2}/tests/test_storage.py +0 -0
- {dfbench-0.3.1 → 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.
|
|
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
|
|
@@ -177,7 +177,7 @@ This adds negligible overhead compared to the objective function itself.
|
|
|
177
177
|
|
|
178
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.
|
|
179
179
|
|
|
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
|
|
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.
|
|
181
181
|
|
|
182
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.
|
|
183
183
|
|
|
@@ -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.
|
|
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
|
|
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
|
|
|
@@ -383,7 +383,8 @@ class MyAlgorithm(OptimizationAlgorithm):
|
|
|
383
383
|
| `obj.vmap_value_and_grad(batch)` | Batched gradient methods | batch losses, grads, params |
|
|
384
384
|
| `obj.vmap_hessian(batch)` | Batched second-order methods | batch hessians, batch params |
|
|
385
385
|
| `obj.vmap_value_grad_and_hessian(batch)` | Batched second-order methods | batch losses, grads, hessians, params |
|
|
386
|
-
| `obj.
|
|
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 |
|
|
387
388
|
|
|
388
389
|
### Register It
|
|
389
390
|
|
|
@@ -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
|
|
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.
|
|
117
|
+
Objective._value_func / derivative transforms / vmapped transforms
|
|
118
118
|
│
|
|
119
119
|
▼
|
|
120
120
|
┌──────────────────────────────┐
|
|
121
121
|
│ optional Objective mapping │
|
|
122
|
-
│
|
|
122
|
+
│ objective_function or │
|
|
123
|
+
│ objective_function_aux │
|
|
123
124
|
└──────────────┬───────────────┘
|
|
124
125
|
│
|
|
125
126
|
▼
|
|
126
127
|
Differometor.simulate()
|
|
127
128
|
│
|
|
128
129
|
▼
|
|
129
|
-
|
|
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
|
-
|
|
146
|
+
_log_to_file()
|
|
134
147
|
│
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
|
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(...)`
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
143
|
-
| `"hessian"` | Record
|
|
144
|
-
| `"eval_type"` | Record
|
|
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
|
|
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
|
|
155
|
-
| `"penalty"` | Record the summed penalty per
|
|
156
|
-
| `"is_feasible"` | Record the physical feasibility flag per
|
|
157
|
-
| `"power_values"` | Record per-group powers (hard, soft, detector) per
|
|
158
|
-
| `"violations"` | Record per-constraint penalty values per
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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`
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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 `
|
|
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
|
|
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-
|
|
504
|
-
| `penalty_history` | `list` | Per-
|
|
505
|
-
| `is_feasible_history` | `list` | Per-
|
|
506
|
-
| `violations_history` | `list` | Per-
|
|
507
|
-
| `power_hard_history` | `list` | Per-
|
|
508
|
-
| `power_soft_history` | `list` | Per-
|
|
509
|
-
| `power_detector_history` | `list` | Per-
|
|
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
|
-
|
|
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
|
|
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)`**:
|
|
607
|
-
3. **`_log_evals(params, loss, grad, hessian, time_exceeded)`**:
|
|
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`.
|
|
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
|
|
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
|
|
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
|
|
|
@@ -70,14 +70,23 @@ CheckpointManager <- the only facade Objective talks to
|
|
|
70
70
|
| `grad_history` | `np.ndarray` | Aligned gradient history |
|
|
71
71
|
| `hessian_history` | `np.ndarray` | Aligned Hessian history |
|
|
72
72
|
| `params_history` | `np.ndarray` | Aligned parameter history (raw space) |
|
|
73
|
-
| `eval_type_history` | `np.ndarray` |
|
|
74
|
-
| `time_steps` | `np.ndarray` | Elapsed-time stamps
|
|
73
|
+
| `eval_type_history` | `np.ndarray` | One call-type bitmask per logged call when enabled |
|
|
74
|
+
| `time_steps` | `np.ndarray` | Elapsed-time stamps for admitted logged calls when enabled |
|
|
75
|
+
| `sensitivity_loss_history` | `np.ndarray` | Selected aux sensitivity losses; `None` for calls without aux |
|
|
76
|
+
| `penalty_history` | `np.ndarray` | Selected aux penalties; `None` for calls without aux |
|
|
77
|
+
| `is_feasible_history` | `np.ndarray` | Selected aux feasibility flags; `None` for calls without aux |
|
|
78
|
+
| `violations_history` | `np.ndarray` | Selected aux violation arrays; `None` for calls without aux |
|
|
79
|
+
| `power_hard_history` | `np.ndarray` | Selected aux hard-group powers; `None` for calls without aux |
|
|
80
|
+
| `power_soft_history` | `np.ndarray` | Selected aux soft-group powers; `None` for calls without aux |
|
|
81
|
+
| `power_detector_history` | `np.ndarray` | Selected aux detector powers; `None` for calls without aux |
|
|
75
82
|
| `eval_count` | `int` | Total evaluations |
|
|
76
83
|
| `best_loss` | `float` | Lowest loss observed |
|
|
77
84
|
| `best_params` | `np.ndarray` | Parameters at `best_loss` (float64; empty if none) |
|
|
85
|
+
| `best_eval_index` | `int \| None` | Logged-call index containing `best_loss` |
|
|
86
|
+
| `best_batch_index` | `int \| None` | Winning within-batch index, if applicable |
|
|
78
87
|
| `improvement_count` | `int` | Times `best_loss` was improved |
|
|
79
88
|
| `evals_since_improvement` | `int` | Evaluations since last improvement |
|
|
80
|
-
| `log_call_count` | `int` | Number of
|
|
89
|
+
| `log_call_count` | `int` | Number of calls admitted into the histories |
|
|
81
90
|
| `eval_type_counts` | `dict[int, int]` | Distribution of eval call types |
|
|
82
91
|
| `metadata` | `RunMetadata` | Record with run identity + problem spec |
|
|
83
92
|
|
|
@@ -324,6 +333,14 @@ CheckpointManager(..., validate_on_save=False, validate_on_load=False)
|
|
|
324
333
|
|
|
325
334
|
The first `save()` without explicit overrides caches the computed path. Subsequent saves without overrides overwrite the same file. Passing `explicit_path` or `hyper_param_str` bypasses the cache. `load()` caches the loaded path, so a resume-then-save cycle overwrites the same file.
|
|
326
335
|
|
|
336
|
+
`SaveConfig` is part of the persistent run identity. When `Objective.load_run_data()`
|
|
337
|
+
loads a checkpoint whose save configuration differs from the constructor, it
|
|
338
|
+
emits `RuntimeWarning` and adopts the checkpoint configuration before restoring
|
|
339
|
+
state. This prevents enabled histories from changing halfway through a run.
|
|
340
|
+
When the problem supports aux logging, legacy checkpoints that advertise an
|
|
341
|
+
enabled aux history but store no array for it are aligned with `None` entries up
|
|
342
|
+
to `log_call_count` before evaluation resumes.
|
|
343
|
+
|
|
327
344
|
### `tick`: periodic checkpointing
|
|
328
345
|
|
|
329
346
|
`tick` is called by `Objective._log_to_file` after each evaluation. The manager checks the cadence (`save_every`); if a checkpoint is due, it lazily calls `state_factory` to build a `RunState`, saves it, and returns the wall-clock duration of the save. The `Objective` then advances `_start_time` by that duration, so the checkpoint write does not consume wall-clock budget. If no checkpoint is due, `tick` returns `0.0` and `state_factory` is never called.
|
|
@@ -344,7 +361,7 @@ The storage components remain modular and individually testable (see the section
|
|
|
344
361
|
|
|
345
362
|
## `RunState` invariant contract
|
|
346
363
|
|
|
347
|
-
A `RunState` is the scoring contract: every metric the competition computes derives from one. A buggy or adversarial submitter algorithm can produce a state whose fields disagree (e.g. `best_loss` doesn't match `loss_history`, or a history length diverges from `
|
|
364
|
+
A `RunState` is the scoring contract: every metric the competition computes derives from one. A buggy or adversarial submitter algorithm can produce a state whose fields disagree (e.g. `best_loss` doesn't match `loss_history`, or a non-empty history length diverges from `log_call_count`). Without a gate, that mismatch surfaces as a crash deep inside a serializer or the scoring layer, with no clean rejection path.
|
|
348
365
|
|
|
349
366
|
`validate_run_state(state, *, strict=True) -> ValidationReport` is the gate. It is a pure function: no I/O, and it does not raise on a malformed state. It collects every violation, so a rejection report lists all problems in one pass rather than one at a time.
|
|
350
367
|
|
|
@@ -365,7 +382,7 @@ if not report.ok:
|
|
|
365
382
|
|
|
366
383
|
| Tier | Checks | When |
|
|
367
384
|
|------|--------|------|
|
|
368
|
-
| **Structural (A)** | Types, shapes, ranges: `eval_count` is a non-negative int;
|
|
385
|
+
| **Structural (A)** | Types, shapes, ranges: `eval_count` is a non-negative int; all 13 history fields are `np.ndarray` (first axis = logged call; N-D allowed since NumPy collapses uniform object arrays); `best_params` is 1-D float64 or empty; `eval_type_counts` is a dict with int keys / non-negative int values; `metadata` is a `RunMetadata`; scalar counters are non-negative ints. A3: every non-empty history's first-axis length equals `log_call_count`. Empty is allowed; it means that history was disabled by `SaveConfig` or dropped by `RunData.to_run_state`. Legacy reduced states whose `log_call_count` is zero fall back to `eval_count`. | Always |
|
|
369
386
|
| **Semantic (B)** | Cross-field consistency, skipped when `strict=False`: `best_loss` is finite iff a non-NaN loss was recorded (grad-only / hessian-only calls increment `eval_count` and append NaN to `loss_history` without updating `best_loss`, so `best_loss == inf` with `eval_count > 0` is legal); `best_loss == nanmin(loss_history)` within `1e-9`; `sum(eval_type_counts.values()) == log_call_count`; `improvement_count <= log_call_count`; `evals_since_improvement <= eval_count`. | `strict=True` only |
|
|
370
387
|
|
|
371
388
|
The on-disk `format_version` is not re-checked here. It is already enforced at deserialization (`RunMetadata.from_dict` and each serializer's `deserialize`), and a constructed `RunMetadata` always reports `FORMAT_VERSION` via `to_dict`, so a future-version metadata cannot exist by construction.
|
|
@@ -374,7 +391,7 @@ The on-disk `format_version` is not re-checked here. It is already enforced at d
|
|
|
374
391
|
|
|
375
392
|
These are deliberately out of scope for the current contract; see plan #2 for the rationale:
|
|
376
393
|
|
|
377
|
-
-
|
|
394
|
+
- Placeholder contents are not semantically validated. `loss_history` uses NaN when a derivative-only call has no returned loss; enabled standard or aux histories use `None` when that result is absent; disabled histories are empty.
|
|
378
395
|
- Batched-array internal shapes (expensive, fragile).
|
|
379
396
|
- `metadata.extra["problem_spec"]` contents. Validated at construction by `ProblemSpec.__post_init__` (type/version/params shape) and at reconstruction by `build_problem_from_spec` (registry lookup). The `RunState` validator itself does not re-check the spec.
|
|
380
397
|
- `SaveConfig` internal coherence (e.g. `grad=True` vs `batched_grad=False`). Belongs to `SaveConfig`.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dfbench"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.2"
|
|
8
8
|
description = "dfbench: A Black-Box Optimization Framework for JAX-Differentiable Gravitational Wave Detector Discovery"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11,<3.14"
|