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@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@458: LpCplex::LpCplex() { deba@458: // env = CPXopenCPLEXdevelop(&status); deba@458: env = CPXopenCPLEX(&status); deba@458: lp = CPXcreateprob(env, &status, "LP problem"); deba@458: } deba@458: deba@458: LpCplex::LpCplex(const LpCplex& cplex) : LpSolverBase() { deba@458: env = CPXopenCPLEX(&status); deba@458: lp = CPXcloneprob(env, cplex.lp, &status); deba@458: rows = cplex.rows; deba@458: cols = cplex.cols; deba@458: } deba@458: deba@458: LpCplex::~LpCplex() { deba@458: CPXfreeprob(env,&lp); deba@458: CPXcloseCPLEX(&env); deba@458: } deba@458: deba@458: LpSolverBase* LpCplex::_newLp() deba@458: { deba@458: //The first approach opens a new environment deba@458: return new LpCplex(); deba@458: } deba@458: deba@458: LpSolverBase* LpCplex::_copyLp() { deba@458: return new LpCplex(*this); deba@458: } deba@458: deba@458: int LpCplex::_addCol() deba@458: { deba@458: int i = CPXgetnumcols(env, lp); deba@458: Value lb[1],ub[1]; deba@458: lb[0]=-INF; deba@458: ub[0]=INF; deba@458: status = CPXnewcols(env, lp, 1, NULL, lb, ub, NULL, NULL); deba@458: return i; deba@458: } deba@458: deba@458: deba@458: int LpCplex::_addRow() deba@458: { deba@458: //We want a row that is not constrained deba@458: char sense[1]; deba@458: sense[0]='L';//<= constraint deba@458: Value rhs[1]; deba@458: rhs[0]=INF; deba@458: int i = CPXgetnumrows(env, lp); deba@458: status = CPXnewrows(env, lp, 1, rhs, sense, NULL, NULL); deba@458: return i; deba@458: } deba@458: deba@458: deba@458: void LpCplex::_eraseCol(int i) { deba@458: CPXdelcols(env, lp, i, i); deba@458: } deba@458: deba@458: void LpCplex::_eraseRow(int i) { deba@458: CPXdelrows(env, lp, i, i); deba@458: } deba@458: deba@458: void LpCplex::_getColName(int col, std::string &name) const deba@458: { deba@458: ///\bug Untested deba@458: int storespace; deba@458: CPXgetcolname(env, lp, 0, 0, 0, &storespace, col, col); deba@458: if (storespace == 0) { deba@458: name.clear(); deba@458: return; deba@458: } deba@458: deba@458: storespace *= -1; deba@458: std::vector buf(storespace); deba@458: char *names[1]; deba@458: int dontcare; deba@458: ///\bug return code unchecked for error deba@458: CPXgetcolname(env, lp, names, &*buf.begin(), storespace, deba@458: &dontcare, col, col); deba@458: name = names[0]; deba@458: } deba@458: deba@458: void LpCplex::_setColName(int col, const std::string &name) deba@458: { deba@458: ///\bug Untested deba@458: char *names[1]; deba@458: names[0] = const_cast(name.c_str()); deba@458: ///\bug return code unchecked for error deba@458: CPXchgcolname(env, lp, 1, &col, names); deba@458: } deba@458: deba@458: int LpCplex::_colByName(const std::string& name) const deba@458: { deba@458: int index; deba@458: if (CPXgetcolindex(env, lp, deba@458: const_cast(name.c_str()), &index) == 0) { deba@458: return index; deba@458: } deba@458: return -1; deba@458: } deba@458: deba@458: ///\warning Data at index 0 is ignored in the arrays. deba@458: void LpCplex::_setRowCoeffs(int i, ConstRowIterator b, ConstRowIterator e) deba@458: { deba@458: std::vector indices; deba@458: std::vector rowlist; deba@458: std::vector values; deba@458: deba@458: for(ConstRowIterator 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@458: status = CPXchgcoeflist(env, lp, values.size(), deba@458: &rowlist[0], &indices[0], &values[0]); deba@458: } deba@458: deba@458: void LpCplex::_getRowCoeffs(int i, RowIterator b) const { deba@458: int tmp1, tmp2, tmp3, length; deba@458: CPXgetrows(env, lp, &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@458: CPXgetrows(env, lp, &tmp1, &tmp2, &indices[0], &values[0], 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: /// \todo implement deba@458: } deba@458: deba@458: void LpCplex::_setColCoeffs(int i, ConstColIterator b, ConstColIterator e) deba@458: { deba@458: std::vector indices; deba@458: std::vector collist; deba@458: std::vector values; deba@458: deba@458: for(ConstColIterator 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@458: status = CPXchgcoeflist(env, lp, values.size(), deba@458: &indices[0], &collist[0], &values[0]); deba@458: } deba@458: deba@458: void LpCplex::_getColCoeffs(int i, ColIterator b) const { deba@458: deba@458: int tmp1, tmp2, tmp3, length; deba@458: CPXgetcols(env, lp, &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@458: CPXgetcols(env, lp, &tmp1, &tmp2, &indices[0], &values[0], 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@458: void LpCplex::_setCoeff(int row, int col, Value value) deba@458: { deba@458: CPXchgcoef(env, lp, row, col, value); deba@458: } deba@458: deba@458: LpCplex::Value LpCplex::_getCoeff(int row, int col) const deba@458: { deba@458: LpCplex::Value value; deba@458: CPXgetcoef(env, lp, row, col, &value); deba@458: return value; deba@458: } deba@458: deba@458: void LpCplex::_setColLowerBound(int i, Value value) deba@458: { deba@458: int indices[1]; deba@458: indices[0]=i; deba@458: char lu[1]; deba@458: lu[0]='L'; deba@458: Value bd[1]; deba@458: bd[0]=value; deba@458: status = CPXchgbds(env, lp, 1, indices, lu, bd); deba@458: deba@458: } deba@458: deba@458: LpCplex::Value LpCplex::_getColLowerBound(int i) const deba@458: { deba@458: LpCplex::Value x; deba@458: CPXgetlb (env, lp, &x, i, i); deba@458: if (x <= -CPX_INFBOUND) x = -INF; deba@458: return x; deba@458: } deba@458: deba@458: void LpCplex::_setColUpperBound(int i, Value value) deba@458: { deba@458: int indices[1]; deba@458: indices[0]=i; deba@458: char lu[1]; deba@458: lu[0]='U'; deba@458: Value bd[1]; deba@458: bd[0]=value; deba@458: status = CPXchgbds(env, lp, 1, indices, lu, bd); deba@458: } deba@458: deba@458: LpCplex::Value LpCplex::_getColUpperBound(int i) const deba@458: { deba@458: LpCplex::Value x; deba@458: CPXgetub (env, lp, &x, i, i); deba@458: if (x >= CPX_INFBOUND) x = INF; deba@458: return x; deba@458: } deba@458: deba@458: //This will be easier to implement deba@458: void LpCplex::_setRowBounds(int i, Value lb, Value ub) deba@458: { deba@458: //Bad parameter deba@458: if (lb==INF || ub==-INF) { deba@458: //FIXME error deba@458: } deba@458: deba@458: int cnt=1; deba@458: int indices[1]; deba@458: indices[0]=i; deba@458: char sense[1]; deba@458: deba@458: if (lb==-INF){ deba@458: sense[0]='L'; deba@458: CPXchgsense(env, lp, cnt, indices, sense); deba@458: CPXchgcoef(env, lp, i, -1, ub); deba@458: deba@458: } deba@458: else{ deba@458: if (ub==INF){ deba@458: sense[0]='G'; deba@458: CPXchgsense(env, lp, cnt, indices, sense); deba@458: CPXchgcoef(env, lp, i, -1, lb); deba@458: } deba@458: else{ deba@458: if (lb == ub){ deba@458: sense[0]='E'; deba@458: CPXchgsense(env, lp, cnt, indices, sense); deba@458: CPXchgcoef(env, lp, i, -1, lb); deba@458: } deba@458: else{ deba@458: sense[0]='R'; deba@458: CPXchgsense(env, lp, cnt, indices, sense); deba@458: CPXchgcoef(env, lp, i, -1, lb); deba@458: CPXchgcoef(env, lp, i, -2, ub-lb); deba@458: } deba@458: } deba@458: } deba@458: } deba@458: deba@458: // void LpCplex::_setRowLowerBound(int i, Value value) deba@458: // { deba@458: // //Not implemented, obsolete deba@458: // } deba@458: deba@458: // void LpCplex::_setRowUpperBound(int i, Value value) deba@458: // { deba@458: // //Not implemented, obsolete deba@458: // // //TODO Ezt kell meg megirni deba@458: // // //type of the problem deba@458: // // char sense[1]; deba@458: // // status = CPXgetsense(env, lp, sense, i, i); deba@458: // // Value rhs[1]; deba@458: // // status = CPXgetrhs(env, lp, rhs, i, i); deba@458: deba@458: // // switch (sense[0]) { deba@458: // // case 'L'://<= constraint deba@458: // // break; deba@458: // // case 'E'://= constraint deba@458: // // break; deba@458: // // case 'G'://>= constraint deba@458: // // break; deba@458: // // case 'R'://ranged constraint deba@458: // // break; deba@458: // // default: ; deba@458: // // //FIXME error deba@458: // // } deba@458: deba@458: // // status = CPXchgcoef(env, lp, i, -2, value_rng); deba@458: // } deba@458: deba@458: void LpCplex::_getRowBounds(int i, Value &lb, Value &ub) const deba@458: { deba@458: char sense; deba@458: CPXgetsense(env, lp, &sense,i,i); deba@458: lb=-INF; deba@458: ub=INF; deba@458: switch (sense) deba@458: { deba@458: case 'L': deba@458: CPXgetcoef(env, lp, i, -1, &ub); deba@458: break; deba@458: case 'G': deba@458: CPXgetcoef(env, lp, i, -1, &lb); deba@458: break; deba@458: case 'E': deba@458: CPXgetcoef(env, lp, i, -1, &lb); deba@458: ub=lb; deba@458: break; deba@458: case 'R': deba@458: CPXgetcoef(env, lp, i, -1, &lb); deba@458: Value x; deba@458: CPXgetcoef(env, lp, i, -2, &x); deba@458: ub=lb+x; deba@458: break; deba@458: } deba@458: } deba@458: deba@458: void LpCplex::_setObjCoeff(int i, Value obj_coef) deba@458: { deba@458: CPXchgcoef(env, lp, -1, i, obj_coef); deba@458: } deba@458: deba@458: LpCplex::Value LpCplex::_getObjCoeff(int i) const deba@458: { deba@458: Value x; deba@458: CPXgetcoef(env, lp, -1, i, &x); deba@458: return x; deba@458: } deba@458: deba@458: void LpCplex::_clearObj() deba@458: { deba@458: for (int i=0;i< CPXgetnumcols(env, lp);++i){ deba@458: CPXchgcoef(env, lp, -1, i, 0); deba@458: } deba@458: deba@458: } 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@458: LpCplex::SolveExitStatus LpCplex::_solve() deba@458: { deba@458: //CPX_PARAM_LPMETHOD deba@458: status = CPXlpopt(env, lp); deba@458: //status = CPXprimopt(env, lp); deba@458: #if CPX_VERSION >= 800 deba@458: if (status) deba@458: { deba@458: return UNSOLVED; deba@458: } deba@458: else deba@458: { deba@458: switch (CPXgetstat(env, lp)) deba@458: { deba@458: case CPX_STAT_OPTIMAL: deba@458: case CPX_STAT_INFEASIBLE: deba@458: case CPX_STAT_UNBOUNDED: deba@458: return SOLVED; deba@458: default: deba@458: return UNSOLVED; deba@458: } deba@458: } deba@458: #else deba@458: if (status == 0){ deba@458: //We want to exclude some cases deba@458: switch (CPXgetstat(env, lp)){ 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@458: } deba@458: else{ deba@458: return UNSOLVED; deba@458: } deba@458: #endif deba@458: } deba@458: deba@458: LpCplex::Value LpCplex::_getPrimal(int i) const deba@458: { deba@458: Value x; deba@458: CPXgetx(env, lp, &x, i, i); deba@458: return x; deba@458: } deba@458: deba@458: LpCplex::Value LpCplex::_getDual(int i) const deba@458: { deba@458: Value y; deba@458: CPXgetpi(env, lp, &y, i, i); deba@458: return y; deba@458: } deba@458: deba@458: LpCplex::Value LpCplex::_getPrimalValue() const deba@458: { deba@458: Value objval; deba@458: //method = CPXgetmethod (env, lp); deba@458: //printf("CPXgetprobtype %d \n",CPXgetprobtype(env,lp)); deba@458: CPXgetobjval(env, lp, &objval); deba@458: //printf("Objective value: %g \n",objval); deba@458: return objval; deba@458: } deba@458: bool LpCplex::_isBasicCol(int i) const deba@458: { deba@458: std::vector cstat(CPXgetnumcols(env, lp)); deba@458: CPXgetbase(env, lp, &*cstat.begin(), NULL); deba@458: return (cstat[i]==CPX_BASIC); deba@458: } deba@458: deba@458: //7.5-os cplex statusai (Vigyazat: a 9.0-asei masok!) deba@458: // This table lists the statuses, returned by the CPXgetstat() deba@458: // routine, for solutions to LP problems or mixed integer problems. If deba@458: // no solution exists, the return value is zero. deba@458: deba@458: // For Simplex, Barrier deba@458: // 1 CPX_OPTIMAL deba@458: // Optimal solution found deba@458: // 2 CPX_INFEASIBLE deba@458: // Problem infeasible deba@458: // 3 CPX_UNBOUNDED deba@458: // Problem unbounded deba@458: // 4 CPX_OBJ_LIM deba@458: // Objective limit exceeded in Phase II deba@458: // 5 CPX_IT_LIM_FEAS deba@458: // Iteration limit exceeded in Phase II deba@458: // 6 CPX_IT_LIM_INFEAS deba@458: // Iteration limit exceeded in Phase I deba@458: // 7 CPX_TIME_LIM_FEAS deba@458: // Time limit exceeded in Phase II deba@458: // 8 CPX_TIME_LIM_INFEAS deba@458: // Time limit exceeded in Phase I deba@458: // 9 CPX_NUM_BEST_FEAS deba@458: // Problem non-optimal, singularities in Phase II deba@458: // 10 CPX_NUM_BEST_INFEAS deba@458: // Problem non-optimal, singularities in Phase I deba@458: // 11 CPX_OPTIMAL_INFEAS deba@458: // Optimal solution found, unscaled infeasibilities deba@458: // 12 CPX_ABORT_FEAS deba@458: // Aborted in Phase II deba@458: // 13 CPX_ABORT_INFEAS deba@458: // Aborted in Phase I deba@458: // 14 CPX_ABORT_DUAL_INFEAS deba@458: // Aborted in barrier, dual infeasible deba@458: // 15 CPX_ABORT_PRIM_INFEAS deba@458: // Aborted in barrier, primal infeasible deba@458: // 16 CPX_ABORT_PRIM_DUAL_INFEAS deba@458: // Aborted in barrier, primal and dual infeasible deba@458: // 17 CPX_ABORT_PRIM_DUAL_FEAS deba@458: // Aborted in barrier, primal and dual feasible deba@458: // 18 CPX_ABORT_CROSSOVER deba@458: // Aborted in crossover deba@458: // 19 CPX_INForUNBD deba@458: // Infeasible or unbounded deba@458: // 20 CPX_PIVOT deba@458: // User pivot used deba@458: // deba@458: // Ezeket hova tegyem: deba@458: // ??case CPX_ABORT_DUAL_INFEAS deba@458: // ??case CPX_ABORT_CROSSOVER deba@458: // ??case CPX_INForUNBD deba@458: // ??case CPX_PIVOT deba@458: deba@458: //Some more interesting stuff: deba@458: deba@458: // CPX_PARAM_LPMETHOD 1062 int LPMETHOD deba@458: // 0 Automatic deba@458: // 1 Primal Simplex deba@458: // 2 Dual Simplex deba@458: // 3 Network Simplex deba@458: // 4 Standard Barrier deba@458: // Default: 0 deba@458: // Description: Method for linear optimization. deba@458: // Determines which algorithm is used when CPXlpopt() (or "optimize" deba@458: // in the Interactive Optimizer) is called. Currently the behavior of deba@458: // the "Automatic" setting is that CPLEX simply invokes the dual deba@458: // simplex method, but this capability may be expanded in the future deba@458: // so that CPLEX chooses the method based on problem characteristics deba@458: #if CPX_VERSION < 900 deba@458: void statusSwitch(CPXENVptr env,int& stat){ deba@458: int lpmethod; deba@458: CPXgetintparam (env,CPX_PARAM_LPMETHOD,&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@458: LpCplex::SolutionStatus LpCplex::_getPrimalStatus() const deba@458: { 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: int stat = CPXgetstat(env, lp); deba@458: #if CPX_VERSION >= 800 deba@458: switch (stat) deba@458: { deba@458: case CPX_STAT_OPTIMAL: deba@458: return OPTIMAL; deba@458: case CPX_STAT_UNBOUNDED: deba@458: return INFINITE; deba@458: case CPX_STAT_INFEASIBLE: deba@458: return INFEASIBLE; deba@458: default: deba@458: return UNDEFINED; deba@458: } deba@458: #else deba@458: statusSwitch(env,stat); deba@458: //CPXgetstat(env, lp); deba@458: //printf("A primal status: %d, CPX_OPTIMAL=%d \n",stat,CPX_OPTIMAL); deba@458: switch (stat) { deba@458: case 0: deba@458: return UNDEFINED; //Undefined deba@458: case CPX_OPTIMAL://Optimal deba@458: return OPTIMAL; deba@458: case CPX_UNBOUNDED://Unbounded deba@458: return INFEASIBLE;//In case of dual simplex deba@458: //return INFINITE; deba@458: case CPX_INFEASIBLE://Infeasible deba@458: // case CPX_IT_LIM_INFEAS: deba@458: // case CPX_TIME_LIM_INFEAS: deba@458: // case CPX_NUM_BEST_INFEAS: deba@458: // case CPX_OPTIMAL_INFEAS: deba@458: // case CPX_ABORT_INFEAS: deba@458: // case CPX_ABORT_PRIM_INFEAS: deba@458: // case CPX_ABORT_PRIM_DUAL_INFEAS: deba@458: return INFINITE;//In case of dual simplex deba@458: //return INFEASIBLE; deba@458: // case CPX_OBJ_LIM: deba@458: // case CPX_IT_LIM_FEAS: deba@458: // case CPX_TIME_LIM_FEAS: deba@458: // case CPX_NUM_BEST_FEAS: deba@458: // case CPX_ABORT_FEAS: deba@458: // case CPX_ABORT_PRIM_DUAL_FEAS: deba@458: // return FEASIBLE; deba@458: default: deba@458: return UNDEFINED; //Everything else comes here deba@458: //FIXME error deba@458: } deba@458: #endif deba@458: } deba@458: deba@458: //9.0-as cplex verzio statusai deba@458: // CPX_STAT_ABORT_DUAL_OBJ_LIM deba@458: // CPX_STAT_ABORT_IT_LIM deba@458: // CPX_STAT_ABORT_OBJ_LIM deba@458: // CPX_STAT_ABORT_PRIM_OBJ_LIM deba@458: // CPX_STAT_ABORT_TIME_LIM deba@458: // CPX_STAT_ABORT_USER deba@458: // CPX_STAT_FEASIBLE_RELAXED deba@458: // CPX_STAT_INFEASIBLE deba@458: // CPX_STAT_INForUNBD deba@458: // CPX_STAT_NUM_BEST deba@458: // CPX_STAT_OPTIMAL deba@458: // CPX_STAT_OPTIMAL_FACE_UNBOUNDED deba@458: // CPX_STAT_OPTIMAL_INFEAS deba@458: // CPX_STAT_OPTIMAL_RELAXED deba@458: // CPX_STAT_UNBOUNDED deba@458: deba@458: LpCplex::SolutionStatus LpCplex::_getDualStatus() const deba@458: { deba@458: int stat = CPXgetstat(env, lp); deba@458: #if CPX_VERSION >= 800 deba@458: switch (stat) deba@458: { deba@458: case CPX_STAT_OPTIMAL: deba@458: return OPTIMAL; deba@458: case CPX_STAT_UNBOUNDED: deba@458: return INFEASIBLE; deba@458: default: deba@458: return UNDEFINED; deba@458: } deba@458: #else deba@458: statusSwitch(env,stat); deba@458: switch (stat) { deba@458: case 0: deba@458: return UNDEFINED; //Undefined deba@458: case CPX_OPTIMAL://Optimal deba@458: return OPTIMAL; deba@458: case CPX_UNBOUNDED: deba@458: return INFEASIBLE; deba@458: default: deba@458: return UNDEFINED; //Everything else comes here deba@458: //FIXME error deba@458: } deba@458: #endif deba@458: } deba@458: deba@458: LpCplex::ProblemTypes LpCplex::_getProblemType() const deba@458: { deba@458: int stat = CPXgetstat(env, lp); deba@458: #if CPX_VERSION >= 800 deba@458: switch (stat) deba@458: { deba@458: case CPX_STAT_OPTIMAL: deba@458: return PRIMAL_DUAL_FEASIBLE; deba@458: case CPX_STAT_UNBOUNDED: deba@458: return PRIMAL_FEASIBLE_DUAL_INFEASIBLE; deba@458: default: deba@458: return UNKNOWN; deba@458: } deba@458: #else deba@458: switch (stat) { deba@458: case CPX_OPTIMAL://Optimal deba@458: return PRIMAL_DUAL_FEASIBLE; deba@458: case CPX_UNBOUNDED: deba@458: return PRIMAL_FEASIBLE_DUAL_INFEASIBLE; deba@458: // return PRIMAL_INFEASIBLE_DUAL_FEASIBLE; deba@458: // return PRIMAL_DUAL_INFEASIBLE; deba@458: deba@458: //Seems to be that this is all we can say for sure deba@458: default: deba@458: //In all other cases deba@458: return UNKNOWN; deba@458: //FIXME error deba@458: } deba@458: #endif deba@458: } deba@458: deba@458: void LpCplex::_setMax() deba@458: { deba@458: CPXchgobjsen(env, lp, CPX_MAX); deba@458: } deba@458: void LpCplex::_setMin() deba@458: { deba@458: CPXchgobjsen(env, lp, CPX_MIN); deba@458: } deba@458: deba@458: bool LpCplex::_isMax() const deba@458: { deba@458: if (CPXgetobjsen(env, lp)==CPX_MAX) deba@458: return true; deba@458: else deba@458: return false; deba@458: } deba@458: deba@458: } //namespace lemon deba@458: