1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
3 * This file is a part of LEMON, a generic C++ optimization library.
5 * Copyright (C) 2003-2013
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
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.
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
20 #include <lemon/soplex.h>
27 ///\brief Implementation of the LEMON-SOPLEX lp solver interface.
30 SoplexLp::SoplexLp() {
31 soplex = new soplex::SoPlex;
32 messageLevel(MESSAGE_NOTHING);
35 SoplexLp::~SoplexLp() {
39 SoplexLp::SoplexLp(const SoplexLp& lp) {
43 soplex = new soplex::SoPlex;
44 (*static_cast<soplex::SPxLP*>(soplex)) = *(lp.soplex);
46 _col_names = lp._col_names;
47 _col_names_ref = lp._col_names_ref;
49 _row_names = lp._row_names;
50 _row_names_ref = lp._row_names_ref;
52 messageLevel(MESSAGE_NOTHING);
55 void SoplexLp::_clear_temporals() {
56 _primal_values.clear();
60 SoplexLp* SoplexLp::newSolver() const {
61 SoplexLp* newlp = new SoplexLp();
65 SoplexLp* SoplexLp::cloneSolver() const {
66 SoplexLp* newlp = new SoplexLp(*this);
70 const char* SoplexLp::_solverName() const { return "SoplexLp"; }
72 int SoplexLp::_addCol() {
74 c.setLower(-soplex::infinity);
75 c.setUpper(soplex::infinity);
78 _col_names.push_back(std::string());
80 return soplex->nCols() - 1;
83 int SoplexLp::_addRow() {
85 r.setLhs(-soplex::infinity);
86 r.setRhs(soplex::infinity);
89 _row_names.push_back(std::string());
91 return soplex->nRows() - 1;
94 int SoplexLp::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) {
96 for (ExprIterator it = b; it != e; ++it) {
97 v.add(it->first, it->second);
99 soplex::LPRow r(l, v, u);
102 _row_names.push_back(std::string());
104 return soplex->nRows() - 1;
108 void SoplexLp::_eraseCol(int i) {
109 soplex->removeCol(i);
110 _col_names_ref.erase(_col_names[i]);
111 _col_names[i] = _col_names.back();
112 _col_names_ref[_col_names.back()] = i;
113 _col_names.pop_back();
116 void SoplexLp::_eraseRow(int i) {
117 soplex->removeRow(i);
118 _row_names_ref.erase(_row_names[i]);
119 _row_names[i] = _row_names.back();
120 _row_names_ref[_row_names.back()] = i;
121 _row_names.pop_back();
124 void SoplexLp::_eraseColId(int i) {
126 cols.relocateIndex(i, cols.maxIndex());
128 void SoplexLp::_eraseRowId(int i) {
130 rows.relocateIndex(i, rows.maxIndex());
133 void SoplexLp::_getColName(int c, std::string &name) const {
134 name = _col_names[c];
137 void SoplexLp::_setColName(int c, const std::string &name) {
138 _col_names_ref.erase(_col_names[c]);
139 _col_names[c] = name;
141 _col_names_ref.insert(std::make_pair(name, c));
145 int SoplexLp::_colByName(const std::string& name) const {
146 std::map<std::string, int>::const_iterator it =
147 _col_names_ref.find(name);
148 if (it != _col_names_ref.end()) {
155 void SoplexLp::_getRowName(int r, std::string &name) const {
156 name = _row_names[r];
159 void SoplexLp::_setRowName(int r, const std::string &name) {
160 _row_names_ref.erase(_row_names[r]);
161 _row_names[r] = name;
163 _row_names_ref.insert(std::make_pair(name, r));
167 int SoplexLp::_rowByName(const std::string& name) const {
168 std::map<std::string, int>::const_iterator it =
169 _row_names_ref.find(name);
170 if (it != _row_names_ref.end()) {
178 void SoplexLp::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) {
179 for (int j = 0; j < soplex->nCols(); ++j) {
180 soplex->changeElement(i, j, 0.0);
182 for(ExprIterator it = b; it != e; ++it) {
183 soplex->changeElement(i, it->first, it->second);
187 void SoplexLp::_getRowCoeffs(int i, InsertIterator b) const {
188 const soplex::SVector& vec = soplex->rowVector(i);
189 for (int k = 0; k < vec.size(); ++k) {
190 *b = std::make_pair(vec.index(k), vec.value(k));
195 void SoplexLp::_setColCoeffs(int j, ExprIterator b, ExprIterator e) {
196 for (int i = 0; i < soplex->nRows(); ++i) {
197 soplex->changeElement(i, j, 0.0);
199 for(ExprIterator it = b; it != e; ++it) {
200 soplex->changeElement(it->first, j, it->second);
204 void SoplexLp::_getColCoeffs(int i, InsertIterator b) const {
205 const soplex::SVector& vec = soplex->colVector(i);
206 for (int k = 0; k < vec.size(); ++k) {
207 *b = std::make_pair(vec.index(k), vec.value(k));
212 void SoplexLp::_setCoeff(int i, int j, Value value) {
213 soplex->changeElement(i, j, value);
216 SoplexLp::Value SoplexLp::_getCoeff(int i, int j) const {
217 return soplex->rowVector(i)[j];
220 void SoplexLp::_setColLowerBound(int i, Value value) {
221 LEMON_ASSERT(value != INF, "Invalid bound");
222 soplex->changeLower(i, value != -INF ? value : -soplex::infinity);
225 SoplexLp::Value SoplexLp::_getColLowerBound(int i) const {
226 double value = soplex->lower(i);
227 return value != -soplex::infinity ? value : -INF;
230 void SoplexLp::_setColUpperBound(int i, Value value) {
231 LEMON_ASSERT(value != -INF, "Invalid bound");
232 soplex->changeUpper(i, value != INF ? value : soplex::infinity);
235 SoplexLp::Value SoplexLp::_getColUpperBound(int i) const {
236 double value = soplex->upper(i);
237 return value != soplex::infinity ? value : INF;
240 void SoplexLp::_setRowLowerBound(int i, Value lb) {
241 LEMON_ASSERT(lb != INF, "Invalid bound");
242 soplex->changeRange(i, lb != -INF ? lb : -soplex::infinity, soplex->rhs(i));
245 SoplexLp::Value SoplexLp::_getRowLowerBound(int i) const {
246 double res = soplex->lhs(i);
247 return res == -soplex::infinity ? -INF : res;
250 void SoplexLp::_setRowUpperBound(int i, Value ub) {
251 LEMON_ASSERT(ub != -INF, "Invalid bound");
252 soplex->changeRange(i, soplex->lhs(i), ub != INF ? ub : soplex::infinity);
255 SoplexLp::Value SoplexLp::_getRowUpperBound(int i) const {
256 double res = soplex->rhs(i);
257 return res == soplex::infinity ? INF : res;
260 void SoplexLp::_setObjCoeffs(ExprIterator b, ExprIterator e) {
261 for (int j = 0; j < soplex->nCols(); ++j) {
262 soplex->changeObj(j, 0.0);
264 for (ExprIterator it = b; it != e; ++it) {
265 soplex->changeObj(it->first, it->second);
269 void SoplexLp::_getObjCoeffs(InsertIterator b) const {
270 for (int j = 0; j < soplex->nCols(); ++j) {
271 Value coef = soplex->obj(j);
273 *b = std::make_pair(j, coef);
279 void SoplexLp::_setObjCoeff(int i, Value obj_coef) {
280 soplex->changeObj(i, obj_coef);
283 SoplexLp::Value SoplexLp::_getObjCoeff(int i) const {
284 return soplex->obj(i);
287 SoplexLp::SolveExitStatus SoplexLp::_solve() {
291 _applyMessageLevel();
293 soplex::SPxSolver::Status status = soplex->solve();
296 case soplex::SPxSolver::OPTIMAL:
297 case soplex::SPxSolver::INFEASIBLE:
298 case soplex::SPxSolver::UNBOUNDED:
305 SoplexLp::Value SoplexLp::_getPrimal(int i) const {
306 if (_primal_values.empty()) {
307 _primal_values.resize(soplex->nCols());
308 soplex::Vector pv(_primal_values.size(), &_primal_values.front());
309 soplex->getPrimal(pv);
311 return _primal_values[i];
314 SoplexLp::Value SoplexLp::_getDual(int i) const {
315 if (_dual_values.empty()) {
316 _dual_values.resize(soplex->nRows());
317 soplex::Vector dv(_dual_values.size(), &_dual_values.front());
320 return _dual_values[i];
323 SoplexLp::Value SoplexLp::_getPrimalValue() const {
324 return soplex->objValue();
327 SoplexLp::VarStatus SoplexLp::_getColStatus(int i) const {
328 switch (soplex->getBasisColStatus(i)) {
329 case soplex::SPxSolver::BASIC:
331 case soplex::SPxSolver::ON_UPPER:
333 case soplex::SPxSolver::ON_LOWER:
335 case soplex::SPxSolver::FIXED:
337 case soplex::SPxSolver::ZERO:
340 LEMON_ASSERT(false, "Wrong column status");
345 SoplexLp::VarStatus SoplexLp::_getRowStatus(int i) const {
346 switch (soplex->getBasisRowStatus(i)) {
347 case soplex::SPxSolver::BASIC:
349 case soplex::SPxSolver::ON_UPPER:
351 case soplex::SPxSolver::ON_LOWER:
353 case soplex::SPxSolver::FIXED:
355 case soplex::SPxSolver::ZERO:
358 LEMON_ASSERT(false, "Wrong row status");
363 SoplexLp::Value SoplexLp::_getPrimalRay(int i) const {
364 if (_primal_ray.empty()) {
365 _primal_ray.resize(soplex->nCols());
366 soplex::Vector pv(_primal_ray.size(), &_primal_ray.front());
367 soplex->getDualfarkas(pv);
369 return _primal_ray[i];
372 SoplexLp::Value SoplexLp::_getDualRay(int i) const {
373 if (_dual_ray.empty()) {
374 _dual_ray.resize(soplex->nRows());
375 soplex::Vector dv(_dual_ray.size(), &_dual_ray.front());
376 soplex->getDualfarkas(dv);
381 SoplexLp::ProblemType SoplexLp::_getPrimalType() const {
382 switch (soplex->status()) {
383 case soplex::SPxSolver::OPTIMAL:
385 case soplex::SPxSolver::UNBOUNDED:
387 case soplex::SPxSolver::INFEASIBLE:
394 SoplexLp::ProblemType SoplexLp::_getDualType() const {
395 switch (soplex->status()) {
396 case soplex::SPxSolver::OPTIMAL:
398 case soplex::SPxSolver::UNBOUNDED:
400 case soplex::SPxSolver::INFEASIBLE:
407 void SoplexLp::_setSense(Sense sense) {
410 soplex->changeSense(soplex::SPxSolver::MINIMIZE);
413 soplex->changeSense(soplex::SPxSolver::MAXIMIZE);
417 SoplexLp::Sense SoplexLp::_getSense() const {
418 switch (soplex->spxSense()) {
419 case soplex::SPxSolver::MAXIMIZE:
421 case soplex::SPxSolver::MINIMIZE:
424 LEMON_ASSERT(false, "Wrong sense.");
425 return SoplexLp::Sense();
429 void SoplexLp::_clear() {
432 _col_names_ref.clear();
434 _row_names_ref.clear();
440 void SoplexLp::_messageLevel(MessageLevel level) {
442 case MESSAGE_NOTHING:
446 _message_level = soplex::SPxOut::ERROR;
448 case MESSAGE_WARNING:
449 _message_level = soplex::SPxOut::WARNING;
452 _message_level = soplex::SPxOut::INFO2;
454 case MESSAGE_VERBOSE:
455 _message_level = soplex::SPxOut::DEBUG;
460 void SoplexLp::_applyMessageLevel() {
461 soplex::Param::setVerbose(_message_level);