STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
test_hybrid_seed_reproducible.py
Go to the documentation of this file.
1"""``layer1_random_seed`` must actually pin the hybrid search.
2
3Measured before this test existed: three Layer 1 runs of configs/ethalox_6500N.yaml, all
4with ``layer1_random_seed: 37``, returned three different injectors (included angle 89 / 87 /
583 deg, O/F 1.5023 / 1.5106 / 1.5144). The seed reached the 16-trial warm start and nothing
6after it: ``run_hybrid_optimization`` built its own ``np.random.default_rng()`` with no seed
7and called ``run_cma_core`` without ``seed=`` in Stage A, every block and every refresh, so
8CMA seeded itself from the clock. The legacy CMA path passes ``_cma_restart_seed``; the hybrid
9path -- the one every shipped config selects -- did not.
10
11The objective here is deliberately a plain function, not the engine: what is under test is
12that the SEARCH is a deterministic function of its seed, and nothing else.
13"""
14import os
15import sys
16
17import numpy as np
18import pytest
19
20sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
21
22from engine.optimizer.layers.layer1_static_optimization import run_hybrid_optimization # noqa: E402
23from engine.pipeline.config_schemas import HybridOptimizerConfig # noqa: E402
24
25
27 return float(sum(100.0 * (x[1:] - x[:-1] ** 2.0) ** 2.0 + (1 - x[:-1]) ** 2.0))
28
29
30def _run(seed, budget=600):
31 """Run the search and return what it *did*: every point it evaluated, in order.
32
33 The first version of this test compared the final best point of two seeds, and that
34 is a coin flip: at a 600-evaluation budget the search often never improves on the
35 start at all -- seed 7 returns the start point on every machine tried, seed 8 finds
36 something marginally better here and nothing at all on the CI runner -- so "the two
37 seeds landed in different places" passed or failed on luck. Whether the seed reaches
38 the sampler is visible in the *sequence of candidates*, which differs between seeds
39 on the very first iteration and is identical between equal seeds, whatever the
40 search then makes of them.
41 """
42 dim = 5
43 seen = []
44
45 def objective(x):
46 seen.append(np.array(x, dtype=float).round(12))
47 return _rosenbrock(np.asarray(x, dtype=float))
48
50 elite_k=20, block_method="corr_greedy", num_blocks=2, cycles=2,
51 per_block_budget_fraction=0.5, refresh_every_pass=True,
52 refresh_budget_fraction=0.1, refresh_sigma_scale=0.2,
53 )
54 best_x, best_f, evals = run_hybrid_optimization(
55 objective, [(-5.0, 5.0)] * dim, np.zeros(dim), cfg,
56 total_budget=budget, logger=None, seed=seed,
57 )
58 return np.array(seen), np.asarray(best_x, dtype=float), float(best_f), int(evals)
59
60
62 sa, xa, fa, ea = _run(7)
63 sb, xb, fb, eb = _run(7)
64 assert ea == eb, "same seed spent a different number of evaluations"
65 assert sa.shape == sb.shape, "same seed evaluated a different number of points"
66 np.testing.assert_array_equal(sa, sb, err_msg="same seed, different candidates")
67 assert fa == fb
68 np.testing.assert_array_equal(xa, xb)
69
70
72 # A different seed must sample different candidates; if it does not, the seed is not
73 # reaching the sampler at all and the previous test passed for the wrong reason.
74 # Judged on the candidates, not on where the search ended up -- see `_run`.
75 sa, _, _, ea = _run(7)
76 sb, _, _, eb = _run(8)
77 assert ea > 0 and eb > 0, f"the search spent no evaluations (evals {ea}, {eb})"
78 n = min(len(sa), len(sb))
79 # The start point is evaluated first under both seeds; everything after it is sampled.
80 assert not np.array_equal(sa[1:n], sb[1:n]), "seed had no effect on the candidates sampled"
81
82
84 # seed=None keeps the old behaviour (fresh entropy each run) and must not raise.
85 _, x, f, e = _run(None, budget=300)
86 assert np.isfinite(f) and e > 0
#define min(a, b)
Definition Arduino.h:42