int main (int argc, char **argv) { IloEnv env; try { IloCplex cplex(env); IloTimer timer(env); const IloNum startTime = cplex.getCplexTime(); parseCommandLine(argc, argv); printCommandLine(argc, argv); // set all default constraint weights as zero consWts["NonOperatorsAtMostOnce"] = 0; consWts["StackDepthUpperBound"] = 0; consWts["ExactlyOneUnknown"] = 0; consWts["NoTwoConsecutiveMultiplications"] = 0; // note: this may be disabled if word "dozen" appears consWts["NoTwoConsecutiveDivisions"] = 0; consWts["NoConsecutiveMultAndDiv"] = 0; consWts["NoNegatives"] = 0; consWts["TypeConsistency"] = 0; consWts["EqualityFirstOrLast"] = 0; consWts["IntConstantsImplyIntUnknown"] = 0; consWts["PreserveOrderingInText"] = 0; consWts["UnknownFirstOrLast"] = 0; consWts["EqualityNextToUnknown"] = 0; consWts["HasAddition"] = 0; consWts["HasSubtraction"] = 0; consWts["HasMultiplication"] = 0; consWts["HasDivision"] = 0; // parse config file defining constraint weights parseConfigFile(param_wts_config_file); cout << "Starting IloTimer" << endl; timer.start(); // parse arithmetic model parameters; note: this may override previously // set constraint weights if (strlen(arith_filename) > 0) parseInputFile(arith_filename); // set cplex paramters setCplexParameters(cplex); // import or build the model IloModel model(env); IloObjective obj(env); IloNumVarArray corevars(env); IloRangeArray rngs(env); if (strlen(mip_filename) > 0) { cout << "------- Importing the model -------" << endl; cplex.importModel(model, mip_filename, obj, corevars, rngs); cout << "Model imported at " << (cplex.getCplexTime() - startTime) << " sec" << endl; } else { cout << "------- Building the model -------" << endl; buildArithmeticModel(model, obj, corevars, rngs); } int nvars = corevars.getSize(); cout << "Number of Core Variables: " << nvars << endl; cplex.extract(model); cout << "Model extracted at " << (cplex.getCplexTime() - startTime) << " sec" << endl; // save the MIP model to a file, if desired if (!param_savemodel.empty()) { cout << endl << "Saving generated MIP model to " << param_savemodel << endl << endl; cplex.exportModel(param_savemodel.c_str()); } // find out whether it is a minimization problem or a maximization one bool isMinimization = true; if (cplex.getObjective().getSense() == IloObjective::Maximize) isMinimization = false; // ask cplex to use MIPInfoCallback cplex.use(MIPInfoCallback(env, isMinimization, cplex, startTime)); cout << "------- Solving the extracted model -------" << endl; //const bool solutionFound = cplex.solve(); const bool solutionFound = (param_nsolutions > 1 ? cplex.populate() : cplex.solve()); const int nSolutionsFound = cplex.getSolnPoolNsolns(); cout << "Stopping IloTimer" << endl; timer.stop(); const IloNum endTime = cplex.getCplexTime(); cout << "-------------------------------------------" << endl; printCommandLine(argc, argv); cout << "-------------------------------------------" << endl; cout << "Number of cplex nodes = " << cplex.getNnodes() << endl; cout << "Number of cplex iterations = " << cplex.getNiterations() << endl; cout << "Aggregated CPU time = " << timer.getTime() << " seconds" << endl; cout << "Elapsed wall clock time = " << endTime - startTime << " seconds" << endl; cout << "Number of threads used = " << param_threads << endl; cout << "Solution status = " << cplex.getStatus() << endl; if (solutionFound) { cout << "Solution value = " << cplex.getObjValue() << endl; cout << "Optimality Gap (in %) = " << fabs((cplex.getBestObjValue() - cplex.getObjValue()) / (1.0 * cplex.getObjValue())) * 100 << endl; //cout << "Maximum bound violation = " << cplex.getQuality(IloCplex::MaxPrimalInfeas) << endl; } cout << endl << "parameters: n=" << n << " l=" << l << " k=" << k << " p=" << p << " q=" << q << " m=" << m << endl; if (solutionFound) { cout << "TOTAL " << nSolutionsFound << " solutions found" << endl; int nAllowedSolutionsFound = 0; if (param_printexpr || param_printanswer || param_printsoln) { IloNumArray objValues(env, nSolutionsFound); vector<pair<IloNum,unsigned> > sortedIndex(nSolutionsFound); // to sort solutions by objective value vector<FormattedExpr> expressions(nSolutionsFound); // extract all solutions as formatted expressions for (int s=0; s<nSolutionsFound; s++) { IloNumArray vals(env); cplex.getValues(vals, corevars, s); // convert solution values to integers; note: simple int cast may lead to errors! IloIntArray intvals(env, vals.getSize()); for (int i=0; i<vals.getSize(); i++) intvals[i] = IloRound(vals[i]); // use IloRound rather than std::round if (param_printsoln) prettyPrintSoln(intvals); objValues[s] = cplex.getObjValue(s); expressions[s] = getFormattedExpr(intvals); sortedIndex[s] = pair<IloNum,unsigned> (objValues[s],s); } // sort solutions by increasing objective value std::stable_sort(sortedIndex.begin(), sortedIndex.end()); // identify which expressions are unique (ignoring type differences); // prefer to keep those that appear earlier in the above sorted order set<int> uniqueExprIndices; set<string> seenExpressions; if (!param_allowdupes) { for (int s=0; s<nSolutionsFound; s++) { const int sId = sortedIndex[s].second; const string & exprPf = expressions[sId].postfix; if (seenExpressions.find(exprPf) == seenExpressions.end()) { uniqueExprIndices.insert(sId); seenExpressions.insert(exprPf); } } } // evaluate all expressions with a single call to Python's SymPy package if (param_printanswer) solveExpressionsWithSymPy(expressions); // print expressions if desired, in sorted order if (param_printexpr) { cout << "SOLN: CORRECT | POS/NEG | INT/FRA | OBJ-SCORE | TRUE-ANS | ANS | INFIX | POSTFIX | TYPED-POSTFIX" << endl; for (int s=0; s<nSolutionsFound; s++) { const int sId = sortedIndex[s].second; if (!param_allowdupes && uniqueExprIndices.find(sId) == uniqueExprIndices.end()) continue; const FormattedExpr & expr = expressions[sId]; const double answerValue = atof(expr.answer.c_str()); const bool isCorrect = (fabs(answerValue - trueAnswer) < epsilon); const bool isAnswerNegative = answerValue < 0; const bool isAnswerInteger = isInt(answerValue); if (!isAnswerNegative && (!allIntConstants || consWts["IntConstantsImplyIntUnknown"] == 0 || isAnswerInteger)) { ++nAllowedSolutionsFound; cout << "EXPR: " << isCorrect << " | " << (isAnswerNegative ? "NEG" : "POS") << " | " << (isAnswerInteger ? "INT" : "FRA") << " | " << objValues[sId] << " | " << trueAnswer << " | " << expr.answer << " | " << expr.infix << " | " << expr.postfix << " | " << expr.typedPostfix << endl; } } } } const string solnProperty = (param_allowdupes ? "" : " unique,") + string(" non-negative") + (allIntConstants && consWts["IntConstantsImplyIntUnknown"] != 0 ? ", integer-valued " : " "); cout << "NET " << nAllowedSolutionsFound << solnProperty << "solutions found out of " << nSolutionsFound << " total solutions" << endl; } cout << "-------------------------------------------" << endl; cout << "RESULT:" << " NODES " << cplex.getNnodes() << " | ITERATIONS " << cplex.getNiterations() << " | CPUTIME " << timer.getTime() << " | WALLTIME " << endTime - startTime << " | THREADS " << param_threads << " | STATUS " << cplex.getStatus(); if (solutionFound) cout << " | SOLUTION " << cplex.getObjValue() << " | OPTGAP " << fabs((cplex.getBestObjValue() - cplex.getObjValue()) / (1.0 * cplex.getObjValue())) * 100; else cout << " | SOLUTION - | OPTGAP -"; cout << endl; //try { // basis may not exist // IloCplex::BasisStatusArray cstat(env); // cplex.getBasisStatuses(cstat, vars); // cout << "Basis statuses = " << cstat << endl; //} //catch (...) { //} } catch (IloException& e) { cerr << "Concert exception caught: " << e << endl; } catch (...) { cerr << "Unknown exception caught" << endl; } env.end(); return 0; } // END main
/** Solve the <code>problem</code> using a distributed implementation of * Benders' decomposition. */ bool BendersOpt::solve (Problem const *problem, int argc, char const *const *argv, std::vector<char const *> const &machines) { IloEnv env = problem->getModel().getEnv(); std::vector<Block *> blocks; Block *master = 0; bool result = false; try { // Extract blocks and master problem. std::cout << "Extracting " << problem->getNBlocks() << " blocks." << std::endl; for (IloInt b = 0; b < problem->getNBlocks(); ++b) blocks.push_back(new Block(problem, b, argc, argv, machines)); master = new Block(problem, blocks); // Write out the master and all blocks (for debugging). master->cplex.exportModel("master.lp"); for (BlockVector::size_type b = 0; b < blocks.size(); ++b) { std::stringstream s; s << "block" << b << ".lp"; blocks[b]->cplex.exportModel(s.str().c_str()); } // Solve the master. // If we find a feasible solution then perform a final solve // with the original problem so that we get solution values for // all variables in the original problem. if ( master->cplex.solve() ) { // Perform a last solve to get the solution values. IloNumArray vals(env), startVals(env); IloNumVarArray startVars(env); master->cplex.getValues(vals, master->vars); IloCplex cplex(problem->getModel()); // Fix integral variables to their value in the master solution // and add them as MIP start. for (IloInt i = 0; i < vals.getSize(); ++i) if ( master->vars[i].getType() != IloNumVar::Float ) { double const v = IloRound(vals[i]); IloNumVar x = master->varMap[master->vars[i]]; startVals.add(v); startVars.add(x); // We add lazy constraints so as to make sure that // - we don't modify the original model // - the problem has only the unique optimal solution // we are interested in cplex.addLazyConstraint(x == v); } cplex.addMIPStart(startVars, startVals); cplex.solve(); // Report the results. std::cout << "#### Problem solved (" << cplex.getObjValue() << ", " << cplex.getCplexStatus() << ")." << std::endl; IloNumVarArray vars = problem->getVariables(); for (IloInt i = 0; i < vars.getSize(); ++i) std::cout << "#### \tx[" << i << "] = " << cplex.getValue(vars[i]) << std::endl; cplex.end(); result = true; } } catch (...) { if ( master ) delete master; while ( blocks.size() > 0 ) { delete blocks.back(); blocks.pop_back(); } throw; } delete master; while ( blocks.size() > 0 ) { delete blocks.back(); blocks.pop_back(); } return result; }
ILOBRANCHCALLBACK1(SOSbranch, IloSOS1Array, sos) { IloNumArray x; IloNumVarArray var; try { IloInt i; x = IloNumArray(getEnv()); var = IloNumVarArray(getEnv()); IloNum bestx = EPS; IloInt besti = -1; IloInt bestj = -1; IloInt num = sos.getSize(); for (i = 0; i < num; i++) { if ( getFeasibility(sos[i]) == Infeasible ) { var.clear(); sos[i].getVariables(var); getValues(x, var); IloInt n = var.getSize(); for (IloInt j = 0; j < n; j++) { IloNum inf = IloAbs(x[j] - IloRound(x[j])); if ( inf > bestx ) { bestx = inf; besti = i; bestj = j; } } } } if ( besti >= 0 ) { IloCplex::BranchDirectionArray dir; IloNumArray val; try { dir = IloCplex::BranchDirectionArray(getEnv()); val = IloNumArray(getEnv()); var.clear(); sos[besti].getVariables(var); IloInt n = var.getSize(); for (IloInt j = 0; j < n; j++) { if ( j != bestj ) { dir.add(IloCplex::BranchDown); val.add(0.0); } else { dir.add(IloCplex::BranchUp); val.add(1.0); } } makeBranch(var, val, dir, getObjValue()); makeBranch(var[bestj], 0.0, IloCplex::BranchDown, getObjValue()); } catch (...) { dir.end(); val.end(); throw; } dir.end(); val.end(); } } catch (...) { var.end(); x.end(); throw; } var.end(); x.end(); }