27 |
29 |
28 ///\file |
30 ///\file |
29 ///\brief Implementation of the LEMON-CPLEX lp solver interface. |
31 ///\brief Implementation of the LEMON-CPLEX lp solver interface. |
30 namespace lemon { |
32 namespace lemon { |
31 |
33 |
32 LpCplex::LpCplex() { |
34 CplexEnv::LicenseError::LicenseError(int status) { |
33 // env = CPXopenCPLEXdevelop(&status); |
35 if (!CPXgeterrorstring(0, status, _message)) { |
34 env = CPXopenCPLEX(&status); |
36 std::strcpy(_message, "Cplex unknown error"); |
35 lp = CPXcreateprob(env, &status, "LP problem"); |
37 } |
36 } |
38 } |
37 |
39 |
38 LpCplex::LpCplex(const LpCplex& cplex) : LpSolverBase() { |
40 CplexEnv::CplexEnv() { |
39 env = CPXopenCPLEX(&status); |
41 int status; |
40 lp = CPXcloneprob(env, cplex.lp, &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 rows = cplex.rows; |
87 rows = cplex.rows; |
42 cols = cplex.cols; |
88 cols = cplex.cols; |
43 } |
89 } |
44 |
90 |
45 LpCplex::~LpCplex() { |
91 CplexBase::~CplexBase() { |
46 CPXfreeprob(env,&lp); |
92 CPXfreeprob(cplexEnv(),&_prob); |
47 CPXcloseCPLEX(&env); |
93 } |
48 } |
94 |
49 |
95 int CplexBase::_addCol() { |
50 LpSolverBase* LpCplex::_newLp() |
96 int i = CPXgetnumcols(cplexEnv(), _prob); |
51 { |
97 double lb = -INF, ub = INF; |
52 //The first approach opens a new environment |
98 CPXnewcols(cplexEnv(), _prob, 1, 0, &lb, &ub, 0, 0); |
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 status = CPXnewcols(env, lp, 1, NULL, lb, ub, NULL, NULL); |
|
67 return i; |
99 return i; |
68 } |
100 } |
69 |
101 |
70 |
102 |
71 int LpCplex::_addRow() |
103 int CplexBase::_addRow() { |
72 { |
104 int i = CPXgetnumrows(cplexEnv(), _prob); |
73 //We want a row that is not constrained |
105 const double ub = INF; |
74 char sense[1]; |
106 const char s = 'L'; |
75 sense[0]='L';//<= constraint |
107 CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0); |
76 Value rhs[1]; |
|
77 rhs[0]=INF; |
|
78 int i = CPXgetnumrows(env, lp); |
|
79 status = CPXnewrows(env, lp, 1, rhs, sense, NULL, NULL); |
|
80 return i; |
108 return i; |
81 } |
109 } |
82 |
110 |
83 |
111 |
84 void LpCplex::_eraseCol(int i) { |
112 void CplexBase::_eraseCol(int i) { |
85 CPXdelcols(env, lp, i, i); |
113 CPXdelcols(cplexEnv(), _prob, i, i); |
86 } |
114 } |
87 |
115 |
88 void LpCplex::_eraseRow(int i) { |
116 void CplexBase::_eraseRow(int i) { |
89 CPXdelrows(env, lp, i, i); |
117 CPXdelrows(cplexEnv(), _prob, i, i); |
90 } |
118 } |
91 |
119 |
92 void LpCplex::_getColName(int col, std::string &name) const |
120 void CplexBase::_eraseColId(int i) { |
93 { |
121 cols.eraseIndex(i); |
94 ///\bug Untested |
122 cols.shiftIndices(i); |
95 int storespace; |
123 } |
96 CPXgetcolname(env, lp, 0, 0, 0, &storespace, col, col); |
124 void CplexBase::_eraseRowId(int i) { |
97 if (storespace == 0) { |
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 name.clear(); |
133 name.clear(); |
99 return; |
134 return; |
100 } |
135 } |
101 |
136 |
102 storespace *= -1; |
137 size *= -1; |
103 std::vector<char> buf(storespace); |
138 std::vector<char> buf(size); |
104 char *names[1]; |
139 char *cname; |
105 int dontcare; |
140 int tmp; |
106 ///\bug return code unchecked for error |
141 CPXgetcolname(cplexEnv(), _prob, &cname, &buf.front(), size, |
107 CPXgetcolname(env, lp, names, &*buf.begin(), storespace, |
142 &tmp, col, col); |
108 &dontcare, col, col); |
143 name = cname; |
109 name = names[0]; |
144 } |
110 } |
145 |
111 |
146 void CplexBase::_setColName(int col, const std::string &name) { |
112 void LpCplex::_setColName(int col, const std::string &name) |
147 char *cname; |
113 { |
148 cname = const_cast<char*>(name.c_str()); |
114 ///\bug Untested |
149 CPXchgcolname(cplexEnv(), _prob, 1, &col, &cname); |
115 char *names[1]; |
150 } |
116 names[0] = const_cast<char*>(name.c_str()); |
151 |
117 ///\bug return code unchecked for error |
152 int CplexBase::_colByName(const std::string& name) const { |
118 CPXchgcolname(env, lp, 1, &col, names); |
|
119 } |
|
120 |
|
121 int LpCplex::_colByName(const std::string& name) const |
|
122 { |
|
123 int index; |
153 int index; |
124 if (CPXgetcolindex(env, lp, |
154 if (CPXgetcolindex(cplexEnv(), _prob, |
125 const_cast<char*>(name.c_str()), &index) == 0) { |
155 const_cast<char*>(name.c_str()), &index) == 0) { |
126 return index; |
156 return index; |
127 } |
157 } |
128 return -1; |
158 return -1; |
129 } |
159 } |
130 |
160 |
131 ///\warning Data at index 0 is ignored in the arrays. |
161 void CplexBase::_getRowName(int row, std::string &name) const { |
132 void LpCplex::_setRowCoeffs(int i, ConstRowIterator b, ConstRowIterator e) |
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 std::vector<int> indices; |
196 std::vector<int> indices; |
135 std::vector<int> rowlist; |
197 std::vector<int> rowlist; |
136 std::vector<Value> values; |
198 std::vector<Value> values; |
137 |
199 |
138 for(ConstRowIterator it=b; it!=e; ++it) { |
200 for(ExprIterator it=b; it!=e; ++it) { |
139 indices.push_back(it->first); |
201 indices.push_back(it->first); |
140 values.push_back(it->second); |
202 values.push_back(it->second); |
141 rowlist.push_back(i); |
203 rowlist.push_back(i); |
142 } |
204 } |
143 |
205 |
144 status = CPXchgcoeflist(env, lp, values.size(), |
206 CPXchgcoeflist(cplexEnv(), _prob, values.size(), |
145 &rowlist[0], &indices[0], &values[0]); |
207 &rowlist.front(), &indices.front(), &values.front()); |
146 } |
208 } |
147 |
209 |
148 void LpCplex::_getRowCoeffs(int i, RowIterator b) const { |
210 void CplexBase::_getRowCoeffs(int i, InsertIterator b) const { |
149 int tmp1, tmp2, tmp3, length; |
211 int tmp1, tmp2, tmp3, length; |
150 CPXgetrows(env, lp, &tmp1, &tmp2, 0, 0, 0, &length, i, i); |
212 CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i); |
151 |
213 |
152 length = -length; |
214 length = -length; |
153 std::vector<int> indices(length); |
215 std::vector<int> indices(length); |
154 std::vector<double> values(length); |
216 std::vector<double> values(length); |
155 |
217 |
156 CPXgetrows(env, lp, &tmp1, &tmp2, &indices[0], &values[0], |
218 CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, |
|
219 &indices.front(), &values.front(), |
157 length, &tmp3, i, i); |
220 length, &tmp3, i, i); |
158 |
221 |
159 for (int i = 0; i < length; ++i) { |
222 for (int i = 0; i < length; ++i) { |
160 *b = std::make_pair(indices[i], values[i]); |
223 *b = std::make_pair(indices[i], values[i]); |
161 ++b; |
224 ++b; |
162 } |
225 } |
163 |
226 } |
164 /// \todo implement |
227 |
165 } |
228 void CplexBase::_setColCoeffs(int i, ExprIterator b, ExprIterator e) { |
166 |
|
167 void LpCplex::_setColCoeffs(int i, ConstColIterator b, ConstColIterator e) |
|
168 { |
|
169 std::vector<int> indices; |
229 std::vector<int> indices; |
170 std::vector<int> collist; |
230 std::vector<int> collist; |
171 std::vector<Value> values; |
231 std::vector<Value> values; |
172 |
232 |
173 for(ConstColIterator it=b; it!=e; ++it) { |
233 for(ExprIterator it=b; it!=e; ++it) { |
174 indices.push_back(it->first); |
234 indices.push_back(it->first); |
175 values.push_back(it->second); |
235 values.push_back(it->second); |
176 collist.push_back(i); |
236 collist.push_back(i); |
177 } |
237 } |
178 |
238 |
179 status = CPXchgcoeflist(env, lp, values.size(), |
239 CPXchgcoeflist(cplexEnv(), _prob, values.size(), |
180 &indices[0], &collist[0], &values[0]); |
240 &indices.front(), &collist.front(), &values.front()); |
181 } |
241 } |
182 |
242 |
183 void LpCplex::_getColCoeffs(int i, ColIterator b) const { |
243 void CplexBase::_getColCoeffs(int i, InsertIterator b) const { |
184 |
244 |
185 int tmp1, tmp2, tmp3, length; |
245 int tmp1, tmp2, tmp3, length; |
186 CPXgetcols(env, lp, &tmp1, &tmp2, 0, 0, 0, &length, i, i); |
246 CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i); |
187 |
247 |
188 length = -length; |
248 length = -length; |
189 std::vector<int> indices(length); |
249 std::vector<int> indices(length); |
190 std::vector<double> values(length); |
250 std::vector<double> values(length); |
191 |
251 |
192 CPXgetcols(env, lp, &tmp1, &tmp2, &indices[0], &values[0], |
252 CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, |
|
253 &indices.front(), &values.front(), |
193 length, &tmp3, i, i); |
254 length, &tmp3, i, i); |
194 |
255 |
195 for (int i = 0; i < length; ++i) { |
256 for (int i = 0; i < length; ++i) { |
196 *b = std::make_pair(indices[i], values[i]); |
257 *b = std::make_pair(indices[i], values[i]); |
197 ++b; |
258 ++b; |
198 } |
259 } |
199 |
260 |
200 } |
261 } |
201 |
262 |
202 void LpCplex::_setCoeff(int row, int col, Value value) |
263 void CplexBase::_setCoeff(int row, int col, Value value) { |
|
264 CPXchgcoef(cplexEnv(), _prob, row, col, value); |
|
265 } |
|
266 |
|
267 CplexBase::Value CplexBase::_getCoeff(int row, int col) const { |
|
268 CplexBase::Value value; |
|
269 CPXgetcoef(cplexEnv(), _prob, row, col, &value); |
|
270 return value; |
|
271 } |
|
272 |
|
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) |
203 { |
285 { |
204 CPXchgcoef(env, lp, row, col, value); |
286 const char s = 'U'; |
205 } |
287 CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value); |
206 |
288 } |
207 LpCplex::Value LpCplex::_getCoeff(int row, int col) const |
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) |
208 { |
359 { |
209 LpCplex::Value value; |
360 LEMON_ASSERT(lb != INF, "Invalid bound"); |
210 CPXgetcoef(env, lp, row, col, &value); |
361 _set_row_bounds(i, lb, CplexBase::_getRowUpperBound(i)); |
211 return value; |
362 } |
212 } |
363 |
213 |
364 void CplexBase::_setRowUpperBound(int i, Value ub) |
214 void LpCplex::_setColLowerBound(int i, Value value) |
|
215 { |
365 { |
216 int indices[1]; |
366 |
217 indices[0]=i; |
367 LEMON_ASSERT(ub != -INF, "Invalid bound"); |
218 char lu[1]; |
368 _set_row_bounds(i, CplexBase::_getRowLowerBound(i), ub); |
219 lu[0]='L'; |
369 } |
220 Value bd[1]; |
370 |
221 bd[0]=value; |
371 void CplexBase::_setObjCoeffs(ExprIterator b, ExprIterator e) |
222 status = CPXchgbds(env, lp, 1, indices, lu, bd); |
|
223 |
|
224 } |
|
225 |
|
226 LpCplex::Value LpCplex::_getColLowerBound(int i) const |
|
227 { |
372 { |
228 LpCplex::Value x; |
373 std::vector<int> indices; |
229 CPXgetlb (env, lp, &x, i, i); |
374 std::vector<Value> values; |
230 if (x <= -CPX_INFBOUND) x = -INF; |
375 for(ExprIterator it=b; it!=e; ++it) { |
231 return x; |
376 indices.push_back(it->first); |
232 } |
377 values.push_back(it->second); |
233 |
378 } |
234 void LpCplex::_setColUpperBound(int i, Value value) |
379 CPXchgobj(cplexEnv(), _prob, values.size(), |
|
380 &indices.front(), &values.front()); |
|
381 |
|
382 } |
|
383 |
|
384 void CplexBase::_getObjCoeffs(InsertIterator b) const |
235 { |
385 { |
236 int indices[1]; |
386 int num = CPXgetnumcols(cplexEnv(), _prob); |
237 indices[0]=i; |
387 std::vector<Value> x(num); |
238 char lu[1]; |
388 |
239 lu[0]='U'; |
389 CPXgetobj(cplexEnv(), _prob, &x.front(), 0, num - 1); |
240 Value bd[1]; |
390 for (int i = 0; i < num; ++i) { |
241 bd[0]=value; |
391 if (x[i] != 0.0) { |
242 status = CPXchgbds(env, lp, 1, indices, lu, bd); |
392 *b = std::make_pair(i, x[i]); |
243 } |
393 ++b; |
244 |
394 } |
245 LpCplex::Value LpCplex::_getColUpperBound(int i) const |
395 } |
|
396 } |
|
397 |
|
398 void CplexBase::_setObjCoeff(int i, Value obj_coef) |
246 { |
399 { |
247 LpCplex::Value x; |
400 CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef); |
248 CPXgetub (env, lp, &x, i, i); |
401 } |
249 if (x >= CPX_INFBOUND) x = INF; |
402 |
250 return x; |
403 CplexBase::Value CplexBase::_getObjCoeff(int i) const |
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 } |
|
290 } |
|
291 } |
|
292 } |
|
293 |
|
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 |
|
326 { |
|
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 } |
|
350 } |
|
351 |
|
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 |
|
358 { |
404 { |
359 Value x; |
405 Value x; |
360 CPXgetcoef(env, lp, -1, i, &x); |
406 CPXgetobj(cplexEnv(), _prob, &x, i, i); |
361 return x; |
407 return x; |
362 } |
408 } |
363 |
409 |
364 void LpCplex::_clearObj() |
410 void CplexBase::_setSense(CplexBase::Sense sense) { |
365 { |
411 switch (sense) { |
366 for (int i=0;i< CPXgetnumcols(env, lp);++i){ |
412 case MIN: |
367 CPXchgcoef(env, lp, -1, i, 0); |
413 CPXchgobjsen(cplexEnv(), _prob, CPX_MIN); |
368 } |
414 break; |
369 |
415 case MAX: |
370 } |
416 CPXchgobjsen(cplexEnv(), _prob, CPX_MAX); |
|
417 break; |
|
418 } |
|
419 } |
|
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 } |
|
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 // The routine returns zero unless an error occurred during the |
466 // The routine returns zero unless an error occurred during the |
372 // optimization. Examples of errors include exhausting available |
467 // optimization. Examples of errors include exhausting available |
373 // memory (CPXERR_NO_MEMORY) or encountering invalid data in the |
468 // memory (CPXERR_NO_MEMORY) or encountering invalid data in the |
374 // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a |
469 // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a |
375 // user-specified CPLEX limit, or proving the model infeasible or |
470 // user-specified CPLEX limit, or proving the model infeasible or |
376 // unbounded, are not considered errors. Note that a zero return |
471 // unbounded, are not considered errors. Note that a zero return |
377 // value does not necessarily mean that a solution exists. Use query |
472 // value does not necessarily mean that a solution exists. Use query |
378 // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain |
473 // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain |
379 // further information about the status of the optimization. |
474 // further information about the status of the optimization. |
380 LpCplex::SolveExitStatus LpCplex::_solve() |
475 LpCplex::SolveExitStatus LpCplex::convertStatus(int status) { |
381 { |
|
382 //CPX_PARAM_LPMETHOD |
|
383 status = CPXlpopt(env, lp); |
|
384 //status = CPXprimopt(env, lp); |
|
385 #if CPX_VERSION >= 800 |
476 #if CPX_VERSION >= 800 |
386 if (status) |
477 if (status == 0) { |
387 { |
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 return UNSOLVED; |
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 #else |
489 #else |
403 if (status == 0){ |
490 if (status == 0) { |
404 //We want to exclude some cases |
491 //We want to exclude some cases |
405 switch (CPXgetstat(env, lp)){ |
492 switch (CPXgetstat(cplexEnv(), _prob)) { |
406 case CPX_OBJ_LIM: |
493 case CPX_OBJ_LIM: |
407 case CPX_IT_LIM_FEAS: |
494 case CPX_IT_LIM_FEAS: |
408 case CPX_IT_LIM_INFEAS: |
495 case CPX_IT_LIM_INFEAS: |
409 case CPX_TIME_LIM_FEAS: |
496 case CPX_TIME_LIM_FEAS: |
410 case CPX_TIME_LIM_INFEAS: |
497 case CPX_TIME_LIM_INFEAS: |
411 return UNSOLVED; |
498 return UNSOLVED; |
412 default: |
499 default: |
413 return SOLVED; |
500 return SOLVED; |
414 } |
501 } |
415 } |
502 } else { |
416 else{ |
|
417 return UNSOLVED; |
503 return UNSOLVED; |
418 } |
504 } |
419 #endif |
505 #endif |
420 } |
506 } |
421 |
507 |
422 LpCplex::Value LpCplex::_getPrimal(int i) const |
508 LpCplex::SolveExitStatus LpCplex::_solve() { |
423 { |
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 Value x; |
529 Value x; |
425 CPXgetx(env, lp, &x, i, i); |
530 CPXgetx(cplexEnv(), _prob, &x, i, i); |
426 return x; |
531 return x; |
427 } |
532 } |
428 |
533 |
429 LpCplex::Value LpCplex::_getDual(int i) const |
534 LpCplex::Value LpCplex::_getDual(int i) const { |
430 { |
|
431 Value y; |
535 Value y; |
432 CPXgetpi(env, lp, &y, i, i); |
536 CPXgetpi(cplexEnv(), _prob, &y, i, i); |
433 return y; |
537 return y; |
434 } |
538 } |
435 |
539 |
436 LpCplex::Value LpCplex::_getPrimalValue() const |
540 LpCplex::Value LpCplex::_getPrimalValue() const { |
437 { |
|
438 Value objval; |
541 Value objval; |
439 //method = CPXgetmethod (env, lp); |
542 CPXgetobjval(cplexEnv(), _prob, &objval); |
440 //printf("CPXgetprobtype %d \n",CPXgetprobtype(env,lp)); |
|
441 CPXgetobjval(env, lp, &objval); |
|
442 //printf("Objective value: %g \n",objval); |
|
443 return objval; |
543 return objval; |
444 } |
544 } |
445 bool LpCplex::_isBasicCol(int i) const |
545 |
446 { |
546 LpCplex::VarStatus LpCplex::_getColStatus(int i) const { |
447 std::vector<int> cstat(CPXgetnumcols(env, lp)); |
547 if (_col_status.empty()) { |
448 CPXgetbase(env, lp, &*cstat.begin(), NULL); |
548 _col_status.resize(CPXgetnumcols(cplexEnv(), _prob)); |
449 return (cstat[i]==CPX_BASIC); |
549 CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0); |
450 } |
550 } |
451 |
551 switch (_col_status[i]) { |
452 //7.5-os cplex statusai (Vigyazat: a 9.0-asei masok!) |
552 case CPX_BASIC: |
453 // This table lists the statuses, returned by the CPXgetstat() |
553 return BASIC; |
454 // routine, for solutions to LP problems or mixed integer problems. If |
554 case CPX_FREE_SUPER: |
455 // no solution exists, the return value is zero. |
555 return FREE; |
456 |
556 case CPX_AT_LOWER: |
457 // For Simplex, Barrier |
557 return LOWER; |
458 // 1 CPX_OPTIMAL |
558 case CPX_AT_UPPER: |
459 // Optimal solution found |
559 return UPPER; |
460 // 2 CPX_INFEASIBLE |
560 default: |
461 // Problem infeasible |
561 LEMON_ASSERT(false, "Wrong column status"); |
462 // 3 CPX_UNBOUNDED |
562 return LpCplex::VarStatus(); |
463 // Problem unbounded |
563 } |
464 // 4 CPX_OBJ_LIM |
564 } |
465 // Objective limit exceeded in Phase II |
565 |
466 // 5 CPX_IT_LIM_FEAS |
566 LpCplex::VarStatus LpCplex::_getRowStatus(int i) const { |
467 // Iteration limit exceeded in Phase II |
567 if (_row_status.empty()) { |
468 // 6 CPX_IT_LIM_INFEAS |
568 _row_status.resize(CPXgetnumrows(cplexEnv(), _prob)); |
469 // Iteration limit exceeded in Phase I |
569 CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front()); |
470 // 7 CPX_TIME_LIM_FEAS |
570 } |
471 // Time limit exceeded in Phase II |
571 switch (_row_status[i]) { |
472 // 8 CPX_TIME_LIM_INFEAS |
572 case CPX_BASIC: |
473 // Time limit exceeded in Phase I |
573 return BASIC; |
474 // 9 CPX_NUM_BEST_FEAS |
574 case CPX_AT_LOWER: |
475 // Problem non-optimal, singularities in Phase II |
575 { |
476 // 10 CPX_NUM_BEST_INFEAS |
576 char s; |
477 // Problem non-optimal, singularities in Phase I |
577 CPXgetsense(cplexEnv(), _prob, &s, i, i); |
478 // 11 CPX_OPTIMAL_INFEAS |
578 return s != 'L' ? LOWER : UPPER; |
479 // Optimal solution found, unscaled infeasibilities |
579 } |
480 // 12 CPX_ABORT_FEAS |
580 case CPX_AT_UPPER: |
481 // Aborted in Phase II |
581 return UPPER; |
482 // 13 CPX_ABORT_INFEAS |
582 default: |
483 // Aborted in Phase I |
583 LEMON_ASSERT(false, "Wrong row status"); |
484 // 14 CPX_ABORT_DUAL_INFEAS |
584 return LpCplex::VarStatus(); |
485 // Aborted in barrier, dual infeasible |
585 } |
486 // 15 CPX_ABORT_PRIM_INFEAS |
586 } |
487 // Aborted in barrier, primal infeasible |
587 |
488 // 16 CPX_ABORT_PRIM_DUAL_INFEAS |
588 LpCplex::Value LpCplex::_getPrimalRay(int i) const { |
489 // Aborted in barrier, primal and dual infeasible |
589 if (_primal_ray.empty()) { |
490 // 17 CPX_ABORT_PRIM_DUAL_FEAS |
590 _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob)); |
491 // Aborted in barrier, primal and dual feasible |
591 CPXgetray(cplexEnv(), _prob, &_primal_ray.front()); |
492 // 18 CPX_ABORT_CROSSOVER |
592 } |
493 // Aborted in crossover |
593 return _primal_ray[i]; |
494 // 19 CPX_INForUNBD |
594 } |
495 // Infeasible or unbounded |
595 |
496 // 20 CPX_PIVOT |
596 LpCplex::Value LpCplex::_getDualRay(int i) const { |
497 // User pivot used |
597 if (_dual_ray.empty()) { |
498 // |
598 |
499 // Ezeket hova tegyem: |
599 } |
500 // ??case CPX_ABORT_DUAL_INFEAS |
600 return _dual_ray[i]; |
501 // ??case CPX_ABORT_CROSSOVER |
601 } |
502 // ??case CPX_INForUNBD |
602 |
503 // ??case CPX_PIVOT |
603 //7.5-os cplex statusai (Vigyazat: a 9.0-asei masok!) |
504 |
604 // This table lists the statuses, returned by the CPXgetstat() |
505 //Some more interesting stuff: |
605 // routine, for solutions to LP problems or mixed integer problems. If |
506 |
606 // no solution exists, the return value is zero. |
507 // CPX_PARAM_LPMETHOD 1062 int LPMETHOD |
607 |
508 // 0 Automatic |
608 // For Simplex, Barrier |
509 // 1 Primal Simplex |
609 // 1 CPX_OPTIMAL |
510 // 2 Dual Simplex |
610 // Optimal solution found |
511 // 3 Network Simplex |
611 // 2 CPX_INFEASIBLE |
512 // 4 Standard Barrier |
612 // Problem infeasible |
513 // Default: 0 |
613 // 3 CPX_UNBOUNDED |
514 // Description: Method for linear optimization. |
614 // Problem unbounded |
515 // Determines which algorithm is used when CPXlpopt() (or "optimize" |
615 // 4 CPX_OBJ_LIM |
516 // in the Interactive Optimizer) is called. Currently the behavior of |
616 // Objective limit exceeded in Phase II |
517 // the "Automatic" setting is that CPLEX simply invokes the dual |
617 // 5 CPX_IT_LIM_FEAS |
518 // simplex method, but this capability may be expanded in the future |
618 // Iteration limit exceeded in Phase II |
519 // so that CPLEX chooses the method based on problem characteristics |
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 #if CPX_VERSION < 900 |
671 #if CPX_VERSION < 900 |
521 void statusSwitch(CPXENVptr env,int& stat){ |
672 void statusSwitch(CPXENVptr cplexEnv(),int& stat){ |
522 int lpmethod; |
673 int lpmethod; |
523 CPXgetintparam (env,CPX_PARAM_LPMETHOD,&lpmethod); |
674 CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod); |
524 if (lpmethod==2){ |
675 if (lpmethod==2){ |
525 if (stat==CPX_UNBOUNDED){ |
676 if (stat==CPX_UNBOUNDED){ |
526 stat=CPX_INFEASIBLE; |
677 stat=CPX_INFEASIBLE; |
527 } |
678 } |
528 else{ |
679 else{ |
550 // unbounded. Note that ILOG CPLEX has not necessarily concluded that |
700 // unbounded. Note that ILOG CPLEX has not necessarily concluded that |
551 // a feasible solution exists. Users can call the routine CPXsolninfo |
701 // a feasible solution exists. Users can call the routine CPXsolninfo |
552 // to determine whether ILOG CPLEX has also concluded that the model |
702 // to determine whether ILOG CPLEX has also concluded that the model |
553 // has a feasible solution. |
703 // has a feasible solution. |
554 |
704 |
555 int stat = CPXgetstat(env, lp); |
705 int stat = CPXgetstat(cplexEnv(), _prob); |
556 #if CPX_VERSION >= 800 |
706 #if CPX_VERSION >= 800 |
557 switch (stat) |
707 switch (stat) |
558 { |
708 { |
559 case CPX_STAT_OPTIMAL: |
709 case CPX_STAT_OPTIMAL: |
560 return OPTIMAL; |
710 return OPTIMAL; |
561 case CPX_STAT_UNBOUNDED: |
711 case CPX_STAT_UNBOUNDED: |
562 return INFINITE; |
712 return UNBOUNDED; |
563 case CPX_STAT_INFEASIBLE: |
713 case CPX_STAT_INFEASIBLE: |
564 return INFEASIBLE; |
714 return INFEASIBLE; |
565 default: |
715 default: |
566 return UNDEFINED; |
716 return UNDEFINED; |
567 } |
717 } |
568 #else |
718 #else |
569 statusSwitch(env,stat); |
719 statusSwitch(cplexEnv(),stat); |
570 //CPXgetstat(env, lp); |
720 //CPXgetstat(cplexEnv(), _prob); |
571 //printf("A primal status: %d, CPX_OPTIMAL=%d \n",stat,CPX_OPTIMAL); |
721 //printf("A primal status: %d, CPX_OPTIMAL=%d \n",stat,CPX_OPTIMAL); |
572 switch (stat) { |
722 switch (stat) { |
573 case 0: |
723 case 0: |
574 return UNDEFINED; //Undefined |
724 return UNDEFINED; //Undefined |
575 case CPX_OPTIMAL://Optimal |
725 case CPX_OPTIMAL://Optimal |
576 return OPTIMAL; |
726 return OPTIMAL; |
577 case CPX_UNBOUNDED://Unbounded |
727 case CPX_UNBOUNDED://Unbounded |
578 return INFEASIBLE;//In case of dual simplex |
728 return INFEASIBLE;//In case of dual simplex |
579 //return INFINITE; |
729 //return UNBOUNDED; |
580 case CPX_INFEASIBLE://Infeasible |
730 case CPX_INFEASIBLE://Infeasible |
581 // case CPX_IT_LIM_INFEAS: |
731 // case CPX_IT_LIM_INFEAS: |
582 // case CPX_TIME_LIM_INFEAS: |
732 // case CPX_TIME_LIM_INFEAS: |
583 // case CPX_NUM_BEST_INFEAS: |
733 // case CPX_NUM_BEST_INFEAS: |
584 // case CPX_OPTIMAL_INFEAS: |
734 // case CPX_OPTIMAL_INFEAS: |
585 // case CPX_ABORT_INFEAS: |
735 // case CPX_ABORT_INFEAS: |
586 // case CPX_ABORT_PRIM_INFEAS: |
736 // case CPX_ABORT_PRIM_INFEAS: |
587 // case CPX_ABORT_PRIM_DUAL_INFEAS: |
737 // case CPX_ABORT_PRIM_DUAL_INFEAS: |
588 return INFINITE;//In case of dual simplex |
738 return UNBOUNDED;//In case of dual simplex |
589 //return INFEASIBLE; |
739 //return INFEASIBLE; |
590 // case CPX_OBJ_LIM: |
740 // case CPX_OBJ_LIM: |
591 // case CPX_IT_LIM_FEAS: |
741 // case CPX_IT_LIM_FEAS: |
592 // case CPX_TIME_LIM_FEAS: |
742 // case CPX_TIME_LIM_FEAS: |
593 // case CPX_NUM_BEST_FEAS: |
743 // case CPX_NUM_BEST_FEAS: |
594 // case CPX_ABORT_FEAS: |
744 // case CPX_ABORT_FEAS: |
595 // case CPX_ABORT_PRIM_DUAL_FEAS: |
745 // case CPX_ABORT_PRIM_DUAL_FEAS: |
596 // return FEASIBLE; |
746 // return FEASIBLE; |
597 default: |
747 default: |
598 return UNDEFINED; //Everything else comes here |
748 return UNDEFINED; //Everything else comes here |
599 //FIXME error |
749 //FIXME error |
600 } |
750 } |
601 #endif |
751 #endif |
602 } |
752 } |
603 |
753 |
604 //9.0-as cplex verzio statusai |
754 //9.0-as cplex verzio statusai |
605 // CPX_STAT_ABORT_DUAL_OBJ_LIM |
755 // CPX_STAT_ABORT_DUAL_OBJ_LIM |
606 // CPX_STAT_ABORT_IT_LIM |
756 // CPX_STAT_ABORT_IT_LIM |
607 // CPX_STAT_ABORT_OBJ_LIM |
757 // CPX_STAT_ABORT_OBJ_LIM |
608 // CPX_STAT_ABORT_PRIM_OBJ_LIM |
758 // CPX_STAT_ABORT_PRIM_OBJ_LIM |
609 // CPX_STAT_ABORT_TIME_LIM |
759 // CPX_STAT_ABORT_TIME_LIM |
610 // CPX_STAT_ABORT_USER |
760 // CPX_STAT_ABORT_USER |
611 // CPX_STAT_FEASIBLE_RELAXED |
761 // CPX_STAT_FEASIBLE_RELAXED |
612 // CPX_STAT_INFEASIBLE |
762 // CPX_STAT_INFEASIBLE |
613 // CPX_STAT_INForUNBD |
763 // CPX_STAT_INForUNBD |
614 // CPX_STAT_NUM_BEST |
764 // CPX_STAT_NUM_BEST |
615 // CPX_STAT_OPTIMAL |
765 // CPX_STAT_OPTIMAL |
616 // CPX_STAT_OPTIMAL_FACE_UNBOUNDED |
766 // CPX_STAT_OPTIMAL_FACE_UNBOUNDED |
617 // CPX_STAT_OPTIMAL_INFEAS |
767 // CPX_STAT_OPTIMAL_INFEAS |
618 // CPX_STAT_OPTIMAL_RELAXED |
768 // CPX_STAT_OPTIMAL_RELAXED |
619 // CPX_STAT_UNBOUNDED |
769 // CPX_STAT_UNBOUNDED |
620 |
770 |
621 LpCplex::SolutionStatus LpCplex::_getDualStatus() const |
771 LpCplex::ProblemType LpCplex::_getDualType() const { |
622 { |
772 int stat = CPXgetstat(cplexEnv(), _prob); |
623 int stat = CPXgetstat(env, lp); |
|
624 #if CPX_VERSION >= 800 |
773 #if CPX_VERSION >= 800 |
625 switch (stat) |
774 switch (stat) { |
626 { |
775 case CPX_STAT_OPTIMAL: |
627 case CPX_STAT_OPTIMAL: |
776 return OPTIMAL; |
628 return OPTIMAL; |
777 case CPX_STAT_UNBOUNDED: |
629 case CPX_STAT_UNBOUNDED: |
778 return INFEASIBLE; |
630 return INFEASIBLE; |
779 default: |
631 default: |
780 return UNDEFINED; |
632 return UNDEFINED; |
|
633 } |
781 } |
634 #else |
782 #else |
635 statusSwitch(env,stat); |
783 statusSwitch(cplexEnv(),stat); |
636 switch (stat) { |
784 switch (stat) { |
637 case 0: |
785 case 0: |
638 return UNDEFINED; //Undefined |
786 return UNDEFINED; //Undefined |
639 case CPX_OPTIMAL://Optimal |
787 case CPX_OPTIMAL://Optimal |
640 return OPTIMAL; |
788 return OPTIMAL; |
641 case CPX_UNBOUNDED: |
789 case CPX_UNBOUNDED: |
642 return INFEASIBLE; |
790 return INFEASIBLE; |
643 default: |
791 default: |
644 return UNDEFINED; //Everything else comes here |
792 return UNDEFINED; //Everything else comes here |
645 //FIXME error |
793 //FIXME error |
646 } |
794 } |
647 #endif |
795 #endif |
648 } |
796 } |
649 |
797 |
650 LpCplex::ProblemTypes LpCplex::_getProblemType() const |
798 // MipCplex members |
651 { |
799 |
652 int stat = CPXgetstat(env, lp); |
800 MipCplex::MipCplex() |
653 #if CPX_VERSION >= 800 |
801 : LpBase(), CplexBase(), MipSolver() { |
654 switch (stat) |
802 |
655 { |
803 #if CPX_VERSION < 800 |
656 case CPX_STAT_OPTIMAL: |
804 CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP); |
657 return PRIMAL_DUAL_FEASIBLE; |
|
658 case CPX_STAT_UNBOUNDED: |
|
659 return PRIMAL_FEASIBLE_DUAL_INFEASIBLE; |
|
660 default: |
|
661 return UNKNOWN; |
|
662 } |
|
663 #else |
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 |
664 switch (stat) { |
881 switch (stat) { |
665 case CPX_OPTIMAL://Optimal |
882 case CPXMIP_OPTIMAL: |
666 return PRIMAL_DUAL_FEASIBLE; |
883 // Optimal integer solution has been found. |
667 case CPX_UNBOUNDED: |
884 case CPXMIP_OPTIMAL_TOL: |
668 return PRIMAL_FEASIBLE_DUAL_INFEASIBLE; |
885 // Optimal soluton with the tolerance defined by epgap or epagap has |
669 // return PRIMAL_INFEASIBLE_DUAL_FEASIBLE; |
886 // been found. |
670 // return PRIMAL_DUAL_INFEASIBLE; |
887 return OPTIMAL; |
671 |
888 //This also exists in later issues |
672 //Seems to be that this is all we can say for sure |
889 // case CPXMIP_UNBOUNDED: |
673 default: |
890 //return UNBOUNDED; |
674 //In all other cases |
891 case CPXMIP_INFEASIBLE: |
675 return UNKNOWN; |
892 return INFEASIBLE; |
676 //FIXME error |
893 default: |
677 } |
894 return UNDEFINED; |
678 #endif |
895 } |
679 } |
896 //Unboundedness not treated well: the following is from cplex 9.0 doc |
680 |
897 // About Unboundedness |
681 void LpCplex::_setMax() |
898 |
682 { |
899 // The treatment of models that are unbounded involves a few |
683 CPXchgobjsen(env, lp, CPX_MAX); |
900 // subtleties. Specifically, a declaration of unboundedness means that |
684 } |
901 // ILOG CPLEX has determined that the model has an unbounded |
685 void LpCplex::_setMin() |
902 // ray. Given any feasible solution x with objective z, a multiple of |
686 { |
903 // the unbounded ray can be added to x to give a feasible solution |
687 CPXchgobjsen(env, lp, CPX_MIN); |
904 // with objective z-1 (or z+1 for maximization models). Thus, if a |
688 } |
905 // feasible solution exists, then the optimal objective is |
689 |
906 // unbounded. Note that ILOG CPLEX has not necessarily concluded that |
690 bool LpCplex::_isMax() const |
907 // a feasible solution exists. Users can call the routine CPXsolninfo |
691 { |
908 // to determine whether ILOG CPLEX has also concluded that the model |
692 if (CPXgetobjsen(env, lp)==CPX_MAX) |
909 // has a feasible solution. |
693 return true; |
910 } |
694 else |
911 |
695 return false; |
912 MipCplex::Value MipCplex::_getSol(int i) const { |
|
913 Value x; |
|
914 CPXgetmipx(cplexEnv(), _prob, &x, i, i); |
|
915 return x; |
|
916 } |
|
917 |
|
918 MipCplex::Value MipCplex::_getSolValue() const { |
|
919 Value objval; |
|
920 CPXgetmipobjval(cplexEnv(), _prob, &objval); |
|
921 return objval; |
696 } |
922 } |
697 |
923 |
698 } //namespace lemon |
924 } //namespace lemon |
699 |
925 |