lp_modeler/format/
lp_format.rs1use 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 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 } _ => (),
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}