Skip to main content

feral-solver

Python bindings for feral, a pure-Rust sparse symmetric indefinite direct solver with certified inertia counts. Aimed at interior-point methods (the IPM in discopt is the primary consumer), but usable for any application that factors symmetric KKT-shaped systems.

Install

pip install feral-solver           # plain
pip install 'feral-solver[scipy]'  # with scipy.sparse adapters
uv add feral-solver                # via uv

Wheels are published for CPython 3.10+ on Linux x86_64/aarch64, macOS universal2, and Windows x86_64. abi3 means one wheel per platform/arch covers all supported Python minor versions.

Quickstart

import numpy as np
import feral

A = feral.CscMatrix.from_dense(np.array([
    [4.0, 1.0, 0.0],
    [1.0, 3.0, 2.0],
    [0.0, 2.0, 5.0],
]))

solver = feral.Solver()
status, inertia = solver.factor(A)
assert status == feral.FactorStatus.SUCCESS
print(inertia)                       # Inertia(n_pos=3, n_neg=0, n_zero=0)

b = np.array([1.0, 2.0, 3.0])
x = solver.solve(b)
print(np.allclose(A.symv(x), b))     # True

IPM use

The feral.ipm.KktSolver class wraps Solver with the Wächter–Biegler 2006 §3.1 perturbation-escalation loop. Symbolic analysis is cached; across an entire Newton run solver.symbolic_call_count stays at 1.

import feral
import feral.ipm

kkt_pattern = feral.CscMatrix.from_scipy(my_kkt)   # see scipy adapter
kkt = feral.ipm.KktSolver(
    kkt_pattern,
    expected_inertia=feral.Inertia(n_vars, n_equality_constraints),
)
for newton_iter in range(max_iter):
    report = kkt.factor(values_this_iter)          # auto-perturbs if needed
    if report.status != feral.FactorStatus.SUCCESS:
        break
    dx_aff, dx_corr = kkt.solve_pair(b_aff, b_corr)
    ...

See examples/discopt_ipm_kkt.py for an end-to-end Newton step against a small NLP.

Unsymmetric LU basis engine

LuFactor factors a general square matrix and solves A x = b (ftran) / Aᵀ y = c (btran), with simplex-style product-form updates. It auto-routes to a dense or sparse engine via the same should_use_dense_lu heuristic the Rust core uses; pass force_dense=True/False to override.

import numpy as np
import feral

A = np.array([[2.0, 1.0, 0.0], [0.0, 3.0, 1.0], [1.0, 0.0, 4.0]])
lu = feral.LuFactor(feral.LuMatrix.from_dense(A))
x = lu.ftran(np.array([1.0, 2.0, 3.0]))     # solve A x = b
y = lu.btran(np.array([1.0, 0.0, 0.0]))     # solve Aᵀ y = c
lu.update(1, np.array([0.0, 5.0, 1.0]))     # replace basis column 1
# P A Q = L U :  A[perm][:, qcol] == l_array() @ u_array()

A singular basis raises SingularBasisError (a FactorError); an exhausted update budget raises NeedsRefactorError — call lu.refactor(new_matrix).

Factor access and introspection

After Solver.factor, the assembled factor and its statistics are available without re-solving:

s = feral.Solver(ordering="amd", profiling=True)
s.factor(A_csc)

fac = s.factors()                  # Factors snapshot
indptr, indices, data = fac.l_csc()   # unit-lower L as CSC (factorization order)
d_diag, d_subdiag = fac.d_blocks()    # block-diagonal D (2×2 where d_subdiag != 0)
L_scipy = fac.to_scipy_l()            # optional scipy.sparse.csc_matrix

# Reconstruction identity (factorization order):
#   L @ D @ L.T  ==  P (S A S) Pᵀ
# with fac.perm and the per-row fac.scaling vector.

stats = s.last_factor_stats()      # nnz, fill_ratio, inertia, pivot range, ...
print(s.min_pivot_magnitude, s.max_pivot_magnitude)
print(s.scaling_info.kind)         # "applied" | "mc64_fallback_to_infnorm" | ...
print(s.profile_report())          # populated when profiling=True

Solver.symbolic() (and the standalone feral.analyze(A_csc, ordering=...), which runs no numeric factorization) return a SymbolicAnalysis with the resolved ordering, perm/perm_inv, num_supernodes, factor_nnz_estimate, col_counts, and the elimination-tree etree_parent array (roots marked -1).

New Solver(...) keyword arguments — all optional, defaulting to the prior behavior — expose the tuning knobs: ordering ("amd", "amf", "metis", "scotch", "kahip", "auto", "auto_race"), mc64_cache, profiling, partial_singular_warning, and auto_cascade_break.

Conversion conveniences

CscMatrix.to_dense() returns the full symmetric matrix as a 2-D numpy array; CscMatrix.from_dense(a, triangle="lower"|"upper"|"full") ingests either triangle; CscMatrix.symmetric_pattern() returns the full (indptr, indices) structural pattern.

