Direct Python bindings for ripopt (interior-point NLP solver) with JAX autodiff
Project description
ripopt (Python)
Direct Python bindings for ripopt, the Rust interior-point NLP solver. Derivatives are built automatically from the user's objective and constraints via JAX autodiff, so you only have to write f(x) and g(x).
This is the analogue of cyipopt for ripopt. For symbolic modeling via Pyomo, see the separate pyomo-ripopt package.
Install
pip install maturin jax jaxlib numpy
maturin develop --release
Example: HS071
import jax.numpy as jnp
import numpy as np
from ripopt import minimize
def f(x):
return x[0] * x[3] * (x[0] + x[1] + x[2]) + x[2]
def g(x):
return jnp.array([
x[0] * x[1] * x[2] * x[3],
x[0]**2 + x[1]**2 + x[2]**2 + x[3]**2,
])
res = minimize(
f,
x0=[1.0, 5.0, 5.0, 1.0],
bounds=(1.0, 5.0),
constraints={"fun": g, "lb": [25.0, 40.0], "ub": [np.inf, 40.0]},
options={"tol": 1e-8},
)
print(res.x, res.fun)
Reusing a problem across many solves
minimize(...) is a single-shot scipy-style API: every call re-traces and re-JITs jax.hessian(lagrangian), which is the single most expensive step for a medium-sized problem. When you solve the same NLP structure many times in a row (e.g. closed-loop NMPC), use the persistent Problem class instead — it builds every JAX callback exactly once and reuses the XLA cache across all solves:
import jax.numpy as jnp
from ripopt import Problem
def stage_cost(z, x0):
x, u = z[:N], z[N:]
return jnp.sum((x - r) ** 2) + 0.01 * jnp.sum(u ** 2)
def dynamics(z, x0):
x, u = z[:N], z[N:]
x_prev = jnp.concatenate([jnp.atleast_1d(x0[0]), x[:-1]])
return x - A * x_prev - B * u
prob = Problem(
stage_cost,
x0=np.zeros(2 * N),
bounds=(lb, ub),
constraints={"fun": dynamics, "lb": 0.0, "ub": 0.0},
params=jnp.array([x0_current]), # extra traced arg threaded into fun and g
jac_mode="reverse", # jacrev is typically cheaper when m ≤ n
options={"tol": 1e-6},
)
for step in range(100):
prob.update_parameters(jnp.array([x0_current]))
res = prob.solve() # warm-starts from previous x* by default
examples/bench_nmpc.py runs this same pattern 100 times and compares minimize() vs Problem.solve() — the persistent object is typically several× faster because JAX tracing and XLA lowering of the Lagrangian Hessian happen exactly once for the Problem's lifetime, not once per call.
Warm-starting from an external solution
Problem.solve() accepts an explicit dual warm-start triple (lam0, z_l0, z_u0) — the constraint multipliers and upper/lower bound multipliers. This is the ripopt equivalent of seeding Ipopt with a cyipopt solution and lets you verify "is the reported x, λ, z_L, z_U a KKT point of this NLP?" independently of the solver's own initial-point and LS-estimate paths:
# e.g. a cyipopt solution you want ripopt to verify
x_star, lam_star, z_l_star, z_u_star = cyipopt_result
res = prob.solve(
x0=x_star,
lam0=lam_star,
z_l0=z_l_star,
z_u0=z_u_star,
)
All three dual arrays must be supplied together (partial specs raise ValueError); passing any of them implies warm_start=True. On plain NMPC-style restarts where you simply want to reuse the previous solve's multipliers, prob.solve(warm_start=True) is the shorter form.
API
minimize(fun, x0, *, bounds=None, constraints=None, options=None, sparsity='dense', params=None, jac_mode='forward') -> OptimizeResult
fun(x)— scalar, JAX-traceable.bounds—None,(lb, ub)with scalars or arrays of length n, or a scipy-style list of(lb_i, ub_i)pairs.constraints— a dict{"fun": g, "lb": ..., "ub": ...}or a list of such dicts. Uselb == ubfor equality.options— recognized keys:tol,max_iter,print_level,constr_viol_tol,dual_inf_tol,compl_inf_tol,max_wall_time,mu_init,hessian_approximation("exact"or"limited-memory").sparsity—'dense'(default) declares every entry structurally nonzero.'detect'probes the Jacobian and Lagrangian Hessian with two random(x, sigma, lambda)samples and takes the union of nonzero entries; with random multipliers, structural nonzeros are identified almost surely.
hessian_approximation="limited-memory" skips building the Hessian entirely and uses ripopt's L-BFGS path — useful when jax.hessian becomes expensive for larger problems.
Ctrl-C is honored: each callback polls PyErr_CheckSignals and the stashed KeyboardInterrupt is re-raised when the solve returns.
Performance
Rough numbers for HS071 on an M-series Mac, release build, warm JIT cache:
| configuration | total wall | solver only | iterations |
|---|---|---|---|
sparsity='dense' |
~155 ms | ~32 ms | 18 |
sparsity='detect' |
~155 ms | ~32 ms | 18 |
Raw ripopt (Rust) on the same problem is ~3 ms. The gap is per-callback JAX dispatch (~300 µs × 5 callbacks × 18 iterations ≈ 27 ms); for problems where ripopt dominates the wall clock this gap is amortized. Run python examples/bench_hs071.py to reproduce.
Documentation
examples/tutorial.ipynb— runnable notebook walking through unconstrained, box-constrained, HS071, options, L-BFGS, sparsity detection, and multi-block constraintsdocs/user_guide.md— task-oriented prose guide (JAX tips, constraint patterns, troubleshooting)docs/api.md— strict reference forminimize,OptimizeResult, and the options dict
Status
Early prototype. Sparsity detection uses a two-probe random-multiplier union — safe for structurally-honest code but defeated by rare numerical cancellations. A wheel is built by maturin build --release; cross-platform wheels, PyPI release, and a symbolic sparsity path are future work.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ripopt-0.7.0-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: ripopt-0.7.0-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 2.0 MB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4321123fa95a74c162fac73fa080dc02131277f38afa63bfa15fb2af34e717ad
|
|
| MD5 |
367b85fbb0a51ab5c6a44c0169a50794
|
|
| BLAKE2b-256 |
2207f64aaa3a2539db4c4de2809c24b82398d53972f9c563c4b81b6642ae2c1f
|
Provenance
The following attestation bundles were made for ripopt-0.7.0-cp39-abi3-win_amd64.whl:
Publisher:
publish-ripopt-py.yml on jkitchin/ripopt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ripopt-0.7.0-cp39-abi3-win_amd64.whl -
Subject digest:
4321123fa95a74c162fac73fa080dc02131277f38afa63bfa15fb2af34e717ad - Sigstore transparency entry: 1363015351
- Sigstore integration time:
-
Permalink:
jkitchin/ripopt@c36349e7cec701a2d07efc86dee9c4127822f039 -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/jkitchin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-ripopt-py.yml@c36349e7cec701a2d07efc86dee9c4127822f039 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ripopt-0.7.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: ripopt-0.7.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 18.9 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3205fe59f4a63790315d09b65f9b3d4ab60d56eb631e8f9cdeae6502de79f540
|
|
| MD5 |
50c8cd4c43e05c7ee55cdc48a4a2eb0d
|
|
| BLAKE2b-256 |
50fe0064789ee22dcd4122656e8e293dec5a7b63712a7b35b5582fc62894ac31
|
Provenance
The following attestation bundles were made for ripopt-0.7.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
publish-ripopt-py.yml on jkitchin/ripopt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ripopt-0.7.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
3205fe59f4a63790315d09b65f9b3d4ab60d56eb631e8f9cdeae6502de79f540 - Sigstore transparency entry: 1363015376
- Sigstore integration time:
-
Permalink:
jkitchin/ripopt@c36349e7cec701a2d07efc86dee9c4127822f039 -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/jkitchin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-ripopt-py.yml@c36349e7cec701a2d07efc86dee9c4127822f039 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ripopt-0.7.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: ripopt-0.7.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 18.6 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
288cebf871d6b2ffd6cdc73d911e25ef2eae3fa4b4496a0af1e55d820080aca0
|
|
| MD5 |
afeac60f0bab845f2bb684a78e73db6c
|
|
| BLAKE2b-256 |
88fa58c6c0c288d949abb42713ad15edd8e0545294f57fcf5172d12a85f6b587
|
Provenance
The following attestation bundles were made for ripopt-0.7.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
publish-ripopt-py.yml on jkitchin/ripopt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ripopt-0.7.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
288cebf871d6b2ffd6cdc73d911e25ef2eae3fa4b4496a0af1e55d820080aca0 - Sigstore transparency entry: 1363015446
- Sigstore integration time:
-
Permalink:
jkitchin/ripopt@c36349e7cec701a2d07efc86dee9c4127822f039 -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/jkitchin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-ripopt-py.yml@c36349e7cec701a2d07efc86dee9c4127822f039 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ripopt-0.7.0-cp39-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: ripopt-0.7.0-cp39-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.9+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b5c37e98ea70a1b05da45bd5abde6b64f9addffcec8a7c131c698520470bd6a5
|
|
| MD5 |
3da2bb7ed343ca7c0d1579a5afe1ab81
|
|
| BLAKE2b-256 |
a88faa9a551cefbc28c01a1e6909bc878b66951e4a22ad5520b8b1bcfeb3eb28
|
Provenance
The following attestation bundles were made for ripopt-0.7.0-cp39-abi3-macosx_11_0_arm64.whl:
Publisher:
publish-ripopt-py.yml on jkitchin/ripopt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ripopt-0.7.0-cp39-abi3-macosx_11_0_arm64.whl -
Subject digest:
b5c37e98ea70a1b05da45bd5abde6b64f9addffcec8a7c131c698520470bd6a5 - Sigstore transparency entry: 1363015478
- Sigstore integration time:
-
Permalink:
jkitchin/ripopt@c36349e7cec701a2d07efc86dee9c4127822f039 -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/jkitchin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-ripopt-py.yml@c36349e7cec701a2d07efc86dee9c4127822f039 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ripopt-0.7.0-cp39-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: ripopt-0.7.0-cp39-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 2.0 MB
- Tags: CPython 3.9+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
beb7c6ea163cb1b75314d83de5fc12d83180cd983396e852b2bfcb064f62f177
|
|
| MD5 |
2d6c4d487fa4c91f268a80d083366afe
|
|
| BLAKE2b-256 |
6619ae9c5adf51816966e3965c307158ad46a95363cb0ae69f18c0a6f46c2f1b
|
Provenance
The following attestation bundles were made for ripopt-0.7.0-cp39-abi3-macosx_10_12_x86_64.whl:
Publisher:
publish-ripopt-py.yml on jkitchin/ripopt
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ripopt-0.7.0-cp39-abi3-macosx_10_12_x86_64.whl -
Subject digest:
beb7c6ea163cb1b75314d83de5fc12d83180cd983396e852b2bfcb064f62f177 - Sigstore transparency entry: 1363015416
- Sigstore integration time:
-
Permalink:
jkitchin/ripopt@c36349e7cec701a2d07efc86dee9c4127822f039 -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/jkitchin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-ripopt-py.yml@c36349e7cec701a2d07efc86dee9c4127822f039 -
Trigger Event:
push
-
Statement type: