void ClpInterface:: eval(void* mem, const double** arg, double** res, int* iw, double* w) const { //auto m = static_cast<ClpMemory*>(mem); if (inputs_check_) { checkInputs(arg[CONIC_LBX], arg[CONIC_UBX], arg[CONIC_LBA], arg[CONIC_UBA]); } // Get inputs double* g=w; w += nx_; casadi_copy(arg[CONIC_G], nx_, g); double* lbx=w; w += nx_; casadi_copy(arg[CONIC_LBX], nx_, lbx); double* ubx=w; w += nx_; casadi_copy(arg[CONIC_UBX], nx_, ubx); double* lba=w; w += na_; casadi_copy(arg[CONIC_LBA], na_, lba); double* uba=w; w += na_; casadi_copy(arg[CONIC_UBA], na_, uba); double* H=w; w += nnz_in(CONIC_H); casadi_copy(arg[CONIC_H], nnz_in(CONIC_H), H); double* A=w; w += nnz_in(CONIC_A); casadi_copy(arg[CONIC_A], nnz_in(CONIC_A), A); // Create model ClpSimplex model; model.loadProblem(A_.size2(), A_.size1(), A_.colind(), A_.row(), A, lbx, ubx, g, lba, uba, nullptr); // Solve the problem using the primal simplex algorithm model.primal(); // Primal solution double* x = model.primalColumnSolution(); casadi_copy(x, nx_, res[CONIC_X]); // Dual solution (x) double* minus_lam_x = model.dualColumnSolution(); if (res[CONIC_LAM_X]) { casadi_copy(minus_lam_x, nx_, res[CONIC_LAM_X]); casadi_scal(nx_, -1., res[CONIC_LAM_X]); } // Dual solution (A) double* minus_lam_a = model.dualRowSolution(); if (res[CONIC_LAM_A]) { casadi_copy(minus_lam_a, na_, res[CONIC_LAM_A]); casadi_scal(na_, -1., res[CONIC_LAM_A]); } // Optimal cost double f = model.rawObjectiveValue(); if (res[CONIC_COST]) *res[CONIC_COST] = f; }
static int solve(EKKModel * model, int startup, int algorithm, int presolve) { // values pass or not if (startup) startup = 1; // if scaled then be careful bool scaled = ekk_scaling(model) == 1; if (scaled) ekk_scaleRim(model, 1); void * compressInfo = NULL; ClpSimplex * clp; if (!presolve || !presolveInfo) { // no presolve or osl presolve - compact columns compressInfo = ekk_compressModel(model); clp = clpmodel(model, startup);; } else { // pick up clp model clp = presolveInfo->model(); } // don't scale if alreday scaled if (scaled) clp->scaling(false); if (clp->numberRows() > 10000) clp->factorization()->maximumPivots(100 + clp->numberRows() / 100); if (algorithm > 0) clp->primal(startup); else clp->dual(); int numberIterations = clp->numberIterations(); if (presolve && presolveInfo) { // very wasteful - create a clp copy of osl model ClpSimplex * clpOriginal = clpmodel(model, 0); presolveInfo->setOriginalModel(clpOriginal); // do postsolve presolveInfo->postsolve(true); delete clp; delete presolveInfo; presolveInfo = NULL; clp = clpOriginal; if (presolve == 3 || (presolve == 2 && clp->status())) { printf("Resolving from postsolved model\n"); clp->primal(1); numberIterations += clp->numberIterations(); } } // put back solution double * rowDual = (double *) ekk_rowduals(model); int numberRows = ekk_getInumrows(model); int numberColumns = ekk_getInumcols(model); int * rowStatus = (int *) ekk_rowstat(model); double * rowSolution = (double *) ekk_rowacts(model); int i; int * columnStatus = (int *) ekk_colstat(model); double * columnSolution = (double *) ekk_colsol(model); memcpy(rowSolution, clp->primalRowSolution(), numberRows * sizeof(double)); memcpy(rowDual, clp->dualRowSolution(), numberRows * sizeof(double)); for (i = 0; i < numberRows; i++) { if (clp->getRowStatus(i) == ClpSimplex::basic) rowStatus[i] = 0x80000000; else rowStatus[i] = 0; } double * columnDual = (double *) ekk_colrcosts(model); memcpy(columnSolution, clp->primalColumnSolution(), numberColumns * sizeof(double)); memcpy(columnDual, clp->dualColumnSolution(), numberColumns * sizeof(double)); for (i = 0; i < numberColumns; i++) { if (clp->getColumnStatus(i) == ClpSimplex::basic) columnStatus[i] = 0x80000000; else columnStatus[i] = 0; } ekk_setIprobstat(model, clp->status()); ekk_setRobjvalue(model, clp->objectiveValue()); ekk_setInumpinf(model, clp->numberPrimalInfeasibilities()); ekk_setInumdinf(model, clp->numberDualInfeasibilities()); ekk_setIiternum(model, numberIterations); ekk_setRsumpinf(model, clp->sumPrimalInfeasibilities()); ekk_setRsumdinf(model, clp->sumDualInfeasibilities()); delete clp; if (compressInfo) ekk_decompressModel(model, compressInfo); if (scaled) ekk_scaleRim(model, 2); return 0; }
//----------------------------------------------------------------------------- void CbcSolverLongThin::resolve() { int * whichRow = NULL; int * whichColumn = NULL; // problem may be small enough to do nested search const double * colLower = modelPtr_->columnLower(); const double * colUpper = modelPtr_->columnUpper(); int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); int numberRows=modelPtr_->numberRows(); int numberColumns = modelPtr_->numberColumns(); int i; int nFix=0; int nNewRow=0; int nNewCol=0; int sizeDynamic = COIN_INT_MAX; int smallOriginalNumberRows=0; if (algorithm_==0) { for (i=0;i<numberIntegers;i++) { int iColumn=integerVariable[i]; if (colLower[iColumn]==colUpper[iColumn]) nFix++; } } else { whichRow = new int[numberRows]; whichColumn = new int [numberColumns]; // more sophisticated OsiCuts cs; tryCut->generateCuts(*this,cs); int numberCuts = cs.sizeColCuts(); if (numberCuts) { for ( i = 0 ; i < numberCuts ; i++) { const OsiColCut *thisCut = cs.colCutPtr(i) ; const CoinPackedVector & ubs = thisCut->ubs() ; int n = ubs.getNumElements() ; const int * which = ubs.getIndices() ; const double * values = ubs.getElements() ; for (int j = 0;j<n;j++) { int iColumn = which[j] ; this->setColUpper(iColumn,values[j]) ; } } } #if 1 const int * duplicate = tryCut->duplicate(); sizeDynamic = tryCut->sizeDynamic(); int nOrig = tryCut->numberOriginalRows(); for (i=0;i<nOrig;i++) { if (duplicate[i]==-1) whichRow[nNewRow++]=i; else modelPtr_->setRowStatus(i,ClpSimplex::basic); } smallOriginalNumberRows=nNewRow; for (;i<numberRows;i++) { whichRow[nNewRow++]=i; } #else for (i=0;i<numberRows;i++) whichRow[i]=i; nNewRow=numberRows; #endif for (i=0;i<numberIntegers;i++) { int iColumn=integerVariable[i]; if (colLower[iColumn]==colUpper[iColumn]) nFix++; bool choose; if (algorithm_==1) choose = true; else choose = (node_[i]>count_-memory_&&node_[i]>0); if ((choose&&colUpper[i]) ||(modelPtr_->getStatus(i)!=ClpSimplex::atLowerBound&& modelPtr_->getStatus(i)!=ClpSimplex::isFixed) ||colLower[i]>0.0) whichColumn[nNewCol++]=i; } } if (nestedSearch_<1.0&&model_&&model_->phase()==2) { if (((double) sizeDynamic)*((double) nNewCol)<1000000000&&sizeDynamic<10000000) { // could do Dynamic Programming // back to original number of rows nNewRow = smallOriginalNumberRows; // and get rid of any basics int nNewCol=0; for (i=0;i<numberColumns;i++) { if (colUpper[i]||colLower[i]>0.0) whichColumn[nNewCol++]=i; } ClpSimplex temp(modelPtr_,nNewRow,whichRow,nNewCol,whichColumn); int returnCode; double * rowLower2 = temp.rowLower(); double * rowUpper2 = temp.rowUpper(); int numberColumns2 = temp.numberColumns(); double * colLower2 = temp.columnLower(); double * colUpper2 = temp.columnUpper(); const CoinPackedMatrix * matrix = temp.matrix(); const double * element = matrix->getElements(); const int * row = matrix->getIndices(); const CoinBigIndex * columnStart = matrix->getVectorStarts(); const int * columnLength = matrix->getVectorLengths(); double offset=0.0; const double * objective = temp.objective(); bool feasible=true; for (i=0;i<numberColumns2;i++) { double value = colLower2[i]; if (value) { offset += value*objective[i]; colLower2[i]=0.0; colUpper2[i] -= value; for (int j=columnStart[i]; j<columnStart[i]+columnLength[i];j++) { int iRow=row[j]; rowLower2[iRow] -= value*element[j]; rowUpper2[iRow] -= value*element[j]; if (rowUpper2[iRow]<-1.0e-8) { feasible=false; printf("odd - problem is infeasible\n"); } } } } temp.setObjectiveOffset(-offset); OsiClpSolverInterface temp2(&temp); double * solutionDP = NULL; if (feasible) { for (i=0;i<numberColumns2;i++) temp2.setInteger(i); CbcModel modelSmall(temp2); modelSmall.messageHandler()->setLogLevel(0); CbcFathomDynamicProgramming fathom1(modelSmall); // Set maximum space allowed fathom1.setMaximumSize(100000000); temp2.writeMps("small"); returnCode=fathom1.fathom(solutionDP); if (returnCode!=1) { printf("probably not enough memory\n"); abort(); } } if (solutionDP) { double objValue = 0.0; double * solution = modelPtr_->primalColumnSolution(); const double * objective = modelPtr_->objective(); for (i=0;i<numberColumns;i++) solution[i]=colLower[i]; for (i=0;i<nNewCol;i++) { int iColumn = whichColumn[i]; solution[iColumn]+=solutionDP[i]; } for (i=0;i<numberColumns;i++) objValue += solution[i]*objective[i]; if (objValue<model_->getCutoff()) { printf("good solution %g by dynamic programming\n",objValue); returnCode = 0; // paranoid check double * rowLower = modelPtr_->rowLower(); double * rowUpper = modelPtr_->rowUpper(); // Column copy const CoinPackedMatrix * matrix2 = modelPtr_->matrix(); element = matrix2->getElements(); row = matrix2->getIndices(); columnStart = matrix2->getVectorStarts(); columnLength = matrix2->getVectorLengths(); double * rowActivity = new double [numberRows]; memset(rowActivity,0,numberRows*sizeof(double)); for (i=0;i<numberColumns;i++) { int j; double value = solution[i]; assert (value>=colLower[i]&&value<=colUpper[i]); if (value) { printf("%d has value %g\n",i,value); for (j=columnStart[i]; j<columnStart[i]+columnLength[i];j++) { int iRow=row[j]; rowActivity[iRow] += value*element[j]; } } } // check was feasible bool feasible=true; for (i=0;i<numberRows;i++) { if(rowActivity[i]<rowLower[i]) { if (rowActivity[i]<rowLower[i]-1.0e-8) feasible = false; } else if(rowActivity[i]>rowUpper[i]) { if (rowActivity[i]>rowUpper[i]+1.0e-8) feasible = false; } } if (!feasible) { printf("** Bad solution by dynamic programming\n"); abort(); } delete [] rowActivity; model_->setBestSolution(CBC_TREE_SOL,objValue,solution); } else { returnCode=2; } } else { returnCode=2; } temp2.releaseClp(); modelPtr_->setProblemStatus(1); delete [] whichRow; delete [] whichColumn; return; } if (nFix>nestedSearch_*numberIntegers) { // Do nested search // back to original number of rows nNewRow = smallOriginalNumberRows; // and get rid of any basics int nNewCol=0; for (i=0;i<numberColumns;i++) { if (colUpper[i]||colLower[i]>0.0) whichColumn[nNewCol++]=i; } #if 0 // We clone from continuous solver so set some stuff OsiSolverInterface * solver = model_->continuousSolver(); CbcSolverLongThin * osiclp = dynamic_cast< CbcSolverLongThin*> (solver); assert (osiclp); // up special options if (osiclp->specialOptions()==3) osiclp->setSpecialOptions(7); double saveNested = osiclp->getNested(); int saveAlgorithm = osiclp->getAlgorithm(); osiclp->setNested(1.0); osiclp->setAlgorithm(0); int numberObjects = model_->numberObjects(); if (numberObjects>model_->numberIntegers()) { // for now only integers //assert (numberObjects == model_->numberIntegers()+1); model_->setNumberObjects(model_->numberIntegers()); // try follow on //model_->setNumberObjects(model_->numberIntegers()+1); } double saveMaxTime = model_->getDblParam(CbcModel::CbcMaximumSeconds); model_->setDblParam(CbcModel::CbcMaximumSeconds,1.0e5); // up special options #if 1 int returnCode= model_->subBranchAndBound(colLower,colUpper,2000); #else CbcModel * model3 = model_->cleanModel(colLower,colUpper); // integer presolve int returnCode=0; CbcModel * model2 = model3->integerPresolve(false); if (!model2||!model2->getNumRows()) { delete model2; delete model3; returnCode= 2; } else { if (handler_->logLevel()>1) printf("Reduced model has %d rows and %d columns\n", model2->getNumRows(),model2->getNumCols()); if (true) { OsiSolverInterface * solver = model2->solver(); OsiSolverInterface * osiclp = dynamic_cast< OsiSolverInterface*> (solver); assert (osiclp); int * priority = new int [numberColumns+1]; int n=0; int iColumn; for ( iColumn=0;iColumn<numberColumns;iColumn++) { if (solver->isInteger(iColumn)) { priority[n++]=10000; } } priority[n]=1; CbcObject * newObject =new CbcFollowOn2(model2); model2->addObjects(1,&newObject); delete newObject; model2->passInPriorities(priority,false); delete [] priority; } returnCode= model_->subBranchAndBound(model3,model2,4000); } #endif model_->setDblParam(CbcModel::CbcMaximumSeconds,saveMaxTime); model_->setNumberObjects(numberObjects); osiclp->setNested(saveNested); osiclp->setAlgorithm(saveAlgorithm); #else // start again very simply ClpSimplex temp(modelPtr_,nNewRow,whichRow,nNewCol,whichColumn); int returnCode; OsiClpSolverInterface temp2(&temp); temp2.setupForRepeatedUse(2); int numberColumns2 = temp.numberColumns(); const double * colUpper2 = temp2.getColUpper(); const double * colLower2 = temp2.getColLower(); const double * solution2 = temp.getColSolution(); double * cleanSolution2 = new double [numberColumns2]; for (i=0;i<numberColumns2;i++) { temp2.setInteger(i); double value = solution2[i]; value = CoinMin(CoinMax(value,colLower2[i]),colUpper2[i]); cleanSolution2[i] = value; } temp2.setColSolution(cleanSolution2); delete [] cleanSolution2; CbcModel modelSmall(temp2); modelSmall.setNumberStrong(0); CglProbing generator1; generator1.setUsingObjective(true); generator1.setMaxPass(3); generator1.setMaxProbe(100); generator1.setMaxLook(50); generator1.setRowCuts(3); CglGomory generator2; // try larger limit generator2.setLimit(300); CglKnapsackCover generator3; CglOddHole generator4; generator4.setMinimumViolation(0.005); generator4.setMinimumViolationPer(0.00002); // try larger limit generator4.setMaximumEntries(200); CglClique generator5; generator5.setStarCliqueReport(false); generator5.setRowCliqueReport(false); CglMixedIntegerRounding mixedGen; CglFlowCover flowGen; // Add in generators modelSmall.addCutGenerator(&generator1,-1,"Probing",true,false,false,-1); modelSmall.addCutGenerator(&generator2,-99,"Gomory",true,false,false,-99); modelSmall.addCutGenerator(&generator3,-99,"Knapsack",true,false,false,-99); modelSmall.addCutGenerator(&generator4,-99,"OddHole",true,false,false,-99); modelSmall.addCutGenerator(&generator5,-99,"Clique",true,false,false,-99); modelSmall.addCutGenerator(&flowGen,-99,"FlowCover",true,false,false,-99); modelSmall.addCutGenerator(&mixedGen,-99,"MixedIntegerRounding",true,false,false,-100); #if 1 const CoinPackedMatrix * matrix = temp2.getMatrixByCol(); const int * columnLength = matrix->getVectorLengths(); int * priority = new int [numberColumns2+1]; // do pseudo costs and priorities - take a reasonable guess CbcObject ** objects = new CbcObject * [numberColumns2+1]; int n=0; const double * objective = modelSmall.getObjCoefficients(); for (i=0;i<numberColumns2;i++) { CbcSimpleIntegerPseudoCost * newObject = new CbcSimpleIntegerPseudoCost(&modelSmall,n,i,objective[i],0.5*objective[i]); newObject->setMethod(3); objects[n]= newObject; priority[n++]=10000-columnLength[i]; } priority[n]=1; objects[n++]=new CbcFollowOn2(&modelSmall); modelSmall.addObjects(n,objects); for (i=0;i<n;i++) delete objects[i]; delete [] objects; modelSmall.passInPriorities(priority,false); delete [] priority; #endif modelSmall.setCutoff(model_->getCutoff()); //if (!onPathX&&modelSmall.getCutoff()>480.5) //modelSmall.setCutoff(480.5); //printf("cutoff %g\n",model_->getCutoff()); modelSmall.messageHandler()->setLogLevel(1); modelSmall.solver()->messageHandler()->setLogLevel(0); modelSmall.messagesPointer()->setDetailMessage(3,9); modelSmall.messagesPointer()->setDetailMessage(3,6); modelSmall.messagesPointer()->setDetailMessage(3,4); modelSmall.messagesPointer()->setDetailMessage(3,13); modelSmall.messagesPointer()->setDetailMessage(3,14); modelSmall.messagesPointer()->setDetailMessage(3,1); modelSmall.messagesPointer()->setDetailMessage(3,3007); modelSmall.branchAndBound(); temp2.releaseClp(); if (modelSmall.bestSolution()) { double objValue = 0.0; const double * solution2 = modelSmall.bestSolution(); double * solution = modelPtr_->primalColumnSolution(); const double * objective = modelPtr_->objective(); for (i=0;i<numberColumns;i++) solution[i]=colLower[i]; for (i=0;i<nNewCol;i++) { int iColumn = whichColumn[i]; solution[iColumn]=solution2[i]; } for (i=0;i<numberColumns;i++) objValue += solution[i]*objective[i]; assert (objValue<model_->getCutoff()); if (objValue<model_->getCutoff()) { //printf("good solution \n"); model_->setBestSolution(CBC_TREE_SOL,objValue,solution); returnCode = 0; } else { returnCode=2; } } else { returnCode=2; } #endif if (returnCode!=0&&returnCode!=2) { printf("pretending entire search done\n"); returnCode=0; } if (returnCode==0||returnCode==2) { modelPtr_->setProblemStatus(1); delete [] whichRow; delete [] whichColumn; return; } } } if ((count_<100&&algorithm_==2)||!algorithm_) { delete [] whichRow; delete [] whichColumn; assert(!modelPtr_->specialOptions()); int saveOptions = modelPtr_->specialOptions(); int startFinishOptions; bool takeHint; OsiHintStrength strength; bool gotHint = (getHintParam(OsiDoInBranchAndCut,takeHint,strength)); assert (gotHint); if (strength!=OsiHintIgnore&&takeHint) { // could do something - think about it //printf("thin hint %d %c\n",strength,takeHint ? 'T' :'F'); } if((specialOptions_&1)==0) { startFinishOptions=0; modelPtr_->setSpecialOptions(saveOptions|(64|1024)); } else { startFinishOptions=1+2+4; if((specialOptions_&4)==0) modelPtr_->setSpecialOptions(saveOptions|(64|128|512|1024|4096)); else modelPtr_->setSpecialOptions(saveOptions|(64|128|512|1024|2048|4096)); } //printf("thin options %d size %d\n",modelPtr_->specialOptions(),modelPtr_->numberColumns()); setBasis(basis_,modelPtr_); //modelPtr_->setLogLevel(1); modelPtr_->dual(0,0); basis_ = getBasis(modelPtr_); modelPtr_->setSpecialOptions(saveOptions); if (modelPtr_->status()==0) { count_++; double * solution = modelPtr_->primalColumnSolution(); int i; for (i=0;i<numberColumns;i++) { if (solution[i]>1.0e-6||modelPtr_->getStatus(i)==ClpSimplex::basic) { node_[i]=CoinMax(count_,node_[i]); howMany_[i]++; } } } else { if (!algorithm_==2) printf("infeasible early on\n"); } } else { // use counts int i; const double * lower = modelPtr_->columnLower(); const double * upper = modelPtr_->columnUpper(); setBasis(basis_,modelPtr_); ClpSimplex * temp = new ClpSimplex(modelPtr_,nNewRow,whichRow,nNewCol,whichColumn); //temp->setLogLevel(2); //printf("small has %d rows and %d columns\n",nNewRow,nNewCol); temp->setSpecialOptions(128+512); temp->setDualObjectiveLimit(1.0e50); temp->dual(); if (temp->status()) { // In some cases we know that it must be infeasible if (believeInfeasible_||algorithm_==1) { modelPtr_->setProblemStatus(1); printf("assuming infeasible!\n"); //modelPtr_->writeMps("infeas.mps"); //temp->writeMps("infeas2.mps"); //abort(); delete temp; delete [] whichRow; delete [] whichColumn; return; } } double * solution = modelPtr_->primalColumnSolution(); if (!temp->status()) { const double * solution2 = temp->primalColumnSolution(); memset(solution,0,numberColumns*sizeof(double)); for (i=0;i<nNewCol;i++) { int iColumn = whichColumn[i]; solution[iColumn]=solution2[i]; modelPtr_->setStatus(iColumn,temp->getStatus(i)); } double * rowSolution = modelPtr_->primalRowSolution(); const double * rowSolution2 = temp->primalRowSolution(); double * dual = modelPtr_->dualRowSolution(); const double * dual2 = temp->dualRowSolution(); memset(dual,0,numberRows*sizeof(double)); for (i=0;i<nNewRow;i++) { int iRow=whichRow[i]; modelPtr_->setRowStatus(iRow,temp->getRowStatus(i)); rowSolution[iRow]=rowSolution2[i]; dual[iRow]=dual2[i]; } // See if optimal double * dj = modelPtr_->dualColumnSolution(); // get reduced cost for large problem // this assumes minimization memcpy(dj,modelPtr_->objective(),numberColumns*sizeof(double)); modelPtr_->transposeTimes(-1.0,dual,dj); modelPtr_->setObjectiveValue(temp->objectiveValue()); modelPtr_->setProblemStatus(0); int nBad=0; for (i=0;i<numberColumns;i++) { if (modelPtr_->getStatus(i)==ClpSimplex::atLowerBound &&upper[i]>lower[i]&&dj[i]<-1.0e-5) nBad++; } //modelPtr_->writeMps("bada.mps"); //temp->writeMps("badb.mps"); if (nBad) { assert (algorithm_==2); //printf("%d bad\n",nBad); timesBad_++; modelPtr_->primal(); } } else { // infeasible - do all modelPtr_->setSpecialOptions(64+128+512); setBasis(basis_,modelPtr_); //modelPtr_->setLogLevel(1); modelPtr_->dual(0,0); basis_ = getBasis(modelPtr_); modelPtr_->setSpecialOptions(0); if (modelPtr_->status()) { printf("really infeasible!\n"); delete temp; delete [] whichRow; delete [] whichColumn; return; } else { printf("initially infeasible\n"); } } delete temp; delete [] whichRow; delete [] whichColumn; basis_ = getBasis(modelPtr_); modelPtr_->setSpecialOptions(0); count_++; if ((count_%100)==0&&algorithm_==2) printf("count %d, bad %d\n",count_,timesBad_); for (i=0;i<numberColumns;i++) { if (solution[i]>1.0e-6||modelPtr_->getStatus(i)==ClpSimplex::basic) { node_[i]=CoinMax(count_,node_[i]); howMany_[i]++; } } if (modelPtr_->objectiveValue()>=modelPtr_->dualObjectiveLimit()) modelPtr_->setProblemStatus(1); } }
int main(int argc, const char *argv[]) { ClpSimplex model; int status; // Keep names when reading an mps file if (argc < 2) { #if defined(SAMPLEDIR) status = model.readMps(SAMPLEDIR "/p0033.mps", true); #else fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); #endif } else status = model.readMps(argv[1], true); if (status) { fprintf(stderr, "Bad readMps %s\n", argv[1]); fprintf(stdout, "Bad readMps %s\n", argv[1]); exit(1); } #ifdef STYLE1 if (argc < 3 || !strstr(argv[2], "primal")) { // Use the dual algorithm unless user said "primal" model.initialDualSolve(); } else { model.initialPrimalSolve(); } #else ClpSolve solvectl; if (argc < 3 || (!strstr(argv[2], "primal") && !strstr(argv[2], "barrier"))) { // Use the dual algorithm unless user said "primal" or "barrier" std::cout << std::endl << " Solve using Dual: " << std::endl; solvectl.setSolveType(ClpSolve::useDual); solvectl.setPresolveType(ClpSolve::presolveOn); model.initialSolve(solvectl); } else if (strstr(argv[2], "barrier")) { // Use the barrier algorithm if user said "barrier" std::cout << std::endl << " Solve using Barrier: " << std::endl; solvectl.setSolveType(ClpSolve::useBarrier); solvectl.setPresolveType(ClpSolve::presolveOn); model.initialSolve(solvectl); } else { std::cout << std::endl << " Solve using Primal: " << std::endl; solvectl.setSolveType(ClpSolve::usePrimal); solvectl.setPresolveType(ClpSolve::presolveOn); model.initialSolve(solvectl); } #endif std::string modelName; model.getStrParam(ClpProbName, modelName); std::cout << "Model " << modelName << " has " << model.numberRows() << " rows and " << model.numberColumns() << " columns" << std::endl; // remove this to print solution exit(0); /* Now to print out solution. The methods used return modifiable arrays while the alternative names return const pointers - which is of course much more virtuous. This version just does non-zero columns */ #if 0 int numberRows = model.numberRows(); // Alternatively getRowActivity() double * rowPrimal = model.primalRowSolution(); // Alternatively getRowPrice() double * rowDual = model.dualRowSolution(); // Alternatively getRowLower() double * rowLower = model.rowLower(); // Alternatively getRowUpper() double * rowUpper = model.rowUpper(); // Alternatively getRowObjCoefficients() double * rowObjective = model.rowObjective(); // If we have not kept names (parameter to readMps) this will be 0 assert(model.lengthNames()); // Row names const std::vector<std::string> * rowNames = model.rowNames(); int iRow; std::cout << " Primal Dual Lower Upper (Cost)" << std::endl; for (iRow = 0; iRow < numberRows; iRow++) { double value; std::cout << std::setw(6) << iRow << " " << std::setw(8) << (*rowNames)[iRow]; value = rowPrimal[iRow]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; value = rowDual[iRow]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; value = rowLower[iRow]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; value = rowUpper[iRow]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; if (rowObjective) { value = rowObjective[iRow]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; } std::cout << std::endl; } #endif std::cout << "--------------------------------------" << std::endl; // Columns int numberColumns = model.numberColumns(); // Alternatively getColSolution() double * columnPrimal = model.primalColumnSolution(); // Alternatively getReducedCost() double * columnDual = model.dualColumnSolution(); // Alternatively getColLower() double * columnLower = model.columnLower(); // Alternatively getColUpper() double * columnUpper = model.columnUpper(); // Alternatively getObjCoefficients() double * columnObjective = model.objective(); // If we have not kept names (parameter to readMps) this will be 0 assert(model.lengthNames()); // Column names const std::vector<std::string> * columnNames = model.columnNames(); int iColumn; std::cout << " Primal Dual Lower Upper Cost" << std::endl; for (iColumn = 0; iColumn < numberColumns; iColumn++) { double value; value = columnPrimal[iColumn]; if (fabs(value) > 1.0e-8) { std::cout << std::setw(6) << iColumn << " " << std::setw(8) << (*columnNames)[iColumn]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnDual[iColumn]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnLower[iColumn]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnUpper[iColumn]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnObjective[iColumn]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; std::cout << std::endl; } } std::cout << "--------------------------------------" << std::endl; return 0; }
int main(int argc, const char *argv[]) { /* Read quadratic model in two stages to test loadQuadraticObjective. And is also possible to just read into ClpSimplex/Interior which sets it all up in one go. But this is only if it is in QUADOBJ format. If no arguments does share2qp using ClpInterior (also creates quad.mps which is in QUADOBJ format) If one argument uses simplex e.g. testit quad.mps If > one uses barrier via ClpSimplex input and then ClpInterior borrow */ if (argc < 2) { CoinMpsIO m; #if defined(SAMPLEDIR) int status = m.readMps(SAMPLEDIR "/share2qp", "mps"); #else fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); #endif if (status) { printf("errors on input\n"); exit(77); } ClpInterior model; model.loadProblem(*m.getMatrixByCol(), m.getColLower(), m.getColUpper(), m.getObjCoefficients(), m.getRowLower(), m.getRowUpper()); // get quadratic part int * start = NULL; int * column = NULL; double * element = NULL; m.readQuadraticMps(NULL, start, column, element, 2); int j; for (j = 0; j < 79; j++) { if (start[j] < start[j+1]) { int i; printf("Column %d ", j); for (i = start[j]; i < start[j+1]; i++) { printf("( %d, %g) ", column[i], element[i]); } printf("\n"); } } model.loadQuadraticObjective(model.numberColumns(), start, column, element); // share2qp is in old style qp format - convert to new so other options can use model.writeMps("quad.mps"); ClpCholeskyBase * cholesky = new ClpCholeskyBase(); cholesky->setKKT(true); model.setCholesky(cholesky); model.primalDual(); double *primal; double *dual; primal = model.primalColumnSolution(); dual = model.dualRowSolution(); int i; int numberColumns = model.numberColumns(); int numberRows = model.numberRows(); for (i = 0; i < numberColumns; i++) { if (fabs(primal[i]) > 1.0e-8) printf("%d primal %g\n", i, primal[i]); } for (i = 0; i < numberRows; i++) { if (fabs(dual[i]) > 1.0e-8) printf("%d dual %g\n", i, dual[i]); } } else { // Could read into ClpInterior ClpSimplex model; if (model.readMps(argv[1])) { printf("errors on input\n"); exit(77); } model.writeMps("quad"); if (argc < 3) { // simplex - just primal as dual does not work // also I need to fix scaling of duals on output // (Was okay in first place - can't mix and match scaling techniques) // model.scaling(0); model.primal(); } else { // barrier ClpInterior barrier; barrier.borrowModel(model); ClpCholeskyBase * cholesky = new ClpCholeskyBase(); cholesky->setKKT(true); barrier.setCholesky(cholesky); barrier.primalDual(); barrier.returnModel(model); } // Just check if share2qp (quad.mps here) // this is because I am not checking if variables at ub if (model.numberColumns() == 79) { double *primal; double *dual; primal = model.primalColumnSolution(); dual = model.dualRowSolution(); // Check duals by hand const ClpQuadraticObjective * quadraticObj = (dynamic_cast<const ClpQuadraticObjective*>(model.objectiveAsObject())); assert(quadraticObj); CoinPackedMatrix * quad = quadraticObj->quadraticObjective(); const int * columnQuadratic = quad->getIndices(); const CoinBigIndex * columnQuadraticStart = quad->getVectorStarts(); const int * columnQuadraticLength = quad->getVectorLengths(); const double * quadraticElement = quad->getElements(); int numberColumns = model.numberColumns(); int numberRows = model.numberRows(); double * gradient = new double [numberColumns]; // move linear objective memcpy(gradient, quadraticObj->linearObjective(), numberColumns * sizeof(double)); int iColumn; for (iColumn = 0; iColumn < numberColumns; iColumn++) { double valueI = primal[iColumn]; CoinBigIndex j; for (j = columnQuadraticStart[iColumn]; j < columnQuadraticStart[iColumn] + columnQuadraticLength[iColumn]; j++) { int jColumn = columnQuadratic[j]; double valueJ = primal[jColumn]; double elementValue = quadraticElement[j]; if (iColumn != jColumn) { double gradientI = valueJ * elementValue; double gradientJ = valueI * elementValue; gradient[iColumn] += gradientI; gradient[jColumn] += gradientJ; } else { double gradientI = valueI * elementValue; gradient[iColumn] += gradientI; } } if (fabs(primal[iColumn]) > 1.0e-8) printf("%d primal %g\n", iColumn, primal[iColumn]); } for (int i = 0; i < numberRows; i++) { if (fabs(dual[i]) > 1.0e-8) printf("%d dual %g\n", i, dual[i]); } // Now use duals to get reduced costs // Can't use this as will try and use scaling // model.transposeTimes(-1.0,dual,gradient); // So ... CoinPackedMatrix * matrix = model.matrix(); const int * row = matrix->getIndices(); const CoinBigIndex * columnStart = matrix->getVectorStarts(); const int * columnLength = matrix->getVectorLengths(); const double * element = matrix->getElements(); for (iColumn = 0; iColumn < numberColumns; iColumn++) { double dj = gradient[iColumn]; CoinBigIndex j; for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) { int jRow = row[j]; dj -= element[j] * dual[jRow]; } if (model.getColumnStatus(iColumn) == ClpSimplex::basic) { assert(fabs(dj) < 1.0e-5); } else { assert(dj > -1.0e-5); } } delete [] gradient; } } return 0; }
//----------------------------------------------------------------------------- void CbcSolver2::resolve() { int numberColumns = modelPtr_->numberColumns(); if ((count_<10&&algorithm_==2)||!algorithm_) { OsiClpSolverInterface::resolve(); if (modelPtr_->status()==0) { count_++; double * solution = modelPtr_->primalColumnSolution(); int i; for (i=0;i<numberColumns;i++) { if (solution[i]>1.0e-6||modelPtr_->getStatus(i)==ClpSimplex::basic) { node_[i]=CoinMax(count_,node_[i]); howMany_[i]++; } } } else { if (!algorithm_==2) printf("infeasible early on\n"); } } else { // use counts int numberRows=modelPtr_->numberRows(); int * whichRow = new int[numberRows]; int * whichColumn = new int [numberColumns]; int i; const double * lower = modelPtr_->columnLower(); const double * upper = modelPtr_->columnUpper(); const double * rowUpper = modelPtr_->rowUpper(); bool equality=false; for (i=0;i<numberRows;i++) { if (rowUpper[i]==1.0) { equality=true; break; } } setBasis(basis_,modelPtr_); int nNewCol=0; // Column copy //const double * element = modelPtr_->matrix()->getElements(); const int * row = modelPtr_->matrix()->getIndices(); const CoinBigIndex * columnStart = modelPtr_->matrix()->getVectorStarts(); const int * columnLength = modelPtr_->matrix()->getVectorLengths(); int * rowActivity = new int[numberRows]; memset(rowActivity,0,numberRows*sizeof(int)); int * rowActivity2 = new int[numberRows]; memset(rowActivity2,0,numberRows*sizeof(int)); char * mark = new char[numberColumns]; memset(mark,0,numberColumns); // Get rows which are satisfied for (i=0;i<numberColumns;i++) { if (lower[i]>0.0) { CoinBigIndex j; for (j=columnStart[i]; j<columnStart[i]+columnLength[i];j++) { int iRow=row[j]; rowActivity2[iRow] ++; } } else if (!upper[i]) { mark[i]=2; // no good } } // If equality - check not infeasible if (equality) { bool feasible=true; for (i=0;i<numberRows;i++) { if (rowActivity2[i]>1) { feasible=false; break; } } if (!feasible) { delete [] rowActivity; delete [] rowActivity2; modelPtr_->setProblemStatus(1); delete [] whichRow; delete [] whichColumn; delete [] mark; printf("infeasible by inspection (over)\n"); return; } } int nNoGood=0; for (i=0;i<numberColumns;i++) { if (mark[i]==2) { nNoGood++; continue; } bool choose; if (algorithm_==1) choose = true; else choose = (node_[i]>count_-memory_&&node_[i]>0); bool any; if (equality) { // See if forced to be zero CoinBigIndex j; any=true; for (j=columnStart[i]; j<columnStart[i]+columnLength[i];j++) { int iRow=row[j]; if (rowActivity2[iRow]) any=false; // can't be in } } else { // See if not useful CoinBigIndex j; any=false; for (j=columnStart[i]; j<columnStart[i]+columnLength[i];j++) { int iRow=row[j]; if (!rowActivity2[iRow]) any=true; // useful } } if (!any&&!lower[i]) { choose=false; // and say can't be useful mark[i]=2; nNoGood++; } if (strategy_&&modelPtr_->getColumnStatus(i)==ClpSimplex::basic) choose=true; if (choose||lower[i]>0.0) { mark[i]=1; whichColumn[nNewCol++]=i; CoinBigIndex j; double value = upper[i]; if (value) { for (j=columnStart[i]; j<columnStart[i]+columnLength[i];j++) { int iRow=row[j]; rowActivity[iRow] ++; } } } } // If equality add in slacks CoinModel build; if (equality) { int row=0; for (i=0;i<numberRows;i++) { // put in all rows if wanted if(strategy_) rowActivity2[i]=0; if (!rowActivity2[i]) { double element=1.0; build.addColumn(1,&row,&element,0.0,1.0,1.0e8); // large cost row++; } } } int nOK=0; int nNewRow=0; for (i=0;i<numberRows;i++) { if (rowActivity[i]) nOK++; if (!rowActivity2[i]) whichRow[nNewRow++]=i; // not satisfied else modelPtr_->setRowStatus(i,ClpSimplex::basic); // make slack basic } if (nOK<numberRows) { for (i=0;i<numberColumns;i++) { if (!mark[i]) { CoinBigIndex j; int good=0; for (j=columnStart[i]; j<columnStart[i]+columnLength[i];j++) { int iRow=row[j]; if (!rowActivity[iRow]) { rowActivity[iRow] ++; good++; } } if (good) { nOK+=good; whichColumn[nNewCol++]=i; } } } } delete [] rowActivity; delete [] rowActivity2; if (nOK<numberRows) { modelPtr_->setProblemStatus(1); delete [] whichRow; delete [] whichColumn; delete [] mark; printf("infeasible by inspection\n"); return; } bool allIn=false; if (nNewCol+nNoGood+numberRows>numberColumns) { // add in all allIn=true; for (i=0;i<numberColumns;i++) { if (!mark[i]) { whichColumn[nNewCol++]=i; } } } ClpSimplex * temp = new ClpSimplex(modelPtr_,nNewRow,whichRow,nNewCol,whichColumn); if (equality) temp->addColumns(build); temp->setLogLevel(1); printf("small has %d rows and %d columns (%d impossible to help) %s\n", nNewRow,nNewCol,nNoGood,allIn ? "all in" : ""); temp->setSpecialOptions(128+512); temp->setDualObjectiveLimit(1.0e50); temp->dual(); assert (!temp->status()); double * solution = modelPtr_->primalColumnSolution(); const double * solution2 = temp->primalColumnSolution(); memset(solution,0,numberColumns*sizeof(double)); for (i=0;i<nNewCol;i++) { int iColumn = whichColumn[i]; solution[iColumn]=solution2[i]; modelPtr_->setStatus(iColumn,temp->getStatus(i)); } double * rowSolution = modelPtr_->primalRowSolution(); const double * rowSolution2 = temp->primalRowSolution(); double * dual = modelPtr_->dualRowSolution(); const double * dual2 = temp->dualRowSolution(); memset(dual,0,numberRows*sizeof(double)); for (i=0;i<nNewRow;i++) { int iRow=whichRow[i]; modelPtr_->setRowStatus(iRow,temp->getRowStatus(i)); rowSolution[iRow]=rowSolution2[i]; dual[iRow]=dual2[i]; } // See if optimal double * dj = modelPtr_->dualColumnSolution(); // get reduced cost for large problem // this assumes minimization memcpy(dj,modelPtr_->objective(),numberColumns*sizeof(double)); modelPtr_->transposeTimes(-1.0,dual,dj); modelPtr_->setObjectiveValue(temp->objectiveValue()); modelPtr_->setProblemStatus(0); int nBad=0; for (i=0;i<numberColumns;i++) { if (modelPtr_->getStatus(i)==ClpSimplex::atLowerBound &&upper[i]>lower[i]&&dj[i]<-1.0e-5) nBad++; } //modelPtr_->writeMps("bada.mps"); //temp->writeMps("badb.mps"); delete temp; if (nBad&&!allIn) { assert (algorithm_==2); //printf("%d bad\n",nBad); timesBad_++; // just non mark==2 int nAdded=0; for (i=0;i<numberColumns;i++) { if (!mark[i]) { whichColumn[nNewCol++]=i; nAdded++; } } assert (nAdded); { temp = new ClpSimplex(modelPtr_,nNewRow,whichRow,nNewCol,whichColumn); if (equality) temp->addColumns(build); temp->setLogLevel(2); temp->setSpecialOptions(128+512); temp->setDualObjectiveLimit(1.0e50); temp->primal(1); assert (!temp->status()); double * solution = modelPtr_->primalColumnSolution(); const double * solution2 = temp->primalColumnSolution(); memset(solution,0,numberColumns*sizeof(double)); for (i=0;i<nNewCol;i++) { int iColumn = whichColumn[i]; solution[iColumn]=solution2[i]; modelPtr_->setStatus(iColumn,temp->getStatus(i)); } double * rowSolution = modelPtr_->primalRowSolution(); const double * rowSolution2 = temp->primalRowSolution(); double * dual = modelPtr_->dualRowSolution(); const double * dual2 = temp->dualRowSolution(); memset(dual,0,numberRows*sizeof(double)); for (i=0;i<nNewRow;i++) { int iRow=whichRow[i]; modelPtr_->setRowStatus(iRow,temp->getRowStatus(i)); rowSolution[iRow]=rowSolution2[i]; dual[iRow]=dual2[i]; } modelPtr_->setObjectiveValue(temp->objectiveValue()); modelPtr_->setProblemStatus(0); iterationsBad_ += temp->numberIterations(); printf("clean %d\n",temp->numberIterations()); delete temp; } } delete [] mark; delete [] whichRow; delete [] whichColumn; basis_ = getBasis(modelPtr_); modelPtr_->setSpecialOptions(0); count_++; if ((count_%100)==0&&algorithm_==2) printf("count %d, bad %d - iterations %d\n",count_,timesBad_,iterationsBad_); for (i=0;i<numberColumns;i++) { if (solution[i]>1.0e-6||modelPtr_->getStatus(i)==ClpSimplex::basic) { node_[i]=CoinMax(count_,node_[i]); howMany_[i]++; } } if (modelPtr_->objectiveValue()>=modelPtr_->dualObjectiveLimit()) modelPtr_->setProblemStatus(1); } }
int main(int argc, const char *argv[]) { ClpSimplex model; int status; if (argc < 2) { #if defined(SAMPLEDIR) status = model.readMps(SAMPLEDIR "/p0033.mps", true); #else fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); #endif } else status = model.readMps(argv[1], true); if( status != 0 ) { printf("Error %d reading MPS file\n", status); return status; } /* This driver uses volume algorithm then does dual - after adjusting costs then solves real problem */ // do volume for a bit VOL_problem volprob; const CoinPackedMatrix* mat = model.matrix(); const int psize = mat->getNumCols(); const int dsize = mat->getNumRows(); char * sense = new char[dsize]; double * rhs = new double[dsize]; const double * rowLower = model.rowLower(); const double * rowUpper = model.rowUpper(); // Set the lb/ub on the duals volprob.dsize = dsize; volprob.psize = psize; volprob.dual_lb.allocate(dsize); volprob.dual_ub.allocate(dsize); volprob.dsol.allocate(dsize); int i; for (i = 0; i < dsize; ++i) { if (rowUpper[i] == rowLower[i]) { // 'E': volprob.dual_lb[i] = -1.0e31; volprob.dual_ub[i] = 1.0e31; rhs[i] = rowUpper[i]; sense[i] = 'E'; } else if (rowLower[i] < -0.99e10 && rowUpper[i] < 0.99e10) { // 'L': volprob.dual_lb[i] = -1.0e31; volprob.dual_ub[i] = 0.0; rhs[i] = rowUpper[i]; sense[i] = 'L'; } else if (rowLower[i] > -0.99e10 && rowUpper[i] > 0.99e10) { // 'G': volprob.dual_lb[i] = 0.0; volprob.dual_ub[i] = 1.0e31; rhs[i] = rowLower[i]; sense[i] = 'G'; } else { printf("Volume Algorithm can't work if there is a non ELG row\n"); abort(); } } // Can't use read_param as private // anyway I want automatic use - so maybe this is problem #if 0 FILE* infile = fopen("parameters", "r"); if (!infile) { printf("Failure to open parameter file\n"); } else { volprob.read_params("parameters"); } #endif #if 0 // should save and restore bounds model.tightenPrimalBounds(); #else double * colUpper = model.columnUpper(); for (i = 0; i < psize; i++) colUpper[i] = 1.0; #endif lpHook myHook(model.getColLower(), model.getColUpper(), model.getObjCoefficients(), rhs, sense, *mat); // move duals double * pi = model.dualRowSolution(); memcpy(volprob.dsol.v, pi, dsize * sizeof(double)); volprob.solve(myHook, false /* not warmstart */); // For now stop as not doing any good exit(77); // create objectives int numberRows = model.numberRows(); int numberColumns = model.numberColumns(); memcpy(pi, volprob.dsol.v, numberRows * sizeof(double)); #define MODIFYCOSTS #ifdef MODIFYCOSTS double * saveObj = new double[numberColumns]; memcpy(saveObj, model.objective(), numberColumns * sizeof(double)); memcpy(model.dualColumnSolution(), model.objective(), numberColumns * sizeof(double)); model.clpMatrix()->transposeTimes(-1.0, pi, model.dualColumnSolution()); memcpy(model.objective(), model.dualColumnSolution(), numberColumns * sizeof(double)); const double * rowsol = model.primalRowSolution(); //const double * rowLower = model.rowLower(); //const double * rowUpper = model.rowUpper(); double offset = 0.0; for (i = 0; i < numberRows; i++) { offset += pi[i] * rowsol[i]; } double value2; model.getDblParam(ClpObjOffset, value2); printf("Offset %g %g\n", offset, value2); model.setRowObjective(pi); // zero out pi memset(pi, 0, numberRows * sizeof(double)); #endif // Could put some in basis - only partially tested model.allSlackBasis(); model.factorization()->maximumPivots(1000); //model.setLogLevel(63); // solve model.dual(1); //model.primal(1); #ifdef MODIFYCOSTS memcpy(model.objective(), saveObj, numberColumns * sizeof(double)); // zero out pi memset(pi, 0, numberRows * sizeof(double)); model.setRowObjective(pi); delete [] saveObj; model.primal(); #endif return 0; }