1 #include "lp_writer.hpp"
2
LPBase(std::shared_ptr<ExpressionBase> _constant_expr,std::vector<std::shared_ptr<ExpressionBase>> & _linear_coefficients,std::vector<std::shared_ptr<Var>> & _linear_vars,std::vector<std::shared_ptr<ExpressionBase>> & _quadratic_coefficients,std::vector<std::shared_ptr<Var>> & _quadratic_vars_1,std::vector<std::shared_ptr<Var>> & _quadratic_vars_2)3 LPBase::LPBase(std::shared_ptr<ExpressionBase> _constant_expr,
4 std::vector<std::shared_ptr<ExpressionBase> > &_linear_coefficients,
5 std::vector<std::shared_ptr<Var> > &_linear_vars,
6 std::vector<std::shared_ptr<ExpressionBase> > &_quadratic_coefficients,
7 std::vector<std::shared_ptr<Var> > &_quadratic_vars_1,
8 std::vector<std::shared_ptr<Var> > &_quadratic_vars_2)
9 {
10 constant_expr = _constant_expr;
11
12 linear_coefficients = std::make_shared<std::vector<std::shared_ptr<ExpressionBase> > >();
13 linear_vars = std::make_shared<std::vector<std::shared_ptr<Var> > >();
14 for (unsigned int ndx=0; ndx<_linear_vars.size(); ++ndx)
15 {
16 linear_coefficients->push_back(_linear_coefficients[ndx]);
17 linear_vars->push_back(_linear_vars[ndx]);
18 }
19
20 quadratic_coefficients = std::make_shared<std::vector<std::shared_ptr<ExpressionBase> > >();
21 quadratic_vars_1 = std::make_shared<std::vector<std::shared_ptr<Var> > >();
22 quadratic_vars_2 = std::make_shared<std::vector<std::shared_ptr<Var> > >();
23 for (unsigned int ndx=0; ndx<_quadratic_coefficients.size(); ++ndx)
24 {
25 quadratic_coefficients->push_back(_quadratic_coefficients[ndx]);
26 quadratic_vars_1->push_back(_quadratic_vars_1[ndx]);
27 quadratic_vars_2->push_back(_quadratic_vars_2[ndx]);
28 }
29 }
30
31
add_constraint(std::shared_ptr<LPConstraint> con)32 void LPWriter::add_constraint(std::shared_ptr<LPConstraint> con)
33 {
34 con->index = current_cons_index;
35 ++current_cons_index;
36 constraints->insert(con);
37 }
38
39
remove_constraint(std::shared_ptr<LPConstraint> con)40 void LPWriter::remove_constraint(std::shared_ptr<LPConstraint> con)
41 {
42 con->index = -1;
43 constraints->erase(con);
44 }
45
46
constraint_sorter(std::shared_ptr<LPConstraint> con1,std::shared_ptr<LPConstraint> con2)47 bool constraint_sorter(std::shared_ptr<LPConstraint> con1, std::shared_ptr<LPConstraint> con2)
48 {
49 return con1->index < con2->index;
50 }
51
52
write_expr(std::ofstream & f,std::shared_ptr<LPBase> obj,bool is_objective)53 void write_expr(std::ofstream &f, std::shared_ptr<LPBase> obj, bool is_objective)
54 {
55 double coef;
56 for (unsigned int ndx=0; ndx<obj->linear_coefficients->size(); ++ndx)
57 {
58 coef = obj->linear_coefficients->at(ndx)->evaluate();
59 if (coef >= 0)
60 {
61 f << "+";
62 }
63 else
64 {
65 f << "-";
66 }
67 f << std::abs(coef) << " ";
68 f << obj->linear_vars->at(ndx)->name << " \n";
69 }
70 if (is_objective)
71 {
72 f << "+1 obj_const \n";
73 }
74
75 if (obj->quadratic_coefficients->size() != 0)
76 {
77 f << "+ [ \n";
78 for (unsigned int ndx=0; ndx<obj->quadratic_coefficients->size(); ++ndx)
79 {
80 coef = obj->quadratic_coefficients->at(ndx)->evaluate();
81 if (is_objective)
82 {
83 coef *= 2;
84 }
85 if (coef >= 0)
86 {
87 f << "+";
88 }
89 else
90 {
91 f << "-";
92 }
93 f << std::abs(coef) << " ";
94 f << obj->quadratic_vars_1->at(ndx)->name << " * ";
95 f << obj->quadratic_vars_2->at(ndx)->name << " \n";
96 }
97 f << "] ";
98 if (is_objective)
99 {
100 f << "/ 2 ";
101 }
102 f << "\n";
103 }
104 }
105
106
write(std::string filename)107 void LPWriter::write(std::string filename)
108 {
109 std::ofstream f;
110 f.open(filename);
111 f.precision(17);
112
113 if (objective->sense == 0)
114 {
115 f << "minimize\n";
116 }
117 else
118 {
119 f << "maximize\n";
120 }
121
122 f << objective->name << ": \n";
123 write_expr(f, objective, true);
124
125 f << "\ns.t.\n\n";
126
127 std::vector<std::shared_ptr<LPConstraint> > sorted_constraints;
128 for (std::shared_ptr<LPConstraint> con : *constraints)
129 {
130 sorted_constraints.push_back(con);
131 }
132 std::sort(sorted_constraints.begin(), sorted_constraints.end(), constraint_sorter);
133 int sorted_con_index = 0;
134 for (std::shared_ptr<LPConstraint> con : sorted_constraints)
135 {
136 con->index = sorted_con_index;
137 sorted_con_index += 1;
138 }
139 current_cons_index = constraints->size();
140
141 std::vector<std::shared_ptr<LPConstraint> > active_constraints;
142 for (std::shared_ptr<LPConstraint> con : sorted_constraints)
143 {
144 if (con->active)
145 {
146 active_constraints.push_back(con);
147 }
148 }
149
150 double con_lb;
151 double con_ub;
152 double body_constant_val;
153 for (std::shared_ptr<LPConstraint> con : active_constraints)
154 {
155 con_lb = con->lb->evaluate();
156 con_ub = con->ub->evaluate();
157 body_constant_val = con->constant_expr->evaluate();
158 if (con_lb == con_ub)
159 {
160 con_lb -= body_constant_val;
161 con_ub = con_lb;
162 f << con->name << "_eq: \n";
163 write_expr(f, con, false);
164 f << "= " << con_lb << " \n\n";
165 }
166 else if (con_lb > -inf && con_ub < inf)
167 {
168 con_lb -= body_constant_val;
169 con_ub -= body_constant_val;
170 f << con->name << "_lb: \n";
171 write_expr(f, con, false);
172 f << ">= " << con_lb << " \n\n";
173 f << con->name << "_ub: \n";
174 write_expr(f, con, false);
175 f << "<= " << con_ub << " \n\n";
176 }
177 else if (con_lb > -inf)
178 {
179 con_lb -= body_constant_val;
180 f << con->name << "_lb: \n";
181 write_expr(f, con, false);
182 f << ">= " << con_lb << " \n\n";
183 }
184 else if (con_ub < inf)
185 {
186 con_ub -= body_constant_val;
187 f << con->name << "_ub: \n";
188 write_expr(f, con, false);
189 f << "<= " << con_ub << " \n\n";
190 }
191 }
192
193 f << "obj_const_con_eq: \n";
194 f << "+1 obj_const \n";
195 f << "= " << objective->constant_expr->evaluate() << " \n\n";
196
197 for (std::shared_ptr<LPConstraint> con : active_constraints)
198 {
199 for (std::shared_ptr<Var> v : *(con->linear_vars))
200 {
201 v->index = -1;
202 }
203 for (std::shared_ptr<Var> v : *(con->quadratic_vars_1))
204 {
205 v->index = -1;
206 }
207 for (std::shared_ptr<Var> v : *(con->quadratic_vars_2))
208 {
209 v->index = -1;
210 }
211 }
212
213 for (std::shared_ptr<Var> v : *(objective->linear_vars))
214 {
215 v->index = -1;
216 }
217 for (std::shared_ptr<Var> v : *(objective->quadratic_vars_1))
218 {
219 v->index = -1;
220 }
221 for (std::shared_ptr<Var> v : *(objective->quadratic_vars_2))
222 {
223 v->index = -1;
224 }
225
226 std::vector<std::shared_ptr<Var> > active_vars;
227 for (std::shared_ptr<LPConstraint> con : active_constraints)
228 {
229 for (std::shared_ptr<Var> v : *(con->linear_vars))
230 {
231 if (v->index == -1)
232 {
233 v->index = -2;
234 active_vars.push_back(v);
235 }
236 }
237 for (std::shared_ptr<Var> v : *(con->quadratic_vars_1))
238 {
239 if (v->index == -1)
240 {
241 v->index = -2;
242 active_vars.push_back(v);
243 }
244 }
245 for (std::shared_ptr<Var> v : *(con->quadratic_vars_2))
246 {
247 if (v->index == -1)
248 {
249 v->index = -2;
250 active_vars.push_back(v);
251 }
252 }
253 }
254
255 for (std::shared_ptr<Var> v : *(objective->linear_vars))
256 {
257 if (v->index == -1)
258 {
259 v->index = -2;
260 active_vars.push_back(v);
261 }
262 }
263 for (std::shared_ptr<Var> v : *(objective->quadratic_vars_1))
264 {
265 if (v->index == -1)
266 {
267 v->index = -2;
268 active_vars.push_back(v);
269 }
270 }
271 for (std::shared_ptr<Var> v : *(objective->quadratic_vars_2))
272 {
273 if (v->index == -1)
274 {
275 v->index = -2;
276 active_vars.push_back(v);
277 }
278 }
279
280 f << "Bounds\n";
281 std::vector<std::shared_ptr<Var> > binaries;
282 std::vector<std::shared_ptr<Var> > integers;
283 for (std::shared_ptr<Var> v : active_vars)
284 {
285 if (v->domain == "binary")
286 {
287 binaries.push_back(v);
288 }
289 else if (v->domain == "integer")
290 {
291 integers.push_back(v);
292 }
293 if (v->fixed)
294 {
295 f << " " << v->value << " <= " << v->name << " <= " << v->value << " \n";
296 }
297 else
298 {
299 f << " ";
300 if (v->lb <= -inf)
301 {
302 f << "-inf";
303 }
304 else
305 {
306 f << v->lb;
307 }
308 f << " <= " << v->name << " <= ";
309 if (v->ub >= inf)
310 {
311 f << "+inf";
312 }
313 else
314 {
315 f << v->ub;
316 }
317 f << " \n";
318 }
319 }
320 f << "-inf <= obj_const <= +inf\n\n";
321
322 if (binaries.size() > 0)
323 {
324 f << "Binaries \n";
325 for (std::shared_ptr<Var> v : binaries)
326 {
327 f << v->name << " \n";
328 }
329 }
330
331 if (integers.size() > 0)
332 {
333 f << "Generals \n";
334 for (std::shared_ptr<Var> v : integers)
335 {
336 f << v->name << " \n";
337 }
338 }
339
340 f << "end\n";
341
342 f.close();
343
344 solve_cons = active_constraints;
345 solve_vars = active_vars;
346 }
347
348
get_solve_vars()349 std::vector<std::shared_ptr<Var> > LPWriter::get_solve_vars()
350 {
351 return solve_vars;
352 }
353
354
get_solve_cons()355 std::vector<std::shared_ptr<LPConstraint> > LPWriter::get_solve_cons()
356 {
357 return solve_cons;
358 }
359
360
process_lp_constraints(py::list cons,py::object writer)361 void process_lp_constraints(py::list cons, py::object writer)
362 {
363 py::object generate_standard_repn = py::module_::import("pyomo.repn.standard_repn").attr("generate_standard_repn");
364 py::object id = py::module_::import("pyomo.contrib.appsi.writers.lp_writer").attr("id");
365 py::object ScalarParam = py::module_::import("pyomo.core.base.param").attr("ScalarParam");
366 py::object _ParamData = py::module_::import("pyomo.core.base.param").attr("_ParamData");
367 py::object NumericConstant = py::module_::import("pyomo.core.expr.numvalue").attr("NumericConstant");
368 py::str cname;
369 py::object repn;
370 py::object getSymbol = writer.attr("_symbol_map").attr("getSymbol");
371 py::object labeler = writer.attr("_con_labeler");
372 py::object dfs_postorder_stack = writer.attr("_walker").attr("dfs_postorder_stack");
373 LPWriter* c_writer = writer.attr("_writer").cast<LPWriter*>();
374 py::dict var_map = writer.attr("_pyomo_var_to_solver_var_map");
375 py::dict param_map = writer.attr("_pyomo_param_to_solver_param_map");
376 py::dict pyomo_con_to_solver_con_map = writer.attr("_pyomo_con_to_solver_con_map");
377 py::dict solver_con_to_pyomo_con_map = writer.attr("_solver_con_to_pyomo_con_map");
378 py::int_ ione = 1;
379 py::float_ fone = 1.0;
380 py::type int_ = py::type::of(ione);
381 py::type float_ = py::type::of(fone);
382 py::type tmp_type = py::type::of(ione);
383 std::shared_ptr<ExpressionBase> _const;
384 py::object repn_constant;
385 std::vector<std::shared_ptr<ExpressionBase> > lin_coef;
386 std::vector<std::shared_ptr<Var> > lin_vars;
387 py::list repn_linear_coefs;
388 py::list repn_linear_vars;
389 std::vector<std::shared_ptr<ExpressionBase> > quad_coef;
390 std::vector<std::shared_ptr<Var> > quad_vars_1;
391 std::vector<std::shared_ptr<Var> > quad_vars_2;
392 py::list repn_quad_coefs;
393 py::list repn_quad_vars;
394 std::shared_ptr<LPConstraint> lp_con;
395 py::tuple v_tuple;
396 py::handle lb;
397 py::handle ub;
398 py::tuple lower_body_upper;
399 py::dict active_constraints = writer.attr("_active_constraints");
400 py::object nonlinear_expr;
401 for (py::handle c : cons)
402 {
403 lower_body_upper = active_constraints[c];
404 cname = getSymbol(c, labeler);
405 repn = generate_standard_repn(lower_body_upper[1], "compute_values"_a=false, "quadratic"_a=true);
406 nonlinear_expr = repn.attr("nonlinear_expr");
407 if (!(nonlinear_expr.is(py::none())))
408 {
409 throw py::value_error("cannot write an LP file with a nonlinear constraint");
410 }
411 repn_constant = repn.attr("constant");
412 tmp_type = py::type::of(repn_constant);
413 if (tmp_type.is(int_) || tmp_type.is(float_))
414 {
415 _const = std::make_shared<Constant>(repn_constant.cast<double>());
416 }
417 else if(tmp_type.is(ScalarParam) || tmp_type.is(_ParamData))
418 {
419 _const = param_map[id(repn_constant)].cast<std::shared_ptr<ExpressionBase> >();
420 }
421 else
422 {
423 _const = dfs_postorder_stack(repn_constant).cast<std::shared_ptr<ExpressionBase> >();
424 }
425 lin_coef.clear();
426 repn_linear_coefs = repn.attr("linear_coefs");
427 for (py::handle coef : repn_linear_coefs)
428 {
429 tmp_type = py::type::of(coef);
430 if (tmp_type.is(int_) || tmp_type.is(float_))
431 {
432 lin_coef.push_back(std::make_shared<Constant>(coef.cast<double>()));
433 }
434 else if(tmp_type.is(ScalarParam) || tmp_type.is(_ParamData))
435 {
436 lin_coef.push_back(param_map[id(coef)].cast<std::shared_ptr<ExpressionBase> >());
437 }
438 else
439 {
440 lin_coef.push_back(dfs_postorder_stack(coef).cast<std::shared_ptr<ExpressionBase> >());
441 }
442 }
443 lin_vars.clear();
444 repn_linear_vars = repn.attr("linear_vars");
445 for (py::handle v : repn_linear_vars)
446 {
447 lin_vars.push_back(var_map[id(v)].cast<std::shared_ptr<Var> >());
448 }
449 quad_coef.clear();
450 repn_quad_coefs = repn.attr("quadratic_coefs");
451 for (py::handle coef : repn_quad_coefs)
452 {
453 tmp_type = py::type::of(coef);
454 if (tmp_type.is(int_) || tmp_type.is(float_))
455 {
456 quad_coef.push_back(std::make_shared<Constant>(coef.cast<double>()));
457 }
458 else if(tmp_type.is(ScalarParam) || tmp_type.is(_ParamData))
459 {
460 quad_coef.push_back(param_map[id(coef)].cast<std::shared_ptr<ExpressionBase> >());
461 }
462 else
463 {
464 quad_coef.push_back(dfs_postorder_stack(coef).cast<std::shared_ptr<ExpressionBase> >());
465 }
466 }
467 quad_vars_1.clear();
468 quad_vars_2.clear();
469 repn_quad_vars = repn.attr("quadratic_vars");
470 for (py::handle v_tuple_handle : repn_quad_vars)
471 {
472 v_tuple = v_tuple_handle.cast<py::tuple>();
473 quad_vars_1.push_back(var_map[id(v_tuple[0])].cast<std::shared_ptr<Var> >());
474 quad_vars_2.push_back(var_map[id(v_tuple[1])].cast<std::shared_ptr<Var> >());
475 }
476
477 lp_con = std::make_shared<LPConstraint>(_const, lin_coef, lin_vars, quad_coef, quad_vars_1, quad_vars_2);
478 lp_con->name = cname;
479
480 lb = lower_body_upper[0];
481 ub = lower_body_upper[2];
482 if (!lb.is(py::none()))
483 {
484 tmp_type = py::type::of(lb);
485 if (tmp_type.is(NumericConstant))
486 {
487 lp_con->lb = std::make_shared<Constant>(lb.attr("value").cast<double>());
488 }
489 else if (tmp_type.is(int_) || tmp_type.is(float_))
490 {
491 lp_con->lb = std::make_shared<Constant>(lb.cast<double>());
492 }
493 else if(tmp_type.is(ScalarParam) || tmp_type.is(_ParamData))
494 {
495 lp_con->lb = param_map[id(lb)].cast<std::shared_ptr<ExpressionBase> >();
496 }
497 else
498 {
499 lp_con->lb = dfs_postorder_stack(lb).cast<std::shared_ptr<ExpressionBase> >();
500 }
501 }
502 if (!ub.is(py::none()))
503 {
504 tmp_type = py::type::of(ub);
505 if (tmp_type.is(NumericConstant))
506 {
507 lp_con->ub = std::make_shared<Constant>(ub.attr("value").cast<double>());
508 }
509 else if (tmp_type.is(int_) || tmp_type.is(float_))
510 {
511 lp_con->ub = std::make_shared<Constant>(ub.cast<double>());
512 }
513 else if(tmp_type.is(ScalarParam) || tmp_type.is(_ParamData))
514 {
515 lp_con->ub = param_map[id(ub)].cast<std::shared_ptr<ExpressionBase> >();
516 }
517 else
518 {
519 lp_con->ub = dfs_postorder_stack(ub).cast<std::shared_ptr<ExpressionBase> >();
520 }
521 }
522 c_writer->add_constraint(lp_con);
523 pyomo_con_to_solver_con_map[c] = py::cast(lp_con);
524 solver_con_to_pyomo_con_map[py::cast(lp_con)] = c;
525 }
526 }
527