Example notebooks

Runnable notebooks live in examples/notebooks/. Regenerate them from the reviewable _build_notebooks.py generator: python _build_notebooks.py re-executes each notebook and commits its cell outputs (the embedded assertions double as a smoke test), or pass --no-execute for source-only .ipynb when feral is not installed in the running interpreter.

  • 01_basic_factor_solve — factor, certified inertia, solve, refine, reuse.
  • 02_multi_rhs_batched — batched multi-RHS solve, motivated by a steady-state heat-conduction sweep, with a correctness check and a looped-vs-batched timing showing the per-RHS speedup (issue #57).
  • 03_kkt_saddle_inertia — indefinite KKT system with certified inertia.
  • 04_scipy_numpy_interop — scipy.sparse round-trip vs spsolve.
  • 05_lu_and_introspection — the LU basis engine (ftran/btran, product-form updates, P A Q = L U), factor access (L/D reconstruction, feral.analyze), and introspection (knobs, factor stats, pivot range, scaling info) added in 0.11.0.

scipy.sparse interop

import scipy.sparse as sp
import feral

A_scipy = sp.csc_matrix(...)
A = feral.from_scipy(A_scipy, symmetric="full")    # reads lower triangle
# ... factor, solve ...
A_back = feral.to_scipy(A)                          # round-trips to scipy

Building from source

Requires a stable Rust toolchain (1.75+) and Python 3.10+.

git clone https://github.com/jkitchin/feral.git
cd feral/python
pip install maturin
maturin develop --release    # builds and installs into current venv
pytest tests/

License

MIT, same as the underlying Rust crate.

Metadata

Release files for feral-solver 0.19.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for feral-solver 0.19.0
File Size Uploaded
feral_solver-0.19.0.tar.gz 1.0 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for feral-solver 0.19.0
File
feral_solver-0.19.0-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
feral_solver-0.19.0-cp310-abi3-manylinux_2_28_aarch64.whl CPython 3.10 abi3 Linux glibc 2.28+ ARM64 Details
feral_solver-0.19.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details
feral_solver-0.19.0-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl CPython 3.10 abi3 macOS 10.12+ universal2 (ARM64, x86-64), macOS 11.0+ ARM64, macOS 10.12+ x86-64 Details

Total release size: 5.6 MB

Release files / feral_solver-0.19.0.tar.gz

Download URL feral_solver-0.19.0.tar.gz
Size 1.0 MB
Tags Source
SHA-256 checksum
How to use checksums
f7803b5848220dacb0f2ac7d8ffd2e95082a2db46aadd16e3cb4c56b357bdc42
BLAKE2b-256 checksum
How to use checksums
3a1d2fa1268b64646f9fb7e3445b5e90f590e2c7ec762dd35ab0e5e94f425ce2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / feral_solver-0.19.0-cp310-abi3-win_amd64.whl

Download URL feral_solver-0.19.0-cp310-abi3-win_amd64.whl
Size 899.8 kB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
397344fb50076f971830abfd12e786c1e096e2f1e0c768e691f078add87655a4
BLAKE2b-256 checksum
How to use checksums
899a6686674d12dfddd2e3f3a01558fcb662f4633fd8d881ff7ec715175ad404
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / feral_solver-0.19.0-cp310-abi3-manylinux_2_28_aarch64.whl

Download URL feral_solver-0.19.0-cp310-abi3-manylinux_2_28_aarch64.whl
Size 909.0 kB
Tags CPython 3.10 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
594c2e5738b1b1253e0bbb16f0fdc71bb6feb3067e05e419ce2497b8897e2057
BLAKE2b-256 checksum
How to use checksums
93c92b72867b16cc5e3f3e2a4fc032f848037e415e9454da72e853b741243fb7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / feral_solver-0.19.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL feral_solver-0.19.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 999.2 kB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
68cf3acb3f0295f77dbc99b536b8aca343bc62579f6d302694ce1826d737b37a
BLAKE2b-256 checksum
How to use checksums
ec013977893987c1efdd1da2fb6558c822c23976d2db689494b14e366a3c3fe2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / feral_solver-0.19.0-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl

Download URL feral_solver-0.19.0-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Size 1.8 MB
Tags CPython 3.10 abi3 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
9e3c4c501292fb52d680e59bb3c2761775f572712faa8b1e2c25e96631a79e27
BLAKE2b-256 checksum
How to use checksums
df231bff19ddae5b2a79bceb5b0bdab98ebfe43ea31e0b28f1dd0a1883f3e74f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.19.0 This release

5 release files

0.18.0

5 release files

0.17.0

5 release files

0.16.0

5 release files

0.15.1

5 release files

0.14.0

5 release files

0.11.3

5 release files

0.11.2

5 release files

0.11.1

5 release files

0.11.0

5 release files

0.9.0

5 release files

0.8.0

5 release files

0.7.0

5 release files

0.6.0

5 release files

0.5.0

5 release files

0.4.0

5 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page