base
Abstract base class for successive convexification algorithms.
:class:Algorithm is the contract every SCP algorithm implements: it builds the
JAX-pure iteration body, stores it, drives it one step at a time, and owns its
convergence policy. The iterate carry it threads lives in sibling modules —
:class:~openscvx.algorithms.state.AlgorithmState (the JAX-traceable current
iterate) and :class:~openscvx.algorithms.history.AlgorithmHistory (the
CPU-side append-only log) — matching the package's base.py-is-the-ABC idiom
(solvers/base.py, discretization/base.py, integrations/base.py).
Algorithm
¶
Bases: ABC
Abstract base class for successive convexification algorithms.
An Algorithm owns the SCP iteration end to end: it builds the
JAX-pure iteration body (:meth:build_iteration), stores it
(:meth:initialize), and drives it one step at a time (:meth:step).
step takes the current :class:AlgorithmState and a CPU-side
:class:AlgorithmHistory, returns the next state plus a convergence flag,
and appends to history for diagnostics.
Statefullness
Avoid storing mutable iteration state on self. All iteration
state lives on :class:AlgorithmState (JAX-traceable) and
:class:AlgorithmHistory (Python-side), threaded explicitly through
step().
The surface :class:~openscvx.problem.Problem relies on, beyond the
abstract methods below:
autotuner— the :class:AutotuningBasewhose declaredhyperfields :class:~openscvx.problem.Problemenumerates to build the per-solve / batched override channel.ep_tr/ep_vb/ep_vc— convergence thresholds :meth:Problem._sync_scp_constantssnapshots onto :class:AlgorithmStatebefore each solve.- :meth:
get_columns— the iteration-table columns to print. weights.build_vb_arrays— called once in :meth:Problem.initializeto size the virtual-buffer weight arrays.- :meth:
_hash_into— contributes the algorithm's identity to thesolve_batchedexport cache key.
t_max is honored only on the Python solve() path; the JAX
lax.while_loop behind solve_jax / solve_batched terminates on
k_max and the convergence predicate alone (no wall-clock probe inside a
trace).
Source code in openscvx/algorithms/base.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | |
__init__(weights: Weights, autotuner: AutotuningBase, k_max: int, t_max: Optional[float], ep_tr: float, ep_vb: float, ep_vc: float)
¶
Record the SCP weights, autotuner, and convergence parameters.
Subclasses build the user-facing defaults (PTR owns them) and end their
own __init__ with super().__init__(...); every parameter here is
required so the ABC is not a fourth place those defaults are declared.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
weights
|
Weights
|
SCP weights used by the algorithm and autotuner. |
required |
autotuner
|
AutotuningBase
|
The penalty-weight update rule (:class: |
required |
k_max
|
int
|
Maximum number of SCP iterations. |
required |
t_max
|
Optional[float]
|
Optional wall-clock time limit in seconds ( |
required |
ep_tr
|
float
|
Trust-region convergence threshold. |
required |
ep_vb
|
float
|
Virtual-buffer convergence threshold. |
required |
ep_vc
|
float
|
Virtual-control convergence threshold. |
required |
Source code in openscvx/algorithms/base.py
build_iteration(dis_continuous: Callable, dis_impulsive: Callable, jax_constraints: LoweredJaxConstraints, solver_callback: Callable, settings: Config) -> Callable
abstractmethod
¶
Build the JAX-pure SCP iteration body for this algorithm.
:class:~openscvx.problem.Problem assembles the discretization
solvers, lowered constraints, and convex-solver callback, then asks
the algorithm to fuse them into one step. The algorithm owns this
because the fusion is algorithm-specific (which autotuner runs, which
penalty terms are assembled); Problem stays algorithm-agnostic.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dis_continuous
|
Callable
|
Continuous-dynamics discretization solver,
|
required |
dis_impulsive
|
Callable
|
Impulsive/discrete-dynamics discretization solver,
|
required |
jax_constraints
|
LoweredJaxConstraints
|
Lowered JAX constraints the body operates over. |
required |
solver_callback
|
Callable
|
The convex backend's |
required |
settings
|
Config
|
Problem configuration. |
required |
Returns:
| Type | Description |
|---|---|
Callable
|
The JAX-pure |
Callable
|
iteration body. It must advance |
Callable
|
both |
Callable
|
behind |
Callable
|
class: |
Callable
|
and hands it back via :meth: |
Source code in openscvx/algorithms/base.py
citation() -> List[str]
abstractmethod
¶
converged(state: AlgorithmState) -> jnp.ndarray
¶
Boolean SCP convergence test from the metrics and thresholds on state.
The default — every metric below its threshold — is algorithm-agnostic:
:class:AlgorithmState carries J_tr / J_vb / J_vc and the
ep_* tolerances generically, so it serves any SCP algorithm. Override
to change the convergence policy; the override is honored on all three
solve paths (solve / solve_jax / solve_batched), since
:meth:step and the lax.while_loop harness both route through it.
Must be JAX-traceable: it runs inside the lax.while_loop cond of
solve_jax / solve_batched (where it is jax.vmap'd per batch
element) as well as on the Python solve() path.
Under save_compiled, the predicate is baked into the exported
solve_batched artifact, but the cache key sees only the algorithm's
class name (:meth:_hash_into): introducing an override — a new
subclass — is a clean cache miss, while editing the body of an
existing override is invisible to the key and silently loads the stale
artifact. Clear the solver cache (or rename the class) when iterating
on a predicate with save_compiled enabled.
Source code in openscvx/algorithms/base.py
get_columns(verbosity: int) -> List[Column]
abstractmethod
¶
Return the iteration-table columns to print at verbosity.
:class:~openscvx.problem.Problem calls this once per solve to lay
out the progress table. Implementations typically concatenate the
algorithm's own columns with the autotuner's COLUMNS and filter by
each column's min_verbosity.
Source code in openscvx/algorithms/base.py
initialize(iteration_fn: Callable, emitter: Callable) -> None
abstractmethod
¶
Store the fused SCP iteration body and per-iteration infrastructure.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
iteration_fn
|
Callable
|
The JAX-pure |
required |
emitter
|
Callable
|
Per-iteration diagnostics sink (printing queue / no-op). |
required |
Source code in openscvx/algorithms/base.py
step(state: AlgorithmState, history: AlgorithmHistory, params: dict, settings: Config) -> Tuple[AlgorithmState, bool]
abstractmethod
¶
Execute one iteration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
AlgorithmState
|
Current-iterate pytree. |
required |
history
|
AlgorithmHistory
|
CPU-side append-only iteration log. |
required |
params
|
dict
|
Problem parameters (may change between steps). |
required |
settings
|
Config
|
Configuration object (may change between steps). |
required |
Returns:
| Type | Description |
|---|---|
AlgorithmState
|
|
bool
|
and a flag indicating whether the SCP convergence criteria are |
Tuple[AlgorithmState, bool]
|
satisfied. |