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

Uploaded CPython 3.9+Windows x86-64

ripopt-0.8.1-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.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (20.7 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

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

Uploaded CPython 3.9+macOS 11.0+ ARM64

ripopt-0.8.1-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.1-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: ripopt-0.8.1-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.1-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 c6d14ec9dc52837c9c8d7223577496fd2217ef919c012d320d67d575e78671ee
MD5 1f6ec4d74328e095d46eaa2f24fd9736
BLAKE2b-256 fdea92d3af8151174a0e99eff4f10f89da8972a9664069998e572b27cae87947

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ripopt-0.8.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5faa6c8bda837b81efefd58fed9d217db003c560909906408dea57181be0eed0
MD5 7edcc32856b270c77e289833fcba4489
BLAKE2b-256 44ed8e3686009d620fa3ec9aecefdef6e5fd53ebfbedc9db266a19aea8c361fa

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ripopt-0.8.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 4ef7ffb00fe1d4c019e89ce75f94a475e774ac749ee7014f6e9d3d9085b2d45d
MD5 718c9388305946d15508eda1185592e1
BLAKE2b-256 cf7894ca31f9fcdd420cb370f82b545ac45ee79744c43c860dc6e7feb30f87de

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ripopt-0.8.1-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 7583c9167c1cd24eaf79a4151b8e4f709566792b6db81f28a7ccaef68463709f
MD5 1ee261a1e5cfc0c9d0a900b7bd92711b
BLAKE2b-256 2e0760f351511c68e430cc49a991426f23c66062298b75ba5f1a830cdd4156aa

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ripopt-0.8.1-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 5e6916dbc3200b10580d11487088fbc9576ad268acafbc482a3cba594241f1f3
MD5 f5b57bc611f216fb6409abe69a39ef32
BLAKE2b-256 eb12eda8a6c66771fcf6afc25d6cf74a193c13544ae98fc25666cf65025be9e7

See more details on using hashes here.

Provenance

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