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.8.2-cp39-abi3-win_amd64.whl (2.2 MB view details)

Uploaded CPython 3.9+Windows x86-64

ripopt-0.8.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (22.0 MB view details)

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

ripopt-0.8.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (20.8 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

ripopt-0.8.2-cp39-abi3-macosx_11_0_arm64.whl (2.1 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

ripopt-0.8.2-cp39-abi3-macosx_10_12_x86_64.whl (2.2 MB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

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

File metadata

  • Download URL: ripopt-0.8.2-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 2.2 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.8.2-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 ac0c58b8a279ccacd3db45a24d329bc94920b0d203e9aca1278b1ee78ef9902a
MD5 1f9cc3ed0d7b756741802f67d99b018d
BLAKE2b-256 88a171d48ebcb4ea0508dd8f61a7ca1e332f1a7775c431adb1ea6bbed848d341

See more details on using hashes here.

Provenance

The following attestation bundles were made for ripopt-0.8.2-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.8.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ripopt-0.8.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e44e51ee1d8044caa4d972ec26cd45bbe2306e69e3b2ce3f2acb19146d074ee8
MD5 b5ba2005280ce14aa9e325dab543d58a
BLAKE2b-256 243896d22649d8dca6a425afc35b7a1a22105ed56eda07ba23c8b4af1dc6ecb6

See more details on using hashes here.

Provenance

The following attestation bundles were made for ripopt-0.8.2-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.8.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ripopt-0.8.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 2173820c5427c38c26b203f1cf94e0da407b5fc5dc99ecb45fd09913f071a3a8
MD5 a11d323ecb943cbdf99d847bf70c807e
BLAKE2b-256 21fad9d8095e76f8853a2cf37ef572cff3d58608f6cfc77b5ffff00ed789b1d7

See more details on using hashes here.

Provenance

The following attestation bundles were made for ripopt-0.8.2-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.8.2-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for ripopt-0.8.2-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 3a56e6070c5c90a4906dbea8cb0b2a318f655d400e0a9fc17a4548d31d87c12e
MD5 faa3e823c1a328b98a16ca897031ceab
BLAKE2b-256 0097ee082de34245d82d4ff9d192a78d6d6e2ea1a15321587a4247b9c8f7be9b

See more details on using hashes here.

Provenance

The following attestation bundles were made for ripopt-0.8.2-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.8.2-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for ripopt-0.8.2-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 e500cc082ec311182e686c3ccb105e71711ae407e77f89b834e0f5090200af6f
MD5 805656b481a5f1fa3033b31af9710198
BLAKE2b-256 7e65e8fefa475ffc70177dcce44c68d898ee35560ef793046913b5f78a2392e3

See more details on using hashes here.

Provenance

The following attestation bundles were made for ripopt-0.8.2-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