Skip to main content

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.
  • boundsNone, (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. Use lb == ub for 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 constraints
  • docs/user_guide.md — task-oriented prose guide (JAX tips, constraint patterns, troubleshooting)
  • docs/api.md — strict reference for minimize, 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

ripopt-0.7.1-cp39-abi3-win_amd64.whl (1.9 MB view details)

Uploaded CPython 3.9+Windows x86-64

ripopt-0.7.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (19.0 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

ripopt-0.7.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (18.5 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

ripopt-0.7.1-cp39-abi3-macosx_11_0_arm64.whl (1.8 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

ripopt-0.7.1-cp39-abi3-macosx_10_12_x86_64.whl (2.0 MB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

Details for the file ripopt-0.7.1-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: ripopt-0.7.1-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 1.9 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

Hashes for ripopt-0.7.1-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 ff143f4a21fc01223583d28219c872bee160ee9b286047970bea84adf3bbb54f
MD5 61ae28e3b0e3795e9f04777665cfbfac
BLAKE2b-256 f0eaa77a4f626cfd2c27afcbc21179505d5360e0f17d96879618f67a7c77e86b

See more details on using hashes here.

Provenance

The following attestation bundles were made for ripopt-0.7.1-cp39-abi3-win_amd64.whl:

Publisher: publish-ripopt-py.yml on jkitchin/ripopt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ripopt-0.7.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ripopt-0.7.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5f1a769451ef13fc9f4134b1674bc9cb81e9d7bc0050da15e6fdf6bd9e4b8429
MD5 d98c2d38b826e59f911a0179d81dc13b
BLAKE2b-256 fbc8d0b5045f5e233beeae2cc5b508410994b64900020b4848fcd058b3e573f3

See more details on using hashes here.

Provenance

The following attestation bundles were made for ripopt-0.7.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish-ripopt-py.yml on jkitchin/ripopt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ripopt-0.7.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ripopt-0.7.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 f5f24edd39db3422956eb025a9d2657ca6fe642028c86d2c735aba4f51a89bc1
MD5 6169ee573c5ca1041ad1ff929334dc77
BLAKE2b-256 62ea49cee51bbe91909dc25308acbb9ee0cba469c1f116ac57babad35a54b87c

See more details on using hashes here.

Provenance

The following attestation bundles were made for ripopt-0.7.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: publish-ripopt-py.yml on jkitchin/ripopt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ripopt-0.7.1-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for ripopt-0.7.1-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 42f7f0aedc9447a5093515e1f4a7e72b125ed1fcc89110140b8212b9ecfec14f
MD5 89d68d6ea4a1f9b98d7f1e121f8a5354
BLAKE2b-256 f23b449a58f3a1c3a5b24c23834cac7a5e5cebc9a7dccab66826dacb9920b01a

See more details on using hashes here.

Provenance

The following attestation bundles were made for ripopt-0.7.1-cp39-abi3-macosx_11_0_arm64.whl:

Publisher: publish-ripopt-py.yml on jkitchin/ripopt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ripopt-0.7.1-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for ripopt-0.7.1-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 9555f3b15a6133eb2efb591d8f657705f331e7cdce66b5442e9d828eaf456215
MD5 00bd359fcf9d9c5ee1a4ef022057eb38
BLAKE2b-256 06dff8cf1a86a73805bbc494ed24260a3a1614c31049b319d940ffc94a555892

See more details on using hashes here.

Provenance

The following attestation bundles were made for ripopt-0.7.1-cp39-abi3-macosx_10_12_x86_64.whl:

Publisher: publish-ripopt-py.yml on jkitchin/ripopt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page