5
18
4
437
179
22
19
1229
854
698
472
181
38
781
473
176
56
82
135
108
62
207
100
61
30
Changeset was too big and was cut off... Show full diff
1 |
/* -*- mode: C++; indent-tabs-mode: nil; -*- |
|
2 |
* |
|
3 |
* This file is a part of LEMON, a generic C++ optimization library. |
|
4 |
* |
|
5 |
* Copyright (C) 2003-2008 |
|
6 |
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
|
7 |
* (Egervary Research Group on Combinatorial Optimization, EGRES). |
|
8 |
* |
|
9 |
* Permission to use, modify and distribute this software is granted |
|
10 |
* provided that this copyright notice appears in all copies. For |
|
11 |
* precise terms see the accompanying LICENSE file. |
|
12 |
* |
|
13 |
* This software is provided "AS IS" with no warranty of any kind, |
|
14 |
* express or implied, and with no claim as to its suitability for any |
|
15 |
* purpose. |
|
16 |
* |
|
17 |
*/ |
|
18 |
|
|
19 |
#ifndef LEMON_BITS_SOLVER_BITS_H |
|
20 |
#define LEMON_BITS_SOLVER_BITS_H |
|
21 |
|
|
22 |
namespace lemon { |
|
23 |
|
|
24 |
namespace _solver_bits { |
|
25 |
|
|
26 |
class VarIndex { |
|
27 |
private: |
|
28 |
struct ItemT { |
|
29 |
int prev, next; |
|
30 |
int index; |
|
31 |
}; |
|
32 |
std::vector<ItemT> items; |
|
33 |
int first_item, last_item, first_free_item; |
|
34 |
|
|
35 |
std::vector<int> cross; |
|
36 |
|
|
37 |
public: |
|
38 |
|
|
39 |
VarIndex() |
|
40 |
: first_item(-1), last_item(-1), first_free_item(-1) { |
|
41 |
} |
|
42 |
|
|
43 |
void clear() { |
|
44 |
first_item = -1; |
|
45 |
first_free_item = -1; |
|
46 |
items.clear(); |
|
47 |
cross.clear(); |
|
48 |
} |
|
49 |
|
|
50 |
int addIndex(int idx) { |
|
51 |
int n; |
|
52 |
if (first_free_item == -1) { |
|
53 |
n = items.size(); |
|
54 |
items.push_back(ItemT()); |
|
55 |
} else { |
|
56 |
n = first_free_item; |
|
57 |
first_free_item = items[n].next; |
|
58 |
if (first_free_item != -1) { |
|
59 |
items[first_free_item].prev = -1; |
|
60 |
} |
|
61 |
} |
|
62 |
items[n].index = idx; |
|
63 |
if (static_cast<int>(cross.size()) <= idx) { |
|
64 |
cross.resize(idx + 1, -1); |
|
65 |
} |
|
66 |
cross[idx] = n; |
|
67 |
|
|
68 |
items[n].prev = last_item; |
|
69 |
items[n].next = -1; |
|
70 |
if (last_item != -1) { |
|
71 |
items[last_item].next = n; |
|
72 |
} else { |
|
73 |
first_item = n; |
|
74 |
} |
|
75 |
last_item = n; |
|
76 |
|
|
77 |
return n; |
|
78 |
} |
|
79 |
|
|
80 |
int addIndex(int idx, int n) { |
|
81 |
while (n >= static_cast<int>(items.size())) { |
|
82 |
items.push_back(ItemT()); |
|
83 |
items.back().prev = -1; |
|
84 |
items.back().next = first_free_item; |
|
85 |
if (first_free_item != -1) { |
|
86 |
items[first_free_item].prev = items.size() - 1; |
|
87 |
} |
|
88 |
first_free_item = items.size() - 1; |
|
89 |
} |
|
90 |
if (items[n].next != -1) { |
|
91 |
items[items[n].next].prev = items[n].prev; |
|
92 |
} |
|
93 |
if (items[n].prev != -1) { |
|
94 |
items[items[n].prev].next = items[n].next; |
|
95 |
} else { |
|
96 |
first_free_item = items[n].next; |
|
97 |
} |
|
98 |
|
|
99 |
items[n].index = idx; |
|
100 |
if (static_cast<int>(cross.size()) <= idx) { |
|
101 |
cross.resize(idx + 1, -1); |
|
102 |
} |
|
103 |
cross[idx] = n; |
|
104 |
|
|
105 |
items[n].prev = last_item; |
|
106 |
items[n].next = -1; |
|
107 |
if (last_item != -1) { |
|
108 |
items[last_item].next = n; |
|
109 |
} else { |
|
110 |
first_item = n; |
|
111 |
} |
|
112 |
last_item = n; |
|
113 |
|
|
114 |
return n; |
|
115 |
} |
|
116 |
|
|
117 |
void eraseIndex(int idx) { |
|
118 |
int n = cross[idx]; |
|
119 |
|
|
120 |
if (items[n].prev != -1) { |
|
121 |
items[items[n].prev].next = items[n].next; |
|
122 |
} else { |
|
123 |
first_item = items[n].next; |
|
124 |
} |
|
125 |
if (items[n].next != -1) { |
|
126 |
items[items[n].next].prev = items[n].prev; |
|
127 |
} else { |
|
128 |
last_item = items[n].prev; |
|
129 |
} |
|
130 |
|
|
131 |
if (first_free_item != -1) { |
|
132 |
items[first_free_item].prev = n; |
|
133 |
} |
|
134 |
items[n].next = first_free_item; |
|
135 |
items[n].prev = -1; |
|
136 |
first_free_item = n; |
|
137 |
|
|
138 |
while (!cross.empty() && cross.back() == -1) { |
|
139 |
cross.pop_back(); |
|
140 |
} |
|
141 |
} |
|
142 |
|
|
143 |
int maxIndex() const { |
|
144 |
return cross.size() - 1; |
|
145 |
} |
|
146 |
|
|
147 |
void shiftIndices(int idx) { |
|
148 |
for (int i = idx + 1; i < static_cast<int>(cross.size()); ++i) { |
|
149 |
cross[i - 1] = cross[i]; |
|
150 |
if (cross[i] != -1) { |
|
151 |
--items[cross[i]].index; |
|
152 |
} |
|
153 |
} |
|
154 |
cross.back() = -1; |
|
155 |
cross.pop_back(); |
|
156 |
while (!cross.empty() && cross.back() == -1) { |
|
157 |
cross.pop_back(); |
|
158 |
} |
|
159 |
} |
|
160 |
|
|
161 |
void relocateIndex(int idx, int jdx) { |
|
162 |
cross[idx] = cross[jdx]; |
|
163 |
items[cross[jdx]].index = idx; |
|
164 |
cross[jdx] = -1; |
|
165 |
|
|
166 |
while (!cross.empty() && cross.back() == -1) { |
|
167 |
cross.pop_back(); |
|
168 |
} |
|
169 |
} |
|
170 |
|
|
171 |
int operator[](int idx) const { |
|
172 |
return cross[idx]; |
|
173 |
} |
|
174 |
|
|
175 |
int operator()(int fdx) const { |
|
176 |
return items[fdx].index; |
|
177 |
} |
|
178 |
|
|
179 |
void firstItem(int& fdx) const { |
|
180 |
fdx = first_item; |
|
181 |
} |
|
182 |
|
|
183 |
void nextItem(int& fdx) const { |
|
184 |
fdx = items[fdx].next; |
|
185 |
} |
|
186 |
|
|
187 |
}; |
|
188 |
} |
|
189 |
} |
|
190 |
|
|
191 |
#endif |
1 |
/* -*- mode: C++; indent-tabs-mode: nil; -*- |
|
2 |
* |
|
3 |
* This file is a part of LEMON, a generic C++ optimization library. |
|
4 |
* |
|
5 |
* Copyright (C) 2003-2008 |
|
6 |
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
|
7 |
* (Egervary Research Group on Combinatorial Optimization, EGRES). |
|
8 |
* |
|
9 |
* Permission to use, modify and distribute this software is granted |
|
10 |
* provided that this copyright notice appears in all copies. For |
|
11 |
* precise terms see the accompanying LICENSE file. |
|
12 |
* |
|
13 |
* This software is provided "AS IS" with no warranty of any kind, |
|
14 |
* express or implied, and with no claim as to its suitability for any |
|
15 |
* purpose. |
|
16 |
* |
|
17 |
*/ |
|
18 |
|
|
19 |
#include <lemon/lp_clp.h> |
|
20 |
#include <coin/ClpSimplex.hpp> |
|
21 |
|
|
22 |
namespace lemon { |
|
23 |
|
|
24 |
LpClp::LpClp() { |
|
25 |
_prob = new ClpSimplex(); |
|
26 |
_init_temporals(); |
|
27 |
messageLevel(MESSAGE_NO_OUTPUT); |
|
28 |
} |
|
29 |
|
|
30 |
LpClp::LpClp(const LpClp& other) { |
|
31 |
_prob = new ClpSimplex(*other._prob); |
|
32 |
rows = other.rows; |
|
33 |
cols = other.cols; |
|
34 |
_init_temporals(); |
|
35 |
messageLevel(MESSAGE_NO_OUTPUT); |
|
36 |
} |
|
37 |
|
|
38 |
LpClp::~LpClp() { |
|
39 |
delete _prob; |
|
40 |
_clear_temporals(); |
|
41 |
} |
|
42 |
|
|
43 |
void LpClp::_init_temporals() { |
|
44 |
_primal_ray = 0; |
|
45 |
_dual_ray = 0; |
|
46 |
} |
|
47 |
|
|
48 |
void LpClp::_clear_temporals() { |
|
49 |
if (_primal_ray) { |
|
50 |
delete[] _primal_ray; |
|
51 |
_primal_ray = 0; |
|
52 |
} |
|
53 |
if (_dual_ray) { |
|
54 |
delete[] _dual_ray; |
|
55 |
_dual_ray = 0; |
|
56 |
} |
|
57 |
} |
|
58 |
|
|
59 |
LpClp* LpClp::_newSolver() const { |
|
60 |
LpClp* newlp = new LpClp; |
|
61 |
return newlp; |
|
62 |
} |
|
63 |
|
|
64 |
LpClp* LpClp::_cloneSolver() const { |
|
65 |
LpClp* copylp = new LpClp(*this); |
|
66 |
return copylp; |
|
67 |
} |
|
68 |
|
|
69 |
const char* LpClp::_solverName() const { return "LpClp"; } |
|
70 |
|
|
71 |
int LpClp::_addCol() { |
|
72 |
_prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0); |
|
73 |
return _prob->numberColumns() - 1; |
|
74 |
} |
|
75 |
|
|
76 |
int LpClp::_addRow() { |
|
77 |
_prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX); |
|
78 |
return _prob->numberRows() - 1; |
|
79 |
} |
|
80 |
|
|
81 |
|
|
82 |
void LpClp::_eraseCol(int c) { |
|
83 |
_col_names_ref.erase(_prob->getColumnName(c)); |
|
84 |
_prob->deleteColumns(1, &c); |
|
85 |
} |
|
86 |
|
|
87 |
void LpClp::_eraseRow(int r) { |
|
88 |
_row_names_ref.erase(_prob->getRowName(r)); |
|
89 |
_prob->deleteRows(1, &r); |
|
90 |
} |
|
91 |
|
|
92 |
void LpClp::_eraseColId(int i) { |
|
93 |
cols.eraseIndex(i); |
|
94 |
cols.shiftIndices(i); |
|
95 |
} |
|
96 |
|
|
97 |
void LpClp::_eraseRowId(int i) { |
|
98 |
rows.eraseIndex(i); |
|
99 |
rows.shiftIndices(i); |
|
100 |
} |
|
101 |
|
|
102 |
void LpClp::_getColName(int c, std::string& name) const { |
|
103 |
name = _prob->getColumnName(c); |
|
104 |
} |
|
105 |
|
|
106 |
void LpClp::_setColName(int c, const std::string& name) { |
|
107 |
_prob->setColumnName(c, const_cast<std::string&>(name)); |
|
108 |
_col_names_ref[name] = c; |
|
109 |
} |
|
110 |
|
|
111 |
int LpClp::_colByName(const std::string& name) const { |
|
112 |
std::map<std::string, int>::const_iterator it = _col_names_ref.find(name); |
|
113 |
return it != _col_names_ref.end() ? it->second : -1; |
|
114 |
} |
|
115 |
|
|
116 |
void LpClp::_getRowName(int r, std::string& name) const { |
|
117 |
name = _prob->getRowName(r); |
|
118 |
} |
|
119 |
|
|
120 |
void LpClp::_setRowName(int r, const std::string& name) { |
|
121 |
_prob->setRowName(r, const_cast<std::string&>(name)); |
|
122 |
_row_names_ref[name] = r; |
|
123 |
} |
|
124 |
|
|
125 |
int LpClp::_rowByName(const std::string& name) const { |
|
126 |
std::map<std::string, int>::const_iterator it = _row_names_ref.find(name); |
|
127 |
return it != _row_names_ref.end() ? it->second : -1; |
|
128 |
} |
|
129 |
|
|
130 |
|
|
131 |
void LpClp::_setRowCoeffs(int ix, ExprIterator b, ExprIterator e) { |
|
132 |
std::map<int, Value> coeffs; |
|
133 |
|
|
134 |
int n = _prob->clpMatrix()->getNumCols(); |
|
135 |
|
|
136 |
const int* indices = _prob->clpMatrix()->getIndices(); |
|
137 |
const double* elements = _prob->clpMatrix()->getElements(); |
|
138 |
|
|
139 |
for (int i = 0; i < n; ++i) { |
|
140 |
CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i]; |
|
141 |
CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i]; |
|
142 |
|
|
143 |
const int* it = std::lower_bound(indices + begin, indices + end, ix); |
|
144 |
if (it != indices + end && *it == ix && elements[it - indices] != 0.0) { |
|
145 |
coeffs[i] = 0.0; |
|
146 |
} |
|
147 |
} |
|
148 |
|
|
149 |
for (ExprIterator it = b; it != e; ++it) { |
|
150 |
coeffs[it->first] = it->second; |
|
151 |
} |
|
152 |
|
|
153 |
for (std::map<int, Value>::iterator it = coeffs.begin(); |
|
154 |
it != coeffs.end(); ++it) { |
|
155 |
_prob->modifyCoefficient(ix, it->first, it->second); |
|
156 |
} |
|
157 |
} |
|
158 |
|
|
159 |
void LpClp::_getRowCoeffs(int ix, InsertIterator b) const { |
|
160 |
int n = _prob->clpMatrix()->getNumCols(); |
|
161 |
|
|
162 |
const int* indices = _prob->clpMatrix()->getIndices(); |
|
163 |
const double* elements = _prob->clpMatrix()->getElements(); |
|
164 |
|
|
165 |
for (int i = 0; i < n; ++i) { |
|
166 |
CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i]; |
|
167 |
CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i]; |
|
168 |
|
|
169 |
const int* it = std::lower_bound(indices + begin, indices + end, ix); |
|
170 |
if (it != indices + end && *it == ix) { |
|
171 |
*b = std::make_pair(i, elements[it - indices]); |
|
172 |
} |
|
173 |
} |
|
174 |
} |
|
175 |
|
|
176 |
void LpClp::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) { |
|
177 |
std::map<int, Value> coeffs; |
|
178 |
|
|
179 |
CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix]; |
|
180 |
CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix]; |
|
181 |
|
|
182 |
const int* indices = _prob->clpMatrix()->getIndices(); |
|
183 |
const double* elements = _prob->clpMatrix()->getElements(); |
|
184 |
|
|
185 |
for (CoinBigIndex i = begin; i != end; ++i) { |
|
186 |
if (elements[i] != 0.0) { |
|
187 |
coeffs[indices[i]] = 0.0; |
|
188 |
} |
|
189 |
} |
|
190 |
for (ExprIterator it = b; it != e; ++it) { |
|
191 |
coeffs[it->first] = it->second; |
|
192 |
} |
|
193 |
for (std::map<int, Value>::iterator it = coeffs.begin(); |
|
194 |
it != coeffs.end(); ++it) { |
|
195 |
_prob->modifyCoefficient(it->first, ix, it->second); |
|
196 |
} |
|
197 |
} |
|
198 |
|
|
199 |
void LpClp::_getColCoeffs(int ix, InsertIterator b) const { |
|
200 |
CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix]; |
|
201 |
CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix]; |
|
202 |
|
|
203 |
const int* indices = _prob->clpMatrix()->getIndices(); |
|
204 |
const double* elements = _prob->clpMatrix()->getElements(); |
|
205 |
|
|
206 |
for (CoinBigIndex i = begin; i != end; ++i) { |
|
207 |
*b = std::make_pair(indices[i], elements[i]); |
|
208 |
++b; |
|
209 |
} |
|
210 |
} |
|
211 |
|
|
212 |
void LpClp::_setCoeff(int ix, int jx, Value value) { |
|
213 |
_prob->modifyCoefficient(ix, jx, value); |
|
214 |
} |
|
215 |
|
|
216 |
LpClp::Value LpClp::_getCoeff(int ix, int jx) const { |
|
217 |
CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix]; |
|
218 |
CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix]; |
|
219 |
|
|
220 |
const int* indices = _prob->clpMatrix()->getIndices(); |
|
221 |
const double* elements = _prob->clpMatrix()->getElements(); |
|
222 |
|
|
223 |
const int* it = std::lower_bound(indices + begin, indices + end, jx); |
|
224 |
if (it != indices + end && *it == jx) { |
|
225 |
return elements[it - indices]; |
|
226 |
} else { |
|
227 |
return 0.0; |
|
228 |
} |
|
229 |
} |
|
230 |
|
|
231 |
void LpClp::_setColLowerBound(int i, Value lo) { |
|
232 |
_prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo); |
|
233 |
} |
|
234 |
|
|
235 |
LpClp::Value LpClp::_getColLowerBound(int i) const { |
|
236 |
double val = _prob->getColLower()[i]; |
|
237 |
return val == - COIN_DBL_MAX ? - INF : val; |
|
238 |
} |
|
239 |
|
|
240 |
void LpClp::_setColUpperBound(int i, Value up) { |
|
241 |
_prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up); |
|
242 |
} |
|
243 |
|
|
244 |
LpClp::Value LpClp::_getColUpperBound(int i) const { |
|
245 |
double val = _prob->getColUpper()[i]; |
|
246 |
return val == COIN_DBL_MAX ? INF : val; |
|
247 |
} |
|
248 |
|
|
249 |
void LpClp::_setRowLowerBound(int i, Value lo) { |
|
250 |
_prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo); |
|
251 |
} |
|
252 |
|
|
253 |
LpClp::Value LpClp::_getRowLowerBound(int i) const { |
|
254 |
double val = _prob->getRowLower()[i]; |
|
255 |
return val == - COIN_DBL_MAX ? - INF : val; |
|
256 |
} |
|
257 |
|
|
258 |
void LpClp::_setRowUpperBound(int i, Value up) { |
|
259 |
_prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up); |
|
260 |
} |
|
261 |
|
|
262 |
LpClp::Value LpClp::_getRowUpperBound(int i) const { |
|
263 |
double val = _prob->getRowUpper()[i]; |
|
264 |
return val == COIN_DBL_MAX ? INF : val; |
|
265 |
} |
|
266 |
|
|
267 |
void LpClp::_setObjCoeffs(ExprIterator b, ExprIterator e) { |
|
268 |
int num = _prob->clpMatrix()->getNumCols(); |
|
269 |
for (int i = 0; i < num; ++i) { |
|
270 |
_prob->setObjectiveCoefficient(i, 0.0); |
|
271 |
} |
|
272 |
for (ExprIterator it = b; it != e; ++it) { |
|
273 |
_prob->setObjectiveCoefficient(it->first, it->second); |
|
274 |
} |
|
275 |
} |
|
276 |
|
|
277 |
void LpClp::_getObjCoeffs(InsertIterator b) const { |
|
278 |
int num = _prob->clpMatrix()->getNumCols(); |
|
279 |
for (int i = 0; i < num; ++i) { |
|
280 |
Value coef = _prob->getObjCoefficients()[i]; |
|
281 |
if (coef != 0.0) { |
|
282 |
*b = std::make_pair(i, coef); |
|
283 |
++b; |
|
284 |
} |
|
285 |
} |
|
286 |
} |
|
287 |
|
|
288 |
void LpClp::_setObjCoeff(int i, Value obj_coef) { |
|
289 |
_prob->setObjectiveCoefficient(i, obj_coef); |
|
290 |
} |
|
291 |
|
|
292 |
LpClp::Value LpClp::_getObjCoeff(int i) const { |
|
293 |
return _prob->getObjCoefficients()[i]; |
|
294 |
} |
|
295 |
|
|
296 |
LpClp::SolveExitStatus LpClp::_solve() { |
|
297 |
return _prob->primal() >= 0 ? SOLVED : UNSOLVED; |
|
298 |
} |
|
299 |
|
|
300 |
LpClp::SolveExitStatus LpClp::solvePrimal() { |
|
301 |
return _prob->primal() >= 0 ? SOLVED : UNSOLVED; |
|
302 |
} |
|
303 |
|
|
304 |
LpClp::SolveExitStatus LpClp::solveDual() { |
|
305 |
return _prob->dual() >= 0 ? SOLVED : UNSOLVED; |
|
306 |
} |
|
307 |
|
|
308 |
LpClp::SolveExitStatus LpClp::solveBarrier() { |
|
309 |
return _prob->barrier() >= 0 ? SOLVED : UNSOLVED; |
|
310 |
} |
|
311 |
|
|
312 |
LpClp::Value LpClp::_getPrimal(int i) const { |
|
313 |
return _prob->primalColumnSolution()[i]; |
|
314 |
} |
|
315 |
LpClp::Value LpClp::_getPrimalValue() const { |
|
316 |
return _prob->objectiveValue(); |
|
317 |
} |
|
318 |
|
|
319 |
LpClp::Value LpClp::_getDual(int i) const { |
|
320 |
return _prob->dualRowSolution()[i]; |
|
321 |
} |
|
322 |
|
|
323 |
LpClp::Value LpClp::_getPrimalRay(int i) const { |
|
324 |
if (!_primal_ray) { |
|
325 |
_primal_ray = _prob->unboundedRay(); |
|
326 |
LEMON_ASSERT(_primal_ray != 0, "Primal ray is not provided"); |
|
327 |
} |
|
328 |
return _primal_ray[i]; |
|
329 |
} |
|
330 |
|
|
331 |
LpClp::Value LpClp::_getDualRay(int i) const { |
|
332 |
if (!_dual_ray) { |
|
333 |
_dual_ray = _prob->infeasibilityRay(); |
|
334 |
LEMON_ASSERT(_dual_ray != 0, "Dual ray is not provided"); |
|
335 |
} |
|
336 |
return _dual_ray[i]; |
|
337 |
} |
|
338 |
|
|
339 |
LpClp::VarStatus LpClp::_getColStatus(int i) const { |
|
340 |
switch (_prob->getColumnStatus(i)) { |
|
341 |
case ClpSimplex::basic: |
|
342 |
return BASIC; |
|
343 |
case ClpSimplex::isFree: |
|
344 |
return FREE; |
|
345 |
case ClpSimplex::atUpperBound: |
|
346 |
return UPPER; |
|
347 |
case ClpSimplex::atLowerBound: |
|
348 |
return LOWER; |
|
349 |
case ClpSimplex::isFixed: |
|
350 |
return FIXED; |
|
351 |
case ClpSimplex::superBasic: |
|
352 |
return FREE; |
|
353 |
default: |
|
354 |
LEMON_ASSERT(false, "Wrong column status"); |
|
355 |
return VarStatus(); |
|
356 |
} |
|
357 |
} |
|
358 |
|
|
359 |
LpClp::VarStatus LpClp::_getRowStatus(int i) const { |
|
360 |
switch (_prob->getColumnStatus(i)) { |
|
361 |
case ClpSimplex::basic: |
|
362 |
return BASIC; |
|
363 |
case ClpSimplex::isFree: |
|
364 |
return FREE; |
|
365 |
case ClpSimplex::atUpperBound: |
|
366 |
return UPPER; |
|
367 |
case ClpSimplex::atLowerBound: |
|
368 |
return LOWER; |
|
369 |
case ClpSimplex::isFixed: |
|
370 |
return FIXED; |
|
371 |
case ClpSimplex::superBasic: |
|
372 |
return FREE; |
|
373 |
default: |
|
374 |
LEMON_ASSERT(false, "Wrong row status"); |
|
375 |
return VarStatus(); |
|
376 |
} |
|
377 |
} |
|
378 |
|
|
379 |
|
|
380 |
LpClp::ProblemType LpClp::_getPrimalType() const { |
|
381 |
if (_prob->isProvenOptimal()) { |
|
382 |
return OPTIMAL; |
|
383 |
} else if (_prob->isProvenPrimalInfeasible()) { |
|
384 |
return INFEASIBLE; |
|
385 |
} else if (_prob->isProvenDualInfeasible()) { |
|
386 |
return UNBOUNDED; |
|
387 |
} else { |
|
388 |
return UNDEFINED; |
|
389 |
} |
|
390 |
} |
|
391 |
|
|
392 |
LpClp::ProblemType LpClp::_getDualType() const { |
|
393 |
if (_prob->isProvenOptimal()) { |
|
394 |
return OPTIMAL; |
|
395 |
} else if (_prob->isProvenDualInfeasible()) { |
|
396 |
return INFEASIBLE; |
|
397 |
} else if (_prob->isProvenPrimalInfeasible()) { |
|
398 |
return INFEASIBLE; |
|
399 |
} else { |
|
400 |
return UNDEFINED; |
|
401 |
} |
|
402 |
} |
|
403 |
|
|
404 |
void LpClp::_setSense(LpClp::Sense sense) { |
|
405 |
switch (sense) { |
|
406 |
case MIN: |
|
407 |
_prob->setOptimizationDirection(1); |
|
408 |
break; |
|
409 |
case MAX: |
|
410 |
_prob->setOptimizationDirection(-1); |
|
411 |
break; |
|
412 |
} |
|
413 |
} |
|
414 |
|
|
415 |
LpClp::Sense LpClp::_getSense() const { |
|
416 |
double dir = _prob->optimizationDirection(); |
|
417 |
if (dir > 0.0) { |
|
418 |
return MIN; |
|
419 |
} else { |
|
420 |
return MAX; |
|
421 |
} |
|
422 |
} |
|
423 |
|
|
424 |
void LpClp::_clear() { |
|
425 |
delete _prob; |
|
426 |
_prob = new ClpSimplex(); |
|
427 |
rows.clear(); |
|
428 |
cols.clear(); |
|
429 |
_col_names_ref.clear(); |
|
430 |
_clear_temporals(); |
|
431 |
} |
|
432 |
|
|
433 |
void LpClp::messageLevel(MessageLevel m) { |
|
434 |
_prob->setLogLevel(static_cast<int>(m)); |
|
435 |
} |
|
436 |
|
|
437 |
} //END OF NAMESPACE LEMON |
1 |
/* -*- mode: C++; indent-tabs-mode: nil; -*- |
|
2 |
* |
|
3 |
* This file is a part of LEMON, a generic C++ optimization library. |
|
4 |
* |
|
5 |
* Copyright (C) 2003-2008 |
|
6 |
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
|
7 |
* (Egervary Research Group on Combinatorial Optimization, EGRES). |
|
8 |
* |
|
9 |
* Permission to use, modify and distribute this software is granted |
|
10 |
* provided that this copyright notice appears in all copies. For |
|
11 |
* precise terms see the accompanying LICENSE file. |
|
12 |
* |
|
13 |
* This software is provided "AS IS" with no warranty of any kind, |
|
14 |
* express or implied, and with no claim as to its suitability for any |
|
15 |
* purpose. |
|
16 |
* |
|
17 |
*/ |
|
18 |
|
|
19 |
#ifndef LEMON_LP_CLP_H |
|
20 |
#define LEMON_LP_CLP_H |
|
21 |
|
|
22 |
///\file |
|
23 |
///\brief Header of the LEMON-CLP lp solver interface. |
|
24 |
|
|
25 |
#include <vector> |
|
26 |
#include <string> |
|
27 |
|
|
28 |
#include <lemon/lp_base.h> |
|
29 |
|
|
30 |
class ClpSimplex; |
|
31 |
|
|
32 |
namespace lemon { |
|
33 |
|
|
34 |
/// \ingroup lp_group |
|
35 |
/// |
|
36 |
/// \brief Interface for the CLP solver |
|
37 |
/// |
|
38 |
/// This class implements an interface for the Clp LP solver. The |
|
39 |
/// Clp library is an object oriented lp solver library developed at |
|
40 |
/// the IBM. The CLP is part of the COIN-OR package and it can be |
|
41 |
/// used with Common Public License. |
|
42 |
class LpClp : public LpSolver { |
|
43 |
protected: |
|
44 |
|
|
45 |
ClpSimplex* _prob; |
|
46 |
|
|
47 |
std::map<std::string, int> _col_names_ref; |
|
48 |
std::map<std::string, int> _row_names_ref; |
|
49 |
|
|
50 |
public: |
|
51 |
|
|
52 |
/// \e |
|
53 |
LpClp(); |
|
54 |
/// \e |
|
55 |
LpClp(const LpClp&); |
|
56 |
/// \e |
|
57 |
~LpClp(); |
|
58 |
|
|
59 |
protected: |
|
60 |
|
|
61 |
mutable double* _primal_ray; |
|
62 |
mutable double* _dual_ray; |
|
63 |
|
|
64 |
void _init_temporals(); |
|
65 |
void _clear_temporals(); |
|
66 |
|
|
67 |
protected: |
|
68 |
|
|
69 |
virtual LpClp* _newSolver() const; |
|
70 |
virtual LpClp* _cloneSolver() const; |
|
71 |
|
|
72 |
virtual const char* _solverName() const; |
|
73 |
|
|
74 |
virtual int _addCol(); |
|
75 |
virtual int _addRow(); |
|
76 |
|
|
77 |
virtual void _eraseCol(int i); |
|
78 |
virtual void _eraseRow(int i); |
|
79 |
|
|
80 |
virtual void _eraseColId(int i); |
|
81 |
virtual void _eraseRowId(int i); |
|
82 |
|
|
83 |
virtual void _getColName(int col, std::string& name) const; |
|
84 |
virtual void _setColName(int col, const std::string& name); |
|
85 |
virtual int _colByName(const std::string& name) const; |
|
86 |
|
|
87 |
virtual void _getRowName(int row, std::string& name) const; |
|
88 |
virtual void _setRowName(int row, const std::string& name); |
|
89 |
virtual int _rowByName(const std::string& name) const; |
|
90 |
|
|
91 |
virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); |
|
92 |
virtual void _getRowCoeffs(int i, InsertIterator b) const; |
|
93 |
|
|
94 |
virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); |
|
95 |
virtual void _getColCoeffs(int i, InsertIterator b) const; |
|
96 |
|
|
97 |
virtual void _setCoeff(int row, int col, Value value); |
|
98 |
virtual Value _getCoeff(int row, int col) const; |
|
99 |
|
|
100 |
virtual void _setColLowerBound(int i, Value value); |
|
101 |
virtual Value _getColLowerBound(int i) const; |
|
102 |
virtual void _setColUpperBound(int i, Value value); |
|
103 |
virtual Value _getColUpperBound(int i) const; |
|
104 |
|
|
105 |
virtual void _setRowLowerBound(int i, Value value); |
|
106 |
virtual Value _getRowLowerBound(int i) const; |
|
107 |
virtual void _setRowUpperBound(int i, Value value); |
|
108 |
virtual Value _getRowUpperBound(int i) const; |
|
109 |
|
|
110 |
virtual void _setObjCoeffs(ExprIterator, ExprIterator); |
|
111 |
virtual void _getObjCoeffs(InsertIterator) const; |
|
112 |
|
|
113 |
virtual void _setObjCoeff(int i, Value obj_coef); |
|
114 |
virtual Value _getObjCoeff(int i) const; |
|
115 |
|
|
116 |
virtual void _setSense(Sense sense); |
|
117 |
virtual Sense _getSense() const; |
|
118 |
|
|
119 |
virtual SolveExitStatus _solve(); |
|
120 |
|
|
121 |
virtual Value _getPrimal(int i) const; |
|
122 |
virtual Value _getDual(int i) const; |
|
123 |
|
|
124 |
virtual Value _getPrimalValue() const; |
|
125 |
|
|
126 |
virtual Value _getPrimalRay(int i) const; |
|
127 |
virtual Value _getDualRay(int i) const; |
|
128 |
|
|
129 |
virtual VarStatus _getColStatus(int i) const; |
|
130 |
virtual VarStatus _getRowStatus(int i) const; |
|
131 |
|
|
132 |
virtual ProblemType _getPrimalType() const; |
|
133 |
virtual ProblemType _getDualType() const; |
|
134 |
|
|
135 |
virtual void _clear(); |
|
136 |
|
|
137 |
public: |
|
138 |
|
|
139 |
///Solves LP with primal simplex method. |
|
140 |
SolveExitStatus solvePrimal(); |
|
141 |
|
|
142 |
///Solves LP with dual simplex method. |
|
143 |
SolveExitStatus solveDual(); |
|
144 |
|
|
145 |
///Solves LP with barrier method. |
|
146 |
SolveExitStatus solveBarrier(); |
|
147 |
|
|
148 |
///Returns the constraint identifier understood by CLP. |
|
149 |
int clpRow(Row r) const { return rows(id(r)); } |
|
150 |
|
|
151 |
///Returns the variable identifier understood by CLP. |
|
152 |
int clpCol(Col c) const { return cols(id(c)); } |
|
153 |
|
|
154 |
///Enum for \c messageLevel() parameter |
|
155 |
enum MessageLevel { |
|
156 |
/// no output (default value) |
|
157 |
MESSAGE_NO_OUTPUT = 0, |
|
158 |
/// print final solution |
|
159 |
MESSAGE_FINAL_SOLUTION = 1, |
|
160 |
/// print factorization |
|
161 |
MESSAGE_FACTORIZATION = 2, |
|
162 |
/// normal output |
|
163 |
MESSAGE_NORMAL_OUTPUT = 3, |
|
164 |
/// verbose output |
|
165 |
MESSAGE_VERBOSE_OUTPUT = 4 |
|
166 |
}; |
|
167 |
///Set the verbosity of the messages |
|
168 |
|
|
169 |
///Set the verbosity of the messages |
|
170 |
/// |
|
171 |
///\param m is the level of the messages output by the solver routines. |
|
172 |
void messageLevel(MessageLevel m); |
|
173 |
|
|
174 |
}; |
|
175 |
|
|
176 |
} //END OF NAMESPACE LEMON |
|
177 |
|
|
178 |
#endif //LEMON_LP_CLP_H |
|
179 |
1 |
AC_DEFUN([LX_CHECK_CLP], |
|
2 |
[ |
|
3 |
AC_ARG_WITH([clp], |
|
4 |
AS_HELP_STRING([--with-clp@<:@=PREFIX@:>@], [search for CLP under PREFIX or under the default search paths if PREFIX is not given @<:@default@:>@]) |
|
5 |
AS_HELP_STRING([--without-clp], [disable checking for CLP]), |
|
6 |
[], [with_clp=yes]) |
|
7 |
|
|
8 |
AC_ARG_WITH([clp-includedir], |
|
9 |
AS_HELP_STRING([--with-clp-includedir=DIR], [search for CLP headers in DIR]), |
|
10 |
[], [with_clp_includedir=no]) |
|
11 |
|
|
12 |
AC_ARG_WITH([clp-libdir], |
|
13 |
AS_HELP_STRING([--with-clp-libdir=DIR], [search for CLP libraries in DIR]), |
|
14 |
[], [with_clp_libdir=no]) |
|
15 |
|
|
16 |
lx_clp_found=no |
|
17 |
if test x"$with_clp" != x"no"; then |
|
18 |
AC_MSG_CHECKING([for CLP]) |
|
19 |
|
|
20 |
if test x"$with_clp_includedir" != x"no"; then |
|
21 |
CLP_CXXFLAGS="-I$with_clp_includedir" |
|
22 |
elif test x"$with_clp" != x"yes"; then |
|
23 |
CLP_CXXFLAGS="-I$with_clp/include" |
|
24 |
fi |
|
25 |
|
|
26 |
if test x"$with_clp_libdir" != x"no"; then |
|
27 |
CLP_LDFLAGS="-L$with_clp_libdir" |
|
28 |
elif test x"$with_clp" != x"yes"; then |
|
29 |
CLP_LDFLAGS="-L$with_clp/lib" |
|
30 |
fi |
|
31 |
CLP_LIBS="-lClp -lCoinUtils -lm" |
|
32 |
|
|
33 |
lx_save_cxxflags="$CXXFLAGS" |
|
34 |
lx_save_ldflags="$LDFLAGS" |
|
35 |
lx_save_libs="$LIBS" |
|
36 |
CXXFLAGS="$CLP_CXXFLAGS" |
|
37 |
LDFLAGS="$CLP_LDFLAGS" |
|
38 |
LIBS="$CLP_LIBS" |
|
39 |
|
|
40 |
lx_clp_test_prog=' |
|
41 |
#include <coin/ClpModel.hpp> |
|
42 |
|
|
43 |
int main(int argc, char** argv) |
|
44 |
{ |
|
45 |
ClpModel clp; |
|
46 |
return 0; |
|
47 |
}' |
|
48 |
|
|
49 |
AC_LANG_PUSH(C++) |
|
50 |
AC_LINK_IFELSE([$lx_clp_test_prog], [lx_clp_found=yes], [lx_clp_found=no]) |
|
51 |
AC_LANG_POP(C++) |
|
52 |
|
|
53 |
CXXFLAGS="$lx_save_cxxflags" |
|
54 |
LDFLAGS="$lx_save_ldflags" |
|
55 |
LIBS="$lx_save_libs" |
|
56 |
|
|
57 |
if test x"$lx_clp_found" = x"yes"; then |
|
58 |
AC_DEFINE([HAVE_CLP], [1], [Define to 1 if you have CLP.]) |
|
59 |
lx_lp_found=yes |
|
60 |
AC_DEFINE([HAVE_LP], [1], [Define to 1 if you have any LP solver.]) |
|
61 |
AC_MSG_RESULT([yes]) |
|
62 |
else |
|
63 |
CLP_CXXFLAGS="" |
|
64 |
CLP_LDFLAGS="" |
|
65 |
CLP_LIBS="" |
|
66 |
AC_MSG_RESULT([no]) |
|
67 |
fi |
|
68 |
fi |
|
69 |
CLP_LIBS="$CLP_LDFLAGS $CLP_LIBS" |
|
70 |
AC_SUBST(CLP_CXXFLAGS) |
|
71 |
AC_SUBST(CLP_LIBS) |
|
72 |
AM_CONDITIONAL([HAVE_CLP], [test x"$lx_clp_found" = x"yes"]) |
|
73 |
]) |
... | ... |
@@ -54,4 +54,5 @@ |
54 | 54 |
LX_CHECK_CPLEX |
55 | 55 |
LX_CHECK_SOPLEX |
56 |
LX_CHECK_CLP |
|
56 | 57 |
|
57 | 58 |
AM_CONDITIONAL([HAVE_LP], [test x"$lx_lp_found" = x"yes"]) |
... | ... |
@@ -121,4 +122,5 @@ |
121 | 122 |
echo CPLEX support................. : $lx_cplex_found |
122 | 123 |
echo SOPLEX support................ : $lx_soplex_found |
124 |
echo CLP support................... : $lx_clp_found |
|
123 | 125 |
echo |
124 | 126 |
echo Build demo programs........... : $enable_demo |
... | ... |
@@ -19,17 +19,19 @@ |
19 | 19 |
$(GLPK_CFLAGS) \ |
20 | 20 |
$(CPLEX_CFLAGS) \ |
21 |
$(SOPLEX_CXXFLAGS) |
|
21 |
$(SOPLEX_CXXFLAGS) \ |
|
22 |
$(CLP_CXXFLAGS) |
|
22 | 23 |
|
23 | 24 |
lemon_libemon_la_LDFLAGS = \ |
24 | 25 |
$(GLPK_LIBS) \ |
25 | 26 |
$(CPLEX_LIBS) \ |
26 |
$(SOPLEX_LIBS) |
|
27 |
$(SOPLEX_LIBS) \ |
|
28 |
$(CLP_LIBS) |
|
27 | 29 |
|
28 | 30 |
if HAVE_GLPK |
29 |
lemon_libemon_la_SOURCES += lemon/lp_glpk.cc |
|
31 |
lemon_libemon_la_SOURCES += lemon/lp_glpk.cc |
|
30 | 32 |
endif |
31 | 33 |
|
32 | 34 |
if HAVE_CPLEX |
33 |
lemon_libemon_la_SOURCES += lemon/lp_cplex.cc |
|
35 |
lemon_libemon_la_SOURCES += lemon/lp_cplex.cc |
|
34 | 36 |
endif |
35 | 37 |
|
... | ... |
@@ -38,4 +40,8 @@ |
38 | 40 |
endif |
39 | 41 |
|
42 |
if HAVE_CLP |
|
43 |
lemon_libemon_la_SOURCES += lemon/lp_clp.cc |
|
44 |
endif |
|
45 |
|
|
40 | 46 |
lemon_HEADERS += \ |
41 | 47 |
lemon/adaptors.h \ |
... | ... |
@@ -66,10 +72,10 @@ |
66 | 72 |
lemon/lp.h \ |
67 | 73 |
lemon/lp_base.h \ |
74 |
lemon/lp_clp.h \ |
|
68 | 75 |
lemon/lp_cplex.h \ |
69 | 76 |
lemon/lp_glpk.h \ |
70 | 77 |
lemon/lp_skeleton.h \ |
71 | 78 |
lemon/lp_soplex.h \ |
72 |
lemon/mip_cplex.h \ |
|
73 |
lemon/mip_glpk.h \ |
|
79 |
lemon/list_graph.h \ |
|
74 | 80 |
lemon/maps.h \ |
75 | 81 |
lemon/math.h \ |
... | ... |
@@ -95,7 +101,7 @@ |
95 | 101 |
lemon/bits/graph_adaptor_extender.h \ |
96 | 102 |
lemon/bits/graph_extender.h \ |
97 |
lemon/bits/lp_id.h \ |
|
98 | 103 |
lemon/bits/map_extender.h \ |
99 | 104 |
lemon/bits/path_dump.h \ |
105 |
lemon/bits/solver_bits.h \ |
|
100 | 106 |
lemon/bits/traits.h \ |
101 | 107 |
lemon/bits/variant.h \ |
... | ... |
@@ -25,10 +25,10 @@ |
25 | 25 |
#ifdef HAVE_GLPK |
26 | 26 |
#include <lemon/lp_glpk.h> |
27 |
#include <lemon/mip_glpk.h> |
|
28 | 27 |
#elif HAVE_CPLEX |
29 | 28 |
#include <lemon/lp_cplex.h> |
30 |
#include <lemon/mip_cplex.h> |
|
31 | 29 |
#elif HAVE_SOPLEX |
32 | 30 |
#include <lemon/lp_soplex.h> |
31 |
#elif HAVE_CLP |
|
32 |
#include <lemon/lp_clp.h> |
|
33 | 33 |
#endif |
34 | 34 |
|
... | ... |
@@ -44,6 +44,7 @@ |
44 | 44 |
///\ingroup lp_group |
45 | 45 |
/// |
46 |
///Currently, the possible values are \c GLPK or \c CPLEX |
|
47 |
#define DEFAULT_LP SOLVER |
|
46 |
///Currently, the possible values are \c LP_GLPK, \c LP_CPLEX, \c |
|
47 |
///LP_SOPLEX or \c LP_CLP |
|
48 |
#define LEMON_DEFAULT_LP SOLVER |
|
48 | 49 |
///The default LP solver |
49 | 50 |
|
... | ... |
@@ -51,36 +52,38 @@ |
51 | 52 |
///\ingroup lp_group |
52 | 53 |
/// |
53 |
///Currently, it is either \c LpGlpk or \c |
|
54 |
///Currently, it is either \c LpGlpk, \c LpCplex, \c LpSoplex or \c LpClp |
|
54 | 55 |
typedef LpGlpk Lp; |
55 |
///The default LP solver identifier string |
|
56 | 56 |
|
57 |
///The default |
|
57 |
///The default MIP solver identifier |
|
58 |
|
|
59 |
///The default MIP solver identifier. |
|
58 | 60 |
///\ingroup lp_group |
59 | 61 |
/// |
60 |
///Currently, the possible values are "GLPK" or "CPLEX" |
|
61 |
const char default_solver_name[]="SOLVER"; |
|
62 |
///Currently, the possible values are \c MIP_GLPK or \c MIP_CPLEX |
|
63 |
#define LEMON_DEFAULT_MIP SOLVER |
|
64 |
///The default MIP solver. |
|
62 | 65 |
|
63 |
///The default ILP solver. |
|
64 |
|
|
65 |
///The default |
|
66 |
///The default MIP solver. |
|
66 | 67 |
///\ingroup lp_group |
67 | 68 |
/// |
68 |
///Currently, it is either \c |
|
69 |
///Currently, it is either \c MipGlpk or \c MipCplex |
|
69 | 70 |
typedef MipGlpk Mip; |
70 | 71 |
#else |
71 | 72 |
#ifdef HAVE_GLPK |
72 |
#define |
|
73 |
# define LEMON_DEFAULT_LP LP_GLPK |
|
73 | 74 |
typedef LpGlpk Lp; |
75 |
# define LEMON_DEFAULT_MIP MIP_GLPK |
|
74 | 76 |
typedef MipGlpk Mip; |
75 |
const char default_solver_name[]="GLPK"; |
|
76 | 77 |
#elif HAVE_CPLEX |
77 |
#define |
|
78 |
# define LEMON_DEFAULT_LP LP_CPLEX |
|
78 | 79 |
typedef LpCplex Lp; |
80 |
# define LEMON_DEFAULT_MIP MIP_CPLEX |
|
79 | 81 |
typedef MipCplex Mip; |
80 |
const char default_solver_name[]="CPLEX"; |
|
81 | 82 |
#elif HAVE_SOPLEX |
82 |
#define DEFAULT_LP |
|
83 |
# define DEFAULT_LP LP_SOPLEX |
|
83 | 84 |
typedef LpSoplex Lp; |
84 |
|
|
85 |
#elif HAVE_CLP |
|
86 |
# define DEFAULT_LP LP_CLP |
|
87 |
typedef LpClp Lp; |
|
85 | 88 |
#endif |
86 | 89 |
#endif |
... | ... |
@@ -23,13 +23,6 @@ |
23 | 23 |
namespace lemon { |
24 | 24 |
|
25 |
const LpSolverBase::Value |
|
26 |
LpSolverBase::INF = std::numeric_limits<Value>::infinity(); |
|
27 |
const LpSolverBase::Value |
|
28 |
LpSolverBase::NaN = std::numeric_limits<Value>::quiet_NaN(); |
|
29 |
|
|
30 |
// const LpSolverBase::Constr::Value |
|
31 |
// LpSolverBase::Constr::INF = std::numeric_limits<Value>::infinity(); |
|
32 |
// const LpSolverBase::Constr::Value |
|
33 |
|
|
25 |
const LpBase::Value LpBase::INF = std::numeric_limits<Value>::infinity(); |
|
26 |
const LpBase::Value LpBase::NaN = std::numeric_limits<Value>::quiet_NaN(); |
|
34 | 27 |
|
35 | 28 |
} //namespace lemon |
... | ... |
@@ -26,6 +26,9 @@ |
26 | 26 |
#include<lemon/math.h> |
27 | 27 |
|
28 |
#include<lemon/error.h> |
|
29 |
#include<lemon/assert.h> |
|
30 |
|
|
28 | 31 |
#include<lemon/core.h> |
29 |
#include<lemon/bits/ |
|
32 |
#include<lemon/bits/solver_bits.h> |
|
30 | 33 |
|
31 | 34 |
///\file |
... | ... |
@@ -34,31 +37,15 @@ |
34 | 37 |
namespace lemon { |
35 | 38 |
|
36 |
/// |
|
39 |
///Common base class for LP and MIP solvers |
|
37 | 40 |
|
38 |
/// Retruns true if the argument is not infinity, minus infinity or NaN. |
|
39 |
/// It does the same as the isfinite() function defined by C99. |
|
40 |
template <typename T> |
|
41 |
bool isFinite(T value) |
|
42 |
{ |
|
43 |
typedef std::numeric_limits<T> Lim; |
|
44 |
if ((Lim::has_infinity && (value == Lim::infinity() || value == |
|
45 |
-Lim::infinity())) || |
|
46 |
((Lim::has_quiet_NaN || Lim::has_signaling_NaN) && value != value)) |
|
47 |
{ |
|
48 |
return false; |
|
49 |
} |
|
50 |
return true; |
|
51 |
} |
|
52 |
|
|
53 |
///Common base class for LP solvers |
|
54 |
|
|
55 |
///\todo Much more docs |
|
41 |
///Usually this class is not used directly, please use one of the concrete |
|
42 |
///implementations of the solver interface. |
|
56 | 43 |
///\ingroup lp_group |
57 |
class |
|
44 |
class LpBase { |
|
58 | 45 |
|
59 | 46 |
protected: |
60 | 47 |
|
61 |
_lp_bits::LpId rows; |
|
62 |
_lp_bits::LpId cols; |
|
48 |
_solver_bits::VarIndex rows; |
|
49 |
_solver_bits::VarIndex cols; |
|
63 | 50 |
|
64 | 51 |
public: |
... | ... |
@@ -75,36 +62,10 @@ |
75 | 62 |
}; |
76 | 63 |
|
77 |
///\e |
|
78 |
enum SolutionStatus { |
|
79 |
///Feasible solution hasn't been found (but may exist). |
|
80 |
|
|
81 |
///\todo NOTFOUND might be a better name. |
|
82 |
/// |
|
83 |
UNDEFINED = 0, |
|
84 |
///The problem has no feasible solution |
|
85 |
INFEASIBLE = 1, |
|
86 |
///Feasible solution found |
|
87 |
FEASIBLE = 2, |
|
88 |
///Optimal solution exists and found |
|
89 |
OPTIMAL = 3, |
|
90 |
///The cost function is unbounded |
|
91 |
|
|
92 |
///\todo Give a feasible solution and an infinite ray (and the |
|
93 |
///corresponding bases) |
|
94 |
INFINITE = 4 |
|
95 |
}; |
|
96 |
|
|
97 |
///\e The type of the investigated LP problem |
|
98 |
enum ProblemTypes { |
|
99 |
///Primal-dual feasible |
|
100 |
PRIMAL_DUAL_FEASIBLE = 0, |
|
101 |
///Primal feasible dual infeasible |
|
102 |
PRIMAL_FEASIBLE_DUAL_INFEASIBLE = 1, |
|
103 |
///Primal infeasible dual feasible |
|
104 |
PRIMAL_INFEASIBLE_DUAL_FEASIBLE = 2, |
|
105 |
///Primal-dual infeasible |
|
106 |
PRIMAL_DUAL_INFEASIBLE = 3, |
|
107 |
///Could not determine so far |
|
108 |
UNKNOWN = 4 |
|
64 |
///Direction of the optimization |
|
65 |
enum Sense { |
|
66 |
/// Minimization |
|
67 |
MIN, |
|
68 |
/// Maximization |
|
69 |
MAX |
|
109 | 70 |
}; |
110 | 71 |
|
... | ... |
@@ -116,9 +77,8 @@ |
116 | 77 |
static const Value NaN; |
117 | 78 |
|
118 |
static inline bool isNaN(const Value& v) { return v!=v; } |
|
119 |
|
|
120 | 79 |
friend class Col; |
121 | 80 |
friend class ColIt; |
122 | 81 |
friend class Row; |
82 |
friend class RowIt; |
|
123 | 83 |
|
124 | 84 |
///Refer to a column of the LP. |
... | ... |
@@ -129,41 +89,91 @@ |
129 | 89 |
///other columns. |
130 | 90 |
/// |
131 |
///\todo Document what can one do with a Col (INVALID, comparing, |
|
132 |
///it is similar to Node/Edge) |
|
91 |
///\note This class is similar to other Item types in LEMON, like |
|
92 |
///Node and Arc types in digraph. |
|
133 | 93 |
class Col { |
94 |
friend class LpBase; |
|
134 | 95 |
protected: |
135 |
int id; |
|
136 |
friend class LpSolverBase; |
|
137 |
friend class MipSolverBase; |
|
138 |
explicit Col(int _id) : id(_id) {} |
|
96 |
int _id; |
|
97 |
explicit Col(int id) : _id(id) {} |
|
139 | 98 |
public: |
140 | 99 |
typedef Value ExprValue; |
141 |
typedef True |
|
100 |
typedef True LpCol; |
|
101 |
/// Default constructor |
|
102 |
|
|
103 |
/// \warning The default constructor sets the Col to an |
|
104 |
/// undefined value. |
|
142 | 105 |
Col() {} |
143 |
Col(const Invalid&) : id(-1) {} |
|
144 |
bool operator< (Col c) const {return id< c.id;} |
|
145 |
bool operator> (Col c) const {return id> c.id;} |
|
146 |
bool operator==(Col c) const {return id==c.id;} |
|
147 |
|
|
106 |
/// Invalid constructor \& conversion. |
|
107 |
|
|
108 |
/// This constructor initializes the Col to be invalid. |
|
109 |
/// \sa Invalid for more details. |
|
110 |
Col(const Invalid&) : _id(-1) {} |
|
111 |
/// Equality operator |
|
112 |
|
|
113 |
/// Two \ref Col "Col"s are equal if and only if they point to |
|
114 |
/// the same LP column or both are invalid. |
|
115 |
bool operator==(Col c) const {return _id == c._id;} |
|
116 |
/// Inequality operator |
|
117 |
|
|
118 |
/// \sa operator==(Col c) |
|
119 |
/// |
|
120 |
bool operator!=(Col c) const {return _id != c._id;} |
|
121 |
/// Artificial ordering operator. |
|
122 |
|
|
123 |
/// To allow the use of this object in std::map or similar |
|
124 |
/// associative container we require this. |
|
125 |
/// |
|
126 |
/// \note This operator only have to define some strict ordering of |
|
127 |
/// the items; this order has nothing to do with the iteration |
|
128 |
/// ordering of the items. |
|
129 |
bool operator<(Col c) const {return _id < c._id;} |
|
148 | 130 |
}; |
149 | 131 |
|
132 |
///Iterator for iterate over the columns of an LP problem |
|
133 |
|
|
134 |
/// Its usage is quite simple, for example you can count the number |
|
135 |
/// of columns in an LP \c lp: |
|
136 |
///\code |
|
137 |
/// int count=0; |
|
138 |
/// for (LpBase::ColIt c(lp); c!=INVALID; ++c) ++count; |
|
139 |
///\endcode |
|
150 | 140 |
class ColIt : public Col { |
151 |
const |
|
141 |
const LpBase *_solver; |
|
152 | 142 |
public: |
143 |
/// Default constructor |
|
144 |
|
|
145 |
/// \warning The default constructor sets the iterator |
|
146 |
/// to an undefined value. |
|
153 | 147 |
ColIt() {} |
154 |
|
|
148 |
/// Sets the iterator to the first Col |
|
149 |
|
|
150 |
/// Sets the iterator to the first Col. |
|
151 |
/// |
|
152 |
ColIt(const LpBase &solver) : _solver(&solver) |
|
155 | 153 |
{ |
156 |
|
|
154 |
_solver->cols.firstItem(_id); |
|
157 | 155 |
} |
156 |
/// Invalid constructor \& conversion |
|
157 |
|
|
158 |
/// Initialize the iterator to be invalid. |
|
159 |
/// \sa Invalid for more details. |
|
158 | 160 |
ColIt(const Invalid&) : Col(INVALID) {} |
161 |
/// Next column |
|
162 |
|
|
163 |
/// Assign the iterator to the next column. |
|
164 |
/// |
|
159 | 165 |
ColIt &operator++() |
160 | 166 |
{ |
161 |
|
|
167 |
_solver->cols.nextItem(_id); |
|
162 | 168 |
return *this; |
163 | 169 |
} |
164 | 170 |
}; |
165 | 171 |
|
166 |
static int id(const Col& col) { return col.id; } |
|
167 |
|
|
172 |
/// \brief Returns the ID of the column. |
|
173 |
static int id(const Col& col) { return col._id; } |
|
174 |
/// \brief Returns the column with the given ID. |
|
175 |
/// |
|
176 |
/// \pre The argument should be a valid column ID in the LP problem. |
|
177 |
static Col colFromId(int id) { return Col(id); } |
|
168 | 178 |
|
169 | 179 |
///Refer to a row of the LP. |
... | ... |
@@ -174,59 +184,91 @@ |
174 | 184 |
///other rows. |
175 | 185 |
/// |
176 |
///\todo Document what can one do with a Row (INVALID, comparing, |
|
177 |
///it is similar to Node/Edge) |
|
186 |
///\note This class is similar to other Item types in LEMON, like |
|
187 |
///Node and Arc types in digraph. |
|
178 | 188 |
class Row { |
189 |
friend class LpBase; |
|
179 | 190 |
protected: |
180 |
int id; |
|
181 |
friend class LpSolverBase; |
|
182 |
|
|
191 |
int _id; |
|
192 |
explicit Row(int id) : _id(id) {} |
|
183 | 193 |
public: |
184 | 194 |
typedef Value ExprValue; |
185 |
typedef True |
|
195 |
typedef True LpRow; |
|
196 |
/// Default constructor |
|
197 |
|
|
198 |
/// \warning The default constructor sets the Row to an |
|
199 |
/// undefined value. |
|
186 | 200 |
Row() {} |
187 |
|
|
201 |
/// Invalid constructor \& conversion. |
|
202 |
|
|
203 |
/// This constructor initializes the Row to be invalid. |
|
204 |
/// \sa Invalid for more details. |
|
205 |
Row(const Invalid&) : _id(-1) {} |
|
206 |
/// Equality operator |
|
188 | 207 |
|
189 |
bool operator< (Row c) const {return id< c.id;} |
|
190 |
bool operator> (Row c) const {return id> c.id;} |
|
191 |
bool operator==(Row c) const {return id==c.id;} |
|
192 |
bool operator!=(Row c) const {return id!=c.id;} |
|
208 |
/// Two \ref Row "Row"s are equal if and only if they point to |
|
209 |
/// the same LP row or both are invalid. |
|
210 |
bool operator==(Row r) const {return _id == r._id;} |
|
211 |
/// Inequality operator |
|
212 |
|
|
213 |
/// \sa operator==(Row r) |
|
214 |
/// |
|
215 |
bool operator!=(Row r) const {return _id != r._id;} |
|
216 |
/// Artificial ordering operator. |
|
217 |
|
|
218 |
/// To allow the use of this object in std::map or similar |
|
219 |
/// associative container we require this. |
|
220 |
/// |
|
221 |
/// \note This operator only have to define some strict ordering of |
|
222 |
/// the items; this order has nothing to do with the iteration |
|
223 |
/// ordering of the items. |
|
224 |
bool operator<(Row r) const {return _id < r._id;} |
|
193 | 225 |
}; |
194 | 226 |
|
227 |
///Iterator for iterate over the rows of an LP problem |
|
228 |
|
|
229 |
/// Its usage is quite simple, for example you can count the number |
|
230 |
/// of rows in an LP \c lp: |
|
231 |
///\code |
|
232 |
/// int count=0; |
|
233 |
/// for (LpBase::RowIt c(lp); c!=INVALID; ++c) ++count; |
|
234 |
///\endcode |
|
195 | 235 |
class RowIt : public Row { |
196 |
const |
|
236 |
const LpBase *_solver; |
|
197 | 237 |
public: |
238 |
/// Default constructor |
|
239 |
|
|
240 |
/// \warning The default constructor sets the iterator |
|
241 |
/// to an undefined value. |
|
198 | 242 |
RowIt() {} |
199 |
|
|
243 |
/// Sets the iterator to the first Row |
|
244 |
|
|
245 |
/// Sets the iterator to the first Row. |
|
246 |
/// |
|
247 |
RowIt(const LpBase &solver) : _solver(&solver) |
|
200 | 248 |
{ |
201 |
|
|
249 |
_solver->rows.firstItem(_id); |
|
202 | 250 |
} |
251 |
/// Invalid constructor \& conversion |
|
252 |
|
|
253 |
/// Initialize the iterator to be invalid. |
|
254 |
/// \sa Invalid for more details. |
|
203 | 255 |
RowIt(const Invalid&) : Row(INVALID) {} |
256 |
/// Next row |
|
257 |
|
|
258 |
/// Assign the iterator to the next row. |
|
259 |
/// |
|
204 | 260 |
RowIt &operator++() |
205 | 261 |
{ |
206 |
|
|
262 |
_solver->rows.nextItem(_id); |
|
207 | 263 |
return *this; |
208 | 264 |
} |
209 | 265 |
}; |
210 | 266 |
|
211 |
static int id(const Row& row) { return row.id; } |
|
212 |
|
|
213 |
protected: |
|
214 |
|
|
215 |
int _lpId(const Col& c) const { |
|
216 |
return cols.floatingId(id(c)); |
|
217 |
} |
|
218 |
|
|
219 |
int _lpId(const Row& r) const { |
|
220 |
return rows.floatingId(id(r)); |
|
221 |
} |
|
222 |
|
|
223 |
Col _item(int i, Col) const { |
|
224 |
return Col(cols.fixId(i)); |
|
225 |
} |
|
226 |
|
|
227 |
Row _item(int i, Row) const { |
|
228 |
return Row(rows.fixId(i)); |
|
229 |
} |
|
230 |
|
|
267 |
/// \brief Returns the ID of the row. |
|
268 |
static int id(const Row& row) { return row._id; } |
|
269 |
/// \brief Returns the row with the given ID. |
|
270 |
/// |
|
271 |
/// \pre The argument should be a valid row ID in the LP problem. |
|
272 |
static Row rowFromId(int id) { return Row(id); } |
|
231 | 273 |
|
232 | 274 |
public: |
... | ... |
@@ -239,8 +281,4 @@ |
239 | 281 |
///There are several ways to access and modify the contents of this |
240 | 282 |
///container. |
241 |
///- Its it fully compatible with \c std::map<Col,double>, so for expamle |
|
242 |
///if \c e is an Expr and \c v and \c w are of type \ref Col, then you can |
|
243 |
///read and modify the coefficients like |
|
244 |
///these. |
|
245 | 283 |
///\code |
246 | 284 |
///e[v]=5; |
... | ... |
@@ -251,8 +289,8 @@ |
251 | 289 |
///\code |
252 | 290 |
///double s=0; |
253 |
///for(LpSolverBase::Expr::iterator i=e.begin();i!=e.end();++i) |
|
254 |
/// s+=i->second; |
|
291 |
///for(LpBase::Expr::ConstCoeffIt i(e);i!=INVALID;++i) |
|
292 |
/// s+=*i * primal(i); |
|
255 | 293 |
///\endcode |
256 |
///(This code computes the |
|
294 |
///(This code computes the primal value of the expression). |
|
257 | 295 |
///- Numbers (<tt>double</tt>'s) |
258 | 296 |
///and variables (\ref Col "Col"s) directly convert to an |
... | ... |
@@ -263,5 +301,5 @@ |
263 | 301 |
///v*2.1+(3*v+(v*12+w+6)*3)/2 |
264 | 302 |
///\endcode |
265 |
///are valid |
|
303 |
///are valid expressions. |
|
266 | 304 |
///The usual assignment operations are also defined. |
267 | 305 |
///\code |
... | ... |
@@ -271,103 +309,216 @@ |
271 | 309 |
///e/=5; |
272 | 310 |
///\endcode |
273 |
///- The constant member can be set and read by |
|
311 |
///- The constant member can be set and read by dereference |
|
312 |
/// operator (unary *) |
|
313 |
/// |
|
274 | 314 |
///\code |
275 |
///e.constComp()=12; |
|
276 |
///double c=e.constComp(); |
|
315 |
///*e=12; |
|
316 |
///double c=*e; |
|
277 | 317 |
///\endcode |
278 | 318 |
/// |
279 |
///\note \ref clear() not only sets all coefficients to 0 but also |
|
280 |
///clears the constant components. |
|
281 |
/// |
|
282 | 319 |
///\sa Constr |
283 |
/// |
|
284 |
class Expr : public std::map<Col,Value> |
|
285 |
{ |
|
320 |
class Expr { |
|
321 |
friend class LpBase; |
|
286 | 322 |
public: |
287 |
typedef LpSolverBase::Col Key; |
|
288 |
typedef LpSolverBase::Value Value; |
|
323 |
/// The key type of the expression |
|
324 |
typedef LpBase::Col Key; |
|
325 |
/// The value type of the expression |
|
326 |
typedef LpBase::Value Value; |
|
289 | 327 |
|
290 | 328 |
protected: |
291 |
|
|
329 |
Value const_comp; |
|
330 |
std::map<int, Value> comps; |
|
292 | 331 |
|
293 |
Value const_comp; |
|
294 | 332 |
public: |
295 |
typedef True IsLinExpression; |
|
296 |
///\e |
|
297 |
Expr() : Base(), const_comp(0) { } |
|
298 |
///\e |
|
299 |
Expr(const Key &v) : const_comp(0) { |
|
300 |
Base::insert(std::make_pair(v, 1)); |
|
333 |
typedef True SolverExpr; |
|
334 |
/// Default constructor |
|
335 |
|
|
336 |
/// Construct an empty expression, the coefficients and |
|
337 |
/// the constant component are initialized to zero. |
|
338 |
Expr() : const_comp(0) {} |
|
339 |
/// Construct an expression from a column |
|
340 |
|
|
341 |
/// Construct an expression, which has a term with \c c variable |
|
342 |
/// and 1.0 coefficient. |
|
343 |
Expr(const Col &c) : const_comp(0) { |
|
344 |
typedef std::map<int, Value>::value_type pair_type; |
|
345 |
comps.insert(pair_type(id(c), 1)); |
|
301 | 346 |
} |
302 |
/// |
|
347 |
/// Construct an expression from a constant |
|
348 |
|
|
349 |
/// Construct an expression, which's constant component is \c v. |
|
350 |
/// |
|
303 | 351 |
Expr(const Value &v) : const_comp(v) {} |
304 |
///\e |
|
305 |
void set(const Key &v,const Value &c) { |
|
306 |
Base::insert(std::make_pair(v, c)); |
|
307 |
} |
|
308 |
///\e |
|
309 |
Value &constComp() { return const_comp; } |
|
310 |
///\e |
|
311 |
const Value &constComp() const { return const_comp; } |
|
312 |
|
|
313 |
///Removes the components with zero coefficient. |
|
314 |
void simplify() { |
|
315 |
for (Base::iterator i=Base::begin(); i!=Base::end();) { |
|
316 |
Base::iterator j=i; |
|
317 |
++j; |
|
318 |
if ((*i).second==0) Base::erase(i); |
|
319 |
i=j; |
|
352 |
/// Returns the coefficient of the column |
|
353 |
Value operator[](const Col& c) const { |
|
354 |
std::map<int, Value>::const_iterator it=comps.find(id(c)); |
|
355 |
if (it != comps.end()) { |
|
356 |
return it->second; |
|
357 |
} else { |
|
358 |
return 0; |
|
320 | 359 |
} |
321 | 360 |
} |
322 |
|
|
323 |
void simplify() const { |
|
324 |
|
|
361 |
/// Returns the coefficient of the column |
|
362 |
Value& operator[](const Col& c) { |
|
363 |
return comps[id(c)]; |
|
364 |
} |
|
365 |
/// Sets the coefficient of the column |
|
366 |
void set(const Col &c, const Value &v) { |
|
367 |
if (v != 0.0) { |
|
368 |
typedef std::map<int, Value>::value_type pair_type; |
|
369 |
comps.insert(pair_type(id(c), v)); |
|
370 |
} else { |
|
371 |
comps.erase(id(c)); |
|
372 |
} |
|
373 |
} |
|
374 |
/// Returns the constant component of the expression |
|
375 |
Value& operator*() { return const_comp; } |
|
376 |
/// Returns the constant component of the expression |
|
377 |
const Value& operator*() const { return const_comp; } |
|
378 |
/// \brief Removes the coefficients which's absolute value does |
|
379 |
/// not exceed \c epsilon. It also sets to zero the constant |
|
380 |
/// component, if it does not exceed epsilon in absolute value. |
|
381 |
void simplify(Value epsilon = 0.0) { |
|
382 |
std::map<int, Value>::iterator it=comps.begin(); |
|
383 |
while (it != comps.end()) { |
|
384 |
std::map<int, Value>::iterator jt=it; |
|
385 |
++jt; |
|
386 |
if (std::fabs((*it).second) <= epsilon) comps.erase(it); |
|
387 |
it=jt; |
|
388 |
} |
|
389 |
if (std::fabs(const_comp) <= epsilon) const_comp = 0; |
|
325 | 390 |
} |
326 | 391 |
|
327 |
///Removes the coefficients closer to zero than \c tolerance. |
|
328 |
void simplify(double &tolerance) { |
|
329 |
for (Base::iterator i=Base::begin(); i!=Base::end();) { |
|
330 |
Base::iterator j=i; |
|
331 |
++j; |
|
332 |
if (std::fabs((*i).second)<tolerance) Base::erase(i); |
|
333 |
i=j; |
|
334 |
} |
|
392 |
void simplify(Value epsilon = 0.0) const { |
|
393 |
const_cast<Expr*>(this)->simplify(epsilon); |
|
335 | 394 |
} |
336 | 395 |
|
337 | 396 |
///Sets all coefficients and the constant component to 0. |
338 | 397 |
void clear() { |
339 |
|
|
398 |
comps.clear(); |
|
340 | 399 |
const_comp=0; |
341 | 400 |
} |
342 | 401 |
|
343 |
/// |
|
402 |
///Compound assignment |
|
344 | 403 |
Expr &operator+=(const Expr &e) { |
345 |
for (Base::const_iterator j=e.begin(); j!=e.end(); ++j) |
|
346 |
(*this)[j->first]+=j->second; |
|
404 |
for (std::map<int, Value>::const_iterator it=e.comps.begin(); |
|
405 |
it!=e.comps.end(); ++it) |
|
406 |
comps[it->first]+=it->second; |
|
347 | 407 |
const_comp+=e.const_comp; |
348 | 408 |
return *this; |
349 | 409 |
} |
350 |
/// |
|
410 |
///Compound assignment |
|
351 | 411 |
Expr &operator-=(const Expr &e) { |
352 |
for (Base::const_iterator j=e.begin(); j!=e.end(); ++j) |
|
353 |
(*this)[j->first]-=j->second; |
|
412 |
for (std::map<int, Value>::const_iterator it=e.comps.begin(); |
|
413 |
it!=e.comps.end(); ++it) |
|
414 |
comps[it->first]-=it->second; |
|
354 | 415 |
const_comp-=e.const_comp; |
355 | 416 |
return *this; |
356 | 417 |
} |
357 |
///\e |
|
358 |
Expr &operator*=(const Value &c) { |
|
359 |
for (Base::iterator j=Base::begin(); j!=Base::end(); ++j) |
|
360 |
j->second*=c; |
|
361 |
|
|
418 |
///Multiply with a constant |
|
419 |
Expr &operator*=(const Value &v) { |
|
420 |
for (std::map<int, Value>::iterator it=comps.begin(); |
|
421 |
it!=comps.end(); ++it) |
|
422 |
it->second*=v; |
|
423 |
const_comp*=v; |
|
362 | 424 |
return *this; |
363 | 425 |
} |
364 |
/// |
|
426 |
///Division with a constant |
|
365 | 427 |
Expr &operator/=(const Value &c) { |
366 |
for (Base::iterator j=Base::begin(); j!=Base::end(); ++j) |
|
367 |
j->second/=c; |
|
428 |
for (std::map<int, Value>::iterator it=comps.begin(); |
|
429 |
it!=comps.end(); ++it) |
|
430 |
it->second/=c; |
|
368 | 431 |
const_comp/=c; |
369 | 432 |
return *this; |
370 | 433 |
} |
371 | 434 |
|
435 |
///Iterator over the expression |
|
436 |
|
|
437 |
///The iterator iterates over the terms of the expression. |
|
438 |
/// |
|
439 |
///\code |
|
440 |
///double s=0; |
|
441 |
///for(LpBase::Expr::CoeffIt i(e);i!=INVALID;++i) |
|
442 |
/// s+= *i * primal(i); |
|
443 |
///\endcode |
|
444 |
class CoeffIt { |
|
445 |
private: |
|
446 |
|
|
447 |
std::map<int, Value>::iterator _it, _end; |
|
448 |
|
|
449 |
public: |
|
450 |
|
|
451 |
/// Sets the iterator to the first term |
|
452 |
|
|
453 |
/// Sets the iterator to the first term of the expression. |
|
454 |
/// |
|
455 |
CoeffIt(Expr& e) |
|
456 |
: _it(e.comps.begin()), _end(e.comps.end()){} |
|
457 |
|
|
458 |
/// Convert the iterator to the column of the term |
|
459 |
operator Col() const { |
|
460 |
return colFromId(_it->first); |
|
461 |
} |
|
462 |
|
|
463 |
/// Returns the coefficient of the term |
|
464 |
Value& operator*() { return _it->second; } |
|
465 |
|
|
466 |
/// Returns the coefficient of the term |
|
467 |
const Value& operator*() const { return _it->second; } |
|
468 |
/// Next term |
|
469 |
|
|
470 |
/// Assign the iterator to the next term. |
|
471 |
/// |
|
472 |
CoeffIt& operator++() { ++_it; return *this; } |
|
473 |
|
|
474 |
/// Equality operator |
|
475 |
bool operator==(Invalid) const { return _it == _end; } |
|
476 |
/// Inequality operator |
|
477 |
bool operator!=(Invalid) const { return _it != _end; } |
|
478 |
}; |
|
479 |
|
|
480 |
/// Const iterator over the expression |
|
481 |
|
|
482 |
///The iterator iterates over the terms of the expression. |
|
483 |
/// |
|
484 |
///\code |
|
485 |
///double s=0; |
|
486 |
///for(LpBase::Expr::ConstCoeffIt i(e);i!=INVALID;++i) |
|
487 |
/// s+=*i * primal(i); |
|
488 |
///\endcode |
|
489 |
class ConstCoeffIt { |
|
490 |
private: |
|
491 |
|
|
492 |
std::map<int, Value>::const_iterator _it, _end; |
|
493 |
|
|
494 |
public: |
|
495 |
|
|
496 |
/// Sets the iterator to the first term |
|
497 |
|
|
498 |
/// Sets the iterator to the first term of the expression. |
|
499 |
/// |
|
500 |
ConstCoeffIt(const Expr& e) |
|
501 |
: _it(e.comps.begin()), _end(e.comps.end()){} |
|
502 |
|
|
503 |
/// Convert the iterator to the column of the term |
|
504 |
operator Col() const { |
|
505 |
return colFromId(_it->first); |
|
506 |
} |
|
507 |
|
|
508 |
/// Returns the coefficient of the term |
|
509 |
const Value& operator*() const { return _it->second; } |
|
510 |
|
|
511 |
/// Next term |
|
512 |
|
|
513 |
/// Assign the iterator to the next term. |
|
514 |
/// |
|
515 |
ConstCoeffIt& operator++() { ++_it; return *this; } |
|
516 |
|
|
517 |
/// Equality operator |
|
518 |
bool operator==(Invalid) const { return _it == _end; } |
|
519 |
/// Inequality operator |
|
520 |
bool operator!=(Invalid) const { return _it != _end; } |
|
521 |
}; |
|
522 |
|
|
372 | 523 |
}; |
373 | 524 |
|
... | ... |
@@ -395,11 +546,11 @@ |
395 | 546 |
/// e>=t |
396 | 547 |
///\endcode |
397 |
///\warning The validity of a constraint is checked only at run time, so |
|
398 |
///e.g. \ref addRow(<tt>x[1]\<=x[2]<=5</tt>) will compile, but will throw |
|
399 |
/// |
|
548 |
///\warning The validity of a constraint is checked only at run |
|
549 |
///time, so e.g. \ref addRow(<tt>x[1]\<=x[2]<=5</tt>) will |
|
550 |
///compile, but will fail an assertion. |
|
400 | 551 |
class Constr |
401 | 552 |
{ |
402 | 553 |
public: |
403 |
typedef |
|
554 |
typedef LpBase::Expr Expr; |
|
404 | 555 |
typedef Expr::Key Key; |
405 | 556 |
typedef Expr::Value Value; |
... | ... |
@@ -412,13 +563,6 @@ |
412 | 563 |
Constr() : _expr(), _lb(NaN), _ub(NaN) {} |
413 | 564 |
///\e |
414 |
Constr(Value lb,const Expr &e,Value ub) : |
|
565 |
Constr(Value lb, const Expr &e, Value ub) : |
|
415 | 566 |
_expr(e), _lb(lb), _ub(ub) {} |
416 |
///\e |
|
417 |
Constr(const Expr &e,Value ub) : |
|
418 |
_expr(e), _lb(NaN), _ub(ub) {} |
|
419 |
///\e |
|
420 |
Constr(Value lb,const Expr &e) : |
|
421 |
_expr(e), _lb(lb), _ub(NaN) {} |
|
422 |
///\e |
|
423 | 567 |
Constr(const Expr &e) : |
424 | 568 |
_expr(e), _lb(NaN), _ub(NaN) {} |
... | ... |
@@ -454,9 +598,9 @@ |
454 | 598 |
///Is the constraint lower bounded? |
455 | 599 |
bool lowerBounded() const { |
456 |
return |
|
600 |
return _lb != -INF && !std::isnan(_lb); |
|
457 | 601 |
} |
458 | 602 |
///Is the constraint upper bounded? |
459 | 603 |
bool upperBounded() const { |
460 |
return |
|
604 |
return _ub != INF && !std::isnan(_ub); |
|
461 | 605 |
} |
462 | 606 |
|
... | ... |
@@ -471,9 +615,4 @@ |
471 | 615 |
///There are several ways to access and modify the contents of this |
472 | 616 |
///container. |
473 |
///- Its it fully compatible with \c std::map<Row,double>, so for expamle |
|
474 |
///if \c e is an DualExpr and \c v |
|
475 |
///and \c w are of type \ref Row, then you can |
|
476 |
///read and modify the coefficients like |
|
477 |
///these. |
|
478 | 617 |
///\code |
479 | 618 |
///e[v]=5; |
... | ... |
@@ -484,6 +623,6 @@ |
484 | 623 |
///\code |
485 | 624 |
///double s=0; |
486 |
///for(LpSolverBase::DualExpr::iterator i=e.begin();i!=e.end();++i) |
|
487 |
/// s+=i->second; |
|
625 |
///for(LpBase::DualExpr::ConstCoeffIt i(e);i!=INVALID;++i) |
|
626 |
/// s+=*i; |
|
488 | 627 |
///\endcode |
489 | 628 |
///(This code computes the sum of all coefficients). |
... | ... |
@@ -496,5 +635,5 @@ |
496 | 635 |
///v*2.1+(3*v+(v*12+w)*3)/2 |
497 | 636 |
///\endcode |
498 |
///are valid \ref DualExpr |
|
637 |
///are valid \ref DualExpr dual expressions. |
|
499 | 638 |
///The usual assignment operations are also defined. |
500 | 639 |
///\code |
... | ... |
@@ -506,91 +645,202 @@ |
506 | 645 |
/// |
507 | 646 |
///\sa Expr |
508 |
/// |
|
509 |
class DualExpr : public std::map<Row,Value> |
|
510 |
{ |
|
647 |
class DualExpr { |
|
648 |
friend class LpBase; |
|
511 | 649 |
public: |
512 |
typedef LpSolverBase::Row Key; |
|
513 |
typedef LpSolverBase::Value Value; |
|
650 |
/// The key type of the expression |
|
651 |
typedef LpBase::Row Key; |
|
652 |
/// The value type of the expression |
|
653 |
typedef LpBase::Value Value; |
|
514 | 654 |
|
515 | 655 |
protected: |
516 |
|
|
656 |
std::map<int, Value> comps; |
|
517 | 657 |
|
518 | 658 |
public: |
519 |
typedef True IsLinExpression; |
|
520 |
///\e |
|
521 |
DualExpr() : Base() { } |
|
522 |
///\e |
|
523 |
DualExpr(const Key &v) { |
|
524 |
Base::insert(std::make_pair(v, 1)); |
|
659 |
typedef True SolverExpr; |
|
660 |
/// Default constructor |
|
661 |
|
|
662 |
/// Construct an empty expression, the coefficients are |
|
663 |
/// initialized to zero. |
|
664 |
DualExpr() {} |
|
665 |
/// Construct an expression from a row |
|
666 |
|
|
667 |
/// Construct an expression, which has a term with \c r dual |
|
668 |
/// variable and 1.0 coefficient. |
|
669 |
DualExpr(const Row &r) { |
|
670 |
typedef std::map<int, Value>::value_type pair_type; |
|
671 |
comps.insert(pair_type(id(r), 1)); |
|
525 | 672 |
} |
526 |
///\e |
|
527 |
void set(const Key &v,const Value &c) { |
|
528 |
|
|
673 |
/// Returns the coefficient of the row |
|
674 |
Value operator[](const Row& r) const { |
|
675 |
std::map<int, Value>::const_iterator it = comps.find(id(r)); |
|
676 |
if (it != comps.end()) { |
|
677 |
return it->second; |
|
678 |
} else { |
|
679 |
return 0; |
|
680 |
} |
|
529 | 681 |
} |
530 |
|
|
531 |
///Removes the components with zero coefficient. |
|
532 |
void simplify() { |
|
533 |
for (Base::iterator i=Base::begin(); i!=Base::end();) { |
|
534 |
Base::iterator j=i; |
|
535 |
++j; |
|
536 |
if ((*i).second==0) Base::erase(i); |
|
537 |
i=j; |
|
682 |
/// Returns the coefficient of the row |
|
683 |
Value& operator[](const Row& r) { |
|
684 |
return comps[id(r)]; |
|
685 |
} |
|
686 |
/// Sets the coefficient of the row |
|
687 |
void set(const Row &r, const Value &v) { |
|
688 |
if (v != 0.0) { |
|
689 |
typedef std::map<int, Value>::value_type pair_type; |
|
690 |
comps.insert(pair_type(id(r), v)); |
|
691 |
} else { |
|
692 |
comps.erase(id(r)); |
|
693 |
} |
|
694 |
} |
|
695 |
/// \brief Removes the coefficients which's absolute value does |
|
696 |
/// not exceed \c epsilon. |
|
697 |
void simplify(Value epsilon = 0.0) { |
|
698 |
std::map<int, Value>::iterator it=comps.begin(); |
|
699 |
while (it != comps.end()) { |
|
700 |
std::map<int, Value>::iterator jt=it; |
|
701 |
++jt; |
|
702 |
if (std::fabs((*it).second) <= epsilon) comps.erase(it); |
|
703 |
it=jt; |
|
538 | 704 |
} |
539 | 705 |
} |
540 | 706 |
|
541 |
void simplify() const { |
|
542 |
const_cast<DualExpr*>(this)->simplify(); |
|
543 |
} |
|
544 |
|
|
545 |
///Removes the coefficients closer to zero than \c tolerance. |
|
546 |
void simplify(double &tolerance) { |
|
547 |
for (Base::iterator i=Base::begin(); i!=Base::end();) { |
|
548 |
Base::iterator j=i; |
|
549 |
++j; |
|
550 |
if (std::fabs((*i).second)<tolerance) Base::erase(i); |
|
551 |
i=j; |
|
552 |
} |
|
707 |
void simplify(Value epsilon = 0.0) const { |
|
708 |
const_cast<DualExpr*>(this)->simplify(epsilon); |
|
553 | 709 |
} |
554 | 710 |
|
555 | 711 |
///Sets all coefficients to 0. |
556 | 712 |
void clear() { |
557 |
|
|
713 |
comps.clear(); |
|
714 |
} |
|
715 |
///Compound assignment |
|
716 |
DualExpr &operator+=(const DualExpr &e) { |
|
717 |
for (std::map<int, Value>::const_iterator it=e.comps.begin(); |
|
718 |
it!=e.comps.end(); ++it) |
|
719 |
comps[it->first]+=it->second; |
|
720 |
return *this; |
|
721 |
} |
|
722 |
///Compound assignment |
|
723 |
DualExpr &operator-=(const DualExpr &e) { |
|
724 |
for (std::map<int, Value>::const_iterator it=e.comps.begin(); |
|
725 |
it!=e.comps.end(); ++it) |
|
726 |
comps[it->first]-=it->second; |
|
727 |
return *this; |
|
728 |
} |
|
729 |
///Multiply with a constant |
|
730 |
DualExpr &operator*=(const Value &v) { |
|
731 |
for (std::map<int, Value>::iterator it=comps.begin(); |
|
732 |
it!=comps.end(); ++it) |
|
733 |
it->second*=v; |
|
734 |
return *this; |
|
735 |
} |
|
736 |
///Division with a constant |
|
737 |
DualExpr &operator/=(const Value &v) { |
|
738 |
for (std::map<int, Value>::iterator it=comps.begin(); |
|
739 |
it!=comps.end(); ++it) |
|
740 |
it->second/=v; |
|
741 |
return *this; |
|
558 | 742 |
} |
559 | 743 |
|
560 |
///\e |
|
561 |
DualExpr &operator+=(const DualExpr &e) { |
|
562 |
for (Base::const_iterator j=e.begin(); j!=e.end(); ++j) |
|
563 |
(*this)[j->first]+=j->second; |
|
564 |
return *this; |
|
565 |
} |
|
566 |
///\e |
|
567 |
DualExpr &operator-=(const DualExpr &e) { |
|
568 |
for (Base::const_iterator j=e.begin(); j!=e.end(); ++j) |
|
569 |
(*this)[j->first]-=j->second; |
|
570 |
return *this; |
|
571 |
} |
|
572 |
///\e |
|
573 |
DualExpr &operator*=(const Value &c) { |
|
574 |
for (Base::iterator j=Base::begin(); j!=Base::end(); ++j) |
|
575 |
j->second*=c; |
|
576 |
return *this; |
|
577 |
} |
|
578 |
///\e |
|
579 |
DualExpr &operator/=(const Value &c) { |
|
580 |
for (Base::iterator j=Base::begin(); j!=Base::end(); ++j) |
|
581 |
j->second/=c; |
|
582 |
return *this; |
|
583 |
} |
|
744 |
///Iterator over the expression |
|
745 |
|
|
746 |
///The iterator iterates over the terms of the expression. |
|
747 |
/// |
|
748 |
///\code |
|
749 |
///double s=0; |
|
750 |
///for(LpBase::DualExpr::CoeffIt i(e);i!=INVALID;++i) |
|
751 |
/// s+= *i * dual(i); |
|
752 |
///\endcode |
|
753 |
class CoeffIt { |
|
754 |
private: |
|
755 |
|
|
756 |
std::map<int, Value>::iterator _it, _end; |
|
757 |
|
|
758 |
public: |
|
759 |
|
|
760 |
/// Sets the iterator to the first term |
|
761 |
|
|
762 |
/// Sets the iterator to the first term of the expression. |
|
763 |
/// |
|
764 |
CoeffIt(DualExpr& e) |
|
765 |
: _it(e.comps.begin()), _end(e.comps.end()){} |
|
766 |
|
|
767 |
/// Convert the iterator to the row of the term |
|
768 |
operator Row() const { |
|
769 |
return rowFromId(_it->first); |
|
770 |
} |
|
771 |
|
|
772 |
/// Returns the coefficient of the term |
|
773 |
Value& operator*() { return _it->second; } |
|
774 |
|
|
775 |
/// Returns the coefficient of the term |
|
776 |
const Value& operator*() const { return _it->second; } |
|
777 |
|
|
778 |
/// Next term |
|
779 |
|
|
780 |
/// Assign the iterator to the next term. |
|
781 |
/// |
|
782 |
CoeffIt& operator++() { ++_it; return *this; } |
|
783 |
|
|
784 |
/// Equality operator |
|
785 |
bool operator==(Invalid) const { return _it == _end; } |
|
786 |
/// Inequality operator |
|
787 |
bool operator!=(Invalid) const { return _it != _end; } |
|
788 |
}; |
|
789 |
|
|
790 |
///Iterator over the expression |
|
791 |
|
|
792 |
///The iterator iterates over the terms of the expression. |
|
793 |
/// |
|
794 |
///\code |
|
795 |
///double s=0; |
|
796 |
///for(LpBase::DualExpr::ConstCoeffIt i(e);i!=INVALID;++i) |
|
797 |
/// s+= *i * dual(i); |
|
798 |
///\endcode |
|
799 |
class ConstCoeffIt { |
|
800 |
private: |
|
801 |
|
|
802 |
std::map<int, Value>::const_iterator _it, _end; |
|
803 |
|
|
804 |
public: |
|
805 |
|
|
806 |
/// Sets the iterator to the first term |
|
807 |
|
|
808 |
/// Sets the iterator to the first term of the expression. |
|
809 |
/// |
|
810 |
ConstCoeffIt(const DualExpr& e) |
|
811 |
: _it(e.comps.begin()), _end(e.comps.end()){} |
|
812 |
|
|
813 |
/// Convert the iterator to the row of the term |
|
814 |
operator Row() const { |
|
815 |
return rowFromId(_it->first); |
|
816 |
} |
|
817 |
|
|
818 |
/// Returns the coefficient of the term |
|
819 |
const Value& operator*() const { return _it->second; } |
|
820 |
|
|
821 |
/// Next term |
|
822 |
|
|
823 |
/// Assign the iterator to the next term. |
|
824 |
/// |
|
825 |
ConstCoeffIt& operator++() { ++_it; return *this; } |
|
826 |
|
|
827 |
/// Equality operator |
|
828 |
bool operator==(Invalid) const { return _it == _end; } |
|
829 |
/// Inequality operator |
|
830 |
bool operator!=(Invalid) const { return _it != _end; } |
|
831 |
}; |
|
584 | 832 |
}; |
585 | 833 |
|
586 | 834 |
|
587 |
|
|
835 |
protected: |
|
588 | 836 |
|
589 |
template <typename _Expr> |
|
590 |
class MappedOutputIterator { |
|
837 |
class InsertIterator { |
|
838 |
private: |
|
839 |
|
|
840 |
std::map<int, Value>& _host; |
|
841 |
const _solver_bits::VarIndex& _index; |
|
842 |
|
|
591 | 843 |
public: |
592 | 844 |
|
593 |
typedef std::insert_iterator<_Expr> Base; |
|
594 |
|
|
595 | 845 |
typedef std::output_iterator_tag iterator_category; |
596 | 846 |
typedef void difference_type; |
... | ... |
@@ -599,51 +849,31 @@ |
599 | 849 |
typedef void pointer; |
600 | 850 |
|
601 |
MappedOutputIterator(const Base& _base, const LpSolverBase& _lp) |
|
602 |
: base(_base), lp(_lp) {} |
|
851 |
InsertIterator(std::map<int, Value>& host, |
|
852 |
const _solver_bits::VarIndex& index) |
|
853 |
: _host(host), _index(index) {} |
|
603 | 854 |
|
604 |
|
|
855 |
InsertIterator& operator=(const std::pair<int, Value>& value) { |
|
856 |
typedef std::map<int, Value>::value_type pair_type; |
|
857 |
_host.insert(pair_type(_index[value.first], value.second)); |
|
605 | 858 |
return *this; |
606 | 859 |
} |
607 | 860 |
|
608 |
MappedOutputIterator& operator=(const std::pair<int, Value>& value) { |
|
609 |
*base = std::make_pair(lp._item(value.first, typename _Expr::Key()), |
|
610 |
value.second); |
|
611 |
return *this; |
|
612 |
} |
|
861 |
InsertIterator& operator*() { return *this; } |
|
862 |
InsertIterator& operator++() { return *this; } |
|
863 |
InsertIterator operator++(int) { return *this; } |
|
613 | 864 |
|
614 |
MappedOutputIterator& operator++() { |
|
615 |
++base; |
|
616 |
return *this; |
|
617 |
} |
|
618 |
|
|
619 |
MappedOutputIterator operator++(int) { |
|
620 |
MappedOutputIterator tmp(*this); |
|
621 |
++base; |
|
622 |
return tmp; |
|
623 |
} |
|
624 |
|
|
625 |
bool operator==(const MappedOutputIterator& it) const { |
|
626 |
return base == it.base; |
|
627 |
} |
|
628 |
|
|
629 |
bool operator!=(const MappedOutputIterator& it) const { |
|
630 |
return base != it.base; |
|
631 |
} |
|
632 |
|
|
633 |
private: |
|
634 |
Base base; |
|
635 |
const LpSolverBase& lp; |
|
636 | 865 |
}; |
637 | 866 |
|
638 |
template <typename Expr> |
|
639 |
class MappedInputIterator { |
|
867 |
class ExprIterator { |
|
868 |
private: |
|
869 |
std::map<int, Value>::const_iterator _host_it; |
|
870 |
const _solver_bits::VarIndex& _index; |
|
640 | 871 |
public: |
641 | 872 |
|
642 |
typedef typename Expr::const_iterator Base; |
|
643 |
|
|
644 |
typedef typename Base::iterator_category iterator_category; |
|
645 |
typedef typename Base::difference_type difference_type; |
|
873 |
typedef std::bidirectional_iterator_tag iterator_category; |
|
874 |
typedef std::ptrdiff_t difference_type; |
|
646 | 875 |
typedef const std::pair<int, Value> value_type; |
647 | 876 |
typedef value_type reference; |
877 |
|
|
648 | 878 |
class pointer { |
649 | 879 |
public: |
... | ... |
@@ -654,9 +884,10 @@ |
654 | 884 |
}; |
655 | 885 |
|
656 |
MappedInputIterator(const Base& _base, const LpSolverBase& _lp) |
|
657 |
: base(_base), lp(_lp) {} |
|
886 |
ExprIterator(const std::map<int, Value>::const_iterator& host_it, |
|
887 |
const _solver_bits::VarIndex& index) |
|
888 |
: _host_it(host_it), _index(index) {} |
|
658 | 889 |
|
659 | 890 |
reference operator*() { |
660 |
return std::make_pair( |
|
891 |
return std::make_pair(_index(_host_it->first), _host_it->second); |
|
661 | 892 |
} |
662 | 893 |
|
... | ... |
@@ -665,69 +896,35 @@ |
665 | 896 |
} |
666 | 897 |
|
667 |
MappedInputIterator& operator++() { |
|
668 |
++base; |
|
669 |
return *this; |
|
898 |
ExprIterator& operator++() { ++_host_it; return *this; } |
|
899 |
ExprIterator operator++(int) { |
|
900 |
ExprIterator tmp(*this); ++_host_it; return tmp; |
|
670 | 901 |
} |
671 | 902 |
|
672 |
MappedInputIterator operator++(int) { |
|
673 |
MappedInputIterator tmp(*this); |
|
674 |
++base; |
|
675 |
return tmp; |
|
903 |
ExprIterator& operator--() { --_host_it; return *this; } |
|
904 |
ExprIterator operator--(int) { |
|
905 |
ExprIterator tmp(*this); --_host_it; return tmp; |
|
676 | 906 |
} |
677 | 907 |
|
678 |
bool operator==(const MappedInputIterator& it) const { |
|
679 |
return base == it.base; |
|
908 |
bool operator==(const ExprIterator& it) const { |
|
909 |
return _host_it == it._host_it; |
|
680 | 910 |
} |
681 | 911 |
|
682 |
bool operator!=(const MappedInputIterator& it) const { |
|
683 |
return base != it.base; |
|
912 |
bool operator!=(const ExprIterator& it) const { |
|
913 |
return _host_it != it._host_it; |
|
684 | 914 |
} |
685 | 915 |
|
686 |
private: |
|
687 |
Base base; |
|
688 |
const LpSolverBase& lp; |
|
689 | 916 |
}; |
690 | 917 |
|
691 | 918 |
protected: |
692 | 919 |
|
693 |
/// STL compatible iterator for lp col |
|
694 |
typedef MappedInputIterator<Expr> ConstRowIterator; |
|
695 |
/// STL compatible iterator for lp row |
|
696 |
typedef MappedInputIterator<DualExpr> ConstColIterator; |
|
920 |
//Abstract virtual functions |
|
921 |
virtual LpBase* _newSolver() const = 0; |
|
922 |
virtual LpBase* _cloneSolver() const = 0; |
|
697 | 923 |
|
698 |
/// STL compatible iterator for lp col |
|
699 |
typedef MappedOutputIterator<Expr> RowIterator; |
|
700 |
/// STL compatible iterator for lp row |
|
701 |
typedef MappedOutputIterator<DualExpr> ColIterator; |
|
924 |
virtual int _addColId(int col) { return cols.addIndex(col); } |
|
925 |
virtual int _addRowId(int row) { return rows.addIndex(row); } |
|
702 | 926 |
|
703 |
//Abstract virtual functions |
|
704 |
virtual LpSolverBase* _newLp() = 0; |
|
705 |
virtual LpSolverBase* _copyLp(){ |
|
706 |
LpSolverBase* newlp = _newLp(); |
|
707 |
|
|
708 |
std::map<Col, Col> ref; |
|
709 |
for (LpSolverBase::ColIt it(*this); it != INVALID; ++it) { |
|
710 |
Col ccol = newlp->addCol(); |
|
711 |
ref[it] = ccol; |
|
712 |
newlp->colName(ccol, colName(it)); |
|
713 |
newlp->colLowerBound(ccol, colLowerBound(it)); |
|
714 |
newlp->colUpperBound(ccol, colUpperBound(it)); |
|
715 |
} |
|
716 |
|
|
717 |
for (LpSolverBase::RowIt it(*this); it != INVALID; ++it) { |
|
718 |
Expr e = row(it), ce; |
|
719 |
for (Expr::iterator jt = e.begin(); jt != e.end(); ++jt) { |
|
720 |
ce[ref[jt->first]] = jt->second; |
|
721 |
} |
|
722 |
ce += e.constComp(); |
|
723 |
Row r = newlp->addRow(ce); |
|
724 |
|
|
725 |
double lower, upper; |
|
726 |
getRowBounds(it, lower, upper); |
|
727 |
newlp->rowBounds(r, lower, upper); |
|
728 |
} |
|
729 |
|
|
730 |
return newlp; |
|
731 |
} |
|
927 |
virtual void _eraseColId(int col) { cols.eraseIndex(col); } |
|
928 |
virtual void _eraseRowId(int row) { rows.eraseIndex(row); } |
|
732 | 929 |
|
733 | 930 |
virtual int _addCol() = 0; |
... | ... |
@@ -737,41 +934,45 @@ |
737 | 934 |
virtual void _eraseRow(int row) = 0; |
738 | 935 |
|
739 |
virtual void _getColName(int col, std::string & name) const = 0; |
|
740 |
virtual void _setColName(int col, const std::string & name) = 0; |
|
936 |
virtual void _getColName(int col, std::string& name) const = 0; |
|
937 |
virtual void _setColName(int col, const std::string& name) = 0; |
|
741 | 938 |
virtual int _colByName(const std::string& name) const = 0; |
742 | 939 |
|
743 |
virtual void _setRowCoeffs(int i, ConstRowIterator b, |
|
744 |
ConstRowIterator e) = 0; |
|
745 |
virtual void _getRowCoeffs(int i, RowIterator b) const = 0; |
|
746 |
virtual void _setColCoeffs(int i, ConstColIterator b, |
|
747 |
ConstColIterator e) = 0; |
|
748 |
virtual void _getColCoeffs(int i, ColIterator b) const = 0; |
|
940 |
virtual void _getRowName(int row, std::string& name) const = 0; |
|
941 |
virtual void _setRowName(int row, const std::string& name) = 0; |
|
942 |
virtual int _rowByName(const std::string& name) const = 0; |
|
943 |
|
|
944 |
virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e) = 0; |
|
945 |
virtual void _getRowCoeffs(int i, InsertIterator b) const = 0; |
|
946 |
|
|
947 |
virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e) = 0; |
|
948 |
virtual void _getColCoeffs(int i, InsertIterator b) const = 0; |
|
949 |
|
|
749 | 950 |
virtual void _setCoeff(int row, int col, Value value) = 0; |
750 | 951 |
virtual Value _getCoeff(int row, int col) const = 0; |
952 |
|
|
751 | 953 |
virtual void _setColLowerBound(int i, Value value) = 0; |
752 | 954 |
virtual Value _getColLowerBound(int i) const = 0; |
955 |
|
|
753 | 956 |
virtual void _setColUpperBound(int i, Value value) = 0; |
754 | 957 |
virtual Value _getColUpperBound(int i) const = 0; |
755 |
virtual void _setRowBounds(int i, Value lower, Value upper) = 0; |
|
756 |
virtual void _getRowBounds(int i, Value &lower, Value &upper) const = 0; |
|
958 |
|
|
959 |
virtual void _setRowLowerBound(int i, Value value) = 0; |
|
960 |
virtual Value _getRowLowerBound(int i) const = 0; |
|
961 |
|
|
962 |
virtual void _setRowUpperBound(int i, Value value) = 0; |
|
963 |
virtual Value _getRowUpperBound(int i) const = 0; |
|
964 |
|
|
965 |
virtual void _setObjCoeffs(ExprIterator b, ExprIterator e) = 0; |
|
966 |
virtual void _getObjCoeffs(InsertIterator b) const = 0; |
|
757 | 967 |
|
758 | 968 |
virtual void _setObjCoeff(int i, Value obj_coef) = 0; |
759 | 969 |
virtual Value _getObjCoeff(int i) const = 0; |
760 |
virtual void _clearObj()=0; |
|
761 | 970 |
|
762 |
virtual SolveExitStatus _solve() = 0; |
|
763 |
virtual Value _getPrimal(int i) const = 0; |
|
764 |
virtual Value _getDual(int i) const = 0; |
|
765 |
virtual Value _getPrimalValue() const = 0; |
|
766 |
virtual bool _isBasicCol(int i) const = 0; |
|
767 |
virtual SolutionStatus _getPrimalStatus() const = 0; |
|
768 |
virtual SolutionStatus _getDualStatus() const = 0; |
|
769 |
virtual ProblemTypes _getProblemType() const = 0; |
|
971 |
virtual void _setSense(Sense) = 0; |
|
972 |
virtual Sense _getSense() const = 0; |
|
770 | 973 |
|
771 |
virtual void _setMax() = 0; |
|
772 |
virtual void _setMin() = 0; |
|
974 |
virtual void _clear() = 0; |
|
773 | 975 |
|
774 |
|
|
775 |
virtual bool _isMax() const = 0; |
|
976 |
virtual const char* _solverName() const = 0; |
|
776 | 977 |
|
777 | 978 |
//Own protected stuff |
... | ... |
@@ -780,16 +981,18 @@ |
780 | 981 |
Value obj_const_comp; |
781 | 982 |
|
983 |
LpBase() : rows(), cols(), obj_const_comp(0) {} |
|
984 |
|
|
782 | 985 |
public: |
783 | 986 |
|
784 |
///\e |
|
785 |
LpSolverBase() : obj_const_comp(0) {} |
|
786 |
|
|
787 |
///\e |
|
788 |
|
|
987 |
/// Virtual destructor |
|
988 |
virtual ~LpBase() {} |
|
789 | 989 |
|
790 | 990 |
///Creates a new LP problem |
791 |
|
|
991 |
LpBase* newSolver() {return _newSolver();} |
|
792 | 992 |
///Makes a copy of the LP problem |
793 |
|
|
993 |
LpBase* cloneSolver() {return _cloneSolver();} |
|
994 |
|
|
995 |
///Gives back the name of the solver. |
|
996 |
const char* solverName() const {return _solverName();} |
|
794 | 997 |
|
795 | 998 |
///\name Build up and modify the LP |
... | ... |
@@ -798,30 +1001,26 @@ |
798 | 1001 |
|
799 | 1002 |
///Add a new empty column (i.e a new variable) to the LP |
800 |
Col addCol() { Col c; |
|
1003 |
Col addCol() { Col c; c._id = _addColId(_addCol()); return c;} |
|
801 | 1004 |
|
802 |
///\brief Adds several new columns |
|
803 |
///(i.e a variables) at once |
|
1005 |
///\brief Adds several new columns (i.e variables) at once |
|
804 | 1006 |
/// |
805 |
///This magic function takes a container as its argument |
|
806 |
///and fills its elements |
|
807 |
/// |
|
1007 |
///This magic function takes a container as its argument and fills |
|
1008 |
///its elements with new columns (i.e. variables) |
|
808 | 1009 |
///\param t can be |
809 | 1010 |
///- a standard STL compatible iterable container with |
810 |
///\ref Col as its \c values_type |
|
811 |
///like |
|
1011 |
///\ref Col as its \c values_type like |
|
812 | 1012 |
///\code |
813 |
///std::vector<LpSolverBase::Col> |
|
814 |
///std::list<LpSolverBase::Col> |
|
1013 |
///std::vector<LpBase::Col> |
|
1014 |
///std::list<LpBase::Col> |
|
815 | 1015 |
///\endcode |
816 | 1016 |
///- a standard STL compatible iterable container with |
817 |
///\ref Col as its \c mapped_type |
|
818 |
///like |
|
1017 |
///\ref Col as its \c mapped_type like |
|
819 | 1018 |
///\code |
820 |
///std::map<AnyType, |
|
1019 |
///std::map<AnyType,LpBase::Col> |
|
821 | 1020 |
///\endcode |
822 | 1021 |
///- an iterable lemon \ref concepts::WriteMap "write map" like |
823 | 1022 |
///\code |
824 |
///ListGraph::NodeMap<LpSolverBase::Col> |
|
825 |
///ListGraph::EdgeMap<LpSolverBase::Col> |
|
1023 |
///ListGraph::NodeMap<LpBase::Col> |
|
1024 |
///ListGraph::ArcMap<LpBase::Col> |
|
826 | 1025 |
///\endcode |
827 | 1026 |
///\return The number of the created column. |
... | ... |
@@ -831,5 +1030,5 @@ |
831 | 1030 |
#else |
832 | 1031 |
template<class T> |
833 |
typename enable_if<typename T::value_type:: |
|
1032 |
typename enable_if<typename T::value_type::LpCol,int>::type |
|
834 | 1033 |
addColSet(T &t,dummy<0> = 0) { |
835 | 1034 |
int s=0; |
... | ... |
@@ -838,5 +1037,5 @@ |
838 | 1037 |
} |
839 | 1038 |
template<class T> |
840 |
typename enable_if<typename T::value_type::second_type:: |
|
1039 |
typename enable_if<typename T::value_type::second_type::LpCol, |
|
841 | 1040 |
int>::type |
842 | 1041 |
addColSet(T &t,dummy<1> = 1) { |
... | ... |
@@ -849,5 +1048,5 @@ |
849 | 1048 |
} |
850 | 1049 |
template<class T> |
851 |
typename enable_if<typename T::MapIt::Value:: |
|
1050 |
typename enable_if<typename T::MapIt::Value::LpCol, |
|
852 | 1051 |
int>::type |
853 | 1052 |
addColSet(T &t,dummy<2> = 2) { |
... | ... |
@@ -867,17 +1066,17 @@ |
867 | 1066 |
///\param e is a dual linear expression (see \ref DualExpr) |
868 | 1067 |
///a better one. |
869 |
void col(Col c,const DualExpr &e) { |
|
1068 |
void col(Col c, const DualExpr &e) { |
|
870 | 1069 |
e.simplify(); |
871 |
_setColCoeffs(_lpId(c), ConstColIterator(e.begin(), *this), |
|
872 |
ConstColIterator(e.end(), *this)); |
|
1070 |
_setColCoeffs(cols(id(c)), ExprIterator(e.comps.begin(), cols), |
|
1071 |
ExprIterator(e.comps.end(), cols)); |
|
873 | 1072 |
} |
874 | 1073 |
|
875 | 1074 |
///Get a column (i.e a dual constraint) of the LP |
876 | 1075 |
|
877 |
///\param |
|
1076 |
///\param c is the column to get |
|
878 | 1077 |
///\return the dual expression associated to the column |
879 | 1078 |
DualExpr col(Col c) const { |
880 | 1079 |
DualExpr e; |
881 |
_getColCoeffs( |
|
1080 |
_getColCoeffs(cols(id(c)), InsertIterator(e.comps, rows)); |
|
882 | 1081 |
return e; |
883 | 1082 |
} |
... | ... |
@@ -886,5 +1085,5 @@ |
886 | 1085 |
|
887 | 1086 |
///\param e is a dual linear expression (see \ref DualExpr) |
888 |
///\param |
|
1087 |
///\param o is the corresponding component of the objective |
|
889 | 1088 |
///function. It is 0 by default. |
890 | 1089 |
///\return The created column. |
... | ... |
@@ -900,30 +1099,26 @@ |
900 | 1099 |
///This function adds a new empty row (i.e a new constraint) to the LP. |
901 | 1100 |
///\return The created row |
902 |
Row addRow() { Row r; |
|
1101 |
Row addRow() { Row r; r._id = _addRowId(_addRow()); return r;} |
|
903 | 1102 |
|
904 |
///\brief Add several new rows |
|
905 |
///(i.e a constraints) at once |
|
1103 |
///\brief Add several new rows (i.e constraints) at once |
|
906 | 1104 |
/// |
907 |
///This magic function takes a container as its argument |
|
908 |
///and fills its elements |
|
909 |
/// |
|
1105 |
///This magic function takes a container as its argument and fills |
|
1106 |
///its elements with new row (i.e. variables) |
|
910 | 1107 |
///\param t can be |
911 | 1108 |
///- a standard STL compatible iterable container with |
912 |
///\ref Row as its \c values_type |
|
913 |
///like |
|
1109 |
///\ref Row as its \c values_type like |
|
914 | 1110 |
///\code |
915 |
///std::vector<LpSolverBase::Row> |
|
916 |
///std::list<LpSolverBase::Row> |
|
1111 |
///std::vector<LpBase::Row> |
|
1112 |
///std::list<LpBase::Row> |
|
917 | 1113 |
///\endcode |
918 | 1114 |
///- a standard STL compatible iterable container with |
919 |
///\ref Row as its \c mapped_type |
|
920 |
///like |
|
1115 |
///\ref Row as its \c mapped_type like |
|
921 | 1116 |
///\code |
922 |
///std::map<AnyType, |
|
1117 |
///std::map<AnyType,LpBase::Row> |
|
923 | 1118 |
///\endcode |
924 | 1119 |
///- an iterable lemon \ref concepts::WriteMap "write map" like |
925 | 1120 |
///\code |
926 |
///ListGraph::NodeMap<LpSolverBase::Row> |
|
927 |
///ListGraph::EdgeMap<LpSolverBase::Row> |
|
1121 |
///ListGraph::NodeMap<LpBase::Row> |
|
1122 |
///ListGraph::ArcMap<LpBase::Row> |
|
928 | 1123 |
///\endcode |
929 | 1124 |
///\return The number of rows created. |
... | ... |
@@ -933,6 +1128,6 @@ |
933 | 1128 |
#else |
934 | 1129 |
template<class T> |
935 |
typename enable_if<typename T::value_type::LpSolverRow,int>::type |
|
936 |
addRowSet(T &t,dummy<0> = 0) { |
|
1130 |
typename enable_if<typename T::value_type::LpRow,int>::type |
|
1131 |
addRowSet(T &t, dummy<0> = 0) { |
|
937 | 1132 |
int s=0; |
938 | 1133 |
for(typename T::iterator i=t.begin();i!=t.end();++i) {*i=addRow();s++;} |
... | ... |
@@ -940,7 +1135,6 @@ |
940 | 1135 |
} |
941 | 1136 |
template<class T> |
942 |
typename enable_if<typename T::value_type::second_type::LpSolverRow, |
|
943 |
int>::type |
|
944 |
|
|
1137 |
typename enable_if<typename T::value_type::second_type::LpRow, int>::type |
|
1138 |
addRowSet(T &t, dummy<1> = 1) { |
|
945 | 1139 |
int s=0; |
946 | 1140 |
for(typename T::iterator i=t.begin();i!=t.end();++i) { |
... | ... |
@@ -951,7 +1145,6 @@ |
951 | 1145 |
} |
952 | 1146 |
template<class T> |
953 |
typename enable_if<typename T::MapIt::Value::LpSolverRow, |
|
954 |
int>::type |
|
955 |
|
|
1147 |
typename enable_if<typename T::MapIt::Value::LpRow, int>::type |
|
1148 |
addRowSet(T &t, dummy<2> = 2) { |
|
956 | 1149 |
int s=0; |
957 | 1150 |
for(typename T::MapIt i(t); i!=INVALID; ++i) |
... | ... |
@@ -970,13 +1163,10 @@ |
970 | 1163 |
///\param e is a linear expression (see \ref Expr) |
971 | 1164 |
///\param u is the upper bound (\ref INF means no bound) |
972 |
///\bug This is a temporary function. The interface will change to |
|
973 |
///a better one. |
|
974 |
///\todo Option to control whether a constraint with a single variable is |
|
975 |
///added or not. |
|
976 | 1165 |
void row(Row r, Value l, const Expr &e, Value u) { |
977 | 1166 |
e.simplify(); |
978 |
_setRowCoeffs(_lpId(r), ConstRowIterator(e.begin(), *this), |
|
979 |
ConstRowIterator(e.end(), *this)); |
|
980 |
|
|
1167 |
_setRowCoeffs(rows(id(r)), ExprIterator(e.comps.begin(), cols), |
|
1168 |
ExprIterator(e.comps.end(), cols)); |
|
1169 |
_setRowLowerBound(rows(id(r)),l - *e); |
|
1170 |
_setRowUpperBound(rows(id(r)),u - *e); |
|
981 | 1171 |
} |
982 | 1172 |
|
... | ... |
@@ -997,5 +1187,5 @@ |
997 | 1187 |
Expr row(Row r) const { |
998 | 1188 |
Expr e; |
999 |
_getRowCoeffs( |
|
1189 |
_getRowCoeffs(rows(id(r)), InsertIterator(e.comps, cols)); |
|
1000 | 1190 |
return e; |
1001 | 1191 |
} |
... | ... |
@@ -1007,6 +1197,4 @@ |
1007 | 1197 |
///\param u is the upper bound (\ref INF means no bound) |
1008 | 1198 |
///\return The created row. |
1009 |
///\bug This is a temporary function. The interface will change to |
|
1010 |
///a better one. |
|
1011 | 1199 |
Row addRow(Value l,const Expr &e, Value u) { |
1012 | 1200 |
Row r=addRow(); |
... | ... |
@@ -1024,28 +1212,26 @@ |
1024 | 1212 |
return r; |
1025 | 1213 |
} |
1026 |
///Erase a |
|
1214 |
///Erase a column (i.e a variable) from the LP |
|
1027 | 1215 |
|
1028 |
///\param c is the coloumn to be deleted |
|
1029 |
///\todo Please check this |
|
1030 |
void eraseCol(Col c) { |
|
1031 |
_eraseCol(_lpId(c)); |
|
1032 |
|
|
1216 |
///\param c is the column to be deleted |
|
1217 |
void erase(Col c) { |
|
1218 |
_eraseCol(cols(id(c))); |
|
1219 |
_eraseColId(cols(id(c))); |
|
1033 | 1220 |
} |
1034 |
///Erase a |
|
1221 |
///Erase a row (i.e a constraint) from the LP |
|
1035 | 1222 |
|
1036 | 1223 |
///\param r is the row to be deleted |
1037 |
///\todo Please check this |
|
1038 |
void eraseRow(Row r) { |
|
1039 |
_eraseRow(_lpId(r)); |
|
1040 |
rows.eraseId(r.id); |
|
1224 |
void erase(Row r) { |
|
1225 |
_eraseRow(rows(id(r))); |
|
1226 |
_eraseRowId(rows(id(r))); |
|
1041 | 1227 |
} |
1042 | 1228 |
|
1043 | 1229 |
/// Get the name of a column |
1044 | 1230 |
|
1045 |
///\param c is the coresponding |
|
1231 |
///\param c is the coresponding column |
|
1046 | 1232 |
///\return The name of the colunm |
1047 | 1233 |
std::string colName(Col c) const { |
1048 | 1234 |
std::string name; |
1049 |
_getColName( |
|
1235 |
_getColName(cols(id(c)), name); |
|
1050 | 1236 |
return name; |
1051 | 1237 |
} |
... | ... |
@@ -1053,8 +1239,8 @@ |
1053 | 1239 |
/// Set the name of a column |
1054 | 1240 |
|
1055 |
///\param c is the coresponding |
|
1241 |
///\param c is the coresponding column |
|
1056 | 1242 |
///\param name The name to be given |
1057 | 1243 |
void colName(Col c, const std::string& name) { |
1058 |
_setColName( |
|
1244 |
_setColName(cols(id(c)), name); |
|
1059 | 1245 |
} |
1060 | 1246 |
|
... | ... |
@@ -1065,5 +1251,32 @@ |
1065 | 1251 |
Col colByName(const std::string& name) const { |
1066 | 1252 |
int k = _colByName(name); |
1067 |
return k != -1 ? Col(cols |
|
1253 |
return k != -1 ? Col(cols[k]) : Col(INVALID); |
|
1254 |
} |
|
1255 |
|
|
1256 |
/// Get the name of a row |
|
1257 |
|
|
1258 |
///\param r is the coresponding row |
|
1259 |
///\return The name of the row |
|
1260 |
std::string rowName(Row r) const { |
|
1261 |
std::string name; |
|
1262 |
_getRowName(rows(id(r)), name); |
|
1263 |
return name; |
|
1264 |
} |
|
1265 |
|
|
1266 |
/// Set the name of a row |
|
1267 |
|
|
1268 |
///\param r is the coresponding row |
|
1269 |
///\param name The name to be given |
|
1270 |
void rowName(Row r, const std::string& name) { |
|
1271 |
_setRowName(rows(id(r)), name); |
|
1272 |
} |
|
1273 |
|
|
1274 |
/// Get the row by its name |
|
1275 |
|
|
1276 |
///\param name The name of the row |
|
1277 |
///\return the proper row or \c INVALID |
|
1278 |
Row rowByName(const std::string& name) const { |
|
1279 |
int k = _rowByName(name); |
|
1280 |
return k != -1 ? Row(rows[k]) : Row(INVALID); |
|
1068 | 1281 |
} |
1069 | 1282 |
|
... | ... |
@@ -1071,19 +1284,17 @@ |
1071 | 1284 |
|
1072 | 1285 |
///\param r is the row of the element to be modified |
1073 |
///\param c is the |
|
1286 |
///\param c is the column of the element to be modified |
|
1074 | 1287 |
///\param val is the new value of the coefficient |
1075 |
|
|
1076 | 1288 |
void coeff(Row r, Col c, Value val) { |
1077 |
_setCoeff( |
|
1289 |
_setCoeff(rows(id(r)),cols(id(c)), val); |
|
1078 | 1290 |
} |
1079 | 1291 |
|
1080 | 1292 |
/// Get an element of the coefficient matrix of the LP |
1081 | 1293 |
|
1082 |
///\param r is the row of the element in question |
|
1083 |
///\param c is the coloumn of the element in question |
|
1294 |
///\param r is the row of the element |
|
1295 |
///\param c is the column of the element |
|
1084 | 1296 |
///\return the corresponding coefficient |
1085 |
|
|
1086 | 1297 |
Value coeff(Row r, Col c) const { |
1087 |
return _getCoeff( |
|
1298 |
return _getCoeff(rows(id(r)),cols(id(c))); |
|
1088 | 1299 |
} |
1089 | 1300 |
|
... | ... |
@@ -1094,24 +1305,24 @@ |
1094 | 1305 |
/// Value or -\ref INF. |
1095 | 1306 |
void colLowerBound(Col c, Value value) { |
1096 |
_setColLowerBound( |
|
1307 |
_setColLowerBound(cols(id(c)),value); |
|
1097 | 1308 |
} |
1098 | 1309 |
|
1099 | 1310 |
/// Get the lower bound of a column (i.e a variable) |
1100 | 1311 |
|
1101 |
/// This function returns the lower bound for column (variable) \ |
|
1312 |
/// This function returns the lower bound for column (variable) \c c |
|
1102 | 1313 |
/// (this might be -\ref INF as well). |
1103 |
///\return The lower bound for |
|
1314 |
///\return The lower bound for column \c c |
|
1104 | 1315 |
Value colLowerBound(Col c) const { |
1105 |
return _getColLowerBound( |
|
1316 |
return _getColLowerBound(cols(id(c))); |
|
1106 | 1317 |
} |
1107 | 1318 |
|
1108 | 1319 |
///\brief Set the lower bound of several columns |
1109 |
///(i.e |
|
1320 |
///(i.e variables) at once |
|
1110 | 1321 |
/// |
1111 | 1322 |
///This magic function takes a container as its argument |
1112 | 1323 |
///and applies the function on all of its elements. |
1113 |
/// The lower bound of a variable (column) has to be given by an |
|
1114 |
/// extended number of type Value, i.e. a finite number of type |
|
1115 |
/// |
|
1324 |
///The lower bound of a variable (column) has to be given by an |
|
1325 |
///extended number of type Value, i.e. a finite number of type |
|
1326 |
///Value or -\ref INF. |
|
1116 | 1327 |
#ifdef DOXYGEN |
1117 | 1328 |
template<class T> |
... | ... |
@@ -1119,5 +1330,5 @@ |
1119 | 1330 |
#else |
1120 | 1331 |
template<class T> |
1121 |
typename enable_if<typename T::value_type:: |
|
1332 |
typename enable_if<typename T::value_type::LpCol,void>::type |
|
1122 | 1333 |
colLowerBound(T &t, Value value,dummy<0> = 0) { |
1123 | 1334 |
for(typename T::iterator i=t.begin();i!=t.end();++i) { |
... | ... |
@@ -1126,5 +1337,5 @@ |
1126 | 1337 |
} |
1127 | 1338 |
template<class T> |
1128 |
typename enable_if<typename T::value_type::second_type:: |
|
1339 |
typename enable_if<typename T::value_type::second_type::LpCol, |
|
1129 | 1340 |
void>::type |
1130 | 1341 |
colLowerBound(T &t, Value value,dummy<1> = 1) { |
... | ... |
@@ -1134,5 +1345,5 @@ |
1134 | 1345 |
} |
1135 | 1346 |
template<class T> |
1136 |
typename enable_if<typename T::MapIt::Value:: |
|
1347 |
typename enable_if<typename T::MapIt::Value::LpCol, |
|
1137 | 1348 |
void>::type |
1138 | 1349 |
colLowerBound(T &t, Value value,dummy<2> = 2) { |
... | ... |
@@ -1149,24 +1360,24 @@ |
1149 | 1360 |
/// Value or \ref INF. |
1150 | 1361 |
void colUpperBound(Col c, Value value) { |
1151 |
_setColUpperBound( |
|
1362 |
_setColUpperBound(cols(id(c)),value); |
|
1152 | 1363 |
}; |
1153 | 1364 |
|
1154 | 1365 |
/// Get the upper bound of a column (i.e a variable) |
1155 | 1366 |
|
1156 |
/// This function returns the upper bound for column (variable) \ |
|
1367 |
/// This function returns the upper bound for column (variable) \c c |
|
1157 | 1368 |
/// (this might be \ref INF as well). |
1158 |
///\return The upper bound for |
|
1369 |
/// \return The upper bound for column \c c |
|
1159 | 1370 |
Value colUpperBound(Col c) const { |
1160 |
return _getColUpperBound( |
|
1371 |
return _getColUpperBound(cols(id(c))); |
|
1161 | 1372 |
} |
1162 | 1373 |
|
1163 | 1374 |
///\brief Set the upper bound of several columns |
1164 |
///(i.e |
|
1375 |
///(i.e variables) at once |
|
1165 | 1376 |
/// |
1166 | 1377 |
///This magic function takes a container as its argument |
1167 | 1378 |
///and applies the function on all of its elements. |
1168 |
/// The upper bound of a variable (column) has to be given by an |
|
1169 |
/// extended number of type Value, i.e. a finite number of type |
|
1170 |
/// |
|
1379 |
///The upper bound of a variable (column) has to be given by an |
|
1380 |
///extended number of type Value, i.e. a finite number of type |
|
1381 |
///Value or \ref INF. |
|
1171 | 1382 |
#ifdef DOXYGEN |
1172 | 1383 |
template<class T> |
... | ... |
@@ -1174,5 +1385,5 @@ |
1174 | 1385 |
#else |
1175 | 1386 |
template<class T> |
1176 |
typename enable_if<typename T::value_type:: |
|
1387 |
typename enable_if<typename T::value_type::LpCol,void>::type |
|
1177 | 1388 |
colUpperBound(T &t, Value value,dummy<0> = 0) { |
1178 | 1389 |
for(typename T::iterator i=t.begin();i!=t.end();++i) { |
... | ... |
@@ -1181,5 +1392,5 @@ |
1181 | 1392 |
} |
1182 | 1393 |
template<class T> |
1183 |
typename enable_if<typename T::value_type::second_type:: |
|
1394 |
typename enable_if<typename T::value_type::second_type::LpCol, |
|
1184 | 1395 |
void>::type |
1185 | 1396 |
colUpperBound(T &t, Value value,dummy<1> = 1) { |
... | ... |
@@ -1189,5 +1400,5 @@ |
1189 | 1400 |
} |
1190 | 1401 |
template<class T> |
1191 |
typename enable_if<typename T::MapIt::Value:: |
|
1402 |
typename enable_if<typename T::MapIt::Value::LpCol, |
|
1192 | 1403 |
void>::type |
1193 | 1404 |
colUpperBound(T &t, Value value,dummy<2> = 2) { |
... | ... |
@@ -1205,10 +1416,10 @@ |
1205 | 1416 |
/// Value, -\ref INF or \ref INF. |
1206 | 1417 |
void colBounds(Col c, Value lower, Value upper) { |
1207 |
_setColLowerBound(_lpId(c),lower); |
|
1208 |
_setColUpperBound(_lpId(c),upper); |
|
1418 |
_setColLowerBound(cols(id(c)),lower); |
|
1419 |
_setColUpperBound(cols(id(c)),upper); |
|
1209 | 1420 |
} |
1210 | 1421 |
|
1211 | 1422 |
///\brief Set the lower and the upper bound of several columns |
1212 |
///(i.e |
|
1423 |
///(i.e variables) at once |
|
1213 | 1424 |
/// |
1214 | 1425 |
///This magic function takes a container as its argument |
... | ... |
@@ -1223,5 +1434,5 @@ |
1223 | 1434 |
#else |
1224 | 1435 |
template<class T> |
1225 |
typename enable_if<typename T::value_type:: |
|
1436 |
typename enable_if<typename T::value_type::LpCol,void>::type |
|
1226 | 1437 |
colBounds(T &t, Value lower, Value upper,dummy<0> = 0) { |
1227 | 1438 |
for(typename T::iterator i=t.begin();i!=t.end();++i) { |
... | ... |
@@ -1230,6 +1441,5 @@ |
1230 | 1441 |
} |
1231 | 1442 |
template<class T> |
1232 |
typename enable_if<typename T::value_type::second_type::LpSolverCol, |
|
1233 |
void>::type |
|
1443 |
typename enable_if<typename T::value_type::second_type::LpCol, void>::type |
|
1234 | 1444 |
colBounds(T &t, Value lower, Value upper,dummy<1> = 1) { |
1235 | 1445 |
for(typename T::iterator i=t.begin();i!=t.end();++i) { |
... | ... |
@@ -1238,6 +1448,5 @@ |
1238 | 1448 |
} |
1239 | 1449 |
template<class T> |
1240 |
typename enable_if<typename T::MapIt::Value::LpSolverCol, |
|
1241 |
void>::type |
|
1450 |
typename enable_if<typename T::MapIt::Value::LpCol, void>::type |
|
1242 | 1451 |
colBounds(T &t, Value lower, Value upper,dummy<2> = 2) { |
1243 | 1452 |
for(typename T::MapIt i(t); i!=INVALID; ++i){ |
... | ... |
@@ -1247,74 +1456,369 @@ |
1247 | 1456 |
#endif |
1248 | 1457 |
|
1458 |
/// Set the lower bound of a row (i.e a constraint) |
|
1249 | 1459 |
|
1250 |
/// Set the lower and the upper bounds of a row (i.e a constraint) |
|
1251 |
|
|
1252 |
/// The lower and the upper bound of a constraint (row) have to be |
|
1253 |
/// given by an extended number of type Value, i.e. a finite |
|
1254 |
/// number of type Value, -\ref INF or \ref INF. There is no |
|
1255 |
/// separate function for the lower and the upper bound because |
|
1256 |
/// that would have been hard to implement for CPLEX. |
|
1257 |
void rowBounds(Row c, Value lower, Value upper) { |
|
1258 |
|
|
1460 |
/// The lower bound of a constraint (row) has to be given by an |
|
1461 |
/// extended number of type Value, i.e. a finite number of type |
|
1462 |
/// Value or -\ref INF. |
|
1463 |
void rowLowerBound(Row r, Value value) { |
|
1464 |
_setRowLowerBound(rows(id(r)),value); |
|
1259 | 1465 |
} |
1260 | 1466 |
|
1261 |
/// Get the lower |
|
1467 |
/// Get the lower bound of a row (i.e a constraint) |
|
1262 | 1468 |
|
1263 |
/// The lower and the upper bound of |
|
1264 |
/// a constraint (row) are |
|
1265 |
/// extended numbers of type Value, i.e. finite numbers of type |
|
1266 |
/// Value, -\ref INF or \ref INF. |
|
1267 |
/// \todo There is no separate function for the |
|
1268 |
/// lower and the upper bound because we had problems with the |
|
1269 |
/// implementation of the setting functions for CPLEX: |
|
1270 |
/// check out whether this can be done for these functions. |
|
1271 |
void getRowBounds(Row c, Value &lower, Value &upper) const { |
|
1272 |
_getRowBounds(_lpId(c),lower, upper); |
|
1469 |
/// This function returns the lower bound for row (constraint) \c c |
|
1470 |
/// (this might be -\ref INF as well). |
|
1471 |
///\return The lower bound for row \c r |
|
1472 |
Value rowLowerBound(Row r) const { |
|
1473 |
return _getRowLowerBound(rows(id(r))); |
|
1474 |
} |
|
1475 |
|
|
1476 |
/// Set the upper bound of a row (i.e a constraint) |
|
1477 |
|
|
1478 |
/// The upper bound of a constraint (row) has to be given by an |
|
1479 |
/// extended number of type Value, i.e. a finite number of type |
|
1480 |
/// Value or -\ref INF. |
|
1481 |
void rowUpperBound(Row r, Value value) { |
|
1482 |
_setRowUpperBound(rows(id(r)),value); |
|
1483 |
} |
|
1484 |
|
|
1485 |
/// Get the upper bound of a row (i.e a constraint) |
|
1486 |
|
|
1487 |
/// This function returns the upper bound for row (constraint) \c c |
|
1488 |
/// (this might be -\ref INF as well). |
|
1489 |
///\return The upper bound for row \c r |
|
1490 |
Value rowUpperBound(Row r) const { |
|
1491 |
return _getRowUpperBound(rows(id(r))); |
|
1273 | 1492 |
} |
1274 | 1493 |
|
1275 | 1494 |
///Set an element of the objective function |
1276 |
void objCoeff(Col c, Value v) {_setObjCoeff( |
|
1495 |
void objCoeff(Col c, Value v) {_setObjCoeff(cols(id(c)),v); }; |
|
1277 | 1496 |
|
1278 | 1497 |
///Get an element of the objective function |
1279 |
Value objCoeff(Col c) const { return _getObjCoeff( |
|
1498 |
Value objCoeff(Col c) const { return _getObjCoeff(cols(id(c))); }; |
|
1280 | 1499 |
|
1281 | 1500 |
///Set the objective function |
1282 | 1501 |
|
1283 | 1502 |
///\param e is a linear expression of type \ref Expr. |
1284 |
void obj(Expr e) { |
|
1285 |
_clearObj(); |
|
1286 |
for (Expr::iterator i=e.begin(); i!=e.end(); ++i) |
|
1287 |
objCoeff((*i).first,(*i).second); |
|
1288 |
|
|
1503 |
/// |
|
1504 |
void obj(const Expr& e) { |
|
1505 |
_setObjCoeffs(ExprIterator(e.comps.begin(), cols), |
|
1506 |
ExprIterator(e.comps.end(), cols)); |
|
1507 |
obj_const_comp = *e; |
|
1289 | 1508 |
} |
1290 | 1509 |
|
1291 | 1510 |
///Get the objective function |
1292 | 1511 |
|
1293 |
///\return the objective function as a linear expression of type |
|
1512 |
///\return the objective function as a linear expression of type |
|
1513 |
///Expr. |
|
1294 | 1514 |
Expr obj() const { |
1295 | 1515 |
Expr e; |
1296 |
for (ColIt it(*this); it != INVALID; ++it) { |
|
1297 |
double c = objCoeff(it); |
|
1298 |
if (c != 0.0) { |
|
1299 |
e.insert(std::make_pair(it, c)); |
|
1300 |
} |
|
1301 |
} |
|
1516 |
_getObjCoeffs(InsertIterator(e.comps, cols)); |
|
1517 |
*e = obj_const_comp; |
|
1302 | 1518 |
return e; |
1303 | 1519 |
} |
1304 | 1520 |
|
1305 | 1521 |
|
1306 |
///Maximize |
|
1307 |
void max() { _setMax(); } |
|
1308 |
///Minimize |
|
1309 |
void min() { _setMin(); } |
|
1522 |
///Set the direction of optimization |
|
1523 |
void sense(Sense sense) { _setSense(sense); } |
|
1310 | 1524 |
|
1311 |
///Query function: is this a maximization problem? |
|
1312 |
bool isMax() const {return _isMax(); } |
|
1525 |
///Query the direction of the optimization |
|
1526 |
Sense sense() const {return _getSense(); } |
|
1313 | 1527 |
|
1314 |
///Query function: is this a minimization problem? |
|
1315 |
bool isMin() const {return !isMax(); } |
|
1528 |
///Set the sense to maximization |
|
1529 |
void max() { _setSense(MAX); } |
|
1530 |
|
|
1531 |
///Set the sense to maximization |
|
1532 |
void min() { _setSense(MIN); } |
|
1533 |
|
|
1534 |
///Clears the problem |
|
1535 |
void clear() { _clear(); } |
|
1316 | 1536 |
|
1317 | 1537 |
///@} |
1318 | 1538 |
|
1539 |
}; |
|
1540 |
|
|
1541 |
/// Addition |
|
1542 |
|
|
1543 |
///\relates LpBase::Expr |
|
1544 |
/// |
|
1545 |
inline LpBase::Expr operator+(const LpBase::Expr &a, const LpBase::Expr &b) { |
|
1546 |
LpBase::Expr tmp(a); |
|
1547 |
tmp+=b; |
|
1548 |
return tmp; |
|
1549 |
} |
|
1550 |
///Substraction |
|
1551 |
|
|
1552 |
///\relates LpBase::Expr |
|
1553 |
/// |
|
1554 |
inline LpBase::Expr operator-(const LpBase::Expr &a, const LpBase::Expr &b) { |
|
1555 |
LpBase::Expr tmp(a); |
|
1556 |
tmp-=b; |
|
1557 |
return tmp; |
|
1558 |
} |
|
1559 |
///Multiply with constant |
|
1560 |
|
|
1561 |
///\relates LpBase::Expr |
|
1562 |
/// |
|
1563 |
inline LpBase::Expr operator*(const LpBase::Expr &a, const LpBase::Value &b) { |
|
1564 |
LpBase::Expr tmp(a); |
|
1565 |
tmp*=b; |
|
1566 |
return tmp; |
|
1567 |
} |
|
1568 |
|
|
1569 |
///Multiply with constant |
|
1570 |
|
|
1571 |
///\relates LpBase::Expr |
|
1572 |
/// |
|
1573 |
inline LpBase::Expr operator*(const LpBase::Value &a, const LpBase::Expr &b) { |
|
1574 |
LpBase::Expr tmp(b); |
|
1575 |
tmp*=a; |
|
1576 |
return tmp; |
|
1577 |
} |
|
1578 |
///Divide with constant |
|
1579 |
|
|
1580 |
///\relates LpBase::Expr |
|
1581 |
/// |
|
1582 |
inline LpBase::Expr operator/(const LpBase::Expr &a, const LpBase::Value &b) { |
|
1583 |
LpBase::Expr tmp(a); |
|
1584 |
tmp/=b; |
|
1585 |
return tmp; |
|
1586 |
} |
|
1587 |
|
|
1588 |
///Create constraint |
|
1589 |
|
|
1590 |
///\relates LpBase::Constr |
|
1591 |
/// |
|
1592 |
inline LpBase::Constr operator<=(const LpBase::Expr &e, |
|
1593 |
const LpBase::Expr &f) { |
|
1594 |
return LpBase::Constr(0, f - e, LpBase::INF); |
|
1595 |
} |
|
1596 |
|
|
1597 |
///Create constraint |
|
1598 |
|
|
1599 |
///\relates LpBase::Constr |
|
1600 |
/// |
|
1601 |
inline LpBase::Constr operator<=(const LpBase::Value &e, |
|
1602 |
const LpBase::Expr &f) { |
|
1603 |
return LpBase::Constr(e, f, LpBase::NaN); |
|
1604 |
} |
|
1605 |
|
|
1606 |
///Create constraint |
|
1607 |
|
|
1608 |
///\relates LpBase::Constr |
|
1609 |
/// |
|
1610 |
inline LpBase::Constr operator<=(const LpBase::Expr &e, |
|
1611 |
const LpBase::Value &f) { |
|
1612 |
return LpBase::Constr(- LpBase::INF, e, f); |
|
1613 |
} |
|
1614 |
|
|
1615 |
///Create constraint |
|
1616 |
|
|
1617 |
///\relates LpBase::Constr |
|
1618 |
/// |
|
1619 |
inline LpBase::Constr operator>=(const LpBase::Expr &e, |
|
1620 |
const LpBase::Expr &f) { |
|
1621 |
return LpBase::Constr(0, e - f, LpBase::INF); |
|
1622 |
} |
|
1623 |
|
|
1624 |
|
|
1625 |
///Create constraint |
|
1626 |
|
|
1627 |
///\relates LpBase::Constr |
|
1628 |
/// |
|
1629 |
inline LpBase::Constr operator>=(const LpBase::Value &e, |
|
1630 |
const LpBase::Expr &f) { |
|
1631 |
return LpBase::Constr(LpBase::NaN, f, e); |
|
1632 |
} |
|
1633 |
|
|
1634 |
|
|
1635 |
///Create constraint |
|
1636 |
|
|
1637 |
///\relates LpBase::Constr |
|
1638 |
/// |
|
1639 |
inline LpBase::Constr operator>=(const LpBase::Expr &e, |
|
1640 |
const LpBase::Value &f) { |
|
1641 |
return LpBase::Constr(f, e, LpBase::INF); |
|
1642 |
} |
|
1643 |
|
|
1644 |
///Create constraint |
|
1645 |
|
|
1646 |
///\relates LpBase::Constr |
|
1647 |
/// |
|
1648 |
inline LpBase::Constr operator==(const LpBase::Expr &e, |
|
1649 |
const LpBase::Value &f) { |
|
1650 |
return LpBase::Constr(f, e, f); |
|
1651 |
} |
|
1652 |
|
|
1653 |
///Create constraint |
|
1654 |
|
|
1655 |
///\relates LpBase::Constr |
|
1656 |
/// |
|
1657 |
inline LpBase::Constr operator==(const LpBase::Expr &e, |
|
1658 |
const LpBase::Expr &f) { |
|
1659 |
return LpBase::Constr(0, f - e, 0); |
|
1660 |
} |
|
1661 |
|
|
1662 |
///Create constraint |
|
1663 |
|
|
1664 |
///\relates LpBase::Constr |
|
1665 |
/// |
|
1666 |
inline LpBase::Constr operator<=(const LpBase::Value &n, |
|
1667 |
const LpBase::Constr &c) { |
|
1668 |
LpBase::Constr tmp(c); |
|
1669 |
LEMON_ASSERT(std::isnan(tmp.lowerBound()), "Wrong LP constraint"); |
|
1670 |
tmp.lowerBound()=n; |
|
1671 |
return tmp; |
|
1672 |
} |
|
1673 |
///Create constraint |
|
1674 |
|
|
1675 |
///\relates LpBase::Constr |
|
1676 |
/// |
|
1677 |
inline LpBase::Constr operator<=(const LpBase::Constr &c, |
|
1678 |
const LpBase::Value &n) |
|
1679 |
{ |
|
1680 |
LpBase::Constr tmp(c); |
|
1681 |
LEMON_ASSERT(std::isnan(tmp.upperBound()), "Wrong LP constraint"); |
|
1682 |
tmp.upperBound()=n; |
|
1683 |
return tmp; |
|
1684 |
} |
|
1685 |
|
|
1686 |
///Create constraint |
|
1687 |
|
|
1688 |
///\relates LpBase::Constr |
|
1689 |
/// |
|
1690 |
inline LpBase::Constr operator>=(const LpBase::Value &n, |
|
1691 |
const LpBase::Constr &c) { |
|
1692 |
LpBase::Constr tmp(c); |
|
1693 |
LEMON_ASSERT(std::isnan(tmp.upperBound()), "Wrong LP constraint"); |
|
1694 |
tmp.upperBound()=n; |
|
1695 |
return tmp; |
|
1696 |
} |
|
1697 |
///Create constraint |
|
1698 |
|
|
1699 |
///\relates LpBase::Constr |
|
1700 |
/// |
|
1701 |
inline LpBase::Constr operator>=(const LpBase::Constr &c, |
|
1702 |
const LpBase::Value &n) |
|
1703 |
{ |
|
1704 |
LpBase::Constr tmp(c); |
|
1705 |
LEMON_ASSERT(std::isnan(tmp.lowerBound()), "Wrong LP constraint"); |
|
1706 |
tmp.lowerBound()=n; |
|
1707 |
return tmp; |
|
1708 |
} |
|
1709 |
|
|
1710 |
///Addition |
|
1711 |
|
|
1712 |
///\relates LpBase::DualExpr |
|
1713 |
/// |
|
1714 |
inline LpBase::DualExpr operator+(const LpBase::DualExpr &a, |
|
1715 |
const LpBase::DualExpr &b) { |
|
1716 |
LpBase::DualExpr tmp(a); |
|
1717 |
tmp+=b; |
|
1718 |
return tmp; |
|
1719 |
} |
|
1720 |
///Substraction |
|
1721 |
|
|
1722 |
///\relates LpBase::DualExpr |
|
1723 |
/// |
|
1724 |
inline LpBase::DualExpr operator-(const LpBase::DualExpr &a, |
|
1725 |
const LpBase::DualExpr &b) { |
|
1726 |
LpBase::DualExpr tmp(a); |
|
1727 |
tmp-=b; |
|
1728 |
return tmp; |
|
1729 |
} |
|
1730 |
///Multiply with constant |
|
1731 |
|
|
1732 |
///\relates LpBase::DualExpr |
|
1733 |
/// |
|
1734 |
inline LpBase::DualExpr operator*(const LpBase::DualExpr &a, |
|
1735 |
const LpBase::Value &b) { |
|
1736 |
LpBase::DualExpr tmp(a); |
|
1737 |
tmp*=b; |
|
1738 |
return tmp; |
|
1739 |
} |
|
1740 |
|
|
1741 |
///Multiply with constant |
|
1742 |
|
|
1743 |
///\relates LpBase::DualExpr |
|
1744 |
/// |
|
1745 |
inline LpBase::DualExpr operator*(const LpBase::Value &a, |
|
1746 |
const LpBase::DualExpr &b) { |
|
1747 |
LpBase::DualExpr tmp(b); |
|
1748 |
tmp*=a; |
|
1749 |
return tmp; |
|
1750 |
} |
|
1751 |
///Divide with constant |
|
1752 |
|
|
1753 |
///\relates LpBase::DualExpr |
|
1754 |
/// |
|
1755 |
inline LpBase::DualExpr operator/(const LpBase::DualExpr &a, |
|
1756 |
const LpBase::Value &b) { |
|
1757 |
LpBase::DualExpr tmp(a); |
|
1758 |
tmp/=b; |
|
1759 |
return tmp; |
|
1760 |
} |
|
1761 |
|
|
1762 |
/// \ingroup lp_group |
|
1763 |
/// |
|
1764 |
/// \brief Common base class for LP solvers |
|
1765 |
/// |
|
1766 |
/// This class is an abstract base class for LP solvers. This class |
|
1767 |
/// provides a full interface for set and modify an LP problem, |
|
1768 |
/// solve it and retrieve the solution. You can use one of the |
|
1769 |
/// descendants as a concrete implementation, or the \c Lp |
|
1770 |
/// default LP solver. However, if you would like to handle LP |
|
1771 |
/// solvers as reference or pointer in a generic way, you can use |
|
1772 |
/// this class directly. |
|
1773 |
class LpSolver : virtual public LpBase { |
|
1774 |
public: |
|
1775 |
|
|
1776 |
/// The problem types for primal and dual problems |
|
1777 |
enum ProblemType { |
|
1778 |
///Feasible solution hasn't been found (but may exist). |
|
1779 |
UNDEFINED = 0, |
|
1780 |
///The problem has no feasible solution |
|
1781 |
INFEASIBLE = 1, |
|
1782 |
///Feasible solution found |
|
1783 |
FEASIBLE = 2, |
|
1784 |
///Optimal solution exists and found |
|
1785 |
OPTIMAL = 3, |
|
1786 |
///The cost function is unbounded |
|
1787 |
UNBOUNDED = 4 |
|
1788 |
}; |
|
1789 |
|
|
1790 |
///The basis status of variables |
|
1791 |
enum VarStatus { |
|
1792 |
/// The variable is in the basis |
|
1793 |
BASIC, |
|
1794 |
/// The variable is free, but not basic |
|
1795 |
FREE, |
|
1796 |
/// The variable has active lower bound |
|
1797 |
LOWER, |
|
1798 |
/// The variable has active upper bound |
|
1799 |
UPPER, |
|
1800 |
/// The variable is non-basic and fixed |
|
1801 |
FIXED |
|
1802 |
}; |
|
1803 |
|
|
1804 |
protected: |
|
1805 |
|
|
1806 |
virtual SolveExitStatus _solve() = 0; |
|
1807 |
|
|
1808 |
virtual Value _getPrimal(int i) const = 0; |
|
1809 |
virtual Value _getDual(int i) const = 0; |
|
1810 |
|
|
1811 |
virtual Value _getPrimalRay(int i) const = 0; |
|
1812 |
virtual Value _getDualRay(int i) const = 0; |
|
1813 |
|
|
1814 |
virtual Value _getPrimalValue() const = 0; |
|
1815 |
|
|
1816 |
virtual VarStatus _getColStatus(int i) const = 0; |
|
1817 |
virtual VarStatus _getRowStatus(int i) const = 0; |
|
1818 |
|
|
1819 |
virtual ProblemType _getPrimalType() const = 0; |
|
1820 |
virtual ProblemType _getDualType() const = 0; |
|
1821 |
|
|
1822 |
public: |
|
1319 | 1823 |
|
1320 | 1824 |
///\name Solve the LP |
... | ... |
@@ -1327,6 +1831,4 @@ |
1327 | 1831 |
///values and their meanings can be found in the documentation of |
1328 | 1832 |
///\ref SolveExitStatus. |
1329 |
/// |
|
1330 |
///\todo Which method is used to solve the problem |
|
1331 | 1833 |
SolveExitStatus solve() { return _solve(); } |
1332 | 1834 |
|
... | ... |
@@ -1337,47 +1839,92 @@ |
1337 | 1839 |
///@{ |
1338 | 1840 |
|
1339 |
/// The status of the primal problem (the original LP problem) |
|
1340 |
SolutionStatus primalStatus() const { |
|
1341 |
|
|
1841 |
/// The type of the primal problem |
|
1842 |
ProblemType primalType() const { |
|
1843 |
return _getPrimalType(); |
|
1342 | 1844 |
} |
1343 | 1845 |
|
1344 |
/// The status of the dual (of the original LP) problem |
|
1345 |
SolutionStatus dualStatus() const { |
|
1346 |
|
|
1846 |
/// The type of the dual problem |
|
1847 |
ProblemType dualType() const { |
|
1848 |
return _getDualType(); |
|
1347 | 1849 |
} |
1348 | 1850 |
|
1349 |
///The type of the original LP problem |
|
1350 |
ProblemTypes problemType() const { |
|
1351 |
|
|
1851 |
/// Return the primal value of the column |
|
1852 |
|
|
1853 |
/// Return the primal value of the column. |
|
1854 |
/// \pre The problem is solved. |
|
1855 |
Value primal(Col c) const { return _getPrimal(cols(id(c))); } |
|
1856 |
|
|
1857 |
/// Return the primal value of the expression |
|
1858 |
|
|
1859 |
/// Return the primal value of the expression, i.e. the dot |
|
1860 |
/// product of the primal solution and the expression. |
|
1861 |
/// \pre The problem is solved. |
|
1862 |
Value primal(const Expr& e) const { |
|
1863 |
double res = *e; |
|
1864 |
for (Expr::ConstCoeffIt c(e); c != INVALID; ++c) { |
|
1865 |
res += *c * primal(c); |
|
1866 |
} |
|
1867 |
return res; |
|
1352 | 1868 |
} |
1869 |
/// Returns a component of the primal ray |
|
1870 |
|
|
1871 |
/// The primal ray is solution of the modified primal problem, |
|
1872 |
/// where we change each finite bound to 0, and we looking for a |
|
1873 |
/// negative objective value in case of minimization, and positive |
|
1874 |
/// objective value for maximization. If there is such solution, |
|
1875 |
/// that proofs the unsolvability of the dual problem, and if a |
|
1876 |
/// feasible primal solution exists, then the unboundness of |
|
1877 |
/// primal problem. |
|
1878 |
/// |
|
1879 |
/// \pre The problem is solved and the dual problem is infeasible. |
|
1880 |
/// \note Some solvers does not provide primal ray calculation |
|
1881 |
/// functions. |
|
1882 |
Value primalRay(Col c) const { return _getPrimalRay(cols(id(c))); } |
|
1353 | 1883 |
|
1354 |
///\e |
|
1355 |
Value primal(Col c) const { return _getPrimal(_lpId(c)); } |
|
1356 |
///\e |
|
1357 |
Value primal(const Expr& e) const { |
|
1358 |
double res = e.constComp(); |
|
1359 |
for (std::map<Col, double>::const_iterator it = e.begin(); |
|
1360 |
it != e.end(); ++it) { |
|
1361 |
res += _getPrimal(_lpId(it->first)) * it->second; |
|
1884 |
/// Return the dual value of the row |
|
1885 |
|
|
1886 |
/// Return the dual value of the row. |
|
1887 |
/// \pre The problem is solved. |
|
1888 |
Value dual(Row r) const { return _getDual(rows(id(r))); } |
|
1889 |
|
|
1890 |
/// Return the dual value of the dual expression |
|
1891 |
|
|
1892 |
/// Return the dual value of the dual expression, i.e. the dot |
|
1893 |
/// product of the dual solution and the dual expression. |
|
1894 |
/// \pre The problem is solved. |
|
1895 |
Value dual(const DualExpr& e) const { |
|
1896 |
double res = 0.0; |
|
1897 |
for (DualExpr::ConstCoeffIt r(e); r != INVALID; ++r) { |
|
1898 |
res += *r * dual(r); |
|
1362 | 1899 |
} |
1363 | 1900 |
return res; |
1364 | 1901 |
} |
1365 | 1902 |
|
1366 |
///\e |
|
1367 |
Value dual(Row r) const { return _getDual(_lpId(r)); } |
|
1368 |
///\e |
|
1369 |
Value dual(const DualExpr& e) const { |
|
1370 |
double res = 0.0; |
|
1371 |
for (std::map<Row, double>::const_iterator it = e.begin(); |
|
1372 |
it != e.end(); ++it) { |
|
1373 |
res += _getPrimal(_lpId(it->first)) * it->second; |
|
1374 |
} |
|
1375 |
return res; |
|
1376 |
|
|
1903 |
/// Returns a component of the dual ray |
|
1904 |
|
|
1905 |
/// The dual ray is solution of the modified primal problem, where |
|
1906 |
/// we change each finite bound to 0 (i.e. the objective function |
|
1907 |
/// coefficients in the primal problem), and we looking for a |
|
1908 |
/// ositive objective value. If there is such solution, that |
|
1909 |
/// proofs the unsolvability of the primal problem, and if a |
|
1910 |
/// feasible dual solution exists, then the unboundness of |
|
1911 |
/// dual problem. |
|
1912 |
/// |
|
1913 |
/// \pre The problem is solved and the primal problem is infeasible. |
|
1914 |
/// \note Some solvers does not provide dual ray calculation |
|
1915 |
/// functions. |
|
1916 |
Value dualRay(Row r) const { return _getDualRay(rows(id(r))); } |
|
1377 | 1917 |
|
1378 |
///\e |
|
1379 |
bool isBasicCol(Col c) const { return _isBasicCol(_lpId(c)); } |
|
1918 |
/// Return the basis status of the column |
|
1380 | 1919 |
|
1381 |
///\ |
|
1920 |
/// \see VarStatus |
|
1921 |
VarStatus colStatus(Col c) const { return _getColStatus(cols(id(c))); } |
|
1922 |
|
|
1923 |
/// Return the basis status of the row |
|
1924 |
|
|
1925 |
/// \see VarStatus |
|
1926 |
VarStatus rowStatus(Row r) const { return _getRowStatus(rows(id(r))); } |
|
1927 |
|
|
1928 |
///The value of the objective function |
|
1382 | 1929 |
|
1383 | 1930 |
///\return |
... | ... |
@@ -1386,7 +1933,14 @@ |
1386 | 1933 |
///- \ref NaN if no primal solution is found. |
1387 | 1934 |
///- The (finite) objective value if an optimal solution is found. |
1388 |
Value |
|
1935 |
Value primal() const { return _getPrimalValue()+obj_const_comp;} |
|
1389 | 1936 |
///@} |
1390 | 1937 |
|
1938 |
LpSolver* newSolver() {return _newSolver();} |
|
1939 |
LpSolver* cloneSolver() {return _cloneSolver();} |
|
1940 |
|
|
1941 |
protected: |
|
1942 |
|
|
1943 |
virtual LpSolver* _newSolver() const = 0; |
|
1944 |
virtual LpSolver* _cloneSolver() const = 0; |
|
1391 | 1945 |
}; |
1392 | 1946 |
|
... | ... |
@@ -1395,308 +1949,129 @@ |
1395 | 1949 |
/// |
1396 | 1950 |
/// \brief Common base class for MIP solvers |
1397 |
/// \todo Much more docs |
|
1398 |
class MipSolverBase : virtual public LpSolverBase{ |
|
1951 |
/// |
|
1952 |
/// This class is an abstract base class for MIP solvers. This class |
|
1953 |
/// provides a full interface for set and modify an MIP problem, |
|
1954 |
/// solve it and retrieve the solution. You can use one of the |
|
1955 |
/// descendants as a concrete implementation, or the \c Lp |
|
1956 |
/// default MIP solver. However, if you would like to handle MIP |
|
1957 |
/// solvers as reference or pointer in a generic way, you can use |
|
1958 |
/// this class directly. |
|
1959 |
class MipSolver : virtual public LpBase { |
|
1399 | 1960 |
public: |
1400 | 1961 |
|
1401 |
/// |
|
1962 |
/// The problem types for MIP problems |
|
1963 |
enum ProblemType { |
|
1964 |
///Feasible solution hasn't been found (but may exist). |
|
1965 |
UNDEFINED = 0, |
|
1966 |
///The problem has no feasible solution |
|
1967 |
INFEASIBLE = 1, |
|
1968 |
///Feasible solution found |
|
1969 |
FEASIBLE = 2, |
|
1970 |
///Optimal solution exists and found |
|
1971 |
OPTIMAL = 3, |
|
1972 |
///The cost function is unbounded |
|
1973 |
/// |
|
1974 |
///The Mip or at least the relaxed problem is unbounded |
|
1975 |
UNBOUNDED = 4 |
|
1976 |
}; |
|
1977 |
|
|
1978 |
///\name Solve the MIP |
|
1979 |
|
|
1980 |
///@{ |
|
1981 |
|
|
1982 |
/// Solve the MIP problem at hand |
|
1983 |
/// |
|
1984 |
///\return The result of the optimization procedure. Possible |
|
1985 |
///values and their meanings can be found in the documentation of |
|
1986 |
///\ref SolveExitStatus. |
|
1987 |
SolveExitStatus solve() { return _solve(); } |
|
1988 |
|
|
1989 |
///@} |
|
1990 |
|
|
1991 |
///\name Setting column type |
|
1992 |
///@{ |
|
1993 |
|
|
1994 |
///Possible variable (column) types (e.g. real, integer, binary etc.) |
|
1402 | 1995 |
enum ColTypes { |
1403 |
///Continuous variable |
|
1996 |
///Continuous variable (default) |
|
1404 | 1997 |
REAL = 0, |
1405 | 1998 |
///Integer variable |
1406 |
|
|
1407 |
///Unfortunately, cplex 7.5 somewhere writes something like |
|
1408 |
///#define INTEGER 'I' |
|
1409 |
INT = 1 |
|
1410 |
|
|
1999 |
INTEGER = 1 |
|
1411 | 2000 |
}; |
1412 | 2001 |
|
1413 |
///Sets the type of the given |
|
2002 |
///Sets the type of the given column to the given type |
|
2003 |
|
|
2004 |
///Sets the type of the given column to the given type. |
|
1414 | 2005 |
/// |
1415 |
///Sets the type of the given coloumn to the given type. |
|
1416 | 2006 |
void colType(Col c, ColTypes col_type) { |
1417 |
|
|
2007 |
_setColType(cols(id(c)),col_type); |
|
1418 | 2008 |
} |
1419 | 2009 |
|
1420 | 2010 |
///Gives back the type of the column. |
2011 |
|
|
2012 |
///Gives back the type of the column. |
|
1421 | 2013 |
/// |
1422 |
///Gives back the type of the column. |
|
1423 | 2014 |
ColTypes colType(Col c) const { |
1424 |
return |
|
2015 |
return _getColType(cols(id(c))); |
|
2016 |
} |
|
2017 |
///@} |
|
2018 |
|
|
2019 |
///\name Obtain the solution |
|
2020 |
|
|
2021 |
///@{ |
|
2022 |
|
|
2023 |
/// The type of the MIP problem |
|
2024 |
ProblemType type() const { |
|
2025 |
return _getType(); |
|
1425 | 2026 |
} |
1426 | 2027 |
|
1427 |
///Sets the type of the given Col to integer or remove that property. |
|
1428 |
/// |
|
1429 |
///Sets the type of the given Col to integer or remove that property. |
|
1430 |
void integer(Col c, bool enable) { |
|
1431 |
if (enable) |
|
1432 |
colType(c,INT); |
|
1433 |
else |
|
1434 |
colType(c,REAL); |
|
2028 |
/// Return the value of the row in the solution |
|
2029 |
|
|
2030 |
/// Return the value of the row in the solution. |
|
2031 |
/// \pre The problem is solved. |
|
2032 |
Value sol(Col c) const { return _getSol(cols(id(c))); } |
|
2033 |
|
|
2034 |
/// Return the value of the expression in the solution |
|
2035 |
|
|
2036 |
/// Return the value of the expression in the solution, i.e. the |
|
2037 |
/// dot product of the solution and the expression. |
|
2038 |
/// \pre The problem is solved. |
|
2039 |
Value sol(const Expr& e) const { |
|
2040 |
double res = *e; |
|
2041 |
for (Expr::ConstCoeffIt c(e); c != INVALID; ++c) { |
|
2042 |
res += *c * sol(c); |
|
2043 |
} |
|
2044 |
return res; |
|
1435 | 2045 |
} |
1436 |
|
|
1437 |
///Gives back whether the type of the column is integer or not. |
|
1438 |
/// |
|
1439 |
///Gives back the type of the column. |
|
1440 |
///\return true if the column has integer type and false if not. |
|
1441 |
bool integer(Col c) const { |
|
1442 |
return (colType(c)==INT); |
|
1443 |
} |
|
1444 |
|
|
1445 |
/// The status of the MIP problem |
|
1446 |
SolutionStatus mipStatus() const { |
|
1447 |
return _getMipStatus(); |
|
1448 |
|
|
2046 |
///The value of the objective function |
|
2047 |
|
|
2048 |
///\return |
|
2049 |
///- \ref INF or -\ref INF means either infeasibility or unboundedness |
|
2050 |
/// of the problem, depending on whether we minimize or maximize. |
|
2051 |
///- \ref NaN if no primal solution is found. |
|
2052 |
///- The (finite) objective value if an optimal solution is found. |
|
2053 |
Value solValue() const { return _getSolValue()+obj_const_comp;} |
|
2054 |
///@} |
|
1449 | 2055 |
|
1450 | 2056 |
protected: |
1451 | 2057 |
|
1452 |
virtual ColTypes _colType(int col) const = 0; |
|
1453 |
virtual void _colType(int col, ColTypes col_type) = 0; |
|
1454 |
virtual |
|
2058 |
virtual SolveExitStatus _solve() = 0; |
|
2059 |
virtual ColTypes _getColType(int col) const = 0; |
|
2060 |
virtual void _setColType(int col, ColTypes col_type) = 0; |
|
2061 |
virtual ProblemType _getType() const = 0; |
|
2062 |
virtual Value _getSol(int i) const = 0; |
|
2063 |
virtual Value _getSolValue() const = 0; |
|
1455 | 2064 |
|
2065 |
public: |
|
2066 |
|
|
2067 |
MipSolver* newSolver() {return _newSolver();} |
|
2068 |
MipSolver* cloneSolver() {return _cloneSolver();} |
|
2069 |
|
|
2070 |
protected: |
|
2071 |
|
|
2072 |
virtual MipSolver* _newSolver() const = 0; |
|
2073 |
virtual MipSolver* _cloneSolver() const = 0; |
|
1456 | 2074 |
}; |
1457 | 2075 |
|
1458 |
///\relates LpSolverBase::Expr |
|
1459 |
/// |
|
1460 |
inline LpSolverBase::Expr operator+(const LpSolverBase::Expr &a, |
|
1461 |
const LpSolverBase::Expr &b) |
|
1462 |
{ |
|
1463 |
LpSolverBase::Expr tmp(a); |
|
1464 |
tmp+=b; |
|
1465 |
return tmp; |
|
1466 |
} |
|
1467 |
///\e |
|
1468 |
|
|
1469 |
///\relates LpSolverBase::Expr |
|
1470 |
/// |
|
1471 |
inline LpSolverBase::Expr operator-(const LpSolverBase::Expr &a, |
|
1472 |
const LpSolverBase::Expr &b) |
|
1473 |
{ |
|
1474 |
LpSolverBase::Expr tmp(a); |
|
1475 |
tmp-=b; |
|
1476 |
return tmp; |
|
1477 |
} |
|
1478 |
///\e |
|
1479 |
|
|
1480 |
///\relates LpSolverBase::Expr |
|
1481 |
/// |
|
1482 |
inline LpSolverBase::Expr operator*(const LpSolverBase::Expr &a, |
|
1483 |
const LpSolverBase::Value &b) |
|
1484 |
{ |
|
1485 |
LpSolverBase::Expr tmp(a); |
|
1486 |
tmp*=b; |
|
1487 |
return tmp; |
|
1488 |
} |
|
1489 |
|
|
1490 |
///\e |
|
1491 |
|
|
1492 |
///\relates LpSolverBase::Expr |
|
1493 |
/// |
|
1494 |
inline LpSolverBase::Expr operator*(const LpSolverBase::Value &a, |
|
1495 |
const LpSolverBase::Expr &b) |
|
1496 |
{ |
|
1497 |
LpSolverBase::Expr tmp(b); |
|
1498 |
tmp*=a; |
|
1499 |
return tmp; |
|
1500 |
} |
|
1501 |
///\e |
|
1502 |
|
|
1503 |
///\relates LpSolverBase::Expr |
|
1504 |
/// |
|
1505 |
inline LpSolverBase::Expr operator/(const LpSolverBase::Expr &a, |
|
1506 |
const LpSolverBase::Value &b) |
|
1507 |
{ |
|
1508 |
LpSolverBase::Expr tmp(a); |
|
1509 |
tmp/=b; |
|
1510 |
return tmp; |
|
1511 |
} |
|
1512 |
|
|
1513 |
///\e |
|
1514 |
|
|
1515 |
///\relates LpSolverBase::Constr |
|
1516 |
/// |
|
1517 |
inline LpSolverBase::Constr operator<=(const LpSolverBase::Expr &e, |
|
1518 |
const LpSolverBase::Expr &f) |
|
1519 |
{ |
|
1520 |
return LpSolverBase::Constr(-LpSolverBase::INF,e-f,0); |
|
1521 |
} |
|
1522 |
|
|
1523 |
///\e |
|
1524 |
|
|
1525 |
///\relates LpSolverBase::Constr |
|
1526 |
/// |
|
1527 |
inline LpSolverBase::Constr operator<=(const LpSolverBase::Value &e, |
|
1528 |
const LpSolverBase::Expr &f) |
|
1529 |
{ |
|
1530 |
return LpSolverBase::Constr(e,f); |
|
1531 |
} |
|
1532 |
|
|
1533 |
///\e |
|
1534 |
|
|
1535 |
///\relates LpSolverBase::Constr |
|
1536 |
/// |
|
1537 |
inline LpSolverBase::Constr operator<=(const LpSolverBase::Expr &e, |
|
1538 |
const LpSolverBase::Value &f) |
|
1539 |
{ |
|
1540 |
return LpSolverBase::Constr(-LpSolverBase::INF,e,f); |
|
1541 |
} |
|
1542 |
|
|
1543 |
///\e |
|
1544 |
|
|
1545 |
///\relates LpSolverBase::Constr |
|
1546 |
/// |
|
1547 |
inline LpSolverBase::Constr operator>=(const LpSolverBase::Expr &e, |
|
1548 |
const LpSolverBase::Expr &f) |
|
1549 |
{ |
|
1550 |
return LpSolverBase::Constr(-LpSolverBase::INF,f-e,0); |
|
1551 |
} |
|
1552 |
|
|
1553 |
|
|
1554 |
///\e |
|
1555 |
|
|
1556 |
///\relates LpSolverBase::Constr |
|
1557 |
/// |
|
1558 |
inline LpSolverBase::Constr operator>=(const LpSolverBase::Value &e, |
|
1559 |
const LpSolverBase::Expr &f) |
|
1560 |
{ |
|
1561 |
return LpSolverBase::Constr(f,e); |
|
1562 |
} |
|
1563 |
|
|
1564 |
|
|
1565 |
///\e |
|
1566 |
|
|
1567 |
///\relates LpSolverBase::Constr |
|
1568 |
/// |
|
1569 |
inline LpSolverBase::Constr operator>=(const LpSolverBase::Expr &e, |
|
1570 |
const LpSolverBase::Value &f) |
|
1571 |
{ |
|
1572 |
return LpSolverBase::Constr(f,e,LpSolverBase::INF); |
|
1573 |
} |
|
1574 |
|
|
1575 |
///\e |
|
1576 |
|
|
1577 |
///\relates LpSolverBase::Constr |
|
1578 |
/// |
|
1579 |
inline LpSolverBase::Constr operator==(const LpSolverBase::Expr &e, |
|
1580 |
const LpSolverBase::Value &f) |
|
1581 |
{ |
|
1582 |
return LpSolverBase::Constr(f,e,f); |
|
1583 |
} |
|
1584 |
|
|
1585 |
///\e |
|
1586 |
|
|
1587 |
///\relates LpSolverBase::Constr |
|
1588 |
/// |
|
1589 |
inline LpSolverBase::Constr operator==(const LpSolverBase::Expr &e, |
|
1590 |
const LpSolverBase::Expr &f) |
|
1591 |
{ |
|
1592 |
return LpSolverBase::Constr(0,e-f,0); |
|
1593 |
} |
|
1594 |
|
|
1595 |
///\e |
|
1596 |
|
|
1597 |
///\relates LpSolverBase::Constr |
|
1598 |
/// |
|
1599 |
inline LpSolverBase::Constr operator<=(const LpSolverBase::Value &n, |
|
1600 |
const LpSolverBase::Constr&c) |
|
1601 |
{ |
|
1602 |
LpSolverBase::Constr tmp(c); |
|
1603 |
LEMON_ASSERT(LpSolverBase::isNaN(tmp.lowerBound()), "Wrong LP constraint"); |
|
1604 |
tmp.lowerBound()=n; |
|
1605 |
return tmp; |
|
1606 |
} |
|
1607 |
///\e |
|
1608 |
|
|
1609 |
///\relates LpSolverBase::Constr |
|
1610 |
/// |
|
1611 |
inline LpSolverBase::Constr operator<=(const LpSolverBase::Constr& c, |
|
1612 |
const LpSolverBase::Value &n) |
|
1613 |
{ |
|
1614 |
LpSolverBase::Constr tmp(c); |
|
1615 |
LEMON_ASSERT(LpSolverBase::isNaN(tmp.upperBound()), "Wrong LP constraint"); |
|
1616 |
tmp.upperBound()=n; |
|
1617 |
return tmp; |
|
1618 |
} |
|
1619 |
|
|
1620 |
///\e |
|
1621 |
|
|
1622 |
///\relates LpSolverBase::Constr |
|
1623 |
/// |
|
1624 |
inline LpSolverBase::Constr operator>=(const LpSolverBase::Value &n, |
|
1625 |
const LpSolverBase::Constr&c) |
|
1626 |
{ |
|
1627 |
LpSolverBase::Constr tmp(c); |
|
1628 |
LEMON_ASSERT(LpSolverBase::isNaN(tmp.upperBound()), "Wrong LP constraint"); |
|
1629 |
tmp.upperBound()=n; |
|
1630 |
return tmp; |
|
1631 |
} |
|
1632 |
///\e |
|
1633 |
|
|
1634 |
///\relates LpSolverBase::Constr |
|
1635 |
/// |
|
1636 |
inline LpSolverBase::Constr operator>=(const LpSolverBase::Constr& c, |
|
1637 |
const LpSolverBase::Value &n) |
|
1638 |
{ |
|
1639 |
LpSolverBase::Constr tmp(c); |
|
1640 |
LEMON_ASSERT(LpSolverBase::isNaN(tmp.lowerBound()), "Wrong LP constraint"); |
|
1641 |
tmp.lowerBound()=n; |
|
1642 |
return tmp; |
|
1643 |
} |
|
1644 |
|
|
1645 |
///\e |
|
1646 |
|
|
1647 |
///\relates LpSolverBase::DualExpr |
|
1648 |
/// |
|
1649 |
inline LpSolverBase::DualExpr operator+(const LpSolverBase::DualExpr &a, |
|
1650 |
const LpSolverBase::DualExpr &b) |
|
1651 |
{ |
|
1652 |
LpSolverBase::DualExpr tmp(a); |
|
1653 |
tmp+=b; |
|
1654 |
return tmp; |
|
1655 |
} |
|
1656 |
///\e |
|
1657 |
|
|
1658 |
///\relates LpSolverBase::DualExpr |
|
1659 |
/// |
|
1660 |
inline LpSolverBase::DualExpr operator-(const LpSolverBase::DualExpr &a, |
|
1661 |
const LpSolverBase::DualExpr &b) |
|
1662 |
{ |
|
1663 |
LpSolverBase::DualExpr tmp(a); |
|
1664 |
tmp-=b; |
|
1665 |
return tmp; |
|
1666 |
} |
|
1667 |
///\e |
|
1668 |
|
|
1669 |
///\relates LpSolverBase::DualExpr |
|
1670 |
/// |
|
1671 |
inline LpSolverBase::DualExpr operator*(const LpSolverBase::DualExpr &a, |
|
1672 |
const LpSolverBase::Value &b) |
|
1673 |
{ |
|
1674 |
LpSolverBase::DualExpr tmp(a); |
|
1675 |
tmp*=b; |
|
1676 |
return tmp; |
|
1677 |
} |
|
1678 |
|
|
1679 |
///\e |
|
1680 |
|
|
1681 |
///\relates LpSolverBase::DualExpr |
|
1682 |
/// |
|
1683 |
inline LpSolverBase::DualExpr operator*(const LpSolverBase::Value &a, |
|
1684 |
const LpSolverBase::DualExpr &b) |
|
1685 |
{ |
|
1686 |
LpSolverBase::DualExpr tmp(b); |
|
1687 |
tmp*=a; |
|
1688 |
return tmp; |
|
1689 |
} |
|
1690 |
///\e |
|
1691 |
|
|
1692 |
///\relates LpSolverBase::DualExpr |
|
1693 |
/// |
|
1694 |
inline LpSolverBase::DualExpr operator/(const LpSolverBase::DualExpr &a, |
|
1695 |
const LpSolverBase::Value &b) |
|
1696 |
{ |
|
1697 |
LpSolverBase::DualExpr tmp(a); |
|
1698 |
tmp/=b; |
|
1699 |
return tmp; |
|
1700 |
} |
|
1701 | 2076 |
|
1702 | 2077 |
... | ... |
@@ -19,4 +19,6 @@ |
19 | 19 |
#include <iostream> |
20 | 20 |
#include <vector> |
21 |
#include <cstring> |
|
22 |
|
|
21 | 23 |
#include <lemon/lp_cplex.h> |
22 | 24 |
|
... | ... |
@@ -30,97 +32,125 @@ |
30 | 32 |
namespace lemon { |
31 | 33 |
|
32 |
LpCplex::LpCplex() { |
|
33 |
// env = CPXopenCPLEXdevelop(&status); |
|
34 |
env = CPXopenCPLEX(&status); |
|
35 |
lp = CPXcreateprob(env, &status, "LP problem"); |
|
34 |
CplexEnv::LicenseError::LicenseError(int status) { |
|
35 |
if (!CPXgeterrorstring(0, status, _message)) { |
|
36 |
std::strcpy(_message, "Cplex unknown error"); |
|
37 |
} |
|
36 | 38 |
} |
37 | 39 |
|
38 |
LpCplex::LpCplex(const LpCplex& cplex) : LpSolverBase() { |
|
39 |
env = CPXopenCPLEX(&status); |
|
40 |
|
|
40 |
CplexEnv::CplexEnv() { |
|
41 |
int status; |
|
42 |
_cnt = new int; |
|
43 |
_env = CPXopenCPLEX(&status); |
|
44 |
if (_env == 0) { |
|
45 |
delete _cnt; |
|
46 |
_cnt = 0; |
|
47 |
throw LicenseError(status); |
|
48 |
} |
|
49 |
} |
|
50 |
|
|
51 |
CplexEnv::CplexEnv(const CplexEnv& other) { |
|
52 |
_env = other._env; |
|
53 |
_cnt = other._cnt; |
|
54 |
++(*_cnt); |
|
55 |
} |
|
56 |
|
|
57 |
CplexEnv& CplexEnv::operator=(const CplexEnv& other) { |
|
58 |
_env = other._env; |
|
59 |
_cnt = other._cnt; |
|
60 |
++(*_cnt); |
|
61 |
return *this; |
|
62 |
} |
|
63 |
|
|
64 |
CplexEnv::~CplexEnv() { |
|
65 |
--(*_cnt); |
|
66 |
if (*_cnt == 0) { |
|
67 |
delete _cnt; |
|
68 |
CPXcloseCPLEX(&_env); |
|
69 |
} |
|
70 |
} |
|
71 |
|
|
72 |
CplexBase::CplexBase() : LpBase() { |
|
73 |
int status; |
|
74 |
_prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); |
|
75 |
} |
|
76 |
|
|
77 |
CplexBase::CplexBase(const CplexEnv& env) |
|
78 |
: LpBase(), _env(env) { |
|
79 |
int status; |
|
80 |
_prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); |
|
81 |
} |
|
82 |
|
|
83 |
CplexBase::CplexBase(const CplexBase& cplex) |
|
84 |
: LpBase() { |
|
85 |
int status; |
|
86 |
_prob = CPXcloneprob(cplexEnv(), cplex._prob, &status); |
|
41 | 87 |
rows = cplex.rows; |
42 | 88 |
cols = cplex.cols; |
43 | 89 |
} |
44 | 90 |
|
45 |
LpCplex::~LpCplex() { |
|
46 |
CPXfreeprob(env,&lp); |
|
47 |
|
|
91 |
CplexBase::~CplexBase() { |
|
92 |
CPXfreeprob(cplexEnv(),&_prob); |
|
48 | 93 |
} |
49 | 94 |
|
50 |
LpSolverBase* LpCplex::_newLp() |
|
51 |
{ |
|
52 |
//The first approach opens a new environment |
|
53 |
return new LpCplex(); |
|
54 |
} |
|
55 |
|
|
56 |
LpSolverBase* LpCplex::_copyLp() { |
|
57 |
return new LpCplex(*this); |
|
58 |
} |
|
59 |
|
|
60 |
int LpCplex::_addCol() |
|
61 |
{ |
|
62 |
int i = CPXgetnumcols(env, lp); |
|
63 |
Value lb[1],ub[1]; |
|
64 |
lb[0]=-INF; |
|
65 |
ub[0]=INF; |
|
66 |
|
|
95 |
int CplexBase::_addCol() { |
|
96 |
int i = CPXgetnumcols(cplexEnv(), _prob); |
|
97 |
double lb = -INF, ub = INF; |
|
98 |
CPXnewcols(cplexEnv(), _prob, 1, 0, &lb, &ub, 0, 0); |
|
67 | 99 |
return i; |
68 | 100 |
} |
69 | 101 |
|
70 | 102 |
|
71 |
int LpCplex::_addRow() |
|
72 |
{ |
|
73 |
//We want a row that is not constrained |
|
74 |
char sense[1]; |
|
75 |
sense[0]='L';//<= constraint |
|
76 |
Value rhs[1]; |
|
77 |
rhs[0]=INF; |
|
78 |
int i = CPXgetnumrows(env, lp); |
|
79 |
|
|
103 |
int CplexBase::_addRow() { |
|
104 |
int i = CPXgetnumrows(cplexEnv(), _prob); |
|
105 |
const double ub = INF; |
|
106 |
const char s = 'L'; |
|
107 |
CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0); |
|
80 | 108 |
return i; |
81 | 109 |
} |
82 | 110 |
|
83 | 111 |
|
84 |
void LpCplex::_eraseCol(int i) { |
|
85 |
CPXdelcols(env, lp, i, i); |
|
112 |
void CplexBase::_eraseCol(int i) { |
|
113 |
CPXdelcols(cplexEnv(), _prob, i, i); |
|
86 | 114 |
} |
87 | 115 |
|
88 |
void LpCplex::_eraseRow(int i) { |
|
89 |
CPXdelrows(env, lp, i, i); |
|
116 |
void CplexBase::_eraseRow(int i) { |
|
117 |
CPXdelrows(cplexEnv(), _prob, i, i); |
|
90 | 118 |
} |
91 | 119 |
|
92 |
void LpCplex::_getColName(int col, std::string &name) const |
|
93 |
{ |
|
94 |
///\bug Untested |
|
95 |
int storespace; |
|
96 |
CPXgetcolname(env, lp, 0, 0, 0, &storespace, col, col); |
|
97 |
if (storespace == 0) { |
|
120 |
void CplexBase::_eraseColId(int i) { |
|
121 |
cols.eraseIndex(i); |
|
122 |
cols.shiftIndices(i); |
|
123 |
} |
|
124 |
void CplexBase::_eraseRowId(int i) { |
|
125 |
rows.eraseIndex(i); |
|
126 |
rows.shiftIndices(i); |
|
127 |
} |
|
128 |
|
|
129 |
void CplexBase::_getColName(int col, std::string &name) const { |
|
130 |
int size; |
|
131 |
CPXgetcolname(cplexEnv(), _prob, 0, 0, 0, &size, col, col); |
|
132 |
if (size == 0) { |
|
98 | 133 |
name.clear(); |
99 | 134 |
return; |
100 | 135 |
} |
101 | 136 |
|
102 |
storespace *= -1; |
|
103 |
std::vector<char> buf(storespace); |
|
104 |
char *names[1]; |
|
105 |
int dontcare; |
|
106 |
///\bug return code unchecked for error |
|
107 |
CPXgetcolname(env, lp, names, &*buf.begin(), storespace, |
|
108 |
&dontcare, col, col); |
|
109 |
name = names[0]; |
|
137 |
size *= -1; |
|
138 |
std::vector<char> buf(size); |
|
139 |
char *cname; |
|
140 |
int tmp; |
|
141 |
CPXgetcolname(cplexEnv(), _prob, &cname, &buf.front(), size, |
|
142 |
&tmp, col, col); |
|
143 |
name = cname; |
|
110 | 144 |
} |
111 | 145 |
|
112 |
void LpCplex::_setColName(int col, const std::string &name) |
|
113 |
{ |
|
114 |
///\bug Untested |
|
115 |
char *names[1]; |
|
116 |
names[0] = const_cast<char*>(name.c_str()); |
|
117 |
///\bug return code unchecked for error |
|
118 |
|
|
146 |
void CplexBase::_setColName(int col, const std::string &name) { |
|
147 |
char *cname; |
|
148 |
cname = const_cast<char*>(name.c_str()); |
|
149 |
CPXchgcolname(cplexEnv(), _prob, 1, &col, &cname); |
|
119 | 150 |
} |
120 | 151 |
|
121 |
int LpCplex::_colByName(const std::string& name) const |
|
122 |
{ |
|
152 |
int CplexBase::_colByName(const std::string& name) const { |
|
123 | 153 |
int index; |
124 |
if (CPXgetcolindex( |
|
154 |
if (CPXgetcolindex(cplexEnv(), _prob, |
|
125 | 155 |
const_cast<char*>(name.c_str()), &index) == 0) { |
126 | 156 |
return index; |
... | ... |
@@ -129,6 +159,38 @@ |
129 | 159 |
} |
130 | 160 |
|
131 |
///\warning Data at index 0 is ignored in the arrays. |
|
132 |
void LpCplex::_setRowCoeffs(int i, ConstRowIterator b, ConstRowIterator e) |
|
161 |
void CplexBase::_getRowName(int row, std::string &name) const { |
|
162 |
int size; |
|
163 |
CPXgetrowname(cplexEnv(), _prob, 0, 0, 0, &size, row, row); |
|
164 |
if (size == 0) { |
|
165 |
name.clear(); |
|
166 |
return; |
|
167 |
} |
|
168 |
|
|
169 |
size *= -1; |
|
170 |
std::vector<char> buf(size); |
|
171 |
char *cname; |
|
172 |
int tmp; |
|
173 |
CPXgetrowname(cplexEnv(), _prob, &cname, &buf.front(), size, |
|
174 |
&tmp, row, row); |
|
175 |
name = cname; |
|
176 |
} |
|
177 |
|
|
178 |
void CplexBase::_setRowName(int row, const std::string &name) { |
|
179 |
char *cname; |
|
180 |
cname = const_cast<char*>(name.c_str()); |
|
181 |
CPXchgrowname(cplexEnv(), _prob, 1, &row, &cname); |
|
182 |
} |
|
183 |
|
|
184 |
int CplexBase::_rowByName(const std::string& name) const { |
|
185 |
int index; |
|
186 |
if (CPXgetrowindex(cplexEnv(), _prob, |
|
187 |
const_cast<char*>(name.c_str()), &index) == 0) { |
|
188 |
return index; |
|
189 |
} |
|
190 |
return -1; |
|
191 |
} |
|
192 |
|
|
193 |
void CplexBase::_setRowCoeffs(int i, ExprIterator b, |
|
194 |
ExprIterator e) |
|
133 | 195 |
{ |
134 | 196 |
std::vector<int> indices; |
... | ... |
@@ -136,5 +198,5 @@ |
136 | 198 |
std::vector<Value> values; |
137 | 199 |
|
138 |
for( |
|
200 |
for(ExprIterator it=b; it!=e; ++it) { |
|
139 | 201 |
indices.push_back(it->first); |
140 | 202 |
values.push_back(it->second); |
... | ... |
@@ -142,11 +204,11 @@ |
142 | 204 |
} |
143 | 205 |
|
144 |
status = CPXchgcoeflist(env, lp, values.size(), |
|
145 |
&rowlist[0], &indices[0], &values[0]); |
|
206 |
CPXchgcoeflist(cplexEnv(), _prob, values.size(), |
|
207 |
&rowlist.front(), &indices.front(), &values.front()); |
|
146 | 208 |
} |
147 | 209 |
|
148 |
void |
|
210 |
void CplexBase::_getRowCoeffs(int i, InsertIterator b) const { |
|
149 | 211 |
int tmp1, tmp2, tmp3, length; |
150 |
CPXgetrows( |
|
212 |
CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i); |
|
151 | 213 |
|
152 | 214 |
length = -length; |
... | ... |
@@ -154,5 +216,6 @@ |
154 | 216 |
std::vector<double> values(length); |
155 | 217 |
|
156 |
CPXgetrows( |
|
218 |
CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, |
|
219 |
&indices.front(), &values.front(), |
|
157 | 220 |
length, &tmp3, i, i); |
158 | 221 |
|
... | ... |
@@ -161,15 +224,12 @@ |
161 | 224 |
++b; |
162 | 225 |
} |
163 |
|
|
164 |
/// \todo implement |
|
165 | 226 |
} |
166 | 227 |
|
167 |
void LpCplex::_setColCoeffs(int i, ConstColIterator b, ConstColIterator e) |
|
168 |
{ |
|
228 |
void CplexBase::_setColCoeffs(int i, ExprIterator b, ExprIterator e) { |
|
169 | 229 |
std::vector<int> indices; |
170 | 230 |
std::vector<int> collist; |
171 | 231 |
std::vector<Value> values; |
172 | 232 |
|
173 |
for( |
|
233 |
for(ExprIterator it=b; it!=e; ++it) { |
|
174 | 234 |
indices.push_back(it->first); |
175 | 235 |
values.push_back(it->second); |
... | ... |
@@ -177,12 +237,12 @@ |
177 | 237 |
} |
178 | 238 |
|
179 |
status = CPXchgcoeflist(env, lp, values.size(), |
|
180 |
&indices[0], &collist[0], &values[0]); |
|
239 |
CPXchgcoeflist(cplexEnv(), _prob, values.size(), |
|
240 |
&indices.front(), &collist.front(), &values.front()); |
|
181 | 241 |
} |
182 | 242 |
|
183 |
void |
|
243 |
void CplexBase::_getColCoeffs(int i, InsertIterator b) const { |
|
184 | 244 |
|
185 | 245 |
int tmp1, tmp2, tmp3, length; |
186 |
CPXgetcols( |
|
246 |
CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i); |
|
187 | 247 |
|
188 | 248 |
length = -length; |
... | ... |
@@ -190,5 +250,6 @@ |
190 | 250 |
std::vector<double> values(length); |
191 | 251 |
|
192 |
CPXgetcols( |
|
252 |
CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, |
|
253 |
&indices.front(), &values.front(), |
|
193 | 254 |
length, &tmp3, i, i); |
194 | 255 |
|
... | ... |
@@ -200,173 +261,207 @@ |
200 | 261 |
} |
201 | 262 |
|
202 |
void LpCplex::_setCoeff(int row, int col, Value value) |
|
203 |
{ |
|
204 |
|
|
263 |
void CplexBase::_setCoeff(int row, int col, Value value) { |
|
264 |
CPXchgcoef(cplexEnv(), _prob, row, col, value); |
|
205 | 265 |
} |
206 | 266 |
|
207 |
LpCplex::Value LpCplex::_getCoeff(int row, int col) const |
|
208 |
{ |
|
209 |
LpCplex::Value value; |
|
210 |
CPXgetcoef(env, lp, row, col, &value); |
|
267 |
CplexBase::Value CplexBase::_getCoeff(int row, int col) const { |
|
268 |
CplexBase::Value value; |
|
269 |
CPXgetcoef(cplexEnv(), _prob, row, col, &value); |
|
211 | 270 |
return value; |
212 | 271 |
} |
213 | 272 |
|
214 |
void |
|
273 |
void CplexBase::_setColLowerBound(int i, Value value) { |
|
274 |
const char s = 'L'; |
|
275 |
CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value); |
|
276 |
} |
|
277 |
|
|
278 |
CplexBase::Value CplexBase::_getColLowerBound(int i) const { |
|
279 |
CplexBase::Value res; |
|
280 |
CPXgetlb(cplexEnv(), _prob, &res, i, i); |
|
281 |
return res <= -CPX_INFBOUND ? -INF : res; |
|
282 |
} |
|
283 |
|
|
284 |
void CplexBase::_setColUpperBound(int i, Value value) |
|
215 | 285 |
{ |
216 |
int indices[1]; |
|
217 |
indices[0]=i; |
|
218 |
char lu[1]; |
|
219 |
lu[0]='L'; |
|
220 |
Value bd[1]; |
|
221 |
bd[0]=value; |
|
222 |
|
|
286 |
const char s = 'U'; |
|
287 |
CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value); |
|
288 |
} |
|
289 |
|
|
290 |
CplexBase::Value CplexBase::_getColUpperBound(int i) const { |
|
291 |
CplexBase::Value res; |
|
292 |
CPXgetub(cplexEnv(), _prob, &res, i, i); |
|
293 |
return res >= CPX_INFBOUND ? INF : res; |
|
294 |
} |
|
295 |
|
|
296 |
CplexBase::Value CplexBase::_getRowLowerBound(int i) const { |
|
297 |
char s; |
|
298 |
CPXgetsense(cplexEnv(), _prob, &s, i, i); |
|
299 |
CplexBase::Value res; |
|
300 |
|
|
301 |
switch (s) { |
|
302 |
case 'G': |
|
303 |
case 'R': |
|
304 |
case 'E': |
|
305 |
CPXgetrhs(cplexEnv(), _prob, &res, i, i); |
|
306 |
return res <= -CPX_INFBOUND ? -INF : res; |
|
307 |
default: |
|
308 |
return -INF; |
|
309 |
} |
|
310 |
} |
|
311 |
|
|
312 |
CplexBase::Value CplexBase::_getRowUpperBound(int i) const { |
|
313 |
char s; |
|
314 |
CPXgetsense(cplexEnv(), _prob, &s, i, i); |
|
315 |
CplexBase::Value res; |
|
316 |
|
|
317 |
switch (s) { |
|
318 |
case 'L': |
|
319 |
case 'E': |
|
320 |
CPXgetrhs(cplexEnv(), _prob, &res, i, i); |
|
321 |
return res >= CPX_INFBOUND ? INF : res; |
|
322 |
case 'R': |
|
323 |
CPXgetrhs(cplexEnv(), _prob, &res, i, i); |
|
324 |
{ |
|
325 |
double rng; |
|
326 |
CPXgetrngval(cplexEnv(), _prob, &rng, i, i); |
|
327 |
res += rng; |
|
328 |
} |
|
329 |
return res >= CPX_INFBOUND ? INF : res; |
|
330 |
default: |
|
331 |
return INF; |
|
332 |
} |
|
333 |
} |
|
334 |
|
|
335 |
//This is easier to implement |
|
336 |
void CplexBase::_set_row_bounds(int i, Value lb, Value ub) { |
|
337 |
if (lb == -INF) { |
|
338 |
const char s = 'L'; |
|
339 |
CPXchgsense(cplexEnv(), _prob, 1, &i, &s); |
|
340 |
CPXchgrhs(cplexEnv(), _prob, 1, &i, &ub); |
|
341 |
} else if (ub == INF) { |
|
342 |
const char s = 'G'; |
|
343 |
CPXchgsense(cplexEnv(), _prob, 1, &i, &s); |
|
344 |
CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb); |
|
345 |
} else if (lb == ub){ |
|
346 |
const char s = 'E'; |
|
347 |
CPXchgsense(cplexEnv(), _prob, 1, &i, &s); |
|
348 |
CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb); |
|
349 |
} else { |
|
350 |
const char s = 'R'; |
|
351 |
CPXchgsense(cplexEnv(), _prob, 1, &i, &s); |
|
352 |
CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb); |
|
353 |
double len = ub - lb; |
|
354 |
CPXchgrngval(cplexEnv(), _prob, 1, &i, &len); |
|
355 |
} |
|
356 |
} |
|
357 |
|
|
358 |
void CplexBase::_setRowLowerBound(int i, Value lb) |
|
359 |
{ |
|
360 |
LEMON_ASSERT(lb != INF, "Invalid bound"); |
|
361 |
_set_row_bounds(i, lb, CplexBase::_getRowUpperBound(i)); |
|
362 |
} |
|
363 |
|
|
364 |
void CplexBase::_setRowUpperBound(int i, Value ub) |
|
365 |
{ |
|
366 |
|
|
367 |
LEMON_ASSERT(ub != -INF, "Invalid bound"); |
|
368 |
_set_row_bounds(i, CplexBase::_getRowLowerBound(i), ub); |
|
369 |
} |
|
370 |
|
|
371 |
void CplexBase::_setObjCoeffs(ExprIterator b, ExprIterator e) |
|
372 |
{ |
|
373 |
std::vector<int> indices; |
|
374 |
std::vector<Value> values; |
|
375 |
for(ExprIterator it=b; it!=e; ++it) { |
|
376 |
indices.push_back(it->first); |
|
377 |
values.push_back(it->second); |
|
378 |
} |
|
379 |
CPXchgobj(cplexEnv(), _prob, values.size(), |
|
380 |
&indices.front(), &values.front()); |
|
223 | 381 |
|
224 | 382 |
} |
225 | 383 |
|
226 |
|
|
384 |
void CplexBase::_getObjCoeffs(InsertIterator b) const |
|
227 | 385 |
{ |
228 |
LpCplex::Value x; |
|
229 |
CPXgetlb (env, lp, &x, i, i); |
|
230 |
if (x <= -CPX_INFBOUND) x = -INF; |
|
231 |
return x; |
|
232 |
|
|
386 |
int num = CPXgetnumcols(cplexEnv(), _prob); |
|
387 |
std::vector<Value> x(num); |
|
233 | 388 |
|
234 |
void LpCplex::_setColUpperBound(int i, Value value) |
|
235 |
{ |
|
236 |
int indices[1]; |
|
237 |
indices[0]=i; |
|
238 |
char lu[1]; |
|
239 |
lu[0]='U'; |
|
240 |
Value bd[1]; |
|
241 |
bd[0]=value; |
|
242 |
status = CPXchgbds(env, lp, 1, indices, lu, bd); |
|
243 |
} |
|
244 |
|
|
245 |
LpCplex::Value LpCplex::_getColUpperBound(int i) const |
|
246 |
{ |
|
247 |
LpCplex::Value x; |
|
248 |
CPXgetub (env, lp, &x, i, i); |
|
249 |
if (x >= CPX_INFBOUND) x = INF; |
|
250 |
return x; |
|
251 |
} |
|
252 |
|
|
253 |
//This will be easier to implement |
|
254 |
void LpCplex::_setRowBounds(int i, Value lb, Value ub) |
|
255 |
{ |
|
256 |
//Bad parameter |
|
257 |
if (lb==INF || ub==-INF) { |
|
258 |
//FIXME error |
|
259 |
} |
|
260 |
|
|
261 |
int cnt=1; |
|
262 |
int indices[1]; |
|
263 |
indices[0]=i; |
|
264 |
char sense[1]; |
|
265 |
|
|
266 |
if (lb==-INF){ |
|
267 |
sense[0]='L'; |
|
268 |
CPXchgsense(env, lp, cnt, indices, sense); |
|
269 |
CPXchgcoef(env, lp, i, -1, ub); |
|
270 |
|
|
271 |
} |
|
272 |
else{ |
|
273 |
if (ub==INF){ |
|
274 |
sense[0]='G'; |
|
275 |
CPXchgsense(env, lp, cnt, indices, sense); |
|
276 |
CPXchgcoef(env, lp, i, -1, lb); |
|
277 |
} |
|
278 |
else{ |
|
279 |
if (lb == ub){ |
|
280 |
sense[0]='E'; |
|
281 |
CPXchgsense(env, lp, cnt, indices, sense); |
|
282 |
CPXchgcoef(env, lp, i, -1, lb); |
|
283 |
} |
|
284 |
else{ |
|
285 |
sense[0]='R'; |
|
286 |
CPXchgsense(env, lp, cnt, indices, sense); |
|
287 |
CPXchgcoef(env, lp, i, -1, lb); |
|
288 |
CPXchgcoef(env, lp, i, -2, ub-lb); |
|
289 |
} |
|
389 |
CPXgetobj(cplexEnv(), _prob, &x.front(), 0, num - 1); |
|
390 |
for (int i = 0; i < num; ++i) { |
|
391 |
if (x[i] != 0.0) { |
|
392 |
*b = std::make_pair(i, x[i]); |
|
393 |
++b; |
|
290 | 394 |
} |
291 | 395 |
} |
292 | 396 |
} |
293 | 397 |
|
294 |
// void LpCplex::_setRowLowerBound(int i, Value value) |
|
295 |
// { |
|
296 |
// //Not implemented, obsolete |
|
297 |
// } |
|
298 |
|
|
299 |
// void LpCplex::_setRowUpperBound(int i, Value value) |
|
300 |
// { |
|
301 |
// //Not implemented, obsolete |
|
302 |
// // //TODO Ezt kell meg megirni |
|
303 |
// // //type of the problem |
|
304 |
// // char sense[1]; |
|
305 |
// // status = CPXgetsense(env, lp, sense, i, i); |
|
306 |
// // Value rhs[1]; |
|
307 |
// // status = CPXgetrhs(env, lp, rhs, i, i); |
|
308 |
|
|
309 |
// // switch (sense[0]) { |
|
310 |
// // case 'L'://<= constraint |
|
311 |
// // break; |
|
312 |
// // case 'E'://= constraint |
|
313 |
// // break; |
|
314 |
// // case 'G'://>= constraint |
|
315 |
// // break; |
|
316 |
// // case 'R'://ranged constraint |
|
317 |
// // break; |
|
318 |
// // default: ; |
|
319 |
// // //FIXME error |
|
320 |
// // } |
|
321 |
|
|
322 |
// // status = CPXchgcoef(env, lp, i, -2, value_rng); |
|
323 |
// } |
|
324 |
|
|
325 |
void LpCplex::_getRowBounds(int i, Value &lb, Value &ub) const |
|
398 |
void CplexBase::_setObjCoeff(int i, Value obj_coef) |
|
326 | 399 |
{ |
327 |
char sense; |
|
328 |
CPXgetsense(env, lp, &sense,i,i); |
|
329 |
lb=-INF; |
|
330 |
ub=INF; |
|
331 |
switch (sense) |
|
332 |
{ |
|
333 |
case 'L': |
|
334 |
CPXgetcoef(env, lp, i, -1, &ub); |
|
335 |
break; |
|
336 |
case 'G': |
|
337 |
CPXgetcoef(env, lp, i, -1, &lb); |
|
338 |
break; |
|
339 |
case 'E': |
|
340 |
CPXgetcoef(env, lp, i, -1, &lb); |
|
341 |
ub=lb; |
|
342 |
break; |
|
343 |
case 'R': |
|
344 |
CPXgetcoef(env, lp, i, -1, &lb); |
|
345 |
Value x; |
|
346 |
CPXgetcoef(env, lp, i, -2, &x); |
|
347 |
ub=lb+x; |
|
348 |
break; |
|
349 |
|
|
400 |
CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef); |
|
350 | 401 |
} |
351 | 402 |
|
352 |
void LpCplex::_setObjCoeff(int i, Value obj_coef) |
|
353 |
{ |
|
354 |
CPXchgcoef(env, lp, -1, i, obj_coef); |
|
355 |
} |
|
356 |
|
|
357 |
LpCplex::Value LpCplex::_getObjCoeff(int i) const |
|
403 |
CplexBase::Value CplexBase::_getObjCoeff(int i) const |
|
358 | 404 |
{ |
359 | 405 |
Value x; |
360 |
|
|
406 |
CPXgetobj(cplexEnv(), _prob, &x, i, i); |
|
361 | 407 |
return x; |
362 | 408 |
} |
363 | 409 |
|
364 |
void LpCplex::_clearObj() |
|
365 |
{ |
|
366 |
for (int i=0;i< CPXgetnumcols(env, lp);++i){ |
|
367 |
CPXchgcoef(env, lp, -1, i, 0); |
|
410 |
void CplexBase::_setSense(CplexBase::Sense sense) { |
|
411 |
switch (sense) { |
|
412 |
case MIN: |
|
413 |
CPXchgobjsen(cplexEnv(), _prob, CPX_MIN); |
|
414 |
break; |
|
415 |
case MAX: |
|
416 |
CPXchgobjsen(cplexEnv(), _prob, CPX_MAX); |
|
417 |
break; |
|
368 | 418 |
} |
419 |
} |
|
369 | 420 |
|
421 |
CplexBase::Sense CplexBase::_getSense() const { |
|
422 |
switch (CPXgetobjsen(cplexEnv(), _prob)) { |
|
423 |
case CPX_MIN: |
|
424 |
return MIN; |
|
425 |
case CPX_MAX: |
|
426 |
return MAX; |
|
427 |
default: |
|
428 |
LEMON_ASSERT(false, "Invalid sense"); |
|
429 |
return CplexBase::Sense(); |
|
430 |
} |
|
370 | 431 |
} |
432 |
|
|
433 |
void CplexBase::_clear() { |
|
434 |
CPXfreeprob(cplexEnv(),&_prob); |
|
435 |
int status; |
|
436 |
_prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); |
|
437 |
rows.clear(); |
|
438 |
cols.clear(); |
|
439 |
} |
|
440 |
|
|
441 |
// LpCplex members |
|
442 |
|
|
443 |
LpCplex::LpCplex() |
|
444 |
: LpBase(), CplexBase(), LpSolver() {} |
|
445 |
|
|
446 |
LpCplex::LpCplex(const CplexEnv& env) |
|
447 |
: LpBase(), CplexBase(env), LpSolver() {} |
|
448 |
|
|
449 |
LpCplex::LpCplex(const LpCplex& other) |
|
450 |
: LpBase(), CplexBase(other), LpSolver() {} |
|
451 |
|
|
452 |
LpCplex::~LpCplex() {} |
|
453 |
|
|
454 |
LpCplex* LpCplex::_newSolver() const { return new LpCplex; } |
|
455 |
LpCplex* LpCplex::_cloneSolver() const {return new LpCplex(*this); } |
|
456 |
|
|
457 |
const char* LpCplex::_solverName() const { return "LpCplex"; } |
|
458 |
|
|
459 |
void LpCplex::_clear_temporals() { |
|
460 |
_col_status.clear(); |
|
461 |
_row_status.clear(); |
|
462 |
_primal_ray.clear(); |
|
463 |
_dual_ray.clear(); |
|
464 |
} |
|
465 |
|
|
371 | 466 |
// The routine returns zero unless an error occurred during the |
372 | 467 |
// optimization. Examples of errors include exhausting available |
... | ... |
@@ -378,30 +473,22 @@ |
378 | 473 |
// routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain |
379 | 474 |
// further information about the status of the optimization. |
380 |
LpCplex::SolveExitStatus LpCplex::_solve() |
|
381 |
{ |
|
382 |
//CPX_PARAM_LPMETHOD |
|
383 |
status = CPXlpopt(env, lp); |
|
384 |
|
|
475 |
LpCplex::SolveExitStatus LpCplex::convertStatus(int status) { |
|
385 | 476 |
#if CPX_VERSION >= 800 |
386 |
if (status) |
|
387 |
{ |
|
477 |
if (status == 0) { |
|
478 |
switch (CPXgetstat(cplexEnv(), _prob)) { |
|
479 |
case CPX_STAT_OPTIMAL: |
|
480 |
case CPX_STAT_INFEASIBLE: |
|
481 |
case CPX_STAT_UNBOUNDED: |
|
482 |
return SOLVED; |
|
483 |
default: |
|
484 |
return UNSOLVED; |
|
485 |
} |
|
486 |
} else { |
|
388 | 487 |
return UNSOLVED; |
389 | 488 |
} |
390 |
else |
|
391 |
{ |
|
392 |
switch (CPXgetstat(env, lp)) |
|
393 |
{ |
|
394 |
case CPX_STAT_OPTIMAL: |
|
395 |
case CPX_STAT_INFEASIBLE: |
|
396 |
case CPX_STAT_UNBOUNDED: |
|
397 |
return SOLVED; |
|
398 |
default: |
|
399 |
return UNSOLVED; |
|
400 |
} |
|
401 |
} |
|
402 | 489 |
#else |
403 |
if (status == 0){ |
|
490 |
if (status == 0) { |
|
404 | 491 |
//We want to exclude some cases |
405 |
switch (CPXgetstat( |
|
492 |
switch (CPXgetstat(cplexEnv(), _prob)) { |
|
406 | 493 |
case CPX_OBJ_LIM: |
407 | 494 |
case CPX_IT_LIM_FEAS: |
... | ... |
@@ -413,6 +500,5 @@ |
413 | 500 |
return SOLVED; |
414 | 501 |
} |
415 |
} |
|
416 |
else{ |
|
502 |
} else { |
|
417 | 503 |
return UNSOLVED; |
418 | 504 |
} |
... | ... |
@@ -420,106 +506,171 @@ |
420 | 506 |
} |
421 | 507 |
|
422 |
LpCplex::Value LpCplex::_getPrimal(int i) const |
|
423 |
{ |
|
508 |
LpCplex::SolveExitStatus LpCplex::_solve() { |
|
509 |
_clear_temporals(); |
|
510 |
return convertStatus(CPXlpopt(cplexEnv(), _prob)); |
|
511 |
} |
|
512 |
|
|
513 |
LpCplex::SolveExitStatus LpCplex::solvePrimal() { |
|
514 |
_clear_temporals(); |
|
515 |
return convertStatus(CPXprimopt(cplexEnv(), _prob)); |
|
516 |
} |
|
517 |
|
|
518 |
LpCplex::SolveExitStatus LpCplex::solveDual() { |
|
519 |
_clear_temporals(); |
|
520 |
return convertStatus(CPXdualopt(cplexEnv(), _prob)); |
|
521 |
} |
|
522 |
|
|
523 |
LpCplex::SolveExitStatus LpCplex::solveBarrier() { |
|
524 |
_clear_temporals(); |
|
525 |
return convertStatus(CPXbaropt(cplexEnv(), _prob)); |
|
526 |
} |
|
527 |
|
|
528 |
LpCplex::Value LpCplex::_getPrimal(int i) const { |
|
424 | 529 |
Value x; |
425 |
CPXgetx( |
|
530 |
CPXgetx(cplexEnv(), _prob, &x, i, i); |
|
426 | 531 |
return x; |
427 | 532 |
} |
428 | 533 |
|
429 |
LpCplex::Value LpCplex::_getDual(int i) const |
|
430 |
{ |
|
534 |
LpCplex::Value LpCplex::_getDual(int i) const { |
|
431 | 535 |
Value y; |
432 |
CPXgetpi( |
|
536 |
CPXgetpi(cplexEnv(), _prob, &y, i, i); |
|
433 | 537 |
return y; |
434 | 538 |
} |
435 | 539 |
|
436 |
LpCplex::Value LpCplex::_getPrimalValue() const |
|
437 |
{ |
|
540 |
LpCplex::Value LpCplex::_getPrimalValue() const { |
|
438 | 541 |
Value objval; |
439 |
//method = CPXgetmethod (env, lp); |
|
440 |
//printf("CPXgetprobtype %d \n",CPXgetprobtype(env,lp)); |
|
441 |
CPXgetobjval(env, lp, &objval); |
|
442 |
//printf("Objective value: %g \n",objval); |
|
542 |
CPXgetobjval(cplexEnv(), _prob, &objval); |
|
443 | 543 |
return objval; |
444 | 544 |
} |
445 |
bool LpCplex::_isBasicCol(int i) const |
|
446 |
{ |
|
447 |
std::vector<int> cstat(CPXgetnumcols(env, lp)); |
|
448 |
CPXgetbase(env, lp, &*cstat.begin(), NULL); |
|
449 |
|
|
545 |
|
|
546 |
LpCplex::VarStatus LpCplex::_getColStatus(int i) const { |
|
547 |
if (_col_status.empty()) { |
|
548 |
_col_status.resize(CPXgetnumcols(cplexEnv(), _prob)); |
|
549 |
CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0); |
|
550 |
} |
|
551 |
switch (_col_status[i]) { |
|
552 |
case CPX_BASIC: |
|
553 |
return BASIC; |
|
554 |
case CPX_FREE_SUPER: |
|
555 |
return FREE; |
|
556 |
case CPX_AT_LOWER: |
|
557 |
return LOWER; |
|
558 |
case CPX_AT_UPPER: |
|
559 |
return UPPER; |
|
560 |
default: |
|
561 |
LEMON_ASSERT(false, "Wrong column status"); |
|
562 |
return LpCplex::VarStatus(); |
|
563 |
} |
|
450 | 564 |
} |
451 | 565 |
|
452 |
//7.5-os cplex statusai (Vigyazat: a 9.0-asei masok!) |
|
453 |
// This table lists the statuses, returned by the CPXgetstat() |
|
454 |
// routine, for solutions to LP problems or mixed integer problems. If |
|
455 |
// no solution exists, the return value is zero. |
|
566 |
LpCplex::VarStatus LpCplex::_getRowStatus(int i) const { |
|
567 |
if (_row_status.empty()) { |
|
568 |
_row_status.resize(CPXgetnumrows(cplexEnv(), _prob)); |
|
569 |
CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front()); |
|
570 |
} |
|
571 |
switch (_row_status[i]) { |
|
572 |
case CPX_BASIC: |
|
573 |
return BASIC; |
|
574 |
case CPX_AT_LOWER: |
|
575 |
{ |
|
576 |
char s; |
|
577 |
CPXgetsense(cplexEnv(), _prob, &s, i, i); |
|
578 |
return s != 'L' ? LOWER : UPPER; |
|
579 |
} |
|
580 |
case CPX_AT_UPPER: |
|
581 |
return UPPER; |
|
582 |
default: |
|
583 |
LEMON_ASSERT(false, "Wrong row status"); |
|
584 |
return LpCplex::VarStatus(); |
|
585 |
} |
|
586 |
} |
|
456 | 587 |
|
457 |
// For Simplex, Barrier |
|
458 |
// 1 CPX_OPTIMAL |
|
459 |
// Optimal solution found |
|
460 |
// 2 CPX_INFEASIBLE |
|
461 |
// Problem infeasible |
|
462 |
// 3 CPX_UNBOUNDED |
|
463 |
// Problem unbounded |
|
464 |
// 4 CPX_OBJ_LIM |
|
465 |
// Objective limit exceeded in Phase II |
|
466 |
// 5 CPX_IT_LIM_FEAS |
|
467 |
// Iteration limit exceeded in Phase II |
|
468 |
// 6 CPX_IT_LIM_INFEAS |
|
469 |
// Iteration limit exceeded in Phase I |
|
470 |
// 7 CPX_TIME_LIM_FEAS |
|
471 |
// Time limit exceeded in Phase II |
|
472 |
// 8 CPX_TIME_LIM_INFEAS |
|
473 |
// Time limit exceeded in Phase I |
|
474 |
// 9 CPX_NUM_BEST_FEAS |
|
475 |
// Problem non-optimal, singularities in Phase II |
|
476 |
// 10 CPX_NUM_BEST_INFEAS |
|
477 |
// Problem non-optimal, singularities in Phase I |
|
478 |
// 11 CPX_OPTIMAL_INFEAS |
|
479 |
// Optimal solution found, unscaled infeasibilities |
|
480 |
// 12 CPX_ABORT_FEAS |
|
481 |
// Aborted in Phase II |
|
482 |
// 13 CPX_ABORT_INFEAS |
|
483 |
// Aborted in Phase I |
|
484 |
// 14 CPX_ABORT_DUAL_INFEAS |
|
485 |
// Aborted in barrier, dual infeasible |
|
486 |
// 15 CPX_ABORT_PRIM_INFEAS |
|
487 |
// Aborted in barrier, primal infeasible |
|
488 |
// 16 CPX_ABORT_PRIM_DUAL_INFEAS |
|
489 |
// Aborted in barrier, primal and dual infeasible |
|
490 |
// 17 CPX_ABORT_PRIM_DUAL_FEAS |
|
491 |
// Aborted in barrier, primal and dual feasible |
|
492 |
// 18 CPX_ABORT_CROSSOVER |
|
493 |
// Aborted in crossover |
|
494 |
// 19 CPX_INForUNBD |
|
495 |
// Infeasible or unbounded |
|
496 |
// 20 CPX_PIVOT |
|
497 |
// User pivot used |
|
498 |
// |
|
499 |
// Ezeket hova tegyem: |
|
500 |
// ??case CPX_ABORT_DUAL_INFEAS |
|
501 |
// ??case CPX_ABORT_CROSSOVER |
|
502 |
// ??case CPX_INForUNBD |
|
503 |
|
|
588 |
LpCplex::Value LpCplex::_getPrimalRay(int i) const { |
|
589 |
if (_primal_ray.empty()) { |
|
590 |
_primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob)); |
|
591 |
CPXgetray(cplexEnv(), _prob, &_primal_ray.front()); |
|
592 |
} |
|
593 |
return _primal_ray[i]; |
|
594 |
} |
|
504 | 595 |
|
505 |
|
|
596 |
LpCplex::Value LpCplex::_getDualRay(int i) const { |
|
597 |
if (_dual_ray.empty()) { |
|
506 | 598 |
|
507 |
// CPX_PARAM_LPMETHOD 1062 int LPMETHOD |
|
508 |
// 0 Automatic |
|
509 |
// 1 Primal Simplex |
|
510 |
// 2 Dual Simplex |
|
511 |
// 3 Network Simplex |
|
512 |
// 4 Standard Barrier |
|
513 |
// Default: 0 |
|
514 |
// Description: Method for linear optimization. |
|
515 |
// Determines which algorithm is used when CPXlpopt() (or "optimize" |
|
516 |
// in the Interactive Optimizer) is called. Currently the behavior of |
|
517 |
// the "Automatic" setting is that CPLEX simply invokes the dual |
|
518 |
// simplex method, but this capability may be expanded in the future |
|
519 |
|
|
599 |
} |
|
600 |
return _dual_ray[i]; |
|
601 |
} |
|
602 |
|
|
603 |
//7.5-os cplex statusai (Vigyazat: a 9.0-asei masok!) |
|
604 |
// This table lists the statuses, returned by the CPXgetstat() |
|
605 |
// routine, for solutions to LP problems or mixed integer problems. If |
|
606 |
// no solution exists, the return value is zero. |
|
607 |
|
|
608 |
// For Simplex, Barrier |
|
609 |
// 1 CPX_OPTIMAL |
|
610 |
// Optimal solution found |
|
611 |
// 2 CPX_INFEASIBLE |
|
612 |
// Problem infeasible |
|
613 |
// 3 CPX_UNBOUNDED |
|
614 |
// Problem unbounded |
|
615 |
// 4 CPX_OBJ_LIM |
|
616 |
// Objective limit exceeded in Phase II |
|
617 |
// 5 CPX_IT_LIM_FEAS |
|
618 |
// Iteration limit exceeded in Phase II |
|
619 |
// 6 CPX_IT_LIM_INFEAS |
|
620 |
// Iteration limit exceeded in Phase I |
|
621 |
// 7 CPX_TIME_LIM_FEAS |
|
622 |
// Time limit exceeded in Phase II |
|
623 |
// 8 CPX_TIME_LIM_INFEAS |
|
624 |
// Time limit exceeded in Phase I |
|
625 |
// 9 CPX_NUM_BEST_FEAS |
|
626 |
// Problem non-optimal, singularities in Phase II |
|
627 |
// 10 CPX_NUM_BEST_INFEAS |
|
628 |
// Problem non-optimal, singularities in Phase I |
|
629 |
// 11 CPX_OPTIMAL_INFEAS |
|
630 |
// Optimal solution found, unscaled infeasibilities |
|
631 |
// 12 CPX_ABORT_FEAS |
|
632 |
// Aborted in Phase II |
|
633 |
// 13 CPX_ABORT_INFEAS |
|
634 |
// Aborted in Phase I |
|
635 |
// 14 CPX_ABORT_DUAL_INFEAS |
|
636 |
// Aborted in barrier, dual infeasible |
|
637 |
// 15 CPX_ABORT_PRIM_INFEAS |
|
638 |
// Aborted in barrier, primal infeasible |
|
639 |
// 16 CPX_ABORT_PRIM_DUAL_INFEAS |
|
640 |
// Aborted in barrier, primal and dual infeasible |
|
641 |
// 17 CPX_ABORT_PRIM_DUAL_FEAS |
|
642 |
// Aborted in barrier, primal and dual feasible |
|
643 |
// 18 CPX_ABORT_CROSSOVER |
|
644 |
// Aborted in crossover |
|
645 |
// 19 CPX_INForUNBD |
|
646 |
// Infeasible or unbounded |
|
647 |
// 20 CPX_PIVOT |
|
648 |
// User pivot used |
|
649 |
// |
|
650 |
// Ezeket hova tegyem: |
|
651 |
// ??case CPX_ABORT_DUAL_INFEAS |
|
652 |
// ??case CPX_ABORT_CROSSOVER |
|
653 |
// ??case CPX_INForUNBD |
|
654 |
// ??case CPX_PIVOT |
|
655 |
|
|
656 |
//Some more interesting stuff: |
|
657 |
|
|
658 |
// CPX_PARAM_PROBMETHOD 1062 int LPMETHOD |
|
659 |
// 0 Automatic |
|
660 |
// 1 Primal Simplex |
|
661 |
// 2 Dual Simplex |
|
662 |
// 3 Network Simplex |
|
663 |
// 4 Standard Barrier |
|
664 |
// Default: 0 |
|
665 |
// Description: Method for linear optimization. |
|
666 |
// Determines which algorithm is used when CPXlpopt() (or "optimize" |
|
667 |
// in the Interactive Optimizer) is called. Currently the behavior of |
|
668 |
// the "Automatic" setting is that CPLEX simply invokes the dual |
|
669 |
// simplex method, but this capability may be expanded in the future |
|
670 |
// so that CPLEX chooses the method based on problem characteristics |
|
520 | 671 |
#if CPX_VERSION < 900 |
521 |
void statusSwitch(CPXENVptr |
|
672 |
void statusSwitch(CPXENVptr cplexEnv(),int& stat){ |
|
522 | 673 |
int lpmethod; |
523 |
CPXgetintparam ( |
|
674 |
CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod); |
|
524 | 675 |
if (lpmethod==2){ |
525 | 676 |
if (stat==CPX_UNBOUNDED){ |
... | ... |
@@ -536,6 +687,211 @@ |
536 | 687 |
#endif |
537 | 688 |
|
538 |
LpCplex::SolutionStatus LpCplex::_getPrimalStatus() const |
|
539 |
{ |
|
689 |
LpCplex::ProblemType LpCplex::_getPrimalType() const { |
|
690 |
// Unboundedness not treated well: the following is from cplex 9.0 doc |
|
691 |
// About Unboundedness |
|
692 |
|
|
693 |
// The treatment of models that are unbounded involves a few |
|
694 |
// subtleties. Specifically, a declaration of unboundedness means that |
|
695 |
// ILOG CPLEX has determined that the model has an unbounded |
|
696 |
// ray. Given any feasible solution x with objective z, a multiple of |
|
697 |
// the unbounded ray can be added to x to give a feasible solution |
|
698 |
// with objective z-1 (or z+1 for maximization models). Thus, if a |
|
699 |
// feasible solution exists, then the optimal objective is |
|
700 |
// unbounded. Note that ILOG CPLEX has not necessarily concluded that |
|
701 |
// a feasible solution exists. Users can call the routine CPXsolninfo |
|
702 |
// to determine whether ILOG CPLEX has also concluded that the model |
|
703 |
// has a feasible solution. |
|
704 |
|
|
705 |
int stat = CPXgetstat(cplexEnv(), _prob); |
|
706 |
#if CPX_VERSION >= 800 |
|
707 |
switch (stat) |
|
708 |
{ |
|
709 |
case CPX_STAT_OPTIMAL: |
|
710 |
return OPTIMAL; |
|
711 |
case CPX_STAT_UNBOUNDED: |
|
712 |
return UNBOUNDED; |
|
713 |
case CPX_STAT_INFEASIBLE: |
|
714 |
return INFEASIBLE; |
|
715 |
default: |
|
716 |
return UNDEFINED; |
|
717 |
} |
|
718 |
#else |
|
719 |
statusSwitch(cplexEnv(),stat); |
|
720 |
//CPXgetstat(cplexEnv(), _prob); |
|
721 |
//printf("A primal status: %d, CPX_OPTIMAL=%d \n",stat,CPX_OPTIMAL); |
|
722 |
switch (stat) { |
|
723 |
case 0: |
|
724 |
return UNDEFINED; //Undefined |
|
725 |
case CPX_OPTIMAL://Optimal |
|
726 |
return OPTIMAL; |
|
727 |
case CPX_UNBOUNDED://Unbounded |
|
728 |
return INFEASIBLE;//In case of dual simplex |
|
729 |
//return UNBOUNDED; |
|
730 |
case CPX_INFEASIBLE://Infeasible |
|
731 |
// case CPX_IT_LIM_INFEAS: |
|
732 |
// case CPX_TIME_LIM_INFEAS: |
|
733 |
// case CPX_NUM_BEST_INFEAS: |
|
734 |
// case CPX_OPTIMAL_INFEAS: |
|
735 |
// case CPX_ABORT_INFEAS: |
|
736 |
// case CPX_ABORT_PRIM_INFEAS: |
|
737 |
// case CPX_ABORT_PRIM_DUAL_INFEAS: |
|
738 |
return UNBOUNDED;//In case of dual simplex |
|
739 |
//return INFEASIBLE; |
|
740 |
// case CPX_OBJ_LIM: |
|
741 |
// case CPX_IT_LIM_FEAS: |
|
742 |
// case CPX_TIME_LIM_FEAS: |
|
743 |
// case CPX_NUM_BEST_FEAS: |
|
744 |
// case CPX_ABORT_FEAS: |
|
745 |
// case CPX_ABORT_PRIM_DUAL_FEAS: |
|
746 |
// return FEASIBLE; |
|
747 |
default: |
|
748 |
return UNDEFINED; //Everything else comes here |
|
749 |
//FIXME error |
|
750 |
} |
|
751 |
#endif |
|
752 |
} |
|
753 |
|
|
754 |
//9.0-as cplex verzio statusai |
|
755 |
// CPX_STAT_ABORT_DUAL_OBJ_LIM |
|
756 |
// CPX_STAT_ABORT_IT_LIM |
|
757 |
// CPX_STAT_ABORT_OBJ_LIM |
|
758 |
// CPX_STAT_ABORT_PRIM_OBJ_LIM |
|
759 |
// CPX_STAT_ABORT_TIME_LIM |
|
760 |
// CPX_STAT_ABORT_USER |
|
761 |
// CPX_STAT_FEASIBLE_RELAXED |
|
762 |
// CPX_STAT_INFEASIBLE |
|
763 |
// CPX_STAT_INForUNBD |
|
764 |
// CPX_STAT_NUM_BEST |
|
765 |
// CPX_STAT_OPTIMAL |
|
766 |
// CPX_STAT_OPTIMAL_FACE_UNBOUNDED |
|
767 |
// CPX_STAT_OPTIMAL_INFEAS |
|
768 |
// CPX_STAT_OPTIMAL_RELAXED |
|
769 |
// CPX_STAT_UNBOUNDED |
|
770 |
|
|
771 |
LpCplex::ProblemType LpCplex::_getDualType() const { |
|
772 |
int stat = CPXgetstat(cplexEnv(), _prob); |
|
773 |
#if CPX_VERSION >= 800 |
|
774 |
switch (stat) { |
|
775 |
case CPX_STAT_OPTIMAL: |
|
776 |
return OPTIMAL; |
|
777 |
case CPX_STAT_UNBOUNDED: |
|
778 |
return INFEASIBLE; |
|
779 |
default: |
|
780 |
return UNDEFINED; |
|
781 |
} |
|
782 |
#else |
|
783 |
statusSwitch(cplexEnv(),stat); |
|
784 |
switch (stat) { |
|
785 |
case 0: |
|
786 |
return UNDEFINED; //Undefined |
|
787 |
case CPX_OPTIMAL://Optimal |
|
788 |
return OPTIMAL; |
|
789 |
case CPX_UNBOUNDED: |
|
790 |
return INFEASIBLE; |
|
791 |
default: |
|
792 |
return UNDEFINED; //Everything else comes here |
|
793 |
//FIXME error |
|
794 |
} |
|
795 |
#endif |
|
796 |
} |
|
797 |
|
|
798 |
// MipCplex members |
|
799 |
|
|
800 |
MipCplex::MipCplex() |
|
801 |
: LpBase(), CplexBase(), MipSolver() { |
|
802 |
|
|
803 |
#if CPX_VERSION < 800 |
|
804 |
CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP); |
|
805 |
#else |
|
806 |
CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP); |
|
807 |
#endif |
|
808 |
} |
|
809 |
|
|
810 |
MipCplex::MipCplex(const CplexEnv& env) |
|
811 |
: LpBase(), CplexBase(env), MipSolver() { |
|
812 |
|
|
813 |
#if CPX_VERSION < 800 |
|
814 |
CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP); |
|
815 |
#else |
|
816 |
CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP); |
|
817 |
#endif |
|
818 |
|
|
819 |
} |
|
820 |
|
|
821 |
MipCplex::MipCplex(const MipCplex& other) |
|
822 |
: LpBase(), CplexBase(other), MipSolver() {} |
|
823 |
|
|
824 |
MipCplex::~MipCplex() {} |
|
825 |
|
|
826 |
MipCplex* MipCplex::_newSolver() const { return new MipCplex; } |
|
827 |
MipCplex* MipCplex::_cloneSolver() const {return new MipCplex(*this); } |
|
828 |
|
|
829 |
const char* MipCplex::_solverName() const { return "MipCplex"; } |
|
830 |
|
|
831 |
void MipCplex::_setColType(int i, MipCplex::ColTypes col_type) { |
|
832 |
|
|
833 |
// Note If a variable is to be changed to binary, a call to CPXchgbds |
|
834 |
// should also be made to change the bounds to 0 and 1. |
|
835 |
|
|
836 |
switch (col_type){ |
|
837 |
case INTEGER: { |
|
838 |
const char t = 'I'; |
|
839 |
CPXchgctype (cplexEnv(), _prob, 1, &i, &t); |
|
840 |
} break; |
|
841 |
case REAL: { |
|
842 |
const char t = 'C'; |
|
843 |
CPXchgctype (cplexEnv(), _prob, 1, &i, &t); |
|
844 |
} break; |
|
845 |
default: |
|
846 |
break; |
|
847 |
} |
|
848 |
} |
|
849 |
|
|
850 |
MipCplex::ColTypes MipCplex::_getColType(int i) const { |
|
851 |
char t; |
|
852 |
CPXgetctype (cplexEnv(), _prob, &t, i, i); |
|
853 |
switch (t) { |
|
854 |
case 'I': |
|
855 |
return INTEGER; |
|
856 |
case 'C': |
|
857 |
return REAL; |
|
858 |
default: |
|
859 |
LEMON_ASSERT(false, "Invalid column type"); |
|
860 |
return ColTypes(); |
|
861 |
} |
|
862 |
|
|
863 |
} |
|
864 |
|
|
865 |
MipCplex::SolveExitStatus MipCplex::_solve() { |
|
866 |
int status; |
|
867 |
status = CPXmipopt (cplexEnv(), _prob); |
|
868 |
if (status==0) |
|
869 |
return SOLVED; |
|
870 |
else |
|
871 |
return UNSOLVED; |
|
872 |
|
|
873 |
} |
|
874 |
|
|
875 |
|
|
876 |
MipCplex::ProblemType MipCplex::_getType() const { |
|
877 |
|
|
878 |
int stat = CPXgetstat(cplexEnv(), _prob); |
|
879 |
|
|
880 |
//Fortunately, MIP statuses did not change for cplex 8.0 |
|
881 |
switch (stat) { |
|
882 |
case CPXMIP_OPTIMAL: |
|
883 |
// Optimal integer solution has been found. |
|
884 |
case CPXMIP_OPTIMAL_TOL: |
|
885 |
// Optimal soluton with the tolerance defined by epgap or epagap has |
|
886 |
// been found. |
|
887 |
return OPTIMAL; |
|
888 |
//This also exists in later issues |
|
889 |
// case CPXMIP_UNBOUNDED: |
|
890 |
//return UNBOUNDED; |
|
891 |
case CPXMIP_INFEASIBLE: |
|
892 |
return INFEASIBLE; |
|
893 |
default: |
|
894 |
return UNDEFINED; |
|
895 |
} |
|
540 | 896 |
//Unboundedness not treated well: the following is from cplex 9.0 doc |
541 | 897 |
// About Unboundedness |
... | ... |
@@ -552,146 +908,16 @@ |
552 | 908 |
// to determine whether ILOG CPLEX has also concluded that the model |
553 | 909 |
// has a feasible solution. |
554 |
|
|
555 |
int stat = CPXgetstat(env, lp); |
|
556 |
#if CPX_VERSION >= 800 |
|
557 |
switch (stat) |
|
558 |
{ |
|
559 |
case CPX_STAT_OPTIMAL: |
|
560 |
return OPTIMAL; |
|
561 |
case CPX_STAT_UNBOUNDED: |
|
562 |
return INFINITE; |
|
563 |
case CPX_STAT_INFEASIBLE: |
|
564 |
return INFEASIBLE; |
|
565 |
default: |
|
566 |
return UNDEFINED; |
|
567 |
} |
|
568 |
#else |
|
569 |
statusSwitch(env,stat); |
|
570 |
//CPXgetstat(env, lp); |
|
571 |
//printf("A primal status: %d, CPX_OPTIMAL=%d \n",stat,CPX_OPTIMAL); |
|
572 |
switch (stat) { |
|
573 |
case 0: |
|
574 |
return UNDEFINED; //Undefined |
|
575 |
case CPX_OPTIMAL://Optimal |
|
576 |
return OPTIMAL; |
|
577 |
case CPX_UNBOUNDED://Unbounded |
|
578 |
return INFEASIBLE;//In case of dual simplex |
|
579 |
//return INFINITE; |
|
580 |
case CPX_INFEASIBLE://Infeasible |
|
581 |
// case CPX_IT_LIM_INFEAS: |
|
582 |
// case CPX_TIME_LIM_INFEAS: |
|
583 |
// case CPX_NUM_BEST_INFEAS: |
|
584 |
// case CPX_OPTIMAL_INFEAS: |
|
585 |
// case CPX_ABORT_INFEAS: |
|
586 |
// case CPX_ABORT_PRIM_INFEAS: |
|
587 |
// case CPX_ABORT_PRIM_DUAL_INFEAS: |
|
588 |
return INFINITE;//In case of dual simplex |
|
589 |
//return INFEASIBLE; |
|
590 |
// case CPX_OBJ_LIM: |
|
591 |
// case CPX_IT_LIM_FEAS: |
|
592 |
// case CPX_TIME_LIM_FEAS: |
|
593 |
// case CPX_NUM_BEST_FEAS: |
|
594 |
// case CPX_ABORT_FEAS: |
|
595 |
// case CPX_ABORT_PRIM_DUAL_FEAS: |
|
596 |
// return FEASIBLE; |
|
597 |
default: |
|
598 |
return UNDEFINED; //Everything else comes here |
|
599 |
//FIXME error |
|
600 |
} |
|
601 |
#endif |
|
602 | 910 |
} |
603 | 911 |
|
604 |
//9.0-as cplex verzio statusai |
|
605 |
// CPX_STAT_ABORT_DUAL_OBJ_LIM |
|
606 |
// CPX_STAT_ABORT_IT_LIM |
|
607 |
// CPX_STAT_ABORT_OBJ_LIM |
|
608 |
// CPX_STAT_ABORT_PRIM_OBJ_LIM |
|
609 |
// CPX_STAT_ABORT_TIME_LIM |
|
610 |
// CPX_STAT_ABORT_USER |
|
611 |
// CPX_STAT_FEASIBLE_RELAXED |
|
612 |
// CPX_STAT_INFEASIBLE |
|
613 |
// CPX_STAT_INForUNBD |
|
614 |
// CPX_STAT_NUM_BEST |
|
615 |
// CPX_STAT_OPTIMAL |
|
616 |
// CPX_STAT_OPTIMAL_FACE_UNBOUNDED |
|
617 |
// CPX_STAT_OPTIMAL_INFEAS |
|
618 |
// CPX_STAT_OPTIMAL_RELAXED |
|
619 |
// CPX_STAT_UNBOUNDED |
|
620 |
|
|
621 |
LpCplex::SolutionStatus LpCplex::_getDualStatus() const |
|
622 |
{ |
|
623 |
int stat = CPXgetstat(env, lp); |
|
624 |
#if CPX_VERSION >= 800 |
|
625 |
switch (stat) |
|
626 |
{ |
|
627 |
case CPX_STAT_OPTIMAL: |
|
628 |
return OPTIMAL; |
|
629 |
case CPX_STAT_UNBOUNDED: |
|
630 |
return INFEASIBLE; |
|
631 |
default: |
|
632 |
return UNDEFINED; |
|
633 |
} |
|
634 |
#else |
|
635 |
statusSwitch(env,stat); |
|
636 |
switch (stat) { |
|
637 |
case 0: |
|
638 |
return UNDEFINED; //Undefined |
|
639 |
case CPX_OPTIMAL://Optimal |
|
640 |
return OPTIMAL; |
|
641 |
case CPX_UNBOUNDED: |
|
642 |
return INFEASIBLE; |
|
643 |
default: |
|
644 |
return UNDEFINED; //Everything else comes here |
|
645 |
//FIXME error |
|
646 |
} |
|
647 |
#endif |
|
912 |
MipCplex::Value MipCplex::_getSol(int i) const { |
|
913 |
Value x; |
|
914 |
CPXgetmipx(cplexEnv(), _prob, &x, i, i); |
|
915 |
return x; |
|
648 | 916 |
} |
649 | 917 |
|
650 |
LpCplex::ProblemTypes LpCplex::_getProblemType() const |
|
651 |
{ |
|
652 |
int stat = CPXgetstat(env, lp); |
|
653 |
#if CPX_VERSION >= 800 |
|
654 |
switch (stat) |
|
655 |
{ |
|
656 |
case CPX_STAT_OPTIMAL: |
|
657 |
return PRIMAL_DUAL_FEASIBLE; |
|
658 |
case CPX_STAT_UNBOUNDED: |
|
659 |
return PRIMAL_FEASIBLE_DUAL_INFEASIBLE; |
|
660 |
default: |
|
661 |
return UNKNOWN; |
|
662 |
} |
|
663 |
#else |
|
664 |
switch (stat) { |
|
665 |
case CPX_OPTIMAL://Optimal |
|
666 |
return PRIMAL_DUAL_FEASIBLE; |
|
667 |
case CPX_UNBOUNDED: |
|
668 |
return PRIMAL_FEASIBLE_DUAL_INFEASIBLE; |
|
669 |
// return PRIMAL_INFEASIBLE_DUAL_FEASIBLE; |
|
670 |
// return PRIMAL_DUAL_INFEASIBLE; |
|
671 |
|
|
672 |
//Seems to be that this is all we can say for sure |
|
673 |
default: |
|
674 |
//In all other cases |
|
675 |
return UNKNOWN; |
|
676 |
//FIXME error |
|
677 |
} |
|
678 |
#endif |
|
679 |
} |
|
680 |
|
|
681 |
void LpCplex::_setMax() |
|
682 |
{ |
|
683 |
CPXchgobjsen(env, lp, CPX_MAX); |
|
684 |
} |
|
685 |
void LpCplex::_setMin() |
|
686 |
{ |
|
687 |
CPXchgobjsen(env, lp, CPX_MIN); |
|
688 |
} |
|
689 |
|
|
690 |
bool LpCplex::_isMax() const |
|
691 |
{ |
|
692 |
if (CPXgetobjsen(env, lp)==CPX_MAX) |
|
693 |
return true; |
|
694 |
else |
|
695 |
return false; |
|
918 |
MipCplex::Value MipCplex::_getSolValue() const { |
|
919 |
Value objval; |
|
920 |
CPXgetmipobjval(cplexEnv(), _prob, &objval); |
|
921 |
return objval; |
|
696 | 922 |
} |
697 | 923 |
... | ... |
@@ -30,43 +30,89 @@ |
30 | 30 |
namespace lemon { |
31 | 31 |
|
32 |
|
|
33 |
/// \brief Interface for the CPLEX solver |
|
32 |
/// \brief Reference counted wrapper around cpxenv pointer |
|
34 | 33 |
/// |
35 |
/// This class implements an interface for the CPLEX LP solver. |
|
36 |
class LpCplex :virtual public LpSolverBase { |
|
34 |
/// The cplex uses environment object which is responsible for |
|
35 |
/// checking the proper license usage. This class provides a simple |
|
36 |
/// interface for share the environment object between different |
|
37 |
/// problems. |
|
38 |
class CplexEnv { |
|
39 |
friend class CplexBase; |
|
40 |
private: |
|
41 |
cpxenv* _env; |
|
42 |
mutable int* _cnt; |
|
37 | 43 |
|
38 | 44 |
public: |
39 | 45 |
|
40 |
|
|
46 |
/// \brief This exception is thrown when the license check is not |
|
47 |
/// sufficient |
|
48 |
class LicenseError : public Exception { |
|
49 |
friend class CplexEnv; |
|
50 |
private: |
|
41 | 51 |
|
42 |
/// \e |
|
43 |
int status; |
|
44 |
cpxenv* env; |
|
45 |
cpxlp* lp; |
|
52 |
LicenseError(int status); |
|
53 |
char _message[510]; |
|
46 | 54 |
|
55 |
public: |
|
47 | 56 |
|
48 |
/// \e |
|
49 |
LpCplex(); |
|
50 |
/// \e |
|
51 |
LpCplex(const LpCplex&); |
|
52 |
/// \e |
|
53 |
~LpCplex(); |
|
57 |
/// The short error message |
|
58 |
virtual const char* what() const throw() { |
|
59 |
return _message; |
|
60 |
} |
|
61 |
}; |
|
62 |
|
|
63 |
/// Constructor |
|
64 |
CplexEnv(); |
|
65 |
/// Shallow copy constructor |
|
66 |
CplexEnv(const CplexEnv&); |
|
67 |
/// Shallow assignement |
|
68 |
CplexEnv& operator=(const CplexEnv&); |
|
69 |
/// Destructor |
|
70 |
virtual ~CplexEnv(); |
|
54 | 71 |
|
55 | 72 |
protected: |
56 |
virtual LpSolverBase* _newLp(); |
|
57 |
virtual LpSolverBase* _copyLp(); |
|
58 | 73 |
|
74 |
cpxenv* cplexEnv() { return _env; } |
|
75 |
const cpxenv* cplexEnv() const { return _env; } |
|
76 |
}; |
|
77 |
|
|
78 |
/// \brief Base interface for the CPLEX LP and MIP solver |
|
79 |
/// |
|
80 |
/// This class implements the common interface of the CPLEX LP and |
|
81 |
/// MIP solvers. |
|
82 |
/// \ingroup lp_group |
|
83 |
class CplexBase : virtual public LpBase { |
|
84 |
protected: |
|
85 |
|
|
86 |
CplexEnv _env; |
|
87 |
cpxlp* _prob; |
|
88 |
|
|
89 |
CplexBase(); |
|
90 |
CplexBase(const CplexEnv&); |
|
91 |
CplexBase(const CplexBase &); |
|
92 |
virtual ~CplexBase(); |
|
59 | 93 |
|
60 | 94 |
virtual int _addCol(); |
61 | 95 |
virtual int _addRow(); |
96 |
|
|
62 | 97 |
virtual void _eraseCol(int i); |
63 | 98 |
virtual void _eraseRow(int i); |
64 |
virtual void _getColName(int col, std::string & name) const; |
|
65 |
virtual void _setColName(int col, const std::string & name); |
|
99 |
|
|
100 |
virtual void _eraseColId(int i); |
|
101 |
virtual void _eraseRowId(int i); |
|
102 |
|
|
103 |
virtual void _getColName(int col, std::string& name) const; |
|
104 |
virtual void _setColName(int col, const std::string& name); |
|
66 | 105 |
virtual int _colByName(const std::string& name) const; |
67 |
virtual void _setRowCoeffs(int i, ConstRowIterator b, ConstRowIterator e); |
|
68 |
virtual void _getRowCoeffs(int i, RowIterator b) const; |
|
69 |
virtual void _setColCoeffs(int i, ConstColIterator b, ConstColIterator e); |
|
70 |
virtual void _getColCoeffs(int i, ColIterator b) const; |
|
106 |
|
|
107 |
virtual void _getRowName(int row, std::string& name) const; |
|
108 |
virtual void _setRowName(int row, const std::string& name); |
|
109 |
virtual int _rowByName(const std::string& name) const; |
|
110 |
|
|
111 |
virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); |
|
112 |
virtual void _getRowCoeffs(int i, InsertIterator b) const; |
|
113 |
|
|
114 |
virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); |
|
115 |
virtual void _getColCoeffs(int i, InsertIterator b) const; |
|
116 |
|
|
71 | 117 |
virtual void _setCoeff(int row, int col, Value value); |
72 | 118 |
virtual Value _getCoeff(int row, int col) const; |
... | ... |
@@ -74,15 +120,75 @@ |
74 | 120 |
virtual void _setColLowerBound(int i, Value value); |
75 | 121 |
virtual Value _getColLowerBound(int i) const; |
122 |
|
|
76 | 123 |
virtual void _setColUpperBound(int i, Value value); |
77 | 124 |
virtual Value _getColUpperBound(int i) const; |
78 | 125 |
|
79 |
// virtual void _setRowLowerBound(int i, Value value); |
|
80 |
// virtual void _setRowUpperBound(int i, Value value); |
|
81 |
virtual void _setRowBounds(int i, Value lower, Value upper); |
|
82 |
virtual void _getRowBounds(int i, Value &lb, Value &ub) const; |
|
126 |
private: |
|
127 |
void _set_row_bounds(int i, Value lb, Value ub); |
|
128 |
protected: |
|
129 |
|
|
130 |
virtual void _setRowLowerBound(int i, Value value); |
|
131 |
virtual Value _getRowLowerBound(int i) const; |
|
132 |
|
|
133 |
virtual void _setRowUpperBound(int i, Value value); |
|
134 |
virtual Value _getRowUpperBound(int i) const; |
|
135 |
|
|
136 |
virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); |
|
137 |
virtual void _getObjCoeffs(InsertIterator b) const; |
|
138 |
|
|
83 | 139 |
virtual void _setObjCoeff(int i, Value obj_coef); |
84 | 140 |
virtual Value _getObjCoeff(int i) const; |
85 |
virtual void _clearObj(); |
|
86 | 141 |
|
142 |
virtual void _setSense(Sense sense); |
|
143 |
virtual Sense _getSense() const; |
|
144 |
|
|
145 |
virtual void _clear(); |
|
146 |
|
|
147 |
public: |
|
148 |
|
|
149 |
/// Returns the used \c CplexEnv instance |
|
150 |
const CplexEnv& env() const { return _env; } |
|
151 |
/// |
|
152 |
const cpxenv* cplexEnv() const { return _env.cplexEnv(); } |
|
153 |
|
|
154 |
cpxlp* cplexLp() { return _prob; } |
|
155 |
const cpxlp* cplexLp() const { return _prob; } |
|
156 |
|
|
157 |
}; |
|
158 |
|
|
159 |
/// \brief Interface for the CPLEX LP solver |
|
160 |
/// |
|
161 |
/// This class implements an interface for the CPLEX LP solver. |
|
162 |
///\ingroup lp_group |
|
163 |
class LpCplex : public CplexBase, public LpSolver { |
|
164 |
public: |
|
165 |
/// \e |
|
166 |
LpCplex(); |
|
167 |
/// \e |
|
168 |
LpCplex(const CplexEnv&); |
|
169 |
/// \e |
|
170 |
LpCplex(const LpCplex&); |
|
171 |
/// \e |
|
172 |
virtual ~LpCplex(); |
|
173 |
|
|
174 |
private: |
|
175 |
|
|
176 |
// these values cannot retrieved element by element |
|
177 |
mutable std::vector<int> _col_status; |
|
178 |
mutable std::vector<int> _row_status; |
|
179 |
|
|
180 |
mutable std::vector<Value> _primal_ray; |
|
181 |
mutable std::vector<Value> _dual_ray; |
|
182 |
|
|
183 |
void _clear_temporals(); |
|
184 |
|
|
185 |
SolveExitStatus convertStatus(int status); |
|
186 |
|
|
187 |
protected: |
|
188 |
|
|
189 |
virtual LpCplex* _cloneSolver() const; |
|
190 |
virtual LpCplex* _newSolver() const; |
|
191 |
|
|
192 |
virtual const char* _solverName() const; |
|
87 | 193 |
|
88 | 194 |
virtual SolveExitStatus _solve(); |
... | ... |
@@ -90,22 +196,59 @@ |
90 | 196 |
virtual Value _getDual(int i) const; |
91 | 197 |
virtual Value _getPrimalValue() const; |
92 |
virtual bool _isBasicCol(int i) const; |
|
93 | 198 |
|
94 |
virtual SolutionStatus _getPrimalStatus() const; |
|
95 |
virtual SolutionStatus _getDualStatus() const; |
|
96 |
virtual |
|
199 |
virtual VarStatus _getColStatus(int i) const; |
|
200 |
virtual VarStatus _getRowStatus(int i) const; |
|
97 | 201 |
|
202 |
virtual Value _getPrimalRay(int i) const; |
|
203 |
virtual Value _getDualRay(int i) const; |
|
98 | 204 |
|
99 |
virtual void _setMax(); |
|
100 |
virtual void _setMin(); |
|
101 |
|
|
102 |
virtual bool _isMax() const; |
|
205 |
virtual ProblemType _getPrimalType() const; |
|
206 |
virtual ProblemType _getDualType() const; |
|
103 | 207 |
|
104 | 208 |
public: |
105 | 209 |
|
106 |
cpxenv* cplexEnv() { return env; } |
|
107 |
cpxlp* cplexLp() { return lp; } |
|
210 |
/// Solve with primal simplex method |
|
211 |
SolveExitStatus solvePrimal(); |
|
212 |
|
|
213 |
/// Solve with dual simplex method |
|
214 |
SolveExitStatus solveDual(); |
|
215 |
|
|
216 |
/// Solve with barrier method |
|
217 |
SolveExitStatus solveBarrier(); |
|
108 | 218 |
|
109 | 219 |
}; |
220 |
|
|
221 |
/// \brief Interface for the CPLEX MIP solver |
|
222 |
/// |
|
223 |
/// This class implements an interface for the CPLEX MIP solver. |
|
224 |
///\ingroup lp_group |
|
225 |
class MipCplex : public CplexBase, public MipSolver { |
|
226 |
public: |
|
227 |
/// \e |
|
228 |
MipCplex(); |
|
229 |
/// \e |
|
230 |
MipCplex(const CplexEnv&); |
|
231 |
/// \e |
|
232 |
MipCplex(const MipCplex&); |
|
233 |
/// \e |
|
234 |
virtual ~MipCplex(); |
|
235 |
|
|
236 |
protected: |
|
237 |
|
|
238 |
virtual MipCplex* _cloneSolver() const; |
|
239 |
virtual MipCplex* _newSolver() const; |
|
240 |
|
|
241 |
virtual const char* _solverName() const; |
|
242 |
|
|
243 |
virtual ColTypes _getColType(int col) const; |
|
244 |
virtual void _setColType(int col, ColTypes col_type); |
|
245 |
|
|
246 |
virtual SolveExitStatus _solve(); |
|
247 |
virtual ProblemType _getType() const; |
|
248 |
virtual Value _getSol(int i) const; |
|
249 |
virtual Value _getSolValue() const; |
|
250 |
|
|
251 |
}; |
|
252 |
|
|
110 | 253 |
} //END OF NAMESPACE LEMON |
111 | 254 |
... | ... |
@@ -18,627 +18,935 @@ |
18 | 18 |
|
19 | 19 |
///\file |
20 |
///\brief Implementation of the LEMON |
|
20 |
///\brief Implementation of the LEMON GLPK LP and MIP solver interface. |
|
21 | 21 |
|
22 | 22 |
#include <lemon/lp_glpk.h> |
23 |
|
|
23 |
#include <glpk.h> |
|
24 | 24 |
|
25 |
extern "C" { |
|
26 |
#include <glpk.h> |
|
27 |
} |
|
28 |
|
|
29 |
#if GLP_MAJOR_VERSION > 4 || (GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION > 15) |
|
30 |
#define LEMON_glp(func) (glp_##func) |
|
31 |
#define LEMON_lpx(func) (lpx_##func) |
|
32 |
|
|
33 |
#define LEMON_GLP(def) (GLP_##def) |
|
34 |
#define LEMON_LPX(def) (LPX_##def) |
|
35 |
|
|
36 |
#else |
|
37 |
|
|
38 |
#define LEMON_glp(func) (lpx_##func) |
|
39 |
#define LEMON_lpx(func) (lpx_##func) |
|
40 |
|
|
41 |
#define LEMON_GLP(def) (LPX_##def) |
|
42 |
#define LEMON_LPX(def) (LPX_##def) |
|
43 |
|
|
44 |
#endif |
|
25 |
#include <lemon/assert.h> |
|
45 | 26 |
|
46 | 27 |
namespace lemon { |
47 | 28 |
|
48 |
LpGlpk::LpGlpk() : Parent() { |
|
49 |
solved = false; |
|
50 |
rows = _lp_bits::LpId(1); |
|
51 |
cols = _lp_bits::LpId(1); |
|
52 |
lp = LEMON_glp(create_prob)(); |
|
53 |
LEMON_glp(create_index)(lp); |
|
54 |
|
|
29 |
// GlpkBase members |
|
30 |
|
|
31 |
GlpkBase::GlpkBase() : LpBase() { |
|
32 |
lp = glp_create_prob(); |
|
33 |
glp_create_index(lp); |
|
55 | 34 |
} |
56 | 35 |
|
57 |
LpGlpk::LpGlpk(const LpGlpk &glp) : Parent() { |
|
58 |
solved = false; |
|
59 |
rows = _lp_bits::LpId(1); |
|
60 |
cols = _lp_bits::LpId(1); |
|
61 |
lp = LEMON_glp(create_prob)(); |
|
62 |
LEMON_glp(create_index)(lp); |
|
63 |
messageLevel(0); |
|
64 |
//Coefficient matrix, row bounds |
|
65 |
LEMON_glp(add_rows)(lp, LEMON_glp(get_num_rows)(glp.lp)); |
|
66 |
LEMON_glp(add_cols)(lp, LEMON_glp(get_num_cols)(glp.lp)); |
|
67 |
int len; |
|
68 |
std::vector<int> ind(1+LEMON_glp(get_num_cols)(glp.lp)); |
|
69 |
std::vector<Value> val(1+LEMON_glp(get_num_cols)(glp.lp)); |
|
70 |
for (int i=1;i<=LEMON_glp(get_num_rows)(glp.lp);++i) |
|
71 |
{ |
|
72 |
len=LEMON_glp(get_mat_row)(glp.lp,i,&*ind.begin(),&*val.begin()); |
|
73 |
LEMON_glp(set_mat_row)(lp, i,len,&*ind.begin(),&*val.begin()); |
|
74 |
LEMON_glp(set_row_bnds)(lp,i, |
|
75 |
LEMON_glp(get_row_type)(glp.lp,i), |
|
76 |
LEMON_glp(get_row_lb)(glp.lp,i), |
|
77 |
LEMON_glp(get_row_ub)(glp.lp,i)); |
|
78 |
} |
|
79 |
|
|
80 |
//Objective function, coloumn bounds |
|
81 |
LEMON_glp(set_obj_dir)(lp, LEMON_glp(get_obj_dir)(glp.lp)); |
|
82 |
//Objectif function's constant term treated separately |
|
83 |
LEMON_glp(set_obj_coef)(lp,0,LEMON_glp(get_obj_coef)(glp.lp,0)); |
|
84 |
for (int i=1;i<=LEMON_glp(get_num_cols)(glp.lp);++i) |
|
85 |
{ |
|
86 |
LEMON_glp(set_obj_coef)(lp,i, |
|
87 |
LEMON_glp(get_obj_coef)(glp.lp,i)); |
|
88 |
LEMON_glp(set_col_bnds)(lp,i, |
|
89 |
LEMON_glp(get_col_type)(glp.lp,i), |
|
90 |
LEMON_glp(get_col_lb)(glp.lp,i), |
|
91 |
LEMON_glp(get_col_ub)(glp.lp,i)); |
|
92 |
} |
|
93 |
rows = glp.rows; |
|
94 |
cols = glp.cols; |
|
36 |
GlpkBase::GlpkBase(const GlpkBase &other) : LpBase() { |
|
37 |
lp = glp_create_prob(); |
|
38 |
glp_copy_prob(lp, other.lp, GLP_ON); |
|
39 |
glp_create_index(lp); |
|
40 |
rows = other.rows; |
|
41 |
cols = other.cols; |
|
95 | 42 |
} |
96 | 43 |
|
97 |
LpGlpk::~LpGlpk() { |
|
98 |
LEMON_glp(delete_prob)(lp); |
|
44 |
GlpkBase::~GlpkBase() { |
|
45 |
glp_delete_prob(lp); |
|
99 | 46 |
} |
100 | 47 |
|
101 |
int LpGlpk::_addCol() { |
|
102 |
int i=LEMON_glp(add_cols)(lp, 1); |
|
103 |
LEMON_glp(set_col_bnds)(lp, i, LEMON_GLP(FR), 0.0, 0.0); |
|
104 |
solved = false; |
|
48 |
int GlpkBase::_addCol() { |
|
49 |
int i = glp_add_cols(lp, 1); |
|
50 |
glp_set_col_bnds(lp, i, GLP_FR, 0.0, 0.0); |
|
105 | 51 |
return i; |
106 | 52 |
} |
107 | 53 |
|
108 |
///\e |
|
109 |
|
|
110 |
|
|
111 |
LpSolverBase* LpGlpk::_newLp() |
|
112 |
{ |
|
113 |
LpGlpk* newlp = new LpGlpk; |
|
114 |
return newlp; |
|
115 |
} |
|
116 |
|
|
117 |
///\e |
|
118 |
|
|
119 |
LpSolverBase* LpGlpk::_copyLp() |
|
120 |
{ |
|
121 |
LpGlpk *newlp = new LpGlpk(*this); |
|
122 |
return newlp; |
|
123 |
} |
|
124 |
|
|
125 |
int LpGlpk::_addRow() { |
|
126 |
int i=LEMON_glp(add_rows)(lp, 1); |
|
127 |
solved = false; |
|
54 |
int GlpkBase::_addRow() { |
|
55 |
int i = glp_add_rows(lp, 1); |
|
56 |
glp_set_row_bnds(lp, i, GLP_FR, 0.0, 0.0); |
|
128 | 57 |
return i; |
129 | 58 |
} |
130 | 59 |
|
131 |
|
|
132 |
void LpGlpk::_eraseCol(int i) { |
|
60 |
void GlpkBase::_eraseCol(int i) { |
|
133 | 61 |
int ca[2]; |
134 |
ca[1]=i; |
|
135 |
LEMON_glp(del_cols)(lp, 1, ca); |
|
136 |
|
|
62 |
ca[1] = i; |
|
63 |
glp_del_cols(lp, 1, ca); |
|
137 | 64 |
} |
138 | 65 |
|
139 |
void |
|
66 |
void GlpkBase::_eraseRow(int i) { |
|
140 | 67 |
int ra[2]; |
141 |
ra[1]=i; |
|
142 |
LEMON_glp(del_rows)(lp, 1, ra); |
|
143 |
|
|
68 |
ra[1] = i; |
|
69 |
glp_del_rows(lp, 1, ra); |
|
144 | 70 |
} |
145 | 71 |
|
146 |
void LpGlpk::_getColName(int c, std::string & name) const |
|
147 |
{ |
|
148 |
|
|
149 |
const char *n = LEMON_glp(get_col_name)(lp,c); |
|
150 |
|
|
72 |
void GlpkBase::_eraseColId(int i) { |
|
73 |
cols.eraseIndex(i); |
|
74 |
cols.shiftIndices(i); |
|
151 | 75 |
} |
152 | 76 |
|
77 |
void GlpkBase::_eraseRowId(int i) { |
|
78 |
rows.eraseIndex(i); |
|
79 |
rows.shiftIndices(i); |
|
80 |
} |
|
153 | 81 |
|
154 |
void LpGlpk::_setColName(int c, const std::string & name) |
|
155 |
{ |
|
156 |
|
|
82 |
void GlpkBase::_getColName(int c, std::string& name) const { |
|
83 |
const char *str = glp_get_col_name(lp, c); |
|
84 |
if (str) name = str; |
|
85 |
else name.clear(); |
|
86 |
} |
|
87 |
|
|
88 |
void GlpkBase::_setColName(int c, const std::string & name) { |
|
89 |
glp_set_col_name(lp, c, const_cast<char*>(name.c_str())); |
|
157 | 90 |
|
158 | 91 |
} |
159 | 92 |
|
160 |
int LpGlpk::_colByName(const std::string& name) const |
|
161 |
{ |
|
162 |
|
|
93 |
int GlpkBase::_colByName(const std::string& name) const { |
|
94 |
int k = glp_find_col(lp, const_cast<char*>(name.c_str())); |
|
163 | 95 |
return k > 0 ? k : -1; |
164 | 96 |
} |
165 | 97 |
|
98 |
void GlpkBase::_getRowName(int r, std::string& name) const { |
|
99 |
const char *str = glp_get_row_name(lp, r); |
|
100 |
if (str) name = str; |
|
101 |
else name.clear(); |
|
102 |
} |
|
166 | 103 |
|
167 |
void LpGlpk::_setRowCoeffs(int i, ConstRowIterator b, ConstRowIterator e) |
|
168 |
{ |
|
169 |
std:: |
|
104 |
void GlpkBase::_setRowName(int r, const std::string & name) { |
|
105 |
glp_set_row_name(lp, r, const_cast<char*>(name.c_str())); |
|
106 |
|
|
107 |
} |
|
108 |
|
|
109 |
int GlpkBase::_rowByName(const std::string& name) const { |
|
110 |
int k = glp_find_row(lp, const_cast<char*>(name.c_str())); |
|
111 |
return k > 0 ? k : -1; |
|
112 |
} |
|
113 |
|
|
114 |
void GlpkBase::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) { |
|
115 |
std::vector<int> indexes; |
|
170 | 116 |
std::vector<Value> values; |
171 | 117 |
|
172 |
|
|
118 |
indexes.push_back(0); |
|
173 | 119 |
values.push_back(0); |
174 | 120 |
|
175 |
for(ConstRowIterator it=b; it!=e; ++it) { |
|
176 |
indices.push_back(it->first); |
|
121 |
for(ExprIterator it = b; it != e; ++it) { |
|
122 |
indexes.push_back(it->first); |
|
177 | 123 |
values.push_back(it->second); |
178 | 124 |
} |
179 | 125 |
|
180 |
LEMON_glp(set_mat_row)(lp, i, values.size() - 1, |
|
181 |
&indices[0], &values[0]); |
|
182 |
|
|
183 |
solved = false; |
|
126 |
glp_set_mat_row(lp, i, values.size() - 1, |
|
127 |
&indexes.front(), &values.front()); |
|
184 | 128 |
} |
185 | 129 |
|
186 |
void LpGlpk::_getRowCoeffs(int ix, RowIterator b) const |
|
187 |
{ |
|
188 |
|
|
130 |
void GlpkBase::_getRowCoeffs(int ix, InsertIterator b) const { |
|
131 |
int length = glp_get_mat_row(lp, ix, 0, 0); |
|
189 | 132 |
|
190 |
std::vector<int> |
|
133 |
std::vector<int> indexes(length + 1); |
|
191 | 134 |
std::vector<Value> values(length + 1); |
192 | 135 |
|
193 |
|
|
136 |
glp_get_mat_row(lp, ix, &indexes.front(), &values.front()); |
|
194 | 137 |
|
195 | 138 |
for (int i = 1; i <= length; ++i) { |
196 |
*b = std::make_pair( |
|
139 |
*b = std::make_pair(indexes[i], values[i]); |
|
197 | 140 |
++b; |
198 | 141 |
} |
199 | 142 |
} |
200 | 143 |
|
201 |
void |
|
144 |
void GlpkBase::_setColCoeffs(int ix, ExprIterator b, |
|
145 |
ExprIterator e) { |
|
202 | 146 |
|
203 |
std::vector<int> |
|
147 |
std::vector<int> indexes; |
|
204 | 148 |
std::vector<Value> values; |
205 | 149 |
|
206 |
|
|
150 |
indexes.push_back(0); |
|
207 | 151 |
values.push_back(0); |
208 | 152 |
|
209 |
for(ConstColIterator it=b; it!=e; ++it) { |
|
210 |
indices.push_back(it->first); |
|
153 |
for(ExprIterator it = b; it != e; ++it) { |
|
154 |
indexes.push_back(it->first); |
|
211 | 155 |
values.push_back(it->second); |
212 | 156 |
} |
213 | 157 |
|
214 |
LEMON_glp(set_mat_col)(lp, ix, values.size() - 1, |
|
215 |
&indices[0], &values[0]); |
|
216 |
|
|
217 |
solved = false; |
|
158 |
glp_set_mat_col(lp, ix, values.size() - 1, |
|
159 |
&indexes.front(), &values.front()); |
|
218 | 160 |
} |
219 | 161 |
|
220 |
void LpGlpk::_getColCoeffs(int ix, ColIterator b) const |
|
221 |
{ |
|
222 |
|
|
162 |
void GlpkBase::_getColCoeffs(int ix, InsertIterator b) const { |
|
163 |
int length = glp_get_mat_col(lp, ix, 0, 0); |
|
223 | 164 |
|
224 |
std::vector<int> |
|
165 |
std::vector<int> indexes(length + 1); |
|
225 | 166 |
std::vector<Value> values(length + 1); |
226 | 167 |
|
227 |
|
|
168 |
glp_get_mat_col(lp, ix, &indexes.front(), &values.front()); |
|
228 | 169 |
|
229 |
for (int i = 1; i <= length; ++i) { |
|
230 |
*b = std::make_pair(indices[i], values[i]); |
|
170 |
for (int i = 1; i <= length; ++i) { |
|
171 |
*b = std::make_pair(indexes[i], values[i]); |
|
231 | 172 |
++b; |
232 | 173 |
} |
233 | 174 |
} |
234 | 175 |
|
235 |
void LpGlpk::_setCoeff(int ix, int jx, Value value) |
|
236 |
{ |
|
176 |
void GlpkBase::_setCoeff(int ix, int jx, Value value) { |
|
237 | 177 |
|
238 |
if ( |
|
178 |
if (glp_get_num_cols(lp) < glp_get_num_rows(lp)) { |
|
239 | 179 |
|
240 |
int length= |
|
180 |
int length = glp_get_mat_row(lp, ix, 0, 0); |
|
241 | 181 |
|
242 |
std::vector<int> |
|
182 |
std::vector<int> indexes(length + 2); |
|
243 | 183 |
std::vector<Value> values(length + 2); |
244 | 184 |
|
245 |
|
|
185 |
glp_get_mat_row(lp, ix, &indexes.front(), &values.front()); |
|
246 | 186 |
|
247 | 187 |
//The following code does not suppose that the elements of the |
248 |
//array indices are sorted |
|
249 |
bool found=false; |
|
250 |
for (int i = 1; i <= length; ++i) { |
|
251 |
if (indices[i]==jx){ |
|
252 |
found=true; |
|
253 |
values[i]=value; |
|
188 |
//array indexes are sorted |
|
189 |
bool found = false; |
|
190 |
for (int i = 1; i <= length; ++i) { |
|
191 |
if (indexes[i] == jx) { |
|
192 |
found = true; |
|
193 |
values[i] = value; |
|
254 | 194 |
break; |
255 | 195 |
} |
256 | 196 |
} |
257 |
if (!found){ |
|
197 |
if (!found) { |
|
258 | 198 |
++length; |
259 |
indices[length]=jx; |
|
260 |
values[length]=value; |
|
199 |
indexes[length] = jx; |
|
200 |
values[length] = value; |
|
261 | 201 |
} |
262 | 202 |
|
263 |
|
|
203 |
glp_set_mat_row(lp, ix, length, &indexes.front(), &values.front()); |
|
264 | 204 |
|
265 | 205 |
} else { |
266 | 206 |
|
267 |
int length= |
|
207 |
int length = glp_get_mat_col(lp, jx, 0, 0); |
|
268 | 208 |
|
269 |
std::vector<int> |
|
209 |
std::vector<int> indexes(length + 2); |
|
270 | 210 |
std::vector<Value> values(length + 2); |
271 | 211 |
|
272 |
|
|
212 |
glp_get_mat_col(lp, jx, &indexes.front(), &values.front()); |
|
273 | 213 |
|
274 | 214 |
//The following code does not suppose that the elements of the |
275 |
//array indices are sorted |
|
276 |
bool found=false; |
|
215 |
//array indexes are sorted |
|
216 |
bool found = false; |
|
277 | 217 |
for (int i = 1; i <= length; ++i) { |
278 |
if (indices[i]==ix){ |
|
279 |
found=true; |
|
280 |
|
|
218 |
if (indexes[i] == ix) { |
|
219 |
found = true; |
|
220 |
values[i] = value; |
|
281 | 221 |
break; |
282 | 222 |
} |
283 | 223 |
} |
284 |
if (!found){ |
|
224 |
if (!found) { |
|
285 | 225 |
++length; |
286 |
indices[length]=ix; |
|
287 |
values[length]=value; |
|
226 |
indexes[length] = ix; |
|
227 |
values[length] = value; |
|
288 | 228 |
} |
289 | 229 |
|
290 |
|
|
230 |
glp_set_mat_col(lp, jx, length, &indexes.front(), &values.front()); |
|
291 | 231 |
} |
292 | 232 |
|
293 |
solved = false; |
|
294 | 233 |
} |
295 | 234 |
|
296 |
LpGlpk::Value LpGlpk::_getCoeff(int ix, int jx) const |
|
297 |
{ |
|
235 |
GlpkBase::Value GlpkBase::_getCoeff(int ix, int jx) const { |
|
298 | 236 |
|
299 |
int length= |
|
237 |
int length = glp_get_mat_row(lp, ix, 0, 0); |
|
300 | 238 |
|
301 |
std::vector<int> |
|
239 |
std::vector<int> indexes(length + 1); |
|
302 | 240 |
std::vector<Value> values(length + 1); |
303 | 241 |
|
304 |
|
|
242 |
glp_get_mat_row(lp, ix, &indexes.front(), &values.front()); |
|
305 | 243 |
|
306 |
//The following code does not suppose that the elements of the |
|
307 |
//array indices are sorted |
|
308 |
for (int i = 1; i <= length; ++i) { |
|
309 |
if (indices[i]==jx){ |
|
244 |
for (int i = 1; i <= length; ++i) { |
|
245 |
if (indexes[i] == jx) { |
|
310 | 246 |
return values[i]; |
311 | 247 |
} |
312 | 248 |
} |
249 |
|
|
313 | 250 |
return 0; |
251 |
} |
|
252 |
|
|
253 |
void GlpkBase::_setColLowerBound(int i, Value lo) { |
|
254 |
LEMON_ASSERT(lo != INF, "Invalid bound"); |
|
255 |
|
|
256 |
int b = glp_get_col_type(lp, i); |
|
257 |
double up = glp_get_col_ub(lp, i); |
|
258 |
if (lo == -INF) { |
|
259 |
switch (b) { |
|
260 |
case GLP_FR: |
|
261 |
case GLP_LO: |
|
262 |
glp_set_col_bnds(lp, i, GLP_FR, lo, up); |
|
263 |
break; |
|
264 |
case GLP_UP: |
|
265 |
break; |
|
266 |
case GLP_DB: |
|
267 |
case GLP_FX: |
|
268 |
glp_set_col_bnds(lp, i, GLP_UP, lo, up); |
|
269 |
break; |
|
270 |
default: |
|
271 |
break; |
|
272 |
} |
|
273 |
} else { |
|
274 |
switch (b) { |
|
275 |
case GLP_FR: |
|
276 |
case GLP_LO: |
|
277 |
glp_set_col_bnds(lp, i, GLP_LO, lo, up); |
|
278 |
break; |
|
279 |
case GLP_UP: |
|
280 |
case GLP_DB: |
|
281 |
case GLP_FX: |
|
282 |
if (lo == up) |
|
283 |
glp_set_col_bnds(lp, i, GLP_FX, lo, up); |
|
284 |
else |
|
285 |
glp_set_col_bnds(lp, i, GLP_DB, lo, up); |
|
286 |
break; |
|
287 |
default: |
|
288 |
break; |
|
289 |
} |
|
290 |
} |
|
291 |
} |
|
292 |
|
|
293 |
GlpkBase::Value GlpkBase::_getColLowerBound(int i) const { |
|
294 |
int b = glp_get_col_type(lp, i); |
|
295 |
switch (b) { |
|
296 |
case GLP_LO: |
|
297 |
case GLP_DB: |
|
298 |
case GLP_FX: |
|
299 |
return glp_get_col_lb(lp, i); |
|
300 |
default: |
|
301 |
return -INF; |
|
302 |
} |
|
303 |
} |
|
304 |
|
|
305 |
void GlpkBase::_setColUpperBound(int i, Value up) { |
|
306 |
LEMON_ASSERT(up != -INF, "Invalid bound"); |
|
307 |
|
|
308 |
int b = glp_get_col_type(lp, i); |
|
309 |
double lo = glp_get_col_lb(lp, i); |
|
310 |
if (up == INF) { |
|
311 |
switch (b) { |
|
312 |
case GLP_FR: |
|
313 |
case GLP_LO: |
|
314 |
break; |
|
315 |
case GLP_UP: |
|
316 |
glp_set_col_bnds(lp, i, GLP_FR, lo, up); |
|
317 |
break; |
|
318 |
case GLP_DB: |
|
319 |
case GLP_FX: |
|
320 |
glp_set_col_bnds(lp, i, GLP_LO, lo, up); |
|
321 |
break; |
|
322 |
default: |
|
323 |
break; |
|
324 |
} |
|
325 |
} else { |
|
326 |
switch (b) { |
|
327 |
case GLP_FR: |
|
328 |
glp_set_col_bnds(lp, i, GLP_UP, lo, up); |
|
329 |
break; |
|
330 |
case GLP_UP: |
|
331 |
glp_set_col_bnds(lp, i, GLP_UP, lo, up); |
|
332 |
break; |
|
333 |
case GLP_LO: |
|
334 |
case GLP_DB: |
|
335 |
case GLP_FX: |
|
336 |
if (lo == up) |
|
337 |
glp_set_col_bnds(lp, i, GLP_FX, lo, up); |
|
338 |
else |
|
339 |
glp_set_col_bnds(lp, i, GLP_DB, lo, up); |
|
340 |
break; |
|
341 |
default: |
|
342 |
break; |
|
343 |
} |
|
344 |
} |
|
314 | 345 |
|
315 | 346 |
} |
316 | 347 |
|
317 |
|
|
318 |
void LpGlpk::_setColLowerBound(int i, Value lo) |
|
319 |
{ |
|
320 |
if (lo==INF) { |
|
321 |
//FIXME error |
|
322 |
} |
|
323 |
int b=LEMON_glp(get_col_type)(lp, i); |
|
324 |
double up=LEMON_glp(get_col_ub)(lp, i); |
|
325 |
|
|
348 |
GlpkBase::Value GlpkBase::_getColUpperBound(int i) const { |
|
349 |
int b = glp_get_col_type(lp, i); |
|
326 | 350 |
switch (b) { |
327 |
case LEMON_GLP(FR): |
|
328 |
case LEMON_GLP(LO): |
|
329 |
LEMON_glp(set_col_bnds)(lp, i, LEMON_GLP(FR), lo, up); |
|
330 |
break; |
|
331 |
case LEMON_GLP(UP): |
|
332 |
break; |
|
333 |
case LEMON_GLP(DB): |
|
334 |
case LEMON_GLP(FX): |
|
335 |
LEMON_glp(set_col_bnds)(lp, i, LEMON_GLP(UP), lo, up); |
|
336 |
break; |
|
337 |
default: ; |
|
338 |
//FIXME error |
|
339 |
} |
|
340 |
} else { |
|
341 |
switch (b) { |
|
342 |
case LEMON_GLP(FR): |
|
343 |
case LEMON_GLP(LO): |
|
344 |
LEMON_glp(set_col_bnds)(lp, i, LEMON_GLP(LO), lo, up); |
|
345 |
break; |
|
346 |
case LEMON_GLP(UP): |
|
347 |
case LEMON_GLP(DB): |
|
348 |
case LEMON_GLP(FX): |
|
349 |
if (lo==up) |
|
350 |
LEMON_glp(set_col_bnds)(lp, i, LEMON_GLP(FX), lo, up); |
|
351 |
else |
|
352 |
LEMON_glp(set_col_bnds)(lp, i, LEMON_GLP(DB), lo, up); |
|
353 |
break; |
|
354 |
default: ; |
|
355 |
//FIXME error |
|
356 |
} |
|
357 |
} |
|
358 |
|
|
359 |
solved = false; |
|
360 |
} |
|
361 |
|
|
362 |
LpGlpk::Value LpGlpk::_getColLowerBound(int i) const |
|
363 |
{ |
|
364 |
int b=LEMON_glp(get_col_type)(lp, i); |
|
365 |
switch (b) { |
|
366 |
case LEMON_GLP(LO): |
|
367 |
case LEMON_GLP(DB): |
|
368 |
case LEMON_GLP(FX): |
|
369 |
return LEMON_glp(get_col_lb)(lp, i); |
|
370 |
default: ; |
|
371 |
return -INF; |
|
372 |
} |
|
373 |
} |
|
374 |
|
|
375 |
void LpGlpk::_setColUpperBound(int i, Value up) |
|
376 |
{ |
|
377 |
if (up==-INF) { |
|
378 |
//FIXME error |
|
379 |
} |
|
380 |
int b=LEMON_glp(get_col_type)(lp, i); |
|
381 |
double lo=LEMON_glp(get_col_lb)(lp, i); |
|
382 |
if (up==INF) { |
|
383 |
switch (b) { |
|
384 |
case LEMON_GLP(FR): |
|
385 |
case LEMON_GLP(LO): |
|
386 |
break; |
|
387 |
case LEMON_GLP(UP): |
|
388 |
LEMON_glp(set_col_bnds)(lp, i, LEMON_GLP(FR), lo, up); |
|
389 |
break; |
|
390 |
case LEMON_GLP(DB): |
|
391 |
case LEMON_GLP(FX): |
|
392 |
LEMON_glp(set_col_bnds)(lp, i, LEMON_GLP(LO), lo, up); |
|
393 |
break; |
|
394 |
default: ; |
|
395 |
//FIXME error |
|
396 |
} |
|
397 |
} else { |
|
398 |
switch (b) { |
|
399 |
case LEMON_GLP(FR): |
|
400 |
LEMON_glp(set_col_bnds)(lp, i, LEMON_GLP(UP), lo, up); |
|
401 |
break; |
|
402 |
case LEMON_GLP(UP): |
|
403 |
LEMON_glp(set_col_bnds)(lp, i, LEMON_GLP(UP), lo, up); |
|
404 |
break; |
|
405 |
case LEMON_GLP(LO): |
|
406 |
case LEMON_GLP(DB): |
|
407 |
case LEMON_GLP(FX): |
|
408 |
if (lo==up) |
|
409 |
LEMON_glp(set_col_bnds)(lp, i, LEMON_GLP(FX), lo, up); |
|
410 |
else |
|
411 |
LEMON_glp(set_col_bnds)(lp, i, LEMON_GLP(DB), lo, up); |
|
412 |
break; |
|
413 |
default: ; |
|
414 |
//FIXME error |
|
415 |
} |
|
416 |
} |
|
417 |
|
|
418 |
solved = false; |
|
419 |
} |
|
420 |
|
|
421 |
LpGlpk::Value LpGlpk::_getColUpperBound(int i) const |
|
422 |
{ |
|
423 |
int b=LEMON_glp(get_col_type)(lp, i); |
|
424 |
switch (b) { |
|
425 |
case LEMON_GLP(UP): |
|
426 |
case LEMON_GLP(DB): |
|
427 |
case LEMON_GLP(FX): |
|
428 |
return LEMON_glp(get_col_ub)(lp, i); |
|
429 |
|
|
351 |
case GLP_UP: |
|
352 |
case GLP_DB: |
|
353 |
case GLP_FX: |
|
354 |
return glp_get_col_ub(lp, i); |
|
355 |
default: |
|
430 | 356 |
return INF; |
431 | 357 |
} |
432 | 358 |
} |
433 | 359 |
|
434 |
void LpGlpk::_setRowBounds(int i, Value lb, Value ub) |
|
435 |
{ |
|
436 |
//Bad parameter |
|
437 |
if (lb==INF || ub==-INF) { |
|
438 |
//FIXME error |
|
439 |
} |
|
360 |
void GlpkBase::_setRowLowerBound(int i, Value lo) { |
|
361 |
LEMON_ASSERT(lo != INF, "Invalid bound"); |
|
440 | 362 |
|
441 |
if (lb == -INF){ |
|
442 |
if (ub == INF){ |
|
443 |
|
|
363 |
int b = glp_get_row_type(lp, i); |
|
364 |
double up = glp_get_row_ub(lp, i); |
|
365 |
if (lo == -INF) { |
|
366 |
switch (b) { |
|
367 |
case GLP_FR: |
|
368 |
case GLP_LO: |
|
369 |
glp_set_row_bnds(lp, i, GLP_FR, lo, up); |
|
370 |
break; |
|
371 |
case GLP_UP: |
|
372 |
break; |
|
373 |
case GLP_DB: |
|
374 |
case GLP_FX: |
|
375 |
glp_set_row_bnds(lp, i, GLP_UP, lo, up); |
|
376 |
break; |
|
377 |
default: |
|
378 |
break; |
|
444 | 379 |
} |
445 |
else{ |
|
446 |
LEMON_glp(set_row_bnds)(lp, i, LEMON_GLP(UP), lb, ub); |
|
380 |
} else { |
|
381 |
switch (b) { |
|
382 |
case GLP_FR: |
|
383 |
case GLP_LO: |
|
384 |
glp_set_row_bnds(lp, i, GLP_LO, lo, up); |
|
385 |
break; |
|
386 |
case GLP_UP: |
|
387 |
case GLP_DB: |
|
388 |
case GLP_FX: |
|
389 |
if (lo == up) |
|
390 |
glp_set_row_bnds(lp, i, GLP_FX, lo, up); |
|
391 |
else |
|
392 |
glp_set_row_bnds(lp, i, GLP_DB, lo, up); |
|
393 |
break; |
|
394 |
default: |
|
395 |
break; |
|
447 | 396 |
} |
448 | 397 |
} |
449 |
else{ |
|
450 |
if (ub==INF){ |
|
451 |
LEMON_glp(set_row_bnds)(lp, i, LEMON_GLP(LO), lb, ub); |
|
452 |
|
|
453 |
} |
|
454 |
else{ |
|
455 |
if (lb == ub){ |
|
456 |
LEMON_glp(set_row_bnds)(lp, i, LEMON_GLP(FX), lb, ub); |
|
457 |
} |
|
458 |
else{ |
|
459 |
LEMON_glp(set_row_bnds)(lp, i, LEMON_GLP(DB), lb, ub); |
|
460 |
} |
|
461 |
} |
|
462 |
} |
|
463 |
|
|
464 |
solved = false; |
|
465 |
} |
|
466 |
|
|
467 |
void LpGlpk::_getRowBounds(int i, Value &lb, Value &ub) const |
|
468 |
{ |
|
469 |
|
|
470 |
int b=LEMON_glp(get_row_type)(lp, i); |
|
471 |
switch (b) { |
|
472 |
case LEMON_GLP(FR): |
|
473 |
case LEMON_GLP(UP): |
|
474 |
lb = -INF; |
|
475 |
break; |
|
476 |
default: |
|
477 |
lb=LEMON_glp(get_row_lb)(lp, i); |
|
478 |
} |
|
479 |
|
|
480 |
switch (b) { |
|
481 |
case LEMON_GLP(FR): |
|
482 |
case LEMON_GLP(LO): |
|
483 |
ub = INF; |
|
484 |
break; |
|
485 |
default: |
|
486 |
ub=LEMON_glp(get_row_ub)(lp, i); |
|
487 |
} |
|
488 | 398 |
|
489 | 399 |
} |
490 | 400 |
|
491 |
void LpGlpk::_setObjCoeff(int i, Value obj_coef) |
|
492 |
{ |
|
493 |
//i=0 means the constant term (shift) |
|
494 |
LEMON_glp(set_obj_coef)(lp, i, obj_coef); |
|
495 |
|
|
496 |
solved = false; |
|
497 |
} |
|
498 |
|
|
499 |
LpGlpk::Value LpGlpk::_getObjCoeff(int i) const { |
|
500 |
//i=0 means the constant term (shift) |
|
501 |
return LEMON_glp(get_obj_coef)(lp, i); |
|
502 |
} |
|
503 |
|
|
504 |
void LpGlpk::_clearObj() |
|
505 |
{ |
|
506 |
for (int i=0;i<=LEMON_glp(get_num_cols)(lp);++i){ |
|
507 |
LEMON_glp(set_obj_coef)(lp, i, 0); |
|
508 |
} |
|
509 |
|
|
510 |
solved = false; |
|
511 |
} |
|
512 |
|
|
513 |
LpGlpk::SolveExitStatus LpGlpk::_solve() |
|
514 |
{ |
|
515 |
// A way to check the problem to be solved |
|
516 |
//LEMON_glp(write_cpxlp(lp,"naittvan.cpx"); |
|
517 |
|
|
518 |
LEMON_lpx(std_basis)(lp); |
|
519 |
int i = LEMON_lpx(simplex)(lp); |
|
520 |
|
|
521 |
switch (i) { |
|
522 |
case LEMON_LPX(E_OK): |
|
523 |
solved = true; |
|
524 |
return SOLVED; |
|
401 |
GlpkBase::Value GlpkBase::_getRowLowerBound(int i) const { |
|
402 |
int b = glp_get_row_type(lp, i); |
|
403 |
switch (b) { |
|
404 |
case GLP_LO: |
|
405 |
case GLP_DB: |
|
406 |
case GLP_FX: |
|
407 |
return glp_get_row_lb(lp, i); |
|
525 | 408 |
default: |
526 |
return |
|
409 |
return -INF; |
|
527 | 410 |
} |
528 | 411 |
} |
529 | 412 |
|
530 |
LpGlpk::Value LpGlpk::_getPrimal(int i) const |
|
531 |
{ |
|
532 |
return LEMON_glp(get_col_prim)(lp,i); |
|
533 |
} |
|
413 |
void GlpkBase::_setRowUpperBound(int i, Value up) { |
|
414 |
LEMON_ASSERT(up != -INF, "Invalid bound"); |
|
534 | 415 |
|
535 |
LpGlpk::Value LpGlpk::_getDual(int i) const |
|
536 |
{ |
|
537 |
return LEMON_glp(get_row_dual)(lp,i); |
|
538 |
} |
|
539 |
|
|
540 |
LpGlpk::Value LpGlpk::_getPrimalValue() const |
|
541 |
{ |
|
542 |
return LEMON_glp(get_obj_val)(lp); |
|
543 |
} |
|
544 |
bool LpGlpk::_isBasicCol(int i) const |
|
545 |
{ |
|
546 |
return (LEMON_glp(get_col_stat)(lp, i)==LEMON_GLP(BS)); |
|
547 |
} |
|
548 |
|
|
549 |
|
|
550 |
LpGlpk::SolutionStatus LpGlpk::_getPrimalStatus() const |
|
551 |
{ |
|
552 |
if (!solved) return UNDEFINED; |
|
553 |
int stat= LEMON_lpx(get_status)(lp); |
|
554 |
switch (stat) { |
|
555 |
case LEMON_LPX(UNDEF)://Undefined (no solve has been run yet) |
|
556 |
return UNDEFINED; |
|
557 |
case LEMON_LPX(NOFEAS)://There is no feasible solution (primal, I guess) |
|
558 |
case LEMON_LPX(INFEAS)://Infeasible |
|
559 |
return INFEASIBLE; |
|
560 |
case LEMON_LPX(UNBND)://Unbounded |
|
561 |
return INFINITE; |
|
562 |
case LEMON_LPX(FEAS)://Feasible |
|
563 |
return FEASIBLE; |
|
564 |
case LEMON_LPX(OPT)://Feasible |
|
565 |
return OPTIMAL; |
|
566 |
default: |
|
567 |
return UNDEFINED; //to avoid gcc warning |
|
568 |
//FIXME error |
|
416 |
int b = glp_get_row_type(lp, i); |
|
417 |
double lo = glp_get_row_lb(lp, i); |
|
418 |
if (up == INF) { |
|
419 |
switch (b) { |
|
420 |
case GLP_FR: |
|
421 |
case GLP_LO: |
|
422 |
break; |
|
423 |
case GLP_UP: |
|
424 |
glp_set_row_bnds(lp, i, GLP_FR, lo, up); |
|
425 |
break; |
|
426 |
case GLP_DB: |
|
427 |
case GLP_FX: |
|
428 |
glp_set_row_bnds(lp, i, GLP_LO, lo, up); |
|
429 |
break; |
|
430 |
default: |
|
431 |
break; |
|
432 |
} |
|
433 |
} else { |
|
434 |
switch (b) { |
|
435 |
case GLP_FR: |
|
436 |
glp_set_row_bnds(lp, i, GLP_UP, lo, up); |
|
437 |
break; |
|
438 |
case GLP_UP: |
|
439 |
glp_set_row_bnds(lp, i, GLP_UP, lo, up); |
|
440 |
break; |
|
441 |
case GLP_LO: |
|
442 |
case GLP_DB: |
|
443 |
case GLP_FX: |
|
444 |
if (lo == up) |
|
445 |
glp_set_row_bnds(lp, i, GLP_FX, lo, up); |
|
446 |
else |
|
447 |
glp_set_row_bnds(lp, i, GLP_DB, lo, up); |
|
448 |
break; |
|
449 |
default: |
|
450 |
break; |
|
451 |
} |
|
569 | 452 |
} |
570 | 453 |
} |
571 | 454 |
|
572 |
LpGlpk::SolutionStatus LpGlpk::_getDualStatus() const |
|
573 |
{ |
|
574 |
if (!solved) return UNDEFINED; |
|
575 |
switch (LEMON_lpx(get_dual_stat)(lp)) { |
|
576 |
case LEMON_LPX(D_UNDEF)://Undefined (no solve has been run yet) |
|
577 |
return UNDEFINED; |
|
578 |
case LEMON_LPX(D_NOFEAS)://There is no dual feasible solution |
|
579 |
// case LEMON_LPX(D_INFEAS://Infeasible |
|
580 |
return INFEASIBLE; |
|
581 |
case LEMON_LPX(D_FEAS)://Feasible |
|
582 |
switch (LEMON_lpx(get_status)(lp)) { |
|
583 |
case LEMON_LPX(NOFEAS): |
|
584 |
return INFINITE; |
|
585 |
case LEMON_LPX(OPT): |
|
586 |
return OPTIMAL; |
|
587 |
default: |
|
588 |
return FEASIBLE; |
|
589 |
} |
|
455 |
GlpkBase::Value GlpkBase::_getRowUpperBound(int i) const { |
|
456 |
int b = glp_get_row_type(lp, i); |
|
457 |
switch (b) { |
|
458 |
case GLP_UP: |
|
459 |
case GLP_DB: |
|
460 |
case GLP_FX: |
|
461 |
return glp_get_row_ub(lp, i); |
|
590 | 462 |
default: |
591 |
return UNDEFINED; //to avoid gcc warning |
|
592 |
//FIXME error |
|
463 |
return INF; |
|
593 | 464 |
} |
594 | 465 |
} |
595 | 466 |
|
596 |
LpGlpk::ProblemTypes LpGlpk::_getProblemType() const |
|
597 |
{ |
|
598 |
if (!solved) return UNKNOWN; |
|
599 |
//int stat= LEMON_glp(get_status(lp); |
|
600 |
int statp= LEMON_lpx(get_prim_stat)(lp); |
|
601 |
int statd= LEMON_lpx(get_dual_stat)(lp); |
|
602 |
if (statp==LEMON_LPX(P_FEAS) && statd==LEMON_LPX(D_FEAS)) |
|
603 |
return PRIMAL_DUAL_FEASIBLE; |
|
604 |
if (statp==LEMON_LPX(P_FEAS) && statd==LEMON_LPX(D_NOFEAS)) |
|
605 |
return PRIMAL_FEASIBLE_DUAL_INFEASIBLE; |
|
606 |
if (statp==LEMON_LPX(P_NOFEAS) && statd==LEMON_LPX(D_FEAS)) |
|
607 |
return PRIMAL_INFEASIBLE_DUAL_FEASIBLE; |
|
608 |
if (statp==LEMON_LPX(P_NOFEAS) && statd==LEMON_LPX(D_NOFEAS)) |
|
609 |
return PRIMAL_DUAL_INFEASIBLE; |
|
610 |
//In all other cases |
|
611 |
return UNKNOWN; |
|
467 |
void GlpkBase::_setObjCoeffs(ExprIterator b, ExprIterator e) { |
|
468 |
for (int i = 1; i <= glp_get_num_cols(lp); ++i) { |
|
469 |
glp_set_obj_coef(lp, i, 0.0); |
|
470 |
} |
|
471 |
for (ExprIterator it = b; it != e; ++it) { |
|
472 |
glp_set_obj_coef(lp, it->first, it->second); |
|
473 |
} |
|
612 | 474 |
} |
613 | 475 |
|
614 |
void LpGlpk::_setMax() |
|
615 |
{ |
|
616 |
solved = false; |
|
617 |
LEMON_glp(set_obj_dir)(lp, LEMON_GLP(MAX)); |
|
476 |
void GlpkBase::_getObjCoeffs(InsertIterator b) const { |
|
477 |
for (int i = 1; i <= glp_get_num_cols(lp); ++i) { |
|
478 |
Value val = glp_get_obj_coef(lp, i); |
|
479 |
if (val != 0.0) { |
|
480 |
*b = std::make_pair(i, val); |
|
481 |
++b; |
|
482 |
} |
|
483 |
} |
|
618 | 484 |
} |
619 | 485 |
|
620 |
void LpGlpk::_setMin() |
|
621 |
{ |
|
622 |
solved = false; |
|
623 |
LEMON_glp(set_obj_dir)(lp, LEMON_GLP(MIN)); |
|
486 |
void GlpkBase::_setObjCoeff(int i, Value obj_coef) { |
|
487 |
//i = 0 means the constant term (shift) |
|
488 |
glp_set_obj_coef(lp, i, obj_coef); |
|
624 | 489 |
} |
625 | 490 |
|
626 |
bool LpGlpk::_isMax() const |
|
627 |
{ |
|
628 |
|
|
491 |
GlpkBase::Value GlpkBase::_getObjCoeff(int i) const { |
|
492 |
//i = 0 means the constant term (shift) |
|
493 |
return glp_get_obj_coef(lp, i); |
|
629 | 494 |
} |
630 | 495 |
|
631 |
|
|
632 |
|
|
633 |
void LpGlpk::messageLevel(int m) |
|
634 |
{ |
|
635 |
|
|
496 |
void GlpkBase::_setSense(GlpkBase::Sense sense) { |
|
497 |
switch (sense) { |
|
498 |
case MIN: |
|
499 |
glp_set_obj_dir(lp, GLP_MIN); |
|
500 |
break; |
|
501 |
case MAX: |
|
502 |
glp_set_obj_dir(lp, GLP_MAX); |
|
503 |
break; |
|
504 |
} |
|
636 | 505 |
} |
637 | 506 |
|
638 |
void LpGlpk::presolver(bool b) |
|
639 |
{ |
|
640 |
|
|
507 |
GlpkBase::Sense GlpkBase::_getSense() const { |
|
508 |
switch(glp_get_obj_dir(lp)) { |
|
509 |
case GLP_MIN: |
|
510 |
return MIN; |
|
511 |
case GLP_MAX: |
|
512 |
return MAX; |
|
513 |
default: |
|
514 |
LEMON_ASSERT(false, "Wrong sense"); |
|
515 |
return GlpkBase::Sense(); |
|
516 |
} |
|
641 | 517 |
} |
642 | 518 |
|
519 |
void GlpkBase::_clear() { |
|
520 |
glp_erase_prob(lp); |
|
521 |
rows.clear(); |
|
522 |
cols.clear(); |
|
523 |
} |
|
524 |
|
|
525 |
// LpGlpk members |
|
526 |
|
|
527 |
LpGlpk::LpGlpk() |
|
528 |
: LpBase(), GlpkBase(), LpSolver() { |
|
529 |
messageLevel(MESSAGE_NO_OUTPUT); |
|
530 |
} |
|
531 |
|
|
532 |
LpGlpk::LpGlpk(const LpGlpk& other) |
|
533 |
: LpBase(other), GlpkBase(other), LpSolver(other) { |
|
534 |
messageLevel(MESSAGE_NO_OUTPUT); |
|
535 |
} |
|
536 |
|
|
537 |
LpGlpk* LpGlpk::_newSolver() const { return new LpGlpk; } |
|
538 |
LpGlpk* LpGlpk::_cloneSolver() const { return new LpGlpk(*this); } |
|
539 |
|
|
540 |
const char* LpGlpk::_solverName() const { return "LpGlpk"; } |
|
541 |
|
|
542 |
void LpGlpk::_clear_temporals() { |
|
543 |
_primal_ray.clear(); |
|
544 |
_dual_ray.clear(); |
|
545 |
} |
|
546 |
|
|
547 |
LpGlpk::SolveExitStatus LpGlpk::_solve() { |
|
548 |
return solvePrimal(); |
|
549 |
} |
|
550 |
|
|
551 |
LpGlpk::SolveExitStatus LpGlpk::solvePrimal() { |
|
552 |
_clear_temporals(); |
|
553 |
|
|
554 |
glp_smcp smcp; |
|
555 |
glp_init_smcp(&smcp); |
|
556 |
|
|
557 |
switch (_message_level) { |
|
558 |
case MESSAGE_NO_OUTPUT: |
|
559 |
smcp.msg_lev = GLP_MSG_OFF; |
|
560 |
break; |
|
561 |
case MESSAGE_ERROR_MESSAGE: |
|
562 |
smcp.msg_lev = GLP_MSG_ERR; |
|
563 |
break; |
|
564 |
case MESSAGE_NORMAL_OUTPUT: |
|
565 |
smcp.msg_lev = GLP_MSG_ON; |
|
566 |
break; |
|
567 |
case MESSAGE_FULL_OUTPUT: |
|
568 |
smcp.msg_lev = GLP_MSG_ALL; |
|
569 |
break; |
|
570 |
} |
|
571 |
|
|
572 |
if (glp_simplex(lp, &smcp) != 0) return UNSOLVED; |
|
573 |
return SOLVED; |
|
574 |
} |
|
575 |
|
|
576 |
LpGlpk::SolveExitStatus LpGlpk::solveDual() { |
|
577 |
_clear_temporals(); |
|
578 |
|
|
579 |
glp_smcp smcp; |
|
580 |
glp_init_smcp(&smcp); |
|
581 |
|
|
582 |
switch (_message_level) { |
|
583 |
case MESSAGE_NO_OUTPUT: |
|
584 |
smcp.msg_lev = GLP_MSG_OFF; |
|
585 |
break; |
|
586 |
case MESSAGE_ERROR_MESSAGE: |
|
587 |
smcp.msg_lev = GLP_MSG_ERR; |
|
588 |
break; |
|
589 |
case MESSAGE_NORMAL_OUTPUT: |
|
590 |
smcp.msg_lev = GLP_MSG_ON; |
|
591 |
break; |
|
592 |
case MESSAGE_FULL_OUTPUT: |
|
593 |
smcp.msg_lev = GLP_MSG_ALL; |
|
594 |
break; |
|
595 |
} |
|
596 |
smcp.meth = GLP_DUAL; |
|
597 |
|
|
598 |
if (glp_simplex(lp, &smcp) != 0) return UNSOLVED; |
|
599 |
return SOLVED; |
|
600 |
} |
|
601 |
|
|
602 |
LpGlpk::Value LpGlpk::_getPrimal(int i) const { |
|
603 |
return glp_get_col_prim(lp, i); |
|
604 |
} |
|
605 |
|
|
606 |
LpGlpk::Value LpGlpk::_getDual(int i) const { |
|
607 |
return glp_get_row_dual(lp, i); |
|
608 |
} |
|
609 |
|
|
610 |
LpGlpk::Value LpGlpk::_getPrimalValue() const { |
|
611 |
return glp_get_obj_val(lp); |
|
612 |
} |
|
613 |
|
|
614 |
LpGlpk::VarStatus LpGlpk::_getColStatus(int i) const { |
|
615 |
switch (glp_get_col_stat(lp, i)) { |
|
616 |
case GLP_BS: |
|
617 |
return BASIC; |
|
618 |
case GLP_UP: |
|
619 |
return UPPER; |
|
620 |
case GLP_LO: |
|
621 |
return LOWER; |
|
622 |
case GLP_NF: |
|
623 |
return FREE; |
|
624 |
case GLP_NS: |
|
625 |
return FIXED; |
|
626 |
default: |
|
627 |
LEMON_ASSERT(false, "Wrong column status"); |
|
628 |
return LpGlpk::VarStatus(); |
|
629 |
} |
|
630 |
} |
|
631 |
|
|
632 |
LpGlpk::VarStatus LpGlpk::_getRowStatus(int i) const { |
|
633 |
switch (glp_get_row_stat(lp, i)) { |
|
634 |
case GLP_BS: |
|
635 |
return BASIC; |
|
636 |
case GLP_UP: |
|
637 |
return UPPER; |
|
638 |
case GLP_LO: |
|
639 |
return LOWER; |
|
640 |
case GLP_NF: |
|
641 |
return FREE; |
|
642 |
case GLP_NS: |
|
643 |
return FIXED; |
|
644 |
default: |
|
645 |
LEMON_ASSERT(false, "Wrong row status"); |
|
646 |
return LpGlpk::VarStatus(); |
|
647 |
} |
|
648 |
} |
|
649 |
|
|
650 |
LpGlpk::Value LpGlpk::_getPrimalRay(int i) const { |
|
651 |
if (_primal_ray.empty()) { |
|
652 |
int row_num = glp_get_num_rows(lp); |
|
653 |
int col_num = glp_get_num_cols(lp); |
|
654 |
|
|
655 |
_primal_ray.resize(col_num + 1, 0.0); |
|
656 |
|
|
657 |
int index = glp_get_unbnd_ray(lp); |
|
658 |
if (index != 0) { |
|
659 |
// The primal ray is found in primal simplex second phase |
|
660 |
LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) : |
|
661 |
glp_get_col_stat(lp, index - row_num)) != GLP_BS, |
|
662 |
"Wrong primal ray"); |
|
663 |
|
|
664 |
bool negate = glp_get_obj_dir(lp) == GLP_MAX; |
|
665 |
|
|
666 |
if (index > row_num) { |
|
667 |
_primal_ray[index - row_num] = 1.0; |
|
668 |
if (glp_get_col_dual(lp, index - row_num) > 0) { |
|
669 |
negate = !negate; |
|
670 |
} |
|
671 |
} else { |
|
672 |
if (glp_get_row_dual(lp, index) > 0) { |
|
673 |
negate = !negate; |
|
674 |
} |
|
675 |
} |
|
676 |
|
|
677 |
std::vector<int> ray_indexes(row_num + 1); |
|
678 |
std::vector<Value> ray_values(row_num + 1); |
|
679 |
int ray_length = glp_eval_tab_col(lp, index, &ray_indexes.front(), |
|
680 |
&ray_values.front()); |
|
681 |
|
|
682 |
for (int i = 1; i <= ray_length; ++i) { |
|
683 |
if (ray_indexes[i] > row_num) { |
|
684 |
_primal_ray[ray_indexes[i] - row_num] = ray_values[i]; |
|
685 |
} |
|
686 |
} |
|
687 |
|
|
688 |
if (negate) { |
|
689 |
for (int i = 1; i <= col_num; ++i) { |
|
690 |
_primal_ray[i] = - _primal_ray[i]; |
|
691 |
} |
|
692 |
} |
|
693 |
} else { |
|
694 |
for (int i = 1; i <= col_num; ++i) { |
|
695 |
_primal_ray[i] = glp_get_col_prim(lp, i); |
|
696 |
} |
|
697 |
} |
|
698 |
} |
|
699 |
return _primal_ray[i]; |
|
700 |
} |
|
701 |
|
|
702 |
LpGlpk::Value LpGlpk::_getDualRay(int i) const { |
|
703 |
if (_dual_ray.empty()) { |
|
704 |
int row_num = glp_get_num_rows(lp); |
|
705 |
|
|
706 |
_dual_ray.resize(row_num + 1, 0.0); |
|
707 |
|
|
708 |
int index = glp_get_unbnd_ray(lp); |
|
709 |
if (index != 0) { |
|
710 |
// The dual ray is found in dual simplex second phase |
|
711 |
LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) : |
|
712 |
glp_get_col_stat(lp, index - row_num)) == GLP_BS, |
|
713 |
|
|
714 |
"Wrong dual ray"); |
|
715 |
|
|
716 |
int idx; |
|
717 |
bool negate = false; |
|
718 |
|
|
719 |
if (index > row_num) { |
|
720 |
idx = glp_get_col_bind(lp, index - row_num); |
|
721 |
if (glp_get_col_prim(lp, index - row_num) > |
|
722 |
glp_get_col_ub(lp, index - row_num)) { |
|
723 |
negate = true; |
|
724 |
} |
|
725 |
} else { |
|
726 |
idx = glp_get_row_bind(lp, index); |
|
727 |
if (glp_get_row_prim(lp, index) > glp_get_row_ub(lp, index)) { |
|
728 |
negate = true; |
|
729 |
} |
|
730 |
} |
|
731 |
|
|
732 |
_dual_ray[idx] = negate ? - 1.0 : 1.0; |
|
733 |
|
|
734 |
glp_btran(lp, &_dual_ray.front()); |
|
735 |
} else { |
|
736 |
double eps = 1e-7; |
|
737 |
// The dual ray is found in primal simplex first phase |
|
738 |
// We assume that the glpk minimizes the slack to get feasible solution |
|
739 |
for (int i = 1; i <= row_num; ++i) { |
|
740 |
int index = glp_get_bhead(lp, i); |
|
741 |
if (index <= row_num) { |
|
742 |
double res = glp_get_row_prim(lp, index); |
|
743 |
if (res > glp_get_row_ub(lp, index) + eps) { |
|
744 |
_dual_ray[i] = -1; |
|
745 |
} else if (res < glp_get_row_lb(lp, index) - eps) { |
|
746 |
_dual_ray[i] = 1; |
|
747 |
} else { |
|
748 |
_dual_ray[i] = 0; |
|
749 |
} |
|
750 |
_dual_ray[i] *= glp_get_rii(lp, index); |
|
751 |
} else { |
|
752 |
double res = glp_get_col_prim(lp, index - row_num); |
|
753 |
if (res > glp_get_col_ub(lp, index - row_num) + eps) { |
|
754 |
_dual_ray[i] = -1; |
|
755 |
} else if (res < glp_get_col_lb(lp, index - row_num) - eps) { |
|
756 |
_dual_ray[i] = 1; |
|
757 |
} else { |
|
758 |
_dual_ray[i] = 0; |
|
759 |
} |
|
760 |
_dual_ray[i] /= glp_get_sjj(lp, index - row_num); |
|
761 |
} |
|
762 |
} |
|
763 |
|
|
764 |
glp_btran(lp, &_dual_ray.front()); |
|
765 |
|
|
766 |
for (int i = 1; i <= row_num; ++i) { |
|
767 |
_dual_ray[i] /= glp_get_rii(lp, i); |
|
768 |
} |
|
769 |
} |
|
770 |
} |
|
771 |
return _dual_ray[i]; |
|
772 |
} |
|
773 |
|
|
774 |
LpGlpk::ProblemType LpGlpk::_getPrimalType() const { |
|
775 |
if (glp_get_status(lp) == GLP_OPT) |
|
776 |
return OPTIMAL; |
|
777 |
switch (glp_get_prim_stat(lp)) { |
|
778 |
case GLP_UNDEF: |
|
779 |
return UNDEFINED; |
|
780 |
case GLP_FEAS: |
|
781 |
case GLP_INFEAS: |
|
782 |
if (glp_get_dual_stat(lp) == GLP_NOFEAS) { |
|
783 |
return UNBOUNDED; |
|
784 |
} else { |
|
785 |
return UNDEFINED; |
|
786 |
} |
|
787 |
case GLP_NOFEAS: |
|
788 |
return INFEASIBLE; |
|
789 |
default: |
|
790 |
LEMON_ASSERT(false, "Wrong primal type"); |
|
791 |
return LpGlpk::ProblemType(); |
|
792 |
} |
|
793 |
} |
|
794 |
|
|
795 |
LpGlpk::ProblemType LpGlpk::_getDualType() const { |
|
796 |
if (glp_get_status(lp) == GLP_OPT) |
|
797 |
return OPTIMAL; |
|
798 |
switch (glp_get_dual_stat(lp)) { |
|
799 |
case GLP_UNDEF: |
|
800 |
return UNDEFINED; |
|
801 |
case GLP_FEAS: |
|
802 |
case GLP_INFEAS: |
|
803 |
if (glp_get_prim_stat(lp) == GLP_NOFEAS) { |
|
804 |
return UNBOUNDED; |
|
805 |
} else { |
|
806 |
return UNDEFINED; |
|
807 |
} |
|
808 |
case GLP_NOFEAS: |
|
809 |
return INFEASIBLE; |
|
810 |
default: |
|
811 |
LEMON_ASSERT(false, "Wrong primal type"); |
|
812 |
return LpGlpk::ProblemType(); |
|
813 |
} |
|
814 |
} |
|
815 |
|
|
816 |
void LpGlpk::presolver(bool b) { |
|
817 |
lpx_set_int_parm(lp, LPX_K_PRESOL, b ? 1 : 0); |
|
818 |
} |
|
819 |
|
|
820 |
void LpGlpk::messageLevel(MessageLevel m) { |
|
821 |
_message_level = m; |
|
822 |
} |
|
823 |
|
|
824 |
// MipGlpk members |
|
825 |
|
|
826 |
MipGlpk::MipGlpk() |
|
827 |
: LpBase(), GlpkBase(), MipSolver() { |
|
828 |
messageLevel(MESSAGE_NO_OUTPUT); |
|
829 |
} |
|
830 |
|
|
831 |
MipGlpk::MipGlpk(const MipGlpk& other) |
|
832 |
: LpBase(), GlpkBase(other), MipSolver() { |
|
833 |
messageLevel(MESSAGE_NO_OUTPUT); |
|
834 |
} |
|
835 |
|
|
836 |
void MipGlpk::_setColType(int i, MipGlpk::ColTypes col_type) { |
|
837 |
switch (col_type) { |
|
838 |
case INTEGER: |
|
839 |
glp_set_col_kind(lp, i, GLP_IV); |
|
840 |
break; |
|
841 |
case REAL: |
|
842 |
glp_set_col_kind(lp, i, GLP_CV); |
|
843 |
break; |
|
844 |
} |
|
845 |
} |
|
846 |
|
|
847 |
MipGlpk::ColTypes MipGlpk::_getColType(int i) const { |
|
848 |
switch (glp_get_col_kind(lp, i)) { |
|
849 |
case GLP_IV: |
|
850 |
case GLP_BV: |
|
851 |
return INTEGER; |
|
852 |
default: |
|
853 |
return REAL; |
|
854 |
} |
|
855 |
|
|
856 |
} |
|
857 |
|
|
858 |
MipGlpk::SolveExitStatus MipGlpk::_solve() { |
|
859 |
glp_smcp smcp; |
|
860 |
glp_init_smcp(&smcp); |
|
861 |
|
|
862 |
switch (_message_level) { |
|
863 |
case MESSAGE_NO_OUTPUT: |
|
864 |
smcp.msg_lev = GLP_MSG_OFF; |
|
865 |
break; |
|
866 |
case MESSAGE_ERROR_MESSAGE: |
|
867 |
smcp.msg_lev = GLP_MSG_ERR; |
|
868 |
break; |
|
869 |
case MESSAGE_NORMAL_OUTPUT: |
|
870 |
smcp.msg_lev = GLP_MSG_ON; |
|
871 |
break; |
|
872 |
case MESSAGE_FULL_OUTPUT: |
|
873 |
smcp.msg_lev = GLP_MSG_ALL; |
|
874 |
break; |
|
875 |
} |
|
876 |
smcp.meth = GLP_DUAL; |
|
877 |
|
|
878 |
if (glp_simplex(lp, &smcp) != 0) return UNSOLVED; |
|
879 |
if (glp_get_status(lp) != GLP_OPT) return SOLVED; |
|
880 |
|
|
881 |
glp_iocp iocp; |
|
882 |
glp_init_iocp(&iocp); |
|
883 |
|
|
884 |
switch (_message_level) { |
|
885 |
case MESSAGE_NO_OUTPUT: |
|
886 |
iocp.msg_lev = GLP_MSG_OFF; |
|
887 |
break; |
|
888 |
case MESSAGE_ERROR_MESSAGE: |
|
889 |
iocp.msg_lev = GLP_MSG_ERR; |
|
890 |
break; |
|
891 |
case MESSAGE_NORMAL_OUTPUT: |
|
892 |
iocp.msg_lev = GLP_MSG_ON; |
|
893 |
break; |
|
894 |
case MESSAGE_FULL_OUTPUT: |
|
895 |
iocp.msg_lev = GLP_MSG_ALL; |
|
896 |
break; |
|
897 |
} |
|
898 |
|
|
899 |
if (glp_intopt(lp, &iocp) != 0) return UNSOLVED; |
|
900 |
return SOLVED; |
|
901 |
} |
|
902 |
|
|
903 |
|
|
904 |
MipGlpk::ProblemType MipGlpk::_getType() const { |
|
905 |
switch (glp_get_status(lp)) { |
|
906 |
case GLP_OPT: |
|
907 |
switch (glp_mip_status(lp)) { |
|
908 |
case GLP_UNDEF: |
|
909 |
return UNDEFINED; |
|
910 |
case GLP_NOFEAS: |
|
911 |
return INFEASIBLE; |
|
912 |
case GLP_FEAS: |
|
913 |
return FEASIBLE; |
|
914 |
case GLP_OPT: |
|
915 |
return OPTIMAL; |
|
916 |
default: |
|
917 |
LEMON_ASSERT(false, "Wrong problem type."); |
|
918 |
return MipGlpk::ProblemType(); |
|
919 |
} |
|
920 |
case GLP_NOFEAS: |
|
921 |
return INFEASIBLE; |
|
922 |
case GLP_INFEAS: |
|
923 |
case GLP_FEAS: |
|
924 |
if (glp_get_dual_stat(lp) == GLP_NOFEAS) { |
|
925 |
return UNBOUNDED; |
|
926 |
} else { |
|
927 |
return UNDEFINED; |
|
928 |
} |
|
929 |
default: |
|
930 |
LEMON_ASSERT(false, "Wrong problem type."); |
|
931 |
return MipGlpk::ProblemType(); |
|
932 |
} |
|
933 |
} |
|
934 |
|
|
935 |
MipGlpk::Value MipGlpk::_getSol(int i) const { |
|
936 |
return glp_mip_col_val(lp, i); |
|
937 |
} |
|
938 |
|
|
939 |
MipGlpk::Value MipGlpk::_getSolValue() const { |
|
940 |
return glp_mip_obj_val(lp); |
|
941 |
} |
|
942 |
|
|
943 |
MipGlpk* MipGlpk::_newSolver() const { return new MipGlpk; } |
|
944 |
MipGlpk* MipGlpk::_cloneSolver() const {return new MipGlpk(*this); } |
|
945 |
|
|
946 |
const char* MipGlpk::_solverName() const { return "MipGlpk"; } |
|
947 |
|
|
948 |
void MipGlpk::messageLevel(MessageLevel m) { |
|
949 |
_message_level = m; |
|
950 |
} |
|
643 | 951 |
|
644 | 952 |
} //END OF NAMESPACE LEMON |
... | ... |
@@ -36,38 +36,43 @@ |
36 | 36 |
|
37 | 37 |
|
38 |
/// \brief |
|
38 |
/// \brief Base interface for the GLPK LP and MIP solver |
|
39 | 39 |
/// |
40 |
/// This class implements an interface for the GLPK LP solver. |
|
41 |
///\ingroup lp_group |
|
42 |
class |
|
40 |
/// This class implements the common interface of the GLPK LP and MIP solver. |
|
41 |
/// \ingroup lp_group |
|
42 |
class GlpkBase : virtual public LpBase { |
|
43 | 43 |
protected: |
44 | 44 |
|
45 | 45 |
typedef glp_prob LPX; |
46 | 46 |
glp_prob* lp; |
47 |
bool solved; |
|
48 | 47 |
|
49 |
public: |
|
50 |
|
|
51 |
typedef LpSolverBase Parent; |
|
52 |
|
|
53 |
LpGlpk(); |
|
54 |
LpGlpk(const LpGlpk &); |
|
55 |
|
|
48 |
GlpkBase(); |
|
49 |
GlpkBase(const GlpkBase&); |
|
50 |
virtual ~GlpkBase(); |
|
56 | 51 |
|
57 | 52 |
protected: |
58 |
virtual LpSolverBase* _newLp(); |
|
59 |
virtual LpSolverBase* _copyLp(); |
|
60 | 53 |
|
61 | 54 |
virtual int _addCol(); |
62 | 55 |
virtual int _addRow(); |
56 |
|
|
63 | 57 |
virtual void _eraseCol(int i); |
64 | 58 |
virtual void _eraseRow(int i); |
65 |
virtual void _getColName(int col, std::string & name) const; |
|
66 |
virtual void _setColName(int col, const std::string & name); |
|
59 |
|
|
60 |
virtual void _eraseColId(int i); |
|
61 |
virtual void _eraseRowId(int i); |
|
62 |
|
|
63 |
virtual void _getColName(int col, std::string& name) const; |
|
64 |
virtual void _setColName(int col, const std::string& name); |
|
67 | 65 |
virtual int _colByName(const std::string& name) const; |
68 |
virtual void _setRowCoeffs(int i, ConstRowIterator b, ConstRowIterator e); |
|
69 |
virtual void _getRowCoeffs(int i, RowIterator b) const; |
|
70 |
virtual void _setColCoeffs(int i, ConstColIterator b, ConstColIterator e); |
|
71 |
virtual void _getColCoeffs(int i, ColIterator b) const; |
|
66 |
|
|
67 |
virtual void _getRowName(int row, std::string& name) const; |
|
68 |
virtual void _setRowName(int row, const std::string& name); |
|
69 |
virtual int _rowByName(const std::string& name) const; |
|
70 |
|
|
71 |
virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); |
|
72 |
virtual void _getRowCoeffs(int i, InsertIterator b) const; |
|
73 |
|
|
74 |
virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); |
|
75 |
virtual void _getColCoeffs(int i, InsertIterator b) const; |
|
76 |
|
|
72 | 77 |
virtual void _setCoeff(int row, int col, Value value); |
73 | 78 |
virtual Value _getCoeff(int row, int col) const; |
... | ... |
@@ -75,47 +80,91 @@ |
75 | 80 |
virtual void _setColLowerBound(int i, Value value); |
76 | 81 |
virtual Value _getColLowerBound(int i) const; |
82 |
|
|
77 | 83 |
virtual void _setColUpperBound(int i, Value value); |
78 | 84 |
virtual Value _getColUpperBound(int i) const; |
79 | 85 |
|
80 |
virtual void _setRowBounds(int i, Value lower, Value upper); |
|
81 |
virtual void _getRowBounds(int i, Value &lb, Value &ub) const; |
|
86 |
virtual void _setRowLowerBound(int i, Value value); |
|
87 |
virtual Value _getRowLowerBound(int i) const; |
|
88 |
|
|
89 |
virtual void _setRowUpperBound(int i, Value value); |
|
90 |
virtual Value _getRowUpperBound(int i) const; |
|
91 |
|
|
92 |
virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); |
|
93 |
virtual void _getObjCoeffs(InsertIterator b) const; |
|
94 |
|
|
82 | 95 |
virtual void _setObjCoeff(int i, Value obj_coef); |
83 | 96 |
virtual Value _getObjCoeff(int i) const; |
84 |
|
|
97 |
|
|
98 |
virtual void _setSense(Sense); |
|
99 |
virtual Sense _getSense() const; |
|
100 |
|
|
101 |
virtual void _clear(); |
|
102 |
|
|
103 |
public: |
|
104 |
|
|
105 |
///Pointer to the underlying GLPK data structure. |
|
106 |
LPX *lpx() {return lp;} |
|
107 |
///Const pointer to the underlying GLPK data structure. |
|
108 |
const LPX *lpx() const {return lp;} |
|
109 |
|
|
110 |
///Returns the constraint identifier understood by GLPK. |
|
111 |
int lpxRow(Row r) const { return rows(id(r)); } |
|
112 |
|
|
113 |
///Returns the variable identifier understood by GLPK. |
|
114 |
int lpxCol(Col c) const { return cols(id(c)); } |
|
115 |
|
|
116 |
}; |
|
117 |
|
|
118 |
/// \brief Interface for the GLPK LP solver |
|
119 |
/// |
|
120 |
/// This class implements an interface for the GLPK LP solver. |
|
121 |
///\ingroup lp_group |
|
122 |
class LpGlpk : public GlpkBase, public LpSolver { |
|
123 |
public: |
|
85 | 124 |
|
86 | 125 |
///\e |
126 |
LpGlpk(); |
|
127 |
///\e |
|
128 |
LpGlpk(const LpGlpk&); |
|
129 |
|
|
130 |
private: |
|
131 |
|
|
132 |
mutable std::vector<double> _primal_ray; |
|
133 |
mutable std::vector<double> _dual_ray; |
|
134 |
|
|
135 |
void _clear_temporals(); |
|
136 |
|
|
137 |
protected: |
|
138 |
|
|
139 |
virtual LpGlpk* _cloneSolver() const; |
|
140 |
virtual LpGlpk* _newSolver() const; |
|
141 |
|
|
142 |
virtual const char* _solverName() const; |
|
143 |
|
|
144 |
virtual SolveExitStatus _solve(); |
|
145 |
virtual Value _getPrimal(int i) const; |
|
146 |
virtual Value _getDual(int i) const; |
|
147 |
|
|
148 |
virtual Value _getPrimalValue() const; |
|
149 |
|
|
150 |
virtual VarStatus _getColStatus(int i) const; |
|
151 |
virtual VarStatus _getRowStatus(int i) const; |
|
152 |
|
|
153 |
virtual Value _getPrimalRay(int i) const; |
|
154 |
virtual Value _getDualRay(int i) const; |
|
87 | 155 |
|
88 | 156 |
///\todo It should be clarified |
89 | 157 |
/// |
90 |
virtual SolveExitStatus _solve(); |
|
91 |
virtual Value _getPrimal(int i) const; |
|
92 |
virtual Value _getDual(int i) const; |
|
93 |
virtual Value _getPrimalValue() const; |
|
94 |
virtual bool _isBasicCol(int i) const; |
|
95 |
///\e |
|
96 |
|
|
97 |
///\todo It should be clarified |
|
98 |
/// |
|
99 |
virtual SolutionStatus _getPrimalStatus() const; |
|
100 |
virtual SolutionStatus _getDualStatus() const; |
|
101 |
virtual ProblemTypes _getProblemType() const; |
|
102 |
|
|
103 |
virtual void _setMax(); |
|
104 |
virtual void _setMin(); |
|
105 |
|
|
106 |
virtual |
|
158 |
virtual ProblemType _getPrimalType() const; |
|
159 |
virtual ProblemType _getDualType() const; |
|
107 | 160 |
|
108 | 161 |
public: |
109 |
///Set the verbosity of the messages |
|
110 | 162 |
|
111 |
///Set the verbosity of the messages |
|
112 |
/// |
|
113 |
///\param m is the level of the messages output by the solver routines. |
|
114 |
///The possible values are: |
|
115 |
///- 0 --- no output (default value) |
|
116 |
///- 1 --- error messages only |
|
117 |
///- 2 --- normal output |
|
118 |
///- 3 --- full output (includes informational messages) |
|
119 |
|
|
163 |
///Solve with primal simplex |
|
164 |
SolveExitStatus solvePrimal(); |
|
165 |
|
|
166 |
///Solve with dual simplex |
|
167 |
SolveExitStatus solveDual(); |
|
168 |
|
|
120 | 169 |
///Turns on or off the presolver |
121 | 170 |
|
... | ... |
@@ -125,13 +174,84 @@ |
125 | 174 |
void presolver(bool b); |
126 | 175 |
|
127 |
///Pointer to the underlying GLPK data structure. |
|
128 |
LPX *lpx() {return lp;} |
|
176 |
///Enum for \c messageLevel() parameter |
|
177 |
enum MessageLevel { |
|
178 |
/// no output (default value) |
|
179 |
MESSAGE_NO_OUTPUT = 0, |
|
180 |
/// error messages only |
|
181 |
MESSAGE_ERROR_MESSAGE = 1, |
|
182 |
/// normal output |
|
183 |
MESSAGE_NORMAL_OUTPUT = 2, |
|
184 |
/// full output (includes informational messages) |
|
185 |
MESSAGE_FULL_OUTPUT = 3 |
|
186 |
}; |
|
129 | 187 |
|
130 |
///Returns the constraint identifier understood by GLPK. |
|
131 |
int lpxRow(Row r) { return _lpId(r); } |
|
188 |
private: |
|
132 | 189 |
|
133 |
///Returns the variable identifier understood by GLPK. |
|
134 |
int lpxCol(Col c) { return _lpId(c); } |
|
190 |
MessageLevel _message_level; |
|
191 |
|
|
192 |
public: |
|
193 |
|
|
194 |
///Set the verbosity of the messages |
|
195 |
|
|
196 |
///Set the verbosity of the messages |
|
197 |
/// |
|
198 |
///\param m is the level of the messages output by the solver routines. |
|
199 |
void messageLevel(MessageLevel m); |
|
135 | 200 |
}; |
201 |
|
|
202 |
/// \brief Interface for the GLPK MIP solver |
|
203 |
/// |
|
204 |
/// This class implements an interface for the GLPK MIP solver. |
|
205 |
///\ingroup lp_group |
|
206 |
class MipGlpk : public GlpkBase, public MipSolver { |
|
207 |
public: |
|
208 |
|
|
209 |
///\e |
|
210 |
MipGlpk(); |
|
211 |
///\e |
|
212 |
MipGlpk(const MipGlpk&); |
|
213 |
|
|
214 |
protected: |
|
215 |
|
|
216 |
virtual MipGlpk* _cloneSolver() const; |
|
217 |
virtual MipGlpk* _newSolver() const; |
|
218 |
|
|
219 |
virtual const char* _solverName() const; |
|
220 |
|
|
221 |
virtual ColTypes _getColType(int col) const; |
|
222 |
virtual void _setColType(int col, ColTypes col_type); |
|
223 |
|
|
224 |
virtual SolveExitStatus _solve(); |
|
225 |
virtual ProblemType _getType() const; |
|
226 |
virtual Value _getSol(int i) const; |
|
227 |
virtual Value _getSolValue() const; |
|
228 |
|
|
229 |
///Enum for \c messageLevel() parameter |
|
230 |
enum MessageLevel { |
|
231 |
/// no output (default value) |
|
232 |
MESSAGE_NO_OUTPUT = 0, |
|
233 |
/// error messages only |
|
234 |
MESSAGE_ERROR_MESSAGE = 1, |
|
235 |
/// normal output |
|
236 |
MESSAGE_NORMAL_OUTPUT = 2, |
|
237 |
/// full output (includes informational messages) |
|
238 |
MESSAGE_FULL_OUTPUT = 3 |
|
239 |
}; |
|
240 |
|
|
241 |
private: |
|
242 |
|
|
243 |
MessageLevel _message_level; |
|
244 |
|
|
245 |
public: |
|
246 |
|
|
247 |
///Set the verbosity of the messages |
|
248 |
|
|
249 |
///Set the verbosity of the messages |
|
250 |
/// |
|
251 |
///\param m is the level of the messages output by the solver routines. |
|
252 |
void messageLevel(MessageLevel m); |
|
253 |
}; |
|
254 |
|
|
255 |
|
|
136 | 256 |
} //END OF NAMESPACE LEMON |
137 | 257 |
... | ... |
@@ -23,164 +23,111 @@ |
23 | 23 |
namespace lemon { |
24 | 24 |
|
25 |
LpSolverBase* LpSkeleton::_newLp() |
|
26 |
{ |
|
27 |
LpSolverBase *tmp=0; |
|
28 |
return tmp; |
|
29 |
} |
|
30 |
|
|
31 |
LpSolverBase* LpSkeleton::_copyLp() |
|
32 |
{ |
|
33 |
LpSolverBase *tmp=0; |
|
34 |
return tmp; |
|
35 |
} |
|
36 |
|
|
37 |
int |
|
25 |
int SkeletonSolverBase::_addCol() |
|
38 | 26 |
{ |
39 | 27 |
return ++col_num; |
40 | 28 |
} |
41 | 29 |
|
42 |
int |
|
30 |
int SkeletonSolverBase::_addRow() |
|
43 | 31 |
{ |
44 | 32 |
return ++row_num; |
45 | 33 |
} |
46 | 34 |
|
47 |
void |
|
35 |
void SkeletonSolverBase::_eraseCol(int) {} |
|
36 |
void SkeletonSolverBase::_eraseRow(int) {} |
|
37 |
|
|
38 |
void SkeletonSolverBase::_getColName(int, std::string &) const {} |
|
39 |
void SkeletonSolverBase::_setColName(int, const std::string &) {} |
|
40 |
int SkeletonSolverBase::_colByName(const std::string&) const { return -1; } |
|
41 |
|
|
42 |
void SkeletonSolverBase::_getRowName(int, std::string &) const {} |
|
43 |
void SkeletonSolverBase::_setRowName(int, const std::string &) {} |
|
44 |
int SkeletonSolverBase::_rowByName(const std::string&) const { return -1; } |
|
45 |
|
|
46 |
void SkeletonSolverBase::_setRowCoeffs(int, ExprIterator, ExprIterator) {} |
|
47 |
void SkeletonSolverBase::_getRowCoeffs(int, InsertIterator) const {} |
|
48 |
|
|
49 |
void SkeletonSolverBase::_setColCoeffs(int, ExprIterator, ExprIterator) {} |
|
50 |
void SkeletonSolverBase::_getColCoeffs(int, InsertIterator) const {} |
|
51 |
|
|
52 |
void SkeletonSolverBase::_setCoeff(int, int, Value) {} |
|
53 |
SkeletonSolverBase::Value SkeletonSolverBase::_getCoeff(int, int) const |
|
54 |
{ return 0; } |
|
55 |
|
|
56 |
void SkeletonSolverBase::_setColLowerBound(int, Value) {} |
|
57 |
SkeletonSolverBase::Value SkeletonSolverBase::_getColLowerBound(int) const |
|
58 |
{ return 0; } |
|
59 |
|
|
60 |
void SkeletonSolverBase::_setColUpperBound(int, Value) {} |
|
61 |
SkeletonSolverBase::Value SkeletonSolverBase::_getColUpperBound(int) const |
|
62 |
{ return 0; } |
|
63 |
|
|
64 |
void SkeletonSolverBase::_setRowLowerBound(int, Value) {} |
|
65 |
SkeletonSolverBase::Value SkeletonSolverBase::_getRowLowerBound(int) const |
|
66 |
{ return 0; } |
|
67 |
|
|
68 |
void SkeletonSolverBase::_setRowUpperBound(int, Value) {} |
|
69 |
SkeletonSolverBase::Value SkeletonSolverBase::_getRowUpperBound(int) const |
|
70 |
{ return 0; } |
|
71 |
|
|
72 |
void SkeletonSolverBase::_setObjCoeffs(ExprIterator, ExprIterator) {} |
|
73 |
void SkeletonSolverBase::_getObjCoeffs(InsertIterator) const {}; |
|
74 |
|
|
75 |
void SkeletonSolverBase::_setObjCoeff(int, Value) {} |
|
76 |
SkeletonSolverBase::Value SkeletonSolverBase::_getObjCoeff(int) const |
|
77 |
{ return 0; } |
|
78 |
|
|
79 |
void SkeletonSolverBase::_setSense(Sense) {} |
|
80 |
SkeletonSolverBase::Sense SkeletonSolverBase::_getSense() const |
|
81 |
{ return MIN; } |
|
82 |
|
|
83 |
void SkeletonSolverBase::_clear() { |
|
84 |
row_num = col_num = 0; |
|
48 | 85 |
} |
49 | 86 |
|
50 |
void LpSkeleton::_eraseRow(int) { |
|
51 |
} |
|
87 |
LpSkeleton::SolveExitStatus LpSkeleton::_solve() { return SOLVED; } |
|
52 | 88 |
|
53 |
void LpSkeleton::_getColName(int, std::string &) const { |
|
54 |
} |
|
89 |
LpSkeleton::Value LpSkeleton::_getPrimal(int) const { return 0; } |
|
90 |
LpSkeleton::Value LpSkeleton::_getDual(int) const { return 0; } |
|
91 |
LpSkeleton::Value LpSkeleton::_getPrimalValue() const { return 0; } |
|
55 | 92 |
|
93 |
LpSkeleton::Value LpSkeleton::_getPrimalRay(int) const { return 0; } |
|
94 |
LpSkeleton::Value LpSkeleton::_getDualRay(int) const { return 0; } |
|
56 | 95 |
|
57 |
void LpSkeleton::_setColName(int, const std::string &) { |
|
58 |
} |
|
96 |
LpSkeleton::ProblemType LpSkeleton::_getPrimalType() const |
|
97 |
{ return UNDEFINED; } |
|
59 | 98 |
|
60 |
|
|
99 |
LpSkeleton::ProblemType LpSkeleton::_getDualType() const |
|
100 |
{ return UNDEFINED; } |
|
61 | 101 |
|
102 |
LpSkeleton::VarStatus LpSkeleton::_getColStatus(int) const |
|
103 |
{ return BASIC; } |
|
62 | 104 |
|
63 |
void LpSkeleton::_setRowCoeffs(int, ConstRowIterator, ConstRowIterator) { |
|
64 |
} |
|
105 |
LpSkeleton::VarStatus LpSkeleton::_getRowStatus(int) const |
|
106 |
{ return BASIC; } |
|
65 | 107 |
|
66 |
void LpSkeleton::_getRowCoeffs(int, RowIterator) const { |
|
67 |
} |
|
108 |
LpSkeleton* LpSkeleton::_newSolver() const |
|
109 |
{ return static_cast<LpSkeleton*>(0); } |
|
68 | 110 |
|
69 |
void LpSkeleton::_setColCoeffs(int, ConstColIterator, ConstColIterator) { |
|
70 |
} |
|
111 |
LpSkeleton* LpSkeleton::_cloneSolver() const |
|
112 |
{ return static_cast<LpSkeleton*>(0); } |
|
71 | 113 |
|
72 |
void LpSkeleton::_getColCoeffs(int, ColIterator) const { |
|
73 |
} |
|
114 |
const char* LpSkeleton::_solverName() const { return "LpSkeleton"; } |
|
74 | 115 |
|
75 |
void LpSkeleton::_setCoeff(int, int, Value ) |
|
76 |
{ |
|
77 |
|
|
116 |
MipSkeleton::SolveExitStatus MipSkeleton::_solve() |
|
117 |
{ return SOLVED; } |
|
78 | 118 |
|
79 |
LpSkeleton::Value LpSkeleton::_getCoeff(int, int) const |
|
80 |
{ |
|
81 |
return 0; |
|
82 |
} |
|
119 |
MipSkeleton::Value MipSkeleton::_getSol(int) const { return 0; } |
|
120 |
MipSkeleton::Value MipSkeleton::_getSolValue() const { return 0; } |
|
83 | 121 |
|
122 |
MipSkeleton::ProblemType MipSkeleton::_getType() const |
|
123 |
{ return UNDEFINED; } |
|
84 | 124 |
|
85 |
void LpSkeleton::_setColLowerBound(int, Value) |
|
86 |
{ |
|
87 |
|
|
125 |
MipSkeleton* MipSkeleton::_newSolver() const |
|
126 |
{ return static_cast<MipSkeleton*>(0); } |
|
88 | 127 |
|
89 |
LpSkeleton::Value LpSkeleton::_getColLowerBound(int) const |
|
90 |
{ |
|
91 |
return 0; |
|
92 |
} |
|
128 |
MipSkeleton* MipSkeleton::_cloneSolver() const |
|
129 |
{ return static_cast<MipSkeleton*>(0); } |
|
93 | 130 |
|
94 |
void LpSkeleton::_setColUpperBound(int, Value) |
|
95 |
{ |
|
96 |
} |
|
97 |
|
|
98 |
LpSkeleton::Value LpSkeleton::_getColUpperBound(int) const |
|
99 |
{ |
|
100 |
return 0; |
|
101 |
} |
|
102 |
|
|
103 |
// void LpSkeleton::_setRowLowerBound(int, Value) |
|
104 |
// { |
|
105 |
// } |
|
106 |
|
|
107 |
// void LpSkeleton::_setRowUpperBound(int, Value) |
|
108 |
// { |
|
109 |
// } |
|
110 |
|
|
111 |
void LpSkeleton::_setRowBounds(int, Value, Value) |
|
112 |
{ |
|
113 |
} |
|
114 |
|
|
115 |
void LpSkeleton::_getRowBounds(int, Value&, Value&) const |
|
116 |
{ |
|
117 |
} |
|
118 |
|
|
119 |
void LpSkeleton::_setObjCoeff(int, Value) |
|
120 |
{ |
|
121 |
} |
|
122 |
|
|
123 |
LpSkeleton::Value LpSkeleton::_getObjCoeff(int) const |
|
124 |
{ |
|
125 |
return 0; |
|
126 |
} |
|
127 |
|
|
128 |
void LpSkeleton::_setMax() |
|
129 |
{ |
|
130 |
} |
|
131 |
|
|
132 |
void LpSkeleton::_setMin() |
|
133 |
{ |
|
134 |
} |
|
135 |
|
|
136 |
bool LpSkeleton::_isMax() const |
|
137 |
{ |
|
138 |
return true; |
|
139 |
} |
|
140 |
|
|
141 |
|
|
142 |
void LpSkeleton::_clearObj() |
|
143 |
{ |
|
144 |
} |
|
145 |
|
|
146 |
LpSkeleton::SolveExitStatus LpSkeleton::_solve() |
|
147 |
{ |
|
148 |
return SOLVED; |
|
149 |
} |
|
150 |
|
|
151 |
LpSkeleton::Value LpSkeleton::_getPrimal(int) const |
|
152 |
{ |
|
153 |
return 0; |
|
154 |
} |
|
155 |
|
|
156 |
LpSkeleton::Value LpSkeleton::_getDual(int) const |
|
157 |
{ |
|
158 |
return 0; |
|
159 |
} |
|
160 |
|
|
161 |
LpSkeleton::Value LpSkeleton::_getPrimalValue() const |
|
162 |
{ |
|
163 |
return 0; |
|
164 |
} |
|
165 |
|
|
166 |
LpSkeleton::SolutionStatus LpSkeleton::_getPrimalStatus() const |
|
167 |
{ |
|
168 |
return UNDEFINED; |
|
169 |
} |
|
170 |
|
|
171 |
LpSkeleton::SolutionStatus LpSkeleton::_getDualStatus() const |
|
172 |
{ |
|
173 |
return UNDEFINED; |
|
174 |
} |
|
175 |
|
|
176 |
LpSkeleton::ProblemTypes LpSkeleton::_getProblemType() const |
|
177 |
{ |
|
178 |
return UNKNOWN; |
|
179 |
} |
|
180 |
|
|
181 |
bool LpSkeleton::_isBasicCol(int) const |
|
182 |
{ |
|
183 |
return true; |
|
184 |
} |
|
131 |
const char* MipSkeleton::_solverName() const { return "MipSkeleton"; } |
|
185 | 132 |
|
186 | 133 |
} //namespace lemon |
... | ... |
@@ -27,13 +27,12 @@ |
27 | 27 |
|
28 | 28 |
///A skeleton class to implement LP solver interfaces |
29 |
class |
|
29 |
class SkeletonSolverBase : public virtual LpBase { |
|
30 | 30 |
int col_num,row_num; |
31 | 31 |
|
32 | 32 |
protected: |
33 | 33 |
|
34 |
///\e |
|
35 |
virtual LpSolverBase* _newLp(); |
|
36 |
///\e |
|
37 |
virtual LpSolverBase* _copyLp(); |
|
34 |
SkeletonSolverBase() |
|
35 |
: col_num(-1), row_num(-1) {} |
|
36 |
|
|
38 | 37 |
/// \e |
39 | 38 |
virtual int _addCol(); |
... | ... |
@@ -44,19 +43,27 @@ |
44 | 43 |
/// \e |
45 | 44 |
virtual void _eraseRow(int i); |
45 |
|
|
46 | 46 |
/// \e |
47 |
virtual void _getColName(int col, std::string |
|
47 |
virtual void _getColName(int col, std::string& name) const; |
|
48 | 48 |
/// \e |
49 |
virtual void _setColName(int col, const std::string |
|
49 |
virtual void _setColName(int col, const std::string& name); |
|
50 | 50 |
/// \e |
51 | 51 |
virtual int _colByName(const std::string& name) const; |
52 | 52 |
|
53 | 53 |
/// \e |
54 |
virtual void |
|
54 |
virtual void _getRowName(int row, std::string& name) const; |
|
55 | 55 |
/// \e |
56 |
virtual void |
|
56 |
virtual void _setRowName(int row, const std::string& name); |
|
57 | 57 |
/// \e |
58 |
virtual |
|
58 |
virtual int _rowByName(const std::string& name) const; |
|
59 |
|
|
59 | 60 |
/// \e |
60 |
virtual void |
|
61 |
virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); |
|
62 |
/// \e |
|
63 |
virtual void _getRowCoeffs(int i, InsertIterator b) const; |
|
64 |
/// \e |
|
65 |
virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); |
|
66 |
/// \e |
|
67 |
virtual void _getColCoeffs(int i, InsertIterator b) const; |
|
61 | 68 |
|
62 | 69 |
/// Set one element of the coefficient matrix |
... | ... |
@@ -88,40 +95,101 @@ |
88 | 95 |
virtual Value _getColUpperBound(int i) const; |
89 | 96 |
|
90 |
// /// The lower bound of a linear expression (row) have to be given by an |
|
91 |
// /// extended number of type Value, i.e. a finite number of type |
|
92 |
// /// Value or -\ref INF. |
|
93 |
// virtual void _setRowLowerBound(int i, Value value); |
|
94 |
// /// \e |
|
95 |
|
|
96 |
// /// The upper bound of a linear expression (row) have to be given by an |
|
97 |
// /// extended number of type Value, i.e. a finite number of type |
|
98 |
// /// Value or \ref INF. |
|
99 |
// virtual void _setRowUpperBound(int i, Value value); |
|
100 |
|
|
101 |
/// The lower and upper bound of a linear expression (row) have to be |
|
102 |
/// given by an |
|
97 |
/// The lower bound of a constraint (row) have to be given by an |
|
103 | 98 |
/// extended number of type Value, i.e. a finite number of type |
104 |
/// Value or +/-\ref INF. |
|
105 |
virtual void _setRowBounds(int i, Value lb, Value ub); |
|
99 |
/// Value or -\ref INF. |
|
100 |
virtual void _setRowLowerBound(int i, Value value); |
|
106 | 101 |
/// \e |
107 | 102 |
|
103 |
/// The lower bound of a constraint (row) is an |
|
104 |
/// extended number of type Value, i.e. a finite number of type |
|
105 |
/// Value or -\ref INF. |
|
106 |
virtual Value _getRowLowerBound(int i) const; |
|
108 | 107 |
|
109 |
/// The lower and the upper bound of |
|
110 |
/// a constraint (row) are |
|
111 |
/// extended numbers of type Value, i.e. finite numbers of type |
|
112 |
/// Value, -\ref INF or \ref INF. |
|
113 |
|
|
108 |
/// The upper bound of a constraint (row) have to be given by an |
|
109 |
/// extended number of type Value, i.e. a finite number of type |
|
110 |
/// Value or \ref INF. |
|
111 |
virtual void _setRowUpperBound(int i, Value value); |
|
114 | 112 |
/// \e |
115 | 113 |
|
114 |
/// The upper bound of a constraint (row) is an |
|
115 |
/// extended number of type Value, i.e. a finite number of type |
|
116 |
/// Value or \ref INF. |
|
117 |
virtual Value _getRowUpperBound(int i) const; |
|
116 | 118 |
|
117 | 119 |
/// \e |
118 |
virtual void |
|
120 |
virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); |
|
121 |
/// \e |
|
122 |
virtual void _getObjCoeffs(InsertIterator b) const; |
|
123 |
|
|
119 | 124 |
/// \e |
120 | 125 |
virtual void _setObjCoeff(int i, Value obj_coef); |
121 |
|
|
122 | 126 |
/// \e |
123 | 127 |
virtual Value _getObjCoeff(int i) const; |
124 | 128 |
|
125 | 129 |
///\e |
130 |
virtual void _setSense(Sense); |
|
131 |
///\e |
|
132 |
virtual Sense _getSense() const; |
|
133 |
|
|
134 |
///\e |
|
135 |
virtual void _clear(); |
|
136 |
|
|
137 |
}; |
|
138 |
|
|
139 |
/// \brief Interface for a skeleton LP solver |
|
140 |
/// |
|
141 |
/// This class implements an interface for a skeleton LP solver. |
|
142 |
///\ingroup lp_group |
|
143 |
class LpSkeleton : public SkeletonSolverBase, public LpSolver { |
|
144 |
public: |
|
145 |
LpSkeleton() : SkeletonSolverBase(), LpSolver() {} |
|
146 |
|
|
147 |
protected: |
|
148 |
|
|
149 |
///\e |
|
150 |
virtual SolveExitStatus _solve(); |
|
151 |
|
|
152 |
///\e |
|
153 |
virtual Value _getPrimal(int i) const; |
|
154 |
///\e |
|
155 |
virtual Value _getDual(int i) const; |
|
156 |
|
|
157 |
///\e |
|
158 |
virtual Value _getPrimalValue() const; |
|
159 |
|
|
160 |
///\e |
|
161 |
virtual Value _getPrimalRay(int i) const; |
|
162 |
///\e |
|
163 |
virtual Value _getDualRay(int i) const; |
|
164 |
|
|
165 |
///\e |
|
166 |
virtual ProblemType _getPrimalType() const; |
|
167 |
///\e |
|
168 |
virtual ProblemType _getDualType() const; |
|
169 |
|
|
170 |
///\e |
|
171 |
virtual VarStatus _getColStatus(int i) const; |
|
172 |
///\e |
|
173 |
virtual VarStatus _getRowStatus(int i) const; |
|
174 |
|
|
175 |
///\e |
|
176 |
virtual LpSkeleton* _newSolver() const; |
|
177 |
///\e |
|
178 |
virtual LpSkeleton* _cloneSolver() const; |
|
179 |
///\e |
|
180 |
virtual const char* _solverName() const; |
|
181 |
|
|
182 |
}; |
|
183 |
|
|
184 |
/// \brief Interface for a skeleton MIP solver |
|
185 |
/// |
|
186 |
/// This class implements an interface for a skeleton MIP solver. |
|
187 |
///\ingroup lp_group |
|
188 |
class MipSkeleton : public SkeletonSolverBase, public MipSolver { |
|
189 |
public: |
|
190 |
MipSkeleton() : SkeletonSolverBase(), MipSolver() {} |
|
191 |
|
|
192 |
protected: |
|
193 |
///\e |
|
126 | 194 |
|
127 | 195 |
///\bug Wrong interface |
... | ... |
@@ -133,5 +201,5 @@ |
133 | 201 |
///\bug Wrong interface |
134 | 202 |
/// |
135 |
virtual Value |
|
203 |
virtual Value _getSol(int i) const; |
|
136 | 204 |
|
137 | 205 |
///\e |
... | ... |
@@ -139,5 +207,5 @@ |
139 | 207 |
///\bug Wrong interface |
140 | 208 |
/// |
141 |
virtual Value |
|
209 |
virtual Value _getSolValue() const; |
|
142 | 210 |
|
143 | 211 |
///\e |
... | ... |
@@ -145,36 +213,14 @@ |
145 | 213 |
///\bug Wrong interface |
146 | 214 |
/// |
147 |
virtual |
|
215 |
virtual ProblemType _getType() const; |
|
148 | 216 |
|
149 | 217 |
///\e |
150 |
|
|
151 |
///\bug Wrong interface |
|
152 |
/// |
|
153 |
virtual SolutionStatus _getPrimalStatus() const; |
|
154 |
|
|
155 |
////e |
|
156 |
virtual SolutionStatus _getDualStatus() const; |
|
157 |
|
|
218 |
virtual MipSkeleton* _newSolver() const; |
|
158 | 219 |
|
159 | 220 |
///\e |
160 |
virtual |
|
221 |
virtual MipSkeleton* _cloneSolver() const; |
|
222 |
///\e |
|
223 |
virtual const char* _solverName() const; |
|
161 | 224 |
|
162 |
///\e |
|
163 |
virtual void _setMax(); |
|
164 |
///\e |
|
165 |
virtual void _setMin(); |
|
166 |
|
|
167 |
///\e |
|
168 |
virtual bool _isMax() const; |
|
169 |
|
|
170 |
|
|
171 |
|
|
172 |
///\e |
|
173 |
virtual bool _isBasicCol(int i) const; |
|
174 |
|
|
175 |
|
|
176 |
|
|
177 |
public: |
|
178 |
LpSkeleton() : LpSolverBase(), col_num(0), row_num(0) {} |
|
179 | 225 |
}; |
180 | 226 |
... | ... |
@@ -17,6 +17,6 @@ |
17 | 17 |
*/ |
18 | 18 |
|
19 |
#include<iostream> |
|
20 |
#include<lemon/lp_soplex.h> |
|
19 |
#include <iostream> |
|
20 |
#include <lemon/lp_soplex.h> |
|
21 | 21 |
|
22 | 22 |
#include <soplex/soplex.h> |
... | ... |
@@ -27,9 +27,6 @@ |
27 | 27 |
namespace lemon { |
28 | 28 |
|
29 |
LpSoplex::LpSoplex() : LpSolverBase() { |
|
30 |
rows.setIdHandler(relocateIdHandler); |
|
31 |
|
|
29 |
LpSoplex::LpSoplex() { |
|
32 | 30 |
soplex = new soplex::SoPlex; |
33 |
solved = false; |
|
34 | 31 |
} |
35 | 32 |
|
... | ... |
@@ -38,32 +35,36 @@ |
38 | 35 |
} |
39 | 36 |
|
40 |
LpSoplex::LpSoplex(const LpSoplex& lp) |
|
37 |
LpSoplex::LpSoplex(const LpSoplex& lp) { |
|
41 | 38 |
rows = lp.rows; |
42 |
rows.setIdHandler(relocateIdHandler); |
|
43 |
|
|
44 | 39 |
cols = lp.cols; |
45 |
cols.setIdHandler(relocateIdHandler); |
|
46 | 40 |
|
47 | 41 |
soplex = new soplex::SoPlex; |
48 | 42 |
(*static_cast<soplex::SPxLP*>(soplex)) = *(lp.soplex); |
49 | 43 |
|
50 |
colNames = lp.colNames; |
|
51 |
invColNames = lp.invColNames; |
|
44 |
_col_names = lp._col_names; |
|
45 |
_col_names_ref = lp._col_names_ref; |
|
52 | 46 |
|
53 |
primal_value = lp.primal_value; |
|
54 |
dual_value = lp.dual_value; |
|
47 |
_row_names = lp._row_names; |
|
48 |
_row_names_ref = lp._row_names_ref; |
|
55 | 49 |
|
56 | 50 |
} |
57 | 51 |
|
58 |
|
|
52 |
void LpSoplex::_clear_temporals() { |
|
53 |
_primal_values.clear(); |
|
54 |
_dual_values.clear(); |
|
55 |
} |
|
56 |
|
|
57 |
LpSoplex* LpSoplex::_newSolver() const { |
|
59 | 58 |
LpSoplex* newlp = new LpSoplex(); |
60 | 59 |
return newlp; |
61 | 60 |
} |
62 | 61 |
|
63 |
|
|
62 |
LpSoplex* LpSoplex::_cloneSolver() const { |
|
64 | 63 |
LpSoplex* newlp = new LpSoplex(*this); |
65 | 64 |
return newlp; |
66 | 65 |
} |
67 | 66 |
|
67 |
const char* LpSoplex::_solverName() const { return "LpSoplex"; } |
|
68 |
|
|
68 | 69 |
int LpSoplex::_addCol() { |
69 | 70 |
soplex::LPCol c; |
... | ... |
@@ -72,7 +73,5 @@ |
72 | 73 |
soplex->addCol(c); |
73 | 74 |
|
74 |
colNames.push_back(std::string()); |
|
75 |
primal_value.push_back(0.0); |
|
76 |
|
|
75 |
_col_names.push_back(std::string()); |
|
77 | 76 |
|
78 | 77 |
return soplex->nCols() - 1; |
... | ... |
@@ -85,6 +84,5 @@ |
85 | 84 |
soplex->addRow(r); |
86 | 85 |
|
87 |
dual_value.push_back(0.0); |
|
88 |
solved = false; |
|
86 |
_row_names.push_back(std::string()); |
|
89 | 87 |
|
90 | 88 |
return soplex->nRows() - 1; |
... | ... |
@@ -94,29 +92,36 @@ |
94 | 92 |
void LpSoplex::_eraseCol(int i) { |
95 | 93 |
soplex->removeCol(i); |
96 |
invColNames.erase(colNames[i]); |
|
97 |
colNames[i] = colNames.back(); |
|
98 |
invColNames[colNames.back()] = i; |
|
99 |
colNames.pop_back(); |
|
100 |
primal_value[i] = primal_value.back(); |
|
101 |
primal_value.pop_back(); |
|
102 |
|
|
94 |
_col_names_ref.erase(_col_names[i]); |
|
95 |
_col_names[i] = _col_names.back(); |
|
96 |
_col_names_ref[_col_names.back()] = i; |
|
97 |
_col_names.pop_back(); |
|
103 | 98 |
} |
104 | 99 |
|
105 | 100 |
void LpSoplex::_eraseRow(int i) { |
106 | 101 |
soplex->removeRow(i); |
107 |
dual_value[i] = dual_value.back(); |
|
108 |
dual_value.pop_back(); |
|
109 |
|
|
102 |
_row_names_ref.erase(_row_names[i]); |
|
103 |
_row_names[i] = _row_names.back(); |
|
104 |
_row_names_ref[_row_names.back()] = i; |
|
105 |
_row_names.pop_back(); |
|
106 |
} |
|
107 |
|
|
108 |
void LpSoplex::_eraseColId(int i) { |
|
109 |
cols.eraseIndex(i); |
|
110 |
cols.relocateIndex(i, cols.maxIndex()); |
|
111 |
} |
|
112 |
void LpSoplex::_eraseRowId(int i) { |
|
113 |
rows.eraseIndex(i); |
|
114 |
rows.relocateIndex(i, rows.maxIndex()); |
|
110 | 115 |
} |
111 | 116 |
|
112 | 117 |
void LpSoplex::_getColName(int c, std::string &name) const { |
113 |
name = |
|
118 |
name = _col_names[c]; |
|
114 | 119 |
} |
115 | 120 |
|
116 | 121 |
void LpSoplex::_setColName(int c, const std::string &name) { |
117 |
invColNames.erase(colNames[c]); |
|
118 |
colNames[c] = name; |
|
122 |
_col_names_ref.erase(_col_names[c]); |
|
123 |
_col_names[c] = name; |
|
119 | 124 |
if (!name.empty()) { |
120 |
|
|
125 |
_col_names_ref.insert(std::make_pair(name, c)); |
|
121 | 126 |
} |
122 | 127 |
} |
... | ... |
@@ -124,6 +129,6 @@ |
124 | 129 |
int LpSoplex::_colByName(const std::string& name) const { |
125 | 130 |
std::map<std::string, int>::const_iterator it = |
126 |
invColNames.find(name); |
|
127 |
if (it != invColNames.end()) { |
|
131 |
_col_names_ref.find(name); |
|
132 |
if (it != _col_names_ref.end()) { |
|
128 | 133 |
return it->second; |
129 | 134 |
} else { |
... | ... |
@@ -132,16 +137,37 @@ |
132 | 137 |
} |
133 | 138 |
|
139 |
void LpSoplex::_getRowName(int r, std::string &name) const { |
|
140 |
name = _row_names[r]; |
|
141 |
} |
|
134 | 142 |
|
135 |
void LpSoplex:: |
|
143 |
void LpSoplex::_setRowName(int r, const std::string &name) { |
|
144 |
_row_names_ref.erase(_row_names[r]); |
|
145 |
_row_names[r] = name; |
|
146 |
if (!name.empty()) { |
|
147 |
_row_names_ref.insert(std::make_pair(name, r)); |
|
148 |
} |
|
149 |
} |
|
150 |
|
|
151 |
int LpSoplex::_rowByName(const std::string& name) const { |
|
152 |
std::map<std::string, int>::const_iterator it = |
|
153 |
_row_names_ref.find(name); |
|
154 |
if (it != _row_names_ref.end()) { |
|
155 |
return it->second; |
|
156 |
} else { |
|
157 |
return -1; |
|
158 |
} |
|
159 |
} |
|
160 |
|
|
161 |
|
|
162 |
void LpSoplex::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) { |
|
136 | 163 |
for (int j = 0; j < soplex->nCols(); ++j) { |
137 | 164 |
soplex->changeElement(i, j, 0.0); |
138 | 165 |
} |
139 |
for( |
|
166 |
for(ExprIterator it = b; it != e; ++it) { |
|
140 | 167 |
soplex->changeElement(i, it->first, it->second); |
141 | 168 |
} |
142 |
solved = false; |
|
143 | 169 |
} |
144 | 170 |
|
145 |
void LpSoplex::_getRowCoeffs(int i, |
|
171 |
void LpSoplex::_getRowCoeffs(int i, InsertIterator b) const { |
|
146 | 172 |
const soplex::SVector& vec = soplex->rowVector(i); |
147 | 173 |
for (int k = 0; k < vec.size(); ++k) { |
... | ... |
@@ -151,15 +177,14 @@ |
151 | 177 |
} |
152 | 178 |
|
153 |
void LpSoplex::_setColCoeffs(int j, |
|
179 |
void LpSoplex::_setColCoeffs(int j, ExprIterator b, ExprIterator e) { |
|
154 | 180 |
for (int i = 0; i < soplex->nRows(); ++i) { |
155 | 181 |
soplex->changeElement(i, j, 0.0); |
156 | 182 |
} |
157 |
for( |
|
183 |
for(ExprIterator it = b; it != e; ++it) { |
|
158 | 184 |
soplex->changeElement(it->first, j, it->second); |
159 | 185 |
} |
160 |
solved = false; |
|
161 | 186 |
} |
162 | 187 |
|
163 |
void LpSoplex::_getColCoeffs(int i, |
|
188 |
void LpSoplex::_getColCoeffs(int i, InsertIterator b) const { |
|
164 | 189 |
const soplex::SVector& vec = soplex->colVector(i); |
165 | 190 |
for (int k = 0; k < vec.size(); ++k) { |
... | ... |
@@ -171,5 +196,4 @@ |
171 | 196 |
void LpSoplex::_setCoeff(int i, int j, Value value) { |
172 | 197 |
soplex->changeElement(i, j, value); |
173 |
solved = false; |
|
174 | 198 |
} |
175 | 199 |
|
... | ... |
@@ -179,6 +203,6 @@ |
179 | 203 |
|
180 | 204 |
void LpSoplex::_setColLowerBound(int i, Value value) { |
205 |
LEMON_ASSERT(value != INF, "Invalid bound"); |
|
181 | 206 |
soplex->changeLower(i, value != -INF ? value : -soplex::infinity); |
182 |
solved = false; |
|
183 | 207 |
} |
184 | 208 |
|
... | ... |
@@ -189,6 +213,6 @@ |
189 | 213 |
|
190 | 214 |
void LpSoplex::_setColUpperBound(int i, Value value) { |
215 |
LEMON_ASSERT(value != -INF, "Invalid bound"); |
|
191 | 216 |
soplex->changeUpper(i, value != INF ? value : soplex::infinity); |
192 |
solved = false; |
|
193 | 217 |
} |
194 | 218 |
|
... | ... |
@@ -198,19 +222,45 @@ |
198 | 222 |
} |
199 | 223 |
|
200 |
void LpSoplex::_setRowBounds(int i, Value lb, Value ub) { |
|
201 |
soplex->changeRange(i, lb != -INF ? lb : -soplex::infinity, |
|
202 |
ub != INF ? ub : soplex::infinity); |
|
203 |
solved = false; |
|
224 |
void LpSoplex::_setRowLowerBound(int i, Value lb) { |
|
225 |
LEMON_ASSERT(lb != INF, "Invalid bound"); |
|
226 |
soplex->changeRange(i, lb != -INF ? lb : -soplex::infinity, soplex->rhs(i)); |
|
204 | 227 |
} |
205 |
void LpSoplex::_getRowBounds(int i, Value &lower, Value &upper) const { |
|
206 |
lower = soplex->lhs(i); |
|
207 |
if (lower == -soplex::infinity) lower = -INF; |
|
208 |
upper = soplex->rhs(i); |
|
209 |
|
|
228 |
|
|
229 |
LpSoplex::Value LpSoplex::_getRowLowerBound(int i) const { |
|
230 |
double res = soplex->lhs(i); |
|
231 |
return res == -soplex::infinity ? -INF : res; |
|
232 |
} |
|
233 |
|
|
234 |
void LpSoplex::_setRowUpperBound(int i, Value ub) { |
|
235 |
LEMON_ASSERT(ub != -INF, "Invalid bound"); |
|
236 |
soplex->changeRange(i, soplex->lhs(i), ub != INF ? ub : soplex::infinity); |
|
237 |
} |
|
238 |
|
|
239 |
LpSoplex::Value LpSoplex::_getRowUpperBound(int i) const { |
|
240 |
double res = soplex->rhs(i); |
|
241 |
return res == soplex::infinity ? INF : res; |
|
242 |
} |
|
243 |
|
|
244 |
void LpSoplex::_setObjCoeffs(ExprIterator b, ExprIterator e) { |
|
245 |
for (int j = 0; j < soplex->nCols(); ++j) { |
|
246 |
soplex->changeObj(j, 0.0); |
|
247 |
} |
|
248 |
for (ExprIterator it = b; it != e; ++it) { |
|
249 |
soplex->changeObj(it->first, it->second); |
|
250 |
} |
|
251 |
} |
|
252 |
|
|
253 |
void LpSoplex::_getObjCoeffs(InsertIterator b) const { |
|
254 |
for (int j = 0; j < soplex->nCols(); ++j) { |
|
255 |
Value coef = soplex->obj(j); |
|
256 |
if (coef != 0.0) { |
|
257 |
*b = std::make_pair(j, coef); |
|
258 |
++b; |
|
259 |
} |
|
260 |
} |
|
210 | 261 |
} |
211 | 262 |
|
212 | 263 |
void LpSoplex::_setObjCoeff(int i, Value obj_coef) { |
213 | 264 |
soplex->changeObj(i, obj_coef); |
214 |
solved = false; |
|
215 | 265 |
} |
216 | 266 |
|
... | ... |
@@ -219,25 +269,14 @@ |
219 | 269 |
} |
220 | 270 |
|
221 |
void LpSoplex::_clearObj() { |
|
222 |
for (int i = 0; i < soplex->nCols(); ++i) { |
|
223 |
soplex->changeObj(i, 0.0); |
|
224 |
} |
|
225 |
solved = false; |
|
226 |
} |
|
271 |
LpSoplex::SolveExitStatus LpSoplex::_solve() { |
|
227 | 272 |
|
228 |
|
|
273 |
_clear_temporals(); |
|
274 |
|
|
229 | 275 |
soplex::SPxSolver::Status status = soplex->solve(); |
230 | 276 |
|
231 |
soplex::Vector pv(primal_value.size(), &primal_value[0]); |
|
232 |
soplex->getPrimal(pv); |
|
233 |
|
|
234 |
soplex::Vector dv(dual_value.size(), &dual_value[0]); |
|
235 |
soplex->getDual(dv); |
|
236 |
|
|
237 | 277 |
switch (status) { |
238 | 278 |
case soplex::SPxSolver::OPTIMAL: |
239 | 279 |
case soplex::SPxSolver::INFEASIBLE: |
240 | 280 |
case soplex::SPxSolver::UNBOUNDED: |
241 |
solved = true; |
|
242 | 281 |
return SOLVED; |
243 | 282 |
default: |
... | ... |
@@ -247,9 +286,19 @@ |
247 | 286 |
|
248 | 287 |
LpSoplex::Value LpSoplex::_getPrimal(int i) const { |
249 |
|
|
288 |
if (_primal_values.empty()) { |
|
289 |
_primal_values.resize(soplex->nCols()); |
|
290 |
soplex::Vector pv(_primal_values.size(), &_primal_values.front()); |
|
291 |
soplex->getPrimal(pv); |
|
292 |
} |
|
293 |
return _primal_values[i]; |
|
250 | 294 |
} |
251 | 295 |
|
252 | 296 |
LpSoplex::Value LpSoplex::_getDual(int i) const { |
253 |
|
|
297 |
if (_dual_values.empty()) { |
|
298 |
_dual_values.resize(soplex->nRows()); |
|
299 |
soplex::Vector dv(_dual_values.size(), &_dual_values.front()); |
|
300 |
soplex->getDual(dv); |
|
301 |
} |
|
302 |
return _dual_values[i]; |
|
254 | 303 |
} |
255 | 304 |
|
... | ... |
@@ -258,15 +307,64 @@ |
258 | 307 |
} |
259 | 308 |
|
260 |
bool LpSoplex::_isBasicCol(int i) const { |
|
261 |
return soplex->getBasisColStatus(i) == soplex::SPxSolver::BASIC; |
|
309 |
LpSoplex::VarStatus LpSoplex::_getColStatus(int i) const { |
|
310 |
switch (soplex->getBasisColStatus(i)) { |
|
311 |
case soplex::SPxSolver::BASIC: |
|
312 |
return BASIC; |
|
313 |
case soplex::SPxSolver::ON_UPPER: |
|
314 |
return UPPER; |
|
315 |
case soplex::SPxSolver::ON_LOWER: |
|
316 |
return LOWER; |
|
317 |
case soplex::SPxSolver::FIXED: |
|
318 |
return FIXED; |
|
319 |
case soplex::SPxSolver::ZERO: |
|
320 |
return FREE; |
|
321 |
default: |
|
322 |
LEMON_ASSERT(false, "Wrong column status"); |
|
323 |
return VarStatus(); |
|
324 |
} |
|
262 | 325 |
} |
263 | 326 |
|
264 |
LpSoplex::SolutionStatus LpSoplex::_getPrimalStatus() const { |
|
265 |
if (!solved) return UNDEFINED; |
|
327 |
LpSoplex::VarStatus LpSoplex::_getRowStatus(int i) const { |
|
328 |
switch (soplex->getBasisRowStatus(i)) { |
|
329 |
case soplex::SPxSolver::BASIC: |
|
330 |
return BASIC; |
|
331 |
case soplex::SPxSolver::ON_UPPER: |
|
332 |
return UPPER; |
|
333 |
case soplex::SPxSolver::ON_LOWER: |
|
334 |
return LOWER; |
|
335 |
case soplex::SPxSolver::FIXED: |
|
336 |
return FIXED; |
|
337 |
case soplex::SPxSolver::ZERO: |
|
338 |
return FREE; |
|
339 |
default: |
|
340 |
LEMON_ASSERT(false, "Wrong row status"); |
|
341 |
return VarStatus(); |
|
342 |
} |
|
343 |
} |
|
344 |
|
|
345 |
LpSoplex::Value LpSoplex::_getPrimalRay(int i) const { |
|
346 |
if (_primal_ray.empty()) { |
|
347 |
_primal_ray.resize(soplex->nCols()); |
|
348 |
soplex::Vector pv(_primal_ray.size(), &_primal_ray.front()); |
|
349 |
soplex->getDualfarkas(pv); |
|
350 |
} |
|
351 |
return _primal_ray[i]; |
|
352 |
} |
|
353 |
|
|
354 |
LpSoplex::Value LpSoplex::_getDualRay(int i) const { |
|
355 |
if (_dual_ray.empty()) { |
|
356 |
_dual_ray.resize(soplex->nRows()); |
|
357 |
soplex::Vector dv(_dual_ray.size(), &_dual_ray.front()); |
|
358 |
soplex->getDualfarkas(dv); |
|
359 |
} |
|
360 |
return _dual_ray[i]; |
|
361 |
} |
|
362 |
|
|
363 |
LpSoplex::ProblemType LpSoplex::_getPrimalType() const { |
|
266 | 364 |
switch (soplex->status()) { |
267 | 365 |
case soplex::SPxSolver::OPTIMAL: |
268 | 366 |
return OPTIMAL; |
269 | 367 |
case soplex::SPxSolver::UNBOUNDED: |
270 |
return |
|
368 |
return UNBOUNDED; |
|
271 | 369 |
case soplex::SPxSolver::INFEASIBLE: |
272 | 370 |
return INFEASIBLE; |
... | ... |
@@ -276,10 +374,11 @@ |
276 | 374 |
} |
277 | 375 |
|
278 |
LpSoplex::SolutionStatus LpSoplex::_getDualStatus() const { |
|
279 |
if (!solved) return UNDEFINED; |
|
376 |
LpSoplex::ProblemType LpSoplex::_getDualType() const { |
|
280 | 377 |
switch (soplex->status()) { |
281 | 378 |
case soplex::SPxSolver::OPTIMAL: |
282 | 379 |
return OPTIMAL; |
283 | 380 |
case soplex::SPxSolver::UNBOUNDED: |
381 |
return UNBOUNDED; |
|
382 |
case soplex::SPxSolver::INFEASIBLE: |
|
284 | 383 |
return INFEASIBLE; |
285 | 384 |
default: |
... | ... |
@@ -288,28 +387,36 @@ |
288 | 387 |
} |
289 | 388 |
|
290 |
LpSoplex::ProblemTypes LpSoplex::_getProblemType() const { |
|
291 |
if (!solved) return UNKNOWN; |
|
292 |
switch (soplex->status()) { |
|
293 |
case soplex::SPxSolver::OPTIMAL: |
|
294 |
return PRIMAL_DUAL_FEASIBLE; |
|
295 |
case soplex::SPxSolver::UNBOUNDED: |
|
296 |
return PRIMAL_FEASIBLE_DUAL_INFEASIBLE; |
|
297 |
default: |
|
298 |
|
|
389 |
void LpSoplex::_setSense(Sense sense) { |
|
390 |
switch (sense) { |
|
391 |
case MIN: |
|
392 |
soplex->changeSense(soplex::SPxSolver::MINIMIZE); |
|
393 |
break; |
|
394 |
case MAX: |
|
395 |
soplex->changeSense(soplex::SPxSolver::MAXIMIZE); |
|
299 | 396 |
} |
300 | 397 |
} |
301 | 398 |
|
302 |
void LpSoplex::_setMax() { |
|
303 |
soplex->changeSense(soplex::SPxSolver::MAXIMIZE); |
|
304 |
solved = false; |
|
305 |
} |
|
306 |
void LpSoplex::_setMin() { |
|
307 |
soplex->changeSense(soplex::SPxSolver::MINIMIZE); |
|
308 |
solved = false; |
|
309 |
} |
|
310 |
bool LpSoplex::_isMax() const { |
|
311 |
return soplex->spxSense() == soplex::SPxSolver::MAXIMIZE; |
|
399 |
LpSoplex::Sense LpSoplex::_getSense() const { |
|
400 |
switch (soplex->spxSense()) { |
|
401 |
case soplex::SPxSolver::MAXIMIZE: |
|
402 |
return MAX; |
|
403 |
case soplex::SPxSolver::MINIMIZE: |
|
404 |
return MIN; |
|
405 |
default: |
|
406 |
LEMON_ASSERT(false, "Wrong sense."); |
|
407 |
return LpSoplex::Sense(); |
|
408 |
} |
|
312 | 409 |
} |
313 | 410 |
|
411 |
void LpSoplex::_clear() { |
|
412 |
soplex->clear(); |
|
413 |
_col_names.clear(); |
|
414 |
_col_names_ref.clear(); |
|
415 |
_row_names.clear(); |
|
416 |
_row_names_ref.clear(); |
|
417 |
cols.clear(); |
|
418 |
rows.clear(); |
|
419 |
_clear_temporals(); |
|
420 |
} |
|
314 | 421 |
|
315 | 422 |
} //namespace lemon |
... | ... |
@@ -44,24 +44,28 @@ |
44 | 44 |
/// Berlin (ZIB). You can find detailed information about it at the |
45 | 45 |
/// <tt>http://soplex.zib.de</tt> address. |
46 |
class LpSoplex :virtual public LpSolverBase { |
|
47 |
protected: |
|
48 |
|
|
49 |
_lp_bits::RelocateIdHandler relocateIdHandler; |
|
46 |
class LpSoplex : public LpSolver { |
|
47 |
private: |
|
50 | 48 |
|
51 | 49 |
soplex::SoPlex* soplex; |
52 |
bool solved; |
|
53 | 50 |
|
54 |
std::vector<std::string> colNames; |
|
55 |
std::map<std::string, int> invColNames; |
|
51 |
std::vector<std::string> _col_names; |
|
52 |
std::map<std::string, int> _col_names_ref; |
|
56 | 53 |
|
57 |
std::vector<Value> primal_value; |
|
58 |
std::vector<Value> dual_value; |
|
54 |
std::vector<std::string> _row_names; |
|
55 |
std::map<std::string, int> _row_names_ref; |
|
59 | 56 |
|
57 |
private: |
|
58 |
|
|
59 |
// these values cannot be retrieved element by element |
|
60 |
mutable std::vector<Value> _primal_values; |
|
61 |
mutable std::vector<Value> _dual_values; |
|
62 |
|
|
63 |
mutable std::vector<Value> _primal_ray; |
|
64 |
mutable std::vector<Value> _dual_ray; |
|
65 |
|
|
66 |
void _clear_temporals(); |
|
60 | 67 |
|
61 | 68 |
public: |
62 | 69 |
|
63 |
typedef LpSolverBase Parent; |
|
64 |
|
|
65 |
|
|
66 | 70 |
/// \e |
67 | 71 |
LpSoplex(); |
... | ... |
@@ -73,46 +77,73 @@ |
73 | 77 |
protected: |
74 | 78 |
|
75 |
virtual LpSolverBase* _newLp(); |
|
76 |
virtual LpSolverBase* _copyLp(); |
|
79 |
virtual LpSoplex* _newSolver() const; |
|
80 |
virtual LpSoplex* _cloneSolver() const; |
|
81 |
|
|
82 |
virtual const char* _solverName() const; |
|
77 | 83 |
|
78 | 84 |
virtual int _addCol(); |
79 | 85 |
virtual int _addRow(); |
86 |
|
|
80 | 87 |
virtual void _eraseCol(int i); |
81 | 88 |
virtual void _eraseRow(int i); |
82 |
virtual void _getColName(int col, std::string & name) const; |
|
83 |
virtual void _setColName(int col, const std::string & name); |
|
89 |
|
|
90 |
virtual void _eraseColId(int i); |
|
91 |
virtual void _eraseRowId(int i); |
|
92 |
|
|
93 |
virtual void _getColName(int col, std::string& name) const; |
|
94 |
virtual void _setColName(int col, const std::string& name); |
|
84 | 95 |
virtual int _colByName(const std::string& name) const; |
85 |
virtual void _setRowCoeffs(int i, ConstRowIterator b, ConstRowIterator e); |
|
86 |
virtual void _getRowCoeffs(int i, RowIterator b) const; |
|
87 |
virtual void _setColCoeffs(int i, ConstColIterator b, ConstColIterator e); |
|
88 |
virtual void _getColCoeffs(int i, ColIterator b) const; |
|
96 |
|
|
97 |
virtual void _getRowName(int row, std::string& name) const; |
|
98 |
virtual void _setRowName(int row, const std::string& name); |
|
99 |
virtual int _rowByName(const std::string& name) const; |
|
100 |
|
|
101 |
virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); |
|
102 |
virtual void _getRowCoeffs(int i, InsertIterator b) const; |
|
103 |
|
|
104 |
virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); |
|
105 |
virtual void _getColCoeffs(int i, InsertIterator b) const; |
|
106 |
|
|
89 | 107 |
virtual void _setCoeff(int row, int col, Value value); |
90 | 108 |
virtual Value _getCoeff(int row, int col) const; |
109 |
|
|
91 | 110 |
virtual void _setColLowerBound(int i, Value value); |
92 | 111 |
virtual Value _getColLowerBound(int i) const; |
93 | 112 |
virtual void _setColUpperBound(int i, Value value); |
94 | 113 |
virtual Value _getColUpperBound(int i) const; |
95 |
virtual void _setRowBounds(int i, Value lower, Value upper); |
|
96 |
virtual void _getRowBounds(int i, Value &lower, Value &upper) const; |
|
114 |
|
|
115 |
virtual void _setRowLowerBound(int i, Value value); |
|
116 |
virtual Value _getRowLowerBound(int i) const; |
|
117 |
virtual void _setRowUpperBound(int i, Value value); |
|
118 |
virtual Value _getRowUpperBound(int i) const; |
|
119 |
|
|
120 |
virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); |
|
121 |
virtual void _getObjCoeffs(InsertIterator b) const; |
|
122 |
|
|
97 | 123 |
virtual void _setObjCoeff(int i, Value obj_coef); |
98 | 124 |
virtual Value _getObjCoeff(int i) const; |
99 |
|
|
125 |
|
|
126 |
virtual void _setSense(Sense sense); |
|
127 |
virtual Sense _getSense() const; |
|
100 | 128 |
|
101 | 129 |
virtual SolveExitStatus _solve(); |
102 | 130 |
virtual Value _getPrimal(int i) const; |
103 | 131 |
virtual Value _getDual(int i) const; |
132 |
|
|
104 | 133 |
virtual Value _getPrimalValue() const; |
105 |
virtual bool _isBasicCol(int i) const; |
|
106 | 134 |
|
107 |
virtual SolutionStatus _getPrimalStatus() const; |
|
108 |
virtual SolutionStatus _getDualStatus() const; |
|
109 |
virtual |
|
135 |
virtual Value _getPrimalRay(int i) const; |
|
136 |
virtual Value _getDualRay(int i) const; |
|
110 | 137 |
|
138 |
virtual VarStatus _getColStatus(int i) const; |
|
139 |
virtual VarStatus _getRowStatus(int i) const; |
|
111 | 140 |
|
112 |
virtual void _setMax(); |
|
113 |
virtual void _setMin(); |
|
114 |
virtual |
|
141 |
virtual ProblemType _getPrimalType() const; |
|
142 |
virtual ProblemType _getDualType() const; |
|
143 |
|
|
144 |
virtual void _clear(); |
|
115 | 145 |
|
116 | 146 |
}; |
147 |
|
|
117 | 148 |
} //END OF NAMESPACE LEMON |
118 | 149 |
1 |
/* -*- mode: C++; indent-tabs-mode: nil; -*- |
|
2 |
* |
|
3 |
* This file is a part of LEMON, a generic C++ optimization library. |
|
4 |
* |
|
5 |
* Copyright (C) 2003-2008 |
|
6 |
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
|
7 |
* (Egervary Research Group on Combinatorial Optimization, EGRES). |
|
8 |
* |
|
9 |
* Permission to use, modify and distribute this software is granted |
|
10 |
* provided that this copyright notice appears in all copies. For |
|
11 |
* precise terms see the accompanying LICENSE file. |
|
12 |
* |
|
13 |
* This software is provided "AS IS" with no warranty of any kind, |
|
14 |
* express or implied, and with no claim as to its suitability for any |
|
15 |
* purpose. |
|
16 |
* |
|
17 |
*/ |
|
18 |
|
|
19 |
#ifndef LEMON_BITS_LP_SOLVER_ID_H |
|
20 |
#define LEMON_BITS_LP_SOLVER_ID_H |
|
21 |
|
|
22 |
namespace lemon { |
|
23 |
|
|
24 |
namespace _lp_bits { |
|
25 |
|
|
26 |
struct LpIdImpl { |
|
27 |
std::vector<int> index; |
|
28 |
std::vector<int> cross; |
|
29 |
int first_index; |
|
30 |
int first_free; |
|
31 |
}; |
|
32 |
|
|
33 |
class LpId { |
|
34 |
public: |
|
35 |
|
|
36 |
class IdHandler { |
|
37 |
public: |
|
38 |
virtual ~IdHandler() {} |
|
39 |
virtual int addId(LpIdImpl&) = 0; |
|
40 |
virtual void eraseId(LpIdImpl&, int xn) = 0; |
|
41 |
}; |
|
42 |
|
|
43 |
LpId(int min_index = 0) { |
|
44 |
id_handler = 0; |
|
45 |
impl.first_free = -1; |
|
46 |
impl.first_index = min_index; |
|
47 |
impl.cross.resize(impl.first_index); |
|
48 |
} |
|
49 |
|
|
50 |
LpId(const LpId& li) { |
|
51 |
id_handler = 0; |
|
52 |
impl = li.impl; |
|
53 |
} |
|
54 |
|
|
55 |
LpId& operator=(const LpId& li) { |
|
56 |
id_handler = 0; |
|
57 |
impl = li.impl; |
|
58 |
return *this; |
|
59 |
} |
|
60 |
|
|
61 |
void setIdHandler(IdHandler& ih) { |
|
62 |
id_handler = &ih; |
|
63 |
} |
|
64 |
|
|
65 |
int fixId(int fn) const {return impl.cross[fn];} |
|
66 |
int floatingId(int xn) const {return impl.index[xn];} |
|
67 |
|
|
68 |
int addId() { |
|
69 |
if (id_handler == 0) { |
|
70 |
int xn, fn = impl.cross.size(); |
|
71 |
if (impl.first_free == -1) { |
|
72 |
xn = impl.index.size(); |
|
73 |
impl.index.push_back(fn); |
|
74 |
} else { |
|
75 |
xn = impl.first_free; |
|
76 |
impl.first_free = impl.index[impl.first_free]; |
|
77 |
impl.index[xn] = fn; |
|
78 |
} |
|
79 |
impl.cross.push_back(xn); |
|
80 |
return xn; |
|
81 |
} else { |
|
82 |
return id_handler->addId(impl); |
|
83 |
} |
|
84 |
} |
|
85 |
|
|
86 |
void eraseId(int xn) { |
|
87 |
if (id_handler == 0) { |
|
88 |
int fn = impl.index[xn]; |
|
89 |
impl.index[xn] = impl.first_free; |
|
90 |
impl.first_free = xn; |
|
91 |
for(int i = fn + 1; i < int(impl.cross.size()); ++i) { |
|
92 |
impl.cross[i - 1] = impl.cross[i]; |
|
93 |
impl.index[impl.cross[i]]--; |
|
94 |
} |
|
95 |
impl.cross.pop_back(); |
|
96 |
} else { |
|
97 |
id_handler->eraseId(impl, xn); |
|
98 |
} |
|
99 |
} |
|
100 |
|
|
101 |
void firstFloating(int& fn) const { |
|
102 |
fn = impl.first_index; |
|
103 |
if (fn == int(impl.cross.size())) fn = -1; |
|
104 |
} |
|
105 |
|
|
106 |
void nextFloating(int& fn) const { |
|
107 |
++fn; |
|
108 |
if (fn == int(impl.cross.size())) fn = -1; |
|
109 |
} |
|
110 |
|
|
111 |
void firstFix(int& xn) const { |
|
112 |
int fn; |
|
113 |
firstFloating(fn); |
|
114 |
xn = fn != -1 ? fixId(fn) : -1; |
|
115 |
} |
|
116 |
|
|
117 |
void nextFix(int& xn) const { |
|
118 |
int fn = floatingId(xn); |
|
119 |
nextFloating(fn); |
|
120 |
xn = fn != -1 ? fixId(fn) : -1; |
|
121 |
} |
|
122 |
|
|
123 |
protected: |
|
124 |
LpIdImpl impl; |
|
125 |
IdHandler *id_handler; |
|
126 |
}; |
|
127 |
|
|
128 |
class RelocateIdHandler : public LpId::IdHandler { |
|
129 |
public: |
|
130 |
|
|
131 |
virtual int addId(LpIdImpl& impl) { |
|
132 |
int xn, fn = impl.cross.size(); |
|
133 |
if (impl.first_free == -1) { |
|
134 |
xn = impl.index.size(); |
|
135 |
impl.index.push_back(fn); |
|
136 |
} else { |
|
137 |
xn = impl.first_free; |
|
138 |
impl.first_free = impl.index[impl.first_free]; |
|
139 |
impl.index[xn] = fn; |
|
140 |
} |
|
141 |
impl.cross.push_back(xn); |
|
142 |
return xn; |
|
143 |
} |
|
144 |
|
|
145 |
virtual void eraseId(LpIdImpl& impl, int xn) { |
|
146 |
int fn = impl.index[xn]; |
|
147 |
impl.index[xn] = impl.first_free; |
|
148 |
impl.first_free = xn; |
|
149 |
impl.cross[fn] = impl.cross.back(); |
|
150 |
impl.index[impl.cross.back()] = fn; |
|
151 |
impl.cross.pop_back(); |
|
152 |
} |
|
153 |
}; |
|
154 |
} |
|
155 |
} |
|
156 |
|
|
157 |
#endif |
1 |
/* -*- mode: C++; indent-tabs-mode: nil; -*- |
|
2 |
* |
|
3 |
* This file is a part of LEMON, a generic C++ optimization library. |
|
4 |
* |
|
5 |
* Copyright (C) 2003-2008 |
|
6 |
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
|
7 |
* (Egervary Research Group on Combinatorial Optimization, EGRES). |
|
8 |
* |
|
9 |
* Permission to use, modify and distribute this software is granted |
|
10 |
* provided that this copyright notice appears in all copies. For |
|
11 |
* precise terms see the accompanying LICENSE file. |
|
12 |
* |
|
13 |
* This software is provided "AS IS" with no warranty of any kind, |
|
14 |
* express or implied, and with no claim as to its suitability for any |
|
15 |
* purpose. |
|
16 |
* |
|
17 |
*/ |
|
18 |
|
|
19 |
///\file |
|
20 |
///\brief Implementation of the LEMON-CPLEX mip solver interface. |
|
21 |
|
|
22 |
#include <lemon/mip_cplex.h> |
|
23 |
|
|
24 |
extern "C" { |
|
25 |
#include <ilcplex/cplex.h> |
|
26 |
} |
|
27 |
|
|
28 |
namespace lemon { |
|
29 |
|
|
30 |
MipCplex::MipCplex() { |
|
31 |
//This is unnecessary: setting integrality constraints on |
|
32 |
//variables will set this, too |
|
33 |
|
|
34 |
///\todo The constant CPXPROB_MIP is |
|
35 |
///called CPXPROB_MILP in later versions |
|
36 |
#if CPX_VERSION < 800 |
|
37 |
CPXchgprobtype( env, lp, CPXPROB_MIP); |
|
38 |
#else |
|
39 |
CPXchgprobtype( env, lp, CPXPROB_MILP); |
|
40 |
#endif |
|
41 |
|
|
42 |
} |
|
43 |
|
|
44 |
void MipCplex::_colType(int i, MipCplex::ColTypes col_type){ |
|
45 |
|
|
46 |
// Note If a variable is to be changed to binary, a call to CPXchgbds |
|
47 |
// should also be made to change the bounds to 0 and 1. |
|
48 |
|
|
49 |
int indices[1]; |
|
50 |
indices[0]=i; |
|
51 |
char ctype[1]; |
|
52 |
switch (col_type){ |
|
53 |
case INT: |
|
54 |
ctype[0]=CPX_INTEGER;//'I' |
|
55 |
break; |
|
56 |
case REAL: |
|
57 |
ctype[0]=CPX_CONTINUOUS ;//'C' |
|
58 |
break; |
|
59 |
default:; |
|
60 |
//FIXME problem |
|
61 |
} |
|
62 |
CPXchgctype (env, lp, 1, indices, ctype); |
|
63 |
} |
|
64 |
|
|
65 |
MipCplex::ColTypes MipCplex::_colType(int i) const { |
|
66 |
|
|
67 |
char ctype[1]; |
|
68 |
CPXgetctype (env, lp, ctype, i, i); |
|
69 |
switch (ctype[0]){ |
|
70 |
|
|
71 |
case CPX_INTEGER: |
|
72 |
return INT; |
|
73 |
case CPX_CONTINUOUS: |
|
74 |
return REAL; |
|
75 |
default: |
|
76 |
return REAL;//Error! |
|
77 |
} |
|
78 |
|
|
79 |
} |
|
80 |
|
|
81 |
LpCplex::SolveExitStatus MipCplex::_solve(){ |
|
82 |
|
|
83 |
status = CPXmipopt (env, lp); |
|
84 |
if (status==0) |
|
85 |
return SOLVED; |
|
86 |
else |
|
87 |
return UNSOLVED; |
|
88 |
|
|
89 |
} |
|
90 |
|
|
91 |
|
|
92 |
LpCplex::SolutionStatus MipCplex::_getMipStatus() const { |
|
93 |
|
|
94 |
int stat = CPXgetstat(env, lp); |
|
95 |
|
|
96 |
//Fortunately, MIP statuses did not change for cplex 8.0 |
|
97 |
switch (stat) |
|
98 |
{ |
|
99 |
case CPXMIP_OPTIMAL: |
|
100 |
// Optimal integer solution has been found. |
|
101 |
case CPXMIP_OPTIMAL_TOL: |
|
102 |
// Optimal soluton with the tolerance defined by epgap or epagap has |
|
103 |
// been found. |
|
104 |
return OPTIMAL; |
|
105 |
//This also exists in later issues |
|
106 |
// case CPXMIP_UNBOUNDED: |
|
107 |
//return INFINITE; |
|
108 |
case CPXMIP_INFEASIBLE: |
|
109 |
return INFEASIBLE; |
|
110 |
default: |
|
111 |
return UNDEFINED; |
|
112 |
} |
|
113 |
//Unboundedness not treated well: the following is from cplex 9.0 doc |
|
114 |
// About Unboundedness |
|
115 |
|
|
116 |
// The treatment of models that are unbounded involves a few |
|
117 |
// subtleties. Specifically, a declaration of unboundedness means that |
|
118 |
// ILOG CPLEX has determined that the model has an unbounded |
|
119 |
// ray. Given any feasible solution x with objective z, a multiple of |
|
120 |
// the unbounded ray can be added to x to give a feasible solution |
|
121 |
// with objective z-1 (or z+1 for maximization models). Thus, if a |
|
122 |
// feasible solution exists, then the optimal objective is |
|
123 |
// unbounded. Note that ILOG CPLEX has not necessarily concluded that |
|
124 |
// a feasible solution exists. Users can call the routine CPXsolninfo |
|
125 |
// to determine whether ILOG CPLEX has also concluded that the model |
|
126 |
// has a feasible solution. |
|
127 |
|
|
128 |
} |
|
129 |
|
|
130 |
MipCplex::Value MipCplex::_getPrimal(int i) const { |
|
131 |
Value x; |
|
132 |
CPXgetmipx(env, lp, &x, i, i); |
|
133 |
return x; |
|
134 |
} |
|
135 |
|
|
136 |
MipCplex::Value MipCplex::_getPrimalValue() const { |
|
137 |
Value objval; |
|
138 |
CPXgetmipobjval(env, lp, &objval); |
|
139 |
return objval; |
|
140 |
} |
|
141 |
} //END OF NAMESPACE LEMON |
1 |
/* -*- mode: C++; indent-tabs-mode: nil; -*- |
|
2 |
* |
|
3 |
* This file is a part of LEMON, a generic C++ optimization library. |
|
4 |
* |
|
5 |
* Copyright (C) 2003-2008 |
|
6 |
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
|
7 |
* (Egervary Research Group on Combinatorial Optimization, EGRES). |
|
8 |
* |
|
9 |
* Permission to use, modify and distribute this software is granted |
|
10 |
* provided that this copyright notice appears in all copies. For |
|
11 |
* precise terms see the accompanying LICENSE file. |
|
12 |
* |
|
13 |
* This software is provided "AS IS" with no warranty of any kind, |
|
14 |
* express or implied, and with no claim as to its suitability for any |
|
15 |
* purpose. |
|
16 |
* |
|
17 |
*/ |
|
18 |
|
|
19 |
#ifndef LEMON_MIP_CPLEX_H |
|
20 |
#define LEMON_MIP_CPLEX_H |
|
21 |
|
|
22 |
///\file |
|
23 |
///\brief Header of the LEMON-CPLEX mip solver interface. |
|
24 |
///\ingroup lp_group |
|
25 |
|
|
26 |
|
|
27 |
#include <lemon/lp_cplex.h> |
|
28 |
|
|
29 |
namespace lemon { |
|
30 |
|
|
31 |
/// \brief Interface for the CPLEX MIP solver |
|
32 |
/// |
|
33 |
/// This class implements an interface for the CPLEX MIP solver. |
|
34 |
///\ingroup lp_group |
|
35 |
class MipCplex : public MipSolverBase, public LpCplex{ |
|
36 |
|
|
37 |
public: |
|
38 |
|
|
39 |
typedef MipSolverBase ParentMip; |
|
40 |
typedef LpCplex ParentLp; |
|
41 |
|
|
42 |
MipCplex(); |
|
43 |
//~MipCplex(); |
|
44 |
|
|
45 |
|
|
46 |
|
|
47 |
|
|
48 |
protected: |
|
49 |
|
|
50 |
virtual ColTypes _colType(int col) const; |
|
51 |
virtual void _colType(int col, ColTypes col_type); |
|
52 |
|
|
53 |
virtual LpCplex::SolveExitStatus _solve(); |
|
54 |
virtual LpCplex::SolutionStatus _getMipStatus() const; |
|
55 |
virtual ParentLp::Value _getPrimal(int i) const; |
|
56 |
virtual ParentLp::Value _getPrimalValue() const; |
|
57 |
}; |
|
58 |
|
|
59 |
} //END OF NAMESPACE LEMON |
|
60 |
|
|
61 |
#endif // END OF LEMON_MIP_CPLEX_H |
1 |
/* -*- mode: C++; indent-tabs-mode: nil; -*- |
|
2 |
* |
|
3 |
* This file is a part of LEMON, a generic C++ optimization library. |
|
4 |
* |
|
5 |
* Copyright (C) 2003-2008 |
|
6 |
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
|
7 |
* (Egervary Research Group on Combinatorial Optimization, EGRES). |
|
8 |
* |
|
9 |
* Permission to use, modify and distribute this software is granted |
|
10 |
* provided that this copyright notice appears in all copies. For |
|
11 |
* precise terms see the accompanying LICENSE file. |
|
12 |
* |
|
13 |
* This software is provided "AS IS" with no warranty of any kind, |
|
14 |
* express or implied, and with no claim as to its suitability for any |
|
15 |
* purpose. |
|
16 |
* |
|
17 |
*/ |
|
18 |
|
|
19 |
///\file |
|
20 |
///\brief Implementation of the LEMON-GLPK mip solver interface. |
|
21 |
|
|
22 |
#include <lemon/mip_glpk.h> |
|
23 |
|
|
24 |
extern "C" { |
|
25 |
#include <glpk.h> |
|
26 |
} |
|
27 |
|
|
28 |
#if GLP_MAJOR_VERSION > 4 || (GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION > 15) |
|
29 |
#define LEMON_glp(func) (glp_##func) |
|
30 |
#define LEMON_lpx(func) (lpx_##func) |
|
31 |
|
|
32 |
#define LEMON_GLP(def) (GLP_##def) |
|
33 |
#define LEMON_LPX(def) (LPX_##def) |
|
34 |
|
|
35 |
#else |
|
36 |
|
|
37 |
#define LEMON_glp(func) (lpx_##func) |
|
38 |
#define LEMON_lpx(func) (lpx_##func) |
|
39 |
|
|
40 |
#define LEMON_GLP(def) (LPX_##def) |
|
41 |
#define LEMON_LPX(def) (LPX_##def) |
|
42 |
|
|
43 |
#endif |
|
44 |
|
|
45 |
namespace lemon { |
|
46 |
|
|
47 |
MipGlpk::MipGlpk() { |
|
48 |
#if !(GLP_MAJOR_VERSION > 4 || \ |
|
49 |
(GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION > 15)) |
|
50 |
LEMON_lpx(set_class)(lp,LEMON_GLP(MIP)); |
|
51 |
#endif |
|
52 |
} |
|
53 |
|
|
54 |
void MipGlpk::_colType(int i, MipGlpk::ColTypes col_type){ |
|
55 |
switch (col_type){ |
|
56 |
case INT: |
|
57 |
LEMON_glp(set_col_kind)(lp,i,LEMON_GLP(IV)); |
|
58 |
break; |
|
59 |
case REAL: |
|
60 |
LEMON_glp(set_col_kind)(lp,i,LEMON_GLP(CV)); |
|
61 |
break; |
|
62 |
default:; |
|
63 |
//FIXME problem |
|
64 |
} |
|
65 |
} |
|
66 |
|
|
67 |
MipGlpk::ColTypes MipGlpk::_colType(int i) const { |
|
68 |
switch (LEMON_glp(get_col_kind)(lp,i)){ |
|
69 |
case LEMON_GLP(IV): |
|
70 |
return INT;//Or binary |
|
71 |
case LEMON_GLP(CV): |
|
72 |
return REAL; |
|
73 |
default: |
|
74 |
return REAL;//Error! |
|
75 |
} |
|
76 |
|
|
77 |
} |
|
78 |
|
|
79 |
LpGlpk::SolveExitStatus MipGlpk::_solve() { |
|
80 |
int result = LEMON_lpx(simplex)(lp); |
|
81 |
|
|
82 |
// hack: mip does not contain integer variable |
|
83 |
#if GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION == 16 |
|
84 |
int tmp = -1; |
|
85 |
if (LEMON_glp(get_num_int(lp)) == 0) { |
|
86 |
tmp = LEMON_lpx(add_cols)(lp, 1); |
|
87 |
LEMON_glp(set_col_bnds)(lp, tmp, LEMON_GLP(FX), 0.0, 0.0); |
|
88 |
LEMON_glp(set_col_kind)(lp, tmp, LEMON_GLP(IV)); |
|
89 |
} |
|
90 |
#endif |
|
91 |
|
|
92 |
if (LEMON_lpx(get_status)(lp)==LEMON_LPX(OPT)) { |
|
93 |
//Maybe we could try the routine lpx_intopt(lp), a revised |
|
94 |
//version of lpx_integer |
|
95 |
|
|
96 |
result = LEMON_lpx(integer)(lp); |
|
97 |
switch (result){ |
|
98 |
case LEMON_LPX(E_OK): |
|
99 |
solved = true; |
|
100 |
break; |
|
101 |
default: |
|
102 |
solved = false; |
|
103 |
} |
|
104 |
} else { |
|
105 |
solved = false; |
|
106 |
} |
|
107 |
#if GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION == 16 |
|
108 |
if (tmp != -1) { |
|
109 |
int tmpa[2]; |
|
110 |
tmpa[1] = tmp; |
|
111 |
LEMON_lpx(del_cols)(lp, 1, tmpa); |
|
112 |
} |
|
113 |
#endif |
|
114 |
return solved ? SOLVED : UNSOLVED; |
|
115 |
} |
|
116 |
|
|
117 |
|
|
118 |
LpGlpk::SolutionStatus MipGlpk::_getMipStatus() const { |
|
119 |
|
|
120 |
if (LEMON_lpx(get_status)(lp)==LEMON_LPX(OPT)){ |
|
121 |
//Meg kell nezni: ha az LP is infinite, akkor ez is, ha az is |
|
122 |
//infeasible, akkor ez is, de ez lehet maskepp is infeasible. |
|
123 |
int stat= LEMON_lpx(mip_status)(lp); |
|
124 |
|
|
125 |
switch (stat) { |
|
126 |
case LEMON_LPX(I_UNDEF)://Undefined (no solve has been run yet) |
|
127 |
return UNDEFINED; |
|
128 |
case LEMON_LPX(I_NOFEAS)://There is no feasible integral solution |
|
129 |
return INFEASIBLE; |
|
130 |
// case LEMON_LPX(UNBND)://Unbounded |
|
131 |
// return INFINITE; |
|
132 |
case LEMON_LPX(I_FEAS)://Feasible |
|
133 |
return FEASIBLE; |
|
134 |
case LEMON_LPX(I_OPT)://Feasible |
|
135 |
return OPTIMAL; |
|
136 |
default: |
|
137 |
return UNDEFINED; //to avoid gcc warning |
|
138 |
//FIXME error |
|
139 |
} |
|
140 |
} |
|
141 |
else |
|
142 |
return UNDEFINED; //Maybe we could refine this: what does the LP |
|
143 |
//relaxation look like |
|
144 |
|
|
145 |
} |
|
146 |
|
|
147 |
MipGlpk::Value MipGlpk::_getPrimal(int i) const { |
|
148 |
return LEMON_glp(mip_col_val)(lp,i); |
|
149 |
} |
|
150 |
|
|
151 |
MipGlpk::Value MipGlpk::_getPrimalValue() const { |
|
152 |
return LEMON_glp(mip_obj_val)(lp); |
|
153 |
} |
|
154 |
} //END OF NAMESPACE LEMON |
1 |
/* -*- mode: C++; indent-tabs-mode: nil; -*- |
|
2 |
* |
|
3 |
* This file is a part of LEMON, a generic C++ optimization library. |
|
4 |
* |
|
5 |
* Copyright (C) 2003-2008 |
|
6 |
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport |
|
7 |
* (Egervary Research Group on Combinatorial Optimization, EGRES). |
|
8 |
* |
|
9 |
* Permission to use, modify and distribute this software is granted |
|
10 |
* provided that this copyright notice appears in all copies. For |
|
11 |
* precise terms see the accompanying LICENSE file. |
|
12 |
* |
|
13 |
* This software is provided "AS IS" with no warranty of any kind, |
|
14 |
* express or implied, and with no claim as to its suitability for any |
|
15 |
* purpose. |
|
16 |
* |
|
17 |
*/ |
|
18 |
|
|
19 |
#ifndef LEMON_MIP_GLPK_H |
|
20 |
#define LEMON_MIP_GLPK_H |
|
21 |
|
|
22 |
///\file |
|
23 |
///\brief Header of the LEMON-GLPK mip solver interface. |
|
24 |
///\ingroup lp_group |
|
25 |
|
|
26 |
|
|
27 |
#include <lemon/lp_glpk.h> |
|
28 |
|
|
29 |
namespace lemon { |
|
30 |
/// \brief Interface for the GLPK MIP solver |
|
31 |
/// |
|
32 |
/// This class implements an interface for the GLPK MIP solver. |
|
33 |
///\ingroup lp_group |
|
34 |
class MipGlpk : public MipSolverBase, public LpGlpk{ |
|
35 |
|
|
36 |
public: |
|
37 |
|
|
38 |
typedef MipSolverBase ParentMip; |
|
39 |
typedef LpGlpk ParentLp; |
|
40 |
|
|
41 |
MipGlpk(); |
|
42 |
//~MipGlpk(); |
|
43 |
|
|
44 |
|
|
45 |
|
|
46 |
protected: |
|
47 |
|
|
48 |
virtual ColTypes _colType(int col) const; |
|
49 |
virtual void _colType(int col, ColTypes col_type); |
|
50 |
|
|
51 |
virtual LpGlpk::SolveExitStatus _solve(); |
|
52 |
virtual LpGlpk::SolutionStatus _getMipStatus() const; |
|
53 |
virtual ParentLp::Value _getPrimal(int i) const; |
|
54 |
virtual ParentLp::Value _getPrimalValue() const; |
|
55 |
}; |
|
56 |
|
|
57 |
} //END OF NAMESPACE LEMON |
|
58 |
|
|
59 |
#endif // END OF LEMON_MIP_GLPK_H |
Changeset was too big and was cut off... Show full diff
0 comments (0 inline)