pounce-rs 0.10.0

Single-crate facade for POUNCE from Rust: re-exports the TNLP trait, the IpoptApplication driver, and the supporting types in one place (plus a prelude), with feature-gated modules for the convex/LP/QP, active-set QP, and sensitivity paths.
Documentation

pounce-rs

crates.io CI docs.rs

A single-crate entry point for solving optimization problems with POUNCE in Rust. For nonlinear programs — the default build — it provides two APIs:

  • a high-level builder API (Problem + Nlp) for the common case, where only the objective is required and everything else is optional; and
  • the low-level TNLP trait, re-exported for full control over Hessians, sparsity patterns, scaling, and other advanced features.

Both APIs are backed by the same pure-Rust interior-point solver. POUNCE's other solver paths — convex/LP/QP, active-set QP, and sensitivity analysis — are behind feature flags.

Install

cargo add pounce-rs

or add it to Cargo.toml:

[dependencies]
pounce-rs = "0.8"

Quick start

Implement Problem (only objective is required), then configure and solve with the Nlp builder:

use pounce_rs::prelude::*;

// min (x0-1)^2 + (x1-2)^2  s.t.  x0 + x1 == 3,  0 <= xi <= 5
struct P;
impl Problem for P {
    fn objective(&self, x: &[f64]) -> f64 {
        (x[0] - 1.0).powi(2) + (x[1] - 2.0).powi(2)
    }
    fn n_constraints(&self) -> usize { 1 }
    fn constraints(&self, x: &[f64], g: &mut [f64]) { g[0] = x[0] + x[1]; }
}

let sol = Nlp::new(P)                     // variable count inferred below
    .var_bounds(&[0.0, 0.0], &[5.0, 5.0])
    .constraint_bounds(&[3.0], &[3.0])    // equality: lower == upper
    .x0(&[0.0, 0.0])
    .option_num("tol", 1e-10)
    .solve();

assert!(sol.success);
assert!((sol.x[0] - 1.0).abs() < 1e-5 && (sol.x[1] - 2.0).abs() < 1e-5);

Anything you don't implement is provided automatically. Missing gradients and Jacobians are approximated with finite differences, while the Hessian defaults to a limited-memory (L-BFGS) approximation. This keeps simple problems concise without sacrificing access to exact derivatives when needed.

Solver options use the same names as upstream Ipopt (option_num, option_int, option_str).

Result

Nlp::solve returns a Solution containing

  • success and the full status
  • the optimal point x
  • the objective value
  • constraint multipliers (multipliers)
  • constraint values (g)
  • bound multipliers (z_l and z_u)
  • solve statistics (stats): wall time, iteration count, evaluation counts, and final infeasibilities

The vector fields remain empty if the solve aborts before finalization. Opt in to the full per-iteration trajectory (stats.iterations) with .capture_iterations() on the builder.

Full control: the TNLP trait

For problems that need an exact Hessian, custom Jacobian/Hessian sparsity, or NLP scaling, implement the re-exported TNLP trait directly and drive it with IpoptApplication. The whole surface is reachable through the prelude.

See the crate docs on docs.rs for a complete HS071 TNLP walkthrough.

Feature flags: beyond the NLP path

The default build is the NLP path only. POUNCE's other solver families live in their own modules behind features — separate modules because the two QP families both name their types QpProblem / QpSolution / QpStatus, so a flat surface could not carry both:

feature module what it covers
convex pounce_rs::convex LP, convex QP, SOCP / exponential / power / PSD cones, SOS; batched and warm-started solves; symbolic-factorization reuse; QP sensitivity and reduced Hessian
qp pounce_rs::qp, pounce_rs::sqp sparse parametric active-set QP — the SQP / MPC / continuation engine, indefinite Hessians allowed — plus the SQP working-set warm-start contract
sensitivity pounce_rs::sensitivity sIPOPT-style NLP sensitivity: ∂x*/∂p predictors, parametric warm starts, reduced Hessian
full all three
[dependencies]
pounce-rs = { version = "0.9", features = ["convex", "sensitivity"] }

convex and qp also bring in pounce_rs::linsol, whose backend() supplies the sparse symmetric factorization those entry points take as an argument.

use pounce_rs::convex::{QpOptions, QpProblem, QpStatus, Triplet, solve_qp_batch_parallel};
use pounce_rs::linsol::serial_backend;

// A batch of box-constrained QPs, one per rayon worker.
let sols = solve_qp_batch_parallel(&probs, &QpOptions::default(), serial_backend);
assert!(sols.iter().all(|s| s.status == QpStatus::Optimal));

Enabling a feature widens what this crate exports; it is close to free at build time, because the default NLP path already pulls pounce-qp, pounce-linsol, and pounce-feral transitively. Only convex and sensitivity add crates to compile.

License

EPL-2.0.