Skip to main content

SoftOpt

A standalone optimizer that excels against leading market optimizers like Adam, in problems with a known, differentiable computation graph.

Each step is an update followed by an exact Newton correction computed from your own model, through Klein–Maimon soft-number calculus (Foundations of Soft Logic, Klein & Maimon, Springer 2024). Free, open source, and runs locally.

Is SoftOpt the right tool for your problem?

One question decides it, and you can answer it without running anything.

Can you get a residual vector? That is: can you compute model(theta) - data and get back an array, rather than a single number?

  • Yes → use scipy.optimize.least_squares. It builds the full Jacobian and exploits the least-squares structure, and it will beat SoftOpt on both accuracy and speed. This holds regardless of how large or how noisy the problem is. We measured it: on solar-cell parameter extraction, least_squares reached 7.9 mA against SoftOpt's 37.3 mA, and did it 21x faster.

  • No → SoftOpt is built for this case. Each evaluation returns one number, and it is noisy: a quantum measurement, a laser-tracker sweep, a backtest, a simulator that returns a score. There is no residual vector for least_squares to work with, and finite-difference methods like L-BFGS-B end up differentiating the noise rather than the model.

SoftOpt's advantage comes from taking the derivative from your model instead of from your measurements. That only matters when the measurements are the noisy part. Every validated domain below is of the second kind; that is not a convenience of selection, it is where the mechanism applies.

Where it helps

If your problem has a known computation graph — a quantum circuit, a physical simulator, a projection or measurement model, anything you can write down exactly, even if the measurements of it are noisy — SoftOpt computes an exact directional derivative of that model on every step, plus the curvature along the same direction, and uses them to correct the optimizer's trajectory. Validated, with real hardware-noise-model data, across:

  • Quantum chemistry (VQE) — H₂, H₄, BeH₂, HeH⁺, and larger multireference molecules
  • Quantum control (GRAPE) — the single cleanest result across every domain tested
  • Computer vision — multi-camera bundle adjustment / camera calibration
  • Finance — portfolio optimization (Markowitz mean-variance)
  • Condensed-matter physics — quasicrystal and spin-chain models (Ising, XY, Heisenberg, SSH, Kitaev)
  • Pharmacokinetics, logistic regression, and more

Where it does not help

Full reinforcement learning (or anything else with a continuously moving target — a policy, an adversary, a non-stationary distribution) is outside SoftOpt's validated scope. The mechanism needs a fixed objective to compute a meaningful correction against; a moving target breaks that assumption. Use plain Adam/SGD there.

Installation

pip install softopt

Quick start

import numpy as np
from softopt import SoftOpt, soft_compile

# Write your model once, in plain Python. No special arithmetic.
def my_model(theta):
    x, y = theta
    return (x - 2.0)**2 + np.exp(y) * x

# soft_compile turns it into the exact directional-derivative function
# SoftOpt needs, and verifies the result against your own model.
g_delta = soft_compile(my_model, n_params=2)

opt = SoftOpt(2, g_delta, lr=0.02)

for step in range(num_steps):
    grad_estimate = my_gradient_estimate(theta)   # e.g. from SPSA on real hardware
    theta = opt.step(theta, grad_estimate)

Your model needs to be built from arithmetic and the elementary functions the soft algebra defines: + - * / ** (including negative and fractional exponents, and 2.0 ** x), abs, sqrt, exp, log, log10, sin, cos, tanh, comparisons, and numpy's versions of those. Loops and if/else branching on parameter values work too — the compiled derivative is then valid on the branch your parameters are actually in.

The one thing to avoid is converting a traced value back to a plain number mid-model — float(x), or np.array(params) on the parameter list, both silently discard the derivative. soft_compile's verification catches this and says so.

If you'd rather write the derivative function yourself — because your model lives in a simulator SoftOpt can't trace, or because you want the speed of a hand-tuned implementation — pass any g_delta(theta, delta) that returns the exact directional derivative, and skip soft_compile entirely.

Validated results

All results below use IBM's FakeFez noise model via Qiskit + Aer, or realistic finite-sample/measurement noise for the non-quantum domains, with torch.optim.Adam as the baseline. Improvement is the reduction in gap to the known optimum (or, for Portfolio, the reduction in loss).

Quantum chemistry (VQE)

Domain Improvement Win rate
H₂ 66.6% 5/5
H₄ 89.8% 5/5
C₁₃Cl₂ (13-term Hamiltonian, incl. a 4-body term) 81.3% 5/5
BeH₂ 94.7% 5/5
HeH⁺ 90.9% 5/5

Quantum control

Domain Improvement Win rate
GRAPE (2-qubit) 84.0% 20/20

Condensed-matter & spin models

Domain Improvement Win rate
Ferromagnetic Ising (6-qubit chain) 82.1% 5/5
Transverse Ising (6-qubit chain) 71.2% 5/5
XY model (6-qubit chain) 62.3% 5/5
Antiferromagnetic Heisenberg (6-qubit chain) 61.3% 5/5
SSH model (topological, 6-qubit chain) 71.7% 5/5
Kitaev chain (6-qubit) 68.8% 5/5
Fibonacci chain (classical antiferromagnetic XY, N=16) 95.4% 10/10
Penrose quasicrystal XY-model (50 sites) 146.4% 10/10

