phase0_via_tnlp/
phase0_via_tnlp.rs1#![allow(clippy::expect_used, clippy::unwrap_used)]
21
22use std::cell::RefCell;
23use std::rc::Rc;
24
25use pounce_common::types::Number;
26use pounce_nlp::tnlp::{
27 BoundsInfo, IndexStyle, IpoptCq, IpoptData, Linearity, NlpInfo, Solution, SparsityRequest,
28 StartingPoint, TNLP,
29};
30use pounce_nlp::SolverReturn;
31use pounce_presolve::{wrap_with_presolve, AuxiliaryCouplingPolicy, PresolveOptions};
32
33struct Mini;
39
40impl TNLP for Mini {
41 fn get_nlp_info(&mut self) -> Option<NlpInfo> {
42 Some(NlpInfo {
43 n: 2,
44 m: 2,
45 nnz_jac_g: 4,
46 nnz_h_lag: 2,
47 index_style: IndexStyle::C,
48 })
49 }
50 fn get_bounds_info(&mut self, b: BoundsInfo<'_>) -> bool {
51 for v in b.x_l.iter_mut() {
52 *v = -1e19;
53 }
54 for v in b.x_u.iter_mut() {
55 *v = 1e19;
56 }
57 b.g_l[0] = 3.0;
58 b.g_u[0] = 3.0;
59 b.g_l[1] = 1.0;
60 b.g_u[1] = 1.0;
61 true
62 }
63 fn get_starting_point(&mut self, sp: StartingPoint<'_>) -> bool {
64 if sp.init_x {
65 sp.x[0] = 0.0;
66 sp.x[1] = 0.0;
67 }
68 true
69 }
70 fn eval_f(&mut self, x: &[Number], _new_x: bool) -> Option<Number> {
71 Some((x[0] - 5.0).powi(2) + (x[1] - 6.0).powi(2))
72 }
73 fn eval_grad_f(&mut self, x: &[Number], _new_x: bool, g: &mut [Number]) -> bool {
74 g[0] = 2.0 * (x[0] - 5.0);
83 g[1] = 2.0 * (x[1] - 6.0);
84 true
85 }
86 fn eval_g(&mut self, x: &[Number], _new_x: bool, g: &mut [Number]) -> bool {
87 g[0] = x[0] + x[1];
88 g[1] = x[0] - x[1];
89 true
90 }
91 fn eval_jac_g(
92 &mut self,
93 _x: Option<&[Number]>,
94 _new_x: bool,
95 mode: SparsityRequest<'_>,
96 ) -> bool {
97 match mode {
98 SparsityRequest::Structure { irow, jcol } => {
99 irow.copy_from_slice(&[0, 0, 1, 1]);
100 jcol.copy_from_slice(&[0, 1, 0, 1]);
101 }
102 SparsityRequest::Values { values } => {
103 values.copy_from_slice(&[1.0, 1.0, 1.0, -1.0]);
104 }
105 }
106 true
107 }
108 fn get_constraints_linearity(&mut self, types: &mut [Linearity]) -> bool {
109 types[0] = Linearity::Linear;
110 types[1] = Linearity::Linear;
111 true
112 }
113 fn finalize_solution(&mut self, sol: Solution<'_>, _d: &IpoptData, _q: &IpoptCq) {
114 println!("\n[finalize_solution received from PresolveTnlp]");
115 println!(" x = {:?}", sol.x);
116 println!(" lambda = {:?}", sol.lambda);
117 println!(" g = {:?}", sol.g);
118 }
119}
120
121fn main() {
122 let opts = PresolveOptions {
123 enabled: true,
124 auxiliary: true,
125 auxiliary_coupling: AuxiliaryCouplingPolicy::Aggressive,
128 ..PresolveOptions::defaults()
129 };
130 let inner: Rc<RefCell<dyn TNLP>> = Rc::new(RefCell::new(Mini));
131 let wrapped = wrap_with_presolve(inner, opts).expect("wrap ok");
132
133 let info = wrapped.borrow_mut().get_nlp_info().expect("init");
134 println!("phase0_via_tnlp — PR 8 of pounce#53");
135 println!("====================================");
136 println!("Inner TNLP: n=2, m=2 (two equalities).");
137 println!("After PresolveTnlp wrapping with presolve_auxiliary=yes:");
138 println!(" outer n = {}", info.n);
139 println!(" outer m = {}", info.m);
140 println!(" outer nnz_jac_g = {}", info.nnz_jac_g);
141
142 let mut x_l = vec![0.0; info.n as usize];
144 let mut x_u = vec![0.0; info.n as usize];
145 let mut g_l = vec![0.0; info.m as usize];
146 let mut g_u = vec![0.0; info.m as usize];
147 wrapped.borrow_mut().get_bounds_info(BoundsInfo {
148 x_l: &mut x_l,
149 x_u: &mut x_u,
150 g_l: &mut g_l,
151 g_u: &mut g_u,
152 });
153 println!("\nClamped bounds (from PresolveTnlp):");
154 println!(" x_l = {:?}", x_l);
155 println!(" x_u = {:?}", x_u);
156 println!(" g_l = {:?}", g_l);
157
158 let sol_x = [x_l[0], x_l[1]];
161 let sol_z_l = vec![0.0; info.n as usize];
162 let sol_z_u = vec![0.0; info.n as usize];
163 let sol_lambda: Vec<Number> = Vec::new(); let sol_g: Vec<Number> = Vec::new();
165 let ip_data = IpoptData::default();
166 let ip_cq = IpoptCq::default();
167 wrapped.borrow_mut().finalize_solution(
168 Solution {
169 status: SolverReturn::Success,
170 x: &sol_x,
171 z_l: &sol_z_l,
172 z_u: &sol_z_u,
173 g: &sol_g,
174 lambda: &sol_lambda,
175 obj_value: 0.0,
176 },
177 &ip_data,
178 &ip_cq,
179 );
180
181 println!("\n✓ End-to-end orchestrator path exercised.");
182}