extern crate mosek;
use mosek::{Task,Streamtype,Solsta,Soltype};
use std::env;
enum FileOrText {
File(String),
Text(String)
}
fn main() -> Result<(),String> {
let mut args = env::args();
if args.len() < 2 {
println!("Syntax: solutionquality FILENAME");
return Err("Invalid argument list".to_string())
}
let _ = args.next();
let filename = args.next().unwrap();
solutionquality(FileOrText::File(filename))
}
fn solutionquality(filename : FileOrText) -> Result<(),String> {
let mut task = Task::new().unwrap().with_callbacks();
task.put_stream_callback(Streamtype::LOG, |msg| print!("{}",msg))?;
match filename {
FileOrText::File(filename) => task.read_data (filename.as_str())?,
FileOrText::Text(data) => task.read_ptf_string(data.as_str())?
}
let _ = task.optimize()?;
task.solution_summary(Streamtype::LOG)?;
let solsta = task.get_sol_sta(Soltype::BAS)?;
let mut pobj : f64 = 0.0;
let mut pviolcon : f64 = 0.0;
let mut pviolvar : f64 = 0.0;
let mut pviolbarvar : f64 = 0.0;
let mut pviolcones : f64 = 0.0;
let mut pviolitg : f64 = 0.0;
let mut dobj : f64 = 0.0;
let mut dviolcon : f64 = 0.0;
let mut dviolvar : f64 = 0.0;
let mut dviolbarvar : f64 = 0.0;
let mut dviolcones : f64 = 0.0;
task.get_solution_info(Soltype::BAS,
& mut pobj, & mut pviolcon, & mut pviolvar, & mut pviolbarvar, & mut pviolcones, & mut pviolitg,
& mut dobj, & mut dviolcon, & mut dviolvar, & mut dviolbarvar, & mut dviolcones)?;
match solsta {
Solsta::OPTIMAL => {
let abs_obj_gap = (dobj-pobj).abs();
let rel_obj_gap = abs_obj_gap / (1.0 + f64::min(pobj.abs(), dobj.abs()));
let max_primal_viol = f64::max(pviolcon, pviolvar);
let max_primal_viol = f64::max(max_primal_viol , pviolbarvar);
let max_primal_viol = f64::max(max_primal_viol , pviolcones);
let max_dual_viol = f64::max(dviolcon, dviolvar);
let max_dual_viol = f64::max(max_dual_viol, dviolbarvar);
let max_dual_viol = f64::max(max_dual_viol, dviolcones);
println!("Customized solution information.");
println!(" Absolute objective gap: {:.3e}", abs_obj_gap);
println!(" Relative objective gap: {:.3e}", rel_obj_gap);
println!(" Max primal violation : {:.3e}", max_primal_viol);
println!(" Max dual violation : {:.3e}", max_dual_viol);
let mut accepted = true;
if rel_obj_gap > 1e-6 {
println!("Warning: The relative objective gap is LARGE.");
accepted = false;
}
if max_primal_viol > 1e-8 {
println!("Warning: Primal violation is too LARGE");
accepted = false;
}
if max_dual_viol > 1e-6 {
println!("Warning: Dual violation is too LARGE.");
accepted = false;
}
if accepted {
let numvar = task.get_num_var()?;
println!("Optimal primal solution");
let mut xx = vec![0.0; numvar as usize];
task.get_xx(Soltype::BAS,xx.as_mut_slice())?;
for (j,&xj) in (0..numvar).zip(xx.iter()) {
println!("x[{}]: {}",j,xj);
}
} else {
task.analyze_solution(Streamtype::LOG, Soltype::BAS)?;
}
},
Solsta::DUAL_INFEAS_CER => println!("Primal or dual infeasibility certificate found."),
Solsta::UNKNOWN => println!("The status of the solution is unknown."),
_ => println!("Other solution status"),
}
Ok(())
}
#[cfg(test)]
mod tests {
const DFLT_FILE : &str = "Task
Objective
Maximize + 3 @x0 + @x1 + 5 @x2 + @x3
Constraints
@c0 [30] + 3 @x0 + @x1 + 2 @x2
@c1 [15;+inf] + 2 @x0 + @x1 + 3 @x2 + @x3
@c2 [-inf;25] + 2 @x1 + 3 @x3
Variables
@x0 [0;+inf]
@x1 [0;10]
@x2 [0;+inf]
@x3 [0;+inf]
";
#[test]
fn test() {
super::solutionquality(super::FileOrText::Text(DFLT_FILE.to_string())).unwrap();
}
}