MSIndexVector MSIntTableColumn::rangeGradeDown(const MSIndexVector &start_,const MSIndexVector &end_) { if (MSView::model()!=0&&start_.length()>0&&start_.length()==end_.length()) { MSIntVector &vector=*(MSIntVector *)_model; MSIndexVector index(vector.length()); for (unsigned i=0;i<start_.length();i++) { MSIndexVector subIndex; subIndex.series(end_(i)-start_(i)+1,start_(i)); MSIntVector subVector=MSIntVector::select(vector,subIndex); MSIndexVector sortedIndex=subVector.gradeDown(); unsigned startIndex=start_(i); for (unsigned j=0;j<sortedIndex.length();j++) { index.replaceAt(startIndex+j,sortedIndex(j)+startIndex); } } return index; } else return MSIndexVector::nullVector(); }
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
int MilpRounding::solution(double &solutionValue, double *betterSolution) { if(model_->getCurrentPassNumber() > 1) return 0; if (model_->currentDepth() > 2 && (model_->getNodeCount()%howOften_)!=0) return 0; int returnCode = 0; // 0 means it didn't find a feasible solution OsiTMINLPInterface * nlp = NULL; if(setup_->getAlgorithm() == B_BB) nlp = dynamic_cast<OsiTMINLPInterface *>(model_->solver()->clone()); else nlp = dynamic_cast<OsiTMINLPInterface *>(setup_->nonlinearSolver()->clone()); TMINLP2TNLP* minlp = nlp->problem(); // set tolerances double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance); //double primalTolerance = 1.0e-6; int n; int m; int nnz_jac_g; int nnz_h_lag; Ipopt::TNLP::IndexStyleEnum index_style; minlp->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style); const Bonmin::TMINLP::VariableType* variableType = minlp->var_types(); const double* x_sol = minlp->x_sol(); const double* g_l = minlp->g_l(); const double* g_u = minlp->g_u(); const double * colsol = model_->solver()->getColSolution(); // Get information about the linear and nonlinear part of the instance TMINLP* tminlp = nlp->model(); vector<Ipopt::TNLP::LinearityType> c_lin(m); tminlp->get_constraints_linearity(m, c_lin()); vector<int> c_idx(m); int n_lin = 0; for (int i=0;i<m;i++) { if (c_lin[i]==Ipopt::TNLP::LINEAR) c_idx[i] = n_lin++; else c_idx[i] = -1; } // Get the structure of the jacobian vector<int> indexRow(nnz_jac_g); vector<int> indexCol(nnz_jac_g); minlp->eval_jac_g(n, x_sol, false, m, nnz_jac_g, indexRow(), indexCol(), 0); // get the jacobian values vector<double> jac_g(nnz_jac_g); minlp->eval_jac_g(n, x_sol, false, m, nnz_jac_g, NULL, NULL, jac_g()); // Sort the matrix to column ordered vector<int> sortedIndex(nnz_jac_g); CoinIotaN(sortedIndex(), nnz_jac_g, 0); MatComp c; c.iRow = indexRow(); c.jCol = indexCol(); std::sort(sortedIndex.begin(), sortedIndex.end(), c); vector<int> row (nnz_jac_g); vector<double> value (nnz_jac_g); vector<int> columnStart(n,0); vector<int> columnLength(n,0); int indexCorrection = (index_style == Ipopt::TNLP::C_STYLE) ? 0 : 1; int iniCol = -1; int nnz = 0; for(int i=0; i<nnz_jac_g; i++) { int thisIndexCol = indexCol[sortedIndex[i]]-indexCorrection; int thisIndexRow = c_idx[indexRow[sortedIndex[i]] - indexCorrection]; if(thisIndexCol != iniCol) { iniCol = thisIndexCol; columnStart[thisIndexCol] = nnz; columnLength[thisIndexCol] = 0; } if(thisIndexRow == -1) continue; columnLength[thisIndexCol]++; row[nnz] = thisIndexRow; value[nnz] = jac_g[i]; nnz++; } // Build the row lower and upper bounds vector<double> newRowLower(n_lin); vector<double> newRowUpper(n_lin); for(int i = 0 ; i < m ; i++){ if(c_idx[i] == -1) continue; newRowLower[c_idx[i]] = g_l[i]; newRowUpper[c_idx[i]] = g_u[i]; } // Get solution array for heuristic solution vector<double> newSolution(n); std::copy(x_sol, x_sol + n, newSolution.begin()); // Define the constraint matrix for MILP CoinPackedMatrix matrix(true,n_lin,n, nnz, value(), row(), columnStart(), columnLength()); // create objective function and columns lower and upper bounds for MILP // and create columns for matrix in MILP //double alpha = 0; double beta = 1; vector<double> objective(n); vector<int> idxIntegers; idxIntegers.reserve(n); for(int i = 0 ; i < n ; i++){ if(variableType[i] != Bonmin::TMINLP::CONTINUOUS){ idxIntegers.push_back(i); objective[i] = beta*(1 - 2*colsol[i]); } } #if 0 // Get dual multipliers and build gradient of the lagrangean const double * duals = nlp->getRowPrice() + 2 *n; vector<double> grad(n, 0); vector<int> indices(n, 0); tminlp->eval_grad_f(n, x_sol, false, grad()); for(int i = 0 ; i < m ; i++){ if(c_lin[i] == Ipopt::TNLP::LINEAR) continue; int nnz; tminlp->eval_grad_gi(n, x_sol, false, i, nnz, indices(), NULL); tminlp->eval_grad_gi(n, x_sol, false, i, nnz, NULL, grad()); for(int k = 0 ; k < nnz ; k++){ objective[indices[k]] += alpha *duals[i] * grad[k]; } } for(int i = 0 ; i < n ; i++){ if(variableType[i] != Bonmin::TMINLP::CONTINUOUS) objective[i] += alpha * grad[i]; //if(fabs(objective[i]) < 1e-4) objective[i] = 0; else objective[i] = 0; } std::copy(objective.begin(), objective.end(), std::ostream_iterator<double>(std::cout, " ")); std::cout<<std::endl; #endif // load the problem to OSI OsiSolverInterface *si = mip_->solver(); assert(si != NULL); CoinMessageHandler * handler = model_->messageHandler()->clone(); si->passInMessageHandler(handler); si->messageHandler()->setLogLevel(1); si->loadProblem(matrix, model_->solver()->getColLower(), model_->solver()->getColUpper(), objective(), newRowLower(), newRowUpper()); si->setInteger(idxIntegers(), static_cast<int>(idxIntegers.size())); si->applyCuts(noGoods); bool hasFractionnal = true; while(hasFractionnal){ mip_->optimize(DBL_MAX, 0, 60); hasFractionnal = false; #if 0 bool feasible = false; if(mip_->getLastSolution()) { const double* solution = mip_->getLastSolution(); std::copy(solution, solution + n, newSolution.begin()); feasible = true; } if(feasible) { // fix the integer variables and solve the NLP // also add no good cut CoinPackedVector v; double lb = 1; for (int iColumn=0;iColumn<n;iColumn++) { if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) { double value=newSolution[iColumn]; if (fabs(floor(value+0.5)-value)>integerTolerance) { #ifdef DEBUG_BON_HEURISTIC_DIVE_MIP cout<<"It should be infeasible because: "<<endl; cout<<"variable "<<iColumn<<" is not integer"<<endl; #endif feasible = false; break; } else { value=floor(newSolution[iColumn]+0.5); if(value > 0.5){ v.insert(iColumn, -1); lb -= value; } minlp->SetVariableUpperBound(iColumn, value); minlp->SetVariableLowerBound(iColumn, value); } } } } #endif } bool feasible = false; if(mip_->getLastSolution()) { const double* solution = mip_->getLastSolution(); std::copy(solution, solution + n, newSolution.begin()); feasible = true; delete handler; } if(feasible) { // fix the integer variables and solve the NLP // also add no good cut CoinPackedVector v; double lb = 1; for (int iColumn=0;iColumn<n;iColumn++) { if (variableType[iColumn] != Bonmin::TMINLP::CONTINUOUS) { double value=newSolution[iColumn]; if (fabs(floor(value+0.5)-value)>integerTolerance) { feasible = false; break; } else { value=floor(newSolution[iColumn]+0.5); if(value > 0.5){ v.insert(iColumn, -1); lb -= value; } minlp->SetVariableUpperBound(iColumn, value); minlp->SetVariableLowerBound(iColumn, value); } } } OsiRowCut c; c.setRow(v); c.setLb(lb); c.setUb(DBL_MAX); noGoods.insert(c); if(feasible) { nlp->initialSolve(); if(minlp->optimization_status() != Ipopt::SUCCESS) { feasible = false; } std::copy(x_sol,x_sol+n, newSolution.begin()); } } if(feasible) { double newSolutionValue; minlp->eval_f(n, newSolution(), true, newSolutionValue); if(newSolutionValue < solutionValue) { std::copy(newSolution.begin(), newSolution.end(), betterSolution); solutionValue = newSolutionValue; returnCode = 1; } } delete nlp; #ifdef DEBUG_BON_HEURISTIC_DIVE_MIP std::cout<<"DiveMIP returnCode = "<<returnCode<<std::endl; #endif return returnCode; }