solutionquality/
solutionquality.rs

1//!
2//!  Copyright : Copyright (c) MOSEK ApS, Denmark. All rights reserved.
3//!
4//!  File : solutionquality.rs
5//!
6//!  Purpose :   To demonstrate how to examine the quality of a solution.
7
8extern crate mosek;
9
10use mosek::{Task,Streamtype,Solsta,Soltype};
11use std::env;
12
13enum FileOrText {
14    File(String),
15    Text(String)
16}
17
18fn main() -> Result<(),String> {
19    let mut args = env::args();
20    if args.len() < 2 {
21        println!("Syntax: solutionquality FILENAME");
22        return Err("Invalid argument list".to_string())
23    }
24    let _ = args.next();
25    let filename = args.next().unwrap();
26    solutionquality(FileOrText::File(filename))
27}
28
29fn solutionquality(filename : FileOrText) -> Result<(),String> {
30    let mut task = Task::new().unwrap().with_callbacks();
31    task.put_stream_callback(Streamtype::LOG, |msg| print!("{}",msg))?;
32    // We assume that a problem file was given as the first command
33    // line argument (received in `args')
34    match filename {
35        FileOrText::File(filename) => task.read_data (filename.as_str())?,
36        FileOrText::Text(data) => task.read_ptf_string(data.as_str())?
37    }
38
39    // Solve the problem
40    let _ = task.optimize()?;
41
42    task.solution_summary(Streamtype::LOG)?;
43
44    let solsta = task.get_sol_sta(Soltype::BAS)?;
45
46    let mut pobj        : f64 = 0.0;
47    let mut pviolcon    : f64 = 0.0;
48    let mut pviolvar    : f64 = 0.0;
49    let mut pviolbarvar : f64 = 0.0;
50    let mut pviolcones  : f64 = 0.0;
51    let mut pviolitg    : f64 = 0.0;
52    let mut dobj        : f64 = 0.0;
53    let mut dviolcon    : f64 = 0.0;
54    let mut dviolvar    : f64 = 0.0;
55    let mut dviolbarvar : f64 = 0.0;
56    let mut dviolcones  : f64 = 0.0;
57
58    task.get_solution_info(Soltype::BAS,
59                           & mut pobj, & mut pviolcon, & mut pviolvar, & mut pviolbarvar, & mut pviolcones, & mut pviolitg,
60                           & mut dobj, & mut dviolcon, & mut dviolvar, & mut dviolbarvar, & mut dviolcones)?;
61    match solsta {
62        Solsta::OPTIMAL => {
63            let abs_obj_gap = (dobj-pobj).abs();
64            let rel_obj_gap = abs_obj_gap / (1.0 + f64::min(pobj.abs(), dobj.abs()));
65            let max_primal_viol = f64::max(pviolcon, pviolvar);
66            let max_primal_viol = f64::max(max_primal_viol  , pviolbarvar);
67            let max_primal_viol = f64::max(max_primal_viol  , pviolcones);
68
69            let max_dual_viol   = f64::max(dviolcon, dviolvar);
70            let max_dual_viol   = f64::max(max_dual_viol, dviolbarvar);
71            let max_dual_viol   = f64::max(max_dual_viol, dviolcones);
72
73            // Assume the application needs the solution to be within
74            //    1e-6 ofoptimality in an absolute sense. Another approach
75            //   would be looking at the relative objective gap
76
77            println!("Customized solution information.");
78            println!("  Absolute objective gap: {:.3e}", abs_obj_gap);
79            println!("  Relative objective gap: {:.3e}", rel_obj_gap);
80            println!("  Max primal violation  : {:.3e}", max_primal_viol);
81            println!("  Max dual violation    : {:.3e}", max_dual_viol);
82
83            let mut accepted = true;
84
85            if rel_obj_gap > 1e-6 {
86                println!("Warning: The relative objective gap is LARGE.");
87                accepted = false;
88            }
89
90            // We will accept a primal infeasibility of 1e-8 and
91            // dual infeasibility of 1e-6. These number should chosen problem
92            // dependent.
93            if max_primal_viol > 1e-8 {
94                println!("Warning: Primal violation is too LARGE");
95                accepted = false;
96            }
97
98            if max_dual_viol > 1e-6 {
99                println!("Warning: Dual violation is too LARGE.");
100                accepted = false;
101            }
102
103            if accepted {
104                let numvar = task.get_num_var()?;
105                println!("Optimal primal solution");
106                let mut xx = vec![0.0; numvar as usize];
107                task.get_xx(Soltype::BAS,xx.as_mut_slice())?;
108                for (j,&xj) in (0..numvar).zip(xx.iter()) {
109                    println!("x[{}]: {}",j,xj);
110                }
111            } else {
112                // print etailed information about the solution
113                task.analyze_solution(Streamtype::LOG, Soltype::BAS)?;
114            }
115        },
116        Solsta::DUAL_INFEAS_CER => println!("Primal or dual infeasibility certificate found."),
117        Solsta::UNKNOWN => println!("The status of the solution is unknown."),
118        _ => println!("Other solution status"),
119    }
120    Ok(())
121}
122
123
124#[cfg(test)]
125mod tests {
126
127    const DFLT_FILE : &str = "Task
128Objective
129    Maximize + 3 @x0 + @x1 + 5 @x2 + @x3
130Constraints
131    @c0 [30] + 3 @x0 + @x1 + 2 @x2
132    @c1 [15;+inf] + 2 @x0 + @x1 + 3 @x2 + @x3
133    @c2 [-inf;25] + 2 @x1 + 3 @x3
134Variables
135    @x0 [0;+inf]
136    @x1 [0;10]
137    @x2 [0;+inf]
138    @x3 [0;+inf]
139";
140
141    #[test]
142    fn test() {
143        super::solutionquality(super::FileOrText::Text(DFLT_FILE.to_string())).unwrap();
144    }
145}