lp_modeler/format/
lp_format.rs

1use std::fs::File;
2use std::io::prelude::*;
3use std::io::Result;
4
5use dsl::*;
6use dsl::Constraint::*;
7
8pub trait LpFileFormat {
9    fn to_lp_file_format(&self) -> String;
10    fn write_lp(&self, file_model: &str) -> Result<()> {
11        let mut buffer = File::create(file_model)?;
12        buffer.write(self.to_lp_file_format().as_bytes())?;
13        Ok(())
14    }
15}
16
17impl LpFileFormat for LpProblem {
18
19    fn to_lp_file_format(&self) -> String {
20
21        let mut buffer = String::new();
22
23        buffer.push_str(format!("\\ {}\n\n", &self.name).as_str());
24
25        buffer.push_str( &objective_lp_file_block(self) );
26
27        let constraints_block = constraints_lp_file_block(self);
28        if constraints_block.len() > 0 {
29            buffer.push_str(format!("\n\nSubject To\n{}", &constraints_block).as_str());
30        }
31
32        let bounds_block = bounds_lp_file_block(self);
33        if bounds_block.len() > 0 {
34            buffer.push_str(format!("\nBounds\n{}", &bounds_block).as_str());
35        }
36
37        let integers_block = integers_lp_file_block(self);
38        if integers_block.len() > 0 {
39            buffer.push_str(format!("\nGenerals\n  {}\n", &integers_block).as_str());
40        }
41
42        let binaries_block = binaries_lp_file_block(self);
43        if binaries_block.len() > 0 {
44            buffer.push_str(format!("\nBinary\n  {}\n", &binaries_block).as_str());
45        }
46
47        buffer.push_str("\nEnd\n");
48
49        buffer
50    }
51}
52
53fn objective_lp_file_block(prob: &LpProblem) -> String {
54    // Write objectives
55    let obj_type = match prob.objective_type {
56        LpObjective::Maximize => "Maximize\n  ",
57        LpObjective::Minimize => "Minimize\n  "
58    };
59    match &prob.obj_expr_arena {
60        Some(expr_arena) => {
61            format!("{}obj: {}", obj_type, expr_arena.to_lp_file_format())
62        }
63        _ => String::new()
64    }
65}
66fn constraints_lp_file_block(prob: &LpProblem) -> String {
67    let mut res = String::new();
68    let mut constraints = prob.constraints.iter();
69    let mut index = 1;
70    while let Some(constraint) = constraints.next() {
71        res.push_str(&format!("  c{}: {}\n", index.to_string(), constraint.to_lp_file_format()));
72        index += 1;
73    }
74    res
75}
76
77fn bounds_lp_file_block(prob: &LpProblem) -> String {
78    let mut res = String::new();
79    for (_, (constraint_index, lp_expr_arena_index)) in prob.variables() {
80        let expr_ref = prob.constraints.get(constraint_index).unwrap().0.expr_ref_at(lp_expr_arena_index);
81        match expr_ref {
82            &LpExprNode::ConsInt(LpInteger {
83                         ref name,
84                         lower_bound,
85                         upper_bound,
86                     })
87            | &LpExprNode::ConsCont(LpContinuous {
88                            ref name,
89                            lower_bound,
90                            upper_bound,
91                        }) => {
92                if let Some(l) = lower_bound {
93                    res.push_str(&format!("  {} <= {}", &l.to_string(), &name));
94                    if let Some(u) = upper_bound {
95                        res.push_str(&format!(" <= {}", &u.to_string()));
96                    }
97                    res.push_str("\n");
98                } else if let Some(u) = upper_bound {
99                    res.push_str(&format!("  {} <= {}\n", &name, &u.to_string()));
100                } else {
101                    match expr_ref {
102                        &LpExprNode::ConsCont(LpContinuous { .. }) => {
103                            res.push_str(&format!("  {} free\n", &name));
104                        } // TODO: IntegerVar => -INF to INF
105                        _ => (),
106                    }
107                }
108            }
109            _ => (),
110        }
111    }
112    res
113}
114
115fn integers_lp_file_block(prob: &LpProblem) -> String {
116    let mut res = String::new();
117    for (_, (constraint_index, lp_expr_arena_index)) in prob.variables() {
118        match prob.constraints.get(constraint_index).unwrap().0.expr_ref_at(lp_expr_arena_index) {
119            &LpExprNode::ConsInt(LpInteger { ref name, .. }) => {
120                res.push_str(format!("{} ", name).as_str());
121            }
122            _ => (),
123        }
124    }
125    res
126}
127
128fn binaries_lp_file_block(prob: &LpProblem) -> String  {
129    let mut res = String::new();
130    for (_, (constraint_index, lp_expr_arena_index)) in prob.variables() {
131        match prob.constraints.get(constraint_index).unwrap().0.expr_ref_at(lp_expr_arena_index) {
132            &LpExprNode::ConsBin(LpBinary { ref name }) => {
133                res.push_str(format!("{} ", name).as_str());
134            }
135            _ => (),
136        }
137    }
138    res
139}
140
141impl LpFileFormat for LpExpression {
142    fn to_lp_file_format(&self) -> String {
143        fn formalize_signs(s: String) -> String {
144            let mut s = s.clone();
145            let mut t = "".to_string();
146            while s != t {
147                t = s.clone();
148                s = s.replace("+ +", "+ ");
149                s = s.replace("- +", "- ");
150                s = s.replace("+ -", "- ");
151                s = s.replace("- -", "+ ");
152                s = s.replace("  ", " ");
153            }
154            s
155        }
156        let root_index = self.get_root_index();
157        let mut clone = self.clone();
158        formalize_signs(clone.simplify().show(&root_index, false))
159    }
160}
161
162
163impl LpFileFormat for LpConstraint {
164    fn to_lp_file_format(&self) -> String {
165        let mut res = String::new();
166        res.push_str(&self.0.to_lp_file_format());
167        match self.1 {
168            GreaterOrEqual => res.push_str(" >= "),
169            LessOrEqual => res.push_str(" <= "),
170            Equal => res.push_str(" = "),
171        }
172        res.push_str(&self.2.to_lp_file_format());
173        res
174    }
175}