alpar@461: /* -*- mode: C++; indent-tabs-mode: nil; -*- alpar@461: * alpar@461: * This file is a part of LEMON, a generic C++ optimization library. alpar@461: * alpar@1092: * Copyright (C) 2003-2013 alpar@461: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport alpar@461: * (Egervary Research Group on Combinatorial Optimization, EGRES). alpar@461: * alpar@461: * Permission to use, modify and distribute this software is granted alpar@461: * provided that this copyright notice appears in all copies. For alpar@461: * precise terms see the accompanying LICENSE file. alpar@461: * alpar@461: * This software is provided "AS IS" with no warranty of any kind, alpar@461: * express or implied, and with no claim as to its suitability for any alpar@461: * purpose. alpar@461: * alpar@461: */ alpar@461: alpar@461: #include alpar@461: #include alpar@461: #include alpar@461: alpar@461: #include alpar@461: alpar@461: extern "C" { alpar@461: #include alpar@461: } alpar@461: alpar@461: alpar@461: ///\file alpar@461: ///\brief Implementation of the LEMON-CPLEX lp solver interface. alpar@461: namespace lemon { alpar@461: alpar@461: CplexEnv::LicenseError::LicenseError(int status) { alpar@461: if (!CPXgeterrorstring(0, status, _message)) { alpar@461: std::strcpy(_message, "Cplex unknown error"); alpar@461: } alpar@461: } alpar@461: alpar@461: CplexEnv::CplexEnv() { alpar@461: int status; alpar@461: _cnt = new int; alpar@1015: (*_cnt) = 1; alpar@461: _env = CPXopenCPLEX(&status); alpar@461: if (_env == 0) { alpar@461: delete _cnt; alpar@461: _cnt = 0; alpar@461: throw LicenseError(status); alpar@461: } alpar@461: } alpar@461: alpar@461: CplexEnv::CplexEnv(const CplexEnv& other) { alpar@461: _env = other._env; alpar@461: _cnt = other._cnt; alpar@461: ++(*_cnt); alpar@461: } alpar@461: alpar@461: CplexEnv& CplexEnv::operator=(const CplexEnv& other) { alpar@461: _env = other._env; alpar@461: _cnt = other._cnt; alpar@461: ++(*_cnt); alpar@461: return *this; alpar@461: } alpar@461: alpar@461: CplexEnv::~CplexEnv() { alpar@461: --(*_cnt); alpar@461: if (*_cnt == 0) { alpar@461: delete _cnt; alpar@461: CPXcloseCPLEX(&_env); alpar@461: } alpar@461: } alpar@461: alpar@461: CplexBase::CplexBase() : LpBase() { alpar@461: int status; alpar@461: _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); deba@576: messageLevel(MESSAGE_NOTHING); alpar@461: } alpar@461: alpar@461: CplexBase::CplexBase(const CplexEnv& env) alpar@461: : LpBase(), _env(env) { alpar@461: int status; alpar@461: _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); deba@576: messageLevel(MESSAGE_NOTHING); alpar@461: } alpar@461: alpar@461: CplexBase::CplexBase(const CplexBase& cplex) alpar@461: : LpBase() { alpar@461: int status; alpar@461: _prob = CPXcloneprob(cplexEnv(), cplex._prob, &status); ggab90@1130: _rows = cplex._rows; ggab90@1130: _cols = cplex._cols; deba@576: messageLevel(MESSAGE_NOTHING); alpar@461: } alpar@461: alpar@461: CplexBase::~CplexBase() { alpar@461: CPXfreeprob(cplexEnv(),&_prob); alpar@461: } alpar@461: alpar@461: int CplexBase::_addCol() { alpar@461: int i = CPXgetnumcols(cplexEnv(), _prob); alpar@461: double lb = -INF, ub = INF; alpar@461: CPXnewcols(cplexEnv(), _prob, 1, 0, &lb, &ub, 0, 0); alpar@461: return i; alpar@461: } alpar@461: alpar@461: alpar@461: int CplexBase::_addRow() { alpar@461: int i = CPXgetnumrows(cplexEnv(), _prob); alpar@461: const double ub = INF; alpar@461: const char s = 'L'; alpar@461: CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0); alpar@461: return i; alpar@461: } alpar@461: alpar@877: int CplexBase::_addRow(Value lb, ExprIterator b, deba@746: ExprIterator e, Value ub) { deba@746: int i = CPXgetnumrows(cplexEnv(), _prob); deba@746: alpar@1125: int rmatbeg = 0; alpar@1125: deba@746: std::vector indices; deba@746: std::vector values; deba@746: deba@746: for(ExprIterator it=b; it!=e; ++it) { deba@746: indices.push_back(it->first); deba@746: values.push_back(it->second); deba@746: } deba@746: alpar@1125: if (lb == -INF) { alpar@1125: const char s = 'L'; alpar@1125: CPXaddrows(cplexEnv(), _prob, 0, 1, values.size(), &ub, &s, alpar@1125: &rmatbeg, &indices.front(), &values.front(), 0, 0); alpar@1125: } else if (ub == INF) { alpar@1125: const char s = 'G'; alpar@1125: CPXaddrows(cplexEnv(), _prob, 0, 1, values.size(), &lb, &s, alpar@1125: &rmatbeg, &indices.front(), &values.front(), 0, 0); alpar@1125: } else if (lb == ub){ alpar@1125: const char s = 'E'; alpar@1125: CPXaddrows(cplexEnv(), _prob, 0, 1, values.size(), &lb, &s, alpar@1125: &rmatbeg, &indices.front(), &values.front(), 0, 0); alpar@1125: } else { alpar@1125: const char s = 'R'; alpar@1125: double len = ub - lb; alpar@1125: CPXaddrows(cplexEnv(), _prob, 0, 1, values.size(), &ub, &s, alpar@1125: &rmatbeg, &indices.front(), &values.front(), 0, 0); alpar@1125: CPXchgrngval(cplexEnv(), _prob, 1, &i, &len); alpar@1125: } alpar@1125: deba@746: return i; deba@746: } alpar@461: alpar@461: void CplexBase::_eraseCol(int i) { alpar@461: CPXdelcols(cplexEnv(), _prob, i, i); alpar@461: } alpar@461: alpar@461: void CplexBase::_eraseRow(int i) { alpar@461: CPXdelrows(cplexEnv(), _prob, i, i); alpar@461: } alpar@461: alpar@461: void CplexBase::_eraseColId(int i) { ggab90@1130: _cols.eraseIndex(i); ggab90@1130: _cols.shiftIndices(i); alpar@461: } alpar@461: void CplexBase::_eraseRowId(int i) { ggab90@1130: _rows.eraseIndex(i); ggab90@1130: _rows.shiftIndices(i); alpar@461: } alpar@461: alpar@461: void CplexBase::_getColName(int col, std::string &name) const { alpar@461: int size; alpar@461: CPXgetcolname(cplexEnv(), _prob, 0, 0, 0, &size, col, col); alpar@461: if (size == 0) { alpar@461: name.clear(); alpar@461: return; alpar@461: } alpar@461: alpar@461: size *= -1; alpar@461: std::vector buf(size); alpar@461: char *cname; alpar@461: int tmp; alpar@461: CPXgetcolname(cplexEnv(), _prob, &cname, &buf.front(), size, alpar@461: &tmp, col, col); alpar@461: name = cname; alpar@461: } alpar@461: alpar@461: void CplexBase::_setColName(int col, const std::string &name) { alpar@461: char *cname; alpar@461: cname = const_cast(name.c_str()); alpar@461: CPXchgcolname(cplexEnv(), _prob, 1, &col, &cname); alpar@461: } alpar@461: alpar@461: int CplexBase::_colByName(const std::string& name) const { alpar@461: int index; alpar@461: if (CPXgetcolindex(cplexEnv(), _prob, alpar@461: const_cast(name.c_str()), &index) == 0) { alpar@461: return index; alpar@461: } alpar@461: return -1; alpar@461: } alpar@461: alpar@461: void CplexBase::_getRowName(int row, std::string &name) const { alpar@461: int size; alpar@461: CPXgetrowname(cplexEnv(), _prob, 0, 0, 0, &size, row, row); alpar@461: if (size == 0) { alpar@461: name.clear(); alpar@461: return; alpar@461: } alpar@461: alpar@461: size *= -1; alpar@461: std::vector buf(size); alpar@461: char *cname; alpar@461: int tmp; alpar@461: CPXgetrowname(cplexEnv(), _prob, &cname, &buf.front(), size, alpar@461: &tmp, row, row); alpar@461: name = cname; alpar@461: } alpar@461: alpar@461: void CplexBase::_setRowName(int row, const std::string &name) { alpar@461: char *cname; alpar@461: cname = const_cast(name.c_str()); alpar@461: CPXchgrowname(cplexEnv(), _prob, 1, &row, &cname); alpar@461: } alpar@461: alpar@461: int CplexBase::_rowByName(const std::string& name) const { alpar@461: int index; alpar@461: if (CPXgetrowindex(cplexEnv(), _prob, alpar@461: const_cast(name.c_str()), &index) == 0) { alpar@461: return index; alpar@461: } alpar@461: return -1; alpar@461: } alpar@461: alpar@461: void CplexBase::_setRowCoeffs(int i, ExprIterator b, alpar@461: ExprIterator e) alpar@461: { alpar@461: std::vector indices; alpar@461: std::vector rowlist; alpar@461: std::vector values; alpar@461: alpar@461: for(ExprIterator it=b; it!=e; ++it) { alpar@461: indices.push_back(it->first); alpar@461: values.push_back(it->second); alpar@461: rowlist.push_back(i); alpar@461: } alpar@461: alpar@461: CPXchgcoeflist(cplexEnv(), _prob, values.size(), alpar@461: &rowlist.front(), &indices.front(), &values.front()); alpar@461: } alpar@461: alpar@461: void CplexBase::_getRowCoeffs(int i, InsertIterator b) const { alpar@461: int tmp1, tmp2, tmp3, length; alpar@461: CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i); alpar@461: alpar@461: length = -length; alpar@461: std::vector indices(length); alpar@461: std::vector values(length); alpar@461: alpar@461: CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, alpar@461: &indices.front(), &values.front(), alpar@461: length, &tmp3, i, i); alpar@461: alpar@461: for (int i = 0; i < length; ++i) { alpar@461: *b = std::make_pair(indices[i], values[i]); alpar@461: ++b; alpar@461: } alpar@461: } alpar@461: alpar@461: void CplexBase::_setColCoeffs(int i, ExprIterator b, ExprIterator e) { alpar@461: std::vector indices; alpar@461: std::vector collist; alpar@461: std::vector values; alpar@461: alpar@461: for(ExprIterator it=b; it!=e; ++it) { alpar@461: indices.push_back(it->first); alpar@461: values.push_back(it->second); alpar@461: collist.push_back(i); alpar@461: } alpar@461: alpar@461: CPXchgcoeflist(cplexEnv(), _prob, values.size(), alpar@461: &indices.front(), &collist.front(), &values.front()); alpar@461: } alpar@461: alpar@461: void CplexBase::_getColCoeffs(int i, InsertIterator b) const { alpar@461: alpar@461: int tmp1, tmp2, tmp3, length; alpar@461: CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i); alpar@461: alpar@461: length = -length; alpar@461: std::vector indices(length); alpar@461: std::vector values(length); alpar@461: alpar@461: CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, alpar@461: &indices.front(), &values.front(), alpar@461: length, &tmp3, i, i); alpar@461: alpar@461: for (int i = 0; i < length; ++i) { alpar@461: *b = std::make_pair(indices[i], values[i]); alpar@461: ++b; alpar@461: } alpar@461: alpar@461: } alpar@461: alpar@461: void CplexBase::_setCoeff(int row, int col, Value value) { alpar@461: CPXchgcoef(cplexEnv(), _prob, row, col, value); alpar@461: } alpar@461: alpar@461: CplexBase::Value CplexBase::_getCoeff(int row, int col) const { alpar@461: CplexBase::Value value; alpar@461: CPXgetcoef(cplexEnv(), _prob, row, col, &value); alpar@461: return value; alpar@461: } alpar@461: alpar@461: void CplexBase::_setColLowerBound(int i, Value value) { alpar@461: const char s = 'L'; alpar@461: CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value); alpar@461: } alpar@461: alpar@461: CplexBase::Value CplexBase::_getColLowerBound(int i) const { alpar@461: CplexBase::Value res; alpar@461: CPXgetlb(cplexEnv(), _prob, &res, i, i); alpar@461: return res <= -CPX_INFBOUND ? -INF : res; alpar@461: } alpar@461: alpar@461: void CplexBase::_setColUpperBound(int i, Value value) alpar@461: { alpar@461: const char s = 'U'; alpar@461: CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value); alpar@461: } alpar@461: alpar@461: CplexBase::Value CplexBase::_getColUpperBound(int i) const { alpar@461: CplexBase::Value res; alpar@461: CPXgetub(cplexEnv(), _prob, &res, i, i); alpar@461: return res >= CPX_INFBOUND ? INF : res; alpar@461: } alpar@461: alpar@461: CplexBase::Value CplexBase::_getRowLowerBound(int i) const { alpar@461: char s; alpar@461: CPXgetsense(cplexEnv(), _prob, &s, i, i); alpar@461: CplexBase::Value res; alpar@461: alpar@461: switch (s) { alpar@461: case 'G': alpar@461: case 'R': alpar@461: case 'E': alpar@461: CPXgetrhs(cplexEnv(), _prob, &res, i, i); alpar@461: return res <= -CPX_INFBOUND ? -INF : res; alpar@461: default: alpar@461: return -INF; alpar@461: } alpar@461: } alpar@461: alpar@461: CplexBase::Value CplexBase::_getRowUpperBound(int i) const { alpar@461: char s; alpar@461: CPXgetsense(cplexEnv(), _prob, &s, i, i); alpar@461: CplexBase::Value res; alpar@461: alpar@461: switch (s) { alpar@461: case 'L': alpar@461: case 'E': alpar@461: CPXgetrhs(cplexEnv(), _prob, &res, i, i); alpar@461: return res >= CPX_INFBOUND ? INF : res; alpar@461: case 'R': alpar@461: CPXgetrhs(cplexEnv(), _prob, &res, i, i); alpar@461: { alpar@461: double rng; alpar@461: CPXgetrngval(cplexEnv(), _prob, &rng, i, i); alpar@461: res += rng; alpar@461: } alpar@461: return res >= CPX_INFBOUND ? INF : res; alpar@461: default: alpar@461: return INF; alpar@461: } alpar@461: } alpar@461: alpar@461: //This is easier to implement alpar@461: void CplexBase::_set_row_bounds(int i, Value lb, Value ub) { alpar@461: if (lb == -INF) { alpar@461: const char s = 'L'; alpar@461: CPXchgsense(cplexEnv(), _prob, 1, &i, &s); alpar@461: CPXchgrhs(cplexEnv(), _prob, 1, &i, &ub); alpar@461: } else if (ub == INF) { alpar@461: const char s = 'G'; alpar@461: CPXchgsense(cplexEnv(), _prob, 1, &i, &s); alpar@461: CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb); alpar@461: } else if (lb == ub){ alpar@461: const char s = 'E'; alpar@461: CPXchgsense(cplexEnv(), _prob, 1, &i, &s); alpar@461: CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb); alpar@461: } else { alpar@461: const char s = 'R'; alpar@461: CPXchgsense(cplexEnv(), _prob, 1, &i, &s); alpar@461: CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb); alpar@461: double len = ub - lb; alpar@461: CPXchgrngval(cplexEnv(), _prob, 1, &i, &len); alpar@461: } alpar@461: } alpar@461: alpar@461: void CplexBase::_setRowLowerBound(int i, Value lb) alpar@461: { alpar@461: LEMON_ASSERT(lb != INF, "Invalid bound"); alpar@461: _set_row_bounds(i, lb, CplexBase::_getRowUpperBound(i)); alpar@461: } alpar@461: alpar@461: void CplexBase::_setRowUpperBound(int i, Value ub) alpar@461: { alpar@461: alpar@461: LEMON_ASSERT(ub != -INF, "Invalid bound"); alpar@461: _set_row_bounds(i, CplexBase::_getRowLowerBound(i), ub); alpar@461: } alpar@461: alpar@461: void CplexBase::_setObjCoeffs(ExprIterator b, ExprIterator e) alpar@461: { alpar@461: std::vector indices; alpar@461: std::vector values; alpar@461: for(ExprIterator it=b; it!=e; ++it) { alpar@461: indices.push_back(it->first); alpar@461: values.push_back(it->second); alpar@461: } alpar@461: CPXchgobj(cplexEnv(), _prob, values.size(), alpar@461: &indices.front(), &values.front()); alpar@461: alpar@461: } alpar@461: alpar@461: void CplexBase::_getObjCoeffs(InsertIterator b) const alpar@461: { alpar@461: int num = CPXgetnumcols(cplexEnv(), _prob); alpar@461: std::vector x(num); alpar@461: alpar@461: CPXgetobj(cplexEnv(), _prob, &x.front(), 0, num - 1); alpar@461: for (int i = 0; i < num; ++i) { alpar@461: if (x[i] != 0.0) { alpar@461: *b = std::make_pair(i, x[i]); alpar@461: ++b; alpar@461: } alpar@461: } alpar@461: } alpar@461: alpar@461: void CplexBase::_setObjCoeff(int i, Value obj_coef) alpar@461: { alpar@461: CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef); alpar@461: } alpar@461: alpar@461: CplexBase::Value CplexBase::_getObjCoeff(int i) const alpar@461: { alpar@461: Value x; alpar@461: CPXgetobj(cplexEnv(), _prob, &x, i, i); alpar@461: return x; alpar@461: } alpar@461: alpar@461: void CplexBase::_setSense(CplexBase::Sense sense) { alpar@461: switch (sense) { alpar@461: case MIN: alpar@461: CPXchgobjsen(cplexEnv(), _prob, CPX_MIN); alpar@461: break; alpar@461: case MAX: alpar@461: CPXchgobjsen(cplexEnv(), _prob, CPX_MAX); alpar@461: break; alpar@461: } alpar@461: } alpar@461: alpar@461: CplexBase::Sense CplexBase::_getSense() const { alpar@461: switch (CPXgetobjsen(cplexEnv(), _prob)) { alpar@461: case CPX_MIN: alpar@461: return MIN; alpar@461: case CPX_MAX: alpar@461: return MAX; alpar@461: default: alpar@461: LEMON_ASSERT(false, "Invalid sense"); alpar@461: return CplexBase::Sense(); alpar@461: } alpar@461: } alpar@461: alpar@461: void CplexBase::_clear() { alpar@461: CPXfreeprob(cplexEnv(),&_prob); alpar@461: int status; alpar@461: _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); alpar@461: } alpar@461: deba@576: void CplexBase::_messageLevel(MessageLevel level) { deba@576: switch (level) { deba@576: case MESSAGE_NOTHING: deba@576: _message_enabled = false; deba@576: break; deba@576: case MESSAGE_ERROR: deba@576: case MESSAGE_WARNING: deba@576: case MESSAGE_NORMAL: deba@576: case MESSAGE_VERBOSE: deba@576: _message_enabled = true; deba@576: break; deba@576: } deba@576: } deba@576: deba@576: void CplexBase::_applyMessageLevel() { alpar@877: CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND, deba@576: _message_enabled ? CPX_ON : CPX_OFF); deba@576: } deba@576: alpar@1063: void CplexBase::_write(std::string file, std::string format) const alpar@1063: { alpar@1063: if(format == "MPS" || format == "LP") alpar@1063: CPXwriteprob(cplexEnv(), cplexLp(), file.c_str(), format.c_str()); alpar@1063: else if(format == "SOL") alpar@1063: CPXsolwrite(cplexEnv(), cplexLp(), file.c_str()); alpar@1063: else throw UnsupportedFormatError(format); alpar@1063: } alpar@1063: alpar@1063: alpar@1063: alpar@462: // CplexLp members alpar@461: alpar@462: CplexLp::CplexLp() deba@551: : LpBase(), LpSolver(), CplexBase() {} alpar@461: alpar@462: CplexLp::CplexLp(const CplexEnv& env) deba@551: : LpBase(), LpSolver(), CplexBase(env) {} alpar@461: alpar@462: CplexLp::CplexLp(const CplexLp& other) deba@551: : LpBase(), LpSolver(), CplexBase(other) {} alpar@461: alpar@462: CplexLp::~CplexLp() {} alpar@461: alpar@540: CplexLp* CplexLp::newSolver() const { return new CplexLp; } alpar@540: CplexLp* CplexLp::cloneSolver() const {return new CplexLp(*this); } alpar@461: alpar@462: const char* CplexLp::_solverName() const { return "CplexLp"; } alpar@461: alpar@462: void CplexLp::_clear_temporals() { alpar@461: _col_status.clear(); alpar@461: _row_status.clear(); alpar@461: _primal_ray.clear(); alpar@461: _dual_ray.clear(); alpar@461: } alpar@461: alpar@461: // The routine returns zero unless an error occurred during the alpar@461: // optimization. Examples of errors include exhausting available alpar@461: // memory (CPXERR_NO_MEMORY) or encountering invalid data in the alpar@461: // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a alpar@461: // user-specified CPLEX limit, or proving the model infeasible or alpar@461: // unbounded, are not considered errors. Note that a zero return alpar@461: // value does not necessarily mean that a solution exists. Use query alpar@461: // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain alpar@461: // further information about the status of the optimization. alpar@462: CplexLp::SolveExitStatus CplexLp::convertStatus(int status) { alpar@461: #if CPX_VERSION >= 800 alpar@461: if (status == 0) { alpar@461: switch (CPXgetstat(cplexEnv(), _prob)) { alpar@461: case CPX_STAT_OPTIMAL: alpar@461: case CPX_STAT_INFEASIBLE: alpar@461: case CPX_STAT_UNBOUNDED: alpar@461: return SOLVED; alpar@461: default: alpar@461: return UNSOLVED; alpar@461: } alpar@461: } else { alpar@461: return UNSOLVED; alpar@461: } alpar@461: #else alpar@461: if (status == 0) { alpar@461: //We want to exclude some cases alpar@461: switch (CPXgetstat(cplexEnv(), _prob)) { alpar@461: case CPX_OBJ_LIM: alpar@461: case CPX_IT_LIM_FEAS: alpar@461: case CPX_IT_LIM_INFEAS: alpar@461: case CPX_TIME_LIM_FEAS: alpar@461: case CPX_TIME_LIM_INFEAS: alpar@461: return UNSOLVED; alpar@461: default: alpar@461: return SOLVED; alpar@461: } alpar@461: } else { alpar@461: return UNSOLVED; alpar@461: } alpar@461: #endif alpar@461: } alpar@461: alpar@462: CplexLp::SolveExitStatus CplexLp::_solve() { alpar@461: _clear_temporals(); deba@576: _applyMessageLevel(); alpar@461: return convertStatus(CPXlpopt(cplexEnv(), _prob)); alpar@461: } alpar@461: alpar@462: CplexLp::SolveExitStatus CplexLp::solvePrimal() { alpar@461: _clear_temporals(); deba@576: _applyMessageLevel(); alpar@461: return convertStatus(CPXprimopt(cplexEnv(), _prob)); alpar@461: } alpar@461: alpar@462: CplexLp::SolveExitStatus CplexLp::solveDual() { alpar@461: _clear_temporals(); deba@576: _applyMessageLevel(); alpar@461: return convertStatus(CPXdualopt(cplexEnv(), _prob)); alpar@461: } alpar@461: alpar@462: CplexLp::SolveExitStatus CplexLp::solveBarrier() { alpar@461: _clear_temporals(); deba@576: _applyMessageLevel(); alpar@461: return convertStatus(CPXbaropt(cplexEnv(), _prob)); alpar@461: } alpar@461: alpar@462: CplexLp::Value CplexLp::_getPrimal(int i) const { alpar@461: Value x; alpar@461: CPXgetx(cplexEnv(), _prob, &x, i, i); alpar@461: return x; alpar@461: } alpar@461: alpar@462: CplexLp::Value CplexLp::_getDual(int i) const { alpar@461: Value y; alpar@461: CPXgetpi(cplexEnv(), _prob, &y, i, i); alpar@461: return y; alpar@461: } alpar@461: alpar@462: CplexLp::Value CplexLp::_getPrimalValue() const { alpar@461: Value objval; alpar@461: CPXgetobjval(cplexEnv(), _prob, &objval); alpar@461: return objval; alpar@461: } alpar@461: alpar@462: CplexLp::VarStatus CplexLp::_getColStatus(int i) const { alpar@461: if (_col_status.empty()) { alpar@461: _col_status.resize(CPXgetnumcols(cplexEnv(), _prob)); alpar@461: CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0); alpar@461: } alpar@461: switch (_col_status[i]) { alpar@461: case CPX_BASIC: alpar@461: return BASIC; alpar@461: case CPX_FREE_SUPER: alpar@461: return FREE; alpar@461: case CPX_AT_LOWER: alpar@461: return LOWER; alpar@461: case CPX_AT_UPPER: alpar@461: return UPPER; alpar@461: default: alpar@461: LEMON_ASSERT(false, "Wrong column status"); alpar@462: return CplexLp::VarStatus(); alpar@461: } alpar@461: } alpar@461: alpar@462: CplexLp::VarStatus CplexLp::_getRowStatus(int i) const { alpar@461: if (_row_status.empty()) { alpar@461: _row_status.resize(CPXgetnumrows(cplexEnv(), _prob)); alpar@461: CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front()); alpar@461: } alpar@461: switch (_row_status[i]) { alpar@461: case CPX_BASIC: alpar@461: return BASIC; alpar@461: case CPX_AT_LOWER: alpar@461: { alpar@461: char s; alpar@461: CPXgetsense(cplexEnv(), _prob, &s, i, i); alpar@461: return s != 'L' ? LOWER : UPPER; alpar@461: } alpar@461: case CPX_AT_UPPER: alpar@461: return UPPER; alpar@461: default: alpar@461: LEMON_ASSERT(false, "Wrong row status"); alpar@462: return CplexLp::VarStatus(); alpar@461: } alpar@461: } alpar@461: alpar@462: CplexLp::Value CplexLp::_getPrimalRay(int i) const { alpar@461: if (_primal_ray.empty()) { alpar@461: _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob)); alpar@461: CPXgetray(cplexEnv(), _prob, &_primal_ray.front()); alpar@461: } alpar@461: return _primal_ray[i]; alpar@461: } alpar@461: alpar@462: CplexLp::Value CplexLp::_getDualRay(int i) const { alpar@461: if (_dual_ray.empty()) { alpar@461: alpar@461: } alpar@461: return _dual_ray[i]; alpar@461: } alpar@461: deba@576: // Cplex 7.0 status values alpar@461: // This table lists the statuses, returned by the CPXgetstat() alpar@461: // routine, for solutions to LP problems or mixed integer problems. If alpar@461: // no solution exists, the return value is zero. alpar@461: alpar@461: // For Simplex, Barrier alpar@461: // 1 CPX_OPTIMAL alpar@461: // Optimal solution found alpar@461: // 2 CPX_INFEASIBLE alpar@461: // Problem infeasible alpar@461: // 3 CPX_UNBOUNDED alpar@461: // Problem unbounded alpar@461: // 4 CPX_OBJ_LIM alpar@461: // Objective limit exceeded in Phase II alpar@461: // 5 CPX_IT_LIM_FEAS alpar@461: // Iteration limit exceeded in Phase II alpar@461: // 6 CPX_IT_LIM_INFEAS alpar@461: // Iteration limit exceeded in Phase I alpar@461: // 7 CPX_TIME_LIM_FEAS alpar@461: // Time limit exceeded in Phase II alpar@461: // 8 CPX_TIME_LIM_INFEAS alpar@461: // Time limit exceeded in Phase I alpar@461: // 9 CPX_NUM_BEST_FEAS alpar@461: // Problem non-optimal, singularities in Phase II alpar@461: // 10 CPX_NUM_BEST_INFEAS alpar@461: // Problem non-optimal, singularities in Phase I alpar@461: // 11 CPX_OPTIMAL_INFEAS alpar@461: // Optimal solution found, unscaled infeasibilities alpar@461: // 12 CPX_ABORT_FEAS alpar@461: // Aborted in Phase II alpar@461: // 13 CPX_ABORT_INFEAS alpar@461: // Aborted in Phase I alpar@461: // 14 CPX_ABORT_DUAL_INFEAS alpar@461: // Aborted in barrier, dual infeasible alpar@461: // 15 CPX_ABORT_PRIM_INFEAS alpar@461: // Aborted in barrier, primal infeasible alpar@461: // 16 CPX_ABORT_PRIM_DUAL_INFEAS alpar@461: // Aborted in barrier, primal and dual infeasible alpar@461: // 17 CPX_ABORT_PRIM_DUAL_FEAS alpar@461: // Aborted in barrier, primal and dual feasible alpar@461: // 18 CPX_ABORT_CROSSOVER alpar@461: // Aborted in crossover alpar@461: // 19 CPX_INForUNBD alpar@461: // Infeasible or unbounded alpar@461: // 20 CPX_PIVOT alpar@461: // User pivot used alpar@461: // deba@576: // Pending return values alpar@461: // ??case CPX_ABORT_DUAL_INFEAS alpar@461: // ??case CPX_ABORT_CROSSOVER alpar@461: // ??case CPX_INForUNBD alpar@461: // ??case CPX_PIVOT alpar@461: alpar@461: //Some more interesting stuff: alpar@461: alpar@461: // CPX_PARAM_PROBMETHOD 1062 int LPMETHOD alpar@461: // 0 Automatic alpar@461: // 1 Primal Simplex alpar@461: // 2 Dual Simplex alpar@461: // 3 Network Simplex alpar@461: // 4 Standard Barrier alpar@461: // Default: 0 alpar@461: // Description: Method for linear optimization. alpar@461: // Determines which algorithm is used when CPXlpopt() (or "optimize" alpar@461: // in the Interactive Optimizer) is called. Currently the behavior of alpar@461: // the "Automatic" setting is that CPLEX simply invokes the dual alpar@461: // simplex method, but this capability may be expanded in the future alpar@461: // so that CPLEX chooses the method based on problem characteristics alpar@461: #if CPX_VERSION < 900 alpar@461: void statusSwitch(CPXENVptr cplexEnv(),int& stat){ alpar@461: int lpmethod; alpar@461: CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod); alpar@461: if (lpmethod==2){ alpar@461: if (stat==CPX_UNBOUNDED){ alpar@461: stat=CPX_INFEASIBLE; alpar@461: } alpar@461: else{ alpar@461: if (stat==CPX_INFEASIBLE) alpar@461: stat=CPX_UNBOUNDED; alpar@461: } alpar@461: } alpar@461: } alpar@461: #else alpar@461: void statusSwitch(CPXENVptr,int&){} alpar@461: #endif alpar@461: alpar@462: CplexLp::ProblemType CplexLp::_getPrimalType() const { alpar@461: // Unboundedness not treated well: the following is from cplex 9.0 doc alpar@461: // About Unboundedness alpar@461: alpar@461: // The treatment of models that are unbounded involves a few alpar@461: // subtleties. Specifically, a declaration of unboundedness means that alpar@461: // ILOG CPLEX has determined that the model has an unbounded alpar@461: // ray. Given any feasible solution x with objective z, a multiple of alpar@461: // the unbounded ray can be added to x to give a feasible solution alpar@461: // with objective z-1 (or z+1 for maximization models). Thus, if a alpar@461: // feasible solution exists, then the optimal objective is alpar@461: // unbounded. Note that ILOG CPLEX has not necessarily concluded that alpar@461: // a feasible solution exists. Users can call the routine CPXsolninfo alpar@461: // to determine whether ILOG CPLEX has also concluded that the model alpar@461: // has a feasible solution. alpar@461: alpar@461: int stat = CPXgetstat(cplexEnv(), _prob); alpar@461: #if CPX_VERSION >= 800 alpar@461: switch (stat) alpar@461: { alpar@461: case CPX_STAT_OPTIMAL: alpar@461: return OPTIMAL; alpar@461: case CPX_STAT_UNBOUNDED: alpar@461: return UNBOUNDED; alpar@461: case CPX_STAT_INFEASIBLE: alpar@461: return INFEASIBLE; alpar@461: default: alpar@461: return UNDEFINED; alpar@461: } alpar@461: #else alpar@461: statusSwitch(cplexEnv(),stat); alpar@461: //CPXgetstat(cplexEnv(), _prob); alpar@461: switch (stat) { alpar@461: case 0: alpar@461: return UNDEFINED; //Undefined alpar@461: case CPX_OPTIMAL://Optimal alpar@461: return OPTIMAL; alpar@461: case CPX_UNBOUNDED://Unbounded alpar@461: return INFEASIBLE;//In case of dual simplex alpar@461: //return UNBOUNDED; alpar@461: case CPX_INFEASIBLE://Infeasible alpar@461: // case CPX_IT_LIM_INFEAS: alpar@461: // case CPX_TIME_LIM_INFEAS: alpar@461: // case CPX_NUM_BEST_INFEAS: alpar@461: // case CPX_OPTIMAL_INFEAS: alpar@461: // case CPX_ABORT_INFEAS: alpar@461: // case CPX_ABORT_PRIM_INFEAS: alpar@461: // case CPX_ABORT_PRIM_DUAL_INFEAS: alpar@461: return UNBOUNDED;//In case of dual simplex alpar@461: //return INFEASIBLE; alpar@461: // case CPX_OBJ_LIM: alpar@461: // case CPX_IT_LIM_FEAS: alpar@461: // case CPX_TIME_LIM_FEAS: alpar@461: // case CPX_NUM_BEST_FEAS: alpar@461: // case CPX_ABORT_FEAS: alpar@461: // case CPX_ABORT_PRIM_DUAL_FEAS: alpar@461: // return FEASIBLE; alpar@461: default: alpar@461: return UNDEFINED; //Everything else comes here alpar@461: //FIXME error alpar@461: } alpar@461: #endif alpar@461: } alpar@461: deba@576: // Cplex 9.0 status values alpar@461: // CPX_STAT_ABORT_DUAL_OBJ_LIM alpar@461: // CPX_STAT_ABORT_IT_LIM alpar@461: // CPX_STAT_ABORT_OBJ_LIM alpar@461: // CPX_STAT_ABORT_PRIM_OBJ_LIM alpar@461: // CPX_STAT_ABORT_TIME_LIM alpar@461: // CPX_STAT_ABORT_USER alpar@461: // CPX_STAT_FEASIBLE_RELAXED alpar@461: // CPX_STAT_INFEASIBLE alpar@461: // CPX_STAT_INForUNBD alpar@461: // CPX_STAT_NUM_BEST alpar@461: // CPX_STAT_OPTIMAL alpar@461: // CPX_STAT_OPTIMAL_FACE_UNBOUNDED alpar@461: // CPX_STAT_OPTIMAL_INFEAS alpar@461: // CPX_STAT_OPTIMAL_RELAXED alpar@461: // CPX_STAT_UNBOUNDED alpar@461: alpar@462: CplexLp::ProblemType CplexLp::_getDualType() const { alpar@461: int stat = CPXgetstat(cplexEnv(), _prob); alpar@461: #if CPX_VERSION >= 800 alpar@461: switch (stat) { alpar@461: case CPX_STAT_OPTIMAL: alpar@461: return OPTIMAL; alpar@461: case CPX_STAT_UNBOUNDED: alpar@461: return INFEASIBLE; alpar@461: default: alpar@461: return UNDEFINED; alpar@461: } alpar@461: #else alpar@461: statusSwitch(cplexEnv(),stat); alpar@461: switch (stat) { alpar@461: case 0: alpar@461: return UNDEFINED; //Undefined alpar@461: case CPX_OPTIMAL://Optimal alpar@461: return OPTIMAL; alpar@461: case CPX_UNBOUNDED: alpar@461: return INFEASIBLE; alpar@461: default: alpar@461: return UNDEFINED; //Everything else comes here alpar@461: //FIXME error alpar@461: } alpar@461: #endif alpar@461: } alpar@461: alpar@462: // CplexMip members alpar@461: alpar@462: CplexMip::CplexMip() deba@551: : LpBase(), MipSolver(), CplexBase() { alpar@461: alpar@461: #if CPX_VERSION < 800 alpar@461: CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP); alpar@461: #else alpar@461: CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP); alpar@461: #endif alpar@461: } alpar@461: alpar@462: CplexMip::CplexMip(const CplexEnv& env) deba@551: : LpBase(), MipSolver(), CplexBase(env) { alpar@461: alpar@461: #if CPX_VERSION < 800 alpar@461: CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP); alpar@461: #else alpar@461: CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP); alpar@461: #endif alpar@461: alpar@461: } alpar@461: alpar@462: CplexMip::CplexMip(const CplexMip& other) deba@551: : LpBase(), MipSolver(), CplexBase(other) {} alpar@461: alpar@462: CplexMip::~CplexMip() {} alpar@461: alpar@540: CplexMip* CplexMip::newSolver() const { return new CplexMip; } alpar@540: CplexMip* CplexMip::cloneSolver() const {return new CplexMip(*this); } alpar@461: alpar@462: const char* CplexMip::_solverName() const { return "CplexMip"; } alpar@461: alpar@462: void CplexMip::_setColType(int i, CplexMip::ColTypes col_type) { alpar@461: alpar@461: // Note If a variable is to be changed to binary, a call to CPXchgbds alpar@461: // should also be made to change the bounds to 0 and 1. alpar@461: alpar@461: switch (col_type){ alpar@461: case INTEGER: { alpar@461: const char t = 'I'; alpar@461: CPXchgctype (cplexEnv(), _prob, 1, &i, &t); alpar@461: } break; alpar@461: case REAL: { alpar@461: const char t = 'C'; alpar@461: CPXchgctype (cplexEnv(), _prob, 1, &i, &t); alpar@461: } break; alpar@461: default: alpar@461: break; alpar@461: } alpar@461: } alpar@461: alpar@462: CplexMip::ColTypes CplexMip::_getColType(int i) const { alpar@461: char t; alpar@461: CPXgetctype (cplexEnv(), _prob, &t, i, i); alpar@461: switch (t) { alpar@461: case 'I': alpar@461: return INTEGER; alpar@461: case 'C': alpar@461: return REAL; alpar@461: default: alpar@461: LEMON_ASSERT(false, "Invalid column type"); alpar@461: return ColTypes(); alpar@461: } alpar@461: alpar@461: } alpar@461: alpar@462: CplexMip::SolveExitStatus CplexMip::_solve() { alpar@461: int status; deba@576: _applyMessageLevel(); alpar@461: status = CPXmipopt (cplexEnv(), _prob); alpar@461: if (status==0) alpar@461: return SOLVED; alpar@461: else alpar@461: return UNSOLVED; alpar@461: alpar@461: } alpar@461: alpar@461: alpar@462: CplexMip::ProblemType CplexMip::_getType() const { alpar@461: alpar@461: int stat = CPXgetstat(cplexEnv(), _prob); alpar@461: alpar@461: //Fortunately, MIP statuses did not change for cplex 8.0 alpar@461: switch (stat) { alpar@461: case CPXMIP_OPTIMAL: alpar@461: // Optimal integer solution has been found. alpar@461: case CPXMIP_OPTIMAL_TOL: alpar@461: // Optimal soluton with the tolerance defined by epgap or epagap has alpar@461: // been found. alpar@461: return OPTIMAL; alpar@461: //This also exists in later issues alpar@461: // case CPXMIP_UNBOUNDED: alpar@461: //return UNBOUNDED; alpar@461: case CPXMIP_INFEASIBLE: alpar@461: return INFEASIBLE; alpar@461: default: alpar@461: return UNDEFINED; alpar@461: } alpar@461: //Unboundedness not treated well: the following is from cplex 9.0 doc alpar@461: // About Unboundedness alpar@461: alpar@461: // The treatment of models that are unbounded involves a few alpar@461: // subtleties. Specifically, a declaration of unboundedness means that alpar@461: // ILOG CPLEX has determined that the model has an unbounded alpar@461: // ray. Given any feasible solution x with objective z, a multiple of alpar@461: // the unbounded ray can be added to x to give a feasible solution alpar@461: // with objective z-1 (or z+1 for maximization models). Thus, if a alpar@461: // feasible solution exists, then the optimal objective is alpar@461: // unbounded. Note that ILOG CPLEX has not necessarily concluded that alpar@461: // a feasible solution exists. Users can call the routine CPXsolninfo alpar@461: // to determine whether ILOG CPLEX has also concluded that the model alpar@461: // has a feasible solution. alpar@461: } alpar@461: alpar@462: CplexMip::Value CplexMip::_getSol(int i) const { alpar@461: Value x; alpar@461: CPXgetmipx(cplexEnv(), _prob, &x, i, i); alpar@461: return x; alpar@461: } alpar@461: alpar@462: CplexMip::Value CplexMip::_getSolValue() const { alpar@461: Value objval; alpar@461: CPXgetmipobjval(cplexEnv(), _prob, &objval); alpar@461: return objval; alpar@461: } alpar@461: alpar@461: } //namespace lemon alpar@461: