use std::fs::OpenOptions;
use std::io::Write;
use std::sync::Mutex;
use std::sync::OnceLock;
pub const COLUMNS: &[&str] = &[
"iter",
"obj",
"inf_pr",
"inf_du",
"compl",
"mu",
"alpha_pr",
"alpha_du",
"alpha_affP",
"alpha_affD",
"mu_aff",
"sigma",
"mu_pc",
"delta_w",
"delta_c",
"dx_inf",
"dzl_inf",
"dzu_inf",
"mcc_iters",
"ls",
"accepted",
"alpha_primal_max",
"tau_used",
"sigma_cond",
"soc_accepted",
];
struct TraceSink {
file: std::fs::File,
}
static SINK: OnceLock<Option<Mutex<TraceSink>>> = OnceLock::new();
fn sink() -> Option<&'static Mutex<TraceSink>> {
SINK.get_or_init(|| {
let path = std::env::var("RIP_TRACE_TSV").ok()?;
let mut file = OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(&path)
.ok()?;
writeln!(file, "{}", COLUMNS.join("\t")).ok()?;
Some(Mutex::new(TraceSink { file }))
})
.as_ref()
}
pub fn is_enabled() -> bool {
sink().is_some()
}
#[derive(Clone, Copy)]
pub struct TraceRow {
pub iter: usize,
pub obj: f64,
pub inf_pr: f64,
pub inf_du: f64,
pub compl: f64,
pub mu: f64,
pub alpha_pr: f64,
pub alpha_du: f64,
pub alpha_aff_p: f64,
pub alpha_aff_d: f64,
pub mu_aff: f64,
pub sigma: f64,
pub mu_pc: f64,
pub delta_w: f64,
pub delta_c: f64,
pub dx_inf: f64,
pub dzl_inf: f64,
pub dzu_inf: f64,
pub mcc_iters: u32,
pub ls: u32,
pub accepted: bool,
pub alpha_primal_max: f64,
pub tau_used: f64,
pub sigma_cond: f64,
pub soc_accepted: bool,
}
impl TraceRow {
pub fn blank(iter: usize) -> Self {
let nan = f64::NAN;
Self {
iter,
obj: nan, inf_pr: nan, inf_du: nan, compl: nan, mu: nan,
alpha_pr: nan, alpha_du: nan,
alpha_aff_p: nan, alpha_aff_d: nan, mu_aff: nan, sigma: nan, mu_pc: nan,
delta_w: nan, delta_c: nan,
dx_inf: nan, dzl_inf: nan, dzu_inf: nan,
mcc_iters: 0, ls: 0, accepted: false,
alpha_primal_max: nan, tau_used: nan, sigma_cond: nan,
soc_accepted: false,
}
}
}
pub fn emit(row: &TraceRow) {
let Some(sink) = sink() else { return };
let Ok(mut guard) = sink.lock() else { return };
let _ = writeln!(
guard.file,
"{}\t{:.17e}\t{:.6e}\t{:.6e}\t{:.6e}\t{:.6e}\t{:.6e}\t{:.6e}\t{:.6e}\t{:.6e}\t{:.6e}\t{:.6e}\t{:.6e}\t{:.6e}\t{:.6e}\t{:.6e}\t{:.6e}\t{:.6e}\t{}\t{}\t{}\t{:.6e}\t{:.6e}\t{:.6e}\t{}",
row.iter,
row.obj, row.inf_pr, row.inf_du, row.compl, row.mu,
row.alpha_pr, row.alpha_du,
row.alpha_aff_p, row.alpha_aff_d, row.mu_aff, row.sigma, row.mu_pc,
row.delta_w, row.delta_c,
row.dx_inf, row.dzl_inf, row.dzu_inf,
row.mcc_iters, row.ls, if row.accepted { 1 } else { 0 },
row.alpha_primal_max, row.tau_used, row.sigma_cond,
if row.soc_accepted { 1 } else { 0 },
);
let _ = guard.file.flush();
}