1 core.autodiff
core.autodiff
Automatic differentiation for symbolic expressions.
Implements symbolic differentiation using the chain rule, producing gradient expressions that can be compiled for fast evaluation.
Supports native gradient rules for vector expressions (VectorSum, LinearCombination, DotProduct) with O(1) coefficient lookup for scalability to n=10,000+ variables.
1.1 Classes
| Name | Description |
|---|---|
| SparsityPattern | Describes which gradient elements are structurally non-zero. |
| VectorExpressionPattern | Classification of patterns in gradient expressions for optimization. |
| VectorGradientPattern | Represents a gradient of the form ∇f(x) = Ax + b. |
1.1.1 SparsityPattern
core.autodiff.SparsityPattern(nnz_indices, size, is_constant, constant_values)Describes which gradient elements are structurally non-zero.
Enables O(nnz) gradient/Jacobian computation by identifying which variables an expression depends on, without computing values.
1.1.1.1 Attributes
| Name | Type | Description |
|---|---|---|
| nnz_indices | NDArray[np.intp] | Sorted array of indices (into the variables list) that have non-zero partial derivatives. |
| size | int | Total number of variables (length of full gradient vector). |
| is_constant | bool | True if all non-zero gradients are constants (e.g. linear expr). |
| constant_values | NDArray[np.floating] | None | If is_constant, the non-zero gradient values at nnz_indices. None if gradients are not all constant. |
1.1.2 VectorExpressionPattern
core.autodiff.VectorExpressionPattern()Classification of patterns in gradient expressions for optimization.
These patterns allow the compiler to generate specialized, high-performance kernels for common vector operations instead of using generic element-wise logic.
1.1.3 VectorGradientPattern
core.autodiff.VectorGradientPattern(
linear_term,
constant_term,
vector,
linear_type=None,
linear_scale=0.0,
linear_diag=None,
)Represents a gradient of the form ∇f(x) = Ax + b.
Used for vectorized compilation of gradients for: - Linear combinations (A=None, b=c) - Quadratic forms (A=Q+Q’, b=0) - Dot products (A=2I, b=0)
1.2 Functions
| Name | Description |
|---|---|
| analyze_gradient_sparsity | Analyze which gradient elements are structurally non-zero. |
| analyze_jacobian_sparsity | Analyze the sparsity structure of the full Jacobian matrix. |
| apply_gradient_rule | Apply the registered gradient rule for an expression type. |
| compile_hessian | Compile the Hessian for fast evaluation. |
| compile_jacobian | Compile the Jacobian for fast evaluation. |
| compile_sparse_jacobian | Compile the Jacobian for fast evaluation, returning sparse output. |
| compute_hessian | Compute the Hessian matrix of an expression. |
| compute_jacobian | Compute the Jacobian matrix of expressions with respect to variables. |
| detect_affine_gradient_pattern | Detect if an expression has a vectorizable gradient pattern: ∇f(x) = Ax + b. |
| detect_vector_gradient_pattern | Detect the structural pattern of an expression. |
| gradient | Compute the symbolic gradient of an expression with respect to a variable. |
| has_gradient_rule | Check if an expression type has a registered gradient rule. |
| increased_recursion_limit | Temporarily increase Python’s recursion limit. |
| register_gradient | Decorator to register a gradient rule for an expression type. |
1.2.1 analyze_gradient_sparsity
core.autodiff.analyze_gradient_sparsity(expr, variables)Analyze which gradient elements are structurally non-zero.
Determines which variables the expression depends on by walking the expression tree, then optionally checks if those gradients are constant (for linear expressions).
1.2.1.1 Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| expr | Expression | The expression to analyze. | required |
| variables | list[Variable] | List of variables defining the gradient vector ordering. | required |
1.2.1.2 Returns
| Name | Type | Description |
|---|---|---|
| SparsityPattern | SparsityPattern describing which gradient elements are non-zero. |
1.2.2 analyze_jacobian_sparsity
core.autodiff.analyze_jacobian_sparsity(exprs, variables)Analyze the sparsity structure of the full Jacobian matrix.
Returns per-row sparsity patterns describing which columns of each Jacobian row are structurally non-zero.
1.2.2.1 Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| exprs | list[Expression] | List of m expressions (rows of the Jacobian). | required |
| variables | list[Variable] | List of n variables (columns of the Jacobian). | required |
1.2.2.2 Returns
| Name | Type | Description |
|---|---|---|
| list[SparsityPattern] | List of m SparsityPattern objects, one per row. |
1.2.3 apply_gradient_rule
core.autodiff.apply_gradient_rule(expr, wrt)Apply the registered gradient rule for an expression type.
1.2.3.1 Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| expr | 'Expression' | The expression to differentiate. | required |
| wrt | 'Variable' | The variable to differentiate with respect to. | required |
1.2.3.2 Returns
| Name | Type | Description |
|---|---|---|
| 'Expression' | The gradient expression. |
1.2.3.3 Raises
| Name | Type | Description |
|---|---|---|
| ValueError | If no gradient rule is registered for this expression type. |
1.2.4 compile_hessian
core.autodiff.compile_hessian(expr, variables)Compile the Hessian for fast evaluation.
1.2.4.1 Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| expr | Expression | The expression to differentiate. | required |
| variables | list[Variable] | List of variables. | required |
1.2.4.2 Returns
| Name | Type | Description |
|---|---|---|
| Callable[[NDArray[np.floating]], NDArray[np.floating]] | A callable that takes a 1D array and returns the Hessian as a 2D array. |
1.2.4.3 Performance
For VectorPowerSum and VectorUnarySum, the Hessian is diagonal, so we use O(n) vectorized computation instead of O(n²).
1.2.5 compile_jacobian
core.autodiff.compile_jacobian(exprs, variables)Compile the Jacobian for fast evaluation.
1.2.5.1 Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| exprs | list[Expression] | List of expressions. | required |
| variables | list[Variable] | List of variables. | required |
1.2.5.2 Returns
| Name | Type | Description |
|---|---|---|
| Callable[[NDArray[np.floating]], NDArray[np.floating]] | A callable that takes a 1D array and returns the Jacobian as a 2D array. |
1.2.5.3 Performance
- Checks for vector patterns (O(1)) per row.
- Checks for constant rows (O(1)).
- Batches execution per row (m calls instead of m*n).
1.2.6 compile_sparse_jacobian
core.autodiff.compile_sparse_jacobian(exprs, variables, density_threshold=0.5)Compile the Jacobian for fast evaluation, returning sparse output.
For sparse constraint systems (nnz << mn), returns scipy.sparse.csr_matrix with O(nnz) memory instead of O(mn). Falls back to dense for high-density Jacobians.
1.2.6.1 Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| exprs | list[Expression] | List of expressions (rows of the Jacobian). | required |
| variables | list[Variable] | List of variables (columns of the Jacobian). | required |
| density_threshold | float | If overall Jacobian density exceeds this, fall back to the dense compile_jacobian (default 0.5). | 0.5 |
1.2.6.2 Returns
| Name | Type | Description |
|---|---|---|
| Callable[[NDArray[np.floating]], Any] | A callable that takes a 1D array and returns the Jacobian. | |
| Callable[[NDArray[np.floating]], Any] | Output is scipy.sparse.csr_matrix for sparse problems, or a dense | |
| Callable[[NDArray[np.floating]], Any] | 2D ndarray for high-density problems. |
1.2.7 compute_hessian
core.autodiff.compute_hessian(expr, variables)Compute the Hessian matrix of an expression.
1.2.7.1 Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| expr | Expression | The expression to differentiate twice. | required |
| variables | list[Variable] | List of variables. | required |
1.2.7.2 Returns
| Name | Type | Description |
|---|---|---|
| list[list[Expression]] | Hessian matrix as H[i][j] = d²(expr)/d(var_i)d(var_j). |
1.2.7.3 Note
The Hessian is symmetric, so H[i][j] = H[j][i]. We compute the full matrix but could optimize by exploiting symmetry.
1.2.8 compute_jacobian
core.autodiff.compute_jacobian(exprs, variables)Compute the Jacobian matrix of expressions with respect to variables.
Uses O(1) vectorized jacobian_row() methods when available for vector expressions (VectorSum, DotProduct, LinearCombination, QuadraticForm). Falls back to individual gradient() calls otherwise.
1.2.8.1 Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| exprs | list[Expression] | List of expressions (constraints or objectives). | required |
| variables | list[Variable] | List of variables to differentiate with respect to. | required |
1.2.8.2 Returns
| Name | Type | Description |
|---|---|---|
| list[list[Expression]] | Jacobian matrix as J[i][j] = d(expr_i)/d(var_j). |
1.2.8.3 Example
x, y = Variable(“x”), Variable(“y”) exprs = [x**2 + y, x*y] J = compute_jacobian(exprs, [x, y]) # J[0][0] = 2*x, J[0][1] = 1 # J[1][0] = y, J[1][1] = x
1.2.9 detect_affine_gradient_pattern
core.autodiff.detect_affine_gradient_pattern(expr)Detect if an expression has a vectorizable gradient pattern: ∇f(x) = Ax + b.
This enables O(1) compilation of gradients for common patterns like quadratic forms, dot products, and linear combinations, entirely bypassing the potentially large expression tree.
1.2.9.1 Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| expr | Expression | The expression to analyze. | required |
1.2.9.2 Returns
| Name | Type | Description |
|---|---|---|
| VectorGradientPattern | None | VectorGradientPattern if detected, None otherwise. |
1.2.10 detect_vector_gradient_pattern
core.autodiff.detect_vector_gradient_pattern(expr, wrt=None)Detect the structural pattern of an expression.
Identifies standard forms like sums, dot products, and norms that can be optimized by the compiler.
1.2.11 gradient
core.autodiff.gradient(expr, wrt)Compute the symbolic gradient of an expression with respect to a variable.
Uses a three-tier approach for optimal performance: 1. Registered gradient rules (O(1) for vector expressions) 2. Cached recursive computation (for shallow trees) 3. Iterative fallback (for deep trees to avoid RecursionError)
1.2.11.1 Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| expr | Expression | The expression to differentiate. | required |
| wrt | Variable | The variable to differentiate with respect to. | required |
1.2.11.2 Returns
| Name | Type | Description |
|---|---|---|
| Expression | A new Expression representing the derivative. |
1.2.11.3 Example
x = Variable(“x”) expr = x**2 + 3x grad = gradient(expr, x) # Returns: 2x + 3
1.2.12 has_gradient_rule
core.autodiff.has_gradient_rule(expr)Check if an expression type has a registered gradient rule.
1.2.12.1 Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| expr | 'Expression' | The expression to check. | required |
1.2.12.2 Returns
| Name | Type | Description |
|---|---|---|
| bool | True if a gradient rule is registered for this expression type. |
1.2.13 increased_recursion_limit
core.autodiff.increased_recursion_limit(limit=5000)Temporarily increase Python’s recursion limit.
This context manager can be used as a workaround for deep expression trees when the automatic iterative/recursive switching isn’t sufficient.
.. warning:: Use with caution - very high limits can cause stack overflow crashes. The iterative gradient implementation is preferred for deep trees.
1.2.13.1 Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| limit | int | The temporary recursion limit (default: 5000). | 5000 |
1.2.13.2 Returns
| Name | Type | Description |
|---|---|---|
| Iterator[None] | A context manager that restores the previous recursion limit when its | |
| Iterator[None] | with block exits. |
1.2.13.3 Example
with increased_recursion_limit(5000): … grad = gradient(deep_expr, x)
1.2.14 register_gradient
core.autodiff.register_gradient(expr_type)Decorator to register a gradient rule for an expression type.
Registered gradient rules are used by the main gradient() function before falling back to recursive tree traversal. This enables O(1) gradient computation for vector expressions.
1.2.14.1 Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| expr_type | type | The expression class to register a gradient rule for. | required |
1.2.14.2 Returns
| Name | Type | Description |
|---|---|---|
| Callable[[GradientFunc], GradientFunc] | A decorator that registers the gradient function. |
1.2.14.3 Example
@register_gradient(VectorSum) def gradient_vector_sum(expr: VectorSum, wrt: Variable) -> Expression: # O(1) gradient computation …