linear ¤
Circuit linear solver strategies.
Separates physics assembly (Jacobian values) from the linear solve (matrix inversion). All solvers implement the lineax abstract interface and are JAX-transformable.
Classes:
| Name | Description |
|---|---|
CircuitLinearSolver | Abstract base for all circuit linear solvers. |
DenseSolver | Solves the system using dense matrix factorization (LU). |
KLUSolver | Solves the system using the KLU sparse solver (via |
KLUSplitLinear | KLU split solver paired with Modified Newton (frozen-Jacobian) for linear convergence. |
KLUSplitQuadratic | KLU split solver paired with full Newton for quadratic convergence via |
KLUSplitSolver | Solves the system using the KLU sparse solver (via |
SparseSolver | Solves the system using JAX's Iterative BiCGStab solver. |
Functions:
| Name | Description |
|---|---|
analyze_circuit | Initializes a linear solver strategy for circuit analysis. |
Attributes:
| Name | Type | Description |
|---|---|---|
DAMPING_EPS | float | Small additive epsilon that prevents division by zero in the damping formula. |
DAMPING_FACTOR | float | Newton-step damping coefficient: limits each step to at most |
DC_DT | float | Effective timestep used for DC analysis; makes capacitor stamps vanish (C/dt → 0). |
GROUND_STIFFNESS | float | Penalty added to ground-node diagonal entries to enforce V=0. |
DAMPING_EPS module-attribute ¤
DAMPING_EPS: float = 1e-09
Small additive epsilon that prevents division by zero in the damping formula.
DAMPING_FACTOR module-attribute ¤
DAMPING_FACTOR: float = 0.5
Newton-step damping coefficient: limits each step to at most DAMPING_FACTOR / |δy|_max.
DC_DT module-attribute ¤
DC_DT: float = 1e+18
Effective timestep used for DC analysis; makes capacitor stamps vanish (C/dt → 0).
GROUND_STIFFNESS module-attribute ¤
GROUND_STIFFNESS: float = 1000000000.0
Penalty added to ground-node diagonal entries to enforce V=0.
CircuitLinearSolver ¤
Bases: AbstractLinearSolver
Abstract base for all circuit linear solvers.
Attributes:
| Name | Type | Description |
|---|---|---|
ground_indices | Array | Indices of nodes connected to ground (forced to 0V). |
is_complex | bool | If True, the system is 2N×2N (real/imag unrolled); otherwise N×N. |
Methods:
| Name | Description |
|---|---|
assume_full_rank | Indicate if the solver assumes the operator is full rank. |
compute | Satisfies the lineax API; call |
init | Initialize the solver state (no-op for stateless solvers). |
solve_dc | DC operating point via damped Newton-Raphson. |
solve_dc_auto | DC Operating Point with automatic homotopy fallback. |
solve_dc_checked | DC Operating Point with convergence status. |
solve_dc_gmin | DC Operating Point via GMIN stepping (homotopy rescue). |
solve_dc_source | DC Operating Point via source stepping (homotopy rescue). |
compute ¤
Satisfies the lineax API; call _solve_impl directly for internal use.
init ¤
solve_dc ¤
solve_dc(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC operating point via damped Newton-Raphson.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_auto ¤
solve_dc_auto(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_gmin: int = 10,
n_source: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point with automatic homotopy fallback.
Attempts a direct Newton solve first. If it fails to converge, falls back to GMIN stepping followed by source stepping — all inside a single JIT-compiled kernel via jax.lax.cond.
Strategy: 1. _run_newton — plain damped Newton from y_guess. 2. On failure: solve_dc_gmin (GMIN stepping) starting from y_guess, then solve_dc_source (source stepping) from the GMIN result.
Because jax.lax.cond evaluates both branches at trace time but only one at runtime, this compiles to a single kernel with no Python- level branching.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage for GMIN stepping (rescue branch). | 0.01 |
n_gmin | int | Number of GMIN steps in the rescue branch. | 10 |
n_source | int | Number of source steps in the rescue branch. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_checked ¤
solve_dc_checked(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> tuple[Array, Array]
DC Operating Point with convergence status.
Identical to :meth:solve_dc but additionally returns a boolean JAX scalar indicating whether the Newton-Raphson fixed-point iteration reported success. Because the flag is a JAX array (not a Python bool) it can be consumed inside compiled programs:
.. code-block:: python
y, converged = solver.solve_dc_checked(groups, y0)
# Outside JIT — inspect in Python:
if not converged:
y = solver.solve_dc_gmin(groups, y0)
# Inside JIT — branch without Python-level control flow:
y = jax.lax.cond(converged, lambda: y, lambda: solver.solve_dc_gmin(groups, y0))
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
rtol | float | Relative tolerance for | 1e-06 |
atol | float | Absolute tolerance for | 1e-06 |
max_steps | int | Maximum Newton iterations. | 100 |
Returns:
| Type | Description |
|---|---|
tuple[Array, Array] |
|
Source code in circulax/solvers/linear.py
solve_dc_gmin ¤
solve_dc_gmin(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via GMIN stepping (homotopy rescue).
Steps the diagonal regularisation conductance g_leak logarithmically from g_start down to self.g_leak, using each converged solution as the warm start for the next step. The large initial g_leak linearises highly nonlinear components (diodes above threshold, lasers) that would otherwise cause Newton to diverge from a flat 0V start.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage conductance (large value, e.g. | 0.01 |
n_steps | int | Number of log-uniform steps from | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector after the full GMIN schedule. |
Source code in circulax/solvers/linear.py
solve_dc_source ¤
solve_dc_source(
component_groups: dict[str, Any],
y_guess: Array,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via source stepping (homotopy rescue).
Ramps all source amplitudes (components tagged with amplitude_param) from 10 % to 100 % of their netlist values, using each converged solution as the warm start for the next step. This guides Newton through the nonlinear region without the large initial step from 0V to full excitation.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
n_steps | int | Number of uniformly-spaced steps from 0.1 to 1.0. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector at full source amplitude. |
Source code in circulax/solvers/linear.py
DenseSolver ¤
Bases: CircuitLinearSolver
Solves the system using dense matrix factorization (LU).
Best For
- Small to Medium circuits (N < 2000).
- Wavelength sweeps (AC Analysis) on GPU.
- Systems where VMAP parallelism is critical.
Attributes:
| Name | Type | Description |
|---|---|---|
static_rows | Array | Row indices for placing values into dense matrix. |
static_cols | Array | Column indices. |
g_leak | float | Leakage conductance added to diagonal to prevent singularity. |
Methods:
| Name | Description |
|---|---|
assume_full_rank | Indicate if the solver assumes the operator is full rank. |
compute | Satisfies the lineax API; call |
from_component_groups | Factory method to pre-calculate indices for the dense matrix. |
init | Initialize the solver state (no-op for stateless solvers). |
solve_dc | DC operating point via damped Newton-Raphson. |
solve_dc_auto | DC Operating Point with automatic homotopy fallback. |
solve_dc_checked | DC Operating Point with convergence status. |
solve_dc_gmin | DC Operating Point via GMIN stepping (homotopy rescue). |
solve_dc_source | DC Operating Point via source stepping (homotopy rescue). |
compute ¤
Satisfies the lineax API; call _solve_impl directly for internal use.
from_component_groups classmethod ¤
from_component_groups(
component_groups: dict[str, Any],
num_vars: int,
*,
is_complex: bool = False,
g_leak: float = 1e-09
) -> DenseSolver
Factory method to pre-calculate indices for the dense matrix.
Source code in circulax/solvers/linear.py
init ¤
solve_dc ¤
solve_dc(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC operating point via damped Newton-Raphson.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_auto ¤
solve_dc_auto(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_gmin: int = 10,
n_source: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point with automatic homotopy fallback.
Attempts a direct Newton solve first. If it fails to converge, falls back to GMIN stepping followed by source stepping — all inside a single JIT-compiled kernel via jax.lax.cond.
Strategy: 1. _run_newton — plain damped Newton from y_guess. 2. On failure: solve_dc_gmin (GMIN stepping) starting from y_guess, then solve_dc_source (source stepping) from the GMIN result.
Because jax.lax.cond evaluates both branches at trace time but only one at runtime, this compiles to a single kernel with no Python- level branching.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage for GMIN stepping (rescue branch). | 0.01 |
n_gmin | int | Number of GMIN steps in the rescue branch. | 10 |
n_source | int | Number of source steps in the rescue branch. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_checked ¤
solve_dc_checked(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> tuple[Array, Array]
DC Operating Point with convergence status.
Identical to :meth:solve_dc but additionally returns a boolean JAX scalar indicating whether the Newton-Raphson fixed-point iteration reported success. Because the flag is a JAX array (not a Python bool) it can be consumed inside compiled programs:
.. code-block:: python
y, converged = solver.solve_dc_checked(groups, y0)
# Outside JIT — inspect in Python:
if not converged:
y = solver.solve_dc_gmin(groups, y0)
# Inside JIT — branch without Python-level control flow:
y = jax.lax.cond(converged, lambda: y, lambda: solver.solve_dc_gmin(groups, y0))
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
rtol | float | Relative tolerance for | 1e-06 |
atol | float | Absolute tolerance for | 1e-06 |
max_steps | int | Maximum Newton iterations. | 100 |
Returns:
| Type | Description |
|---|---|
tuple[Array, Array] |
|
Source code in circulax/solvers/linear.py
solve_dc_gmin ¤
solve_dc_gmin(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via GMIN stepping (homotopy rescue).
Steps the diagonal regularisation conductance g_leak logarithmically from g_start down to self.g_leak, using each converged solution as the warm start for the next step. The large initial g_leak linearises highly nonlinear components (diodes above threshold, lasers) that would otherwise cause Newton to diverge from a flat 0V start.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage conductance (large value, e.g. | 0.01 |
n_steps | int | Number of log-uniform steps from | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector after the full GMIN schedule. |
Source code in circulax/solvers/linear.py
solve_dc_source ¤
solve_dc_source(
component_groups: dict[str, Any],
y_guess: Array,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via source stepping (homotopy rescue).
Ramps all source amplitudes (components tagged with amplitude_param) from 10 % to 100 % of their netlist values, using each converged solution as the warm start for the next step. This guides Newton through the nonlinear region without the large initial step from 0V to full excitation.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
n_steps | int | Number of uniformly-spaced steps from 0.1 to 1.0. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector at full source amplitude. |
Source code in circulax/solvers/linear.py
KLUSolver ¤
Bases: CircuitLinearSolver
Solves the system using the KLU sparse solver (via klujax).
Best For
- Large circuits (N > 5000) running on CPU.
- DC Operating Points of massive meshes.
- Cases where DenseSolver runs out of memory (OOM).
Note
Does NOT support vmap (batching) automatically.
Methods:
| Name | Description |
|---|---|
assume_full_rank | Indicate if the solver assumes the operator is full rank. |
compute | Satisfies the lineax API; call |
from_component_groups | Factory method to pre-hash indices for sparse coalescence. |
init | Initialize the solver state (no-op for stateless solvers). |
solve_dc | DC operating point via damped Newton-Raphson. |
solve_dc_auto | DC Operating Point with automatic homotopy fallback. |
solve_dc_checked | DC Operating Point with convergence status. |
solve_dc_gmin | DC Operating Point via GMIN stepping (homotopy rescue). |
solve_dc_source | DC Operating Point via source stepping (homotopy rescue). |
compute ¤
Satisfies the lineax API; call _solve_impl directly for internal use.
from_component_groups classmethod ¤
from_component_groups(
component_groups: dict[str, Any],
num_vars: int,
*,
is_complex: bool = False,
g_leak: float = 1e-09
) -> KLUSolver
Factory method to pre-hash indices for sparse coalescence.
Source code in circulax/solvers/linear.py
init ¤
solve_dc ¤
solve_dc(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC operating point via damped Newton-Raphson.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_auto ¤
solve_dc_auto(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_gmin: int = 10,
n_source: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point with automatic homotopy fallback.
Attempts a direct Newton solve first. If it fails to converge, falls back to GMIN stepping followed by source stepping — all inside a single JIT-compiled kernel via jax.lax.cond.
Strategy: 1. _run_newton — plain damped Newton from y_guess. 2. On failure: solve_dc_gmin (GMIN stepping) starting from y_guess, then solve_dc_source (source stepping) from the GMIN result.
Because jax.lax.cond evaluates both branches at trace time but only one at runtime, this compiles to a single kernel with no Python- level branching.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage for GMIN stepping (rescue branch). | 0.01 |
n_gmin | int | Number of GMIN steps in the rescue branch. | 10 |
n_source | int | Number of source steps in the rescue branch. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_checked ¤
solve_dc_checked(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> tuple[Array, Array]
DC Operating Point with convergence status.
Identical to :meth:solve_dc but additionally returns a boolean JAX scalar indicating whether the Newton-Raphson fixed-point iteration reported success. Because the flag is a JAX array (not a Python bool) it can be consumed inside compiled programs:
.. code-block:: python
y, converged = solver.solve_dc_checked(groups, y0)
# Outside JIT — inspect in Python:
if not converged:
y = solver.solve_dc_gmin(groups, y0)
# Inside JIT — branch without Python-level control flow:
y = jax.lax.cond(converged, lambda: y, lambda: solver.solve_dc_gmin(groups, y0))
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
rtol | float | Relative tolerance for | 1e-06 |
atol | float | Absolute tolerance for | 1e-06 |
max_steps | int | Maximum Newton iterations. | 100 |
Returns:
| Type | Description |
|---|---|
tuple[Array, Array] |
|
Source code in circulax/solvers/linear.py
solve_dc_gmin ¤
solve_dc_gmin(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via GMIN stepping (homotopy rescue).
Steps the diagonal regularisation conductance g_leak logarithmically from g_start down to self.g_leak, using each converged solution as the warm start for the next step. The large initial g_leak linearises highly nonlinear components (diodes above threshold, lasers) that would otherwise cause Newton to diverge from a flat 0V start.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage conductance (large value, e.g. | 0.01 |
n_steps | int | Number of log-uniform steps from | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector after the full GMIN schedule. |
Source code in circulax/solvers/linear.py
solve_dc_source ¤
solve_dc_source(
component_groups: dict[str, Any],
y_guess: Array,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via source stepping (homotopy rescue).
Ramps all source amplitudes (components tagged with amplitude_param) from 10 % to 100 % of their netlist values, using each converged solution as the warm start for the next step. This guides Newton through the nonlinear region without the large initial step from 0V to full excitation.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
n_steps | int | Number of uniformly-spaced steps from 0.1 to 1.0. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector at full source amplitude. |
Source code in circulax/solvers/linear.py
KLUSplitLinear ¤
Bases: KLUSplitSolver
KLU split solver paired with Modified Newton (frozen-Jacobian) for linear convergence.
Extends :class:KLUSplitSolver with an explicit numeric factorization step so the Jacobian can be factored once per time step and reused across all Newton iterations within that step (Modified Newton / frozen-Jacobian scheme). Use together with :class:~circulax.solvers.transient.FactorizedTransientSolver.
Best For
- Large circuits (N > 5000) running on CPU where the Jacobian changes slowly.
- Transient simulations with many Newton iterations per step.
Methods:
| Name | Description |
|---|---|
assume_full_rank | Indicate if the solver assumes the operator is full rank. |
compute | Satisfies the lineax API; call |
factor_jacobian | Factor the Jacobian and return a numeric handle for repeated solves. |
from_component_groups | Factory — delegates to :meth: |
init | Initialize the solver state (no-op for stateless solvers). |
solve_dc | DC operating point via damped Newton-Raphson. |
solve_dc_auto | DC Operating Point with automatic homotopy fallback. |
solve_dc_checked | DC Operating Point with convergence status. |
solve_dc_gmin | DC Operating Point via GMIN stepping (homotopy rescue). |
solve_dc_source | DC Operating Point via source stepping (homotopy rescue). |
solve_with_frozen_jacobian | Solve using a pre-computed numeric factorization. |
compute ¤
Satisfies the lineax API; call _solve_impl directly for internal use.
factor_jacobian ¤
Factor the Jacobian and return a numeric handle for repeated solves.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
all_vals | Array | Flattened non-zero Jacobian values (COO format). | required |
Returns:
| Type | Description |
|---|---|
Array | Opaque numeric handle ( |
Array | meth: |
Array |
|
Source code in circulax/solvers/linear.py
from_component_groups classmethod ¤
from_component_groups(
component_groups: dict[str, Any],
num_vars: int,
*,
is_complex: bool = False,
g_leak: float = 1e-09
) -> KLUSplitLinear
Factory — delegates to :meth:KLUSplitSolver.from_component_groups.
Source code in circulax/solvers/linear.py
init ¤
solve_dc ¤
solve_dc(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC operating point via damped Newton-Raphson.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_auto ¤
solve_dc_auto(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_gmin: int = 10,
n_source: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point with automatic homotopy fallback.
Attempts a direct Newton solve first. If it fails to converge, falls back to GMIN stepping followed by source stepping — all inside a single JIT-compiled kernel via jax.lax.cond.
Strategy: 1. _run_newton — plain damped Newton from y_guess. 2. On failure: solve_dc_gmin (GMIN stepping) starting from y_guess, then solve_dc_source (source stepping) from the GMIN result.
Because jax.lax.cond evaluates both branches at trace time but only one at runtime, this compiles to a single kernel with no Python- level branching.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage for GMIN stepping (rescue branch). | 0.01 |
n_gmin | int | Number of GMIN steps in the rescue branch. | 10 |
n_source | int | Number of source steps in the rescue branch. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_checked ¤
solve_dc_checked(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> tuple[Array, Array]
DC Operating Point with convergence status.
Identical to :meth:solve_dc but additionally returns a boolean JAX scalar indicating whether the Newton-Raphson fixed-point iteration reported success. Because the flag is a JAX array (not a Python bool) it can be consumed inside compiled programs:
.. code-block:: python
y, converged = solver.solve_dc_checked(groups, y0)
# Outside JIT — inspect in Python:
if not converged:
y = solver.solve_dc_gmin(groups, y0)
# Inside JIT — branch without Python-level control flow:
y = jax.lax.cond(converged, lambda: y, lambda: solver.solve_dc_gmin(groups, y0))
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
rtol | float | Relative tolerance for | 1e-06 |
atol | float | Absolute tolerance for | 1e-06 |
max_steps | int | Maximum Newton iterations. | 100 |
Returns:
| Type | Description |
|---|---|
tuple[Array, Array] |
|
Source code in circulax/solvers/linear.py
solve_dc_gmin ¤
solve_dc_gmin(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via GMIN stepping (homotopy rescue).
Steps the diagonal regularisation conductance g_leak logarithmically from g_start down to self.g_leak, using each converged solution as the warm start for the next step. The large initial g_leak linearises highly nonlinear components (diodes above threshold, lasers) that would otherwise cause Newton to diverge from a flat 0V start.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage conductance (large value, e.g. | 0.01 |
n_steps | int | Number of log-uniform steps from | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector after the full GMIN schedule. |
Source code in circulax/solvers/linear.py
solve_dc_source ¤
solve_dc_source(
component_groups: dict[str, Any],
y_guess: Array,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via source stepping (homotopy rescue).
Ramps all source amplitudes (components tagged with amplitude_param) from 10 % to 100 % of their netlist values, using each converged solution as the warm start for the next step. This guides Newton through the nonlinear region without the large initial step from 0V to full excitation.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
n_steps | int | Number of uniformly-spaced steps from 0.1 to 1.0. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector at full source amplitude. |
Source code in circulax/solvers/linear.py
solve_with_frozen_jacobian ¤
Solve using a pre-computed numeric factorization.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
residual | Array | The right-hand side vector | required |
numeric | Array | Handle returned by :meth: | required |
Returns:
| Type | Description |
|---|---|
Solution | class: |
Source code in circulax/solvers/linear.py
KLUSplitQuadratic ¤
Bases: KLUSplitLinear
KLU split solver paired with full Newton for quadratic convergence via klu_refactor.
Extends :class:KLUSplitLinear with :meth:refactor_jacobian, which updates the numeric LU factorization in-place using klujax.refactor. The sparsity pattern is fixed for a given circuit topology, so KLU reuses the existing memory allocation and fill-reducing permutation — only the L/U values are recomputed. This gives full Newton (quadratic) convergence at a fraction of the cost of re-calling klu_factor at every iteration.
Use together with :class:~circulax.solvers.transient.RefactoringTransientSolver.
Best For
- Large circuits on CPU with nonlinear devices where quadratic convergence is desired.
- Transient simulations where the Jacobian changes significantly between Newton iterates.
Methods:
| Name | Description |
|---|---|
assume_full_rank | Indicate if the solver assumes the operator is full rank. |
compute | Satisfies the lineax API; call |
factor_jacobian | Factor the Jacobian and return a numeric handle for repeated solves. |
from_component_groups | Factory — delegates to :meth: |
init | Initialize the solver state (no-op for stateless solvers). |
refactor_jacobian | Update the numeric factorization in-place with new Jacobian values. |
solve_dc | DC operating point via damped Newton-Raphson. |
solve_dc_auto | DC Operating Point with automatic homotopy fallback. |
solve_dc_checked | DC Operating Point with convergence status. |
solve_dc_gmin | DC Operating Point via GMIN stepping (homotopy rescue). |
solve_dc_source | DC Operating Point via source stepping (homotopy rescue). |
solve_with_frozen_jacobian | Solve using a pre-computed numeric factorization. |
compute ¤
Satisfies the lineax API; call _solve_impl directly for internal use.
factor_jacobian ¤
Factor the Jacobian and return a numeric handle for repeated solves.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
all_vals | Array | Flattened non-zero Jacobian values (COO format). | required |
Returns:
| Type | Description |
|---|---|
Array | Opaque numeric handle ( |
Array | meth: |
Array |
|
Source code in circulax/solvers/linear.py
from_component_groups classmethod ¤
from_component_groups(
component_groups: dict[str, Any],
num_vars: int,
*,
is_complex: bool = False,
g_leak: float = 1e-09
) -> KLUSplitQuadratic
Factory — delegates to :meth:KLUSplitSolver.from_component_groups.
Source code in circulax/solvers/linear.py
init ¤
refactor_jacobian ¤
Update the numeric factorization in-place with new Jacobian values.
Reuses the existing memory allocation and fill-reducing permutation from the symbolic analysis; only the L/U values are recomputed. Faster than calling :meth:~KLUSplitLinear.factor_jacobian from scratch each Newton iteration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
all_vals | Array | Flattened non-zero Jacobian values (COO format). | required |
numeric | Array | Existing handle returned by :meth: | required |
Returns:
| Type | Description |
|---|---|
Array | Refreshed numeric handle (same underlying C++ object, now connected in the |
Array | XLA computation graph so the refactor cannot be eliminated as dead code). |
Source code in circulax/solvers/linear.py
solve_dc ¤
solve_dc(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC operating point via damped Newton-Raphson.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_auto ¤
solve_dc_auto(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_gmin: int = 10,
n_source: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point with automatic homotopy fallback.
Attempts a direct Newton solve first. If it fails to converge, falls back to GMIN stepping followed by source stepping — all inside a single JIT-compiled kernel via jax.lax.cond.
Strategy: 1. _run_newton — plain damped Newton from y_guess. 2. On failure: solve_dc_gmin (GMIN stepping) starting from y_guess, then solve_dc_source (source stepping) from the GMIN result.
Because jax.lax.cond evaluates both branches at trace time but only one at runtime, this compiles to a single kernel with no Python- level branching.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage for GMIN stepping (rescue branch). | 0.01 |
n_gmin | int | Number of GMIN steps in the rescue branch. | 10 |
n_source | int | Number of source steps in the rescue branch. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_checked ¤
solve_dc_checked(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> tuple[Array, Array]
DC Operating Point with convergence status.
Identical to :meth:solve_dc but additionally returns a boolean JAX scalar indicating whether the Newton-Raphson fixed-point iteration reported success. Because the flag is a JAX array (not a Python bool) it can be consumed inside compiled programs:
.. code-block:: python
y, converged = solver.solve_dc_checked(groups, y0)
# Outside JIT — inspect in Python:
if not converged:
y = solver.solve_dc_gmin(groups, y0)
# Inside JIT — branch without Python-level control flow:
y = jax.lax.cond(converged, lambda: y, lambda: solver.solve_dc_gmin(groups, y0))
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
rtol | float | Relative tolerance for | 1e-06 |
atol | float | Absolute tolerance for | 1e-06 |
max_steps | int | Maximum Newton iterations. | 100 |
Returns:
| Type | Description |
|---|---|
tuple[Array, Array] |
|
Source code in circulax/solvers/linear.py
solve_dc_gmin ¤
solve_dc_gmin(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via GMIN stepping (homotopy rescue).
Steps the diagonal regularisation conductance g_leak logarithmically from g_start down to self.g_leak, using each converged solution as the warm start for the next step. The large initial g_leak linearises highly nonlinear components (diodes above threshold, lasers) that would otherwise cause Newton to diverge from a flat 0V start.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage conductance (large value, e.g. | 0.01 |
n_steps | int | Number of log-uniform steps from | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector after the full GMIN schedule. |
Source code in circulax/solvers/linear.py
solve_dc_source ¤
solve_dc_source(
component_groups: dict[str, Any],
y_guess: Array,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via source stepping (homotopy rescue).
Ramps all source amplitudes (components tagged with amplitude_param) from 10 % to 100 % of their netlist values, using each converged solution as the warm start for the next step. This guides Newton through the nonlinear region without the large initial step from 0V to full excitation.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
n_steps | int | Number of uniformly-spaced steps from 0.1 to 1.0. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector at full source amplitude. |
Source code in circulax/solvers/linear.py
solve_with_frozen_jacobian ¤
Solve using a pre-computed numeric factorization.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
residual | Array | The right-hand side vector | required |
numeric | Array | Handle returned by :meth: | required |
Returns:
| Type | Description |
|---|---|
Solution | class: |
Source code in circulax/solvers/linear.py
KLUSplitSolver ¤
Bases: CircuitLinearSolver
Solves the system using the KLU sparse solver (via klujax) with split interface.
This solver performs symbolic analysis ONCE during initialization and reuses the symbolic handle for subsequent solves, significantly speeding up non-linear simulations (Newton-Raphson iterations).
Best For
- Large circuits (N > 5000) running on CPU.
- DC Operating Points of massive meshes.
Attributes:
| Name | Type | Description |
|---|---|---|
Bp, | Bi | CSC format indices (fixed structure). |
csc_map_idx | Bi | Mapping from raw value indices to CSC value vector. |
symbolic_handle | Bi | Pointer to the pre-computed KLU symbolic analysis. |
Methods:
| Name | Description |
|---|---|
assume_full_rank | Indicate if the solver assumes the operator is full rank. |
compute | Satisfies the lineax API; call |
from_component_groups | Factory method to pre-hash indices for sparse coalescence. |
init | Initialize the solver state (no-op for stateless solvers). |
solve_dc | DC operating point via damped Newton-Raphson. |
solve_dc_auto | DC Operating Point with automatic homotopy fallback. |
solve_dc_checked | DC Operating Point with convergence status. |
solve_dc_gmin | DC Operating Point via GMIN stepping (homotopy rescue). |
solve_dc_source | DC Operating Point via source stepping (homotopy rescue). |
compute ¤
Satisfies the lineax API; call _solve_impl directly for internal use.
from_component_groups classmethod ¤
from_component_groups(
component_groups: dict[str, Any],
num_vars: int,
*,
is_complex: bool = False,
g_leak: float = 1e-09
) -> KLUSplitSolver
Factory method to pre-hash indices for sparse coalescence.
Source code in circulax/solvers/linear.py
init ¤
solve_dc ¤
solve_dc(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC operating point via damped Newton-Raphson.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_auto ¤
solve_dc_auto(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_gmin: int = 10,
n_source: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point with automatic homotopy fallback.
Attempts a direct Newton solve first. If it fails to converge, falls back to GMIN stepping followed by source stepping — all inside a single JIT-compiled kernel via jax.lax.cond.
Strategy: 1. _run_newton — plain damped Newton from y_guess. 2. On failure: solve_dc_gmin (GMIN stepping) starting from y_guess, then solve_dc_source (source stepping) from the GMIN result.
Because jax.lax.cond evaluates both branches at trace time but only one at runtime, this compiles to a single kernel with no Python- level branching.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage for GMIN stepping (rescue branch). | 0.01 |
n_gmin | int | Number of GMIN steps in the rescue branch. | 10 |
n_source | int | Number of source steps in the rescue branch. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_checked ¤
solve_dc_checked(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> tuple[Array, Array]
DC Operating Point with convergence status.
Identical to :meth:solve_dc but additionally returns a boolean JAX scalar indicating whether the Newton-Raphson fixed-point iteration reported success. Because the flag is a JAX array (not a Python bool) it can be consumed inside compiled programs:
.. code-block:: python
y, converged = solver.solve_dc_checked(groups, y0)
# Outside JIT — inspect in Python:
if not converged:
y = solver.solve_dc_gmin(groups, y0)
# Inside JIT — branch without Python-level control flow:
y = jax.lax.cond(converged, lambda: y, lambda: solver.solve_dc_gmin(groups, y0))
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
rtol | float | Relative tolerance for | 1e-06 |
atol | float | Absolute tolerance for | 1e-06 |
max_steps | int | Maximum Newton iterations. | 100 |
Returns:
| Type | Description |
|---|---|
tuple[Array, Array] |
|
Source code in circulax/solvers/linear.py
solve_dc_gmin ¤
solve_dc_gmin(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via GMIN stepping (homotopy rescue).
Steps the diagonal regularisation conductance g_leak logarithmically from g_start down to self.g_leak, using each converged solution as the warm start for the next step. The large initial g_leak linearises highly nonlinear components (diodes above threshold, lasers) that would otherwise cause Newton to diverge from a flat 0V start.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage conductance (large value, e.g. | 0.01 |
n_steps | int | Number of log-uniform steps from | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector after the full GMIN schedule. |
Source code in circulax/solvers/linear.py
solve_dc_source ¤
solve_dc_source(
component_groups: dict[str, Any],
y_guess: Array,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via source stepping (homotopy rescue).
Ramps all source amplitudes (components tagged with amplitude_param) from 10 % to 100 % of their netlist values, using each converged solution as the warm start for the next step. This guides Newton through the nonlinear region without the large initial step from 0V to full excitation.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
n_steps | int | Number of uniformly-spaced steps from 0.1 to 1.0. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector at full source amplitude. |
Source code in circulax/solvers/linear.py
SparseSolver ¤
Bases: CircuitLinearSolver
Solves the system using JAX's Iterative BiCGStab solver.
Best For
- Large Transient Simulations on GPU (uses previous step as warm start).
- Systems where N is too large for Dense, but we need VMAP support.
Attributes:
| Name | Type | Description |
|---|---|---|
diag_mask | Array | Mask to extract diagonal elements for preconditioning. |
Methods:
| Name | Description |
|---|---|
assume_full_rank | Indicate if the solver assumes the operator is full rank. |
compute | Satisfies the lineax API; call |
from_component_groups | Factory method to prepare indices and diagonal mask. |
init | Initialize the solver state (no-op for stateless solvers). |
solve_dc | DC operating point via damped Newton-Raphson. |
solve_dc_auto | DC Operating Point with automatic homotopy fallback. |
solve_dc_checked | DC Operating Point with convergence status. |
solve_dc_gmin | DC Operating Point via GMIN stepping (homotopy rescue). |
solve_dc_source | DC Operating Point via source stepping (homotopy rescue). |
compute ¤
Satisfies the lineax API; call _solve_impl directly for internal use.
from_component_groups classmethod ¤
from_component_groups(
component_groups: dict[str, Any],
num_vars: int,
*,
is_complex: bool = False,
g_leak: float = 1e-09
) -> SparseSolver
Factory method to prepare indices and diagonal mask.
Source code in circulax/solvers/linear.py
init ¤
solve_dc ¤
solve_dc(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC operating point via damped Newton-Raphson.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_auto ¤
solve_dc_auto(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_gmin: int = 10,
n_source: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point with automatic homotopy fallback.
Attempts a direct Newton solve first. If it fails to converge, falls back to GMIN stepping followed by source stepping — all inside a single JIT-compiled kernel via jax.lax.cond.
Strategy: 1. _run_newton — plain damped Newton from y_guess. 2. On failure: solve_dc_gmin (GMIN stepping) starting from y_guess, then solve_dc_source (source stepping) from the GMIN result.
Because jax.lax.cond evaluates both branches at trace time but only one at runtime, this compiles to a single kernel with no Python- level branching.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage for GMIN stepping (rescue branch). | 0.01 |
n_gmin | int | Number of GMIN steps in the rescue branch. | 10 |
n_source | int | Number of source steps in the rescue branch. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector. |
Source code in circulax/solvers/linear.py
solve_dc_checked ¤
solve_dc_checked(
component_groups: dict[str, Any],
y_guess: Array,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> tuple[Array, Array]
DC Operating Point with convergence status.
Identical to :meth:solve_dc but additionally returns a boolean JAX scalar indicating whether the Newton-Raphson fixed-point iteration reported success. Because the flag is a JAX array (not a Python bool) it can be consumed inside compiled programs:
.. code-block:: python
y, converged = solver.solve_dc_checked(groups, y0)
# Outside JIT — inspect in Python:
if not converged:
y = solver.solve_dc_gmin(groups, y0)
# Inside JIT — branch without Python-level control flow:
y = jax.lax.cond(converged, lambda: y, lambda: solver.solve_dc_gmin(groups, y0))
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess vector (shape | required |
rtol | float | Relative tolerance for | 1e-06 |
atol | float | Absolute tolerance for | 1e-06 |
max_steps | int | Maximum Newton iterations. | 100 |
Returns:
| Type | Description |
|---|---|
tuple[Array, Array] |
|
Source code in circulax/solvers/linear.py
solve_dc_gmin ¤
solve_dc_gmin(
component_groups: dict[str, Any],
y_guess: Array,
g_start: float = 0.01,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via GMIN stepping (homotopy rescue).
Steps the diagonal regularisation conductance g_leak logarithmically from g_start down to self.g_leak, using each converged solution as the warm start for the next step. The large initial g_leak linearises highly nonlinear components (diodes above threshold, lasers) that would otherwise cause Newton to diverge from a flat 0V start.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
g_start | float | Starting leakage conductance (large value, e.g. | 0.01 |
n_steps | int | Number of log-uniform steps from | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector after the full GMIN schedule. |
Source code in circulax/solvers/linear.py
solve_dc_source ¤
solve_dc_source(
component_groups: dict[str, Any],
y_guess: Array,
n_steps: int = 10,
rtol: float = 1e-06,
atol: float = 1e-06,
max_steps: int = 100,
) -> Array
DC Operating Point via source stepping (homotopy rescue).
Ramps all source amplitudes (components tagged with amplitude_param) from 10 % to 100 % of their netlist values, using each converged solution as the warm start for the next step. This guides Newton through the nonlinear region without the large initial step from 0V to full excitation.
Implemented with jax.lax.scan — fully JIT/grad/vmap-compatible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups | dict[str, Any] | Compiled circuit components. | required |
y_guess | Array | Initial guess (typically | required |
n_steps | int | Number of uniformly-spaced steps from 0.1 to 1.0. | 10 |
rtol | float | Relative tolerance for each inner Newton solve. | 1e-06 |
atol | float | Absolute tolerance for each inner Newton solve. | 1e-06 |
max_steps | int | Max Newton iterations per step. | 100 |
Returns:
| Type | Description |
|---|---|
Array | Converged solution vector at full source amplitude. |
Source code in circulax/solvers/linear.py
analyze_circuit ¤
analyze_circuit(
groups: list,
num_vars: int,
backend: str = "default",
*,
is_complex: bool = False,
g_leak: float = 1e-09
) -> CircuitLinearSolver
Initializes a linear solver strategy for circuit analysis.
Factory that selects and configures the numerical backend for solving the linear system derived from a circuit's topology.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
groups | list | A list of component groups that define the circuit's structure and properties. | required |
num_vars | int | The total number of variables in the linear system. | required |
backend | str | The name of the solver backend to use. Supported backends are 'klu', 'klu_split', 'dense', and 'sparse'. Defaults to 'default', which uses 'klu_split'. | 'default' |
is_complex | bool | A flag indicating whether the circuit analysis involves complex numbers. Defaults to False. | False |
Returns:
| Name | Type | Description |
|---|---|---|
CircuitLinearSolver | CircuitLinearSolver | An instance of a circuit linear solver strategy |
CircuitLinearSolver | configured for the specified backend and circuit parameters. |
Raises:
| Type | Description |
|---|---|
ValueError | If the specified backend is not supported. |