Computer vision

Domain Improvement Win rate
Camera calibration (bundle adjustment, realistic pixel + outlier noise) 91.6% 16/20

Finance

Domain Improvement Win rate
Portfolio optimization (realistic backtest noise) ~58x lower loss 20/20

See benchmarks/ for the exact, runnable scripts behind every one of these numbers, including the raw per-seed results.

A performance table cannot show why a method wins. The ablation runs the optimizer's own code path while replacing the genuine soft-computed curvature with a frozen constant, or with real curvature measured at an unrelated point — everything else held identical.

On GRAPE, 1000 seeds per arm:

curvature fed to the correction mean gap genuine wins p
genuine 5.63e-06 — —
none (Adam alone) 2.52e-04 985/1000 3.3e-163
frozen constant 4.84e-01 1000/1000 3.3e-165
foreign point, fresh direction 4.12e-01 1000/1000 3.3e-165
foreign point, same direction 4.26e-01 1000/1000 3.3e-165

A correction fed a non-genuine value does not merely help less — it lands about 1600× worse than applying no correction at all. Run it yourself:

cd benchmarks/grape && python3 causal_ablation.py --seeds 1000
python3 tests/test_causal.py          # the same test, smaller and faster

Two interfaces to the same algebra

SoftNumber gives you operator syntax (x * y, x.exp()) and is what soft_compile traces your model with. The tuple functions (smul, sadd, ssin, ...) are the same operations applied to whole numpy arrays at once, which is what the benchmark engines use — a quantum circuit propagates 2ⁿ amplitudes per gate, and one Python object per amplitude would not be workable.

They are the same algebra and produce identical numbers; tests/test_causal.py asserts that agreement to 1e-15 across every operation, and also asserts that soft-number operations actually fire during an optimizer step.

The math

The full soft-number algebra is available from the package (from softopt import SoftNumber, sadd, smul, ...), each operation cited to its exact source in Foundations of Soft Logic (Klein & Maimon, Springer 2024):

Operation Book source Formula
sadd(a,b) §3.3.1, p.19 (a+c, b+d)
smul(a,b) §3.3.2, p.19 (ad+bc, bd)
sinv(a,b) Lemma 3.1, p.20 (−a/b², 1/b)
spow(x, n) Lemma 3.3, p.21 (n·a·bⁿ⁻¹, bⁿ)
sroot(x, n), ssqrt(x) Lemma 3.4 (p.22) & 3.5 (p.23) inverts spow
ssin, scos, sexp Lemma 6.1 (p.40) & §6.2 (p.41) f(a,b) = (a·f′(b), f(b))
sdiv(x,y) composition smul(x, sinv(y))

SoftNumber wraps these with operator syntax (x + y, x * y, x ** 3, x.sqrt()) and is verified, axiom by axiom, against the book's own proofs that bridge numbers form an abelian group under addition and a ring under both operations (tests/test_soft_number.py).

What SoftOpt is not

  • Not a claim to beat specialized full-Jacobian second-order solvers (Levenberg–Marquardt, L-BFGS) where those are already practical — SoftOpt's validated niche is genuine improvement over first-order optimizers (Adam, SGD) already in use, particularly where switching to a full second-order method isn't practical (embedded in a larger pipeline, high dimensionality, or measurement noise).
  • Not a general-purpose black-box optimizer — it requires a known computation graph, as described above.

License

MIT. See LICENSE.

Metadata

Release files for softopt 0.5.9

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

Source distribution (sdist)

Source distribution for softopt 0.5.9
File Size Uploaded Provenance Actions
softopt-0.5.9.tar.gz 24.2 kB Without provenance Details for softopt-0.5.9.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for softopt 0.5.9
File Interpreter ABI Platform Actions
softopt-0.5.9-py3-none-any.whl Python 3 none any Details for softopt-0.5.9-py3-none-any.whl

Total release size: 39.0 kB

Release files / softopt-0.5.9.tar.gz

Download URL softopt-0.5.9.tar.gz
Size 24.2 kB
Tags Source
SHA-256 checksum
How to use checksums
772ae3d6030692d79a9a3997b7f7522fe1c39da8be83d42b8eedcf3b9595d8a3
BLAKE2b-256 checksum
How to use checksums
71aafb31c72b490e1d995ceb4497baff3e9089198e4f11fe77782456217cb6b4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.7

Release files / softopt-0.5.9-py3-none-any.whl

Download URL softopt-0.5.9-py3-none-any.whl
Size 14.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b3d30c1de46de35f945421a01bff9280b84a6e56b1847944373afd7214dc9876
BLAKE2b-256 checksum
How to use checksums
55c9fd62e8f926173186e4d33beb5ab2b325901b1a59553c4d2d946d8fb11f22
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.7

Security for softopt 0.5.9

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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