Metadata-Version: 2.4
Name: feral-solver
Version: 0.4.0
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Rust
Classifier: Topic :: Scientific/Engineering :: Mathematics
Requires-Dist: numpy>=1.23
Requires-Dist: maturin>=1.5,<2.0 ; extra == 'dev'
Requires-Dist: pytest>=7 ; extra == 'dev'
Requires-Dist: scipy>=1.10 ; extra == 'dev'
Requires-Dist: numpy>=1.23 ; extra == 'dev'
Requires-Dist: jax>=0.4.30 ; extra == 'dev'
Requires-Dist: ruff>=0.5 ; extra == 'dev'
Requires-Dist: mypy>=1.10 ; extra == 'dev'
Requires-Dist: jax>=0.4.30 ; extra == 'jax'
Requires-Dist: scipy>=1.10 ; extra == 'scipy'
Requires-Dist: pytest>=7 ; extra == 'test'
Requires-Dist: scipy>=1.10 ; extra == 'test'
Requires-Dist: numpy>=1.23 ; extra == 'test'
Requires-Dist: jax>=0.4.30 ; extra == 'test'
Provides-Extra: dev
Provides-Extra: jax
Provides-Extra: scipy
Provides-Extra: test
Summary: Sparse symmetric indefinite direct solver with certified inertia, in pure Rust.
Keywords: sparse,solver,linear-algebra,ldlt,kkt,interior-point
Author-email: John Kitchin <jkitchin@andrew.cmu.edu>
License: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/jkitchin/feral
Project-URL: Issues, https://github.com/jkitchin/feral/issues
Project-URL: Repository, https://github.com/jkitchin/feral

# feral-solver

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

## Install

```bash
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

```python
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.

```python
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.

## scipy.sparse interop

```python
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+.

```bash
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.

