discretization
Discretization methods for trajectory optimization.
This module provides implementations of discretization schemes that convert continuous-time optimal control problems into discrete-time approximations suitable for numerical optimization.
Discretization and linearization are combined into a single interface
(:class:Discretizer) because different schemes may linearize then discretize,
discretize then linearize, or use other approaches. The ordering changes the
intermediate types, but the input (continuous nonlinear dynamics + reference
trajectory) and output (discrete-time linear matrices A_d, B_d, C_d) are
always consistent.
:class:Problem uses :class:LinearizeDiscretizeSparse by default (sparse
Jacobians and compact variational integration when sparsity patterns exist).
:class:LinearizeDiscretize is the dense linearize-then-discretize scheme.
DiscretizeLinearizeVectorize
¶
Bases: Discretizer
Discretization via differentiating through the integrator for each segment individually.
Propagates the nonlinear dynamics for each trajectory segment on its own, then directly computes Jacobians of the propagated solutions (dF/dx, dF/du) via JAX forward-mode autodiff to produce discrete-time Jacobians for each node.
Supports ZOH (zero-order hold) and FOH (first-order hold) control interpolation between nodes, including independent per-control selection.
Use this integration scheme when the nonlinear dynamics are challenging (e.g. stiff/sensitive, badly scaled, or over long time horizons) and require very tight tolerances. A prototypical example is atmospheric entry of a spacecraft.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dis_type
|
Union[str, Sequence[str]]
|
Control hold type. |
'FOH'
|
ode_solver
|
str
|
Diffrax solver name. Any solver from
|
'Tsit5'
|
custom_integrator
|
bool
|
Use the built-in fixed-step RK45 integrator instead of Diffrax.
Faster but less robust. Defaults to |
False
|
diffrax_kwargs
|
Optional[dict[str, Any]]
|
Preferred Diffrax keyword overrides. These map to
:func: |
None
|
args
|
Optional[dict]
|
Deprecated alias for |
None
|
Source code in openscvx/discretization/discretize_linearize.py
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 | |
citation() -> List[str]
¶
Return BibTeX citations for the discretize-then-linearize-then-vectorize method.
Returns:
| Type | Description |
|---|---|
List[str]
|
List containing the BibTeX entries |
Source code in openscvx/discretization/discretize_linearize.py
get_solver(dynamics: Dynamics, settings: Config) -> callable
¶
Create a multiple-shooting discretize-then-linearize-then-vectorize solver.
Integrates dynamics.f and computes Jacobians of the discretized function directly
(i.e. without using the variational equations). Outputs are vmapped for batch evaluation
across nodes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dynamics
|
Dynamics
|
System dynamics. Only |
required |
settings
|
Config
|
Problem configuration. |
required |
Returns:
| Type | Description |
|---|---|
callable
|
Callable |
Source code in openscvx/discretization/discretize_linearize.py
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | |
Discretizer
¶
Bases: ABC
Abstract base class for dynamics linearization and discretization.
This class defines the interface for converting continuous-time nonlinear dynamics into discrete-time linear approximations suitable for convex subproblems in successive convexification.
The lifecycle mirrors other OpenSCvx ABCs:
Setup (called once):
- get_solver: Build a callable that computes discrete-time matrices
Per-iteration (via the returned callable):
- The callable is invoked with a reference trajectory and parameters, returning discretized matrices (A_d, B_d, C_d, x_prop)
Discretization parameters (hold type, integrator, tolerances) live on each concrete subclass as instance attributes.
Subclasses must implement the get_solver and citation methods.
Example
Implementing a custom discretizer::
class EulerDiscretizer(Discretizer):
def get_solver(self, dynamics, settings):
def solver(x, u, params):
# Euler discretization of dynamics
...
return A_d, B_d, C_d, x_prop, V
return solver
def citation(self):
return []
Source code in openscvx/discretization/base.py
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 | |
citation() -> List[str]
abstractmethod
¶
Return BibTeX citations for this discretization method.
Implementations should return a list of BibTeX entry strings for the papers that should be cited when using this discretization scheme.
Returns:
| Type | Description |
|---|---|
List[str]
|
List of BibTeX citation strings. |
Source code in openscvx/discretization/base.py
get_solver(dynamics: Dynamics, settings: Config) -> callable
abstractmethod
¶
Create a discretization solver callable.
Called once during problem initialization. Returns a function that computes linearized discrete-time dynamics matrices around a reference trajectory. The returned callable will be JIT-compiled and cached by the framework.
Implementations are responsible for computing any Jacobians they need.
The dynamics object always provides dynamics.f (the continuous-
time nonlinear dynamics). Implementations that linearize first may
compute Jacobians via jax.jacfwd(dynamics.f, ...).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dynamics
|
Dynamics
|
System dynamics object. |
required |
settings
|
Config
|
Problem configuration (node count, scaling matrices, etc.). |
required |
Returns:
| Name | Type | Description |
|---|---|---|
callable
|
Callable with signature |
|
callable
|
|
|
where |
callable
|
|
callable
|
|
|
callable
|
|
|
callable
|
|
|
callable
|
|
|
callable
|
|
Source code in openscvx/discretization/base.py
DiscretizerSpec
¶
Bases: BaseModel
Validates discretizer configuration from dict/YAML input.
A single spec covers all discretizer types. The type field selects
the concrete class; custom_integrator and args are only used by
the two vectorized variants and are silently ignored by the others.
Source code in openscvx/discretization/base.py
LinearizeDiscretize
¶
Bases: Discretizer
Linearize-then-discretize via augmented ODE integration.
Computes continuous-time Jacobians (df/dx, df/du) via JAX forward-mode autodiff, then integrates them alongside the nonlinear dynamics through an augmented state vector using a multi-shooting approach to produce discrete-time matrices.
Supports ZOH (zero-order hold) and FOH (first-order hold) control interpolation between nodes.
This is the default discretization scheme in OpenSCvx.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dis_type
|
Union[str, Sequence[str]]
|
Control hold type. |
'FOH'
|
ode_solver
|
str
|
Diffrax solver name. Any solver from
|
'Tsit5'
|
diffrax_kwargs
|
Optional[dict[str, Any]]
|
Preferred Diffrax keyword overrides. These map to
:func: |
None
|
Source code in openscvx/discretization/linearize_discretize.py
20 21 22 23 24 25 26 27 28 29 30 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 | |
citation() -> List[str]
¶
Return BibTeX citations for the linearize-then-discretize discretization method.
Returns:
| Type | Description |
|---|---|
List[str]
|
List containing the BibTeX entries |
Source code in openscvx/discretization/linearize_discretize.py
get_solver(dynamics: Dynamics, settings: Config) -> callable
¶
Create a multi-shoot discretization solver.
Computes Jacobians of dynamics.f via jax.jacfwd, vmaps all
functions for batch evaluation across nodes, and returns a callable
that integrates the augmented variational equations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dynamics
|
Dynamics
|
System dynamics. Only |
required |
settings
|
Config
|
Problem configuration. |
required |
Returns:
| Type | Description |
|---|---|
callable
|
Callable |
Source code in openscvx/discretization/linearize_discretize.py
LinearizeDiscretizeSparse
¶
Bases: LinearizeDiscretize
Sparse variant of linearize-then-discretize.
Uses graph-coloring-based sparse Jacobian computation and a compact
augmented state vector that only integrates the structurally nonzero
entries of Φ, B_d and C_d. This reduces the ODE system dimension
from n_x + n_x² + 2·n_x·n_u to n_x + nnz_Ad + nnz_Bd + nnz_Cd
per segment.
Requires A_c_sparsity and B_c_sparsity boolean arrays on the
:class:Dynamics object (set automatically when using the symbolic
problem interface). Falls back to the dense
:class:LinearizeDiscretize path when sparsity patterns are
unavailable or fully dense.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dis_type
|
Union[str, Sequence[str]]
|
Control hold type. |
'FOH'
|
ode_solver
|
str
|
Diffrax solver name. Defaults to |
'Tsit5'
|
diffrax_kwargs
|
Optional[dict[str, Any]]
|
Diffrax keyword overrides inherited from
:class: |
None
|
Source code in openscvx/discretization/linearize_discretize_sparse.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 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 | |
get_solver(dynamics: Dynamics, settings: Config) -> callable
¶
Create a sparse multi-shoot discretization solver.
When dynamics.A_c_sparsity and dynamics.B_c_sparsity are
available and the pattern is not fully dense, builds a compact-V
integration path with graph-coloring Jacobians. Otherwise
delegates to the dense parent implementation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dynamics
|
Dynamics
|
System dynamics with optional sparsity annotations. |
required |
settings
|
Config
|
Problem configuration. |
required |
Returns:
| Type | Description |
|---|---|
callable
|
Callable |
Source code in openscvx/discretization/linearize_discretize_sparse.py
VectorizeDiscretizeLinearize
¶
Bases: Discretizer
Discretization via differentiating through the integrator for all segments simultaneously.
Propagates the nonlinear dynamics over all trajectory segments at once, then directly computes Jacobians of the propagated solutions (dF/dx, dF/du) via JAX forward-mode autodiff to produce discrete-time Jacobians.
Supports ZOH (zero-order hold) and FOH (first-order hold) control interpolation between nodes, including independent per-control selection.
This integration scheme offers the best balance of speed and accuracy for most problems.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dis_type
|
Union[str, Sequence[str]]
|
Control hold type. |
'FOH'
|
ode_solver
|
str
|
Diffrax solver name. Any solver from
|
'Tsit5'
|
custom_integrator
|
bool
|
Use the built-in fixed-step RK45 integrator instead of Diffrax.
Faster but less robust. Defaults to |
False
|
diffrax_kwargs
|
Optional[dict[str, Any]]
|
Preferred Diffrax keyword overrides. These map to
:func: |
None
|
args
|
Optional[dict]
|
Deprecated alias for |
None
|
Source code in openscvx/discretization/discretize_linearize.py
21 22 23 24 25 26 27 28 29 30 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 | |
citation() -> List[str]
¶
Return BibTeX citations for the vectorize-then-discretize-then-linearize method.
Returns:
| Type | Description |
|---|---|
List[str]
|
List containing the BibTeX entries |
Source code in openscvx/discretization/discretize_linearize.py
get_solver(dynamics: Dynamics, settings: Config) -> callable
¶
Create a multiple-shooting vectorize-then-discretize-then-linearize solver.
Batches dynamics.f across all nodes, integrates it, and computes Jacobians of the
solution directly (i.e. without using the variational equations).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dynamics
|
Dynamics
|
System dynamics. Only |
required |
settings
|
Config
|
Problem configuration. |
required |
Returns:
| Type | Description |
|---|---|
callable
|
Callable |
Source code in openscvx/discretization/discretize_linearize.py
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 | |
calculate_impulsive_discretization(x_nodes: np.ndarray, u_nodes: np.ndarray, state_dot_discrete: callable, A_discrete: callable, B_discrete: callable, params: dict) -> tuple[jnp.ndarray, jnp.ndarray, jnp.ndarray, jnp.ndarray]
¶
Evaluate discrete/impulsive dynamics and Jacobians at all nodes.
Source code in openscvx/discretization/linearize_discretize.py
color_columns(pattern: np.ndarray) -> np.ndarray
¶
Greedy column coloring of a boolean sparsity pattern.
Two columns i and j can share a color when they have no row
in common where both are nonzero. This function assigns the fewest
colors possible via a greedy (first-fit) algorithm over columns
ordered by decreasing number of nonzeros.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pattern
|
ndarray
|
Boolean |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Integer array of length |
ndarray
|
(0-indexed). The number of distinct colors is |
Source code in openscvx/discretization/sparse_utils/sparse_jacobian.py
get_impulsive_discretization_solver(dyn_discrete: Dynamics) -> callable
¶
Create a solver for discrete/impulsive dynamics linearization.
Source code in openscvx/discretization/linearize_discretize.py
make_sparse_jacobian_fns(f: Callable, A_c_pattern: Optional[np.ndarray], B_c_pattern: Optional[np.ndarray], n_x: int, n_u: int) -> Tuple[Callable, Callable]
¶
Create vmapped sparse Jacobian functions for df/dx and df/du.
If a sparsity pattern is fully dense or None, falls back to the
standard jax.jacfwd path for that Jacobian.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
f
|
Callable
|
Dynamics function |
required |
A_c_pattern
|
Optional[ndarray]
|
Boolean |
required |
B_c_pattern
|
Optional[ndarray]
|
Boolean |
required |
n_x
|
int
|
Number of state dimensions. |
required |
n_u
|
int
|
Number of control dimensions. |
required |
Returns:
| Type | Description |
|---|---|
Callable
|
|
Callable
|
signature |
Source code in openscvx/discretization/sparse_utils/sparse_jacobian.py
resolve_discretizer_config(val: Any) -> DiscretizerSpec
¶
Validate a dict/Spec into a :class:DiscretizerSpec instance.
Injects the default type (VectorizeDiscretizeLinearize) when the
input dict omits it, preserving backwards compatibility.