deba@2316
|
1 |
/* -*- C++ -*-
|
deba@2316
|
2 |
*
|
deba@2316
|
3 |
* This file is a part of LEMON, a generic C++ optimization library
|
deba@2316
|
4 |
*
|
deba@2316
|
5 |
* Copyright (C) 2003-2006
|
deba@2316
|
6 |
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
|
deba@2316
|
7 |
* (Egervary Research Group on Combinatorial Optimization, EGRES).
|
deba@2316
|
8 |
*
|
deba@2316
|
9 |
* Permission to use, modify and distribute this software is granted
|
deba@2316
|
10 |
* provided that this copyright notice appears in all copies. For
|
deba@2316
|
11 |
* precise terms see the accompanying LICENSE file.
|
deba@2316
|
12 |
*
|
deba@2316
|
13 |
* This software is provided "AS IS" with no warranty of any kind,
|
deba@2316
|
14 |
* express or implied, and with no claim as to its suitability for any
|
deba@2316
|
15 |
* purpose.
|
deba@2316
|
16 |
*
|
deba@2316
|
17 |
*/
|
deba@2316
|
18 |
|
deba@2316
|
19 |
#ifndef LEMON_LP_UTILS_H
|
deba@2316
|
20 |
#define LEMON_LP_UTILS_H
|
deba@2316
|
21 |
|
deba@2316
|
22 |
#include <lemon/lp_base.h>
|
deba@2316
|
23 |
|
deba@2316
|
24 |
#include <lemon/lemon_reader.h>
|
deba@2363
|
25 |
#include <lemon/lemon_writer.h>
|
deba@2316
|
26 |
|
deba@2316
|
27 |
namespace lemon {
|
deba@2316
|
28 |
|
deba@2316
|
29 |
class LpReader : public LemonReader::SectionReader {
|
deba@2316
|
30 |
typedef LemonReader::SectionReader Parent;
|
deba@2316
|
31 |
public:
|
deba@2316
|
32 |
|
deba@2316
|
33 |
|
deba@2316
|
34 |
/// \brief Constructor.
|
deba@2316
|
35 |
///
|
deba@2316
|
36 |
/// Constructor for LpReader. It creates the LpReader and attach
|
deba@2316
|
37 |
/// it into the given LemonReader. The lp reader will add
|
deba@2316
|
38 |
/// variables, constraints and objective function to the
|
deba@2316
|
39 |
/// given lp solver.
|
deba@2316
|
40 |
LpReader(LemonReader& _reader, LpSolverBase& _lp,
|
deba@2316
|
41 |
const std::string& _name = std::string())
|
deba@2316
|
42 |
: Parent(_reader), lp(_lp), name(_name) {}
|
deba@2316
|
43 |
|
deba@2316
|
44 |
|
deba@2316
|
45 |
/// \brief Destructor.
|
deba@2316
|
46 |
///
|
deba@2316
|
47 |
/// Destructor for NodeSetReader.
|
deba@2316
|
48 |
virtual ~LpReader() {}
|
deba@2316
|
49 |
|
deba@2316
|
50 |
private:
|
deba@2316
|
51 |
LpReader(const LpReader&);
|
deba@2316
|
52 |
void operator=(const LpReader&);
|
deba@2316
|
53 |
|
deba@2316
|
54 |
protected:
|
deba@2316
|
55 |
|
deba@2316
|
56 |
/// \brief Gives back true when the SectionReader can process
|
deba@2316
|
57 |
/// the section with the given header line.
|
deba@2316
|
58 |
///
|
deba@2316
|
59 |
/// It gives back true when the header line starts with \c \@lp,
|
deba@2316
|
60 |
/// and the header line's name and the nodeset's name are the same.
|
deba@2316
|
61 |
virtual bool header(const std::string& line) {
|
deba@2316
|
62 |
std::istringstream ls(line);
|
deba@2316
|
63 |
std::string command;
|
deba@2316
|
64 |
std::string id;
|
deba@2316
|
65 |
ls >> command >> id;
|
deba@2316
|
66 |
return command == "@lp" && name == id;
|
deba@2316
|
67 |
}
|
deba@2316
|
68 |
|
deba@2316
|
69 |
private:
|
deba@2316
|
70 |
|
deba@2316
|
71 |
enum Relation {
|
deba@2316
|
72 |
LE, EQ, GE
|
deba@2316
|
73 |
};
|
deba@2316
|
74 |
|
deba@2316
|
75 |
std::istream& readConstraint(std::istream& is, LpSolverBase::Constr& c) {
|
deba@2316
|
76 |
char x;
|
deba@2316
|
77 |
LpSolverBase::Expr e1, e2;
|
deba@2316
|
78 |
Relation op1;
|
deba@2316
|
79 |
is >> std::ws;
|
deba@2316
|
80 |
readExpression(is, e1);
|
deba@2316
|
81 |
is >> std::ws;
|
deba@2316
|
82 |
readRelation(is, op1);
|
deba@2316
|
83 |
is >> std::ws;
|
deba@2316
|
84 |
readExpression(is, e2);
|
deba@2316
|
85 |
if (!is.get(x)) {
|
deba@2316
|
86 |
if (op1 == LE) {
|
deba@2316
|
87 |
c = e1 <= e2;
|
deba@2316
|
88 |
} else if (op1 == GE) {
|
deba@2316
|
89 |
c = e1 >= e2;
|
deba@2316
|
90 |
} else {
|
deba@2316
|
91 |
c = e1 == e2;
|
deba@2316
|
92 |
}
|
deba@2316
|
93 |
} else {
|
deba@2316
|
94 |
is.putback(x);
|
deba@2316
|
95 |
LpSolverBase::Expr e3;
|
deba@2316
|
96 |
Relation op2;
|
deba@2316
|
97 |
readRelation(is, op2);
|
deba@2316
|
98 |
is >> std::ws;
|
deba@2316
|
99 |
readExpression(is, e3);
|
deba@2316
|
100 |
if (!e1.empty() || !e3.empty()) {
|
deba@2316
|
101 |
throw DataFormatError("Wrong range format");
|
deba@2316
|
102 |
}
|
deba@2316
|
103 |
if (op2 != op1 || op1 == EQ) {
|
deba@2316
|
104 |
throw DataFormatError("Wrong range format");
|
deba@2316
|
105 |
}
|
deba@2316
|
106 |
if (op1 == LE) {
|
deba@2316
|
107 |
c = e1.constComp() <= e2 <= e3.constComp();
|
deba@2316
|
108 |
} else {
|
deba@2316
|
109 |
c = e1.constComp() >= e2 >= e3.constComp();
|
deba@2316
|
110 |
}
|
deba@2316
|
111 |
}
|
deba@2316
|
112 |
}
|
deba@2316
|
113 |
|
deba@2316
|
114 |
std::istream& readExpression(std::istream& is, LpSolverBase::Expr& e) {
|
deba@2316
|
115 |
LpSolverBase::Col c;
|
deba@2316
|
116 |
double d;
|
deba@2316
|
117 |
char x;
|
deba@2316
|
118 |
readElement(is, c, d);
|
deba@2316
|
119 |
if (c != INVALID) {
|
deba@2316
|
120 |
e += d * c;
|
deba@2316
|
121 |
} else {
|
deba@2316
|
122 |
e += d;
|
deba@2316
|
123 |
}
|
deba@2316
|
124 |
is >> std::ws;
|
deba@2316
|
125 |
while (is.get(x) && (x == '+' || x == '-')) {
|
deba@2316
|
126 |
is >> std::ws;
|
deba@2316
|
127 |
readElement(is, c, d);
|
deba@2316
|
128 |
if (c != INVALID) {
|
deba@2316
|
129 |
e += (x == '+' ? d : -d) * c;
|
deba@2316
|
130 |
} else {
|
deba@2316
|
131 |
e += (x == '+' ? d : -d);
|
deba@2316
|
132 |
}
|
deba@2316
|
133 |
is >> std::ws;
|
deba@2316
|
134 |
}
|
deba@2316
|
135 |
if (!is) {
|
deba@2316
|
136 |
is.clear();
|
deba@2316
|
137 |
} else {
|
deba@2316
|
138 |
is.putback(x);
|
deba@2316
|
139 |
}
|
deba@2316
|
140 |
return is;
|
deba@2316
|
141 |
}
|
deba@2316
|
142 |
|
deba@2316
|
143 |
std::istream& readElement(std::istream& is,
|
deba@2316
|
144 |
LpSolverBase::Col& c, double& d) {
|
deba@2316
|
145 |
d = 1.0;
|
deba@2316
|
146 |
c = INVALID;
|
deba@2316
|
147 |
char x, y;
|
deba@2316
|
148 |
if (!is.get(x)) throw DataFormatError("Cannot find lp element");
|
deba@2316
|
149 |
if (x == '+' || x == '-') {
|
deba@2316
|
150 |
is >> std::ws;
|
deba@2316
|
151 |
d *= x == '-' ? -1 : 1;
|
deba@2316
|
152 |
while (is.get(x) && (x == '+' || x == '-')) {
|
deba@2316
|
153 |
d *= x == '-' ? -1 : 1;
|
deba@2316
|
154 |
is >> std::ws;
|
deba@2316
|
155 |
}
|
deba@2316
|
156 |
if (!is) throw DataFormatError("Cannot find lp element");
|
deba@2316
|
157 |
}
|
deba@2316
|
158 |
if (numFirstChar(x)) {
|
deba@2316
|
159 |
is.putback(x);
|
deba@2316
|
160 |
double e;
|
deba@2316
|
161 |
readNum(is, e);
|
deba@2316
|
162 |
d *= e;
|
deba@2316
|
163 |
} else if (varFirstChar(x)) {
|
deba@2316
|
164 |
is.putback(x);
|
deba@2316
|
165 |
LpSolverBase::Col f;
|
deba@2316
|
166 |
readCol(is, f);
|
deba@2316
|
167 |
c = f;
|
deba@2316
|
168 |
} else {
|
deba@2316
|
169 |
throw DataFormatError("Invalid expression format");
|
deba@2316
|
170 |
}
|
deba@2316
|
171 |
is >> std::ws;
|
deba@2316
|
172 |
while (is.get(y) && (y == '*' || y == '/')) {
|
deba@2316
|
173 |
is >> std::ws;
|
deba@2316
|
174 |
if (!is.get(x)) throw DataFormatError("Cannot find lp element");
|
deba@2316
|
175 |
if (x == '+' || x == '-') {
|
deba@2316
|
176 |
is >> std::ws;
|
deba@2316
|
177 |
d *= x == '-' ? -1 : 1;
|
deba@2316
|
178 |
while (is.get(x) && (x == '+' || x == '-')) {
|
deba@2316
|
179 |
d *= x == '-' ? -1 : 1;
|
deba@2316
|
180 |
is >> std::ws;
|
deba@2316
|
181 |
}
|
deba@2316
|
182 |
if (!is) throw DataFormatError("Cannot find lp element");
|
deba@2316
|
183 |
}
|
deba@2316
|
184 |
if (numFirstChar(x)) {
|
deba@2316
|
185 |
is.putback(x);
|
deba@2316
|
186 |
double e;
|
deba@2316
|
187 |
readNum(is, e);
|
deba@2316
|
188 |
if (y == '*') {
|
deba@2316
|
189 |
d *= e;
|
deba@2316
|
190 |
} else {
|
deba@2316
|
191 |
d /= e;
|
deba@2316
|
192 |
}
|
deba@2316
|
193 |
} else if (varFirstChar(x)) {
|
deba@2316
|
194 |
is.putback(x);
|
deba@2316
|
195 |
LpSolverBase::Col f;
|
deba@2316
|
196 |
readCol(is, f);
|
deba@2316
|
197 |
if (y == '*') {
|
deba@2316
|
198 |
if (c == INVALID) {
|
deba@2316
|
199 |
c = f;
|
deba@2316
|
200 |
} else {
|
deba@2316
|
201 |
throw DataFormatError("Quadratic element in expression");
|
deba@2316
|
202 |
}
|
deba@2316
|
203 |
} else {
|
deba@2316
|
204 |
throw DataFormatError("Division by variable");
|
deba@2316
|
205 |
}
|
deba@2316
|
206 |
} else {
|
deba@2316
|
207 |
throw DataFormatError("Invalid expression format");
|
deba@2316
|
208 |
}
|
deba@2316
|
209 |
is >> std::ws;
|
deba@2316
|
210 |
}
|
deba@2316
|
211 |
if (!is) {
|
deba@2316
|
212 |
is.clear();
|
deba@2316
|
213 |
} else {
|
deba@2316
|
214 |
is.putback(y);
|
deba@2316
|
215 |
}
|
deba@2316
|
216 |
return is;
|
deba@2316
|
217 |
}
|
deba@2316
|
218 |
|
deba@2316
|
219 |
std::istream& readCol(std::istream& is, LpSolverBase::Col& c) {
|
deba@2316
|
220 |
char x;
|
deba@2316
|
221 |
std::string var;
|
deba@2316
|
222 |
while (is.get(x) && varChar(x)) {
|
deba@2316
|
223 |
var += x;
|
deba@2316
|
224 |
}
|
deba@2316
|
225 |
if (!is) {
|
deba@2316
|
226 |
is.clear();
|
deba@2316
|
227 |
} else {
|
deba@2316
|
228 |
is.putback(x);
|
deba@2316
|
229 |
}
|
deba@2316
|
230 |
ColMap::const_iterator it = cols.find(var);
|
deba@2316
|
231 |
if (cols.find(var) != cols.end()) {
|
deba@2316
|
232 |
c = it->second;
|
deba@2316
|
233 |
} else {
|
deba@2316
|
234 |
c = lp.addCol();
|
deba@2316
|
235 |
cols.insert(std::make_pair(var, c));
|
deba@2316
|
236 |
lp.colName(c, var);
|
deba@2316
|
237 |
}
|
deba@2316
|
238 |
return is;
|
deba@2316
|
239 |
}
|
deba@2316
|
240 |
|
deba@2316
|
241 |
std::istream& readNum(std::istream& is, double& d) {
|
deba@2316
|
242 |
is >> d;
|
deba@2316
|
243 |
if (!is) throw DataFormatError("Wrong number format");
|
deba@2316
|
244 |
return is;
|
deba@2316
|
245 |
}
|
deba@2316
|
246 |
|
deba@2316
|
247 |
std::istream& readRelation(std::istream& is, Relation& op) {
|
deba@2316
|
248 |
char x, y;
|
deba@2316
|
249 |
if (!is.get(x) || !(x == '<' || x == '=' || x == '>')) {
|
deba@2316
|
250 |
throw DataFormatError("Wrong relation operator");
|
deba@2316
|
251 |
}
|
deba@2316
|
252 |
if (!is.get(y) || y != '=') {
|
deba@2316
|
253 |
throw DataFormatError("Wrong relation operator");
|
deba@2316
|
254 |
}
|
deba@2316
|
255 |
switch (x) {
|
deba@2316
|
256 |
case '<': op = LE;
|
deba@2316
|
257 |
break;
|
deba@2316
|
258 |
case '=': op = EQ;
|
deba@2316
|
259 |
break;
|
deba@2316
|
260 |
case '>': op = GE;
|
deba@2316
|
261 |
break;
|
deba@2316
|
262 |
}
|
deba@2316
|
263 |
return is;
|
deba@2316
|
264 |
}
|
deba@2316
|
265 |
|
deba@2316
|
266 |
static bool relationFirstChar(char c) {
|
deba@2316
|
267 |
return c == '<' || c == '=' || c == '>';
|
deba@2316
|
268 |
}
|
deba@2316
|
269 |
|
deba@2316
|
270 |
static bool varFirstChar(char c) {
|
deba@2316
|
271 |
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
deba@2316
|
272 |
}
|
deba@2316
|
273 |
|
deba@2316
|
274 |
static bool numFirstChar(char c) {
|
deba@2316
|
275 |
return (c >= '0' && c <= '9') || c == '.';
|
deba@2316
|
276 |
}
|
deba@2316
|
277 |
|
deba@2316
|
278 |
static bool varChar(char c) {
|
deba@2316
|
279 |
return (c >= '0' && c <= '9') ||
|
deba@2316
|
280 |
(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
deba@2316
|
281 |
}
|
deba@2316
|
282 |
|
deba@2316
|
283 |
|
deba@2316
|
284 |
void addConstraint(const LpSolverBase::Constr& constr) {
|
deba@2316
|
285 |
if (constr.expr().size() != 1) {
|
deba@2316
|
286 |
lp.addRow(constr);
|
deba@2316
|
287 |
} else {
|
deba@2316
|
288 |
Lp::Expr e = constr.expr();
|
deba@2316
|
289 |
LpSolverBase::Col col = e.begin()->first;
|
deba@2316
|
290 |
double coeff = e.begin()->second;
|
deba@2316
|
291 |
double lb = LpSolverBase::NaN;
|
deba@2316
|
292 |
double ub = LpSolverBase::NaN;
|
deba@2316
|
293 |
if (coeff > 0) {
|
deba@2316
|
294 |
if (constr.upperBounded()) {
|
deba@2316
|
295 |
lb = (constr.lowerBound() - e.constComp()) / coeff;
|
deba@2316
|
296 |
}
|
deba@2316
|
297 |
if (constr.lowerBounded()) {
|
deba@2316
|
298 |
ub = (constr.upperBound() - e.constComp()) / coeff;
|
deba@2316
|
299 |
}
|
deba@2316
|
300 |
} else if (coeff < 0) {
|
deba@2316
|
301 |
if (constr.upperBounded()) {
|
deba@2316
|
302 |
lb = (constr.upperBound() - e.constComp()) / coeff;
|
deba@2316
|
303 |
}
|
deba@2316
|
304 |
if (constr.lowerBounded()) {
|
deba@2316
|
305 |
ub = (constr.lowerBound() - e.constComp()) / coeff;
|
deba@2316
|
306 |
}
|
deba@2316
|
307 |
} else {
|
deba@2316
|
308 |
lb = -LpSolverBase::INF;
|
deba@2316
|
309 |
ub = LpSolverBase::INF;
|
deba@2316
|
310 |
}
|
deba@2316
|
311 |
lp.colLowerBound(col, lb);
|
deba@2316
|
312 |
lp.colUpperBound(col, ub);
|
deba@2316
|
313 |
}
|
deba@2316
|
314 |
}
|
deba@2316
|
315 |
|
deba@2316
|
316 |
protected:
|
deba@2316
|
317 |
|
deba@2316
|
318 |
/// \brief Reader function of the section.
|
deba@2316
|
319 |
///
|
deba@2316
|
320 |
/// It reads the content of the section.
|
deba@2316
|
321 |
virtual void read(std::istream& is) {
|
deba@2316
|
322 |
std::string line;
|
deba@2316
|
323 |
while (getline(is, line)) {
|
deba@2316
|
324 |
std::istringstream ls(line);
|
deba@2316
|
325 |
std::string sense;
|
deba@2316
|
326 |
ls >> sense;
|
deba@2316
|
327 |
if (sense == "min" || sense == "max") {
|
deba@2316
|
328 |
LpSolverBase::Expr expr;
|
deba@2316
|
329 |
ls >> std::ws;
|
deba@2316
|
330 |
readExpression(ls, expr);
|
deba@2316
|
331 |
lp.setObj(expr);
|
deba@2316
|
332 |
if (sense == "min") {
|
deba@2316
|
333 |
lp.min();
|
deba@2316
|
334 |
} else {
|
deba@2316
|
335 |
lp.max();
|
deba@2316
|
336 |
}
|
deba@2316
|
337 |
} else {
|
deba@2316
|
338 |
ls.str(line);
|
deba@2316
|
339 |
LpSolverBase::Constr constr;
|
deba@2316
|
340 |
ls >> std::ws;
|
deba@2316
|
341 |
readConstraint(ls, constr);
|
deba@2316
|
342 |
addConstraint(constr);
|
deba@2316
|
343 |
}
|
deba@2316
|
344 |
}
|
deba@2316
|
345 |
}
|
deba@2316
|
346 |
|
deba@2316
|
347 |
virtual void missing() {
|
deba@2316
|
348 |
ErrorMessage msg;
|
deba@2316
|
349 |
msg << "Lp section not found in file: @lp " << name;
|
deba@2316
|
350 |
throw IoParameterError(msg.message());
|
deba@2316
|
351 |
}
|
deba@2316
|
352 |
|
deba@2316
|
353 |
private:
|
deba@2316
|
354 |
|
deba@2316
|
355 |
typedef std::map<std::string, LpSolverBase::Col> ColMap;
|
deba@2316
|
356 |
|
deba@2316
|
357 |
LpSolverBase& lp;
|
deba@2316
|
358 |
std::string name;
|
deba@2316
|
359 |
ColMap cols;
|
deba@2316
|
360 |
};
|
deba@2316
|
361 |
|
deba@2363
|
362 |
|
deba@2363
|
363 |
// class LpWriter : public LemonWriter::SectionWriter {
|
deba@2363
|
364 |
// typedef LemonWriter::SectionWriter Parent;
|
deba@2363
|
365 |
// public:
|
deba@2363
|
366 |
|
deba@2363
|
367 |
|
deba@2363
|
368 |
// /// \brief Constructor.
|
deba@2363
|
369 |
// ///
|
deba@2363
|
370 |
// /// Constructor for LpWriter. It creates the LpWriter and attach
|
deba@2363
|
371 |
// /// it into the given LemonWriter. The lp writer will add
|
deba@2363
|
372 |
// /// variables, constraints and objective function to the
|
deba@2363
|
373 |
// /// given lp solver.
|
deba@2363
|
374 |
// LpWriter(LemonWriter& _writer, LpSolverBase& _lp,
|
deba@2363
|
375 |
// const std::string& _name = std::string())
|
deba@2363
|
376 |
// : Parent(_writer), lp(_lp), name(_name) {}
|
deba@2363
|
377 |
|
deba@2363
|
378 |
|
deba@2363
|
379 |
// /// \brief Destructor.
|
deba@2363
|
380 |
// ///
|
deba@2363
|
381 |
// /// Destructor for NodeSetWriter.
|
deba@2363
|
382 |
// virtual ~LpWriter() {}
|
deba@2363
|
383 |
|
deba@2363
|
384 |
// private:
|
deba@2363
|
385 |
// LpWriter(const LpWriter&);
|
deba@2363
|
386 |
// void operator=(const LpWriter&);
|
deba@2363
|
387 |
|
deba@2363
|
388 |
// protected:
|
deba@2363
|
389 |
|
deba@2363
|
390 |
// /// \brief Gives back true when the SectionWriter can process
|
deba@2363
|
391 |
// /// the section with the given header line.
|
deba@2363
|
392 |
// ///
|
deba@2363
|
393 |
// /// It gives back the header line of the \c \@lp section.
|
deba@2363
|
394 |
// virtual std::string header() {
|
deba@2363
|
395 |
// std::ostringstream ls(line);
|
deba@2363
|
396 |
// ls << "@lp " << name;
|
deba@2363
|
397 |
// return ls.str();
|
deba@2363
|
398 |
// }
|
deba@2363
|
399 |
|
deba@2363
|
400 |
// private:
|
deba@2363
|
401 |
|
deba@2363
|
402 |
// std::ostream& writeConstraint(std::ostream& is, LpSolverBase::Constr& c) {
|
deba@2363
|
403 |
// char x;
|
deba@2363
|
404 |
|
deba@2363
|
405 |
|
deba@2363
|
406 |
// LpSolverBase::Expr e1, e2;
|
deba@2363
|
407 |
// Relation op1;
|
deba@2363
|
408 |
// is >> std::ws;
|
deba@2363
|
409 |
// writexpression(is, e1);
|
deba@2363
|
410 |
// is >> std::ws;
|
deba@2363
|
411 |
// writeRelation(is, op1);
|
deba@2363
|
412 |
// is >> std::ws;
|
deba@2363
|
413 |
// writexpression(is, e2);
|
deba@2363
|
414 |
// if (!is.get(x)) {
|
deba@2363
|
415 |
// if (op1 == LE) {
|
deba@2363
|
416 |
// c = e1 <= e2;
|
deba@2363
|
417 |
// } else if (op1 == GE) {
|
deba@2363
|
418 |
// c = e1 >= e2;
|
deba@2363
|
419 |
// } else {
|
deba@2363
|
420 |
// c = e1 == e2;
|
deba@2363
|
421 |
// }
|
deba@2363
|
422 |
// } else {
|
deba@2363
|
423 |
// is.putback(x);
|
deba@2363
|
424 |
// LpSolverBase::Expr e3;
|
deba@2363
|
425 |
// Relation op2;
|
deba@2363
|
426 |
// writeRelation(is, op2);
|
deba@2363
|
427 |
// is >> std::ws;
|
deba@2363
|
428 |
// writexpression(is, e3);
|
deba@2363
|
429 |
// if (!e1.empty() || !e3.empty()) {
|
deba@2363
|
430 |
// throw DataFormatError("Wrong range format");
|
deba@2363
|
431 |
// }
|
deba@2363
|
432 |
// if (op2 != op1 || op1 == EQ) {
|
deba@2363
|
433 |
// throw DataFormatError("Wrong range format");
|
deba@2363
|
434 |
// }
|
deba@2363
|
435 |
// if (op1 == LE) {
|
deba@2363
|
436 |
// c = e1.constComp() <= e2 <= e3.constComp();
|
deba@2363
|
437 |
// } else {
|
deba@2363
|
438 |
// c = e1.constComp() >= e2 >= e3.constComp();
|
deba@2363
|
439 |
// }
|
deba@2363
|
440 |
// }
|
deba@2363
|
441 |
// }
|
deba@2363
|
442 |
|
deba@2363
|
443 |
// std::ostream& writexpression(std::ostream& is, LpSolverBase::Expr& e) {
|
deba@2363
|
444 |
// LpSolverBase::Col c;
|
deba@2363
|
445 |
// double d;
|
deba@2363
|
446 |
// char x;
|
deba@2363
|
447 |
// writelement(is, c, d);
|
deba@2363
|
448 |
// if (c != INVALID) {
|
deba@2363
|
449 |
// e += d * c;
|
deba@2363
|
450 |
// } else {
|
deba@2363
|
451 |
// e += d;
|
deba@2363
|
452 |
// }
|
deba@2363
|
453 |
// is >> std::ws;
|
deba@2363
|
454 |
// while (is.get(x) && (x == '+' || x == '-')) {
|
deba@2363
|
455 |
// is >> std::ws;
|
deba@2363
|
456 |
// writelement(is, c, d);
|
deba@2363
|
457 |
// if (c != INVALID) {
|
deba@2363
|
458 |
// e += (x == '+' ? d : -d) * c;
|
deba@2363
|
459 |
// } else {
|
deba@2363
|
460 |
// e += (x == '+' ? d : -d);
|
deba@2363
|
461 |
// }
|
deba@2363
|
462 |
// is >> std::ws;
|
deba@2363
|
463 |
// }
|
deba@2363
|
464 |
// if (!is) {
|
deba@2363
|
465 |
// is.clear();
|
deba@2363
|
466 |
// } else {
|
deba@2363
|
467 |
// is.putback(x);
|
deba@2363
|
468 |
// }
|
deba@2363
|
469 |
// return is;
|
deba@2363
|
470 |
// }
|
deba@2363
|
471 |
|
deba@2363
|
472 |
// std::ostream& writelement(std::ostream& is,
|
deba@2363
|
473 |
// LpSolverBase::Col& c, double& d) {
|
deba@2363
|
474 |
// d = 1.0;
|
deba@2363
|
475 |
// c = INVALID;
|
deba@2363
|
476 |
// char x, y;
|
deba@2363
|
477 |
// if (!is.get(x)) throw DataFormatError("Cannot find lp element");
|
deba@2363
|
478 |
// if (x == '+' || x == '-') {
|
deba@2363
|
479 |
// is >> std::ws;
|
deba@2363
|
480 |
// d *= x == '-' ? -1 : 1;
|
deba@2363
|
481 |
// while (is.get(x) && (x == '+' || x == '-')) {
|
deba@2363
|
482 |
// d *= x == '-' ? -1 : 1;
|
deba@2363
|
483 |
// is >> std::ws;
|
deba@2363
|
484 |
// }
|
deba@2363
|
485 |
// if (!is) throw DataFormatError("Cannot find lp element");
|
deba@2363
|
486 |
// }
|
deba@2363
|
487 |
// if (numFirstChar(x)) {
|
deba@2363
|
488 |
// is.putback(x);
|
deba@2363
|
489 |
// double e;
|
deba@2363
|
490 |
// writeNum(is, e);
|
deba@2363
|
491 |
// d *= e;
|
deba@2363
|
492 |
// } else if (varFirstChar(x)) {
|
deba@2363
|
493 |
// is.putback(x);
|
deba@2363
|
494 |
// LpSolverBase::Col f;
|
deba@2363
|
495 |
// writeCol(is, f);
|
deba@2363
|
496 |
// c = f;
|
deba@2363
|
497 |
// } else {
|
deba@2363
|
498 |
// throw DataFormatError("Invalid expression format");
|
deba@2363
|
499 |
// }
|
deba@2363
|
500 |
// is >> std::ws;
|
deba@2363
|
501 |
// while (is.get(y) && (y == '*' || y == '/')) {
|
deba@2363
|
502 |
// is >> std::ws;
|
deba@2363
|
503 |
// if (!is.get(x)) throw DataFormatError("Cannot find lp element");
|
deba@2363
|
504 |
// if (x == '+' || x == '-') {
|
deba@2363
|
505 |
// is >> std::ws;
|
deba@2363
|
506 |
// d *= x == '-' ? -1 : 1;
|
deba@2363
|
507 |
// while (is.get(x) && (x == '+' || x == '-')) {
|
deba@2363
|
508 |
// d *= x == '-' ? -1 : 1;
|
deba@2363
|
509 |
// is >> std::ws;
|
deba@2363
|
510 |
// }
|
deba@2363
|
511 |
// if (!is) throw DataFormatError("Cannot find lp element");
|
deba@2363
|
512 |
// }
|
deba@2363
|
513 |
// if (numFirstChar(x)) {
|
deba@2363
|
514 |
// is.putback(x);
|
deba@2363
|
515 |
// double e;
|
deba@2363
|
516 |
// writeNum(is, e);
|
deba@2363
|
517 |
// if (y == '*') {
|
deba@2363
|
518 |
// d *= e;
|
deba@2363
|
519 |
// } else {
|
deba@2363
|
520 |
// d /= e;
|
deba@2363
|
521 |
// }
|
deba@2363
|
522 |
// } else if (varFirstChar(x)) {
|
deba@2363
|
523 |
// is.putback(x);
|
deba@2363
|
524 |
// LpSolverBase::Col f;
|
deba@2363
|
525 |
// writeCol(is, f);
|
deba@2363
|
526 |
// if (y == '*') {
|
deba@2363
|
527 |
// if (c == INVALID) {
|
deba@2363
|
528 |
// c = f;
|
deba@2363
|
529 |
// } else {
|
deba@2363
|
530 |
// throw DataFormatError("Quadratic element in expression");
|
deba@2363
|
531 |
// }
|
deba@2363
|
532 |
// } else {
|
deba@2363
|
533 |
// throw DataFormatError("Division by variable");
|
deba@2363
|
534 |
// }
|
deba@2363
|
535 |
// } else {
|
deba@2363
|
536 |
// throw DataFormatError("Invalid expression format");
|
deba@2363
|
537 |
// }
|
deba@2363
|
538 |
// is >> std::ws;
|
deba@2363
|
539 |
// }
|
deba@2363
|
540 |
// if (!is) {
|
deba@2363
|
541 |
// is.clear();
|
deba@2363
|
542 |
// } else {
|
deba@2363
|
543 |
// is.putback(y);
|
deba@2363
|
544 |
// }
|
deba@2363
|
545 |
// return is;
|
deba@2363
|
546 |
// }
|
deba@2363
|
547 |
|
deba@2363
|
548 |
// std::ostream& writeCol(std::ostream& is, LpSolverBase::Col& c) {
|
deba@2363
|
549 |
// char x;
|
deba@2363
|
550 |
// std::string var;
|
deba@2363
|
551 |
// while (is.get(x) && varChar(x)) {
|
deba@2363
|
552 |
// var += x;
|
deba@2363
|
553 |
// }
|
deba@2363
|
554 |
// if (!is) {
|
deba@2363
|
555 |
// is.clear();
|
deba@2363
|
556 |
// } else {
|
deba@2363
|
557 |
// is.putback(x);
|
deba@2363
|
558 |
// }
|
deba@2363
|
559 |
// ColMap::const_iterator it = cols.find(var);
|
deba@2363
|
560 |
// if (cols.find(var) != cols.end()) {
|
deba@2363
|
561 |
// c = it->second;
|
deba@2363
|
562 |
// } else {
|
deba@2363
|
563 |
// c = lp.addCol();
|
deba@2363
|
564 |
// cols.insert(std::make_pair(var, c));
|
deba@2363
|
565 |
// lp.colName(c, var);
|
deba@2363
|
566 |
// }
|
deba@2363
|
567 |
// return is;
|
deba@2363
|
568 |
// }
|
deba@2363
|
569 |
|
deba@2363
|
570 |
// std::ostream& writeNum(std::ostream& is, double& d) {
|
deba@2363
|
571 |
// is >> d;
|
deba@2363
|
572 |
// if (!is) throw DataFormatError("Wrong number format");
|
deba@2363
|
573 |
// return is;
|
deba@2363
|
574 |
// }
|
deba@2363
|
575 |
|
deba@2363
|
576 |
// std::ostream& writeRelation(std::ostream& is, Relation& op) {
|
deba@2363
|
577 |
// char x, y;
|
deba@2363
|
578 |
// if (!is.get(x) || !(x == '<' || x == '=' || x == '>')) {
|
deba@2363
|
579 |
// throw DataFormatError("Wrong relation operator");
|
deba@2363
|
580 |
// }
|
deba@2363
|
581 |
// if (!is.get(y) || y != '=') {
|
deba@2363
|
582 |
// throw DataFormatError("Wrong relation operator");
|
deba@2363
|
583 |
// }
|
deba@2363
|
584 |
// switch (x) {
|
deba@2363
|
585 |
// case '<': op = LE;
|
deba@2363
|
586 |
// break;
|
deba@2363
|
587 |
// case '=': op = EQ;
|
deba@2363
|
588 |
// break;
|
deba@2363
|
589 |
// case '>': op = GE;
|
deba@2363
|
590 |
// break;
|
deba@2363
|
591 |
// }
|
deba@2363
|
592 |
// return is;
|
deba@2363
|
593 |
// }
|
deba@2363
|
594 |
|
deba@2363
|
595 |
// static bool relationFirstChar(char c) {
|
deba@2363
|
596 |
// return c == '<' || c == '=' || c == '>';
|
deba@2363
|
597 |
// }
|
deba@2363
|
598 |
|
deba@2363
|
599 |
// static bool varFirstChar(char c) {
|
deba@2363
|
600 |
// return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
deba@2363
|
601 |
// }
|
deba@2363
|
602 |
|
deba@2363
|
603 |
// static bool numFirstChar(char c) {
|
deba@2363
|
604 |
// return (c >= '0' && c <= '9') || c == '.';
|
deba@2363
|
605 |
// }
|
deba@2363
|
606 |
|
deba@2363
|
607 |
// static bool varChar(char c) {
|
deba@2363
|
608 |
// return (c >= '0' && c <= '9') ||
|
deba@2363
|
609 |
// (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
deba@2363
|
610 |
// }
|
deba@2363
|
611 |
|
deba@2363
|
612 |
|
deba@2363
|
613 |
// void addConstraint(const LpSolverBase::Constr& constr) {
|
deba@2363
|
614 |
// if (constr.expr().size() != 1) {
|
deba@2363
|
615 |
// lp.addRow(constr);
|
deba@2363
|
616 |
// } else {
|
deba@2363
|
617 |
// Lp::Expr e = constr.expr();
|
deba@2363
|
618 |
// LpSolverBase::Col col = e.begin()->first;
|
deba@2363
|
619 |
// double coeff = e.begin()->second;
|
deba@2363
|
620 |
// double lb = LpSolverBase::NaN;
|
deba@2363
|
621 |
// double ub = LpSolverBase::NaN;
|
deba@2363
|
622 |
// if (coeff > 0) {
|
deba@2363
|
623 |
// if (constr.upperBounded()) {
|
deba@2363
|
624 |
// lb = (constr.lowerBound() - e.constComp()) / coeff;
|
deba@2363
|
625 |
// }
|
deba@2363
|
626 |
// if (constr.lowerBounded()) {
|
deba@2363
|
627 |
// ub = (constr.upperBound() - e.constComp()) / coeff;
|
deba@2363
|
628 |
// }
|
deba@2363
|
629 |
// } else if (coeff < 0) {
|
deba@2363
|
630 |
// if (constr.upperBounded()) {
|
deba@2363
|
631 |
// lb = (constr.upperBound() - e.constComp()) / coeff;
|
deba@2363
|
632 |
// }
|
deba@2363
|
633 |
// if (constr.lowerBounded()) {
|
deba@2363
|
634 |
// ub = (constr.lowerBound() - e.constComp()) / coeff;
|
deba@2363
|
635 |
// }
|
deba@2363
|
636 |
// } else {
|
deba@2363
|
637 |
// lb = -LpSolverBase::INF;
|
deba@2363
|
638 |
// ub = LpSolverBase::INF;
|
deba@2363
|
639 |
// }
|
deba@2363
|
640 |
// lp.colLowerBound(col, lb);
|
deba@2363
|
641 |
// lp.colUpperBound(col, ub);
|
deba@2363
|
642 |
// }
|
deba@2363
|
643 |
// }
|
deba@2363
|
644 |
|
deba@2363
|
645 |
// protected:
|
deba@2363
|
646 |
|
deba@2363
|
647 |
// /// \brief Writer function of the section.
|
deba@2363
|
648 |
// ///
|
deba@2363
|
649 |
// /// It writes the content of the section.
|
deba@2363
|
650 |
// virtual void write(std::ostream& is) {
|
deba@2363
|
651 |
// std::string line;
|
deba@2363
|
652 |
// std::map<std::string, LpSolverBase::Col> vars;
|
deba@2363
|
653 |
// while (getline(is, line)) {
|
deba@2363
|
654 |
// std::istringstream ls(line);
|
deba@2363
|
655 |
// std::string sense;
|
deba@2363
|
656 |
// ls >> sense;
|
deba@2363
|
657 |
// if (sense == "min" || sense == "max") {
|
deba@2363
|
658 |
// LpSolverBase::Expr expr;
|
deba@2363
|
659 |
// ls >> std::ws;
|
deba@2363
|
660 |
// writeExpression(ls, expr);
|
deba@2363
|
661 |
// lp.setObj(expr);
|
deba@2363
|
662 |
// if (sense == "min") {
|
deba@2363
|
663 |
// lp.min();
|
deba@2363
|
664 |
// } else {
|
deba@2363
|
665 |
// lp.max();
|
deba@2363
|
666 |
// }
|
deba@2363
|
667 |
// } else {
|
deba@2363
|
668 |
// ls.str(line);
|
deba@2363
|
669 |
// LpSolverBase::Constr constr;
|
deba@2363
|
670 |
// ls >> std::ws;
|
deba@2363
|
671 |
// writeConstraint(ls, constr);
|
deba@2363
|
672 |
// addConstraint(constr);
|
deba@2363
|
673 |
// }
|
deba@2363
|
674 |
// }
|
deba@2363
|
675 |
// }
|
deba@2363
|
676 |
|
deba@2363
|
677 |
// virtual void missing() {
|
deba@2363
|
678 |
// ErrorMessage msg;
|
deba@2363
|
679 |
// msg << "Lp section not found in file: @lp " << name;
|
deba@2363
|
680 |
// throw IoParameterError(msg.message());
|
deba@2363
|
681 |
// }
|
deba@2363
|
682 |
|
deba@2363
|
683 |
// private:
|
deba@2363
|
684 |
|
deba@2363
|
685 |
// typedef std::map<std::string, LpSolverBase::Col> ColMap;
|
deba@2363
|
686 |
|
deba@2363
|
687 |
// LpSolverBase& lp;
|
deba@2363
|
688 |
// std::string name;
|
deba@2363
|
689 |
// ColMap cols;
|
deba@2363
|
690 |
// };
|
deba@2363
|
691 |
|
deba@2316
|
692 |
}
|
deba@2316
|
693 |
|
deba@2316
|
694 |
#endif
|