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

Uploaded CPython 3.9+Windows x86-64

ripopt-0.8.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (17.5 MB view details)

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

ripopt-0.8.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (16.8 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

ripopt-0.8.0-cp39-abi3-macosx_11_0_arm64.whl (1.4 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

ripopt-0.8.0-cp39-abi3-macosx_10_12_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

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

File metadata

  • Download URL: ripopt-0.8.0-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 1.4 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.0-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 c18e957efe139b94fe85f2dd5ad86d9c34a960396061f214d03a73640f94725f
MD5 13cef5aad5cdfd8dbd6ab20bfc3a6d7a
BLAKE2b-256 16613fd23df6d493e316af681a5176ff810c3ddd26d498ba8d6838ba433de9d0

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ripopt-0.8.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1561c718d466cc9c5d98cce95b2d3ec40604b258d82fe85523731c5ba87b6ce9
MD5 372f8554393b1de7b5601226468e26b6
BLAKE2b-256 7415611295ceae0cda7e588fc71b46f8fe16bb637f2eb97d61455df38bcbeb42

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ripopt-0.8.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 3921b555575ff3199d14e98fc7481a1eb39462ce1f2774035eaf78f70dc54264
MD5 6e30db7eb2d0050829689501fe3958d5
BLAKE2b-256 3fd16db3e1155033bf0e545fbe9c06cff36bc34a23b78c9439b9c735b5d74269

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ripopt-0.8.0-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2dff2d1888b383b5460e24a7eaa8f6116fd530ea369abdd22f91c7956481f84a
MD5 e0d58ea1d3aa271f80a1ef066f5963b5
BLAKE2b-256 3bf24764f8e9173e7356e1dc2327d002f18d6c13f6fc212a79426d6456685522

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ripopt-0.8.0-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 c60918f92fa1e138ecf8813149fb7547fdc87d666923a235c6131509a38f996b
MD5 b636bf44ff1aa67cb108ce3c5151496f
BLAKE2b-256 91b71ef98bf76dae01961a028abe4d4f24b6525def1d9ea5a8c32e96a1d6115d

See more details on using hashes here.

Provenance

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