use crate::ipopt_cq::IpoptCqHandle;
use crate::ipopt_data::IpoptDataHandle;
use crate::output::r#trait::IterationOutput;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PrintInfoString {
Yes,
No,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InfPrTag {
Internal,
Original,
}
pub struct OrigIterationOutput {
pub print_info_string: PrintInfoString,
pub inf_pr_output: InfPrTag,
pub print_frequency_iter: i32,
pub print_frequency_time: f64,
last_header_iter: i32,
}
impl Default for OrigIterationOutput {
fn default() -> Self {
Self {
print_info_string: PrintInfoString::No,
inf_pr_output: InfPrTag::Original,
print_frequency_iter: 1,
print_frequency_time: 0.0,
last_header_iter: -1,
}
}
}
impl OrigIterationOutput {
pub fn new() -> Self {
Self::default()
}
pub const HEADER: &'static str =
"iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n";
}
impl IterationOutput for OrigIterationOutput {
fn write_output(&mut self) {
self.last_header_iter = 0;
}
fn format_row(&mut self, data: &IpoptDataHandle, cq: &IpoptCqHandle) -> String {
let d = data.borrow();
let c = cq.borrow();
let iter = d.iter_count;
let unscaled_f = c.unscaled_curr_f();
let inf_pr = match self.inf_pr_output {
InfPrTag::Internal => c.curr_primal_infeasibility_max(),
InfPrTag::Original => c.curr_primal_infeasibility_max(),
};
let inf_du = c.curr_dual_infeasibility_max();
let mu = d.curr_mu;
let lg_mu = mu.log10();
let dnrm = match &d.delta {
Some(delta) => delta.x.amax().max(delta.s.amax()),
None => 0.0,
};
let regu_x = d.info_regu_x;
let regu_str: String = if regu_x == 0.0 {
" - ".to_string()
} else {
format_field_5_1(regu_x.log10())
};
let alpha_dual = d.info_alpha_dual;
let alpha_primal = d.info_alpha_primal;
let alpha_char = d.info_alpha_primal_char;
let ls_count = d.info_ls_count;
let mut row = format!(
"{:>4} {:14.7e} {:7.2e} {:7.2e} {:5.1} {:7.2e} {:>5} {:7.2e} {:7.2e}{}{:>3}",
iter,
unscaled_f,
inf_pr,
inf_du,
lg_mu,
dnrm,
regu_str,
alpha_dual,
alpha_primal,
alpha_char,
ls_count,
);
if self.print_info_string == PrintInfoString::Yes && !d.info_string.is_empty() {
row.push(' ');
row.push_str(&d.info_string);
}
row
}
}
fn format_field_5_1(x: f64) -> String {
format!("{:5.1}", x)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn header_matches_upstream_literal() {
assert_eq!(
OrigIterationOutput::HEADER,
"iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n"
);
}
#[test]
fn regu_field_dashes_when_zero() {
assert_eq!(format_field_5_1(-1.0), " -1.0");
}
}