Skip to main content

pounce_algorithm/mu/
trait.rs

1//! `MuUpdate` trait — port of `IpMuUpdate.hpp`.
2
3use crate::ipopt_cq::IpoptCqHandle;
4use crate::ipopt_data::IpoptDataHandle;
5use crate::ipopt_nlp::IpoptNlp;
6use crate::kkt::pd_search_dir_calc::PdSearchDirCalc;
7use pounce_common::types::Number;
8use std::cell::RefCell;
9use std::rc::Rc;
10
11pub trait MuUpdate {
12    /// Initialize `data.curr_mu` and `data.curr_tau` before the first
13    /// iteration. Mirrors upstream's `MuUpdate::InitializeImpl`.
14    /// Default is no-op so existing implementors don't have to change.
15    fn initialize(&mut self, _data: &IpoptDataHandle) {}
16
17    /// Compute the next mu after a successful iteration. Mirrors
18    /// upstream's `MuUpdate::UpdateBarrierParameter`. Implementations
19    /// that need the iterate state (adaptive mu, oracles) read it via
20    /// the supplied handles; pure scalar reductions like
21    /// Fiacco-McCormick consult only `data.curr_mu`.
22    ///
23    /// `nlp` and `pd_search_dir` are optional handles needed by the
24    /// adaptive μ oracles that drive an affine-step / centring solve
25    /// (probing, quality-function). When either is `None` the adaptive
26    /// path silently falls back to the LOQO closed form — matching
27    /// upstream's "oracle returned no candidate" branch
28    /// (`IpAdaptiveMuUpdate.cpp:CalculateMuFromOracle:330-340`).
29    fn update_barrier_parameter(
30        &mut self,
31        data: &IpoptDataHandle,
32        cq: &IpoptCqHandle,
33        nlp: Option<&Rc<RefCell<dyn IpoptNlp>>>,
34        pd_search_dir: Option<&mut PdSearchDirCalc>,
35    ) -> Number;
36
37    /// Whether the main loop may infer `STOP_AT_TINY_STEP` from
38    /// "tiny-step flag set and μ came back unchanged".
39    ///
40    /// Upstream `IpMonotoneMuUpdate.cpp:158-161` throws
41    /// `TINY_STEP_DETECTED` in exactly that case, and it is the update's
42    /// only throw site, so the inference is exact — `MonotoneMuUpdate`
43    /// overrides to `true`.
44    ///
45    /// `IpAdaptiveMuUpdate.cpp` also terminates on a tiny step (`:330-333`
46    /// and `:377-380`), but only at those two sites; elsewhere it routes
47    /// the flag through `force_no_progress`, fixing μ and continuing. The
48    /// μ comparison cannot tell the two apart, so the adaptive update
49    /// signals its own termination through
50    /// [`IpoptData::request_tiny_step_stop`](crate::ipopt_data::IpoptData::request_tiny_step_stop)
51    /// and leaves this `false` (pounce#512). A `false` here means "does
52    /// not use the inference", not "never terminates".
53    fn terminates_on_tiny_step(&self) -> bool {
54        false
55    }
56}