|
18 | 18 | _collapse_stacked_candidates, |
19 | 19 | ) |
20 | 20 | from _lcm.egm.interp import interp_on_padded_grid, prepare_padded_grid |
| 21 | +from lcm.solvers import GridSearch |
21 | 22 | from tests.conftest import X64_ENABLED |
| 23 | +from tests.test_models import negm_kinked_toy as negm_toy |
22 | 24 |
|
23 | 25 | # The host comparison reruns the identical interpolation arithmetic, so the two |
24 | 26 | # sides agree to the active float precision's roundoff, not better. |
@@ -466,3 +468,26 @@ def test_a_poisoned_candidate_at_a_nonzero_index_keeps_the_collapse_nan(): |
466 | 468 |
|
467 | 469 | assert bool(jnp.isnan(value[0])) |
468 | 470 | assert bool(jnp.isnan(marginal[0])) |
| 471 | + |
| 472 | + |
| 473 | +def test_negm_solver_declares_its_stacked_candidate_count(): |
| 474 | + """A NEGM solver's published carry stacks one row per outer node plus keeper. |
| 475 | +
|
| 476 | + The parent's continuation read sizes its candidate axis off this |
| 477 | + declaration, so it must equal the outer-grid length plus the keeper slot. |
| 478 | + """ |
| 479 | + assert ( |
| 480 | + negm_toy.NEGM_SOLVER.n_stacked_carry_candidates |
| 481 | + == negm_toy.OUTER_GRID.n_points + 1 |
| 482 | + ) |
| 483 | + |
| 484 | + |
| 485 | +def test_non_stacking_solvers_declare_zero_stacked_candidates(): |
| 486 | + """A solver that publishes an already-collapsed carry declares no candidates. |
| 487 | +
|
| 488 | + An outer margin folded inside the solver (or no outer margin at all) |
| 489 | + leaves the carry without a candidate axis; the parent read must then |
| 490 | + query each carry row once instead of broadcasting queries over a |
| 491 | + phantom axis. |
| 492 | + """ |
| 493 | + assert GridSearch().n_stacked_carry_candidates == 0 |
0 commit comments