# pounce-rs
[](https://crates.io/crates/pounce-rs) [](https://github.com/jkitchin/pounce/actions/workflows/ci.yml) [](https://docs.rs/pounce-rs)
A single-crate entry point for solving optimization problems with
[POUNCE](https://github.com/jkitchin/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](#feature-flags-beyond-the-nlp-path).
## Install
```sh
cargo add pounce-rs
```
or add it to `Cargo.toml`:
```toml
[dependencies]
pounce-rs = "0.8"
```
## Quick start
Implement `Problem` (only `objective` is required), then configure and solve
with the `Nlp` builder:
```rust
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](https://docs.rs/pounce-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:
| `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 |
```toml
[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.
```rust
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);
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.