solvers
¤
Root finding and transient solvers.
Modules:
| Name | Description |
|---|---|
assembly |
Assembly functions for the transient circuit solver. |
linear |
Circuit Linear Solvers Strategy Pattern. |
transient |
Transient solvers to be used with Diffrax. |
Classes:
| Name | Description |
|---|---|
CircuitLinearSolver |
Abstract Base Class for all circuit linear solvers. |
DenseSolver |
Solves the system using dense matrix factorization (LU). |
KLUSolver |
Solves the system using the KLU sparse solver (via |
SparseSolver |
Solves the system using JAX's Iterative BiCGStab solver. |
VectorizedTransientSolver |
Transient solver that works strictly on FLAT (Real) vectors. |
Functions:
| Name | Description |
|---|---|
analyze_circuit |
Initializes a linear solver strategy for circuit analysis. |
assemble_system_complex |
Assemble the residual vectors and effective Jacobian values for an unrolled complex system. |
assemble_system_real |
Assemble the residual vectors and effective Jacobian values for a real system. |
setup_transient |
Configures and returns a function for executing transient analysis. |
CircuitLinearSolver
¤
Bases: AbstractLinearSolver
Abstract Base Class for all circuit linear solvers.
This class provides the unified interface for: 1. Storing static matrix structure (indices, rows, cols). 2. Handling Real vs. Complex-Unrolled system configurations. 3. Providing a robust Newton-Raphson DC Operating Point solver.
Attributes:
| Name | Type | Description |
|---|---|---|
ground_indices |
Array
|
Indices of nodes connected to ground (forced to 0V). |
is_complex |
bool
|
Static flag. If True, the system is 2N x 2N (Real/Imag unrolled). If False, the system is N x N (Real). |
Methods:
| Name | Description |
|---|---|
assume_full_rank |
Indicate if the solver assumes the operator is full rank. |
compute |
Performs the computation of the component for each step. |
init |
Initialize the solver state (No-op for stateless solvers). |
solve_dc |
Performs a robust DC Operating Point analysis (Newton-Raphson). |
compute
¤
Performs the computation of the component for each step.
In our case, we usually call _solve_impl directly to avoid overhead,
but this satisfies the API.
Source code in circulax/solvers/linear.py
init
¤
solve_dc
¤
Performs a robust DC Operating Point analysis (Newton-Raphson).
This method:
1. Detects if the system is Real or Complex based on self.is_complex.
2. Assembles the system with dt=infinity (to open capacitors).
3. Applies ground constraints (setting specific rows/cols to identity).
4. Solves the linear system J * delta = -Residual.
5. Applies voltage damping to prevent exponential overshoot.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups
|
dict
|
The circuit components and their parameters. |
required |
y_guess
|
Array
|
Initial guess vector (Shape: [N] or [2N]). |
required |
Returns:
| Type | Description |
|---|---|
Array
|
jax.Array: The converged solution vector (Flat). |
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 |
Performs the computation of the component for each step. |
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 |
Performs a robust DC Operating Point analysis (Newton-Raphson). |
compute
¤
Performs the computation of the component for each step.
In our case, we usually call _solve_impl directly to avoid overhead,
but this satisfies the API.
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
) -> DenseSolver
Factory method to pre-calculate indices for the dense matrix.
Source code in circulax/solvers/linear.py
init
¤
solve_dc
¤
Performs a robust DC Operating Point analysis (Newton-Raphson).
This method:
1. Detects if the system is Real or Complex based on self.is_complex.
2. Assembles the system with dt=infinity (to open capacitors).
3. Applies ground constraints (setting specific rows/cols to identity).
4. Solves the linear system J * delta = -Residual.
5. Applies voltage damping to prevent exponential overshoot.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups
|
dict
|
The circuit components and their parameters. |
required |
y_guess
|
Array
|
Initial guess vector (Shape: [N] or [2N]). |
required |
Returns:
| Type | Description |
|---|---|
Array
|
jax.Array: The converged solution vector (Flat). |
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 |
Performs the computation of the component for each step. |
from_component_groups |
Factory method to pre-hash indices for sparse coalescence. |
init |
Initialize the solver state (No-op for stateless solvers). |
solve_dc |
Performs a robust DC Operating Point analysis (Newton-Raphson). |
compute
¤
Performs the computation of the component for each step.
In our case, we usually call _solve_impl directly to avoid overhead,
but this satisfies the API.
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
) -> KLUSolver
Factory method to pre-hash indices for sparse coalescence.
Source code in circulax/solvers/linear.py
init
¤
solve_dc
¤
Performs a robust DC Operating Point analysis (Newton-Raphson).
This method:
1. Detects if the system is Real or Complex based on self.is_complex.
2. Assembles the system with dt=infinity (to open capacitors).
3. Applies ground constraints (setting specific rows/cols to identity).
4. Solves the linear system J * delta = -Residual.
5. Applies voltage damping to prevent exponential overshoot.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups
|
dict
|
The circuit components and their parameters. |
required |
y_guess
|
Array
|
Initial guess vector (Shape: [N] or [2N]). |
required |
Returns:
| Type | Description |
|---|---|
Array
|
jax.Array: The converged solution vector (Flat). |
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 |
Performs the computation of the component for each step. |
from_component_groups |
Factory method to prepare indices and diagonal mask. |
init |
Initialize the solver state (No-op for stateless solvers). |
solve_dc |
Performs a robust DC Operating Point analysis (Newton-Raphson). |
compute
¤
Performs the computation of the component for each step.
In our case, we usually call _solve_impl directly to avoid overhead,
but this satisfies the API.
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
) -> SparseSolver
Factory method to prepare indices and diagonal mask.
Source code in circulax/solvers/linear.py
init
¤
solve_dc
¤
Performs a robust DC Operating Point analysis (Newton-Raphson).
This method:
1. Detects if the system is Real or Complex based on self.is_complex.
2. Assembles the system with dt=infinity (to open capacitors).
3. Applies ground constraints (setting specific rows/cols to identity).
4. Solves the linear system J * delta = -Residual.
5. Applies voltage damping to prevent exponential overshoot.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
component_groups
|
dict
|
The circuit components and their parameters. |
required |
y_guess
|
Array
|
Initial guess vector (Shape: [N] or [2N]). |
required |
Returns:
| Type | Description |
|---|---|
Array
|
jax.Array: The converged solution vector (Flat). |
Source code in circulax/solvers/linear.py
VectorizedTransientSolver
¤
Bases: AbstractSolver
Transient solver that works strictly on FLAT (Real) vectors.
Delegates complexity handling to the 'linear_solver' strategy.
analyze_circuit
¤
analyze_circuit(
groups: list, num_vars: int, backend: str = "default", *, is_complex: bool = False
) -> CircuitLinearSolver
Initializes a linear solver strategy for circuit analysis.
This function serves as a factory and wrapper to select and configure the appropriate numerical backend for solving the linear system of equations 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 the 'klu' solver. |
'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. |
Source code in circulax/solvers/linear.py
assemble_system_complex
¤
assemble_system_complex(
y_guess: Array, component_groups: dict, t1: float, dt: float
) -> tuple[Array, Array, Array]
Assemble the residual vectors and effective Jacobian values for an unrolled complex system.
The complex state vector is stored in unrolled (block) format: the first
half of y_guess holds the real parts of all node voltages/states, the
second half holds the imaginary parts. This avoids JAX's limited support
for complex-valued sparse linear solvers by keeping all arithmetic real.
The Jacobian is split into four real blocks — RR, RI, IR, II — representing the partial derivatives of the real and imaginary residual components with respect to the real and imaginary state components respectively. The blocks are concatenated in RR→RI→IR→II order to match the sparsity index layout produced during compilation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y_guess
|
Array
|
Unrolled state vector of shape |
required |
component_groups
|
dict
|
Compiled component groups returned by
:func: |
required |
t1
|
float
|
Time at which the system is being evaluated. |
required |
dt
|
float
|
Timestep duration, used to scale the reactive Jacobian blocks. |
required |
Returns:
| Type | Description |
|---|---|
Array
|
A three-tuple |
Array
|
|
Array
|
|
tuple[Array, Array, Array]
|
|
Source code in circulax/solvers/assembly.py
assemble_system_real
¤
assemble_system_real(
y_guess: Array, component_groups: dict, t1: float, dt: float
) -> tuple[Array, Array, Array]
Assemble the residual vectors and effective Jacobian values for a real system.
For each component group, evaluates the physics at t1 and computes the
forward-mode Jacobian via jax.jacfwd. The effective Jacobian combines
the resistive and reactive contributions as J_eff = df/dy + (1/dt) * dq/dy,
consistent with the implicit trapezoidal discretisation used by the solver.
Components are processed in sorted key order to ensure a deterministic non-zero layout in the sparse Jacobian, which is required for the factorisation step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y_guess
|
Array
|
Current state vector of shape |
required |
component_groups
|
dict
|
Compiled component groups returned by
:func: |
required |
t1
|
float
|
Time at which the system is being evaluated. |
required |
dt
|
float
|
Timestep duration, used to scale the reactive Jacobian block. |
required |
Returns:
| Type | Description |
|---|---|
Array
|
A three-tuple |
Array
|
|
Array
|
|
tuple[Array, Array, Array]
|
|
Source code in circulax/solvers/assembly.py
setup_transient
¤
setup_transient(
groups: list,
linear_strategy: CircuitLinearSolver,
transient_solver: AbstractSolver = None,
) -> Callable[..., Solution]
Configures and returns a function for executing transient analysis.
This function acts as a factory, preparing a transient solver that is
pre-configured with the circuit's linear strategy. It returns a callable
that executes the time-domain simulation using diffrax.diffeqsolve.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
groups
|
list
|
A list of component groups that define the circuit. |
required |
linear_strategy
|
CircuitLinearSolver
|
The configured linear solver
strategy, typically obtained from |
required |
transient_solver
|
optional
|
The transient solver class to use.
If None, |
None
|
Returns:
| Type | Description |
|---|---|
Callable[..., Solution]
|
Callable[..., Any]: A function that executes the transient analysis. |
Callable[..., Solution]
|
This returned function accepts the following arguments: t0 (float): The start time of the simulation.
t1 (float): The end time of the simulation.
dt0 (float): The initial time step for the solver.
y0 (ArrayLike): The initial state vector of the system.
saveat (diffrax.SaveAt, optional): Specifies time points at which
to save the solution. Defaults to None.
max_steps (int, optional): The maximum number of steps the solver
can take. Defaults to 100000.
throw (bool, optional): If True, the solver will raise an error on
failure. Defaults to False.
term (diffrax.AbstractTerm, optional): The term defining the ODE.
Defaults to a zero-value ODETerm.
stepsize_controller (diffrax.AbstractStepSizeController, optional):
The step size controller. Defaults to |
Source code in circulax/solvers/transient.py
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 | |