API Reference
spice-rs can be used in three ways:
- Rust library -- direct integration via
spice_rscrate - WebAssembly module -- browser and Node.js usage via
spice-rs-wasm - sparse-rs -- standalone sparse matrix solver (KLU and Markowitz backends)
All three share the same simulation core. The WASM module wraps the Rust API with JSON serialization. sparse-rs is an independent crate that can be used without the SPICE engine.
Rust API
Add spice-rs as a dependency:
[dependencies]
spice-rs = { path = "../sim/spice-rs" }
High-level runner functions
All runner functions accept a netlist string and return a Result.
run_netlist
pub fn run_netlist(netlist: &str) -> Result<(HashMap<String, f64>, Analysis), String>
Runs whatever analysis the netlist specifies (.OP, .TRAN, .AC, .DC, .SENS, .TF, .PZ). Returns node voltages/branch currents as a HashMap, plus an Analysis enum indicating which analysis ran.
For .TRAN, the returned HashMap contains the values at the last timepoint.
run_netlist_tran_waveform
pub fn run_netlist_tran_waveform(netlist: &str)
-> Result<(Vec<String>, TransientResult), String>
Runs transient analysis and returns full waveforms. TransientResult has:
times: Vec<f64>-- time pointsvalues: Vec<Vec<f64>>-- one row per timepoint, one column per signalaccepted: usize-- number of accepted timestepsrejected: usize-- number of rejected timesteps
run_netlist_dc_sweep
pub fn run_netlist_dc_sweep(netlist: &str) -> Result<DcSweepWaveform, String>
Runs a .DC sweep analysis. DcSweepWaveform has:
sweep_values: Vec<f64>-- swept parameter valuessignals: HashMap<String, Vec<f64>>-- signal name to waveformnames: Vec<String>-- signal names
run_netlist_ac
pub fn run_netlist_ac(netlist: &str) -> Result<AcWaveform, String>
Runs .AC analysis. AcWaveform has:
frequencies: Vec<f64>-- frequency pointssignals_re: HashMap<String, Vec<f64>>-- real partsignals_im: HashMap<String, Vec<f64>>-- imaginary partnames: Vec<String>-- signal names
run_netlist_params
pub fn run_netlist_params(netlist: &str)
-> Result<Vec<(String, Vec<(String, f64)>)>, String>
Returns device operating-point parameters after DC analysis.
run_netlist_dc_op_profiled
pub fn run_netlist_dc_op_profiled(netlist: &str)
-> Result<(HashMap<String, f64>, Vec<NrSnapshot>), String>
Runs DC operating point and returns NR iteration snapshots for debugging convergence.
Complete example
use spice_rs::runner::run_netlist;
fn main() {
let netlist = "\
Voltage Divider
V1 vdd 0 DC 3.3
R1 vdd mid 10K
R2 mid 0 10K
.OP
.END
";
match run_netlist(netlist) {
Ok((voltages, _analysis)) => {
for (node, value) in &voltages {
println!("{}: {:.4} V", node, value);
}
}
Err(e) => eprintln!("Simulation error: {}", e),
}
}
Transient example
use spice_rs::runner::run_netlist_tran_waveform;
fn main() {
let netlist = "\
RC Step Response
V1 in 0 PULSE(0 1 0 1N 1N 10U 20U)
R1 in out 1K
C1 out 0 1N
.TRAN 10N 20U
.END
";
let (names, result) = run_netlist_tran_waveform(netlist).unwrap();
println!("Signals: {:?}", names);
println!("Timepoints: {}", result.times.len());
println!("Accepted: {}, Rejected: {}", result.accepted, result.rejected);
}
WASM API
The spice-rs-wasm package exposes spice-rs to JavaScript via WebAssembly. It works in browsers and Node.js.
Installation
Build from source with wasm-pack:
cd sim/spice-rs-wasm
wasm-pack build --target web
This produces a pkg/ directory with .wasm, .js, and .d.ts files.
SimulationEngine
All methods accept a SPICE netlist string and return a JSON string.
Constructor
dc_op(netlist) -> string
Runs DC operating point analysis. Returns:
{
"nodes": { "vdd": 3.3, "mid": 1.65 }
}
tran(netlist) -> string
Runs transient analysis with full waveforms. Returns:
{
"times": [0.0, 1e-9, 2e-9],
"signals": { "v(out)": [0.0, 0.001, 0.003] },
"names": ["v(out)", "v(in)"],
"accepted": 1234,
"rejected": 56
}
dc_sweep(netlist) -> string
Runs DC parameter sweep.
ac(netlist) -> string
Runs AC frequency sweep. Returns real/imaginary parts plus magnitude and phase.
simulate(netlist) -> string
Auto-detects analysis type and runs it.
parse_nodes(netlist) -> string
Returns the equation map (available signals) without running a simulation.
Schematic rendering methods
kdl_to_svg(kdl) -> string
Parses a KDL circuit description and returns an SVG string.
kdl_to_spice(kdl) -> string
Generates a SPICE netlist from a KDL circuit description.
kdl_extract_params(kdl) -> string
Extracts editable parameters from a KDL circuit.
Complete example
import init, { SimulationEngine } from './pkg/spice_rs_wasm.js';
async function main() {
await init();
const engine = new SimulationEngine();
const netlist = `
Voltage Divider
V1 vdd 0 DC 3.3
R1 vdd mid 10K
R2 mid 0 10K
.OP
.END
`;
const result = JSON.parse(engine.dc_op(netlist));
console.log("mid =", result.nodes.mid, "V");
}
main();
Error handling
All methods throw a JsError on failure.
sparse-rs API
sparse-rs is a pure Rust sparse matrix solver with two backends:
- KLU -- column-oriented LU factorization with BTF and AMD reordering, faithful port of SuiteSparse KLU
- Markowitz -- row-oriented factorization with Markowitz pivot selection, faithful port of Sparse 1.4
Both solve
Matrix construction
All backends use CscMatrix (compressed sparse column) as input:
use sparse_rs::CscMatrix;
let mat = CscMatrix::from_triplets(
n, // matrix dimension (n x n)
&rows, // row indices
&cols, // column indices
&values, // nonzero values
);
Duplicate entries at the same (row, col) are summed, matching the standard assembly convention for circuit matrices.
KLU backend
Three-phase workflow: symbolic analysis, numeric factorization, solve.
use sparse_rs::klu::{symbolic, numeric, solve};
// Phase 1: symbolic analysis (depends only on sparsity pattern)
let sym = symbolic(&mat);
// Phase 2: numeric factorization
let num = numeric(&mat, &sym).expect("factorization failed");
// Phase 3: solve Ax = b (solution overwrites b in-place)
let mut b = vec![1.0, 2.0, 3.0];
solve(&num, &sym, &mut b).expect("solve failed");
Symbolic analysis is expensive but only needs to run once for a given sparsity pattern. Numeric factorization and solve are fast and can be repeated when matrix values change but the pattern stays the same.
Markowitz backend
Two-phase workflow: combined ordering + factorization, then solve.
use sparse_rs::markowitz::{order_and_factor, solve};
let lu = order_and_factor(&mat).expect("factorization failed");
let mut b = vec![1.0, 2.0, 3.0];
solve(&lu, &mut b).expect("solve failed");
Choosing a backend
| KLU | Markowitz | |
|---|---|---|
| Best for | Large sparse systems (100+ nodes) | Small to medium systems |
| Reordering | AMD + BTF block decomposition | Markowitz criterion |
| Refactorization | Fast (reuse symbolic) | Must re-order |
| Complex support | Not yet | Yes |
| Used by | spice-rs (default solver) | spice-rs (AC analysis complex solve) |