loop
The JAX-pure SCP solve loop shared by solve_jax and solve_batched.
:func:make_solve_loop wraps any algorithm's fused iteration body in a
lax.while_loop keyed on convergence. The loop structure is generic harness
logic — the iteration cap, the freeze-on-converged jax.vmap semantics, the
projecting-away of per-iteration diagnostics — identical for every algorithm.
The one algorithm-specific piece is the convergence predicate, which the caller
passes in (typically :meth:Algorithm.converged), so a custom algorithm's
policy is honored on the JAX paths exactly as it is on the Python solve()
path.
make_solve_loop(iteration_fn: Callable[[AlgorithmState, dict], Tuple[AlgorithmState, object]], converged: Callable[[AlgorithmState], jnp.ndarray]) -> Callable[[AlgorithmState, dict], AlgorithmState]
¶
Wrap iteration_fn in a lax.while_loop keyed on convergence.
The loop runs iteration_fn until either converged(state) holds or
the iteration counter state.k exceeds state.k_max — matching the
Python while loop in Problem.solve(). The cap and the thresholds the
predicate reads are :class:AlgorithmState fields (runtime inputs, not
closure constants), so one built loop serves every tolerance / max_iters
setting and jax.vmap batches them per element. The per-iteration
diagnostics returned alongside the next state are projected away so the loop
carry stays state -> state (XLA dead-code-eliminates their host-only
pieces).
This loop backs Problem.solve_jax and Problem.solve_batched; the
Python Problem.solve() drives iteration_fn directly so it can record
the diagnostics into AlgorithmHistory per iteration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
iteration_fn
|
Callable[[AlgorithmState, dict], Tuple[AlgorithmState, object]]
|
A fused SCP body, |
required |
converged
|
Callable[[AlgorithmState], ndarray]
|
The algorithm's convergence predicate,
|
required |
Returns:
| Type | Description |
|---|---|
Callable[[AlgorithmState, dict], AlgorithmState]
|
|