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