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

Uploaded CPython 3.9+Windows x86-64

ripopt-0.7.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (18.9 MB view details)

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

ripopt-0.7.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (18.6 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

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

Uploaded CPython 3.9+macOS 11.0+ ARM64

ripopt-0.7.0-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.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

Hashes for ripopt-0.7.0-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 4321123fa95a74c162fac73fa080dc02131277f38afa63bfa15fb2af34e717ad
MD5 367b85fbb0a51ab5c6a44c0169a50794
BLAKE2b-256 2207f64aaa3a2539db4c4de2809c24b82398d53972f9c563c4b81b6642ae2c1f

See more details on using hashes here.

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

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.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ripopt-0.7.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 3205fe59f4a63790315d09b65f9b3d4ab60d56eb631e8f9cdeae6502de79f540
MD5 50c8cd4c43e05c7ee55cdc48a4a2eb0d
BLAKE2b-256 50fe0064789ee22dcd4122656e8e293dec5a7b63712a7b35b5582fc62894ac31

See more details on using hashes here.

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

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.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ripopt-0.7.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 288cebf871d6b2ffd6cdc73d911e25ef2eae3fa4b4496a0af1e55d820080aca0
MD5 afeac60f0bab845f2bb684a78e73db6c
BLAKE2b-256 88fa58c6c0c288d949abb42713ad15edd8e0545294f57fcf5172d12a85f6b587

See more details on using hashes here.

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

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.0-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for ripopt-0.7.0-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b5c37e98ea70a1b05da45bd5abde6b64f9addffcec8a7c131c698520470bd6a5
MD5 3da2bb7ed343ca7c0d1579a5afe1ab81
BLAKE2b-256 a88faa9a551cefbc28c01a1e6909bc878b66951e4a22ad5520b8b1bcfeb3eb28

See more details on using hashes here.

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

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.0-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for ripopt-0.7.0-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 beb7c6ea163cb1b75314d83de5fc12d83180cd983396e852b2bfcb064f62f177
MD5 2d6c4d487fa4c91f268a80d083366afe
BLAKE2b-256 6619ae9c5adf51816966e3965c307158ad46a95363cb0ae69f18c0a6f46c2f1b

See more details on using hashes here.

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

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