From 05fdd94ac08b44255a01044c57c557394e450803 Mon Sep 17 00:00:00 2001 From: Nicholas Ehsan Roy Date: Wed, 7 Oct 2026 06:00:36 +0200 Subject: [PATCH 01/13] wip: guard the IQN least-squares against a non-finite matrix [skip ci] --- src/maddening/core/coupling/acceleration.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/maddening/core/coupling/acceleration.py b/src/maddening/core/coupling/acceleration.py index d66634a2..45ce74e6 100644 --- a/src/maddening/core/coupling/acceleration.py +++ b/src/maddening/core/coupling/acceleration.py @@ -2472,8 +2472,21 @@ def iqn_ils_update( # then rounded its secant step differently from the same group at # scale 1. An exact power of two leaves every product of a matrix in # range as it was. + # + # The factorisation is never handed a non-finite matrix: LAPACK's + # divide-and-conquer SVD does not return on some matrices that hold an + # ``inf`` (measured: a 12 x 8 matrix with one ``inf`` entry, float32 + # and float64), so a group whose iterate left float range before its + # cap never returned from its step. The matrix is replaced by zeros + # BEFORE the call (a select after it would still run the call: both + # sides of a ``where`` are computed), and the quasi-Newton step is + # then not taken (``is_valid`` below), which is what a non-finite + # ``c`` already meant. A finite matrix passes through unchanged. ls_pow2 = pow2_frame(V_masked, residual) - c = jnp.linalg.pinv(V_masked * ls_pow2, rtol=1e-6) @ (-(residual * ls_pow2)) + ls_matrix = V_masked * ls_pow2 + ls_finite = jnp.all(jnp.isfinite(ls_matrix)) + c = (jnp.linalg.pinv(jnp.where(ls_finite, ls_matrix, jnp.zeros_like(ls_matrix)), rtol=1e-6) + @ (-(residual * ls_pow2))) # QN correction correction = W_masked @ c + residual @@ -2504,7 +2517,8 @@ def iqn_ils_update( correction_norm = jnp.sqrt(jnp.sum((correction * pow2) ** 2)) residual_norm = jnp.sqrt(jnp.sum((residual * pow2) ** 2)) is_valid = ( - jnp.all(jnp.isfinite(x_qn)) + ls_finite + & jnp.all(jnp.isfinite(x_qn)) & (correction_norm < 1e6 * residual_norm) & (new_n_cols > 0) ) From 452212ece3b34afb575aaff3beddc89e0e1053eb Mon Sep 17 00:00:00 2001 From: Nicholas Ehsan Roy Date: Wed, 7 Oct 2026 06:11:53 +0200 Subject: [PATCH 02/13] wip: the gradient bound leaves out a probe the pass does not resolve [skip ci] --- src/maddening/core/coupling/_bounds.py | 24 ++++++++++++++++++- tests/property/coupling_reference.py | 24 +++++++++++++++++++ .../test_coupling_nonlinear_search.py | 17 ++++++++++++- 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/maddening/core/coupling/_bounds.py b/src/maddening/core/coupling/_bounds.py index 412823ce..f6206ab2 100644 --- a/src/maddening/core/coupling/_bounds.py +++ b/src/maddening/core/coupling/_bounds.py @@ -954,7 +954,29 @@ def g_derivative(row, ts, z): # A probe whose tangent could not be computed (non-finite) counts as # responding, so its NaN bound poisons the maximum; it used to drop # out silently where the tangent was NaN (``NaN > 0`` is False). - responds = jnp.logical_or(norm(t_s) > 0, jnp.logical_not(jnp.isfinite(norm(t_s)))) + # + # **And only a probe the pass resolves.** A relative error divides by + # the tangent's size, and a tangent that is rounding has none: where + # moving the constant by the probe's whole size (its own magnitude) + # moves one pass by no more than the pass's float resolution -- the + # floor the distance carries, in this norm -- the right-hand side is + # what cancellation left of terms the size of the fields, and so is + # the tangent solved from it. That is the same statement as a zero + # tangent (the fixed point does not respond to the probe) made at the + # resolution it can be made at, and such a probe is not in the worst + # either. It used to be: for the centre and the curve of a + # nonlinearity evaluated on its centre (a constant the fixed point + # does not respond to; right-hand sides of 2e-33 to 5e-18 beside ones + # of order one, float64) the bound read 1.09 for a relative error of + # 1.134 on a converged hub, usable. The absolute error for such a + # constant is of the size of its tangent (1.7e-34 there, beside + # gradients of 3.5e3). A right-hand side that is not finite still + # counts (its NaN bound poisons the maximum). + rhs_size = norm(s * w) + resolved_probe = jnp.logical_or(rhs_size > floor, jnp.logical_not(jnp.isfinite(rhs_size))) + responds = jnp.logical_and( + jnp.logical_or(norm(t_s) > 0, jnp.logical_not(jnp.isfinite(norm(t_s)))), + resolved_probe) worst = jnp.max(jnp.where(responds, per_probe, -jnp.inf)) worst = jnp.where(jnp.any(responds), worst, nan) diff --git a/tests/property/coupling_reference.py b/tests/property/coupling_reference.py index e42d0495..04740413 100644 --- a/tests/property/coupling_reference.py +++ b/tests/property/coupling_reference.py @@ -349,6 +349,30 @@ def moved(x_, theta_, pre, params): return np.asarray(self._jit_sens(jnp.asarray(x, jnp.float64), theta, self._pre, self._params)) + def pass_responses(self, x, norm: Norm) -> np.ndarray: + """How far one pass from iterate *x* moves, in *norm* at *x*'s + weights, when each scalar constant is moved by its own magnitude + (a zero entry by its constant's largest magnitude, or by 1 for an + all-zero constant): the size ``gradient_relative_error_bound`` + probes a constant at, and the quantity it compares with the + residual's float floor to say whether the pass resolves the + constant at all. One entry per column of :meth:`sensitivities`.""" + x = np.asarray(x, np.float64) + with x64(): + theta, _restore = ravel_pytree(self._constants_of(self._params)) + theta = np.abs(np.asarray(theta, np.float64)) + names = self.constant_names() + tops: dict = {} + for name, value in zip(names, theta): + leaf = name.rsplit("[", 1)[0] + tops[leaf] = max(tops.get(leaf, 0.0), float(value)) + scale = np.asarray([value if value > 0 else (tops[name.rsplit("[", 1)[0]] or 1.0) + for name, value in zip(names, theta)]) + moved = self.sensitivities(x) * scale[None, :] + weights, zero = norm.weights(x), np.zeros(self.size) + return np.asarray([norm.of_difference(moved[:, c], zero, weights) + for c in range(moved.shape[1])]) + def constant_names(self) -> list: """``node.leaf[i]`` / ``mapping:key.leaf[i]`` per column of :meth:`sensitivities`.""" with x64(): diff --git a/tests/property/test_coupling_nonlinear_search.py b/tests/property/test_coupling_nonlinear_search.py index 8dd9758c..b208a348 100644 --- a/tests/property/test_coupling_nonlinear_search.py +++ b/tests/property/test_coupling_nonlinear_search.py @@ -651,9 +651,19 @@ def observe(case: Case) -> dict: bound = (float(d["gradient_relative_error_bound"]) * allowed + 64.0 * case.eps + ref.gradient_resolution(x, raw)) names = ref.constant_names() + # CPL-093 is made for a constant the pass resolves: moving it by + # its own magnitude moves one pass by more than the residual's + # float floor. Held here to ``RESOLVED_MARGIN`` floors (the two + # sides are two computations of one comparison). + response = ref.pass_responses(x, raw) + resolved = [not out["floor_reported"] or r > RESOLVED_MARGIN * floor for r in response] + out["report"]["constants_resolved"] = (sum(resolved), len(resolved)) for score, vanishing in (("gradient", False), ("gradient_vanishing", True)): + mine = [does_not_move_the_fixed_point(n) is vanishing for n in names] + out["report"][f"{score}_constants"] = ( + sum(m and r for m, r in zip(mine, resolved)), sum(mine)) true, column = ref.gradient_error(x, fixed, raw, columns=[ - does_not_move_the_fixed_point(n) is vanishing for n in names]) + m and r for m, r in zip(mine, resolved)]) out[score] = math.inf if math.isnan(bound) else true / bound out["report"].update({f"{score}_error": true, f"{score}_constant": ( None if column is None else ref.constant_names()[column])}) @@ -679,6 +689,11 @@ def observe(case: Case) -> dict: #: a fixed point (measured: 0.93 to 1.00; a capped solve from a start a #: whole field away can return where Newton reaches none). USABLE_FLOOR = 0.25 +#: A constant is scored for the gradient bound where its pass response +#: (``PassReference.pass_responses``) is above this many floors: the +#: bound drops a probe at one floor, by its own float32 or float64 +#: arithmetic, and the reference measures the response in float64. +RESOLVED_MARGIN = 2.0 REFERENCED_FLOOR = 0.75 From 6216f774afe105a4b10f816f698e753d4fa7067a Mon Sep 17 00:00:00 2001 From: Nicholas Ehsan Roy Date: Wed, 7 Oct 2026 06:30:56 +0200 Subject: [PATCH 03/13] wip: SVD input guard at every site, regression tests, claims and guide [skip ci] --- .../coupling_algorithm_guide.md | 22 ++ docs/developer_guide/testing_standards.md | 2 +- docs/validation/coupling_claims.yaml | 15 +- src/maddening/core/coupling/_bounds.py | 14 +- src/maddening/core/coupling/acceleration.py | 57 ++-- src/maddening/core/graph_manager.py | 22 +- ...ing_iqn_returns_on_a_non_finite_iterate.py | 254 ++++++++++++++++++ .../test_coupling_nonlinear_search.py | 137 +++++----- 8 files changed, 427 insertions(+), 96 deletions(-) create mode 100644 tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py diff --git a/docs/developer_guide/coupling_algorithm_guide.md b/docs/developer_guide/coupling_algorithm_guide.md index e6e00760..945fe244 100644 --- a/docs/developer_guide/coupling_algorithm_guide.md +++ b/docs/developer_guide/coupling_algorithm_guide.md @@ -564,6 +564,28 @@ Arnoldi factor, which is the resolvent restricted to the Krylov space and read the bound 0.19x the true error on a ring whose secant falls outside it; and Newton-Kantorovich takes the full-operator resolvent norm. +**Which constants are in it.** A relative error divides by the tangent's +size, so the worst is taken over the probes that have one: a probe whose +tangent is exactly zero is left out (the fixed point does not respond to +it), and so is a probe the pass does not *resolve* — moving the constant +by the probe's whole size (its own magnitude) moves one pass from `x_k` +by no more than the floor the distance carries, `‖s · F_c ċ‖ ≤ floor` in +the bound's own norm. Its right-hand side is then what cancellation left +of terms the size of the fields, and so is the tangent solved from it. +The case that showed it: the centre `c` and the curve `s` of a +nonlinearity `φ(u; c, s)` with `φ(c) = c`, `φ′(c) = 1`, evaluated where +`u = c`. The fixed point does not respond to either, the returned iterate +does by the rounding it is away, and the relative error of that gradient +is of order one at any iterate (the bound read 1.09 for 1.134 on a +converged float64 hub, usable, with right-hand sides of 2e-33 to 5e-18 +for those probes beside ones of order one; without them it reads 5.3e-12 +for an error of 5.3e-12 over the gains). Where such a constant *is* +resolved (an iterate stopped well short of the fixed point) it is in the +bound, which then reads above one: the relative error of that gradient +is of order one, and the bound says so. A weak constant is left out by +the same rule: a gain whose whole value moves the pass by less than the +pass can resolve has a gradient no pass in that dtype can tell from zero. + Measured `bound / true` (jaxlib 0.11.0, float32), the fixed point's gradient from tight `ift` and `fori` arms that agree, every point a fresh graph stepped through `gm.step()` and stopped early by diff --git a/docs/developer_guide/testing_standards.md b/docs/developer_guide/testing_standards.md index d9d579d6..a84351aa 100644 --- a/docs/developer_guide/testing_standards.md +++ b/docs/developer_guide/testing_standards.md @@ -427,7 +427,7 @@ The coupling search above scores against a closed form, which exists only for li | gradient bound (CPL-093, CPL-095) | two scores: over the gains, biases and mapping weights (`gradient`), and over each nonlinearity's `c` and `s` (`gradient_vanishing`), which the fixed point does not respond to, so that the relative error is of order one at any other iterate | | floor (CPL-097, CPL-100) | the exact residual is the reference's | -Per push: one cell (`tri`, three members with one nonlinearity each, float32, five Jacobi passes), twenty derandomised examples a score, and two seed examples on which a number is within an eighth of its limit. Slow: 115 random examples a score on each of six blocks of seven cells (every structure, each nonlinearity, both dtypes, every configuration), not shrunk (a shrink is thousands of steps). An example that plain passes carry out of float range is not stepped on a cell with a quasi-Newton acceleration (see the pinned finding in the module). To add a nonlinearity, add a branch to `phi` with `phi(c) = c` and `phi'(c) = 1`; to add a structure, add it to `STRUCTURES` (single-rate: a sub-cycled member reads its input interpolated, and `c` would not be its input at the fixed point). +Per push: one cell (`tri`, three members with one nonlinearity each, float32, five Jacobi passes), twenty derandomised examples a score, and two seed examples on which a number is within an eighth of its limit. Slow: 115 random examples a score on each of six blocks of seven cells (every structure, each nonlinearity, both dtypes, every configuration), not shrunk (a shrink is thousands of steps). The gradient bound is scored twice, over the gains, biases and weights and over each nonlinearity's own constants (`gradient_vanishing`), and in both only over the constants the pass resolves (`PassReference.pass_responses` above `RESOLVED_MARGIN` floors: CPL-093's condition). To add a nonlinearity, add a branch to `phi` with `phi(c) = c` and `phi'(c) = 1`; to add a structure, add it to `STRUCTURES` (single-rate: a sub-cycled member reads its input interpolated, and `c` would not be its input at the fixed point). **The twins with the same interface reading** (`tests/property/geometry_graphs.py`, `tests/property/test_interface_reading_twins.py`). `convergence_norm="interface"` reads what each internal edge delivers. The node-inlined twin of a geometry edge moves the mapping into the *target*, so its edges deliver the raw source field and its interface norm is another norm. Two twins keep the reading: diff --git a/docs/validation/coupling_claims.yaml b/docs/validation/coupling_claims.yaml index 6c26c269..4b47ef30 100644 --- a/docs/validation/coupling_claims.yaml +++ b/docs/validation/coupling_claims.yaml @@ -1997,6 +1997,7 @@ claims: - tests/core/test_coupling_claims_graphs.py::test_unconverged_means_at_the_cap_or_not_finite - tests/core/test_coupling_non_finite_state.py::test_a_non_finite_field_no_edge_reads_is_still_a_non_finite_state - tests/core/test_coupling_sixteen_bit_norms_in_float32.py::test_a_sixteen_bit_residual_at_the_default_rtol_is_finite_and_held_in_float32 + - tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py::test_a_step_whose_iterate_leaves_float_range_under_iqn_returns status: verified domains: f32: tests/core/test_coupling_claims_graphs.py::test_unconverged_means_at_the_cap_or_not_finite @@ -3140,6 +3141,8 @@ claims: - tests/core/test_coupling_non_finite_state.py::test_strict_convergence_names_the_non_finite_state - tests/core/test_coupling_sixteen_bit_norms_in_float32.py::test_a_sixteen_bit_residual_at_the_default_rtol_is_finite_and_held_in_float32 - tests/core/test_coupling_sixteen_bit_norms_in_float32.py::test_strict_convergence_names_a_state_beyond_its_dtypes_range + - tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py::test_a_step_whose_iterate_leaves_float_range_under_iqn_returns + - tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py::test_the_secant_update_returns_on_every_non_finite_input status: verified domains: f32: tests/core/test_coupling_non_finite_state.py::test_a_non_finite_state_never_reads_as_converged @@ -3688,7 +3691,14 @@ claims: read 5.1e-6 for a true 3.0e-5 at the float floor: MADD-ANO-226, resolved); where the pass has no reverse mode and more than 64 state entries that norm is unavailable and the bound is inf unless the - right-hand side does not depend on the state. + right-hand side does not depend on the state. A constant the pass + resolves: moving it by its own magnitude moves one pass from x_k by + more than the residual's float floor, in the bound's norm, and its + tangent is not exactly zero. A constant below that (the centre or the + curve of a nonlinearity evaluated on its centre: the fixed point does + not respond to it, and its gradient at x_k is rounding) is not in the + bound, which says nothing of it; it read 1.09 for a relative error of + 1.134 with those probes in it (MADD-ANO-232, resolved). oracle: the fixed point's gradient from the float64 solve or from tight ift and fori arms that agree. tests: - tests/core/test_coupling_gradient_error_bound.py::test_the_gradient_bound_holds_across_an_early_exit_sweep @@ -3706,6 +3716,9 @@ claims: - tests/core/test_coupling_gradient_bound_far_from_the_fixed_point.py::test_a_usable_gradient_bound_holds_on_the_audit_pair_at_every_cap - tests/core/test_coupling_gradient_bound_far_from_the_fixed_point.py::test_far_from_its_fixed_point_the_gradient_bound_holds_or_is_withdrawn - tests/property/test_coupling_targeted_search.py::test_a_usable_gradient_bound_is_never_below_the_error_per_push + - tests/property/test_coupling_nonlinear_search.py::test_a_usable_gradient_bound_is_never_below_the_error_on_the_nonlinear_cell_per_push + - tests/property/test_coupling_nonlinear_search.py::test_a_usable_gradient_bound_covers_a_nonlinearity_s_own_constants_per_push + - tests/property/test_coupling_nonlinear_search.py::test_a_constant_the_pass_does_not_resolve_is_not_in_the_gradient_bound status: verified notes: >- 16bit domain failing on d2429a6: jax.grad and jax.jvp through a bfloat16 diff --git a/src/maddening/core/coupling/_bounds.py b/src/maddening/core/coupling/_bounds.py index f6206ab2..e937121d 100644 --- a/src/maddening/core/coupling/_bounds.py +++ b/src/maddening/core/coupling/_bounds.py @@ -643,10 +643,12 @@ def _full_resolvent_norm_and_rows(U, M, make_transpose): the directions ``J`` reads at no further reverse-mode cost. ``(None, None)`` without a transpose. """ + from maddening.core.coupling.acceleration import _spectral_norm # noqa: PLC0415 + n, k = U.shape eye_k = jnp.eye(k, dtype=M.dtype) if n <= k: - return jnp.linalg.norm(jnp.linalg.inv(eye_k - M), ord=2), jnp.eye(n, dtype=M.dtype) + return _spectral_norm(jnp.linalg.inv(eye_k - M)), jnp.eye(n, dtype=M.dtype) matvec_t = make_transpose() if matvec_t is None: return None, None @@ -654,7 +656,7 @@ def _full_resolvent_norm_and_rows(U, M, make_transpose): P, _ = jnp.linalg.qr(jnp.concatenate([U, B.T], axis=1)) T = jnp.eye(P.shape[1], dtype=M.dtype) + (P.T @ U) @ jnp.linalg.solve(eye_k - M, B @ P) R, _ = jnp.linalg.qr(B.T) - return jnp.maximum(jnp.linalg.norm(T, ord=2), jnp.ones((), M.dtype)), R + return jnp.maximum(_spectral_norm(T), jnp.ones((), M.dtype)), R def _kantorovich_root_and_miss(step, h): @@ -678,6 +680,7 @@ def _gradient_error_bound_body(step_pure, probed, x_sg, consts_sg, d, rho, arnoldi_residual, amplification, res): """The arithmetic of :func:`_gradient_error_bound_at`, on stopped inputs.""" from maddening.core.coupling.acceleration import ( # noqa: PLC0415 + _spectral_norm, ift_gradient_error_bound, jacobian_range_basis, resolvent_apply, @@ -928,7 +931,10 @@ def g_derivative(row, ts, z): dG = jax.vmap( lambda row, ts: jax.vmap(lambda z: g_derivative(row, ts, z))(rows_g.T))( jnp.arange(n_rows), t_s) - any_dir = jnp.linalg.norm(live[None, None, :] * dG, ord=2, axis=(-2, -1)) + # A derivative that is not finite bounds nothing: ``inf``, so the + # probe's bound is (a NaN here compared False below and the term + # was dropped). + any_dir = _spectral_norm(live[None, None, :] * dG, unbounded=jnp.inf) # The undirected distance: the floor through the resolvent (the larger # of the Krylov factor the distance itself uses and the full norm), # or the whole distance at an unresolved iterate. @@ -1048,7 +1054,7 @@ def jac_at(xx, z): JR = jax.vmap(lambda xx: jax.vmap(lambda z: jac_at(xx, z))(rows.T))(points) JR = jax.lax.optimization_barrier(JR).astype(dtype) change = live * _framed_difference(JR[1], JR[0], s / lift) - op_change = jnp.linalg.norm(live * jax.vmap(resolve)(change), ord=2) + op_change = _spectral_norm(live * jax.vmap(resolve)(change)) numerator = jnp.maximum(beta * jac_change, op_change * step) h = jnp.where( step > 0, numerator / jnp.where(step > 0, step, 1.0), 0.0, diff --git a/src/maddening/core/coupling/acceleration.py b/src/maddening/core/coupling/acceleration.py index 45ce74e6..66faf8af 100644 --- a/src/maddening/core/coupling/acceleration.py +++ b/src/maddening/core/coupling/acceleration.py @@ -973,6 +973,33 @@ def body(j, carry): return jnp.where(alive, jnp.exp(log_rho), jnp.zeros_like(log_rho)) +def _lapack_input(A): + """``(A, ok)``: *A*, or zeros where an SVD must not be handed it. + + LAPACK's SVD drivers do not return on some matrices that hold an + ``inf``, or whose entries' squares leave the float range (measured on + CPU, jaxlib 0.11.0, float32 and float64, with a wall-clock limit: + ``jnp.linalg.svd`` and ``pinv`` of 4 x 4 to 16 x 16 matrices with one + ``inf`` entry or an ``inf`` column, and of one with a row and a column + at ``finfo.max``; a NaN beside the ``inf`` returns). Under ``jit`` + both sides of a ``where`` are computed, so a select *after* the + factorisation still runs it: the matrix is replaced *before* the call. + ``ok`` is that the sum of the squares is finite, per matrix (the last + two axes); a matrix that passes is returned unchanged, bit for bit. + """ + A = jnp.asarray(A) + ok = jnp.isfinite(jnp.sum(A * A, axis=(-2, -1))) + return jnp.where(ok[..., None, None], A, jnp.zeros_like(A)), ok + + +def _spectral_norm(A, unbounded=jnp.nan): + """``||A||_2`` per matrix (the last two axes), *unbounded* where + :func:`_lapack_input` withholds the matrix (NaN: what the SVD of a + non-finite matrix returns where it returns).""" + safe, ok = _lapack_input(A) + return jnp.where(ok, jnp.linalg.norm(safe, ord=2, axis=(-2, -1)), unbounded) + + #: Backends on which ``jax.numpy.linalg.eigvals`` of a non-symmetric #: matrix lowers (the supported JAX range implements it on CPU and, by #: calling LAPACK on the host, on GPU). @@ -1143,8 +1170,12 @@ def _compressed_spectrum(H, coefficients, column, extended): k = H.shape[1] Hk = H[:k, :k] rho = _spectral_radius(Hk) - sigma = jnp.linalg.svd(jnp.eye(k, dtype=Hk.dtype) - Hk, compute_uv=False) - sigma_min = sigma[-1] + # Never an SVD of a matrix that is not finite (``_lapack_input``): its + # smallest singular value then reads NaN, as it did where the driver + # returned, and the amplification ``inf``. + shifted, shifted_ok = _lapack_input(jnp.eye(k, dtype=Hk.dtype) - Hk) + sigma = jnp.linalg.svd(shifted, compute_uv=False) + sigma_min = jnp.where(shifted_ok, sigma[-1], jnp.nan) invertible = sigma_min > 0 amplification = jnp.where( invertible, 1.0 / jnp.where(invertible, sigma_min, 1.0), jnp.inf, @@ -2473,20 +2504,16 @@ def iqn_ils_update( # scale 1. An exact power of two leaves every product of a matrix in # range as it was. # - # The factorisation is never handed a non-finite matrix: LAPACK's - # divide-and-conquer SVD does not return on some matrices that hold an - # ``inf`` (measured: a 12 x 8 matrix with one ``inf`` entry, float32 - # and float64), so a group whose iterate left float range before its - # cap never returned from its step. The matrix is replaced by zeros - # BEFORE the call (a select after it would still run the call: both - # sides of a ``where`` are computed), and the quasi-Newton step is - # then not taken (``is_valid`` below), which is what a non-finite - # ``c`` already meant. A finite matrix passes through unchanged. + # The factorisation is never handed a matrix that is not finite + # (``_lapack_input``: LAPACK's SVD does not return on some that hold + # an ``inf``, so a group whose iterate left float range before its cap + # never returned from its step). It is replaced by zeros before the + # call and the quasi-Newton step is then not taken (``is_valid`` + # below), which is what a non-finite ``c`` already meant. A finite + # matrix passes through unchanged. ls_pow2 = pow2_frame(V_masked, residual) - ls_matrix = V_masked * ls_pow2 - ls_finite = jnp.all(jnp.isfinite(ls_matrix)) - c = (jnp.linalg.pinv(jnp.where(ls_finite, ls_matrix, jnp.zeros_like(ls_matrix)), rtol=1e-6) - @ (-(residual * ls_pow2))) + ls_matrix, ls_finite = _lapack_input(V_masked * ls_pow2) + c = jnp.linalg.pinv(ls_matrix, rtol=1e-6) @ (-(residual * ls_pow2)) # QN correction correction = W_masked @ c + residual diff --git a/src/maddening/core/graph_manager.py b/src/maddening/core/graph_manager.py index 33d19c54..0df14c28 100644 --- a/src/maddening/core/graph_manager.py +++ b/src/maddening/core/graph_manager.py @@ -4411,7 +4411,27 @@ def coupling_diagnostics(self) -> dict[str, dict]: fixed point responds to no constant, where a constant's tangent through the group is not finite (that constant has no gradient to bound) and where the returned state is - not finite. Costs + not finite. **Only for a constant the pass resolves.** A + relative error is a statement about a gradient that has a + size: a constant is in the bound where moving it by its + own magnitude (by its array's largest magnitude where the + entry is zero, by 1 where the array is) moves one pass + from ``x_k`` by more than the pass's float resolution, the + floor ``"spectral_error_bound"`` adds to the residual, + measured as that bound's distance is; and where its + tangent through the group is not exactly zero. A constant + below that has a gradient that is what rounding left of + terms the size of the fields, its relative error is of + order one or undefined, and the bound says nothing of it + (it is not the worst probe): the centre or the curve of a + nonlinearity evaluated on its centre, a term multiplied by + a field that has converged to zero. The gradient with + respect to such a constant is small beside the others in + the same units (measured: 1.5e-34 for an error of 1.7e-34 + where the resolved constants' are up to 3.5e3, float64); + check a constant with one Jacobian-vector product of the + pass, or treat a gradient many orders below its + neighbours' as zero. Costs ``11 + 4 k + 5 n_p + 2 k n_p`` Jacobian-vector products per group per step beside the spectral bound's eight (plus one linearisation and ``k`` reverse-mode products where the diff --git a/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py b/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py new file mode 100644 index 00000000..6e553cca --- /dev/null +++ b/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py @@ -0,0 +1,254 @@ +"""A coupling group under IQN returns from its step when its iterate leaves float range. + +``acceleration="iqn-ils"`` and ``"iqn-imvj"`` solve a least-squares +problem on the secant columns each pass, through an SVD. LAPACK's SVD +does not return on some matrices that hold an ``inf``, and a group whose +iterate overflowed before ``max_iterations`` handed it one: ``step()`` +never returned (no return in 240 s where a converging step of the same +compiled graph takes 0.05 s), in every release that has IQN. ``"none"`` +and ``"aitken"`` ran to the cap and reported the state as not finite. + +Every call that could hang runs in a thread of its own and is given +:data:`LIMIT` seconds, so a regression fails this file and does not stop +the run. The fixture's first entry is ``exp`` of itself each pass (no +fixed point; it leaves float range within a few passes of any start) +beside three entries that contract, so the secant column of the pass +that overflows holds one ``inf`` and finite entries: the matrix the SVD +does not return on (an all-``inf`` column, or a NaN beside the ``inf``, +returns). +""" + +from __future__ import annotations + +import math +import threading + +import jax +import jax.numpy as jnp +import numpy as np +import pytest + +from maddening.core.coupling import acceleration +from maddening.core.graph_manager import GraphManager +from maddening.core.node import BoundaryInputSpec, SimulationNode + +#: Seconds a call is given (a step that returns takes well under one). +LIMIT = 30.0 +IQN = ("iqn-ils", "iqn-imvj") +DTYPES = ("float32", "float64") + + +def within_the_limit(fn): + """``fn()`` from a daemon thread, or a failure after :data:`LIMIT` seconds.""" + box: dict = {} + + def run(): + try: + box["value"] = fn() + except BaseException as exc: # noqa: BLE001 - re-raised in the caller's thread + box["error"] = exc + + thread = threading.Thread(target=run, daemon=True) + thread.start() + thread.join(LIMIT) + assert not thread.is_alive(), f"no return in {LIMIT:.0f} s" + if "error" in box: + raise box["error"] + return box["value"] + + +class _Relay(SimulationNode): + """``x <- (exp(u_0), u_1 / 2 + 1, ...)``, or ``x <- u``.""" + + def __init__(self, name, grows, dtype): + super().__init__(name=name, timestep=1.0) + self._grows, self._dtype = grows, jnp.dtype(dtype) + + def initial_state(self): + return {"x": jnp.asarray(_START, self._dtype)} + + def state_fields(self): + return ["x"] + + def boundary_input_spec(self): + return {"u": BoundaryInputSpec(shape=(len(_START),), dtype=self._dtype, + description="u")} + + def update(self, state, boundary_inputs, dt, *, params=None): + u = boundary_inputs["u"] + if self._grows: + u = jnp.concatenate([jnp.exp(u[:1]), 0.5 * u[1:] + 1.0]) + return {"x": u.astype(self._dtype)} + + +_START = (3.0, -5.0, 7.0, 2.0) + + +def _graph(acceleration_, dtype, **group): + gm = GraphManager() + gm.add_node(_Relay("a", True, dtype)) + gm.add_node(_Relay("b", False, dtype)) + gm.add_edge(source="b", target="a", source_field="x", target_field="u") + gm.add_edge(source="a", target="b", source_field="x", target_field="u") + kw = dict(max_iterations=40, tolerance=1e-6, acceleration=acceleration_, diagnostics=False) + kw.update(group) + gm.add_coupling_group(["a", "b"], **kw) + gm.compile() + return gm + + +def _step_reports_a_state_that_is_not_finite(acceleration_, dtype, **group): + x64 = jax.config.jax_enable_x64 + jax.config.update("jax_enable_x64", dtype == "float64") + try: + gm = _graph(acceleration_, dtype, **group) + within_the_limit(gm.step) # the compile is in the limit too + (report,) = gm.coupling_diagnostics().values() + state = np.asarray(gm.get_node_state("a")["x"]) + finally: + jax.config.update("jax_enable_x64", x64) + assert not np.all(np.isfinite(state)), f"premise: the iterate stayed finite ({state})" + assert report["converged"] is False, report + assert report["residual"] == math.inf, report + return report + + +@pytest.mark.parametrize("dtype", DTYPES) +@pytest.mark.parametrize("acceleration_", IQN) +def test_a_step_whose_iterate_leaves_float_range_under_iqn_returns(acceleration_, dtype): + """CPL-053, CPL-084: the step returns, ``converged`` False and + ``residual`` ``inf``, having run to its cap as the unaccelerated group + does.""" + report = _step_reports_a_state_that_is_not_finite(acceleration_, dtype) + assert report["iterations"] == 40, report + + +# Slow: four more compiles of the pair, two of them of an unrolled loop. +# Per push: tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py::test_a_step_whose_iterate_leaves_float_range_under_iqn_returns +@pytest.mark.slow +@pytest.mark.parametrize("group", [ + dict(solver="fori", max_iterations=24), + dict(diagnostics=True), + dict(convergence_norm="l2"), + dict(convergence_norm="interface"), + dict(iteration_mode="jacobi"), +], ids=["fori", "diagnostics", "l2", "interface", "jacobi"]) +@pytest.mark.parametrize("acceleration_", IQN + ("aitken", "none")) +def test_the_step_returns_under_every_solver_norm_and_schedule(acceleration_, group): + """The same step under the unrolled solver, with the diagnostics (whose + analysis takes singular values at the returned state), under each norm + and both schedules; and the accelerations that always + returned, beside it.""" + report = _step_reports_a_state_that_is_not_finite(acceleration_, "float64", **group) + assert report["iterations"] == group.get("max_iterations", 40), report + + +def _poisoned(kind, n, cols, dtype, rng): + """``(V, W, residual, previous residual)`` with *kind* written into them.""" + big = float(np.finfo(dtype).max) + V = rng.standard_normal((n, cols)).astype(dtype) + W = rng.standard_normal((n, cols)).astype(dtype) + r = rng.standard_normal(n).astype(dtype) + r_prev = rng.standard_normal(n).astype(dtype) + if kind == "an inf in a stored column": + V[min(3, n - 1), 1] = np.inf + elif kind == "a -inf in a stored column": + V[0, cols - 1] = -np.inf + elif kind == "an inf column": + V[:, 1] = np.inf + elif kind == "every entry inf": + V[:] = np.inf + elif kind == "a NaN in a stored column": + V[0, 1] = np.nan + elif kind == "an inf and a NaN": + V[0, 1], V[1, 2] = np.inf, np.nan + elif kind == "an inf residual": # the new column is inf + r[0] = np.inf + elif kind == "a NaN residual": + r[1] = np.nan + elif kind == "a previous residual at the largest float": # the new column overflows + r_prev[:] = -big + r[:] = big + elif kind == "columns at the largest float": + V[:, 1], V[0, :] = big, -big + else: + assert kind == "finite", kind + return V, W, r, r_prev + + +_POISONS = ("an inf in a stored column", "a -inf in a stored column", "an inf column", + "every entry inf", "a NaN in a stored column", "an inf and a NaN", + "an inf residual", "a NaN residual", "a previous residual at the largest float", + "columns at the largest float", "finite") + + +@pytest.mark.parametrize("dtype", DTYPES) +def test_the_secant_update_returns_on_every_non_finite_input(dtype): + """``iqn_ils_update`` itself, compiled, on secant matrices and + residuals holding each kind of value a diverging iterate leaves in + them, at three sizes: it returns, and a matrix that is not finite + means the quasi-Newton step is not taken (the Aitken fallback's + iterate comes back).""" + x64 = jax.config.jax_enable_x64 + jax.config.update("jax_enable_x64", dtype == "float64") + try: + rng = np.random.default_rng(0) + for n, cols in ((4, 4), (12, 8), (16, 16)): + update = jax.jit(lambda *a: acceleration.iqn_ils_update(*a, have_prev=True)) + for kind in _POISONS: + V, W, r, r_prev = _poisoned(kind, n, cols, np.dtype(dtype), rng) + x_old = rng.standard_normal(n).astype(dtype) + with np.errstate(all="ignore"): + x_raw = (x_old + r).astype(dtype) + args = (jnp.asarray(x_raw), jnp.asarray(x_old), jnp.asarray(r_prev), + jnp.asarray(x_old), jnp.asarray(V), jnp.asarray(W), jnp.int32(cols - 1), + jnp.asarray(1.0, dtype), jnp.zeros(n, dtype)) + out = within_the_limit(lambda args=args: jax.block_until_ready(update(*args))) + x_new, new_V = np.asarray(out[0]), np.asarray(out[1]) + if kind == "finite": + assert np.all(np.isfinite(x_new)), (kind, n, cols) + elif not np.all(np.isfinite(new_V)): + aitken = np.asarray(acceleration.aitken_relaxation( + args[1], args[0], args[8], args[7])[0]) + np.testing.assert_array_equal(x_new, aitken, err_msg=f"{kind}, {n} x {cols}") + finally: + jax.config.update("jax_enable_x64", x64) + + +@pytest.mark.parametrize("dtype", DTYPES) +def test_no_svd_of_the_coupling_analysis_is_handed_a_matrix_that_is_not_finite(dtype): + """``_lapack_input`` withholds exactly the matrices whose squares do + not sum to a finite number, and returns every other unchanged; + ``_spectral_norm`` of a withheld matrix is NaN (or what the caller + asks for) and of any other the SVD's.""" + x64 = jax.config.jax_enable_x64 + jax.config.update("jax_enable_x64", dtype == "float64") + try: + rng = np.random.default_rng(1) + big = float(np.finfo(dtype).max) + norm = jax.jit(acceleration._spectral_norm) # noqa: SLF001 + norm_inf = jax.jit(lambda A: acceleration._spectral_norm(A, unbounded=jnp.inf)) # noqa: SLF001 + for n, m in ((4, 4), (12, 8), (16, 16)): + A = rng.standard_normal((n, m)).astype(dtype) + safe, ok = acceleration._lapack_input(jnp.asarray(A)) # noqa: SLF001 + assert bool(ok) + np.testing.assert_array_equal(np.asarray(safe), A) + np.testing.assert_array_equal(np.asarray(norm(jnp.asarray(A))), + np.asarray(jnp.linalg.norm(jnp.asarray(A), ord=2))) + for poison in (np.inf, -np.inf, np.nan, big): + B = A.copy() + B[min(3, n - 1), 0] = poison + if poison == big: + B[:, 0], B[0, :] = big, -big + safe, ok = acceleration._lapack_input(jnp.asarray(B)) # noqa: SLF001 + assert not bool(ok), (poison, n, m) + assert not np.any(np.asarray(safe)), (poison, n, m) + assert math.isnan(float(within_the_limit(lambda B=B: norm(jnp.asarray(B))))) + assert float(within_the_limit(lambda B=B: norm_inf(jnp.asarray(B)))) == math.inf + # Per matrix of a batch. + batch = rng.standard_normal((3, 4, 4)).astype(dtype) + batch[1, 2, 2] = np.inf + out = np.asarray(within_the_limit(lambda: norm(jnp.asarray(batch)))) + assert np.isfinite(out[0]) and np.isnan(out[1]) and np.isfinite(out[2]), out + finally: + jax.config.update("jax_enable_x64", x64) diff --git a/tests/property/test_coupling_nonlinear_search.py b/tests/property/test_coupling_nonlinear_search.py index b208a348..68ae0ae8 100644 --- a/tests/property/test_coupling_nonlinear_search.py +++ b/tests/property/test_coupling_nonlinear_search.py @@ -549,30 +549,6 @@ def does_not_move_the_fixed_point(constant: str) -> bool: return leaf[0] in "cs" and leaf[1].isdigit() -def leaves_float_range(cell: Cell, values: dict, ref: cr.PassReference) -> bool: - """Whether plain passes from the drawn start leave *cell*'s float - range before its cap, on a cell with a quasi-Newton acceleration. - - Such an example is not stepped: under ``"iqn-ils"`` and ``"iqn-imvj"`` - a group whose iterate becomes non-finite before the cap never returns - from ``step()`` (the finding pinned by - ``test_a_group_that_leaves_float_range_under_iqn_still_returns``), and - a search cannot score a call that does not return. Every other - acceleration returns a non-finite state, which is scored as unusable. - *ref* is bound to *values*. - """ - if not str(cell.knobs.get("acceleration", "none")).startswith("iqn"): - return False - x = ref.flat({m: {"x": values["nodes"][m]["x0"]} for m in cell.topo.names}) - limit = math.sqrt(float(np.finfo(cell.dtype).max)) - for _ in range(min(cell.cap, 60)): - with np.errstate(all="ignore"): - x = ref.apply(x) - if not np.all(np.isfinite(x)) or float(np.max(np.abs(x))) > limit: - return True - return False - - @functools.lru_cache(maxsize=4096) def observe(case: Case) -> dict: """One step of *case* and the scores of what it reported.""" @@ -581,18 +557,12 @@ def observe(case: Case) -> dict: values = values_of(case) built, twin, ref = _built(case.cell) ref = bound_reference(ref, values, twin) - if leaves_float_range(cell, values, ref): - # Not stepped (see ``leaves_float_range``): nothing is scored. - return dict(bound=0.0, radius=0.0, radius_strict=0.0, gradient=0.0, gradient_vanishing=0.0, - floor=0.0, - spectral_usable=False, gradient_usable=False, floor_reported=False, - referenced=False, near=False, stepped=False, finite=False, report={}) with precision(cell.dtype == "float64"): step = run_once(built, values) d = dict(step.reports[0]) floor = linear._reported_floor(built.gm, topo.group_key(0), step.metas[0], d) # noqa: SLF001 out = dict(bound=0.0, radius=0.0, radius_strict=0.0, gradient=0.0, gradient_vanishing=0.0, - floor=0.0, spectral_usable=bool(d["spectral_usable"]), + floor=0.0, vanishing_scored=False, spectral_usable=bool(d["spectral_usable"]), gradient_usable=bool(d["gradient_bound_usable"]), floor_reported=math.isfinite(floor), referenced=False, near=False, stepped=True, finite=False, @@ -664,6 +634,8 @@ def observe(case: Case) -> dict: sum(m and r for m, r in zip(mine, resolved)), sum(mine)) true, column = ref.gradient_error(x, fixed, raw, columns=[ m and r for m, r in zip(mine, resolved)]) + if vanishing: + out["vanishing_scored"] = column is not None out[score] = math.inf if math.isnan(bound) else true / bound out["report"].update({f"{score}_error": true, f"{score}_constant": ( None if column is None else ref.constant_names()[column])}) @@ -681,7 +653,10 @@ def observe(case: Case) -> dict: THRESHOLD = {**linear.THRESHOLD, "gradient_vanishing": linear.THRESHOLD["gradient"]} FLAG = {**linear.FLAG, "gradient_vanishing": "gradient_usable"} -SEARCHES = linear.SEARCHES +#: The linear search's four and the gradient bound over a nonlinearity's +#: own constants (its centre and its curve), which the fixed point does +#: not respond to: scored wherever the pass resolves one. +SEARCHES = linear.SEARCHES + ("gradient_vanishing",) #: The least fraction of a hunt's examples with the flag set (measured: #: 0.64 to 1.00 by block and score; the linear search holds a half, and a #: hunt here climbs towards starts that diverge), and the least fraction of @@ -727,6 +702,7 @@ def score(case: Case): referenced=sum(s["referenced"] for s in seen) / count, near=sum(s["near"] for s in seen) / count, stepped=sum(s["stepped"] for s in seen) / count, + vanishing_scored=sum(s["vanishing_scored"] for s in seen) / count, finite=sum(s["finite"] for s in seen) / count) @@ -911,6 +887,17 @@ def test_a_usable_gradient_bound_is_never_below_the_error_on_the_nonlinear_cell_ _held("gradient", fractions) +def test_a_usable_gradient_bound_covers_a_nonlinearity_s_own_constants_per_push(): + """A nonlinearity's centre and curve do not move the fixed point, so + the relative error of the gradient with respect to one is of order one + at any other iterate: the bound reads above it wherever the pass + resolves the constant, and leaves the constant out where it does not + (premise: some examples have such a constant scored).""" + _report, fractions = search("gradient_vanishing") + _held("gradient_vanishing", fractions) + assert fractions["vanishing_scored"] > 0, fractions + + def test_the_floor_covers_what_the_reported_residual_misses_on_the_nonlinear_cell_per_push(): _report, fractions = search("floor") _held("floor", fractions) @@ -970,46 +957,52 @@ def dropped(z): # What the search found # --------------------------------------------------------------------------- -#: The findings of the hunt on this tree, each an example as drawn (the -#: hunt does not shrink). Strict: a fix turns each green. ``EDGE``: at -#: the edge of what the claim is made on, as the reason says; a ``CORE`` -#: finding would be inside it (the hunt found none). -KNOWN = { +#: The examples the hunt reached on the tree before the gradient bound +#: left out a probe the pass does not resolve, as drawn (the hunt does not +#: shrink). On each the nonlinearity's own constants (a centre ``c``, a +#: curve ``s``) are below the pass's float floor: the fixed point does not +#: respond to one, and the returned iterate, a rounding away, by a +#: rounding. ``(case, the bound it read, the relative error it stood +#: beside)``. +UNRESOLVED = { # A two-member float32 ring with saturating gains, started on its - # fixed point: one pass, residual 0, precision_limited. The curve - # ``s`` of a nonlinearity moves the fixed point by nothing (the - # derivative with respect to it is zero there) and the returned - # iterate, a float32 rounding away, by a little: relative error 2.7, - # ``gradient_relative_error_bound`` 1.4e-6 with the flag set. - "CPL-093-EDGE-a-constant-the-fixed-point-does-not-respond-to-at-a-stalled-start": ( - Case(1, linear.Case(0, 0, 0.05, False, 1.0, 0.0, 1.0, 0, 0.0, 0), 1.0), - "gradient_vanishing", - "FINDING (EDGE, CPL-093): for a constant whose derivative is zero at the fixed point " - "the relative gradient error is of order one at any other iterate; at a start stalled " - "on its float floor the usable bound reads 1.4e-6"), - # The same constant on a float64 hub converged in four passes from a - # start a whole field away: the bound reads 1.09 for a relative error - # of 1.134 (4% short). - "CPL-093-EDGE-a-constant-the-fixed-point-does-not-respond-to-four-percent-short": ( - Case(26, linear.Case(0, 2619, 0.05, False, 1.0, 0.0, 1.0, 3, 1.0, 3), 10.0), - "gradient_vanishing", - "FINDING (EDGE, CPL-093): for a constant whose derivative is zero at the fixed point " - "the usable bound reads 1.09 for a relative error of 1.13"), + # fixed point: one pass, residual 0, precision_limited. The float32 + # tangents of the centres and curves are exactly zero (never in the + # bound); in float64 at the returned iterate the curve's is 6e-26 + # beside gradients of order one, a relative error of 2.7. + "a-ring-stalled-on-its-start": ( + Case(1, linear.Case(0, 0, 0.05, False, 1.0, 0.0, 1.0, 0, 0.0, 0), 1.0), 1.4e-6, 2.7), + # A float64 hub converged in four passes from a start a whole field + # away: right-hand sides of 2e-33 to 5e-18 for the centres and curves + # beside ones of order one. The bound read 1.09 (their probes') for a + # relative error of 1.134 on one of them; without them it is the + # gains', 5.3e-12. + "a-converged-hub": ( + Case(26, linear.Case(0, 2619, 0.05, False, 1.0, 0.0, 1.0, 3, 1.0, 3), 10.0), 1.09, 1.134), } -# Slow: each pin compiles its cell (a graph with diagnostics and a twin). -# Per push: tests/property/test_coupling_nonlinear_search.py::test_a_usable_gradient_bound_is_never_below_the_error_on_the_nonlinear_cell_per_push +# Slow: each example compiles its cell (a graph with diagnostics and a twin). +# Per push: tests/property/test_coupling_nonlinear_search.py::test_a_usable_gradient_bound_covers_a_nonlinearity_s_own_constants_per_push @pytest.mark.slow -@pytest.mark.parametrize("case,score", [ - pytest.param(case, score, marks=pytest.mark.xfail(strict=True, reason=reason)) - for case, score, reason in KNOWN.values()], ids=list(KNOWN)) -def test_a_known_defect_the_nonlinear_search_reached_is_fixed(case, score): +@pytest.mark.parametrize("name", list(UNRESOLVED)) +def test_a_constant_the_pass_does_not_resolve_is_not_in_the_gradient_bound(name): + """CPL-093 is a relative bound for a constant the pass resolves. On + these examples none of the nonlinearity's own constants is, and the + usable bound is the other constants': far below one, and not below + their error.""" + case, _read, _beside = UNRESOLVED[name] seen = observe(case) - assert seen["stepped"] and seen["referenced"], seen - assert seen[FLAG[score]], f"the flag is no longer set: {seen['report']}" - assert seen[score] <= THRESHOLD[score], ( - f"{score} is {seen[score]!r}, over {THRESHOLD[score]!r}: {seen['report']}") + report = seen["report"] + assert seen["stepped"] and seen["referenced"] and seen["gradient_usable"], seen + resolved, total = report["gradient_vanishing_constants"] + assert total > 0 and resolved == 0, ( + f"premise: {resolved} of the {total} constants of a nonlinearity are resolved: {report}") + scored, others = report["gradient_constants"] + assert scored == others > 0, report + assert seen["gradient"] <= THRESHOLD["gradient"], report + # units: a relative error; the hub read 1.09 with those probes in it. + assert report["gradient_relative_error_bound"] < 1e-5, report #: The example the hunt stopped on: the fan-out hub with products of two @@ -1077,14 +1070,10 @@ def test_a_group_that_leaves_float_range_without_a_quasi_newton_acceleration_ret # Per push: tests/property/test_coupling_nonlinear_search.py::test_a_usable_error_bound_reaches_the_distance_on_the_nonlinear_cell_per_push @pytest.mark.slow @pytest.mark.parametrize("acceleration", ["iqn-ils", "iqn-imvj"]) -@pytest.mark.xfail(strict=True, reason=( - "FINDING (EDGE, CPL-053/CPL-084): a group under acceleration='iqn-ils' or 'iqn-imvj' whose " - "iterate becomes non-finite before max_iterations never returns from step() (measured: no " - "return in 240 s; 0.05 s for a step of the same compiled graph that converges)")) def test_a_group_that_leaves_float_range_under_iqn_still_returns(acceleration): """``converged`` False "means ... the group hit max_iterations" (CPL-053) and ``residual`` is "inf on a non-finite state" (CPL-084): - both say the step returns. With diagnostics on or off, under the l2 - norm as under the mixed one; at a cap of 12, before the iterate is - non-finite, it returns.""" - assert _steps_in_a_subprocess(acceleration, 30.0).startswith("RETURNED") + both say the step returns, and it runs to its cap as the unaccelerated + group does. It did not return (no return in 240 s): the secant + least-squares handed LAPACK's SVD a matrix holding an ``inf``.""" + assert _steps_in_a_subprocess(acceleration, 30.0) == "RETURNED 120 False" From c0263d4200d3972abc55b3bd046241171bcf7e59 Mon Sep 17 00:00:00 2001 From: Nicholas Ehsan Roy Date: Wed, 7 Oct 2026 06:41:04 +0200 Subject: [PATCH 04/13] wip: additive probes stay in the bound; docs [skip ci] --- .../coupling_algorithm_guide.md | 22 ++++++++++--- docs/validation/coupling_claims.yaml | 15 +++++---- src/maddening/core/coupling/_bounds.py | 33 +++++++++++-------- src/maddening/core/graph_manager.py | 24 ++++++++------ tests/property/coupling_reference.py | 11 +++++++ .../test_coupling_nonlinear_search.py | 8 +++-- 6 files changed, 75 insertions(+), 38 deletions(-) diff --git a/docs/developer_guide/coupling_algorithm_guide.md b/docs/developer_guide/coupling_algorithm_guide.md index 945fe244..305f801f 100644 --- a/docs/developer_guide/coupling_algorithm_guide.md +++ b/docs/developer_guide/coupling_algorithm_guide.md @@ -570,8 +570,14 @@ tangent is exactly zero is left out (the fixed point does not respond to it), and so is a probe the pass does not *resolve* — moving the constant by the probe's whole size (its own magnitude) moves one pass from `x_k` by no more than the floor the distance carries, `‖s · F_c ċ‖ ≤ floor` in -the bound's own norm. Its right-hand side is then what cancellation left -of terms the size of the fields, and so is the tangent solved from it. +the bound's own norm, and that movement depends on the iterate (a probe +whose right-hand side does not, an additive constant, is kept at any +size). Its right-hand side can then be what the iterate's last rounding, +or a cancellation inside the node's own derivative, left of it, and so is +the tangent solved from it: the saturating `c + tanh(s (u − c)) / s` has +`∂/∂s = d sech²(s d) / s − tanh(s d) / s²`, two terms of size `d / s` +that cancel to `−(2/3) s d³`, which at `d = 1e-12` is 24 orders below +either. The case that showed it: the centre `c` and the curve `s` of a nonlinearity `φ(u; c, s)` with `φ(c) = c`, `φ′(c) = 1`, evaluated where `u = c`. The fixed point does not respond to either, the returned iterate @@ -582,9 +588,15 @@ for those probes beside ones of order one; without them it reads 5.3e-12 for an error of 5.3e-12 over the gains). Where such a constant *is* resolved (an iterate stopped well short of the fixed point) it is in the bound, which then reads above one: the relative error of that gradient -is of order one, and the bound says so. A weak constant is left out by -the same rule: a gain whose whole value moves the pass by less than the -pass can resolve has a gradient no pass in that dtype can tell from zero. +is of order one, and the bound says so. A weak *multiplicative* constant +is left out by the same rule, although its tangent may be exact: a gain +whose whole value moves the pass by less than the pass resolves. Nothing +the bound measures tells that case from the cancelled one (the +sensitivity of the tangent to a floor-sized change of the state read 1.6% +for the saturating curve above, whose relative error is 113%), so the +rule is the magnitude's. On 108 drawn float32 and float64 rings of three +members the bound moved on two (2.3e-5 to 6.8e-6, 1.8e-2 to 2.5e-4: a +weak gain was its worst probe) and no flag changed. Measured `bound / true` (jaxlib 0.11.0, float32), the fixed point's gradient from tight `ift` and `fori` arms that agree, every point a diff --git a/docs/validation/coupling_claims.yaml b/docs/validation/coupling_claims.yaml index 4b47ef30..b4db6f61 100644 --- a/docs/validation/coupling_claims.yaml +++ b/docs/validation/coupling_claims.yaml @@ -3693,12 +3693,15 @@ claims: entries that norm is unavailable and the bound is inf unless the right-hand side does not depend on the state. A constant the pass resolves: moving it by its own magnitude moves one pass from x_k by - more than the residual's float floor, in the bound's norm, and its - tangent is not exactly zero. A constant below that (the centre or the - curve of a nonlinearity evaluated on its centre: the fixed point does - not respond to it, and its gradient at x_k is rounding) is not in the - bound, which says nothing of it; it read 1.09 for a relative error of - 1.134 with those probes in it (MADD-ANO-232, resolved). + more than the residual's float floor, in the bound's norm, or by an + amount that does not depend on the iterate (an additive constant), and + its tangent is not exactly zero. A constant below that (the centre or + the curve of a nonlinearity evaluated on its centre: the fixed point + does not respond to it, and its gradient at x_k is rounding; and a + gain so weak that its whole value moves the pass by less than the + floor) is not in the bound, which says nothing of it; it read 1.09 for + a relative error of 1.134 with those probes in it (MADD-ANO-232, + resolved). oracle: the fixed point's gradient from the float64 solve or from tight ift and fori arms that agree. tests: - tests/core/test_coupling_gradient_error_bound.py::test_the_gradient_bound_holds_across_an_early_exit_sweep diff --git a/src/maddening/core/coupling/_bounds.py b/src/maddening/core/coupling/_bounds.py index e937121d..f8bf1878 100644 --- a/src/maddening/core/coupling/_bounds.py +++ b/src/maddening/core/coupling/_bounds.py @@ -965,21 +965,26 @@ def g_derivative(row, ts, z): # the tangent's size, and a tangent that is rounding has none: where # moving the constant by the probe's whole size (its own magnitude) # moves one pass by no more than the pass's float resolution -- the - # floor the distance carries, in this norm -- the right-hand side is - # what cancellation left of terms the size of the fields, and so is - # the tangent solved from it. That is the same statement as a zero - # tangent (the fixed point does not respond to the probe) made at the - # resolution it can be made at, and such a probe is not in the worst - # either. It used to be: for the centre and the curve of a - # nonlinearity evaluated on its centre (a constant the fixed point - # does not respond to; right-hand sides of 2e-33 to 5e-18 beside ones - # of order one, float64) the bound read 1.09 for a relative error of - # 1.134 on a converged hub, usable. The absolute error for such a - # constant is of the size of its tangent (1.7e-34 there, beside - # gradients of 3.5e3). A right-hand side that is not finite still - # counts (its NaN bound poisons the maximum). + # floor the distance carries, in this norm -- *and* that movement + # depends on the iterate, the right-hand side is what the iterate's + # last rounding made it, and so is the tangent solved from it. That + # is the same statement as a zero tangent (the fixed point does not + # respond to the probe) made at the resolution it can be made at, and + # such a probe is not in the worst either. It used to be: for the + # centre and the curve of a nonlinearity evaluated on its centre (a + # constant the fixed point does not respond to; right-hand sides of + # 2e-33 to 5e-18 beside ones of order one, float64) the bound read + # 1.09 for a relative error of 1.134 on a converged hub, usable. The + # absolute error for such a constant is of the size of its tangent + # (1.7e-34 there, beside gradients of 3.5e3). A probe whose + # right-hand side does not depend on the iterate (an additive + # constant: ``any_dir`` is exactly zero) is resolved at any size, a + # weak forcing included; and one that is not finite still counts (its + # NaN bound poisons the maximum). rhs_size = norm(s * w) - resolved_probe = jnp.logical_or(rhs_size > floor, jnp.logical_not(jnp.isfinite(rhs_size))) + resolved_probe = jnp.logical_or( + jnp.logical_or(rhs_size > floor, jnp.logical_not(jnp.isfinite(rhs_size))), + any_dir == 0) responds = jnp.logical_and( jnp.logical_or(norm(t_s) > 0, jnp.logical_not(jnp.isfinite(norm(t_s)))), resolved_probe) diff --git a/src/maddening/core/graph_manager.py b/src/maddening/core/graph_manager.py index 0df14c28..7e8ee5b2 100644 --- a/src/maddening/core/graph_manager.py +++ b/src/maddening/core/graph_manager.py @@ -4418,20 +4418,24 @@ def coupling_diagnostics(self) -> dict[str, dict]: entry is zero, by 1 where the array is) moves one pass from ``x_k`` by more than the pass's float resolution, the floor ``"spectral_error_bound"`` adds to the residual, - measured as that bound's distance is; and where its + measured as that bound's distance is, or by an amount + that does not depend on the iterate (an additive constant, + a forcing: in the bound however weak); and where its tangent through the group is not exactly zero. A constant - below that has a gradient that is what rounding left of - terms the size of the fields, its relative error is of + below that has a gradient that can be what the iterate's + last rounding left of it, its relative error is then of order one or undefined, and the bound says nothing of it (it is not the worst probe): the centre or the curve of a nonlinearity evaluated on its centre, a term multiplied by - a field that has converged to zero. The gradient with - respect to such a constant is small beside the others in - the same units (measured: 1.5e-34 for an error of 1.7e-34 - where the resolved constants' are up to 3.5e3, float64); - check a constant with one Jacobian-vector product of the - pass, or treat a gradient many orders below its - neighbours' as zero. Costs + a field that has converged to zero -- and also a gain so + weak that its whole value moves the pass by less than the + pass resolves, whose gradient may be exact and is not + bounded here. The gradient with respect to such a + constant is small beside the others in the same units + (measured: 1.5e-34 for an error of 1.7e-34 where the + resolved constants' are up to 3.5e3, float64); check a + constant with one Jacobian-vector product of the pass. + Costs ``11 + 4 k + 5 n_p + 2 k n_p`` Jacobian-vector products per group per step beside the spectral bound's eight (plus one linearisation and ``k`` reverse-mode products where the diff --git a/tests/property/coupling_reference.py b/tests/property/coupling_reference.py index 04740413..ece4250b 100644 --- a/tests/property/coupling_reference.py +++ b/tests/property/coupling_reference.py @@ -373,6 +373,17 @@ def pass_responses(self, x, norm: Norm) -> np.ndarray: return np.asarray([norm.of_difference(moved[:, c], zero, weights) for c in range(moved.shape[1])]) + def read_through_the_iterate(self, x) -> np.ndarray: + """Per scalar constant, whether its ``dP/dc`` depends on the + iterate (it differs, in any bit, at a second point a third of each + entry's size away). An additive constant's does not, and the + gradient bound keeps such a probe at any size.""" + x = np.asarray(x, np.float64) + here = self.sensitivities(x) + there = self.sensitivities(x + 0.375 * (np.abs(x) + 1.0)) + return np.asarray([not np.array_equal(here[:, c], there[:, c]) + for c in range(here.shape[1])]) + def constant_names(self) -> list: """``node.leaf[i]`` / ``mapping:key.leaf[i]`` per column of :meth:`sensitivities`.""" with x64(): diff --git a/tests/property/test_coupling_nonlinear_search.py b/tests/property/test_coupling_nonlinear_search.py index 68ae0ae8..b8a725e2 100644 --- a/tests/property/test_coupling_nonlinear_search.py +++ b/tests/property/test_coupling_nonlinear_search.py @@ -623,10 +623,12 @@ def observe(case: Case) -> dict: names = ref.constant_names() # CPL-093 is made for a constant the pass resolves: moving it by # its own magnitude moves one pass by more than the residual's - # float floor. Held here to ``RESOLVED_MARGIN`` floors (the two - # sides are two computations of one comparison). + # float floor, or by an amount that does not depend on the iterate + # (an additive constant). Held here to ``RESOLVED_MARGIN`` floors + # (the two sides are two computations of one comparison). response = ref.pass_responses(x, raw) - resolved = [not out["floor_reported"] or r > RESOLVED_MARGIN * floor for r in response] + resolved = [not out["floor_reported"] or r > RESOLVED_MARGIN * floor or not through + for r, through in zip(response, ref.read_through_the_iterate(x))] out["report"]["constants_resolved"] = (sum(resolved), len(resolved)) for score, vanishing in (("gradient", False), ("gradient_vanishing", True)): mine = [does_not_move_the_fixed_point(n) is vanishing for n in names] From c24eb5b35d83a5bc282e199866c4d4fe8db28dbf Mon Sep 17 00:00:00 2001 From: Nicholas Ehsan Roy Date: Wed, 7 Oct 2026 06:51:29 +0200 Subject: [PATCH 05/13] wip: the plain magnitude rule; records [skip ci] --- CHANGELOG.md | 2 + .../coupling_algorithm_guide.md | 8 +- docs/release_notes/v0.4.0.md | 7 + docs/validation/coupling_claims.yaml | 11 +- docs/validation/known_anomalies.yaml | 121 ++++++++++++++++++ src/maddening/core/coupling/_bounds.py | 36 +++--- src/maddening/core/coupling/acceleration.py | 8 +- src/maddening/core/graph_manager.py | 12 +- tests/compliance/test_soup_evidence.py | 2 +- ...ing_iqn_returns_on_a_non_finite_iterate.py | 8 +- tests/property/coupling_reference.py | 11 -- .../test_coupling_nonlinear_search.py | 8 +- 12 files changed, 170 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8e23234..cf6bf0b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -417,6 +417,8 @@ guidance; the itemized changes follow. The `[verify]` extra now only pulls `hypothesis`. ### Fixed +- **A coupling group under `acceleration="iqn-ils"` or `"iqn-imvj"` returns from `step()` when its iterate leaves float range** (MADD-ANO-231; 0.3.0 and 0.3.1 under `solver="ift"` with `"iqn-imvj"`): the secant least-squares handed LAPACK's SVD a matrix holding an `inf`, and the step never returned. It now runs to `max_iterations` and reports `converged=False`, `residual=inf`, as the other accelerations do; steps of a finite run are unchanged, bit for bit. Action: none; on 0.3.x use `solver="fori"` or `"aitken"`. +- **`gradient_relative_error_bound` covers the constants one pass resolves** (MADD-ANO-232, never released): with a constant in it whose tangent at the returned iterate is rounding (the centre or curve of a nonlinearity evaluated on its centre) it read 1.09 for a relative error of 1.134, usable. Such a constant, and a gain whose whole value moves the pass by less than the residual's float floor, is no longer in the bound; the docstring says which constants are. Action: none. - **`coupling_diagnostics()`: three numbers that read wrong with their flag set, and one found beside them** (MADD-ANO-222, 225, 226, 229, never released): `gradient_relative_error_bound` at the float floor took the change along one stand-in direction (5.1e-6 for 3.0e-5); `rho_spectral` read settled past eight interface scalars (0.273 for 0.219), from sampled rounding on a float32 group far from normal (0.250 for 0.206), and lost a loop below a field's rounding on a sub-cycled group (1e-12 for 1.25e-4). The gradient bound's undirected distance now takes an operator norm; a Krylov space still growing at the cap is never settled (`spectral_usable=False` above seven interface scalars, eight where they are the whole state); a certificate over every perturbation of the measured size replaces the samples; a sub-cycled boundary value is differentiated as `(1 - alpha) a + alpha b` (values unchanged, gradients of sub-cycled groups move at rounding level). Action: none; expect `spectral_usable=False` on more float32 and 16-bit groups whose Jacobian is far from normal (usable fraction on the search's draws 0.979 to 0.976). diff --git a/docs/developer_guide/coupling_algorithm_guide.md b/docs/developer_guide/coupling_algorithm_guide.md index 305f801f..1e99d351 100644 --- a/docs/developer_guide/coupling_algorithm_guide.md +++ b/docs/developer_guide/coupling_algorithm_guide.md @@ -570,9 +570,7 @@ tangent is exactly zero is left out (the fixed point does not respond to it), and so is a probe the pass does not *resolve* — moving the constant by the probe's whole size (its own magnitude) moves one pass from `x_k` by no more than the floor the distance carries, `‖s · F_c ċ‖ ≤ floor` in -the bound's own norm, and that movement depends on the iterate (a probe -whose right-hand side does not, an additive constant, is kept at any -size). Its right-hand side can then be what the iterate's last rounding, +the bound's own norm. Its right-hand side can then be what the iterate's last rounding, or a cancellation inside the node's own derivative, left of it, and so is the tangent solved from it: the saturating `c + tanh(s (u − c)) / s` has `∂/∂s = d sech²(s d) / s − tanh(s d) / s²`, two terms of size `d / s` @@ -588,8 +586,8 @@ for those probes beside ones of order one; without them it reads 5.3e-12 for an error of 5.3e-12 over the gains). Where such a constant *is* resolved (an iterate stopped well short of the fixed point) it is in the bound, which then reads above one: the relative error of that gradient -is of order one, and the bound says so. A weak *multiplicative* constant -is left out by the same rule, although its tangent may be exact: a gain +is of order one, and the bound says so. A weak constant is left out by +the same rule, although its tangent may be exact: a gain or a forcing whose whole value moves the pass by less than the pass resolves. Nothing the bound measures tells that case from the cancelled one (the sensitivity of the tangent to a floor-sized change of the state read 1.6% diff --git a/docs/release_notes/v0.4.0.md b/docs/release_notes/v0.4.0.md index 98d75ebd..e8a6b3cc 100644 --- a/docs/release_notes/v0.4.0.md +++ b/docs/release_notes/v0.4.0.md @@ -7377,6 +7377,13 @@ its nodes on different clocks; now a `ValueError` at `compile()` and a 400 at `POST /graph/nodes`. `228` (resolved; carried by 0.1.0 to 0.3.1): REST read a boolean or numeric text as a node's timestep and clamped `/sim/profile`'s counts silently; now a 422. +`231` (resolved; carried by 0.3.0 and 0.3.1): a coupling group under +`acceleration="iqn-ils"` or `"iqn-imvj"` whose iterate left float range before +its cap never returned from `step()`; it now runs to the cap and reports +`converged=False`, `residual=inf`. +`232` (resolved, never released): `gradient_relative_error_bound` read 1.09 for +a relative error of 1.134 with a constant in it whose tangent is rounding; a +constant one pass does not resolve is no longer in the bound. ## Verification evidence diff --git a/docs/validation/coupling_claims.yaml b/docs/validation/coupling_claims.yaml index b4db6f61..34484410 100644 --- a/docs/validation/coupling_claims.yaml +++ b/docs/validation/coupling_claims.yaml @@ -3693,12 +3693,11 @@ claims: entries that norm is unavailable and the bound is inf unless the right-hand side does not depend on the state. A constant the pass resolves: moving it by its own magnitude moves one pass from x_k by - more than the residual's float floor, in the bound's norm, or by an - amount that does not depend on the iterate (an additive constant), and - its tangent is not exactly zero. A constant below that (the centre or - the curve of a nonlinearity evaluated on its centre: the fixed point - does not respond to it, and its gradient at x_k is rounding; and a - gain so weak that its whole value moves the pass by less than the + more than the residual's float floor, in the bound's norm, and its + tangent is not exactly zero. A constant below that (the centre or the + curve of a nonlinearity evaluated on its centre: the fixed point does + not respond to it, and its gradient at x_k is rounding; and a gain or + forcing so weak that its whole value moves the pass by less than the floor) is not in the bound, which says nothing of it; it read 1.09 for a relative error of 1.134 with those probes in it (MADD-ANO-232, resolved). diff --git a/docs/validation/known_anomalies.yaml b/docs/validation/known_anomalies.yaml index 7641eb68..6f1e6686 100644 --- a/docs/validation/known_anomalies.yaml +++ b/docs/validation/known_anomalies.yaml @@ -15505,3 +15505,124 @@ anomalies: - "tests/property/test_rest_requests_generated_from_the_schema.py::test_every_integer_query_declares_its_range" - "tests/api/test_profile_endpoints.py::TestSimProfile::test_a_count_outside_its_range_is_a_422_and_nothing_is_profiled" github_issue: null + + - anomaly_id: "MADD-ANO-231" + title: "A coupling group under IQN whose iterate left float range before its cap never returned from step()" + description: > + `acceleration="iqn-ils"` and `"iqn-imvj"` solve a least-squares + problem on the secant columns each pass, through an SVD + (`jnp.linalg.pinv`; `jnp.linalg.lstsq` in v0.3.0 and v0.3.1). On the + pass where part of the iterate overflowed, the new column held `inf` + in those entries and finite numbers in the rest, and LAPACK's SVD does + not return on such a matrix: `step()` never returned, with no error + and one core busy. Measured (CPU, jaxlib 0.11.0, each probe under a + wall-clock limit): a fan-out hub of four members with products of two + fields in float64, Jacobi, cap 120, started a whole field from its + fixed point -- no return in 240 s, where a converging step of the + same compiled graph takes 0.05 s; a pair whose first entry is `exp` + of itself beside three that contract -- no return in 25 s, float32 + and float64, both IQN kinds, `solver="ift"` and `"fori"`. The same + groups under `"none"` and `"aitken"` ran to the cap and reported + `converged=False`, `residual=inf`. `jnp.linalg.svd` and `pinv` + alone: no return on 4 x 4 to 16 x 16 matrices with one `inf` entry or + one `inf` column, nor on one with a row and a column at `finfo.max`; + a NaN beside the `inf`, or every entry `inf`, returns. At v0.3.0 and + v0.3.1 (`git archive` of each tag): `solver="ift"` with + `acceleration="iqn-imvj"` does not return on the `exp` pair in either + dtype; the default `solver="fori"` solved the normal equations by LU + and returns a NaN state. v0.2.1 and earlier have no `solver="ift"`. + Resolved in 0.4.0: the secant matrix is replaced by zeros before the + factorisation wherever the sum of its squares is not finite, the + quasi-Newton step is then not taken (the Aitken fallback's is), and + the group runs to its cap and reports the state as not finite, as + the other accelerations do. A finite matrix passes through + unchanged: 200 random finite calls of the update and 108 drawn + three-member rings stepped twice return the same bits before and + after. The same guard stands in front of every other SVD of the + coupling analysis (the spectral amplification and the gradient + bound's operator norms). + severity: "major" + safety_relevance: "context_dependent" + safety_relevance_rationale: > + Not silent: the call does not return and nothing wrong is reported. + `major` because a simulation that diverges is the case a caller's + own checks exist for, and none of them runs: no exception, no + report, a loop that stops. `context_dependent` because it needs a + quasi-Newton acceleration (not the default) and an iterate that + overflows part of its entries before the cap. + affected_components: + - "maddening.core.coupling.acceleration.iqn_ils_update" + - "maddening.core.coupling.group.CouplingGroup.acceleration" + affected_versions: ">=0.3.0, <0.4.0" + workaround: > + On v0.3.x use `solver="fori"` (the default there) with a + quasi-Newton acceleration, or `acceleration="aitken"`; or run the + step under a wall-clock limit. + resolution_status: "resolved" + resolution_version: "0.4.0" + residual_risk: > + The guard is on the matrix handed to the SVD, measured on CPU with + jaxlib 0.11.0; other LAPACK-backed calls of the coupling analysis + (`qr`, `solve`, `inv`, `eigvals`) returned on every non-finite and + extreme finite matrix tried (288 and 576 cases a dtype) and are not + guarded, except `eigvals`, which already was. A group that diverges + under IQN still spends its whole cap of passes. + verification: + - "tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py::test_a_step_whose_iterate_leaves_float_range_under_iqn_returns" + - "tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py::test_the_secant_update_returns_on_every_non_finite_input" + - "tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py::test_no_svd_of_the_coupling_analysis_is_handed_a_matrix_that_is_not_finite" + - "tests/property/test_coupling_nonlinear_search.py::test_a_group_that_leaves_float_range_under_iqn_still_returns" + github_issue: null + + - anomaly_id: "MADD-ANO-232" + title: "gradient_relative_error_bound read below the error, gradient_bound_usable=True, with a constant in it whose tangent is rounding: 1.09 for a relative error of 1.134" + description: > + The bound is the worst, over one probe per scalar constant, of a + bound on that probe's tangent error over the tangent's size. For a + constant the fixed point does not respond to -- the centre or the + curve of a nonlinearity evaluated on its centre -- the tangent at the + returned iterate is what the iterate's last rounding, or a + cancellation inside the node's derivative, left of it, and a relative + error of it is of order one or undefined. Measured (CPU, jaxlib + 0.11.0): on a float64 fan-out hub of four members with saturating + gains, converged in four passes, the right-hand sides of those probes + were 2e-33 to 5e-18 beside ones of order one, the bound read 1.09 and + the relative error of the gradient with respect to one curve was + 1.134 (absolute: 1.7e-34, beside gradients up to 3.5e3), + `gradient_bound_usable=True`. On a float32 ring stalled on its start + the float32 tangents of those constants are exactly zero and were + never in the bound (1.4e-6); in float64 at the same iterate one is + 6e-26 with a relative error of 2.7. Found by the nonlinear coupling + search. No release carries the gradient bound. Resolved in 0.4.0: + a probe is in the bound where moving its constant by its own + magnitude moves one pass by more than the residual's float floor; + the docstring and + the claim say so. The hub then reads 5.3e-12 for an error of + 5.3e-12 over its gains. + severity: "major" + safety_relevance: "context_dependent" + safety_relevance_rationale: > + A bound below its quantity with its flag set is a silent wrong + result, never `minor`. Not `critical`: the gradient concerned is + 1e-34 beside others of 1e3, and a bound that reads above one already + says the relative error is not bounded. `context_dependent` because + whether the bound gates anything is the program's choice. + affected_components: + - "maddening.core.graph_manager.GraphManager.coupling_diagnostics" + affected_versions: "none" + workaround: > + None needed in 0.4.0. + resolution_status: "resolved" + resolution_version: "0.4.0" + residual_risk: > + The rule is a magnitude: a gain so weak that its whole value moves + the pass by less than the floor is left out of the bound too, + although its tangent may be exact (on 108 drawn rings the bound moved + on two, 1.8e-2 to 2.5e-4 on one, and no flag changed). Nothing the + bound measures tells that case from the cancelled one. A constant + left out is not named in the report; one Jacobian-vector product of + the pass tells. + verification: + - "tests/property/test_coupling_nonlinear_search.py::test_a_constant_the_pass_does_not_resolve_is_not_in_the_gradient_bound" + - "tests/property/test_coupling_nonlinear_search.py::test_a_usable_gradient_bound_covers_a_nonlinearity_s_own_constants_per_push" + github_issue: null diff --git a/src/maddening/core/coupling/_bounds.py b/src/maddening/core/coupling/_bounds.py index f8bf1878..41961546 100644 --- a/src/maddening/core/coupling/_bounds.py +++ b/src/maddening/core/coupling/_bounds.py @@ -931,10 +931,7 @@ def g_derivative(row, ts, z): dG = jax.vmap( lambda row, ts: jax.vmap(lambda z: g_derivative(row, ts, z))(rows_g.T))( jnp.arange(n_rows), t_s) - # A derivative that is not finite bounds nothing: ``inf``, so the - # probe's bound is (a NaN here compared False below and the term - # was dropped). - any_dir = _spectral_norm(live[None, None, :] * dG, unbounded=jnp.inf) + any_dir = _spectral_norm(live[None, None, :] * dG) # The undirected distance: the floor through the resolvent (the larger # of the Krylov factor the distance itself uses and the full norm), # or the whole distance at an unresolved iterate. @@ -965,26 +962,25 @@ def g_derivative(row, ts, z): # the tangent's size, and a tangent that is rounding has none: where # moving the constant by the probe's whole size (its own magnitude) # moves one pass by no more than the pass's float resolution -- the - # floor the distance carries, in this norm -- *and* that movement - # depends on the iterate, the right-hand side is what the iterate's - # last rounding made it, and so is the tangent solved from it. That - # is the same statement as a zero tangent (the fixed point does not - # respond to the probe) made at the resolution it can be made at, and - # such a probe is not in the worst either. It used to be: for the - # centre and the curve of a nonlinearity evaluated on its centre (a - # constant the fixed point does not respond to; right-hand sides of + # floor the distance carries, in this norm -- the right-hand side can + # be what the iterate's last rounding, or a cancellation inside the + # node's own derivative, left of it, and so is the tangent solved from + # it. That is the same statement as a zero tangent (the fixed point + # does not respond to the probe) made at the resolution it can be made + # at, and such a probe is not in the worst either. It used to be: for + # the centre and the curve of a nonlinearity evaluated on its centre + # (a constant the fixed point does not respond to; right-hand sides of # 2e-33 to 5e-18 beside ones of order one, float64) the bound read # 1.09 for a relative error of 1.134 on a converged hub, usable. The # absolute error for such a constant is of the size of its tangent - # (1.7e-34 there, beside gradients of 3.5e3). A probe whose - # right-hand side does not depend on the iterate (an additive - # constant: ``any_dir`` is exactly zero) is resolved at any size, a - # weak forcing included; and one that is not finite still counts (its - # NaN bound poisons the maximum). + # (1.7e-34 there, beside gradients of 3.5e3). The rule is the + # magnitude's, so a weak constant whose tangent is exact is left out + # with the cancelled one: nothing measured here tells them apart (the + # tangent's sensitivity to a floor-sized change of the state read 1.6% + # for that curve). A right-hand side that is not finite still counts + # (its NaN bound poisons the maximum). rhs_size = norm(s * w) - resolved_probe = jnp.logical_or( - jnp.logical_or(rhs_size > floor, jnp.logical_not(jnp.isfinite(rhs_size))), - any_dir == 0) + resolved_probe = jnp.logical_or(rhs_size > floor, jnp.logical_not(jnp.isfinite(rhs_size))) responds = jnp.logical_and( jnp.logical_or(norm(t_s) > 0, jnp.logical_not(jnp.isfinite(norm(t_s)))), resolved_probe) diff --git a/src/maddening/core/coupling/acceleration.py b/src/maddening/core/coupling/acceleration.py index 66faf8af..e33c5ae8 100644 --- a/src/maddening/core/coupling/acceleration.py +++ b/src/maddening/core/coupling/acceleration.py @@ -992,12 +992,12 @@ def _lapack_input(A): return jnp.where(ok[..., None, None], A, jnp.zeros_like(A)), ok -def _spectral_norm(A, unbounded=jnp.nan): - """``||A||_2`` per matrix (the last two axes), *unbounded* where - :func:`_lapack_input` withholds the matrix (NaN: what the SVD of a +def _spectral_norm(A): + """``||A||_2`` per matrix (the last two axes), NaN where + :func:`_lapack_input` withholds the matrix (what the SVD of a non-finite matrix returns where it returns).""" safe, ok = _lapack_input(A) - return jnp.where(ok, jnp.linalg.norm(safe, ord=2, axis=(-2, -1)), unbounded) + return jnp.where(ok, jnp.linalg.norm(safe, ord=2, axis=(-2, -1)), jnp.nan) #: Backends on which ``jax.numpy.linalg.eigvals`` of a non-symmetric diff --git a/src/maddening/core/graph_manager.py b/src/maddening/core/graph_manager.py index 7e8ee5b2..77f498fe 100644 --- a/src/maddening/core/graph_manager.py +++ b/src/maddening/core/graph_manager.py @@ -4418,19 +4418,17 @@ def coupling_diagnostics(self) -> dict[str, dict]: entry is zero, by 1 where the array is) moves one pass from ``x_k`` by more than the pass's float resolution, the floor ``"spectral_error_bound"`` adds to the residual, - measured as that bound's distance is, or by an amount - that does not depend on the iterate (an additive constant, - a forcing: in the bound however weak); and where its + measured as that bound's distance is; and where its tangent through the group is not exactly zero. A constant below that has a gradient that can be what the iterate's last rounding left of it, its relative error is then of order one or undefined, and the bound says nothing of it (it is not the worst probe): the centre or the curve of a nonlinearity evaluated on its centre, a term multiplied by - a field that has converged to zero -- and also a gain so - weak that its whole value moves the pass by less than the - pass resolves, whose gradient may be exact and is not - bounded here. The gradient with respect to such a + a field that has converged to zero -- and also a gain or + a forcing so weak that its whole value moves the pass by + less than the pass resolves, whose gradient may be exact + and is not bounded here. The gradient with respect to such a constant is small beside the others in the same units (measured: 1.5e-34 for an error of 1.7e-34 where the resolved constants' are up to 3.5e3, float64); check a diff --git a/tests/compliance/test_soup_evidence.py b/tests/compliance/test_soup_evidence.py index 92f21d24..da65005a 100644 --- a/tests/compliance/test_soup_evidence.py +++ b/tests/compliance/test_soup_evidence.py @@ -97,7 +97,7 @@ def test_the_committed_soup_tables_match_a_fresh_generation(): # anomaly is closed -- resolved, or a duplicate of the entry that carries it # -- and stays in the registry; only a closed entry, or a number no commit # ever recorded, can be retired. The gate reads the last status from git. -_HIGHEST_ANOMALY_ID = 230 +_HIGHEST_ANOMALY_ID = 232 _RETIRED_ANOMALY_IDS: dict = {} _HIGHEST_BENCHMARK_ID = 16 diff --git a/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py b/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py index 6e553cca..39808705 100644 --- a/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py +++ b/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py @@ -202,7 +202,7 @@ def test_the_secant_update_returns_on_every_non_finite_input(dtype): x_raw = (x_old + r).astype(dtype) args = (jnp.asarray(x_raw), jnp.asarray(x_old), jnp.asarray(r_prev), jnp.asarray(x_old), jnp.asarray(V), jnp.asarray(W), jnp.int32(cols - 1), - jnp.asarray(1.0, dtype), jnp.zeros(n, dtype)) + jnp.asarray(0.5, dtype), jnp.asarray(r_prev)) out = within_the_limit(lambda args=args: jax.block_until_ready(update(*args))) x_new, new_V = np.asarray(out[0]), np.asarray(out[1]) if kind == "finite": @@ -219,15 +219,14 @@ def test_the_secant_update_returns_on_every_non_finite_input(dtype): def test_no_svd_of_the_coupling_analysis_is_handed_a_matrix_that_is_not_finite(dtype): """``_lapack_input`` withholds exactly the matrices whose squares do not sum to a finite number, and returns every other unchanged; - ``_spectral_norm`` of a withheld matrix is NaN (or what the caller - asks for) and of any other the SVD's.""" + ``_spectral_norm`` of a withheld matrix is NaN and of any other the + SVD's.""" x64 = jax.config.jax_enable_x64 jax.config.update("jax_enable_x64", dtype == "float64") try: rng = np.random.default_rng(1) big = float(np.finfo(dtype).max) norm = jax.jit(acceleration._spectral_norm) # noqa: SLF001 - norm_inf = jax.jit(lambda A: acceleration._spectral_norm(A, unbounded=jnp.inf)) # noqa: SLF001 for n, m in ((4, 4), (12, 8), (16, 16)): A = rng.standard_normal((n, m)).astype(dtype) safe, ok = acceleration._lapack_input(jnp.asarray(A)) # noqa: SLF001 @@ -244,7 +243,6 @@ def test_no_svd_of_the_coupling_analysis_is_handed_a_matrix_that_is_not_finite(d assert not bool(ok), (poison, n, m) assert not np.any(np.asarray(safe)), (poison, n, m) assert math.isnan(float(within_the_limit(lambda B=B: norm(jnp.asarray(B))))) - assert float(within_the_limit(lambda B=B: norm_inf(jnp.asarray(B)))) == math.inf # Per matrix of a batch. batch = rng.standard_normal((3, 4, 4)).astype(dtype) batch[1, 2, 2] = np.inf diff --git a/tests/property/coupling_reference.py b/tests/property/coupling_reference.py index ece4250b..04740413 100644 --- a/tests/property/coupling_reference.py +++ b/tests/property/coupling_reference.py @@ -373,17 +373,6 @@ def pass_responses(self, x, norm: Norm) -> np.ndarray: return np.asarray([norm.of_difference(moved[:, c], zero, weights) for c in range(moved.shape[1])]) - def read_through_the_iterate(self, x) -> np.ndarray: - """Per scalar constant, whether its ``dP/dc`` depends on the - iterate (it differs, in any bit, at a second point a third of each - entry's size away). An additive constant's does not, and the - gradient bound keeps such a probe at any size.""" - x = np.asarray(x, np.float64) - here = self.sensitivities(x) - there = self.sensitivities(x + 0.375 * (np.abs(x) + 1.0)) - return np.asarray([not np.array_equal(here[:, c], there[:, c]) - for c in range(here.shape[1])]) - def constant_names(self) -> list: """``node.leaf[i]`` / ``mapping:key.leaf[i]`` per column of :meth:`sensitivities`.""" with x64(): diff --git a/tests/property/test_coupling_nonlinear_search.py b/tests/property/test_coupling_nonlinear_search.py index b8a725e2..68ae0ae8 100644 --- a/tests/property/test_coupling_nonlinear_search.py +++ b/tests/property/test_coupling_nonlinear_search.py @@ -623,12 +623,10 @@ def observe(case: Case) -> dict: names = ref.constant_names() # CPL-093 is made for a constant the pass resolves: moving it by # its own magnitude moves one pass by more than the residual's - # float floor, or by an amount that does not depend on the iterate - # (an additive constant). Held here to ``RESOLVED_MARGIN`` floors - # (the two sides are two computations of one comparison). + # float floor. Held here to ``RESOLVED_MARGIN`` floors (the two + # sides are two computations of one comparison). response = ref.pass_responses(x, raw) - resolved = [not out["floor_reported"] or r > RESOLVED_MARGIN * floor or not through - for r, through in zip(response, ref.read_through_the_iterate(x))] + resolved = [not out["floor_reported"] or r > RESOLVED_MARGIN * floor for r in response] out["report"]["constants_resolved"] = (sum(resolved), len(resolved)) for score, vanishing in (("gradient", False), ("gradient_vanishing", True)): mine = [does_not_move_the_fixed_point(n) is vanishing for n in names] From 0114b68c4409959cf973e78bd57e9cd0c89968b6 Mon Sep 17 00:00:00 2001 From: Nicholas Ehsan Roy Date: Wed, 7 Oct 2026 06:54:12 +0200 Subject: [PATCH 06/13] wip: seed for a resolved nonlinearity constant; simplify the spectral guard [skip ci] --- src/maddening/core/coupling/acceleration.py | 11 ++++++----- ...ling_iqn_returns_on_a_non_finite_iterate.py | 4 +++- .../property/test_coupling_nonlinear_search.py | 18 +++++++++++++++--- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/maddening/core/coupling/acceleration.py b/src/maddening/core/coupling/acceleration.py index e33c5ae8..d7191cf2 100644 --- a/src/maddening/core/coupling/acceleration.py +++ b/src/maddening/core/coupling/acceleration.py @@ -1170,12 +1170,13 @@ def _compressed_spectrum(H, coefficients, column, extended): k = H.shape[1] Hk = H[:k, :k] rho = _spectral_radius(Hk) - # Never an SVD of a matrix that is not finite (``_lapack_input``): its - # smallest singular value then reads NaN, as it did where the driver - # returned, and the amplification ``inf``. - shifted, shifted_ok = _lapack_input(jnp.eye(k, dtype=Hk.dtype) - Hk) + # Never an SVD of a matrix that is not finite (``_lapack_input``): the + # zeros that stand in for one have no singular value above zero, so + # the amplification reads ``inf``, as it did where the driver returned + # (a NaN singular value is not above zero either). + shifted, _ = _lapack_input(jnp.eye(k, dtype=Hk.dtype) - Hk) sigma = jnp.linalg.svd(shifted, compute_uv=False) - sigma_min = jnp.where(shifted_ok, sigma[-1], jnp.nan) + sigma_min = sigma[-1] invertible = sigma_min > 0 amplification = jnp.where( invertible, 1.0 / jnp.where(invertible, sigma_min, 1.0), jnp.inf, diff --git a/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py b/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py index 39808705..bb85e1b9 100644 --- a/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py +++ b/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py @@ -210,7 +210,9 @@ def test_the_secant_update_returns_on_every_non_finite_input(dtype): elif not np.all(np.isfinite(new_V)): aitken = np.asarray(acceleration.aitken_relaxation( args[1], args[0], args[8], args[7])[0]) - np.testing.assert_array_equal(x_new, aitken, err_msg=f"{kind}, {n} x {cols}") + # Compiled against not: an ulp or two (a fused multiply-add). + np.testing.assert_allclose(x_new, aitken, rtol=16 * np.finfo(dtype).eps, + err_msg=f"{kind}, {n} x {cols}") finally: jax.config.update("jax_enable_x64", x64) diff --git a/tests/property/test_coupling_nonlinear_search.py b/tests/property/test_coupling_nonlinear_search.py index 68ae0ae8..4736d731 100644 --- a/tests/property/test_coupling_nonlinear_search.py +++ b/tests/property/test_coupling_nonlinear_search.py @@ -850,6 +850,13 @@ def test_the_nonlinear_fixed_point_is_the_linear_one_and_the_jacobian_moves(): "the-jacobian-a-fifth-from-the-fixed-point-s": ( Case(0, linear.Case(0, 1, 1.0 / 3.0, False, 1.0, 0.0, 1.0, -1, 1.0, 0), 21.544346900318832), "gradient", 0.05), + # Five Jacobi passes from a whole field away: the pass resolves six of + # the twelve centres and curves, the relative error of the gradient + # with respect to one is of order one (the fixed point does not + # respond to it), and the bound reads 1.27, the error 0.79 of it. + "a-nonlinearity-s-own-constant-resolved-short-of-the-fixed-point": ( + Case(0, linear.Case(0, 1, 0.3, False, 1.0, 0.0, 1.0, 0, 1.0, 0), 1.0), + "gradient_vanishing", 0.5), } @@ -891,11 +898,13 @@ def test_a_usable_gradient_bound_covers_a_nonlinearity_s_own_constants_per_push( """A nonlinearity's centre and curve do not move the fixed point, so the relative error of the gradient with respect to one is of order one at any other iterate: the bound reads above it wherever the pass - resolves the constant, and leaves the constant out where it does not - (premise: some examples have such a constant scored).""" + resolves the constant, and leaves the constant out where it does not. + (This cell's twenty examples end within a float32 rounding of their + fixed points, where none is resolved; the seed + ``a-nonlinearity-s-own-constant-resolved-short-of-the-fixed-point`` + holds one that is, and the slow hunt holds that some are.)""" _report, fractions = search("gradient_vanishing") _held("gradient_vanishing", fractions) - assert fractions["vanishing_scored"] > 0, fractions def test_the_floor_covers_what_the_reported_residual_misses_on_the_nonlinear_cell_per_push(): @@ -920,6 +929,9 @@ def test_the_hunt_finds_no_number_on_the_wrong_side_of_a_nonlinear_group(block, assert fractions["usable"] >= USABLE_FLOOR, ( f"{name}, block {block}: only {fractions['usable']:.2f} of the examples had the flag " f"set (floor {USABLE_FLOOR})") + if name == "gradient_vanishing": + # Measured 0.17 to 0.57 by block: the score is not empty. + assert fractions["vanishing_scored"] > 0, fractions def test_the_reference_s_jacobian_is_the_central_difference_of_its_pass(): From db71f5466febb55a0ac2b9819445925e93b98457 Mon Sep 17 00:00:00 2001 From: Nicholas Ehsan Roy Date: Wed, 7 Oct 2026 06:58:04 +0200 Subject: [PATCH 07/13] wip: a stuck call fails cleanly [skip ci] --- ...ing_iqn_returns_on_a_non_finite_iterate.py | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py b/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py index bb85e1b9..bb84af59 100644 --- a/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py +++ b/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py @@ -20,7 +20,10 @@ from __future__ import annotations +import atexit import math +import os +import sys import threading import jax @@ -38,6 +41,25 @@ DTYPES = ("float32", "float64") +_STUCK = [] + + +def _leave_without_finalising(): + """A thread that never returns from LAPACK aborts the interpreter when + it finalises (exit -6, after the report): leave by ``os._exit`` once + everything else at exit has run, with the failing status.""" + if _STUCK: + return + _STUCK.append(True) + + def leave(): + sys.stdout.flush() + sys.stderr.flush() + os._exit(1) + + atexit.register(leave) + + def within_the_limit(fn): """``fn()`` from a daemon thread, or a failure after :data:`LIMIT` seconds.""" box: dict = {} @@ -51,7 +73,9 @@ def run(): thread = threading.Thread(target=run, daemon=True) thread.start() thread.join(LIMIT) - assert not thread.is_alive(), f"no return in {LIMIT:.0f} s" + if thread.is_alive(): + _leave_without_finalising() + pytest.fail(f"no return in {LIMIT:.0f} s") if "error" in box: raise box["error"] return box["value"] From 457f4b4f4d6812793621a48253acd7a106bb916c Mon Sep 17 00:00:00 2001 From: Nicholas Ehsan Roy Date: Wed, 7 Oct 2026 06:58:42 +0200 Subject: [PATCH 08/13] fix(coupling): an IQN step returns when its iterate leaves float range; the gradient bound covers the constants a pass resolves The secant least-squares of iqn-ils / iqn-imvj handed LAPACK's SVD a matrix holding an inf on the pass where part of the iterate overflowed, and the SVD does not return on such a matrix: step() never returned (MADD-ANO-231; v0.3.0 and v0.3.1 under solver=ift with iqn-imvj). The matrix is now replaced by zeros before the factorisation wherever the sum of its squares is not finite, and the quasi-Newton step is not taken; the same guard stands in front of every SVD of the coupling analysis. gradient_relative_error_bound took its worst over every probe with a non-zero tangent, including a constant whose tangent at the returned iterate is rounding (1.09 for a relative error of 1.134, usable; MADD-ANO-232). A probe is now in the bound where moving its constant by its own magnitude moves one pass by more than the residual's float floor. The step-program digests are removed here and recaptured on this commit: the programs of the eight gate graphs with an iqn-ils group change (a guard is new code); the other sixteen are compared with the earlier capture in the commit that adds the file. [skip ci] Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013UkCde7g23gTziUjYAvnKD --- tests/core/data/step_program_digests.json | 516 ---------------------- 1 file changed, 516 deletions(-) delete mode 100644 tests/core/data/step_program_digests.json diff --git a/tests/core/data/step_program_digests.json b/tests/core/data/step_program_digests.json deleted file mode 100644 index 82bd02d7..00000000 --- a/tests/core/data/step_program_digests.json +++ /dev/null @@ -1,516 +0,0 @@ -{ - "format": 1, - "commit": "396eb59a828e1f8932ae046e13e0f4d53b1f881b", - "captures": { - "0.10.2": { - "named/chain-into-ring/choice-0": { - "step": "3d95c94bf7cb1d724447fb2ac3cf681c57b896b981b98a66d9da984462007c76", - "step_baked_params": "6c037930cce262f23178056accd7f1889d87d219651e5d7067006abe13c03154", - "scan3": "d7ae0aa34da0c97a725138cf5b3a7da4d45925e5f420f4b57ee7c56eda48b04f", - "sweep2": "42ac7f72789eb69386d994718402efbbf1849867f0a0f8ec67f600fabc95a0ea", - "adaptive": "fe21f8305b5cc8c638fe5def9d1f4dbc1fb090dbef131b3fd150a3137719a9ed" - }, - "named/chain-into-ring/choice-1": { - "step": "77010e94608aa336fea5429548ad91827a69ec5a74f0df4bba13ff067b284ebf", - "step_baked_params": "881775955ba7e821fe18265d9bb8a6bb4034eea5aed9453c67daf9efd6fbaad0", - "scan3": "9f5530ce916463da201fc565b7aecf155ebf4dd702cdf0735d7d44996f47f199", - "sweep2": "3dcf241511b981e28a4a0ffcd2842080ca1a91e0ed15bf1b5a0f4bc8fa5393a1", - "adaptive": "2802121fb7d4dd3dec32cde61cea4b8d2f350ab6307e665fc02f38a578f661b8" - }, - "named/nested-loop-additive/choice-0": { - "step": "bc54ed660d1254db887726f5f6820d60306fae3e69505c96ab594c58b1313d77", - "step_baked_params": "63b1cd68da4cd95ad453f7940fe2fb8a8c8831cba89fb6f071fbb57e90dc1774", - "scan3": "410c4e8ce3a77a282c1491625405a30e1311e3930283084706f04b5f913e799f", - "sweep2": "fb2ef9f0dc59d4a293a0b79274f33e77921956214be520d5a179d3f2289af788", - "adaptive": "59f02fbb799870822b260824b2089103d0b16f3361b5150b781635748d7ec838" - }, - "named/nested-loop-additive/choice-1": { - "step": "e56cfe472c750a6f5f8cb73c129fb54046eba7a42dd9f1c3e24f134f9ac159b4", - "step_baked_params": "d891df17f3820ac940449d8a4856650380eaec93563337aee600a47b6dba9d94", - "scan3": "71f7bfcd8a50419ee69cc3ca1e8d6c0fa73a73ba1373c3c539b133044cb588b9", - "sweep2": "f2befbfc08571344fc0ae2696ef40fdaacd87888ce6c8493fc63c2f10b78f524", - "adaptive": "220660cb43283bd99152eff361c088d9ab6ad2086b399646c405dd88e3d3b09e" - }, - "named/star-and-ungrouped-ring/choice-0": { - "step": "980568cb12b370111642d74d21c15be3d144edff05f21504ac299e1c810b840b", - "step_baked_params": "05cb43132e2b16559d02b69b8a68f652d18c4e417ed82bb15b982a68498d4680", - "scan3": "d03a7504bd2cba695ebd9e88d806cffb17f929c361ca4aa2d6a78ecfca59002c", - "sweep2": "b31deb0b0b45c16ff2cae5cf4c2ce18e8946e5f43073c2cf109835f29fb56cd4", - "adaptive": "4ec3b069cbcd09b787cd6c512536a5ded358cb57426c911744e2b8dc1443daed" - }, - "named/star-and-ungrouped-ring/choice-1": { - "step": "6ffb74199bddb07ca4daaf4496ea52c55f25b9a1fd1c66d41c61ecd6478c5013", - "step_baked_params": "18090c65e76110e1f247c6e6f8e6ee844bcce4d957a8729aab1e6c3660ac6c10", - "scan3": "5b8177984391af8b8d0897d8fb6ef5cf6893be05a3504c365f1692ae1a48ae1f", - "sweep2": "ba459278f3c12b39e8a8a70952393033f941116930af424369c1f804b9d94868", - "adaptive": "2ed2bc5194b3df6f5b1da7fcdf22982f0865f3c546187d0733df6c57194df2a1" - }, - "named/two-groups-one-scc/choice-0": { - "step": "ef8ee10d5e2e8c0ecb89ae3ca685e15c035178aa9645d76c04c6dfdfe5796c25", - "step_baked_params": "fdb9ba80076653f8b0a79554fdf0481ebf7bd49a5d0796e45dcc43aa6af0c2ca", - "scan3": "cc5606fe9145f8b2733749e4d1c4d8ffe5eec83ba97596b2662ea39312cfbd76", - "sweep2": "0c3c2fc58fbb0fae5f145cc6c6bd907b860f70dd096c5b023b0d0a54109b436f", - "adaptive": "7ba3d0184e141097cba3bc9ca47753aec687a800e9f8600f7d4d3195fee490ff" - }, - "named/two-groups-one-scc/choice-1": { - "step": "902c7025d6423b76e9036cfc70710a96bcb0d88c268cfd09b9bf00d1ca712ab6", - "step_baked_params": "2ff1ea6e4dc8fac0c68344d2747e6b4a5159f62acc1d7310c91081aeaa8b64db", - "scan3": "55d0d49a44b7c3cf4380272c9ca3a81acb01fc79a8571f39505b7fc747ba81ff", - "sweep2": "ba847d07db8160c490902bb4ae853403ebdb6c550de217932398e26f04ff4377", - "adaptive": "6510a87216c98a0e93dcb31c6e13d9cd9eaa21d9fe7a61ef1c15faf71086038d" - }, - "sparse-ragged/chain-into-ring/choice-0": { - "step": "a040003c3fab4927b422ab355351fec717edaa18bd319892b9ae213b4a199d69", - "step_baked_params": "25225aab6b9a1f91a0a59fadd1e02407c57a3b06da119d91883473874f59f07e", - "scan3": "360467fc02792d8560e53c7964e2f718eb022dee0526ddbd3eab7e9922edbd83", - "sweep2": "8d9a2d28c417a3a7537bc479c4060916a762e22a1e6bad9eb0badd5abab6da57", - "adaptive": "ffdfb67740d207a524fd229b14a2b411ac844f290ce530a90e0d1373d95ab177" - }, - "sparse-ragged/chain-into-ring/choice-1": { - "step": "7fc03677b4e2299958b5a71ed295af077f3fa7a7af70ed08c954926a0777eb34", - "step_baked_params": "0b56690c921175dd77819fc09fa6bf0f1590adaf37702db17cfaff82b829567a", - "scan3": "1fec5fe29926022cbbf099266ae70f6acf753b612e1b34a17bbacd8782ce83e2", - "sweep2": "34ee3ef72d564b80178c26381b09afd4d664314c7d72e7c3465a6b685b313120", - "adaptive": "686d45d6a546d046e2f7f78021d616b8aadd1f0ba5fafac13191b47946337dd7" - }, - "sparse-ragged/nested-loop-additive/choice-0": { - "step": "c9c9e4f3d14a74453c76b80f591f9a33d967afdd3e0fd48842201069d1a9f522", - "step_baked_params": "0e7ec9ae3dc6b45abfc7205453c0dea0373a8e92372fa1b4b2548b78475a31b1", - "scan3": "08c37b700d554d462e1a15ffe8e1a95b7b963f3dd4c54d5ceadfdb69c0751f39", - "sweep2": "892c8fefe403d0b27efc527c5e4763552d009c95fe19741fbad8f0c9b475dd95", - "adaptive": "edebe0ecb0e53c5430268aa1f5ff1d273bd480e64810e4ce1587a26f94548bc8" - }, - "sparse-ragged/nested-loop-additive/choice-1": { - "step": "c8742294fba468391c1ed9c17f6ddd769742351a2da63aba0bd549f3f91eb8b1", - "step_baked_params": "cc1b788642e8528cccbcca31451809580211c901aeec3c774c56e57e3c0ef554", - "scan3": "c6e65a3db2e1d7c65754cf25dcab95db0e4986ed8a4f643cb38db4ff2529164c", - "sweep2": "0182765642184948565b9ba0a0075e03726e6bd162fd375ae32005d55ea54176", - "adaptive": "cb99ce65cb3c1afd40bd415d85a75ebc59c8ad25728f4562ec75decf105ee6bb" - }, - "sparse-ragged/star-and-ungrouped-ring/choice-0": { - "step": "fc03fed86715ba646ed87eb1d44b3cd7d4c97ea149447cac0f6bd55e8d68a2a7", - "step_baked_params": "e7377bbe13039184c7e7b18617a8fad28db3f8306fca00eb8a85a797d7b08f89", - "scan3": "ee93caab1ec01268410f764f81d53f687ca34fc2d55adfcea7c785969af29266", - "sweep2": "6bf68ca6cc53251766799a12a5e443324e060905e58b39aad9b1358907b4168e", - "adaptive": "e6a338e1a17c0945b57d3a1e5f1b179605eb880a5113c48a0058a9019acfa7ae" - }, - "sparse-ragged/star-and-ungrouped-ring/choice-1": { - "step": "89459d699db5b797abe749b59c089a401d4524d5123d0a8500eca198714f37f0", - "step_baked_params": "d02622eb7884f348a64944ed1f98e8fdffae44168655abe8e340aa848f04143b", - "scan3": "adb62dce5d73e627b30b23fa9d736a298542b9fd2a910cb17e22ceedfb0fff7b", - "sweep2": "7c9025c5fbad72d52d24930bfa7a7322d35d4fb2669ee59f2ab76f518718f5e5", - "adaptive": "41ccbe8dc202db2b4cbf363e154959b09eef4ea8b781979b0aa387e454184d8b" - }, - "sparse-ragged/two-groups-one-scc/choice-0": { - "step": "5ff074bcafef59bfb21fb326e651dc7574ef1e92c93f7433d60858e71aad1c6c", - "step_baked_params": "770c180fd0d77898f846531f4c886eb43e0542f0dbfffe0a813ea17e398091f0", - "scan3": "1b763778bb09d6db147bad07240a7ef91e19e4c4b04938141e47f0ac38690771", - "sweep2": "dfe5eecda0ca401f28f0a3c6d09f2ab9537607538cf7fffc660cd152ac2623e7", - "adaptive": "a1b870b596f6f1d789113769129bb223280813d3dbb78df827db3fc490635ed1" - }, - "sparse-ragged/two-groups-one-scc/choice-1": { - "step": "ee72c2ce48fdb8b957be9945381b4b15703e53d6bf8b40d263df14c7f73544f1", - "step_baked_params": "183b89093472553d6393cfd6bae1e60fc2324d3290427250ab2a873a8a65e625", - "scan3": "92f4c2900889b602120090b9c2c1766fcddd9c1e8f10ec6b0218583632202ec9", - "sweep2": "376da2989bf38cf2751f8ae0ef4f3b953fe4056f2262e42952fdb47a3911c7b7", - "adaptive": "efb6c828dd52ff70127229e8fd653847fdcc94f1529d98351acf9804af469422" - }, - "sparse-scatter/chain-into-ring/choice-0": { - "step": "0a022a3c93a67d7282bd33166c571589f4b87b5fc51ee6d7dea22bf61ddd22ef", - "step_baked_params": "a0247c73d698a912a3704d19486248571db3639d0bfaae5c15f60f65a0bff14a", - "scan3": "e8938709e266fd4b7aa9aeacf8a05df71ad00895190fbfb65bc74a7b76e17552", - "sweep2": "9eb5a90f9350c45f93bb98ccd9c07131525c4b4d5c35dc9b9adf1a7e3b722900", - "adaptive": "29f57e5c7579d6e037e7345cb8c88bd7ed8bd82056e60297aeb5c54e7f7e97bd" - }, - "multi-rate/chain-into-ring": { - "step": "69895dc913f671ca3cb5082c4b665067ca83b87d7bd3dba234f60fe0a17ef77c", - "step_baked_params": "20059555ce1bc0163630111dfe5054e4914c859a182e9b68f2edc704493f60fb", - "scan3": "5c9186cc994f323f5961f125a2b8265f3ccb3b307b30dd6e372993fd4d4f6dff", - "sweep2": "f8a9c984e1a52d06f7a8b2c9e1a709e5bda0d108326e6254a42dbb6cf6972e09", - "adaptive": "2737b8f2c88af012cae6f00ee5045862d3a39aeac14aab880a7f0d06aa7694fa" - }, - "sub-cycled/chain-into-ring": { - "step": "04d8b64cf117bec39458863c429371acb8464ee5adc5db12b69be75b0d9571a9", - "step_baked_params": "ebe7bcd8d04537d4ee5c9c4d08389d2c5b841985c6c998be0bd8d19948a23a50", - "scan3": "8658aecbbce5dde6ab121164801330b6e4a07ada89ea98a67b569aa3af141f20", - "sweep2": "854321e855daadeb562f0936800c31c933f7e5dd8b4bf5531516afa661f0e4da", - "adaptive": "8216a3230af80d84566813cd4a797dac320fec64161ff9e3127d0a852e025188" - }, - "predictor/chain-into-ring": { - "step": "d19c185c46219e8d801851751a0ec004c75dc464e8bea924e8c80b3bd0ae5cc8", - "step_baked_params": "a548c0e3fb299a2e854fd6c00797f5692131f8e64375177d52375a04fb9e76e3", - "scan3": "6b223c1a59a1a83daae911f31b4a1372726b2e8f58d898f16b9e5f7e462fe145", - "sweep2": "5924ff438208c7956355ac25fb124c21cb2146694ebb6004e0058d8e6a4d784a", - "adaptive": "204433c156183477b5aa4849ee77a13a493d2efb968fc837234a0e33cbcaa555" - }, - "aitken/chain-into-ring": { - "step": "b27b47b2d049c72c3fcd2715958f77bd20ede34f6b2098ab5cd9ebbd34649252", - "step_baked_params": "ed5d206d3420447bf4b9cf6acfbc68f68b87301e9e6f1749b971332c2d09e6dc", - "scan3": "e22e3e8d685e845f4def058e2ffe8ce188ba49bd3e571b3800657c98e7761588", - "sweep2": "5996c073c6e4bbabead9cb0f65b7e5ba8ed9f1325815554a3e1d8b296b1930d1", - "adaptive": "80073b2c8f57c4389f65e21c79087cb5e6b700daf9570cf071a195bdb72bccd2" - }, - "flux-outside-a-group": { - "step": "fb8a0ebd01f3b0e896e6790ec734332262ec7528bd270ea676fb23baa4ba103e", - "step_baked_params": "b5af89027eec5b08304e0bf146a0c0d5bcd706dda99ab24a3abc1125aaf8cc3a", - "scan3": "d800e3550d086a53cd5776d6c0c9c20c1faa52b7f28d063827aaf19c69d8751a", - "sweep2": "e639020358b8a006022a32e2024c987b21f5080149298fb44d82d9b54397f048", - "adaptive": "ddf0d8966c2cce3e829a3bf35c80d02301cf054999d9ad1df17d6cc0f71bf85e" - }, - "rbf-edge": { - "step": "ba518ff7a8f2fd5780dc43103b395dc98af157ff655e904443ae6b8a84b67952", - "step_baked_params": "1df4b758b8feddd9720b64218d6f8bf4ca58b926e3473acb2ced3d50aae2bd37", - "scan3": "1486b3f8c181abeba43949623d0dcd90af6c8a3b259ff1b4e33da525ec777de9", - "sweep2": "27d97e1fe18aef49f3996299a2c2a59d3ab486d0b29e91df433eacd151c091d5", - "adaptive": "457f9224a13240dde6e6fe6ee4e66cd8ff8a864f52075e8069d96656f98f35df" - }, - "sharded": { - "step": "fc2919966e0774ee015aa0a809337e118a6a478b71cd2e6daa4de2a43423ee93", - "step_baked_params": "e2a64269916a1337278c48d4708b5db14707be07e737a43a87e621d19a14bc31", - "scan3": "e237452cf5fe0e0ec7a383cc5c14a9644aed458258dec1f4bcc74b8dbfbb60e6", - "sweep2": "f2b7113dd3eedf32aea01851648d6ab7e3044fb993bedb9910b44dd04deb1620", - "adaptive": "daf1b6619b10be39f8c26e6a2d9d4fad108546e45d9062e1574680a5929fd193" - } - }, - "0.11.0": { - "named/chain-into-ring/choice-0": { - "step": "c456daf56c7221f1195621468c8b84d7d6ede240e2f051df4fdfc5404f547a8f", - "step_baked_params": "99d325e6b6561acf42a781e208ffebd6a421175fd8ad09bc77a09a8906f67c6a", - "scan3": "0358e43773f5bdaff31101f2c661210ae562ed6dc00dde5f4a778dc32fcc5aa8", - "sweep2": "dbab6db649335e6ff81872df3f174e682dce324a379a79a763897eab3bb207cb", - "adaptive": "7d1c7e1b579ec758e8cd1fc261d2b84e78b8d54fd8b822c93b92920c9451fc61" - }, - "named/chain-into-ring/choice-1": { - "step": "01b6db6024177a326cbe48dca8bd37314b3fddfad1b34af9c752726219be8e04", - "step_baked_params": "e4de1dcd323a25808801f629b949205a1bd9723fb324a27744b4611e70de1fdd", - "scan3": "7f8bc9b0f6d0e0f59140c6c201b956b8833340089c8da01c3c60ca2ddcd7ea89", - "sweep2": "f2e91633aca375c0229de183ae8fb412635301b5fcf2c3fec49f53ae139a2e17", - "adaptive": "c3d949100668a7646998fb4aae8f48ee51ef6cde017684bb7f1751d7c4939437" - }, - "named/nested-loop-additive/choice-0": { - "step": "7b69d62c10bd2f5db6d9b22e566d0bfd7b55616e94f90fed8ea94bb1656bf79a", - "step_baked_params": "ae462bd8a3bc53060ede4e76e71a3cd00f58c8f3d0c79fed38ffa7a388337405", - "scan3": "65aabb6578bcafcf829b64472bf84b148e3d5a7aad2e755dab0d072e3d1b699a", - "sweep2": "f0ad6217fb2cd1dbb97e570c5e63ca2629bda17c086c8e39f8013dd477a97e88", - "adaptive": "58052216f9e3ea0459349a3c8df1317809f93a540408d5bc3d4b3b129ba3d3f8" - }, - "named/nested-loop-additive/choice-1": { - "step": "00e6a6ede91913ad81297d9314a11beb275c82d8450b198f3ea87f406ac3bbaf", - "step_baked_params": "0dce69711b34afb145e50adce6bf2b8148e179dd4eafa14b339cf0814654f6b8", - "scan3": "15013f30c4e243532abf4a9e08c78376d52f989c27dd520e77376417020fa7b4", - "sweep2": "331b3ef42b1d9e703ad1a4c5ca22a958b7d6aacb66e39cb5d64646f4aadc0307", - "adaptive": "a1fd90b3c307e4241c7a4a2fb6cd6411c76d8ab00a68b385e9c869a5d9d9e4a3" - }, - "named/star-and-ungrouped-ring/choice-0": { - "step": "c0b915612684825a05489d00a08817f1380973a46bde1610d8823499c988c364", - "step_baked_params": "7d5264c7396c8a765d78f33f579c82c6e0b9896240b7610a3beb195f7afe5d57", - "scan3": "a71976504b24e74ac4bdb205b1eccc0f4d663bccbd59c7ddb0c8baa9d492b201", - "sweep2": "ad9a67937e26ff1da737f8ffc802c732822033968e071bf639334806d7f011e3", - "adaptive": "51c45d8d05899b2e0fd57268dd5b4ef30675d549ea27a7f76cc89ccaf6be5728" - }, - "named/star-and-ungrouped-ring/choice-1": { - "step": "85bc745a6faaea0ace3b4f2ffef3c8e2f8cadac4359ac3aaddb0ac9ff33426da", - "step_baked_params": "8387c4541894157333b14b7c284af8a5a883484b633f8dfd259ab0d2b0c5c5f2", - "scan3": "f0dc6eb7edd920677a89ce9079948b064427286680ac85d8ba8486e853e38faa", - "sweep2": "540c3e575526954d43a53fa5d69e1ddaac100bd12db310a15cacfde5c0a87aef", - "adaptive": "6649c1eff42245fc745de5e72e9be560928ad39833bd671567ad53b61c7666c5" - }, - "named/two-groups-one-scc/choice-0": { - "step": "de2bf4361c015c611d5c3559d30e084004de1ff6b1a13809137e452c0f3fa5a5", - "step_baked_params": "67b2235bb6222e4d7ad87899da2e417a2ea835f9a9891ac6d0d506241cd36927", - "scan3": "87ec1a0b7d348f6e8f650d34dc6fea2c0279b28bdbe74ad720362b72c9c63af4", - "sweep2": "54127b2b36338f077a1e3ff874dfb0044d0eeff0310eda63b991ef9f006d1814", - "adaptive": "7d65aa1831bba00f322798f385f09be034fe23374d1109e159e755fc0448149c" - }, - "named/two-groups-one-scc/choice-1": { - "step": "8817a7c929fffb075d52a5a365a6278a457679629827e2027febf1826416efcb", - "step_baked_params": "041159d782be38dac007ce2c1762b1d4b317583c37f59485487899328935f9eb", - "scan3": "2774bb2df2e0a7ec190697fc634d66f3c56068e5dd55b5fc854ad443d2c52eb0", - "sweep2": "92eb0e3282e9b07afaeb13b32bec7aa1a056a1037d660903099e870617e85ee9", - "adaptive": "85a0c6e878150ce0471c2e7d3a37d7540904cb3dbf84d43c6d9e186afea48f76" - }, - "sparse-ragged/chain-into-ring/choice-0": { - "step": "49ecc7671f29e467413807306d8ca7964d115ad126ab41ced0a5d07147295142", - "step_baked_params": "d0af828c98dd316acceb65309057fbf1a243c4c4c90da871fadffb1357476269", - "scan3": "2505f5d6092d9ff3f35e6848642fbdaaf50c04e6c09e53a96b0b637ea9694694", - "sweep2": "f07e9b0e06577d95f029ffcba1578017deb2d6d70924d2bfa8a65652eba4281d", - "adaptive": "ddf88ee55192e45fd04762543edab29fb83648879751f827f17ca63f97566a44" - }, - "sparse-ragged/chain-into-ring/choice-1": { - "step": "9598bb4b169e74a4802b31fd93ae6458e6a6e3cec8b86df18bebcf501abb8c99", - "step_baked_params": "b9941b1a315767f73ff7a43dd71004e65b25d9696df7ea3eaa39cf3695928a91", - "scan3": "2c791911ddcf669a2a3d884a96774d29e822c8a629a8b2a64dc5c1fed977eaa1", - "sweep2": "f6697b746e136e3eb057b8258538f5568d9e598aa2e71d4599b1b3d7d807fcaf", - "adaptive": "6234e8e096f630da3240b96bb7b1b5cd58e24c354034a7a590f3d95236303138" - }, - "sparse-ragged/nested-loop-additive/choice-0": { - "step": "6b794d10b9f080320e4d81f107ea78f41abbb06f09e2302fa7e4292ac2c8b602", - "step_baked_params": "67719515e92484c1a04675cf72583aae68baf70b711d80fe81dfd5a764ef2581", - "scan3": "f1b64eecea0e4aa32f0a7c31a296b4ade29e5695e1941db27204b180813181f1", - "sweep2": "bde3ed654029105b12f131a8968515763756fdf2e4c9845e829aee19628520c3", - "adaptive": "86613fed7d196e64fa42e3c7f8cad689153fcc3a3ef36bb8e90dcf6182ef62b7" - }, - "sparse-ragged/nested-loop-additive/choice-1": { - "step": "0d745682d9769f60ef6d3ce48c3bef2a22c830c4cd7c27dabc382acc2dbe2e6c", - "step_baked_params": "60974bd550e9c7219f85b7aa8a004e0f71cb38e26b1ab9e53b1030d3fa77d196", - "scan3": "94dfa3376fc1e4fd759bed750268e63d99c2eefe9a1ad70529423cbfb0adc514", - "sweep2": "66deb06f08296e3379b4cbbf61f263dae89f73ea61c4f53d5632f0e2c14645b0", - "adaptive": "477e7342ecb4f6afcc414c70522ec00c21c2cc96908794b9d8b78fbbca9e60a0" - }, - "sparse-ragged/star-and-ungrouped-ring/choice-0": { - "step": "3401466b54108785fe38f98a9267661dcbee7bd9ca56f8e9867a9119a28c7661", - "step_baked_params": "f075e1c195092d4e1a0bedcb19c861fedde8c914e5ac58b0ca3c5495d6411b34", - "scan3": "a0aca1a4896f929e74b226bc17d16f4ee9ddd8d0f1a7fdd97e0d2f53f8a6b3a9", - "sweep2": "39d0cf74730980a7b04f36aedcf16b82246f7ca91d1238f0982d43d63e6ac74c", - "adaptive": "a6f8c74c9f60fec9fe4ceb83513d433301cd62725aa21ca0bf433ae6c69233b5" - }, - "sparse-ragged/star-and-ungrouped-ring/choice-1": { - "step": "260ceed5906c5b6105676f3fa00b9b4b65b2e0e227639a7fe921c0cd36ed6a63", - "step_baked_params": "dbf429fa392f749994c2836866063c05eb0f694afe171799a9d6b1b453c110a3", - "scan3": "78a803a76397f89814beadca908296caa508a2487cfdfac830ff218634175f41", - "sweep2": "8d007ed7c32facfa097d3e4c842f59e3e5516775c82a5692eb4c69eaf3cb7ea6", - "adaptive": "3d912d5ce69ed5763fa7f7a29b1cdd708a119aa2d26b3288b04d5faf26a0b999" - }, - "sparse-ragged/two-groups-one-scc/choice-0": { - "step": "46e2aa87979618f7f0e93704535322e2feb6cc27b85227ee4462f84a96323519", - "step_baked_params": "bb9cd8fa1f7a5cb1da0fa8d464112b8ff0ca86567b9be56e9912095aa012c77b", - "scan3": "24f8ac9207107de6870aed938f90b2755aee07cc85453e1b3f45e405631f4ef2", - "sweep2": "e65c27980129ff6dd3103d87b0f867aadb93747c51e4072025466d6accf86d13", - "adaptive": "e03a8b99b7b77f9443657ce186e0fcc1e1ac00edec03161ffd165aa5904b88cd" - }, - "sparse-ragged/two-groups-one-scc/choice-1": { - "step": "4ca011662febcd04f6382ee4e2c109ac33611608122f0daa4e0dd612569b43a7", - "step_baked_params": "f7b0f3f6f5912a1a32fbc6bcd8b82db3358da9fb2910cb28dfc1bd48f59c7989", - "scan3": "2e9f95e1a84d7424df5a64c25ea82322a091153de88ad3faee47687534f83c20", - "sweep2": "35ad03140e4df8e66915700099f33e208d4e8c80b01561ad38e3249d836ff412", - "adaptive": "f0dddefbf2725bc3d156b07502434042da1f8c3a40cce9c84fc744decc86929f" - }, - "sparse-scatter/chain-into-ring/choice-0": { - "step": "b9399e53bd8a9748df5c86d6e2e68b97ebd3ce07889654a2dba6450f10322aa2", - "step_baked_params": "60573e556b0758820d912a312125c5e99affeaa753c399dd39a01e8821b8800f", - "scan3": "29b00eda2cd05a0572ea0380188a09a569fa07b7a471276c56840891cdfbb2e5", - "sweep2": "ed04f6eaf225cbf025e2e6b353d2573c172b3e51e31a1df34295ee05be664503", - "adaptive": "f018373755b63f3e051634fea8eebe32f967ad7452034684d97ed618d5bc2139" - }, - "multi-rate/chain-into-ring": { - "step": "f2cd5bbdb53f9bee25427dd3df4406bfe4fc4dd407885434ce9ed1400fb7bf8f", - "step_baked_params": "8bf34bf6d51e9492d16ee29fe9c60c466873e1514886ee565d21b19e867ffa96", - "scan3": "08bfe7ebff284dc336aeb3729d6c0be647c3a64004cd8755b53c8e261995d229", - "sweep2": "7bb6c8dc768d34e3736c141bc220cda81646a92bbff10a96eb9d65c036f19e17", - "adaptive": "ac9167a6bf59acfa231c862d1143e7084f255c39d240c06ead637030c7c72da7" - }, - "sub-cycled/chain-into-ring": { - "step": "cf19bb9b7e6c1b679da00460b8447be6c1ffc347dfff60575e286ed93368487e", - "step_baked_params": "02b4f30fb153fe4aa0d2a9f8795beb80a48ff83ad7d100a275c85cc0c61c2c9e", - "scan3": "e8ca6edbd3f8ac2e070280825e45d6276831bd48f5618f13936376f21221391b", - "sweep2": "b3da6331316714ce2becf364fdcc6b9a1e79f1e6b731ddae63187249d3b24a2f", - "adaptive": "f1a3faa544008d5e0bdccca1fcdf8676816c828f77a74e82d2b5d48a5ab1706e" - }, - "predictor/chain-into-ring": { - "step": "aa161151d0d9aeff8eb52b751165de8d9b1d954ae4cbc1da8fdebad57657ead0", - "step_baked_params": "a1649c95f4e1d8a3558280b96b2200961f366f15778bb01b43ddb5142eb28df2", - "scan3": "c1e358c862759c483b3432f4ce5c0f6ed98760a4d4f901e39ba5591e6b968f5c", - "sweep2": "220c708c5fb2172224ff022d6fb30f6d6e0b5bbf1d6bb6f70198ca2843c388e9", - "adaptive": "74d3979f83bd350af9850c6daeefc55dd7f27dfab629c0fca2f2244fc9c9a144" - }, - "aitken/chain-into-ring": { - "step": "acbafc4b39f58a1713032790586049359dd5f5d6235793e1abd15f0ded213e83", - "step_baked_params": "8bbd16abbeeff5cab027c96520c409a019d35d2834867c1c5d65d22ab4ed8b18", - "scan3": "a423e321f18ecf23ede76c866744e4dc035ba0e5210722f6150a10aae8e00c14", - "sweep2": "ef8e22f97604446011737596f6e2a81b86611b2645826c77f3c2ed83611ea3df", - "adaptive": "a6e312d4780ac2308b80c3462e1508c51ec0ffeab124be242e4a6d2366c444da" - }, - "flux-outside-a-group": { - "step": "fb8a0ebd01f3b0e896e6790ec734332262ec7528bd270ea676fb23baa4ba103e", - "step_baked_params": "b5af89027eec5b08304e0bf146a0c0d5bcd706dda99ab24a3abc1125aaf8cc3a", - "scan3": "d800e3550d086a53cd5776d6c0c9c20c1faa52b7f28d063827aaf19c69d8751a", - "sweep2": "e639020358b8a006022a32e2024c987b21f5080149298fb44d82d9b54397f048", - "adaptive": "ddf0d8966c2cce3e829a3bf35c80d02301cf054999d9ad1df17d6cc0f71bf85e" - }, - "rbf-edge": { - "step": "ba518ff7a8f2fd5780dc43103b395dc98af157ff655e904443ae6b8a84b67952", - "step_baked_params": "1df4b758b8feddd9720b64218d6f8bf4ca58b926e3473acb2ced3d50aae2bd37", - "scan3": "1486b3f8c181abeba43949623d0dcd90af6c8a3b259ff1b4e33da525ec777de9", - "sweep2": "27d97e1fe18aef49f3996299a2c2a59d3ab486d0b29e91df433eacd151c091d5", - "adaptive": "457f9224a13240dde6e6fe6ee4e66cd8ff8a864f52075e8069d96656f98f35df" - }, - "sharded": { - "step": "fc2919966e0774ee015aa0a809337e118a6a478b71cd2e6daa4de2a43423ee93", - "step_baked_params": "e2a64269916a1337278c48d4708b5db14707be07e737a43a87e621d19a14bc31", - "scan3": "e237452cf5fe0e0ec7a383cc5c14a9644aed458258dec1f4bcc74b8dbfbb60e6", - "sweep2": "f2b7113dd3eedf32aea01851648d6ab7e3044fb993bedb9910b44dd04deb1620", - "adaptive": "daf1b6619b10be39f8c26e6a2d9d4fad108546e45d9062e1574680a5929fd193" - } - }, - "0.11.2": { - "named/chain-into-ring/choice-0": { - "step": "262df382d7c88a7667c5b9477e06ac6adbc00abadb14fad54756e0673ef59073", - "step_baked_params": "624580ba3ef58d4484a41518bffb7173875d28c93b4c7fe0c228dfcad8e5e0d0", - "scan3": "3d4b92087f8c3b8497f5f9324f7eba933b98c99134dac786b99b7fb9c0e105a1", - "sweep2": "07d7fe9201106c6f6841aa4dc1a6f6995da1f49f3a87513a6a0dee7e062565b0", - "adaptive": "234b41942fa7bdf7cd6b7f8160be851fee3693a3254aa5f32b4398cf0140e191" - }, - "named/chain-into-ring/choice-1": { - "step": "4155b9cd7011f083a50322d86f75edd0d645623e0129ddc3e5e0205a17691e4c", - "step_baked_params": "2a0a66a847e81bc69961c2b3f299fe1273e0fb5464b5cc44bf7fb54aa69de4d2", - "scan3": "f745d03f395390f5b06d7cb78a9c402bd0110d7b0aa42467b53dc21c4e612d21", - "sweep2": "b8cc8ab049bbd1191d6d39d2052aaeff3898cd59107c94c6a57a28e3e4315d06", - "adaptive": "e8d21036c4c384c8e41549ce144636338298698e798d3ea0b8d9ebc74f7651c7" - }, - "named/nested-loop-additive/choice-0": { - "step": "01fec07edabf64fe40d2931e09b093810e7bb5dcc91177ca590783c467ad616e", - "step_baked_params": "04bc2833b26c152d4ec9ecb37de2b1ef95501dbb658fa0060dc4925ee131d589", - "scan3": "25d2d29e96fd5ae28a88e807c5125187c6e5e05982ee6c73cfc56dc382afe71e", - "sweep2": "91aefe031ece79673297e5856d5ab6b1546d76862bd457088717d7132eabbc7c", - "adaptive": "e3b66165c26db01e498776630ce7bcab79cc972407af207935976ffb77400bf0" - }, - "named/nested-loop-additive/choice-1": { - "step": "6bffa482acbb2c5f037d9007305c0460767a891984a322c853ea4193da6a9d61", - "step_baked_params": "c6c97af04e388640af722d7fe9135aca79e81ca8a1e11ad9b4c592dd442e64df", - "scan3": "b3bda7a2550669a9cd6a59384b26004116b66f0fe9332608988a625931e470b1", - "sweep2": "3f5d0146a644c603a06cf3a8be5f2747fccf37f0aad29fd2ee934a15653e0ab9", - "adaptive": "19ab5946c631d363afb4086298387cc661a461234a80dd132b5e9b37363a0995" - }, - "named/star-and-ungrouped-ring/choice-0": { - "step": "502e0ef19debc7197d506a1000174568869e416c7a9e2047379fca9175b3143b", - "step_baked_params": "119a7caa35db55c0fb5c90857a4d2441f67a54b8319957297cc864033f399c38", - "scan3": "006ca73c903e0452852ab46ec104770cba10af5ad0fab155a5511305790ee50c", - "sweep2": "d8eee601fe0402302678b532d72fb4d9c32914b4efff2bd46986bd0db40ff888", - "adaptive": "4acbaf0c3dec63d64cfdee27df0ae81424a8df7694a18c4ad33fb21aa5e0c075" - }, - "named/star-and-ungrouped-ring/choice-1": { - "step": "c29c2ab83b82ff81ce0c07793e4ded64d5a38228d606f4bf0fc9fd31ac75a77b", - "step_baked_params": "4532b90b13738efba953febfc8379ce94ce0690bdd2f36b44b1720e504c9dc38", - "scan3": "ed7f1a4552d335ff9cfe14e5dd2574e2530816d154f9aae4248ec6b9ef4f236f", - "sweep2": "2f9f5c06e497cc6521a7280733be8bc67057ba640527c5f02ed6a6b7ee5ad3bb", - "adaptive": "fa03b4f40b51f282f17ede7c6be2dd4d9c87feb10457a7c42adbdc3d774a7319" - }, - "named/two-groups-one-scc/choice-0": { - "step": "42289c549bec4577eb4c1a4d68d15f0e9e85cd1e8e1709cff21c11f51e5e07ad", - "step_baked_params": "cc70db4db1788b8eb98c3c69ab1c6e6512543597e87615f3c0fd990eafc6b1d0", - "scan3": "f0bf6cdf16633bf6855f15045469317c7e74cc3dd0188abf8a5a979817d536cf", - "sweep2": "c4db21ccc1d1c5ab0a2579150555a911d2e74884c54de84c6ca8d0abf71aa64d", - "adaptive": "7e820315e3e03918349d881be2669c9edec6e0be5947c027f0bb429cd76a0032" - }, - "named/two-groups-one-scc/choice-1": { - "step": "c61786ca25d09b308cacf975a31db85477938b70aa4b1e51b0d15280e91f9f1a", - "step_baked_params": "ebba5d6fdc3d361846429454e30ac11ded49f7f3eccfb0947016642e6a281b68", - "scan3": "1e6c9e5d390e46851a48016603c251bde47c1433c96ffbd8eb03eb5f9b726180", - "sweep2": "b4d2f47295f7f78aa260f9e189b63a7e50850f00506e27d9e6028ff4cebc22c6", - "adaptive": "3cd4a8afa0e5cc9f5842bc4798f73e9a53fd0ca5fc5f49e86d61755239f7d0a4" - }, - "sparse-ragged/chain-into-ring/choice-0": { - "step": "b92003aa6ad49b0e3161e20471e48bdd3c125bad9164561602f7addb9e735b22", - "step_baked_params": "06b6378863a6d48eca29323badcdf9098b075f87f9264aa66a9f1c24e37bd715", - "scan3": "51b692869fa3517edaedc95511d23971d89db3ba40dd0f729c85411a401efeb3", - "sweep2": "f3fede8a4230024c0d6d2e41c6be6bca0b010c64875f3bcbea47b3eb6066844d", - "adaptive": "bc81df5b3b1cbe83b00df7aed82d603052a82c48ad7f9acaff5c0dd689884601" - }, - "sparse-ragged/chain-into-ring/choice-1": { - "step": "675635c3f1eea095d5e8c969b664b0bc30d59f78aff082ede62d13b34762f210", - "step_baked_params": "7a4ad33b4852f72d47dd84f8109fcf98f619ac1bc37e21d13a206089d1454454", - "scan3": "d3cb3de31189fca190d605ba8b5ebf9084f8390e2a301efd2db97acaf1eda3c2", - "sweep2": "07a367b6e6d61a798bb6c74f72ce37e7fb9169ef84bdd4db5d15f748e9709807", - "adaptive": "c591acfaf858bccfcefd5b874b8160d3a48344a27ca2dd1327a9da3d9fe403ea" - }, - "sparse-ragged/nested-loop-additive/choice-0": { - "step": "27286d2a65cd06297a55b662e0a18e9eba14b2312e27c17da652d755eacd8b48", - "step_baked_params": "0430140a66f08a6acb499c6801506412f21eef47379719d10c097b4d30e97381", - "scan3": "07243ed35236fb8568c0516b28e61730ee6e0cbe191e9f21e74d4d58ddf1a1d6", - "sweep2": "e767e46e47a787dbab46a47a4daf72e7228e7caf3bdd3a4a007c2d32c8f07641", - "adaptive": "eeb25b5be26837d3e102a8977cfab1fccd3a4680bb68d4df34507cdaef88b9cb" - }, - "sparse-ragged/nested-loop-additive/choice-1": { - "step": "7e38cdcfdc3eeca3bf7cb9edd302d8cd7aebb0b6df594761f989362e04cdcb91", - "step_baked_params": "492b09e773eb47d9ee33562c8cb6e7d2b4ceb71960dab8306b7ba0f6f25ea419", - "scan3": "edf4a23adf570c674e77b29f0d987973d04807385485a9f9c0281fceee899587", - "sweep2": "e24b28ce3420c5524a4627dfc6ea8bdf83c1cf6b2bd3cb90670e6b7161096756", - "adaptive": "4875976071126180713ec4df7d8105b194500618bb75a40dbf60afa456589e42" - }, - "sparse-ragged/star-and-ungrouped-ring/choice-0": { - "step": "cddf8e836c78e8f192f0b69b57f435efb8abed26feac5b47925944a16399d0ae", - "step_baked_params": "6669ea3deb2e275dfebdfba173ccd2ce7f5c7b7af3707c3e8e084a5e3598cd52", - "scan3": "92a164083d76e2776574d684eef3b525ab5d90b504d8fe81808575775a77f588", - "sweep2": "a3b7f509332279025c64ca0821ad3c5ea5b36f18b7cfd62a8bb438e144dbf81d", - "adaptive": "7b89261fc6f1985232efd4cee63c02bd146bc6888354617259a47a37fe4c6a34" - }, - "sparse-ragged/star-and-ungrouped-ring/choice-1": { - "step": "9e4d48215c71dc2d7757d7159758279a43ecf52fde332eff1b822beea4ff518e", - "step_baked_params": "ac7307ab1c218f280b7d0e937f1acb0673fa60ab347a15fa746ff4df54774259", - "scan3": "eaf9c7c68b4de40060b669b3f9688efa535094bbc9a6c514c400b04508524918", - "sweep2": "94b7b5b622d95a367016f4ab6eb94b95fde81e9ad7ae11979ef45d20fd1eb46c", - "adaptive": "b6c6c44b3d95bf017e4fe11975050e7822922d6561be7def3bb7bfcbcc34465a" - }, - "sparse-ragged/two-groups-one-scc/choice-0": { - "step": "50d5420e5ca2a6d20e7fe14f6921e72bc0eb8e77088dc28bf782b7667041bae3", - "step_baked_params": "d2011425b1889e64acb030e20de1e694a79659b9716ee53b0f272f092a37d8ba", - "scan3": "6415f840f45657a261118e933f635274b78434291ed659523d968c701e46923f", - "sweep2": "0b86f13c5698f63c0c24bdadadef8a5f2518e02d25f2391e4490298011630a1c", - "adaptive": "a384bce06769bb0612058b92f58551b24fb888916314ff68256c0c2e07036eb9" - }, - "sparse-ragged/two-groups-one-scc/choice-1": { - "step": "d687e5f1e9bf5409013844859745527dac6e33f68446f9c34870d29a3cff2fd1", - "step_baked_params": "2ef22b934053cb362d6f102530359f0dcd47930a992c7afb1789642682bc79be", - "scan3": "0d377be5c0ac7508ded3e246298d1aef2ee2858ae2e4c19d787d23609cdf182e", - "sweep2": "8eb7b71f2850805309d2a27c28290852952ce4d824c02776f3f10d761f423bec", - "adaptive": "00a3b68776986dd7f916f35ebbc74d12141e1d317d1e20ed971af71ecf3083cc" - }, - "sparse-scatter/chain-into-ring/choice-0": { - "step": "f5afdf2ff848d603999e18927ee3161147b4b57ff1f9e81c2bd5dfe1239c3998", - "step_baked_params": "4cd2715862b80d6b5bacbf57c2886626e8b041d022d5c002566ba01736e05f08", - "scan3": "2560b4c1f77e09177e1691f73989025763d78409c6281001bc622a153d76fbcc", - "sweep2": "407471592c47206d27670ad998f06f4f919c4062233fae5d99758b1280880b00", - "adaptive": "4c1b09c5c464ed8ce9db7d9697633305864f06397ad737c301eab1ab23c24b3b" - }, - "multi-rate/chain-into-ring": { - "step": "fd7656017b77152a7f720a16fccbac00537be42075bfa49f42c0a6d78f854a5e", - "step_baked_params": "87b47231944e15749b47500028706731e8635369b8ed2779b0033c4b77c08db4", - "scan3": "f473941cd4a9d403d70e20176b39afeb4d56ee1faa42e49e16adddce8244ebbc", - "sweep2": "565af502391b07d59942f074fd0bb60a0b4961754786ec62b9406755c621e916", - "adaptive": "96998d76a5420dc2a97b3b45d0c1376f524d7070f48fcee2577d540864c3fad3" - }, - "sub-cycled/chain-into-ring": { - "step": "1427d2a1beb43643564660bd3fce17370061670c375fe8d90a592e4300876d62", - "step_baked_params": "f9fb84ec3531e2711f239b5191a56bb701b25fd67707f68f929c8508c6db35c4", - "scan3": "aa40608ea5427e4a820bc792142c33d7d41fa1d0c19b35d708fe8b9e22cdd729", - "sweep2": "9d31243b12797aa4f530ffc494efc757d40248691411fadbe60c1de7c48dbf29", - "adaptive": "25a9fadd9972341b28d7eded82d8bb37eed5845d6ba3987a9056d6ca5588c361" - }, - "predictor/chain-into-ring": { - "step": "5694689b7c80c9e70cbe8406559f0135ac92f7a60955274918f069c99432761c", - "step_baked_params": "7197cdabda90583a3e1fb251a94355d16cbc829a2495fe49afae00b7a7d17b6e", - "scan3": "e6b5392cf79a4df6771ab33ff4455e7777d36846121a09922c0e88ad9ac7fbc1", - "sweep2": "22c982d9bbb6b01fa60b2f9d7c64283fb14ddcdee5f4cfe9d878edf7978728c1", - "adaptive": "474cbd67f43b5d3c753de5ff258e24a1ee647aea1688eb302daf64aadb014b7e" - }, - "aitken/chain-into-ring": { - "step": "5a7e72a1966638806d8695f0b5e9dc50cd99cd4e6fc38985947d7868d5e15969", - "step_baked_params": "b343544f2401082e3277ad547c22cf6e9c2fde1831b01a91f215fd78d2ab24a2", - "scan3": "b95df02a843c4c5580c43bb0d8f393bad91c91df2dd2b20a0b24a5fda2cbc2c4", - "sweep2": "e00e308f9602a04c2709b74f3ff986075e4555735aa8b60143735baeba5b05db", - "adaptive": "c60f74053c803deb53a00886a530155a8aaa158508ef1a2c4a7633521e6b8d78" - }, - "flux-outside-a-group": { - "step": "fb8a0ebd01f3b0e896e6790ec734332262ec7528bd270ea676fb23baa4ba103e", - "step_baked_params": "b5af89027eec5b08304e0bf146a0c0d5bcd706dda99ab24a3abc1125aaf8cc3a", - "scan3": "8727d0f591cca017e225181cf72f4c8634465bb9f378a96cbca684d39c851ab9", - "sweep2": "8281f01b57f0e2641580454838d9db3c805b58151760687a6f6d0960c0dc3e0d", - "adaptive": "ddf0d8966c2cce3e829a3bf35c80d02301cf054999d9ad1df17d6cc0f71bf85e" - }, - "rbf-edge": { - "step": "ba518ff7a8f2fd5780dc43103b395dc98af157ff655e904443ae6b8a84b67952", - "step_baked_params": "1df4b758b8feddd9720b64218d6f8bf4ca58b926e3473acb2ced3d50aae2bd37", - "scan3": "27fe9a91bff92080f06110ac09296157328a7c4a4970875286f214ad491b86e7", - "sweep2": "c8c847002554d775be7d21c218ab9786cb79188f0d988f65d0932e4a67697f68", - "adaptive": "457f9224a13240dde6e6fe6ee4e66cd8ff8a864f52075e8069d96656f98f35df" - }, - "sharded": { - "step": "fc2919966e0774ee015aa0a809337e118a6a478b71cd2e6daa4de2a43423ee93", - "step_baked_params": "e2a64269916a1337278c48d4708b5db14707be07e737a43a87e621d19a14bc31", - "scan3": "d5d69245de829fdf1858d4915b147678bb27062ae478b6df861987da0851f7ec", - "sweep2": "f8bb8ba0d1872b0808b3caf8a0f1f7e1dae353e575d3608f61827bd7391b5203", - "adaptive": "daf1b6619b10be39f8c26e6a2d9d4fad108546e45d9062e1574680a5929fd193" - } - } - } -} From c3f10735e4cb8e457ffd34171584c75309d91fa9 Mon Sep 17 00:00:00 2001 From: Nicholas Ehsan Roy Date: Wed, 7 Oct 2026 07:01:10 +0200 Subject: [PATCH 09/13] test(coupling): recapture the step programs on the IQN guard's commit Captured on 457f4b4f under jax 0.10.2, 0.11.0 and 0.11.2, each in a fresh process. Against the capture it replaces (396eb59a): sixteen of the twenty-four gate graphs hold the same digests in all three versions; the eight that moved are the choice-1 graphs of the named and sparse-ragged topologies, each of which has a group under acceleration=iqn-ils, whose secant least-squares now passes through the guard. [skip ci] Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013UkCde7g23gTziUjYAvnKD --- tests/core/data/step_program_digests.json | 516 ++++++++++++++++++++++ 1 file changed, 516 insertions(+) create mode 100644 tests/core/data/step_program_digests.json diff --git a/tests/core/data/step_program_digests.json b/tests/core/data/step_program_digests.json new file mode 100644 index 00000000..064c1843 --- /dev/null +++ b/tests/core/data/step_program_digests.json @@ -0,0 +1,516 @@ +{ + "format": 1, + "commit": "457f4b4f4d6812793621a48253acd7a106bb916c", + "captures": { + "0.10.2": { + "named/chain-into-ring/choice-0": { + "step": "3d95c94bf7cb1d724447fb2ac3cf681c57b896b981b98a66d9da984462007c76", + "step_baked_params": "6c037930cce262f23178056accd7f1889d87d219651e5d7067006abe13c03154", + "scan3": "d7ae0aa34da0c97a725138cf5b3a7da4d45925e5f420f4b57ee7c56eda48b04f", + "sweep2": "42ac7f72789eb69386d994718402efbbf1849867f0a0f8ec67f600fabc95a0ea", + "adaptive": "fe21f8305b5cc8c638fe5def9d1f4dbc1fb090dbef131b3fd150a3137719a9ed" + }, + "named/chain-into-ring/choice-1": { + "step": "21ea3c5aea3f57ad56ee92e97df7be8c94ff65116d0739e6a2717d682dd1f903", + "step_baked_params": "216f3d98e7f1f9027f9f6ec2d09a1b379dc49c8f829456c71474c913a35d85da", + "scan3": "2c70e93be8b67d8db78156296fd23d78e4c921d49ccdad3195efef7314b61a9e", + "sweep2": "75840d207dce7c67404812a52b095a11dbac0c91de331c0b906563ba0e44a575", + "adaptive": "d243bc32568dcc7a17723f332c47e7481a21f5044c621f9008fb0b55474c8abc" + }, + "named/nested-loop-additive/choice-0": { + "step": "bc54ed660d1254db887726f5f6820d60306fae3e69505c96ab594c58b1313d77", + "step_baked_params": "63b1cd68da4cd95ad453f7940fe2fb8a8c8831cba89fb6f071fbb57e90dc1774", + "scan3": "410c4e8ce3a77a282c1491625405a30e1311e3930283084706f04b5f913e799f", + "sweep2": "fb2ef9f0dc59d4a293a0b79274f33e77921956214be520d5a179d3f2289af788", + "adaptive": "59f02fbb799870822b260824b2089103d0b16f3361b5150b781635748d7ec838" + }, + "named/nested-loop-additive/choice-1": { + "step": "f18bd5bdeef573808aeae9d58fa2c3fddc6753d7546b506e55e530eb6745c8f0", + "step_baked_params": "1e5892d4771a877878b42b832a540524d8cf88e3926bcfabcd257d0a6361f80f", + "scan3": "6531a126389fb4c53f7928e99feef7ee04ec7122f8ae255d5b64424b86016f69", + "sweep2": "6267788b48f0c5c0ee5b42cb76ef20d899a004e98f5b60ca539596f45755bfad", + "adaptive": "691fd2085620b37ffe096eee9b1d30afc7e6eb9ff0a906f4233cc97a69cd48d3" + }, + "named/star-and-ungrouped-ring/choice-0": { + "step": "980568cb12b370111642d74d21c15be3d144edff05f21504ac299e1c810b840b", + "step_baked_params": "05cb43132e2b16559d02b69b8a68f652d18c4e417ed82bb15b982a68498d4680", + "scan3": "d03a7504bd2cba695ebd9e88d806cffb17f929c361ca4aa2d6a78ecfca59002c", + "sweep2": "b31deb0b0b45c16ff2cae5cf4c2ce18e8946e5f43073c2cf109835f29fb56cd4", + "adaptive": "4ec3b069cbcd09b787cd6c512536a5ded358cb57426c911744e2b8dc1443daed" + }, + "named/star-and-ungrouped-ring/choice-1": { + "step": "bf5645ef9c7f12f8389aa171fbc8468cc47cc912b7dc01425f15af3336a20cfc", + "step_baked_params": "d06643d290d2a7f16750c45884fe5c8429d75cc196e810b46403002983cc984d", + "scan3": "19137fa448ba993e785e8ede787aba989de1032999ba9e49e41a8170ee1ed29e", + "sweep2": "6a980f59154cbf564049fd0e9206b1169c89ef3d2588e68538b1486d07d4147d", + "adaptive": "f15743b7c1937f73db4833d2b2a28156cb220e0e35d4a9368a96c0cf1d91639e" + }, + "named/two-groups-one-scc/choice-0": { + "step": "ef8ee10d5e2e8c0ecb89ae3ca685e15c035178aa9645d76c04c6dfdfe5796c25", + "step_baked_params": "fdb9ba80076653f8b0a79554fdf0481ebf7bd49a5d0796e45dcc43aa6af0c2ca", + "scan3": "cc5606fe9145f8b2733749e4d1c4d8ffe5eec83ba97596b2662ea39312cfbd76", + "sweep2": "0c3c2fc58fbb0fae5f145cc6c6bd907b860f70dd096c5b023b0d0a54109b436f", + "adaptive": "7ba3d0184e141097cba3bc9ca47753aec687a800e9f8600f7d4d3195fee490ff" + }, + "named/two-groups-one-scc/choice-1": { + "step": "d890fc8ad99a2f0af85355ff123c8b46215f54862c1594003f1dabad2f585383", + "step_baked_params": "eeb49e56c876d6277dc3ddc5694651201ddf420be1e152a6d3d1fed00f1eea35", + "scan3": "50d3a9fafa33a8aa464b663ca7d90dd20fc1e4aafbec39f5e3295036f123f31b", + "sweep2": "a1b464b969486a4c2bca48ffea1c1fc2582c2bc5da74017de894af9af44e1796", + "adaptive": "e3d7883ef1e1b68bd8471517d87a41f26de459415a9dc798db766f0f02e9d41a" + }, + "sparse-ragged/chain-into-ring/choice-0": { + "step": "a040003c3fab4927b422ab355351fec717edaa18bd319892b9ae213b4a199d69", + "step_baked_params": "25225aab6b9a1f91a0a59fadd1e02407c57a3b06da119d91883473874f59f07e", + "scan3": "360467fc02792d8560e53c7964e2f718eb022dee0526ddbd3eab7e9922edbd83", + "sweep2": "8d9a2d28c417a3a7537bc479c4060916a762e22a1e6bad9eb0badd5abab6da57", + "adaptive": "ffdfb67740d207a524fd229b14a2b411ac844f290ce530a90e0d1373d95ab177" + }, + "sparse-ragged/chain-into-ring/choice-1": { + "step": "c71672d13b27752a22787a0446b8a464062d75704c6cf34eec42ce0d87982afc", + "step_baked_params": "ec891ec371b297c12b6dd05f4302bef1bc54b3abbb7e3ad37b89631965583604", + "scan3": "37c0ff6a144576cb3fdfb2d41bd768fd555c50c1ca16d5543300df022a09d2db", + "sweep2": "2290b389e310fed5fc5a1346a71eea7cba2cf8bbff5bae5105a5557d946addbc", + "adaptive": "4e79df556a76951e5bdf80d03acd28616de751f45bdf6915468729b25b4564ed" + }, + "sparse-ragged/nested-loop-additive/choice-0": { + "step": "c9c9e4f3d14a74453c76b80f591f9a33d967afdd3e0fd48842201069d1a9f522", + "step_baked_params": "0e7ec9ae3dc6b45abfc7205453c0dea0373a8e92372fa1b4b2548b78475a31b1", + "scan3": "08c37b700d554d462e1a15ffe8e1a95b7b963f3dd4c54d5ceadfdb69c0751f39", + "sweep2": "892c8fefe403d0b27efc527c5e4763552d009c95fe19741fbad8f0c9b475dd95", + "adaptive": "edebe0ecb0e53c5430268aa1f5ff1d273bd480e64810e4ce1587a26f94548bc8" + }, + "sparse-ragged/nested-loop-additive/choice-1": { + "step": "d4e9e9b92349b04d743461689a9a27ed6224201568ca9122c2cbf6db2c84c5fb", + "step_baked_params": "37acd8f36da5a88a9f0547ecf25ad80f6f573f7cc6a65921ecbb62b017224a8a", + "scan3": "613bacafc764bf004cf01e20f5f3623f413471cf526f90e1abd0f9a105277140", + "sweep2": "4914f46aec525bcf220eec6125b7ba6fb271a789f1309f5253f26e0e58674573", + "adaptive": "ed7f78a65da393dfd71c0fae5a32731ec0a60f1dbd96c436b9805ae859899bad" + }, + "sparse-ragged/star-and-ungrouped-ring/choice-0": { + "step": "fc03fed86715ba646ed87eb1d44b3cd7d4c97ea149447cac0f6bd55e8d68a2a7", + "step_baked_params": "e7377bbe13039184c7e7b18617a8fad28db3f8306fca00eb8a85a797d7b08f89", + "scan3": "ee93caab1ec01268410f764f81d53f687ca34fc2d55adfcea7c785969af29266", + "sweep2": "6bf68ca6cc53251766799a12a5e443324e060905e58b39aad9b1358907b4168e", + "adaptive": "e6a338e1a17c0945b57d3a1e5f1b179605eb880a5113c48a0058a9019acfa7ae" + }, + "sparse-ragged/star-and-ungrouped-ring/choice-1": { + "step": "8667c3457ea66983f23d4086c91c3cd3f0a4be7394b896f154866a365836a170", + "step_baked_params": "b816611c0301dab4e70ed4e557bd971df033a9528f585baeb65a9fad8a1dd5de", + "scan3": "f8d77ffe93720f1c6c42e20aa067a0ad41155f6cb719adf1654c36c4e9dc8cf3", + "sweep2": "b090089f95ccc36bc67a382db4bacdce09d3e5b67f3ebf8d8ccddae9d7ab2787", + "adaptive": "34a65d065068ca36ac77edc81758429f9b8973e43685aa92daa566235bd8a89e" + }, + "sparse-ragged/two-groups-one-scc/choice-0": { + "step": "5ff074bcafef59bfb21fb326e651dc7574ef1e92c93f7433d60858e71aad1c6c", + "step_baked_params": "770c180fd0d77898f846531f4c886eb43e0542f0dbfffe0a813ea17e398091f0", + "scan3": "1b763778bb09d6db147bad07240a7ef91e19e4c4b04938141e47f0ac38690771", + "sweep2": "dfe5eecda0ca401f28f0a3c6d09f2ab9537607538cf7fffc660cd152ac2623e7", + "adaptive": "a1b870b596f6f1d789113769129bb223280813d3dbb78df827db3fc490635ed1" + }, + "sparse-ragged/two-groups-one-scc/choice-1": { + "step": "5fd3acdd6b72d2c3f1c5d71511c35ae98cf5748b8f9d81c86d793c3cab777565", + "step_baked_params": "bbc1a4e40fbad5281915aa149f578938df1b4b0e87e805bbfe5737606a9bee25", + "scan3": "62d7ce14cac50f8abe0ce236f47495b6eaee7ac91d859328138272343b9ee696", + "sweep2": "1fae3755017f708e0dbcb0113858f8ed87d1fce283d4bc017429dae723b4cc41", + "adaptive": "d0d407a5455b498d112148ed3598b9c3d4307baecbd4a36f72dc9dd63b63363a" + }, + "sparse-scatter/chain-into-ring/choice-0": { + "step": "0a022a3c93a67d7282bd33166c571589f4b87b5fc51ee6d7dea22bf61ddd22ef", + "step_baked_params": "a0247c73d698a912a3704d19486248571db3639d0bfaae5c15f60f65a0bff14a", + "scan3": "e8938709e266fd4b7aa9aeacf8a05df71ad00895190fbfb65bc74a7b76e17552", + "sweep2": "9eb5a90f9350c45f93bb98ccd9c07131525c4b4d5c35dc9b9adf1a7e3b722900", + "adaptive": "29f57e5c7579d6e037e7345cb8c88bd7ed8bd82056e60297aeb5c54e7f7e97bd" + }, + "multi-rate/chain-into-ring": { + "step": "69895dc913f671ca3cb5082c4b665067ca83b87d7bd3dba234f60fe0a17ef77c", + "step_baked_params": "20059555ce1bc0163630111dfe5054e4914c859a182e9b68f2edc704493f60fb", + "scan3": "5c9186cc994f323f5961f125a2b8265f3ccb3b307b30dd6e372993fd4d4f6dff", + "sweep2": "f8a9c984e1a52d06f7a8b2c9e1a709e5bda0d108326e6254a42dbb6cf6972e09", + "adaptive": "2737b8f2c88af012cae6f00ee5045862d3a39aeac14aab880a7f0d06aa7694fa" + }, + "sub-cycled/chain-into-ring": { + "step": "04d8b64cf117bec39458863c429371acb8464ee5adc5db12b69be75b0d9571a9", + "step_baked_params": "ebe7bcd8d04537d4ee5c9c4d08389d2c5b841985c6c998be0bd8d19948a23a50", + "scan3": "8658aecbbce5dde6ab121164801330b6e4a07ada89ea98a67b569aa3af141f20", + "sweep2": "854321e855daadeb562f0936800c31c933f7e5dd8b4bf5531516afa661f0e4da", + "adaptive": "8216a3230af80d84566813cd4a797dac320fec64161ff9e3127d0a852e025188" + }, + "predictor/chain-into-ring": { + "step": "d19c185c46219e8d801851751a0ec004c75dc464e8bea924e8c80b3bd0ae5cc8", + "step_baked_params": "a548c0e3fb299a2e854fd6c00797f5692131f8e64375177d52375a04fb9e76e3", + "scan3": "6b223c1a59a1a83daae911f31b4a1372726b2e8f58d898f16b9e5f7e462fe145", + "sweep2": "5924ff438208c7956355ac25fb124c21cb2146694ebb6004e0058d8e6a4d784a", + "adaptive": "204433c156183477b5aa4849ee77a13a493d2efb968fc837234a0e33cbcaa555" + }, + "aitken/chain-into-ring": { + "step": "b27b47b2d049c72c3fcd2715958f77bd20ede34f6b2098ab5cd9ebbd34649252", + "step_baked_params": "ed5d206d3420447bf4b9cf6acfbc68f68b87301e9e6f1749b971332c2d09e6dc", + "scan3": "e22e3e8d685e845f4def058e2ffe8ce188ba49bd3e571b3800657c98e7761588", + "sweep2": "5996c073c6e4bbabead9cb0f65b7e5ba8ed9f1325815554a3e1d8b296b1930d1", + "adaptive": "80073b2c8f57c4389f65e21c79087cb5e6b700daf9570cf071a195bdb72bccd2" + }, + "flux-outside-a-group": { + "step": "fb8a0ebd01f3b0e896e6790ec734332262ec7528bd270ea676fb23baa4ba103e", + "step_baked_params": "b5af89027eec5b08304e0bf146a0c0d5bcd706dda99ab24a3abc1125aaf8cc3a", + "scan3": "d800e3550d086a53cd5776d6c0c9c20c1faa52b7f28d063827aaf19c69d8751a", + "sweep2": "e639020358b8a006022a32e2024c987b21f5080149298fb44d82d9b54397f048", + "adaptive": "ddf0d8966c2cce3e829a3bf35c80d02301cf054999d9ad1df17d6cc0f71bf85e" + }, + "rbf-edge": { + "step": "ba518ff7a8f2fd5780dc43103b395dc98af157ff655e904443ae6b8a84b67952", + "step_baked_params": "1df4b758b8feddd9720b64218d6f8bf4ca58b926e3473acb2ced3d50aae2bd37", + "scan3": "1486b3f8c181abeba43949623d0dcd90af6c8a3b259ff1b4e33da525ec777de9", + "sweep2": "27d97e1fe18aef49f3996299a2c2a59d3ab486d0b29e91df433eacd151c091d5", + "adaptive": "457f9224a13240dde6e6fe6ee4e66cd8ff8a864f52075e8069d96656f98f35df" + }, + "sharded": { + "step": "fc2919966e0774ee015aa0a809337e118a6a478b71cd2e6daa4de2a43423ee93", + "step_baked_params": "e2a64269916a1337278c48d4708b5db14707be07e737a43a87e621d19a14bc31", + "scan3": "e237452cf5fe0e0ec7a383cc5c14a9644aed458258dec1f4bcc74b8dbfbb60e6", + "sweep2": "f2b7113dd3eedf32aea01851648d6ab7e3044fb993bedb9910b44dd04deb1620", + "adaptive": "daf1b6619b10be39f8c26e6a2d9d4fad108546e45d9062e1574680a5929fd193" + } + }, + "0.11.0": { + "named/chain-into-ring/choice-0": { + "step": "c456daf56c7221f1195621468c8b84d7d6ede240e2f051df4fdfc5404f547a8f", + "step_baked_params": "99d325e6b6561acf42a781e208ffebd6a421175fd8ad09bc77a09a8906f67c6a", + "scan3": "0358e43773f5bdaff31101f2c661210ae562ed6dc00dde5f4a778dc32fcc5aa8", + "sweep2": "dbab6db649335e6ff81872df3f174e682dce324a379a79a763897eab3bb207cb", + "adaptive": "7d1c7e1b579ec758e8cd1fc261d2b84e78b8d54fd8b822c93b92920c9451fc61" + }, + "named/chain-into-ring/choice-1": { + "step": "974b2187df3bd5290239cbe489842325ef7dc999706dc9045cb428192ad40d32", + "step_baked_params": "53f07995a68cf0f5b760b7b684c9f8841139f3761977ced9f1a8c71e689b08e7", + "scan3": "f1b058f6afb1430db8da3e9f9457d6991cd7383ae986c988b17181694079d49c", + "sweep2": "3202024325b4a45f37024c772662d8d7eee96c8ab8a7d32977da257a37444574", + "adaptive": "a8e563c3d7f11a96938aa44020f31211e9657c41c5b0199e5f922f2254144ba6" + }, + "named/nested-loop-additive/choice-0": { + "step": "7b69d62c10bd2f5db6d9b22e566d0bfd7b55616e94f90fed8ea94bb1656bf79a", + "step_baked_params": "ae462bd8a3bc53060ede4e76e71a3cd00f58c8f3d0c79fed38ffa7a388337405", + "scan3": "65aabb6578bcafcf829b64472bf84b148e3d5a7aad2e755dab0d072e3d1b699a", + "sweep2": "f0ad6217fb2cd1dbb97e570c5e63ca2629bda17c086c8e39f8013dd477a97e88", + "adaptive": "58052216f9e3ea0459349a3c8df1317809f93a540408d5bc3d4b3b129ba3d3f8" + }, + "named/nested-loop-additive/choice-1": { + "step": "8efc5f0a10716687ef948b422eb054ce26036c443332d4a02fb5b15c1c537a6d", + "step_baked_params": "c589586d5f9fabae3953e16d58026f59d1ca2d8d939007357369cf3e9bec80a2", + "scan3": "0b0ab15be9435ffcd6695c40284947f65c9bb60444ba512035f0c3072433bfcc", + "sweep2": "69196d0f25deb77e587bc122ea8a4c54fda1e1717115844042ca60301a09436c", + "adaptive": "6334291cda84f20726ef3a5cfeecb45acff8490ab665a3e555caf4ce379fd112" + }, + "named/star-and-ungrouped-ring/choice-0": { + "step": "c0b915612684825a05489d00a08817f1380973a46bde1610d8823499c988c364", + "step_baked_params": "7d5264c7396c8a765d78f33f579c82c6e0b9896240b7610a3beb195f7afe5d57", + "scan3": "a71976504b24e74ac4bdb205b1eccc0f4d663bccbd59c7ddb0c8baa9d492b201", + "sweep2": "ad9a67937e26ff1da737f8ffc802c732822033968e071bf639334806d7f011e3", + "adaptive": "51c45d8d05899b2e0fd57268dd5b4ef30675d549ea27a7f76cc89ccaf6be5728" + }, + "named/star-and-ungrouped-ring/choice-1": { + "step": "dc92d5ef6796a2fa8636e6b1c6f272864c738b06c4350281f0b764cf8c73349f", + "step_baked_params": "62a0c8c532ce847a983f431c5774facbfbba950191b69d962082caee8228acae", + "scan3": "8bf6ae61168f6ee696aa0e53626cee282f3e48ef075faf4e40945dc288f153ff", + "sweep2": "b2e9a144558fcfb14e1140f5ccddceb7077bbb09d129ab37334f3cfe28cdc484", + "adaptive": "d8d20fe7e550f2fe49f5277b21a484421a0fc58fe730923c9ce4f87d5da492e6" + }, + "named/two-groups-one-scc/choice-0": { + "step": "de2bf4361c015c611d5c3559d30e084004de1ff6b1a13809137e452c0f3fa5a5", + "step_baked_params": "67b2235bb6222e4d7ad87899da2e417a2ea835f9a9891ac6d0d506241cd36927", + "scan3": "87ec1a0b7d348f6e8f650d34dc6fea2c0279b28bdbe74ad720362b72c9c63af4", + "sweep2": "54127b2b36338f077a1e3ff874dfb0044d0eeff0310eda63b991ef9f006d1814", + "adaptive": "7d65aa1831bba00f322798f385f09be034fe23374d1109e159e755fc0448149c" + }, + "named/two-groups-one-scc/choice-1": { + "step": "3efd4ab2e52a2f2fd96c3bffb23a9c28e6026886a5b9a93b47ea7a46c6585faf", + "step_baked_params": "ef0d10cd243d9272703bd07a35ab793d24316e977ca2576c7a7f4e1759723693", + "scan3": "860d263b08da25e16bd76ed9dad0602846beebfa64d0b209375ce26abedd3d66", + "sweep2": "5cb7703950e7d38b7ac797ebd3569809103acc487c6be39749f51303a5cb8b8a", + "adaptive": "5bed84c87b104bd0bd16f38ddeb790a56710eead39338c28548e66366212b354" + }, + "sparse-ragged/chain-into-ring/choice-0": { + "step": "49ecc7671f29e467413807306d8ca7964d115ad126ab41ced0a5d07147295142", + "step_baked_params": "d0af828c98dd316acceb65309057fbf1a243c4c4c90da871fadffb1357476269", + "scan3": "2505f5d6092d9ff3f35e6848642fbdaaf50c04e6c09e53a96b0b637ea9694694", + "sweep2": "f07e9b0e06577d95f029ffcba1578017deb2d6d70924d2bfa8a65652eba4281d", + "adaptive": "ddf88ee55192e45fd04762543edab29fb83648879751f827f17ca63f97566a44" + }, + "sparse-ragged/chain-into-ring/choice-1": { + "step": "4650a150c5ec3768c6fa3832b399ce167d3c7a84281d62020a10d00b5aea6a55", + "step_baked_params": "a97fd2662ad3049e0a3ed3f2541f52584f8d0ab6981e55608ccb66260be9e454", + "scan3": "ebdc6a5ec9e185d9c86b53c05fbbbdce84e3c109002b0f41692b8caa779afe37", + "sweep2": "0899acf0b3fec0f79c7bc24980e25a14330bb7b50d30a8efc3a2e65946846572", + "adaptive": "4f0891af826315bdd8244c675584b2fb2668c387d08e6d4c42d215e92e7b472f" + }, + "sparse-ragged/nested-loop-additive/choice-0": { + "step": "6b794d10b9f080320e4d81f107ea78f41abbb06f09e2302fa7e4292ac2c8b602", + "step_baked_params": "67719515e92484c1a04675cf72583aae68baf70b711d80fe81dfd5a764ef2581", + "scan3": "f1b64eecea0e4aa32f0a7c31a296b4ade29e5695e1941db27204b180813181f1", + "sweep2": "bde3ed654029105b12f131a8968515763756fdf2e4c9845e829aee19628520c3", + "adaptive": "86613fed7d196e64fa42e3c7f8cad689153fcc3a3ef36bb8e90dcf6182ef62b7" + }, + "sparse-ragged/nested-loop-additive/choice-1": { + "step": "09f11ffe331a82ba918dfc148f4cd58bf6a71281db74745a1943973002518939", + "step_baked_params": "304c4bcb5787c8c5c207f703220a98de53d701fbe0d5f779f2856929b0d05ac5", + "scan3": "fd98072e056f31a4c351c7f01c2ff914795ac5b5e159f9738a6f72f0a0cba996", + "sweep2": "c427d0539e974dd11dbe2b700f09c9d6fd000f04406486a55217171f9ae236fb", + "adaptive": "1626b6f5122ffa3a1c9137928a8c837124a8bdf966a3b589ef496bc57ef96779" + }, + "sparse-ragged/star-and-ungrouped-ring/choice-0": { + "step": "3401466b54108785fe38f98a9267661dcbee7bd9ca56f8e9867a9119a28c7661", + "step_baked_params": "f075e1c195092d4e1a0bedcb19c861fedde8c914e5ac58b0ca3c5495d6411b34", + "scan3": "a0aca1a4896f929e74b226bc17d16f4ee9ddd8d0f1a7fdd97e0d2f53f8a6b3a9", + "sweep2": "39d0cf74730980a7b04f36aedcf16b82246f7ca91d1238f0982d43d63e6ac74c", + "adaptive": "a6f8c74c9f60fec9fe4ceb83513d433301cd62725aa21ca0bf433ae6c69233b5" + }, + "sparse-ragged/star-and-ungrouped-ring/choice-1": { + "step": "8c667d2f6b7c3589bded1fb68984c11f55dae9c77dc081b0172daa69911b7f80", + "step_baked_params": "e52a871e9eed49590e16773b2c29b561bff33cc603b145af8f4d3d2903760704", + "scan3": "d932d02e0f4ab256ec02655d55139ef2c090260b26a814cb26f8b0e71994b058", + "sweep2": "0c2d6fbbc6edab2de17ce89305943eeefffcfa3bda7a6980e9727fa05551ccd0", + "adaptive": "bd063faecaccdd891fbcd0fe0cea5dc649bc770a94a4ab1f876746fb5d3b46ac" + }, + "sparse-ragged/two-groups-one-scc/choice-0": { + "step": "46e2aa87979618f7f0e93704535322e2feb6cc27b85227ee4462f84a96323519", + "step_baked_params": "bb9cd8fa1f7a5cb1da0fa8d464112b8ff0ca86567b9be56e9912095aa012c77b", + "scan3": "24f8ac9207107de6870aed938f90b2755aee07cc85453e1b3f45e405631f4ef2", + "sweep2": "e65c27980129ff6dd3103d87b0f867aadb93747c51e4072025466d6accf86d13", + "adaptive": "e03a8b99b7b77f9443657ce186e0fcc1e1ac00edec03161ffd165aa5904b88cd" + }, + "sparse-ragged/two-groups-one-scc/choice-1": { + "step": "70c612746a00072b8576961971cbc9410967ff6fd1ec3b4f2575112e0c6e7d0d", + "step_baked_params": "aca098d37ec148bafc843edc6bd2d6bf18b8c2c1b69bc4be499b4f97b5136ba5", + "scan3": "1b1d9bb6e9145345177491ecefeb4950932ff01354794803cedfa0225385bb56", + "sweep2": "8621c0c246b5fd548c7ecd2afcc0d09e3167ac80a8f65e02b356e25c8e688614", + "adaptive": "2cea363e871ea5c15e8b41890329223b0c5197d045efb31d6b5d402ba2cd18a7" + }, + "sparse-scatter/chain-into-ring/choice-0": { + "step": "b9399e53bd8a9748df5c86d6e2e68b97ebd3ce07889654a2dba6450f10322aa2", + "step_baked_params": "60573e556b0758820d912a312125c5e99affeaa753c399dd39a01e8821b8800f", + "scan3": "29b00eda2cd05a0572ea0380188a09a569fa07b7a471276c56840891cdfbb2e5", + "sweep2": "ed04f6eaf225cbf025e2e6b353d2573c172b3e51e31a1df34295ee05be664503", + "adaptive": "f018373755b63f3e051634fea8eebe32f967ad7452034684d97ed618d5bc2139" + }, + "multi-rate/chain-into-ring": { + "step": "f2cd5bbdb53f9bee25427dd3df4406bfe4fc4dd407885434ce9ed1400fb7bf8f", + "step_baked_params": "8bf34bf6d51e9492d16ee29fe9c60c466873e1514886ee565d21b19e867ffa96", + "scan3": "08bfe7ebff284dc336aeb3729d6c0be647c3a64004cd8755b53c8e261995d229", + "sweep2": "7bb6c8dc768d34e3736c141bc220cda81646a92bbff10a96eb9d65c036f19e17", + "adaptive": "ac9167a6bf59acfa231c862d1143e7084f255c39d240c06ead637030c7c72da7" + }, + "sub-cycled/chain-into-ring": { + "step": "cf19bb9b7e6c1b679da00460b8447be6c1ffc347dfff60575e286ed93368487e", + "step_baked_params": "02b4f30fb153fe4aa0d2a9f8795beb80a48ff83ad7d100a275c85cc0c61c2c9e", + "scan3": "e8ca6edbd3f8ac2e070280825e45d6276831bd48f5618f13936376f21221391b", + "sweep2": "b3da6331316714ce2becf364fdcc6b9a1e79f1e6b731ddae63187249d3b24a2f", + "adaptive": "f1a3faa544008d5e0bdccca1fcdf8676816c828f77a74e82d2b5d48a5ab1706e" + }, + "predictor/chain-into-ring": { + "step": "aa161151d0d9aeff8eb52b751165de8d9b1d954ae4cbc1da8fdebad57657ead0", + "step_baked_params": "a1649c95f4e1d8a3558280b96b2200961f366f15778bb01b43ddb5142eb28df2", + "scan3": "c1e358c862759c483b3432f4ce5c0f6ed98760a4d4f901e39ba5591e6b968f5c", + "sweep2": "220c708c5fb2172224ff022d6fb30f6d6e0b5bbf1d6bb6f70198ca2843c388e9", + "adaptive": "74d3979f83bd350af9850c6daeefc55dd7f27dfab629c0fca2f2244fc9c9a144" + }, + "aitken/chain-into-ring": { + "step": "acbafc4b39f58a1713032790586049359dd5f5d6235793e1abd15f0ded213e83", + "step_baked_params": "8bbd16abbeeff5cab027c96520c409a019d35d2834867c1c5d65d22ab4ed8b18", + "scan3": "a423e321f18ecf23ede76c866744e4dc035ba0e5210722f6150a10aae8e00c14", + "sweep2": "ef8e22f97604446011737596f6e2a81b86611b2645826c77f3c2ed83611ea3df", + "adaptive": "a6e312d4780ac2308b80c3462e1508c51ec0ffeab124be242e4a6d2366c444da" + }, + "flux-outside-a-group": { + "step": "fb8a0ebd01f3b0e896e6790ec734332262ec7528bd270ea676fb23baa4ba103e", + "step_baked_params": "b5af89027eec5b08304e0bf146a0c0d5bcd706dda99ab24a3abc1125aaf8cc3a", + "scan3": "d800e3550d086a53cd5776d6c0c9c20c1faa52b7f28d063827aaf19c69d8751a", + "sweep2": "e639020358b8a006022a32e2024c987b21f5080149298fb44d82d9b54397f048", + "adaptive": "ddf0d8966c2cce3e829a3bf35c80d02301cf054999d9ad1df17d6cc0f71bf85e" + }, + "rbf-edge": { + "step": "ba518ff7a8f2fd5780dc43103b395dc98af157ff655e904443ae6b8a84b67952", + "step_baked_params": "1df4b758b8feddd9720b64218d6f8bf4ca58b926e3473acb2ced3d50aae2bd37", + "scan3": "1486b3f8c181abeba43949623d0dcd90af6c8a3b259ff1b4e33da525ec777de9", + "sweep2": "27d97e1fe18aef49f3996299a2c2a59d3ab486d0b29e91df433eacd151c091d5", + "adaptive": "457f9224a13240dde6e6fe6ee4e66cd8ff8a864f52075e8069d96656f98f35df" + }, + "sharded": { + "step": "fc2919966e0774ee015aa0a809337e118a6a478b71cd2e6daa4de2a43423ee93", + "step_baked_params": "e2a64269916a1337278c48d4708b5db14707be07e737a43a87e621d19a14bc31", + "scan3": "e237452cf5fe0e0ec7a383cc5c14a9644aed458258dec1f4bcc74b8dbfbb60e6", + "sweep2": "f2b7113dd3eedf32aea01851648d6ab7e3044fb993bedb9910b44dd04deb1620", + "adaptive": "daf1b6619b10be39f8c26e6a2d9d4fad108546e45d9062e1574680a5929fd193" + } + }, + "0.11.2": { + "named/chain-into-ring/choice-0": { + "step": "262df382d7c88a7667c5b9477e06ac6adbc00abadb14fad54756e0673ef59073", + "step_baked_params": "624580ba3ef58d4484a41518bffb7173875d28c93b4c7fe0c228dfcad8e5e0d0", + "scan3": "3d4b92087f8c3b8497f5f9324f7eba933b98c99134dac786b99b7fb9c0e105a1", + "sweep2": "07d7fe9201106c6f6841aa4dc1a6f6995da1f49f3a87513a6a0dee7e062565b0", + "adaptive": "234b41942fa7bdf7cd6b7f8160be851fee3693a3254aa5f32b4398cf0140e191" + }, + "named/chain-into-ring/choice-1": { + "step": "d07c81be586a45960fc3e9120e6879037fe1860bd5e4dc424725196549545d90", + "step_baked_params": "03af49770ce0112348bbf119e38182afeb7a14a9c7dcf67b93b3d67b351dad77", + "scan3": "05c4bcd77cd111a1549d1c05e0f46ceca1ccea1b72c000b85437314834370789", + "sweep2": "f3570ed145bd38f44d47ee436240eaabc820421f6bfb0c6fbd180a5201e21c0e", + "adaptive": "676de2f26707420434fa7a6af735a6d87a72a67741fbb85e0abfb3c74e03e9b5" + }, + "named/nested-loop-additive/choice-0": { + "step": "01fec07edabf64fe40d2931e09b093810e7bb5dcc91177ca590783c467ad616e", + "step_baked_params": "04bc2833b26c152d4ec9ecb37de2b1ef95501dbb658fa0060dc4925ee131d589", + "scan3": "25d2d29e96fd5ae28a88e807c5125187c6e5e05982ee6c73cfc56dc382afe71e", + "sweep2": "91aefe031ece79673297e5856d5ab6b1546d76862bd457088717d7132eabbc7c", + "adaptive": "e3b66165c26db01e498776630ce7bcab79cc972407af207935976ffb77400bf0" + }, + "named/nested-loop-additive/choice-1": { + "step": "1858f6906e9bcf15e7a54d759b77243741f24ae7e54bce0a7bccf76a4b08d973", + "step_baked_params": "1748b22912af4302b3f65eaa2bb537fdb81eaf10496fcf842edd667c5f27f82c", + "scan3": "a42f09372957462bc6d91643bcd46a47b629a9db1f1e249f36dd54941590f4e0", + "sweep2": "90de123369a836b2d9a9d70d3c96bb8619f71bb29cd86f46c066604743670784", + "adaptive": "ce436b9df290168554a9a245c713f2a89b45a95631aaf69e3d5b395b41d93164" + }, + "named/star-and-ungrouped-ring/choice-0": { + "step": "502e0ef19debc7197d506a1000174568869e416c7a9e2047379fca9175b3143b", + "step_baked_params": "119a7caa35db55c0fb5c90857a4d2441f67a54b8319957297cc864033f399c38", + "scan3": "006ca73c903e0452852ab46ec104770cba10af5ad0fab155a5511305790ee50c", + "sweep2": "d8eee601fe0402302678b532d72fb4d9c32914b4efff2bd46986bd0db40ff888", + "adaptive": "4acbaf0c3dec63d64cfdee27df0ae81424a8df7694a18c4ad33fb21aa5e0c075" + }, + "named/star-and-ungrouped-ring/choice-1": { + "step": "217c4a51b0ec88a8caa03c95d06eacfb0d803c7e5e7cb43b82cbd613c7f8640c", + "step_baked_params": "e6c20ec851a954a5179e75c5fb0d6250871af742ea125b74dda4e92dbf6865d7", + "scan3": "afe48d0f4184d4a2d04e5be7e20ffbbd42f50a36ba2dfaae8aeff46187a98778", + "sweep2": "f38f5469a05b6b195273f50a8e7b4a72e873818b2d6e974806bf8e65a07fb531", + "adaptive": "7b45a880c508f35d130f2bd82e04a33061c55affcd19250df463bb94ecfac9ab" + }, + "named/two-groups-one-scc/choice-0": { + "step": "42289c549bec4577eb4c1a4d68d15f0e9e85cd1e8e1709cff21c11f51e5e07ad", + "step_baked_params": "cc70db4db1788b8eb98c3c69ab1c6e6512543597e87615f3c0fd990eafc6b1d0", + "scan3": "f0bf6cdf16633bf6855f15045469317c7e74cc3dd0188abf8a5a979817d536cf", + "sweep2": "c4db21ccc1d1c5ab0a2579150555a911d2e74884c54de84c6ca8d0abf71aa64d", + "adaptive": "7e820315e3e03918349d881be2669c9edec6e0be5947c027f0bb429cd76a0032" + }, + "named/two-groups-one-scc/choice-1": { + "step": "75684440a0e0a43f4ba59fd3a74c3a3199b5cb805f93537d445340dc6fca6925", + "step_baked_params": "93aada4aed471f6d3454c108f5b2488473af2a5f396abe15215814ee5fb65f7c", + "scan3": "f0b98dc9dad6f7e7e72eb06dc7a6213353702a3325e8ff759b64799027e087c4", + "sweep2": "428d1c76f740772764b940d550e876aea922b31c19287ed8bbad58fffb0e2d8b", + "adaptive": "a41d2f983415f9557fafa6fc27fefb05ef87fc995c4a331606aad66b10659498" + }, + "sparse-ragged/chain-into-ring/choice-0": { + "step": "b92003aa6ad49b0e3161e20471e48bdd3c125bad9164561602f7addb9e735b22", + "step_baked_params": "06b6378863a6d48eca29323badcdf9098b075f87f9264aa66a9f1c24e37bd715", + "scan3": "51b692869fa3517edaedc95511d23971d89db3ba40dd0f729c85411a401efeb3", + "sweep2": "f3fede8a4230024c0d6d2e41c6be6bca0b010c64875f3bcbea47b3eb6066844d", + "adaptive": "bc81df5b3b1cbe83b00df7aed82d603052a82c48ad7f9acaff5c0dd689884601" + }, + "sparse-ragged/chain-into-ring/choice-1": { + "step": "ad8e3433dfb67bf18dee1bcc632686cb5cd70c73e7c11c20c3e69bfca33079c5", + "step_baked_params": "2e74fbe52576e5f88daa3fd23c9034b18fe773b56fe32101faa4714ae6179996", + "scan3": "4e9ee126a3eb38eb61fc7e2e172acc60b46ad553393d35bab66752cddba40361", + "sweep2": "c5cb6aef1c93abcf8a68105153b4ca7c2152cfc97ec01f0444926e34a60b470f", + "adaptive": "39f09fb05e17e3e6cef52aaeb478ddfe9bf4a950279d06ad4ef9be9fb6191a0c" + }, + "sparse-ragged/nested-loop-additive/choice-0": { + "step": "27286d2a65cd06297a55b662e0a18e9eba14b2312e27c17da652d755eacd8b48", + "step_baked_params": "0430140a66f08a6acb499c6801506412f21eef47379719d10c097b4d30e97381", + "scan3": "07243ed35236fb8568c0516b28e61730ee6e0cbe191e9f21e74d4d58ddf1a1d6", + "sweep2": "e767e46e47a787dbab46a47a4daf72e7228e7caf3bdd3a4a007c2d32c8f07641", + "adaptive": "eeb25b5be26837d3e102a8977cfab1fccd3a4680bb68d4df34507cdaef88b9cb" + }, + "sparse-ragged/nested-loop-additive/choice-1": { + "step": "eea46612ea6f424ed8bfc278ad51ea60d5894334f814a70924a70a8ba95a01a0", + "step_baked_params": "f8e2edf559e9c82619b3120aab2260e142e262040399e686690a4d67189e70d1", + "scan3": "a67eb287b84eb29471692d27f698a8aee1edd5c2d8d6d39a7f28c1285686be8e", + "sweep2": "ae6c6e69ac0eb823f16c71131bb3c09359a1352aab7a71f1757fb3638eb553ca", + "adaptive": "5c3d9911437b4fff28554f79fe2ffd17cfe58e5ef3336b224b0456a55a22be01" + }, + "sparse-ragged/star-and-ungrouped-ring/choice-0": { + "step": "cddf8e836c78e8f192f0b69b57f435efb8abed26feac5b47925944a16399d0ae", + "step_baked_params": "6669ea3deb2e275dfebdfba173ccd2ce7f5c7b7af3707c3e8e084a5e3598cd52", + "scan3": "92a164083d76e2776574d684eef3b525ab5d90b504d8fe81808575775a77f588", + "sweep2": "a3b7f509332279025c64ca0821ad3c5ea5b36f18b7cfd62a8bb438e144dbf81d", + "adaptive": "7b89261fc6f1985232efd4cee63c02bd146bc6888354617259a47a37fe4c6a34" + }, + "sparse-ragged/star-and-ungrouped-ring/choice-1": { + "step": "aa7b02078dabdb9700832ebe49bca991f5e632631ed940ec73b447c4ae041b8e", + "step_baked_params": "d4c87ad15e3b371893639e4cc85004c849b0cc4e5123c147592d6f2e06f52531", + "scan3": "acda7c53790b41eb88b7b4d3e9d3b91511e568306e41cc218536e9afe5b2ae53", + "sweep2": "f1d4285059d2382b500623c48f0ae073ca87a1e37bc13b7b144fc70e8c8ef5b7", + "adaptive": "ec34b180a3dbd1410399209872f7d3d977c1723b782ef85c39ae843ba87fa80f" + }, + "sparse-ragged/two-groups-one-scc/choice-0": { + "step": "50d5420e5ca2a6d20e7fe14f6921e72bc0eb8e77088dc28bf782b7667041bae3", + "step_baked_params": "d2011425b1889e64acb030e20de1e694a79659b9716ee53b0f272f092a37d8ba", + "scan3": "6415f840f45657a261118e933f635274b78434291ed659523d968c701e46923f", + "sweep2": "0b86f13c5698f63c0c24bdadadef8a5f2518e02d25f2391e4490298011630a1c", + "adaptive": "a384bce06769bb0612058b92f58551b24fb888916314ff68256c0c2e07036eb9" + }, + "sparse-ragged/two-groups-one-scc/choice-1": { + "step": "b59a68a2fe258e3d96409a6995f4dc230f253664143cff63c68cd7e80ab2abd9", + "step_baked_params": "1da8133fc75e6fd55a07f33a93c5d08f8832f0b6893d4fd356b85a6ebd444b91", + "scan3": "4b216059ed8edd0f7a74d3e89002cd865b4c462e38019919e4db6dad246fadf7", + "sweep2": "b62fbe1acf155560e236e0d62809e92487320842383dc7506abc7c7ae42c3d02", + "adaptive": "b70d27b84c98656a8def9abfafb15fa433232a44b621b7a58e2159afa2854a6c" + }, + "sparse-scatter/chain-into-ring/choice-0": { + "step": "f5afdf2ff848d603999e18927ee3161147b4b57ff1f9e81c2bd5dfe1239c3998", + "step_baked_params": "4cd2715862b80d6b5bacbf57c2886626e8b041d022d5c002566ba01736e05f08", + "scan3": "2560b4c1f77e09177e1691f73989025763d78409c6281001bc622a153d76fbcc", + "sweep2": "407471592c47206d27670ad998f06f4f919c4062233fae5d99758b1280880b00", + "adaptive": "4c1b09c5c464ed8ce9db7d9697633305864f06397ad737c301eab1ab23c24b3b" + }, + "multi-rate/chain-into-ring": { + "step": "fd7656017b77152a7f720a16fccbac00537be42075bfa49f42c0a6d78f854a5e", + "step_baked_params": "87b47231944e15749b47500028706731e8635369b8ed2779b0033c4b77c08db4", + "scan3": "f473941cd4a9d403d70e20176b39afeb4d56ee1faa42e49e16adddce8244ebbc", + "sweep2": "565af502391b07d59942f074fd0bb60a0b4961754786ec62b9406755c621e916", + "adaptive": "96998d76a5420dc2a97b3b45d0c1376f524d7070f48fcee2577d540864c3fad3" + }, + "sub-cycled/chain-into-ring": { + "step": "1427d2a1beb43643564660bd3fce17370061670c375fe8d90a592e4300876d62", + "step_baked_params": "f9fb84ec3531e2711f239b5191a56bb701b25fd67707f68f929c8508c6db35c4", + "scan3": "aa40608ea5427e4a820bc792142c33d7d41fa1d0c19b35d708fe8b9e22cdd729", + "sweep2": "9d31243b12797aa4f530ffc494efc757d40248691411fadbe60c1de7c48dbf29", + "adaptive": "25a9fadd9972341b28d7eded82d8bb37eed5845d6ba3987a9056d6ca5588c361" + }, + "predictor/chain-into-ring": { + "step": "5694689b7c80c9e70cbe8406559f0135ac92f7a60955274918f069c99432761c", + "step_baked_params": "7197cdabda90583a3e1fb251a94355d16cbc829a2495fe49afae00b7a7d17b6e", + "scan3": "e6b5392cf79a4df6771ab33ff4455e7777d36846121a09922c0e88ad9ac7fbc1", + "sweep2": "22c982d9bbb6b01fa60b2f9d7c64283fb14ddcdee5f4cfe9d878edf7978728c1", + "adaptive": "474cbd67f43b5d3c753de5ff258e24a1ee647aea1688eb302daf64aadb014b7e" + }, + "aitken/chain-into-ring": { + "step": "5a7e72a1966638806d8695f0b5e9dc50cd99cd4e6fc38985947d7868d5e15969", + "step_baked_params": "b343544f2401082e3277ad547c22cf6e9c2fde1831b01a91f215fd78d2ab24a2", + "scan3": "b95df02a843c4c5580c43bb0d8f393bad91c91df2dd2b20a0b24a5fda2cbc2c4", + "sweep2": "e00e308f9602a04c2709b74f3ff986075e4555735aa8b60143735baeba5b05db", + "adaptive": "c60f74053c803deb53a00886a530155a8aaa158508ef1a2c4a7633521e6b8d78" + }, + "flux-outside-a-group": { + "step": "fb8a0ebd01f3b0e896e6790ec734332262ec7528bd270ea676fb23baa4ba103e", + "step_baked_params": "b5af89027eec5b08304e0bf146a0c0d5bcd706dda99ab24a3abc1125aaf8cc3a", + "scan3": "8727d0f591cca017e225181cf72f4c8634465bb9f378a96cbca684d39c851ab9", + "sweep2": "8281f01b57f0e2641580454838d9db3c805b58151760687a6f6d0960c0dc3e0d", + "adaptive": "ddf0d8966c2cce3e829a3bf35c80d02301cf054999d9ad1df17d6cc0f71bf85e" + }, + "rbf-edge": { + "step": "ba518ff7a8f2fd5780dc43103b395dc98af157ff655e904443ae6b8a84b67952", + "step_baked_params": "1df4b758b8feddd9720b64218d6f8bf4ca58b926e3473acb2ced3d50aae2bd37", + "scan3": "27fe9a91bff92080f06110ac09296157328a7c4a4970875286f214ad491b86e7", + "sweep2": "c8c847002554d775be7d21c218ab9786cb79188f0d988f65d0932e4a67697f68", + "adaptive": "457f9224a13240dde6e6fe6ee4e66cd8ff8a864f52075e8069d96656f98f35df" + }, + "sharded": { + "step": "fc2919966e0774ee015aa0a809337e118a6a478b71cd2e6daa4de2a43423ee93", + "step_baked_params": "e2a64269916a1337278c48d4708b5db14707be07e737a43a87e621d19a14bc31", + "scan3": "d5d69245de829fdf1858d4915b147678bb27062ae478b6df861987da0851f7ec", + "sweep2": "f8bb8ba0d1872b0808b3caf8a0f1f7e1dae353e575d3608f61827bd7391b5203", + "adaptive": "daf1b6619b10be39f8c26e6a2d9d4fad108546e45d9062e1574680a5929fd193" + } + } + } +} From 93ddf8c5d1bb6e7d80f8055b59275f61f8e38b60 Mon Sep 17 00:00:00 2001 From: Nicholas Ehsan Roy Date: Wed, 7 Oct 2026 07:02:55 +0200 Subject: [PATCH 10/13] docs(soup): regenerate for MADD-ANO-231 and 232 [skip ci] --- docs/validation/soup_package.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/validation/soup_package.md b/docs/validation/soup_package.md index 225a57ce..8a55fd4c 100644 --- a/docs/validation/soup_package.md +++ b/docs/validation/soup_package.md @@ -293,8 +293,10 @@ stale copy fails CI rather than shipping. | MADD-ANO-230 | A direction the Arnoldi breakdown test takes for rounding can carry the dominant mode of a Jacobian far from normal: float32 fan-out hubs with a field 1e-4 to 1e-2 of the rest read rho_spectral 0.157 for 0.349 and 0.503 for 0.397, settled | `major` | `context_dependent` | `open` | >=0.4.0.dev0 | | MADD-ANO-227 | Nodes whose timesteps are more than about 1e9 apart, or have no common step the float GCD finds, ran on different clocks with no error | `major` | `context_dependent` | `resolved` (in 0.4.0) | >=0.1.0, <0.4.0 | | MADD-ANO-228 | REST read a boolean or numeric text as a timestep (`true` added a node stepping at 1.0 s), and clamped the counts of POST /sim/profile without saying so | `major` | `context_dependent` | `resolved` (in 0.4.0) | >=0.1.0, <0.4.0 | +| MADD-ANO-231 | A coupling group under IQN whose iterate left float range before its cap never returned from step() | `major` | `context_dependent` | `resolved` (in 0.4.0) | >=0.3.0, <0.4.0 | +| MADD-ANO-232 | gradient_relative_error_bound read below the error, gradient_bound_usable=True, with a constant in it whose tangent is rounding: 1.09 for a relative error of 1.134 | `major` | `context_dependent` | `resolved` (in 0.4.0) | none | -*230 anomalies registered. 37 have a defect reachable in this version — every entry whose `resolution_status` is not `resolved` or `duplicate`, which is 28 `open` plus 9 `partially_resolved` whose residual risk is still live. The Affected Versions column is a PEP 440 specifier set read against this document's version; `none` marks a defect introduced and fixed within one development cycle, which no release carried. The convention, and the gate that holds every range to it, are in the header of `known_anomalies.yaml`. Rationale, workaround, affected components and verification evidence for each: `known_anomalies.yaml`.* +*232 anomalies registered. 37 have a defect reachable in this version — every entry whose `resolution_status` is not `resolved` or `duplicate`, which is 28 `open` plus 9 `partially_resolved` whose residual risk is still live. The Affected Versions column is a PEP 440 specifier set read against this document's version; `none` marks a defect introduced and fixed within one development cycle, which no release carried. The convention, and the gate that holds every range to it, are in the header of `known_anomalies.yaml`. Rationale, workaround, affected components and verification evidence for each: `known_anomalies.yaml`.* ## 4. Verification Evidence From 2cec694d2dbb0b52ac4943b7b0fea81c5bd4ec93 Mon Sep 17 00:00:00 2001 From: Nicholas Ehsan Roy Date: Wed, 7 Oct 2026 07:39:03 +0200 Subject: [PATCH 11/13] test(coupling): the slow IQN cases state their premises (fori reports with diagnostics; Jacobi stalls finite) [skip ci] --- ...pling_iqn_returns_on_a_non_finite_iterate.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py b/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py index bb84af59..50120533 100644 --- a/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py +++ b/tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py @@ -121,7 +121,7 @@ def _graph(acceleration_, dtype, **group): return gm -def _step_reports_a_state_that_is_not_finite(acceleration_, dtype, **group): +def _step_reports_a_state_that_is_not_finite(acceleration_, dtype, overflows=True, **group): x64 = jax.config.jax_enable_x64 jax.config.update("jax_enable_x64", dtype == "float64") try: @@ -131,9 +131,10 @@ def _step_reports_a_state_that_is_not_finite(acceleration_, dtype, **group): state = np.asarray(gm.get_node_state("a")["x"]) finally: jax.config.update("jax_enable_x64", x64) - assert not np.all(np.isfinite(state)), f"premise: the iterate stayed finite ({state})" assert report["converged"] is False, report - assert report["residual"] == math.inf, report + if overflows: + assert not np.all(np.isfinite(state)), f"premise: the iterate stayed finite ({state})" + assert report["residual"] == math.inf, report return report @@ -151,7 +152,7 @@ def test_a_step_whose_iterate_leaves_float_range_under_iqn_returns(acceleration_ # Per push: tests/core/test_coupling_iqn_returns_on_a_non_finite_iterate.py::test_a_step_whose_iterate_leaves_float_range_under_iqn_returns @pytest.mark.slow @pytest.mark.parametrize("group", [ - dict(solver="fori", max_iterations=24), + dict(solver="fori", max_iterations=24, diagnostics=True), dict(diagnostics=True), dict(convergence_norm="l2"), dict(convergence_norm="interface"), @@ -162,8 +163,12 @@ def test_the_step_returns_under_every_solver_norm_and_schedule(acceleration_, gr """The same step under the unrolled solver, with the diagnostics (whose analysis takes singular values at the returned state), under each norm and both schedules; and the accelerations that always - returned, beside it.""" - report = _step_reports_a_state_that_is_not_finite(acceleration_, "float64", **group) + returned, beside it. (Under Jacobi the quasi-Newton iterate of this + pair stalls at a finite state, not converged, on the tree before the + guard as well: there the step is only held to return and to say so.)""" + stalls = group.get("iteration_mode") == "jacobi" and acceleration_ in IQN + report = _step_reports_a_state_that_is_not_finite(acceleration_, "float64", + overflows=not stalls, **group) assert report["iterations"] == group.get("max_iterations", 40), report From 1866fb7d3330f655638d67eb5abc4b73b702a774 Mon Sep 17 00:00:00 2001 From: Nicholas Ehsan Roy Date: Wed, 7 Oct 2026 09:52:11 +0200 Subject: [PATCH 12/13] docs(registry): this branch's entries take MADD-ANO-233 and 234 (the base reached 232) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013UkCde7g23gTziUjYAvnKD --- CHANGELOG.md | 4 ++-- docs/release_notes/v0.4.0.md | 4 ++-- docs/validation/coupling_claims.yaml | 2 +- docs/validation/known_anomalies.yaml | 4 ++-- docs/validation/soup_package.md | 4 ++-- tests/compliance/test_soup_evidence.py | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d83be6b5..2552e82a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -418,8 +418,8 @@ guidance; the itemized changes follow. The `[verify]` extra now only pulls `hypothesis`. ### Fixed -- **A coupling group under `acceleration="iqn-ils"` or `"iqn-imvj"` returns from `step()` when its iterate leaves float range** (MADD-ANO-231; 0.3.0 and 0.3.1 under `solver="ift"` with `"iqn-imvj"`): the secant least-squares handed LAPACK's SVD a matrix holding an `inf`, and the step never returned. It now runs to `max_iterations` and reports `converged=False`, `residual=inf`, as the other accelerations do; steps of a finite run are unchanged, bit for bit. Action: none; on 0.3.x use `solver="fori"` or `"aitken"`. -- **`gradient_relative_error_bound` covers the constants one pass resolves** (MADD-ANO-232, never released): with a constant in it whose tangent at the returned iterate is rounding (the centre or curve of a nonlinearity evaluated on its centre) it read 1.09 for a relative error of 1.134, usable. Such a constant, and a gain whose whole value moves the pass by less than the residual's float floor, is no longer in the bound; the docstring says which constants are. Action: none. +- **A coupling group under `acceleration="iqn-ils"` or `"iqn-imvj"` returns from `step()` when its iterate leaves float range** (MADD-ANO-233; 0.3.0 and 0.3.1 under `solver="ift"` with `"iqn-imvj"`): the secant least-squares handed LAPACK's SVD a matrix holding an `inf`, and the step never returned. It now runs to `max_iterations` and reports `converged=False`, `residual=inf`, as the other accelerations do; steps of a finite run are unchanged, bit for bit. Action: none; on 0.3.x use `solver="fori"` or `"aitken"`. +- **`gradient_relative_error_bound` covers the constants one pass resolves** (MADD-ANO-234, never released): with a constant in it whose tangent at the returned iterate is rounding (the centre or curve of a nonlinearity evaluated on its centre) it read 1.09 for a relative error of 1.134, usable. Such a constant, and a gain whose whole value moves the pass by less than the residual's float floor, is no longer in the bound; the docstring says which constants are. Action: none. - **`GraphManager.step`, `run` and `run_adaptive` no longer store a step that reshapes a state leaf** (`MADD-ANO-220`, in 0.1.0 to 0.3.1): a list given for a scalar constant (`BallNode(initial_velocity=[1.0, 2.0])`), or an external input of another shape at a later step, broadcast a scalar leaf, and the state's checkpoint then did not load after `reset_state()`. The step is refused by name (compared once per trace, host-side: no compiled program changes), as `run_scan` always did; the FMU sidecar and bridge refuse it too. - **`coupling_diagnostics()`: three numbers that read wrong with their flag set, and one found beside them** (MADD-ANO-222, 225, 226, 229, never released): `gradient_relative_error_bound` at the float floor took the change along one stand-in direction (5.1e-6 for 3.0e-5); `rho_spectral` read settled past eight interface scalars (0.273 for 0.219), from sampled rounding on a float32 group far from normal (0.250 for 0.206), and lost a loop below a field's rounding on a sub-cycled group (1e-12 for 1.25e-4). The gradient bound's undirected distance now takes an operator norm; a Krylov space still growing at the cap is never settled (`spectral_usable=False` above seven interface scalars, eight where they are the whole state); a certificate over every perturbation of the measured size replaces the samples; a sub-cycled boundary value is differentiated as `(1 - alpha) a + alpha b` (values unchanged, gradients of sub-cycled groups move at rounding level). diff --git a/docs/release_notes/v0.4.0.md b/docs/release_notes/v0.4.0.md index 9f4148c0..7d8099a6 100644 --- a/docs/release_notes/v0.4.0.md +++ b/docs/release_notes/v0.4.0.md @@ -7376,11 +7376,11 @@ its nodes on different clocks; now a `ValueError` at `compile()` and a 400 at `POST /graph/nodes`. `228` (resolved; carried by 0.1.0 to 0.3.1): REST read a boolean or numeric text as a node's timestep and clamped `/sim/profile`'s counts silently; now a 422. -`231` (resolved; carried by 0.3.0 and 0.3.1): a coupling group under +`233` (resolved; carried by 0.3.0 and 0.3.1): a coupling group under `acceleration="iqn-ils"` or `"iqn-imvj"` whose iterate left float range before its cap never returned from `step()`; it now runs to the cap and reports `converged=False`, `residual=inf`. -`232` (resolved, never released): `gradient_relative_error_bound` read 1.09 for +`234` (resolved, never released): `gradient_relative_error_bound` read 1.09 for a relative error of 1.134 with a constant in it whose tangent is rounding; a constant one pass does not resolve is no longer in the bound. diff --git a/docs/validation/coupling_claims.yaml b/docs/validation/coupling_claims.yaml index 34484410..530b27f2 100644 --- a/docs/validation/coupling_claims.yaml +++ b/docs/validation/coupling_claims.yaml @@ -3699,7 +3699,7 @@ claims: not respond to it, and its gradient at x_k is rounding; and a gain or forcing so weak that its whole value moves the pass by less than the floor) is not in the bound, which says nothing of it; it read 1.09 for - a relative error of 1.134 with those probes in it (MADD-ANO-232, + a relative error of 1.134 with those probes in it (MADD-ANO-234, resolved). oracle: the fixed point's gradient from the float64 solve or from tight ift and fori arms that agree. tests: diff --git a/docs/validation/known_anomalies.yaml b/docs/validation/known_anomalies.yaml index c0988626..8c072f36 100644 --- a/docs/validation/known_anomalies.yaml +++ b/docs/validation/known_anomalies.yaml @@ -15534,7 +15534,7 @@ anomalies: - "tests/api/test_profile_endpoints.py::TestSimProfile::test_a_count_outside_its_range_is_a_422_and_nothing_is_profiled" github_issue: null - - anomaly_id: "MADD-ANO-231" + - anomaly_id: "MADD-ANO-233" title: "A coupling group under IQN whose iterate left float range before its cap never returned from step()" description: > `acceleration="iqn-ils"` and `"iqn-imvj"` solve a least-squares @@ -15602,7 +15602,7 @@ anomalies: - "tests/property/test_coupling_nonlinear_search.py::test_a_group_that_leaves_float_range_under_iqn_still_returns" github_issue: null - - anomaly_id: "MADD-ANO-232" + - anomaly_id: "MADD-ANO-234" title: "gradient_relative_error_bound read below the error, gradient_bound_usable=True, with a constant in it whose tangent is rounding: 1.09 for a relative error of 1.134" description: > The bound is the worst, over one probe per scalar constant, of a diff --git a/docs/validation/soup_package.md b/docs/validation/soup_package.md index 8a55fd4c..e18979ea 100644 --- a/docs/validation/soup_package.md +++ b/docs/validation/soup_package.md @@ -293,8 +293,8 @@ stale copy fails CI rather than shipping. | MADD-ANO-230 | A direction the Arnoldi breakdown test takes for rounding can carry the dominant mode of a Jacobian far from normal: float32 fan-out hubs with a field 1e-4 to 1e-2 of the rest read rho_spectral 0.157 for 0.349 and 0.503 for 0.397, settled | `major` | `context_dependent` | `open` | >=0.4.0.dev0 | | MADD-ANO-227 | Nodes whose timesteps are more than about 1e9 apart, or have no common step the float GCD finds, ran on different clocks with no error | `major` | `context_dependent` | `resolved` (in 0.4.0) | >=0.1.0, <0.4.0 | | MADD-ANO-228 | REST read a boolean or numeric text as a timestep (`true` added a node stepping at 1.0 s), and clamped the counts of POST /sim/profile without saying so | `major` | `context_dependent` | `resolved` (in 0.4.0) | >=0.1.0, <0.4.0 | -| MADD-ANO-231 | A coupling group under IQN whose iterate left float range before its cap never returned from step() | `major` | `context_dependent` | `resolved` (in 0.4.0) | >=0.3.0, <0.4.0 | -| MADD-ANO-232 | gradient_relative_error_bound read below the error, gradient_bound_usable=True, with a constant in it whose tangent is rounding: 1.09 for a relative error of 1.134 | `major` | `context_dependent` | `resolved` (in 0.4.0) | none | +| MADD-ANO-233 | A coupling group under IQN whose iterate left float range before its cap never returned from step() | `major` | `context_dependent` | `resolved` (in 0.4.0) | >=0.3.0, <0.4.0 | +| MADD-ANO-234 | gradient_relative_error_bound read below the error, gradient_bound_usable=True, with a constant in it whose tangent is rounding: 1.09 for a relative error of 1.134 | `major` | `context_dependent` | `resolved` (in 0.4.0) | none | *232 anomalies registered. 37 have a defect reachable in this version — every entry whose `resolution_status` is not `resolved` or `duplicate`, which is 28 `open` plus 9 `partially_resolved` whose residual risk is still live. The Affected Versions column is a PEP 440 specifier set read against this document's version; `none` marks a defect introduced and fixed within one development cycle, which no release carried. The convention, and the gate that holds every range to it, are in the header of `known_anomalies.yaml`. Rationale, workaround, affected components and verification evidence for each: `known_anomalies.yaml`.* diff --git a/tests/compliance/test_soup_evidence.py b/tests/compliance/test_soup_evidence.py index da65005a..c75a13aa 100644 --- a/tests/compliance/test_soup_evidence.py +++ b/tests/compliance/test_soup_evidence.py @@ -97,7 +97,7 @@ def test_the_committed_soup_tables_match_a_fresh_generation(): # anomaly is closed -- resolved, or a duplicate of the entry that carries it # -- and stays in the registry; only a closed entry, or a number no commit # ever recorded, can be retired. The gate reads the last status from git. -_HIGHEST_ANOMALY_ID = 232 +_HIGHEST_ANOMALY_ID = 234 _RETIRED_ANOMALY_IDS: dict = {} _HIGHEST_BENCHMARK_ID = 16 From 7a6ae1cd214056abaae5dda96ab9076a1870addd Mon Sep 17 00:00:00 2001 From: Nicholas Ehsan Roy Date: Wed, 7 Oct 2026 10:25:28 +0200 Subject: [PATCH 13/13] test(coupling): the slow nonlinear hunt puts no floor on a rounding-dependent fraction Whether a pass resolves a nonlinearity's own constant depends on where the float32 iterate stops: one block scores 0.17 to 0.57 of its examples on the development machine and none on CI's runners. The per-push seed holds that the score is not empty. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013UkCde7g23gTziUjYAvnKD --- tests/property/test_coupling_nonlinear_search.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/property/test_coupling_nonlinear_search.py b/tests/property/test_coupling_nonlinear_search.py index 4736d731..06815c52 100644 --- a/tests/property/test_coupling_nonlinear_search.py +++ b/tests/property/test_coupling_nonlinear_search.py @@ -929,9 +929,14 @@ def test_the_hunt_finds_no_number_on_the_wrong_side_of_a_nonlinear_group(block, assert fractions["usable"] >= USABLE_FLOOR, ( f"{name}, block {block}: only {fractions['usable']:.2f} of the examples had the flag " f"set (floor {USABLE_FLOOR})") - if name == "gradient_vanishing": - # Measured 0.17 to 0.57 by block: the score is not empty. - assert fractions["vanishing_scored"] > 0, fractions + # No floor on fractions["vanishing_scored"] here. Whether the pass + # resolves a nonlinearity's own constant depends on where the float32 + # iterate stops relative to its fixed point, and that is a matter of + # rounding: one block reads 0.17 to 0.57 with jaxlib 0.11.0 on the + # development machine and 0.0 on CI's runners (same seed, jaxlib 0.10.2 + # and 0.11.2). That the score is not empty is held per push, by the + # seed ``a-nonlinearity-s-own-constant-resolved-short-of-the-fixed-point`` + # (test_every_score_holds_on_the_nonlinear_seed_shapes), which CI runs. def test_the_reference_s_jacobian_is_the_central_difference_of_its_pass():