1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! # ripopt — Rust Interior Point Optimizer
//!
//! ripopt is a primal-dual interior point solver for nonlinear programming (NLP) problems:
//!
//! ```text
//! min f(x)
//! x
//! s.t. g_l ≤ g(x) ≤ g_u
//! x_l ≤ x ≤ x_u
//! ```
//!
//! It closely follows the algorithm of [Ipopt](https://coin-or.github.io/Ipopt/) and achieves
//! comparable or better solve rates on standard benchmark suites (HS120, CUTEst).
//!
//! ## Quick Start
//!
//! Implement [`NlpProblem`] for your problem, then call [`solve`]:
//!
//! ```rust,no_run
//! use ripopt::{NlpProblem, SolveResult, SolverOptions, SolveStatus, solve};
//!
//! struct MyProblem;
//!
//! impl NlpProblem for MyProblem {
//! fn num_variables(&self) -> usize { 2 }
//! fn num_constraints(&self) -> usize { 0 }
//! fn bounds(&self, x_l: &mut [f64], x_u: &mut [f64]) {
//! x_l.fill(f64::NEG_INFINITY);
//! x_u.fill(f64::INFINITY);
//! }
//! fn constraint_bounds(&self, _g_l: &mut [f64], _g_u: &mut [f64]) {}
//! fn initial_point(&self, x0: &mut [f64]) { x0[0] = 0.5; x0[1] = 0.5; }
//! fn objective(&self, x: &[f64], _new_x: bool, obj: &mut f64) -> bool {
//! *obj = (1.0 - x[0]).powi(2) + 100.0 * (x[1] - x[0].powi(2)).powi(2);
//! true
//! }
//! fn gradient(&self, x: &[f64], _new_x: bool, grad: &mut [f64]) -> bool {
//! grad[0] = -2.0 * (1.0 - x[0]) - 400.0 * x[0] * (x[1] - x[0].powi(2));
//! grad[1] = 200.0 * (x[1] - x[0].powi(2));
//! true
//! }
//! fn constraints(&self, _x: &[f64], _new_x: bool, _g: &mut [f64]) -> bool { true }
//! fn jacobian_structure(&self) -> (Vec<usize>, Vec<usize>) { (vec![], vec![]) }
//! fn jacobian_values(&self, _x: &[f64], _new_x: bool, _vals: &mut [f64]) -> bool { true }
//! fn hessian_structure(&self) -> (Vec<usize>, Vec<usize>) {
//! (vec![0, 1, 1], vec![0, 0, 1])
//! }
//! fn hessian_values(&self, x: &[f64], _new_x: bool, obj_factor: f64, _lambda: &[f64], vals: &mut [f64]) -> bool {
//! vals[0] = obj_factor * (2.0 - 400.0 * (x[1] - x[0].powi(2)) + 800.0 * x[0].powi(2));
//! vals[1] = obj_factor * (-400.0 * x[0]);
//! vals[2] = obj_factor * 200.0;
//! true
//! }
//! }
//!
//! let result = solve(&MyProblem, &SolverOptions::default());
//! assert_eq!(result.status, SolveStatus::Optimal);
//! ```
//!
//! ## Key Types
//!
//! - [`NlpProblem`] — trait to implement for your problem
//! - [`SolverOptions`] — all solver tuning parameters
//! - [`SolveResult`] — solution, status, and diagnostics
//! - [`SolveStatus`] — outcome (`Optimal`, `LocalInfeasibility`, etc.)
//!
//! ## Algorithm
//!
//! The solver implements:
//! - Mehrotra predictor-corrector IPM with Gondzio corrections
//! - Filter line search with second-order corrections
//! - Gauss-Newton and NLP restoration phases
//! - Fallback cascade: IPM → L-BFGS → Augmented Lagrangian → SQP → slack reformulation
//! - Sparse (multifrontal LDL^T) and dense (Bunch-Kaufman LDL^T) linear solvers
//! - Parametric sensitivity analysis ([`solve_with_sensitivity`])
pub
pub use ;
pub use NlpProblem;
pub use ;
pub use ;
/// Solve a nonlinear programming problem using the interior point method.
/// Solve and retain factored KKT for parametric sensitivity analysis.