Exemple #1
0
void
CglClique::generateCuts(const OsiSolverInterface& si, OsiCuts & cs,
			const CglTreeInfo info)
{
   int i;
   bool has_petol_set = petol != -1.0;

   if (! has_petol_set)
      si.getDblParam(OsiPrimalTolerance, petol);
   int numberOriginalRows = si.getNumRows();
   if (info.inTree&&justOriginalRows_)
     numberOriginalRows = info.formulation_rows;
   int numberRowCutsBefore = cs.sizeRowCuts();
   // First select which rows/columns we are interested in.
   if (!setPacking_) {
      selectFractionalBinaries(si);
      if (!sp_orig_row_ind) {
	 selectRowCliques(si,numberOriginalRows);
      }
   } else {
      selectFractionals(si);
      delete[] sp_orig_row_ind;
      sp_numrows = numberOriginalRows;
      //sp_numcols = si.getNumCols();
      sp_orig_row_ind = new int[sp_numrows];
      for (i = 0; i < sp_numrows; ++i)
	 sp_orig_row_ind[i] = i;
   }
   // Just original rows
   if (justOriginalRows_&&info.inTree) 
     sp_numrows = CoinMin(info.formulation_rows,sp_numrows);
     

   createSetPackingSubMatrix(si);
   fgraph.edgenum = createNodeNode();
   createFractionalGraph();

   cl_indices = new int[sp_numcols];
   cl_del_indices = new int[sp_numcols];

   if (do_row_clique)
      find_rcl(cs);
   if (do_star_clique)
      find_scl(cs);
   if (!info.inTree&&((info.options&4)==4||((info.options&8)&&!info.pass))) {
     int numberRowCutsAfter = cs.sizeRowCuts();
     for (int i=numberRowCutsBefore;i<numberRowCutsAfter;i++)
       cs.rowCutPtr(i)->setGloballyValid();
   }

   delete[] cl_indices;     cl_indices = 0;
   delete[] cl_del_indices; cl_del_indices = 0;

   deleteFractionalGraph();
   delete[] node_node;      node_node = 0;
   deleteSetPackingSubMatrix();

   if (! has_petol_set)
      petol = -1;
}
Exemple #2
0
// Add cuts
void
CglStored::addCut(const OsiCuts & cs)
{
  int numberRowCuts = cs.sizeRowCuts();
  for (int i=0;i<numberRowCuts;i++) {
    cuts_.insert(*cs.rowCutPtr(i));
  }
}
Exemple #3
0
//-------------------------------------------------------------------
void OsiCuts::gutsOfCopy(const OsiCuts& source)
{
  assert( sizeRowCuts()==0 );
  assert( sizeColCuts()==0 );
  assert( sizeCuts()==0 );
  int i;
  int ne = source.sizeRowCuts();
  for (i=0; i<ne; i++) insert( source.rowCut(i) );
  ne = source.sizeColCuts();
  for (i=0; i<ne; i++) insert( source.colCut(i) );

}
// LANNEZ SEBASTIEN added Thu May 25 01:22:51 EDT 2006
void OsiCuts::insert(const OsiCuts & cs)
{
  for (OsiCuts::const_iterator it = cs.begin (); it != cs.end (); it++)
  {
    const OsiRowCut * rCut = dynamic_cast <const OsiRowCut * >(*it);
    const OsiColCut * cCut = dynamic_cast <const OsiColCut * >(*it);
    assert (rCut || cCut);
    if (rCut)
      insert (*rCut);
    else
      insert (*cCut);
  }
}
Exemple #5
0
	int CPXPUBLIC CPX_CutCallback(CPXCENVptr xenv, void *cbdata,
			int wherefrom, void *cbhandle, int *useraction_p) {
//		cout << "Entering CPX Callback\n" << flush;
		CPXLPptr nodelp;
		CPXgetcallbacknodelp(xenv, cbdata, wherefrom, &nodelp);

		CoinCallbacks* ccc = (CoinCallbacks*)cbhandle;
		
		int length = CPXgetnumcols(xenv,nodelp) - 1; //hey, don't ask me! some VERY WIERD PHENOMENON... crap
		double objVal;
		double* solution = new double[length];
		CPXgetcallbacknodeobjval(xenv, cbdata, wherefrom, &objVal);
		CPXgetcallbacknodex(xenv, cbdata, wherefrom, solution, 0, length-1);

		OsiCuts* cuts = new OsiCuts();		
		CoinCallbacks::CutReturn ret = ccc->cutCallback(objVal, solution, cuts);
		
		if(ret == CoinCallbacks::CR_AddCuts) {
			for(int i = cuts->sizeRowCuts(); i-->0;) {
				const OsiRowCut& c = cuts->rowCut(i);				
				const CoinPackedVector& vec = c.row();

				if(c.globallyValid())
					/* Old Cplex-Versions did NOT have the last parameter (now set to "false").
					 * If you compile agains an older CPLEX version, simple *REMOVE*
					 *   ", false"
					 * from the calls to CPXcutscallbackadd
					 */
					CPXcutcallbackadd(xenv, cbdata, wherefrom,
						vec.getNumElements(), c.rhs(), c.sense(), vec.getIndices(), vec.getElements(), false);  //default to non-purgable cuts
				else
					CPXcutcallbackaddlocal(xenv, cbdata, wherefrom,
						vec.getNumElements(), c.rhs(), c.sense(), vec.getIndices(), vec.getElements());
				cuts->eraseRowCut(i);
			}
			if(cuts->sizeColCuts() > 0) {
				cerr << "ColCuts currently not supported...\n";
				OGDF_THROW_PARAM(LibraryNotSupportedException, lnscFunctionNotImplemented);
			}
		}
		
		*useraction_p = ( ret == CoinCallbacks::CR_Error) ? CPX_CALLBACK_FAIL :
		                ( ret == CoinCallbacks::CR_AddCuts ) ? CPX_CALLBACK_SET : 
		                CPX_CALLBACK_DEFAULT;
		delete cuts;
		delete[] solution;
//		cout << "Leaving CPX Callback\n" << flush;
		return 0; // success
	}
Exemple #6
0
//-------------------------------------------------------------------
// Generate Stored cuts
//------------------------------------------------------------------- 
void 
CglStoredUser::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
			     const CglTreeInfo info) const
{
  // Get basic problem information
  const double * solution = si.getColSolution();
  if (info.inTree&&info.pass>numberPasses_) {
    // only continue if integer feasible
    int numberColumns=si.getNumCols(); 
    int i;
    const double * colUpper = si.getColUpper();
    const double * colLower = si.getColLower();
    int numberAway=0;
    for (i=0;i<numberColumns;i++) {
      double value = solution[i];
      // In case slightly away from bounds
      value = CoinMax(colLower[i],value);
      value = CoinMin(colUpper[i],value);
      if (si.isInteger(i)&&fabs(value-fabs(value+0.5))>1.0e-5) 
	numberAway++;
    }
    if (numberAway)
      return; // let code branch
  }
  int numberRowCuts = cuts_.sizeRowCuts();
  for (int i=0;i<numberRowCuts;i++) {
    const OsiRowCut * rowCutPointer = cuts_.rowCutPtr(i);
    double violation = rowCutPointer->violated(solution);
    if (violation>=requiredViolation_)
      cs.insert(*rowCutPointer);
  }
}
/*
  Append cuts to the cuts_ array in a nodeInfo. The initial reference count
  is set to numberToBranchOn, which will normally be the number of arms
  defined for the CbcBranchingObject attached to the CbcNode that owns this
  CbcNodeInfo.
*/
void
CbcNodeInfo::addCuts (OsiCuts & cuts, int numberToBranchOn,
                      /*int * whichGenerator,*/int numberPointingToThis)
{
    int numberCuts = cuts.sizeRowCuts();
    if (numberCuts) {
        int i;
        if (!numberCuts_) {
            cuts_ = new CbcCountRowCut * [numberCuts];
        } else {
            CbcCountRowCut ** temp = new CbcCountRowCut * [numberCuts+numberCuts_];
            memcpy(temp, cuts_, numberCuts_*sizeof(CbcCountRowCut *));
            delete [] cuts_;
            cuts_ = temp;
        }
        for (i = 0; i < numberCuts; i++) {
            CbcCountRowCut * thisCut = new CbcCountRowCut(*cuts.rowCutPtr(i),
                    this, numberCuts_,
                    -1, numberPointingToThis);
            thisCut->increment(numberToBranchOn);
            cuts_[numberCuts_++] = thisCut;
#ifdef CBC_DEBUG
#if CBC_DEBUG>1
            int n = thisCut->row().getNumElements();
            printf("Cut %d has %d entries, rhs %g %g =>", i, n, thisCut->lb(),
                   thisCut->ub());
            int j;
            const int * index = thisCut->row().getIndices();
            const double * element = thisCut->row().getElements();
            for (j = 0; j < n; j++) {
                printf(" (%d,%g)", index[j], element[j]);
                assert(fabs(element[j]) > 1.00e-12);
            }
            printf("\n");
#else
            int n = thisCut->row().getNumElements();
            int j;
            const double * element = thisCut->row().getElements();
            for (j = 0; j < n; j++) {
                assert(fabs(element[j]) > 1.00e-12);
            }
#endif
#endif
        }
    }
}
bool isWiped (OsiCuts &cs) {

  if (cs.sizeColCuts () == 0)
  //(cs.sizeColCuts () != 1))
    return false;

  CoinPackedVector 
    lbs = cs.colCutPtr (cs.sizeColCuts () - 1) -> lbs (),
    ubs = cs.colCutPtr (cs.sizeColCuts () - 1) -> ubs ();

  return ((lbs.getNumElements ()  == 1)  &&
	  (ubs.getNumElements ()  == 1)  &&
	  (*(lbs.getIndices   ()) == 0)  &&
	  (*(lbs.getElements  ()) == 1.) &&
	  (*(ubs.getIndices   ()) == 0)  &&
	  (*(ubs.getElements  ()) == -1.));
}
Exemple #9
0
int
Cuts::insertAll(OsiCuts & cs, CoinRelFltEq& eq)
{
    int r_val = 0;
    for (unsigned int i = 0 ; i < cuts_.size() ; i++)
    {
        if (cuts_[i] != NULL)
        {
            cs.insertIfNotDuplicate(*cuts_[i], eq);
            delete cuts_[i];
            cuts_[i] = NULL;
            r_val++;
        }
    }
    return r_val;
}
void WipeMakeInfeas (OsiCuts &cs) {

  //for (int i=cs.sizeRowCuts(); i--;) cs. eraseRowCut (i);
  //for (int i=cs.sizeColCuts(); i--;) cs. eraseColCut (i);

  OsiColCut *infeascut = new OsiColCut;

  if (infeascut) {
    int i=0;
    double upper = -1., lower = +1.;
    infeascut -> setLbs (1, &i, &lower);
    infeascut -> setUbs (1, &i, &upper);
    cs.insert (infeascut);
    delete infeascut;
  }
}
Exemple #11
0
void
CglClique::recordClique(const int len, int* indices, OsiCuts& cs)
{
   /* transform relative indices into user indices and order them */
   for (int j = len - 1; j >= 0; j--)
      indices[j] = sp_orig_col_ind[indices[j]];
   std::sort(indices, indices + len);
   OsiRowCut rowcut;
   double* coef = new double[len];
   std::fill(coef, coef + len, 1.0);
   rowcut.setRow(len, indices, coef);
   rowcut.setUb(1.0);
   CoinAbsFltEq equal(1.0e-12);
   cs.insertIfNotDuplicate(rowcut,equal);
   delete[] coef;
}
Exemple #12
0
void
CglLandP::scanExtraCuts(OsiCuts& cs, const double * colsol) const
{
    int numAdded = 0;
    for (int i = extraCuts_.sizeRowCuts() - 1; i > -1 ; i--)
    {
        double violation = extraCuts_.rowCut(i).violated(colsol);
        if (violation > 0.)
        {
            cs.insert(extraCuts_.rowCut(i));
            numAdded++;
            //      std::cout<<"A cut computed in a previous iteration is violated by "<<violation<<"."<<std::endl;
            //extraCuts_.eraseRowCut(i);
        }
    }
    //  std::cout<<"Added "<<numAdded<<" previously generated cuts."<<std::endl;
}
Exemple #13
0
void
OaDecompositionBase::OaDebug::printEndOfProcedureDebugMessage(const OsiCuts &cs,
    bool foundSolution,
    double solValue,
    double milpBound,
    bool isInteger,
    bool feasible,
    std::ostream & os) const{
  std::cout<<"------------------------------------------------------------------"
  <<std::endl;
  std::cout<<"OA procedure finished"<<std::endl;
  std::cout<<"Generated "<<cs.sizeRowCuts()<<std::endl;
  if (foundSolution)
    std::cout <<"Found NLP-integer feasible solution of  value : "<<solValue<<std::endl;
  std::cout<<"Current MILP lower bound is : "<<milpBound<<std::endl;
  std::cout<<"-------------------------------------------------------------------"<<std::endl;
  std::cout<<"Stopped because : isInteger "<<isInteger<<", feasible "<<feasible<<std::endl<<std::endl;

}
  void 
  LinearCutsGenerator::generateCuts(const OsiSolverInterface &solver, OsiCuts &cs,
                     const CglTreeInfo info) const {

    //const OsiTMINLPInterface * tmp = dynamic_cast<const OsiTMINLPInterface *>(&solver);
    OsiTMINLPInterface * nlp = dynamic_cast<OsiTMINLPInterface *>(solver.clone());//const_cast<OsiTMINLPInterface *>(tmp);
    assert(nlp);
    OuterApprox oa;
    //si.writeMps("toto");
    int numberRows = nlp->getNumRows();
    for(int i = 0 ; i < 5 ; i++){
      nlp->resolve();
      OsiClpSolverInterface si;
      oa(*nlp, &si, solver.getColSolution(), true); 
      si.resolve();
      OsiCuts cuts;
      for(std::list<Coin::SmartPtr<CuttingMethod> >::const_iterator i = methods_.begin() ;
          i != methods_.end() ; i++){
         (*i)->cgl->generateCuts(si, cuts, info);
      }
      std::vector<OsiRowCut *> mycuts(cuts.sizeRowCuts());
      for(int i = 0 ; i < cuts.sizeRowCuts() ; i++){
        mycuts[i] = cuts.rowCutPtr(i);
        cs.insert(*mycuts[i]);
      }
      nlp->applyRowCuts(mycuts.size(), const_cast<const OsiRowCut **> (&mycuts[0]));
    }

    // Take off slack cuts
    std::vector<int> kept;
    int numberRowsNow = nlp->getNumRows();
    int * del = new int [numberRowsNow-numberRows];
    nlp->resolve();
    
    const double * activity = nlp->getRowActivity();
    const double * lb = nlp->getRowLower();
    const double * ub = nlp->getRowUpper();
    CoinRelFltEq eq(1e-06);
    //int nDelete=0;
    for (int i=numberRowsNow -1;i>=numberRows;i--) {
      if ( !(eq(activity[i], lb[i]) || eq(activity[i], ub[i])) )
        cs.eraseRowCut(i - numberRows);
    }
    delete [] del;
    delete nlp;
  }
bool
BlisConGenerator::generateCons(OsiCuts & coinCuts , bool fullScan)
{
    bool status = false;

    if (strategy_ == -2) {
        // This con generator has been disabled.
        return false;
    }

    OsiSolverInterface * solver = model_->solver();

#if defined(BLIS_DEBUG_MORE)
    std::cout << "model_->getNodeCount() = " << model_->getNodeCount()
              << std::endl;
#endif

    if ( fullScan ||
         ((strategy_ > 0) && (model_->getNumNodes() % strategy_) == 0) ) {

        //--------------------------------------------------
        // Start to generate cons ...
        //--------------------------------------------------

	int j;
        double start = CoinCpuTime();
        int numConsBefore = coinCuts.sizeCuts();
        int numRowsBefore = coinCuts.sizeRowCuts();

        assert(generator_ != NULL);

        CglProbing* generator = dynamic_cast<CglProbing *>(generator_);

        if (!generator) {
            generator_->generateCuts(*solver, coinCuts);
        }
        else {
            // It is probing - return tight column bound
 	    CglTreeInfo info;
            generator->generateCutsAndModify(*solver, coinCuts, &info);
            const double * tightLower = generator->tightLower();
            const double * lower = solver->getColLower();
            const double * tightUpper = generator->tightUpper();
            const double * upper = solver->getColUpper();
            const double * solution = solver->getColSolution();

            int numberColumns = solver->getNumCols();
            double primalTolerance = 1.0e-8;
            for (j = 0; j < numberColumns; ++j) {
                if ( (tightUpper[j] == tightLower[j]) &&
                     (upper[j] > lower[j]) ) {
                    // fix column j
                    solver->setColLower(j, tightLower[j]);
                    solver->setColUpper(j, tightUpper[j]);
                    if ( (tightLower[j] > solution[j] + primalTolerance) ||
                         (tightUpper[j] < solution[j] - primalTolerance) ) {
                        status = true;
                    }
                }
            }
        } // EOF probing.

        //--------------------------------------------------
        // Remove zero length row cuts.
        //--------------------------------------------------

	int numRowCons = coinCuts.sizeRowCuts();
	for (j = numRowsBefore; j < numRowCons; ++j) {
	    OsiRowCut & rCut = coinCuts.rowCut(j);
	    int len = rCut.row().getNumElements();
#ifdef BLIS_DEBUG_MORE
	    std::cout << "Cut " << j<<": length = " << len << std::endl;
#endif
	    if (len == 0) {
		// Empty cuts
		coinCuts.eraseRowCut(j);
		--j;
		--numRowCons;
#ifdef BLIS_DEBUG
		std::cout << "WARNING: Empty cut from " << name_ << std::endl;
#endif
	    }
	    else if (len < 0) {
#ifdef BLIS_DEBUG
		std::cout << "ERROR: Cut length = " << len << std::endl;
#endif
		// Error
		assert(0);
	    }
	}

        //--------------------------------------------------
        // Update statistics.
        //--------------------------------------------------

        ++calls_;
        numConsGenerated_ += (coinCuts.sizeCuts() - numConsBefore);
        time_ += (CoinCpuTime() - start);
        if (numConsGenerated_ == 0) {
            ++noConsCalls_;
        }
    }

    return status;
}
Exemple #16
0
/** Perform a branch-and-bound on given setup.*/
void CouenneBab::branchAndBound (Bonmin::BabSetupBase & s) {

  double remaining_time = s.getDoubleParameter(Bonmin::BabSetupBase::MaxTime) + CoinCpuTime();

  /* Put a link to this into solver.*/
  OsiBabSolver *  babInfo = dynamic_cast<OsiBabSolver *>(s.continuousSolver()->getAuxiliaryInfo());
  assert(babInfo);
  Bonmin::BabInfo *  bonBabInfoPtr = dynamic_cast<Bonmin::BabInfo*>(babInfo);

  if (bonBabInfoPtr == NULL) { //Replace with a Bonmin::babInfo
    bonBabInfoPtr = new Bonmin::BabInfo(*babInfo);
    s.continuousSolver()->setAuxiliaryInfo(bonBabInfoPtr);
    delete bonBabInfoPtr;
    bonBabInfoPtr = dynamic_cast<Bonmin::BabInfo*>(s.continuousSolver()->getAuxiliaryInfo());
  }

  bonBabInfoPtr->setBabPtr(this);

  s.nonlinearSolver()->solver()->setup_global_time_limit(s.getDoubleParameter(Bonmin::BabSetupBase::MaxTime));
  OsiSolverInterface * solver = s.continuousSolver()->clone();
  delete modelHandler_;
  modelHandler_ = s.continuousSolver()->messageHandler()->clone();
  model_.passInMessageHandler(modelHandler_);
  model_.assignSolver(solver, true);

  //  s.continuousSolver() = model_.solver();
  //   if(s.continuousSolver()->objects()!=NULL){
  //     model_.addObjects(s.continuousSolver()->numberObjects(),s.continuousSolver()->objects());
  //   }

  int specOpt = s.getIntParameter(Bonmin::BabSetupBase::SpecialOption);
  if (specOpt) {
    model_.setSpecialOptions(specOpt);
    if (specOpt==16) {
      Bonmin::CbcNlpStrategy strat(s.getIntParameter(Bonmin::BabSetupBase::MaxFailures), 
				   s.getIntParameter(Bonmin::BabSetupBase::MaxInfeasible), 
				   s.getIntParameter(Bonmin::BabSetupBase::FailureBehavior));
      model_.setStrategy(strat);
    }
  }

  model_.setMaximumCutPasses(s.getIntParameter(Bonmin::BabSetupBase::NumCutPasses));
  model_.setMaximumCutPassesAtRoot(s.getIntParameter(Bonmin::BabSetupBase::NumCutPassesAtRoot));

  //Setup cutting plane methods
  for (Bonmin::BabSetupBase::CuttingMethods::iterator i = s.cutGenerators().begin() ;
       i != s.cutGenerators().end() ; i++) {

    Bonmin::OaDecompositionBase * oa = dynamic_cast<Bonmin::OaDecompositionBase *>(i->cgl);
    if (oa && oa->reassignLpsolver())
      oa->assignLpInterface(model_.solver());
    model_.addCutGenerator(i->cgl,i->frequency,i->id.c_str(), i->normal,
			   i->atSolution);
    if(i->always){
      model_.cutGenerators()[model_.numberCutGenerators()-1]
	->setMustCallAgain(true);
    }
  }

  for (Bonmin::BabSetupBase::HeuristicMethods::iterator i = s.heuristics().begin() ;
       i != s.heuristics().end() ; i++) {
    CbcHeuristic * heu = i->heuristic;
    heu->setModel(&model_);
    model_.addHeuristic(heu, i->id.c_str());
  }

  //need to record solver logLevel here
  int logLevel = s.continuousSolver()->messageHandler()->logLevel();

  //Set true branch-and-bound parameters
  model_.setLogLevel(s.getIntParameter(Bonmin::BabSetupBase::BabLogLevel));

  // Put back solver logLevel
  model_.solver()->messageHandler()->setLogLevel(logLevel);

  model_.setPrintFrequency(s.getIntParameter(Bonmin::BabSetupBase::BabLogInterval));

  bool ChangedObject = false;
  //Pass over user set branching priorities to Cbc
  if (s.continuousSolver()->objects()==NULL) {
    //assert (s.branchingMethod() == NULL);
    const OsiTMINLPInterface * nlpSolver = s.nonlinearSolver();
    //set priorities, prefered directions...
    const int * priorities = nlpSolver->getPriorities();
    const double * upPsCosts = nlpSolver->getUpPsCosts();
    const double * downPsCosts = nlpSolver->getDownPsCosts();
    const int * directions = nlpSolver->getBranchingDirections();
    bool hasPseudo = (upPsCosts!=NULL);
    model_.findIntegers(true,hasPseudo);
    OsiObject ** simpleIntegerObjects = model_.objects();
    int numberObjects = model_.numberObjects();
    if (priorities != NULL || directions != NULL || hasPseudo) {
      ChangedObject = true;
      for (int i = 0 ; i < numberObjects ; i++) {
	CbcObject * object = dynamic_cast<CbcObject *>
	  (simpleIntegerObjects[i]);
	int iCol = object->columnNumber();
	if (priorities)
	  object->setPriority(priorities[iCol]);
	if (directions)
	  object->setPreferredWay(directions[iCol]);
	if (upPsCosts) {
	  CbcSimpleIntegerPseudoCost * pscObject =
	    dynamic_cast<CbcSimpleIntegerPseudoCost*> (object);
	  pscObject->setUpPseudoCost(upPsCosts[iCol]);
	  pscObject->setDownPseudoCost(downPsCosts[iCol]);
	}
      }
    }

#if 1
    // Now pass user set Sos constraints (code inspired from CoinSolve.cpp)
    const TMINLP::SosInfo * sos = s.nonlinearSolver()->model()->sosConstraints();

    if (!s.getIntParameter(Bonmin::BabSetupBase::DisableSos) && sos && sos->num > 0) {

      // we have some sos constraints

        const OsiTMINLPInterface * nlpSolver = s.nonlinearSolver();
        const int & numSos = sos->num;
	(*nlpSolver->messageHandler())<<"Adding "<<sos->num<<" sos constraints."
				      <<CoinMessageEol;

        CbcObject ** objects = new CbcObject*[numSos];
        const int * starts = sos->starts;
        const int * indices = sos->indices;
        const char * types = sos->types;
        const double * weights = sos->weights;
        //verify if model has user set priorities
        bool hasPriorities = false;
        const int * varPriorities = nlpSolver->getPriorities();
        int numberObjects = model_.numberObjects();
        if (varPriorities)
	  {
	    for (int i = 0 ; i < numberObjects ; i++) {
	      if (varPriorities[i]) {
		hasPriorities = true;
		break;
	      }
	    }
	  }
        const int * sosPriorities = sos->priorities;
        if (sosPriorities)
	  {
	    for (int i = 0 ; i < numSos ; i++) {
	      if (sosPriorities[i]) {
		hasPriorities = true;
		break;
	      }
	    }
	  }
        for (int i = 0 ; i < numSos ; i++)
	  {
	    int start = starts[i];
	    int length = starts[i + 1] - start;
#ifdef DO_IT_NWAY
	    printf("setting nway object\n"),
	      objects[i] = new CbcNWay(&model_, length, &indices[start],
				       i);
	    objects[i]->setPriority(1);
#else
	    objects[i] = new CbcSOS(&model_, length, &indices[start],
				    &weights[start], i, types[i]);
	    objects[i]->setPriority(10);
#endif
	    if (hasPriorities && sosPriorities && sosPriorities[i]) {
	      objects[i]->setPriority(sosPriorities[i]);
	    }
	  }
        model_.addObjects (numSos, objects);
        for (int i = 0 ; i < numSos ; i++)
          delete objects[i];
        delete [] objects;
      }
#endif
    //If Setup contains more objects add them to Cbc
    if (s.objects().size()) {
      CbcObject ** objects = new CbcObject *[s.objects().size()];
      for (unsigned int i = 0 ; i < s.objects().size() ; i++) {
	objects[i] = dynamic_cast<CbcObject *> (s.objects()[i]);
	assert(objects[i]);
	objects[i]->setModel(&model_);
      }
      model_.addObjects ((int) s.objects().size(), objects);
      delete [] objects;
    }

    replaceIntegers(model_.objects(), model_.numberObjects());

  } else { // Pass in objects to Cbc

    // Redundant definition of default branching (as Default == User)
    assert (s.branchingMethod() != NULL);

    // Add nonlinear and integer objects (need to add OsiSOS)
    model_.addObjects (s.continuousSolver () -> numberObjects (), s.continuousSolver () -> objects ());

    // Now model_ has only CouenneObjects and SOS objects

    // for (int i=0; i<nco; i++) 
    //   if (!(dynamic_cast <CbcSimpleInteger *> (s.continuousSolver () -> objects () [i])))
    // 	model_ . objects () [nRealObj++] = s.continuousSolver () -> objects () [i] -> clone ();

    CbcBranchDefaultDecision branch;
    s.branchingMethod()->setSolver(model_.solver());
    BonChooseVariable * strong2 = dynamic_cast<BonChooseVariable *>(s.branchingMethod());
    if (strong2)
      strong2->setCbcModel(&model_);
    branch.setChooseMethod(*s.branchingMethod());

    model_.setBranchingMethod(&branch);
    // prevent duplicating object when copying in CbcModel.cpp
    model_.solver()->deleteObjects();
  }

  model_.setDblParam(CbcModel::CbcCutoffIncrement, s.getDoubleParameter(Bonmin::BabSetupBase::CutoffDecr));

  model_.setCutoff(s.getDoubleParameter(Bonmin::BabSetupBase::Cutoff) + CUTOFF_TOL);

  model_.setDblParam(CbcModel::CbcAllowableGap, s.getDoubleParameter(Bonmin::BabSetupBase::AllowableGap));
  model_.setDblParam(CbcModel::CbcAllowableFractionGap, s.getDoubleParameter(Bonmin::BabSetupBase::AllowableFractionGap));

  // Definition of node selection strategy

  if (s.nodeComparisonMethod()==Bonmin::BabSetupBase::bestBound) {
    CbcCompareObjective compare;
    model_.setNodeComparison(compare);
  }
  else if (s.nodeComparisonMethod()==Bonmin::BabSetupBase::DFS) {
    CbcCompareDepth compare;
    model_.setNodeComparison(compare);
  }
  else if (s.nodeComparisonMethod()==Bonmin::BabSetupBase::BFS) {
    CbcCompareDefault compare;
    compare.setWeight(0.0);
    model_.setNodeComparison(compare);
  }
  else if (s.nodeComparisonMethod()==Bonmin::BabSetupBase::dynamic) {
    CbcCompareDefault compare;
    model_.setNodeComparison(compare);
  }
  else if (s.nodeComparisonMethod()==Bonmin::BabSetupBase::bestGuess) {
    // Right now, this is a mess.  We need a separation of the
    // pseudo costs from the ChooseVariable method
    CbcCompareEstimate compare;
    model_.setNodeComparison(compare);
    GuessHeuristic * guessHeu = new GuessHeuristic(model_);
    model_.addHeuristic(guessHeu);
    delete guessHeu;
  }

  if (s.treeTraversalMethod() == Bonmin::BabSetupBase::HeapOnly) {
    //Do nothing this is the default of Cbc.
  }
  else if (s.treeTraversalMethod() == Bonmin::BabSetupBase::DiveFromBest) {
    CbcDiver treeTraversal;
    treeTraversal.initialize(s);
    model_.passInTreeHandler(treeTraversal);
  }
  else if (s.treeTraversalMethod() == Bonmin::BabSetupBase::ProbedDive) {
    CbcProbedDiver treeTraversal;
    treeTraversal.initialize(s);
    model_.passInTreeHandler(treeTraversal);
  }
  else if (s.treeTraversalMethod() == Bonmin::BabSetupBase::DfsDiveFromBest) {
    CbcDfsDiver treeTraversal;
    treeTraversal.initialize(s);
    model_.passInTreeHandler(treeTraversal);
  }
  else if (s.treeTraversalMethod() == Bonmin::BabSetupBase::DfsDiveDynamic) {
    CbcDfsDiver treeTraversal;
    treeTraversal.initialize(s);
    model_.passInTreeHandler(treeTraversal);

    DiverCompare compare;
    compare.setComparisonDive(*model_.nodeComparison());
    compare.setComparisonBound(CbcCompareObjective());
    CbcDfsDiver * dfs = dynamic_cast<CbcDfsDiver *> (model_.tree());
    assert(dfs);
    compare.setDiver(dfs);
    model_.setNodeComparison(compare);
  }

  model_.setNumberStrong(s.getIntParameter(Bonmin::BabSetupBase::NumberStrong));
  model_.setNumberBeforeTrust(s.getIntParameter(Bonmin::BabSetupBase::MinReliability));
  model_.setNumberPenalties(8);

  model_.setDblParam(CbcModel::CbcMaximumSeconds, s.getDoubleParameter(Bonmin::BabSetupBase::MaxTime));

  model_.setMaximumNodes(s.getIntParameter(Bonmin::BabSetupBase::MaxNodes));

  model_.setMaximumNumberIterations(s.getIntParameter(Bonmin::BabSetupBase::MaxIterations));

  model_.setMaximumSolutions(s.getIntParameter(Bonmin::BabSetupBase::MaxSolutions));

  model_.setIntegerTolerance(s.getDoubleParameter(Bonmin::BabSetupBase::IntTol));

  //Get objects from model_ if it is not null means there are some sos constraints or non-integer branching object
  // pass them to cut generators.
  OsiObject ** objects = model_.objects();

  if (specOpt!=16 && objects) {

    int numberObjects = model_.numberObjects();
    if (objects_ != NULL) {
      for (int i = 0 ; i < nObjects_; i++)
  	delete objects_[i];
    }
    delete [] objects_;
    objects_ = new OsiObject*[numberObjects];
    nObjects_ = numberObjects;
    for (int i = 0 ; i < numberObjects; i++) {
      OsiObject * obj = objects[i];
      CbcSimpleInteger * intObj = dynamic_cast<CbcSimpleInteger *> (obj);
      if (intObj) {
  	objects_[i] = intObj->osiObject();
      }
      else {
  	CbcSOS * sosObj = dynamic_cast<CbcSOS *>(obj);
  	if (sosObj) objects_[i] = sosObj->osiObject(model_.solver());
  	else {//Maybe an unsupported CbcObject
  	  CbcObject * cbcObj = dynamic_cast<CbcObject *>(obj);
  	  if (cbcObj) {
  	    std::cerr<<"Unsupported CbcObject appears in the code"<<std::endl;
  	    throw UNSUPPORTED_CBC_OBJECT;
  	  }
  	  else {//It has to be an OsiObject.
  	    objects_[i]=obj->clone();
  	  }
  	}
      }
    }
    CbcCutGenerator ** gen = model_.cutGenerators();
    int numGen = model_.numberCutGenerators();
    for (int i = 0 ; i < numGen ; i++) {
      Bonmin::OaDecompositionBase * oa = dynamic_cast<Bonmin::OaDecompositionBase * >(gen[i]->generator());
      // if (oa)
      // 	printf ("\n\n\nat least one OADecompBase\n\n\n");
      if (oa) // pass objects
  	oa->setObjects(objects_,nObjects_);
    }
  }

  // if (objects_) {

  //   for (int i = 0 ; i < nObjects_; i++)
  //     delete objects_ [i];

  //   delete [] objects_;
  // }

  // OsiObject ** objects = model_.objects();
  // int numObjects = model_.numberObjects();

  // nObjects_ = 0;
  // objects_ = new OsiObject* [numObjects];

  // for (int i=0; i < numObjects; ++i)
  //   if (objects [i])
  //     objects_ [nObjects_++] = objects [i] -> clone ();

  try {

    //Get the time and start.

    {
      OsiTMINLPInterface * tmpOsi = NULL;
      if(s.nonlinearSolver() == s.continuousSolver()){
        tmpOsi = dynamic_cast<OsiTMINLPInterface *> (model_.solver());
        tmpOsi->forceSolverOutput(s.getIntParameter(Bonmin::BabSetupBase::RootLogLevel)); 
      }

      model_.initialSolve();

      if(tmpOsi != NULL){
        tmpOsi->setSolverOutputToDefault(); 
      }
    }

    int ival;

    s.options()->GetEnumValue("enable_dynamic_nlp", ival, "bonmin.");

    if(s.nonlinearSolver() == s.continuousSolver() && ival) {

	if(!model_.solver()->isProvenOptimal() ){//Something went wrong check if objective is linear and alternate model
	  // can be solved
	  OsiTMINLPInterface * tmpOsi = dynamic_cast<OsiTMINLPInterface *> (model_.solver());
	  TMINLPLinObj * tmp_tminlp = dynamic_cast<TMINLPLinObj *> (tmpOsi->model());
	  tmpOsi->setModel(tmp_tminlp->tminlp());
	  model_.initialSolve();
	} 
	else {
	  LinearCutsGenerator cgl;
	  cgl.initialize(s); 
	  OsiCuts cuts;
	  cgl.generateCuts(*model_.solver(), cuts);
	  std::vector<const OsiRowCut *> mycuts(cuts.sizeRowCuts());
	  for(int i = 0 ; i < cuts.sizeRowCuts() ; i++){
	    mycuts[i] = cuts.rowCutPtr(i);
	  }
	  model_. solver () -> applyRowCuts ((int) mycuts.size(), (const OsiRowCut **) &mycuts[0]);
	}

	//Added by Claudia
	OsiTMINLPInterface * nlpSolver = dynamic_cast<OsiTMINLPInterface *>(model_.solver());
	if(nlpSolver && nlpSolver->getNewCutoffDecr()!=COIN_DBL_MAX)
          model_.setDblParam(CbcModel::CbcCutoffIncrement, nlpSolver->getNewCutoffDecr());

	model_.solver()->resolve();
      }

    // for Couenne
    model_.passInSolverCharacteristics (bonBabInfoPtr);

    continuousRelaxation_ =model_.solver()->getObjValue();
    if (specOpt==16)//Set warm start point for Ipopt
      {
#if 1
	const double * colsol = model_.solver()->getColSolution();
	const double * duals = model_.solver()->getRowPrice();

	OsiTMINLPInterface * tnlpSolver = dynamic_cast<OsiTMINLPInterface *>(model_.solver());
	// Primal dual point is not copied if one (supposedly a better one) has already been put into the solver.
	if(tnlpSolver->problem()->has_x_init() != 2){
	  model_.solver()->setColSolution(colsol);
	  model_.solver()->setRowPrice(duals);
	}
#else
	OsiTMINLPInterface * tnlpSolver = dynamic_cast<OsiTMINLPInterface *>(model_.solver());
	CoinWarmStart * warm = tnlpSolver->solver()->getWarmStart(tnlpSolver->problem());
	tnlpSolver->solver()->setWarmStart(warm, tnlpSolver->problem());
	delete warm;
#endif

#if 0 // Sometimes primal dual point is problematic in the context of Cut-and-branch
	model_.solver()->resolve();
	if(!model_.solver()->isProvenOptimal())
	  model_.solver()->setColSolution(NULL);
#endif 
      }

#ifdef SIGNAL
    CoinSighandler_t saveSignal = SIG_DFL;
    // register signal handler
    saveSignal = signal (SIGINT,couenne_signal_handler);
    currentBranchModel = &model_;
#endif


    // to get node parent info in Cbc, pass parameter 3.
    //model_.branchAndBound(3);
    remaining_time -= CoinCpuTime();
    model_.setDblParam(CbcModel::CbcMaximumSeconds, remaining_time);
    if(remaining_time > 0.)
      model_.branchAndBound();
  }

  catch(TNLPSolver::UnsolvedError *E){
    s.nonlinearSolver()->model()->finalize_solution
      (TMINLP::MINLP_ERROR, 0, NULL, DBL_MAX);
    throw E;
  }

  numNodes_ = model_.getNodeCount();
  bestObj_ = model_.getObjValue();
  bestBound_ = model_.getBestPossibleObjValue();
  mipIterationCount_ = model_.getIterationCount();

  bool hasFailed = false;
  if (specOpt==16)//Did we continue branching on a failure
    {
      CbcNlpStrategy * nlpStrategy = dynamic_cast<CbcNlpStrategy *>(model_.strategy());
      if (nlpStrategy)
        hasFailed = nlpStrategy->hasFailed();
      else
        throw -1;
    }
  else
    hasFailed = s.nonlinearSolver()->hasContinuedOnAFailure();

  // Output summarizing cut generators (taken from CbcSolver.cpp)
  // ToDo put into proper print level

  int numberGenerators = model_.numberCutGenerators();
  for (int iGenerator=0;iGenerator<numberGenerators;iGenerator++) {
    CbcCutGenerator * generator = model_.cutGenerator(iGenerator);
    //CglStored * stored = dynamic_cast<CglStored*>(generator->generator());
    if (true&&!(generator->numberCutsInTotal() || generator->numberColumnCuts()))
      continue;
    if(modelHandler_->logLevel() >= 1) {
      *modelHandler_ << generator->cutGeneratorName()
		     << "was tried" << generator->numberTimesEntered()
		     << "times and created" << generator->numberCutsInTotal()+generator->numberColumnCuts()
		     << "cuts of which" << generator->numberCutsActive()
		     << "were active after adding rounds of cuts";
      // if (generator->timing()) {
      // 	char timebuf[20];
      // 	sprintf(timebuf, "(%.3fs)", generator->timeInCutGenerator());
      // 	*modelHandler_ << timebuf << CoinMessageEol;
      // }
      // else {
      // 	*modelHandler_ << CoinMessageEol;
      // }
    }
  }

  TMINLP::SolverReturn status = TMINLP::MINLP_ERROR;

  if (model_.numberObjects()==0) {
    if (bestSolution_)
      delete [] bestSolution_;
    OsiSolverInterface * solver = 
      (s.nonlinearSolver() == s.continuousSolver())? 
      model_.solver() : s.nonlinearSolver();
    bestSolution_ = new double[solver->getNumCols()];
    CoinCopyN(solver->getColSolution(), solver->getNumCols(),
	      bestSolution_);
    bestObj_ = bestBound_ = solver->getObjValue();
  }

  if (bonBabInfoPtr->bestSolution2().size() > 0) {
    assert((int) bonBabInfoPtr->bestSolution2().size() == s.nonlinearSolver()->getNumCols());
    if (bestSolution_)
      delete [] bestSolution_;
    bestSolution_ = new double[s.nonlinearSolver()->getNumCols()];
    std::copy(bonBabInfoPtr->bestSolution2().begin(), bonBabInfoPtr->bestSolution2().end(),
	      bestSolution_);
    bestObj_ = (bonBabInfoPtr->bestObj2());
    (*s.nonlinearSolver()->messageHandler())<<"\nReal objective function: "
                                            <<bestObj_<<CoinMessageEol;
  }
  else if (model_.bestSolution()) {
    if (bestSolution_)
      delete [] bestSolution_;
    bestSolution_ = new double[s.nonlinearSolver()->getNumCols()];
    CoinCopyN(model_.bestSolution(), s.nonlinearSolver()->getNumCols(), bestSolution_);
  }
  if(remaining_time <= 0.){
    status = TMINLP::LIMIT_EXCEEDED;
    if (bestSolution_) {
      mipStatus_ = Feasible;
    }
    else {
      mipStatus_ = NoSolutionKnown;
    }
  }
  else if (model_.status() == 0) {
    if(model_.isContinuousUnbounded()){
      status = TMINLP::CONTINUOUS_UNBOUNDED;
      mipStatus_ = UnboundedOrInfeasible;
    }
    else
      if (bestSolution_) {
        status = TMINLP::SUCCESS;
        mipStatus_ = FeasibleOptimal;
      }
      else {
        status = TMINLP::INFEASIBLE;
        mipStatus_ = ProvenInfeasible;
      }
  }
  else if (model_.status() == 1 || model_.status() == 5) {
#if (BONMIN_VERSION_MAJOR > 1) || (BONMIN_VERSION_MINOR > 6)
    status = model_.status() == 1 ? TMINLP::LIMIT_EXCEEDED : TMINLP::USER_INTERRUPT;
#else
    status = TMINLP::LIMIT_EXCEEDED;
#endif
    if (bestSolution_) {
      mipStatus_ = Feasible;
    }
    else {
      mipStatus_ = NoSolutionKnown;
    }
  }
  else if (model_.status()==2) {
    status = TMINLP::MINLP_ERROR;
  }

  // Which solution should we use? false if RBS's, true if Cbc's
  bool use_RBS_Cbc = 
    !problem_ ||
    !(problem_ -> getRecordBestSol ()) ||
    !(problem_ -> getRecordBestSol () -> getHasSol()) ||
    (((fabs (bestObj_) < COUENNE_INFINITY / 1e4) && 
      (problem_ -> getRecordBestSol () -> getVal () > bestObj_)));

  /* if we do not pass the cbc solution and problem_ -> getRecordBestSol () -> getHasSol() is true, then there should be a solution vector in problem_ -> getRecordBestSol () */
  assert(use_RBS_Cbc || problem_ -> getRecordBestSol () -> getSol() != NULL);

  s.nonlinearSolver () -> model () -> finalize_solution 
    (status,
     s.nonlinearSolver () -> getNumCols (),
     use_RBS_Cbc ? bestSolution_ : problem_ -> getRecordBestSol () -> getSol (),
     use_RBS_Cbc ? bestObj_      : problem_ -> getRecordBestSol () -> getVal ());
}
Exemple #17
0
// Generate cuts
void
CglFakeClique::generateCuts(const OsiSolverInterface& si, OsiCuts & cs,
			const CglTreeInfo info)
{
  if (fakeSolver_) {
    assert (si.getNumCols()==fakeSolver_->getNumCols());
    fakeSolver_->setColLower(si.getColLower());
    const double * solution = si.getColSolution();
    fakeSolver_->setColSolution(solution);
    fakeSolver_->setColUpper(si.getColUpper());
    // get and set branch and bound cutoff
    double cutoff;
    si.getDblParam(OsiDualObjectiveLimit,cutoff);
    fakeSolver_->setDblParam(OsiDualObjectiveLimit,COIN_DBL_MAX);
#ifdef COIN_HAS_CLP
    OsiClpSolverInterface * clpSolver
      = dynamic_cast<OsiClpSolverInterface *> (fakeSolver_);
    if (clpSolver) {
      // fix up fake solver
      const ClpSimplex * siSimplex = clpSolver->getModelPtr();
      // need to set djs
      memcpy(siSimplex->primalColumnSolution(),
	     si.getReducedCost(),si.getNumCols()*sizeof(double));
      fakeSolver_->setDblParam(OsiDualObjectiveLimit,cutoff);
    }
#endif
    const CoinPackedMatrix * matrixByRow = si.getMatrixByRow();
    const double * elementByRow = matrixByRow->getElements();
    const int * column = matrixByRow->getIndices();
    const CoinBigIndex * rowStart = matrixByRow->getVectorStarts();
    const int * rowLength = matrixByRow->getVectorLengths();
    const double * rowUpper = si.getRowUpper();
    const double * rowLower = si.getRowLower();
    
    // Scan all rows looking for possibles
    int numberRows = si.getNumRows();
    double tolerance = 1.0e-3;
    for (int iRow=0;iRow<numberRows;iRow++) {
      CoinBigIndex start = rowStart[iRow];
      CoinBigIndex end = start + rowLength[iRow];
      double upRhs = rowUpper[iRow]; 
      double loRhs = rowLower[iRow]; 
      double sum = 0.0;
      for (CoinBigIndex j=start;j<end;j++) {
	int iColumn=column[j];
	double value = elementByRow[j];
	sum += solution[iColumn]*value;
      }
      if (sum<loRhs-tolerance||sum>upRhs+tolerance) {
	// add as cut
	OsiRowCut rc;
	rc.setLb(loRhs);
	rc.setUb(upRhs);
	rc.setRow(end-start,column+start,elementByRow+start,false);
	CoinAbsFltEq equal(1.0e-12);
	cs.insertIfNotDuplicate(rc,equal);
      }
    }
    CglClique::generateCuts(*fakeSolver_,cs,info);
    if (probing_) {
      probing_->generateCuts(*fakeSolver_,cs,info);
    }
  } else {
    // just use real solver
    CglClique::generateCuts(si,cs,info);
  }
}
//--------------------------------------------------------------------------
// test solution methods.
void OsiCbcSolverInterfaceUnitTest(const std::string & mpsDir, const std::string & netlibDir)
{
  {    
    CoinRelFltEq eq;
    OsiCbcSolverInterface m;
    std::string fn = mpsDir+"exmip1";
    m.readMps(fn.c_str(),"mps");

    {
      OsiCbcSolverInterface im;    
      OSIUNITTEST_ASSERT_ERROR(im.getNumCols() == 0, {}, "cbc", "default constructor");
      OSIUNITTEST_ASSERT_ERROR(im.getModelPtr() != NULL, {}, "cbc", "default constructor");
    }
    
    // Test copy constructor and assignment operator
    {
      OsiCbcSolverInterface lhs;
      {      
        OsiCbcSolverInterface im(m);        
        
        OsiCbcSolverInterface imC1(im);
        OSIUNITTEST_ASSERT_ERROR(imC1.getModelPtr() != im.getModelPtr(), {}, "cbc", "copy constructor");
        OSIUNITTEST_ASSERT_ERROR(imC1.getNumCols()  == im.getNumCols(),  {}, "cbc", "copy constructor");
        OSIUNITTEST_ASSERT_ERROR(imC1.getNumRows()  == im.getNumRows(),  {}, "cbc", "copy constructor");
        
        OsiCbcSolverInterface imC2(im);
        OSIUNITTEST_ASSERT_ERROR(imC2.getModelPtr() != im.getModelPtr(), {}, "cbc", "copy constructor");
        OSIUNITTEST_ASSERT_ERROR(imC2.getNumCols()  == im.getNumCols(),  {}, "cbc", "copy constructor");
        OSIUNITTEST_ASSERT_ERROR(imC2.getNumRows()  == im.getNumRows(),  {}, "cbc", "copy constructor");

        OSIUNITTEST_ASSERT_ERROR(imC1.getModelPtr() != imC2.getModelPtr(), {}, "cbc", "copy constructor");
        
        lhs = imC2;
      }

      // Test that lhs has correct values even though rhs has gone out of scope
      OSIUNITTEST_ASSERT_ERROR(lhs.getModelPtr() != m.getModelPtr(), {}, "cbc", "assignment operator");
      OSIUNITTEST_ASSERT_ERROR(lhs.getNumCols()  == m.getNumCols(),  {}, "cbc", "copy constructor");
      OSIUNITTEST_ASSERT_ERROR(lhs.getNumRows()  == m.getNumRows(),  {}, "cbc", "copy constructor");
    }

    // Test clone
    {
      OsiCbcSolverInterface cbcSi(m);
      OsiSolverInterface * siPtr = &cbcSi;
      OsiSolverInterface * siClone = siPtr->clone();
      OsiCbcSolverInterface * cbcClone = dynamic_cast<OsiCbcSolverInterface*>(siClone);

      OSIUNITTEST_ASSERT_ERROR(cbcClone != NULL, {}, "cbc", "clone");
      OSIUNITTEST_ASSERT_ERROR(cbcClone->getModelPtr() != cbcSi.getModelPtr(), {}, "cbc", "clone");
      OSIUNITTEST_ASSERT_ERROR(cbcClone->getNumRows() == cbcSi.getNumRows(),   {}, "cbc", "clone");
      OSIUNITTEST_ASSERT_ERROR(cbcClone->getNumCols() == m.getNumCols(),       {}, "cbc", "clone");
      
      delete siClone;
    }
  
    // test infinity
    {
      OsiCbcSolverInterface si;
      OSIUNITTEST_ASSERT_ERROR(si.getInfinity() == OsiCbcInfinity, {}, "cbc", "infinity");
    }     
    
    // Test some catches
    if (!OsiCbcHasNDEBUG())
    {
      OsiCbcSolverInterface solver;
      try {
        solver.setObjCoeff(0,0.0);
        OSIUNITTEST_ADD_OUTCOME("cbc", "setObjCoeff on empty model", "should throw exception", OsiUnitTest::TestOutcome::ERROR, false);
      }
      catch (CoinError e) {
        if (OsiUnitTest::verbosity >= 1)
          std::cout<<"Correct throw from setObjCoeff on empty model"<<std::endl;
      }

      std::string fn = mpsDir+"exmip1";
      solver.readMps(fn.c_str(),"mps");
      OSIUNITTEST_CATCH_ERROR(solver.setObjCoeff(0,0.0), {}, "cbc", "setObjCoeff on nonempty model");

      try {
        int index[]={0,20};
        double value[]={0.0,0.0,0.0,0.0};
        solver.setColSetBounds(index,index+2,value);
        OSIUNITTEST_ADD_OUTCOME("cbc", "setColSetBounds on cols not in model", "should throw exception", OsiUnitTest::TestOutcome::ERROR, false);
      }
      catch (CoinError e) {
        if (OsiUnitTest::verbosity >= 1)
          std::cout<<"Correct throw from setObjCoeff on empty model"<<std::endl;
      }
    }
    
    {    
      OsiCbcSolverInterface cbcSi(m);
      int nc = cbcSi.getNumCols();
      int nr = cbcSi.getNumRows();
      const double * cl = cbcSi.getColLower();
      const double * cu = cbcSi.getColUpper();
      const double * rl = cbcSi.getRowLower();
      const double * ru = cbcSi.getRowUpper();
      OSIUNITTEST_ASSERT_ERROR(nc == 8, return, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(nr == 5, return, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cl[0],2.5), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cl[1],0.0), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cu[1],4.1), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cu[2],1.0), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(rl[0],2.5), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(rl[4],3.0), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(ru[1],2.1), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(ru[4],15.), {}, "cbc", "read and copy exmip1");
      
      const double * cs = cbcSi.getColSolution();
      OSIUNITTEST_ASSERT_ERROR(eq(cs[0],2.5), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cs[7],0.0), {}, "cbc", "read and copy exmip1");
      
      OSIUNITTEST_ASSERT_ERROR(!eq(cl[3],1.2345), {}, "cbc", "set col lower");
      cbcSi.setColLower( 3, 1.2345 );
      OSIUNITTEST_ASSERT_ERROR( eq(cbcSi.getColLower()[3],1.2345), {}, "cbc", "set col lower");
      
      OSIUNITTEST_ASSERT_ERROR(!eq(cbcSi.getColUpper()[4],10.2345), {}, "cbc", "set col upper");
      cbcSi.setColUpper( 4, 10.2345 );
      OSIUNITTEST_ASSERT_ERROR( eq(cbcSi.getColUpper()[4],10.2345), {}, "cbc", "set col upper");

      // LH: Objective will depend on how underlying solver constructs and maintains initial solution
      double objValue = cbcSi.getObjValue();
      OSIUNITTEST_ASSERT_ERROR(eq(objValue,3.5) || eq(objValue,10.5), {}, "cbc", "getObjValue() before solve");

      OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[0], 1.0), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[1], 0.0), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[2], 0.0), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[3], 0.0), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[4], 2.0), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[5], 0.0), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[6], 0.0), {}, "cbc", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cbcSi.getObjCoefficients()[7],-1.0), {}, "cbc", "read and copy exmip1");
    }
    
    // Test matrixByRow method
    { 
      const OsiCbcSolverInterface si(m);
      const CoinPackedMatrix * smP = si.getMatrixByRow();

      OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim()    ==  5, return, "cbc", "getMatrixByRow: major dim");
      OSIUNITTEST_ASSERT_ERROR(smP->getMinorDim()    ==  8, return, "cbc", "getMatrixByRow: major dim");
      OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "cbc", "getMatrixByRow: num elements");
      OSIUNITTEST_ASSERT_ERROR(smP->getSizeVectorStarts() == 6, return, "cbc", "getMatrixByRow: num elements");

#ifdef OSICBC_TEST_MTX_STRUCTURE
      CoinRelFltEq eq;
      const double * ev = smP->getElements();
      OSIUNITTEST_ASSERT_ERROR(eq(ev[0],   3.0), {}, "cbc", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[1],   1.0), {}, "cbc", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[2],  -2.0), {}, "cbc", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[3],  -1.0), {}, "cbc", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[4],  -1.0), {}, "cbc", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[5],   2.0), {}, "cbc", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[6],   1.1), {}, "cbc", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[7],   1.0), {}, "cbc", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[8],   1.0), {}, "cbc", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[9],   2.8), {}, "cbc", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[10], -1.2), {}, "cbc", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[11],  5.6), {}, "cbc", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[12],  1.0), {}, "cbc", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[13],  1.9), {}, "cbc", "getMatrixByRow: elements");
      
      const int * mi = smP->getVectorStarts();
      OSIUNITTEST_ASSERT_ERROR(mi[0] ==  0, {}, "cbc", "getMatrixByRow: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[1] ==  5, {}, "cbc", "getMatrixByRow: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[2] ==  7, {}, "cbc", "getMatrixByRow: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[3] ==  9, {}, "cbc", "getMatrixByRow: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "cbc", "getMatrixByRow: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "cbc", "getMatrixByRow: vector starts");
      
      const int * ei = smP->getIndices();
      OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "cbc", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "cbc", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "cbc", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "cbc", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "cbc", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "cbc", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "cbc", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "cbc", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "cbc", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "cbc", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "cbc", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "cbc", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "cbc", "getMatrixByRow: indices");
#else	// OSICBC_TEST_MTX_STRUCTURE

      CoinPackedMatrix exmip1Mtx ;
      exmip1Mtx.reverseOrderedCopyOf(BuildExmip1Mtx()) ;
      OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*smP), {}, "cbc", "getMatrixByRow") ;
#endif	// OSICBC_TEST_MTX_STRUCTURE
    }

    // Test adding several cuts, and handling of a coefficient of infinity
    // in the constraint matrix.
    {
      OsiCbcSolverInterface fim;
      std::string fn = mpsDir+"exmip1";
      fim.readMps(fn.c_str(),"mps");
      // exmip1.mps has 2 integer variables with index 2 & 3
      fim.initialSolve();
      OsiRowCut cuts[3];
      
      
      // Generate one ineffective cut plus two trivial cuts
      int c;
      int nc = fim.getNumCols();
      int *inx = new int[nc];
      for (c=0;c<nc;c++) inx[c]=c;
      double *el = new double[nc];
      for (c=0;c<nc;c++) el[c]=1.0e-50+((double)c)*((double)c);
      
      cuts[0].setRow(nc,inx,el);
      cuts[0].setLb(-100.);
      cuts[0].setUb(500.);
      cuts[0].setEffectiveness(22);
      el[4]=0.0; // to get inf later
      
      for (c=2;c<4;c++) {
        el[0]=1.0;
        inx[0]=c;
        cuts[c-1].setRow(1,inx,el);
        cuts[c-1].setLb(1.);
        cuts[c-1].setUb(100.);
        cuts[c-1].setEffectiveness(c);
      }
      fim.writeMps("x1.mps");
      fim.applyRowCuts(3,cuts);
      fim.writeMps("x2.mps");
      // resolve - should get message about zero elements
      fim.resolve();
      fim.writeMps("x3.mps");
      // check integer solution
      const double * cs = fim.getColSolution();
      CoinRelFltEq eq;
      OSIUNITTEST_ASSERT_ERROR(eq(cs[2], 1.0), {}, "cbc", "add cuts");
      OSIUNITTEST_ASSERT_ERROR(eq(cs[3], 1.0), {}, "cbc", "add cuts");
      // check will find invalid matrix
      el[0]=1.0/el[4];
      inx[0]=0;
      cuts[0].setRow(nc,inx,el);
      cuts[0].setLb(-100.);
      cuts[0].setUb(500.);
      cuts[0].setEffectiveness(22);
      fim.applyRowCut(cuts[0]);
      // resolve - should get message about zero elements
      fim.resolve();
      OSIUNITTEST_ASSERT_WARNING(fim.isAbandoned(), {}, "cbc", "add cuts");
      delete[]el;
      delete[]inx;
    }

    // Test matrixByCol method
    {
      const OsiCbcSolverInterface si(m);
      const CoinPackedMatrix * smP = si.getMatrixByCol();

      OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim()    ==  8, return, "cbc", "getMatrixByCol: major dim");
      OSIUNITTEST_ASSERT_ERROR(smP->getMinorDim()    ==  5, return, "cbc", "getMatrixByCol: minor dim");
      OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "cbc", "getMatrixByCol: number of elements");
      OSIUNITTEST_ASSERT_ERROR(smP->getSizeVectorStarts() == 9, return, "cbc", "getMatrixByCol: vector starts size");

#ifdef OSICBC_TEST_MTX_STRUCTURE
      CoinRelFltEq eq;
      const double * ev = smP->getElements();
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "cbc", "getMatrixByCol: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 5.6), {}, "cbc", "getMatrixByCol: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2], 1.0), {}, "cbc", "getMatrixByCol: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3], 2.0), {}, "cbc", "getMatrixByCol: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4], 1.1), {}, "cbc", "getMatrixByCol: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 1.0), {}, "cbc", "getMatrixByCol: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6],-2.0), {}, "cbc", "getMatrixByCol: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 2.8), {}, "cbc", "getMatrixByCol: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8],-1.0), {}, "cbc", "getMatrixByCol: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 1.0), {}, "cbc", "getMatrixByCol: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[10], 1.0), {}, "cbc", "getMatrixByCol: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[11],-1.2), {}, "cbc", "getMatrixByCol: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[12],-1.0), {}, "cbc", "getMatrixByCol: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "getMatrixByCol: elements");
      
      const CoinBigIndex * mi = smP->getVectorStarts();
      OSIUNITTEST_ASSERT_ERROR(mi[0] ==  0, {}, "cbc", "getMatrixByCol: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[1] ==  2, {}, "cbc", "getMatrixByCol: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[2] ==  4, {}, "cbc", "getMatrixByCol: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[3] ==  6, {}, "cbc", "getMatrixByCol: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[4] ==  8, {}, "cbc", "getMatrixByCol: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[5] == 10, {}, "cbc", "getMatrixByCol: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[6] == 11, {}, "cbc", "getMatrixByCol: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[7] == 12, {}, "cbc", "getMatrixByCol: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[8] == 14, {}, "cbc", "getMatrixByCol: vector starts");
      
      const int * ei = smP->getIndices();
      OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "getMatrixByCol: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 4, {}, "cbc", "getMatrixByCol: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 0, {}, "cbc", "getMatrixByCol: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 1, {}, "cbc", "getMatrixByCol: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 1, {}, "cbc", "getMatrixByCol: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 2, {}, "cbc", "getMatrixByCol: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 0, {}, "cbc", "getMatrixByCol: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 3, {}, "cbc", "getMatrixByCol: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 0, {}, "cbc", "getMatrixByCol: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 4, {}, "cbc", "getMatrixByCol: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[10] == 2, {}, "cbc", "getMatrixByCol: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[11] == 3, {}, "cbc", "getMatrixByCol: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[12] == 0, {}, "cbc", "getMatrixByCol: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[13] == 4, {}, "cbc", "getMatrixByCol: indices");
#else // OSICBC_TEST_MTX_STRUCTURE

      CoinPackedMatrix &exmip1Mtx = BuildExmip1Mtx() ;
      OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*smP), {}, "cbc", "getMatrixByCol");
#endif	// OSICBC_TEST_MTX_STRUCTURE     
    }

    //--------------
    // Test rowsense, rhs, rowrange, matrixByRow, solver assignment
    {
      OsiCbcSolverInterface lhs;
      {
        OsiCbcSolverInterface siC1(m);

        const char   * siC1rs  = siC1.getRowSense();
        OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "cbc", "row sense");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "cbc", "row sense");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "cbc", "row sense");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "cbc", "row sense");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "cbc", "row sense");

        const double * siC1rhs = siC1.getRightHandSide();
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "cbc", "right hand side");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "cbc", "right hand side");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "cbc", "right hand side");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "cbc", "right hand side");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "cbc", "right hand side");

        const double * siC1rr  = siC1.getRowRange();
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "cbc", "row range");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "cbc", "row range");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "cbc", "row range");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "cbc", "row range");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "cbc", "row range");
        
        const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow();
        OSIUNITTEST_ASSERT_ERROR(siC1mbr != NULL, {}, "cbc", "matrix by row");
        OSIUNITTEST_ASSERT_ERROR(siC1mbr->getMajorDim()    ==  5, return, "cbc", "matrix by row: major dim");
        OSIUNITTEST_ASSERT_ERROR(siC1mbr->getMinorDim()    ==  8, return, "cbc", "matrix by row: major dim");
        OSIUNITTEST_ASSERT_ERROR(siC1mbr->getNumElements() == 14, return, "cbc", "matrix by row: num elements");
        OSIUNITTEST_ASSERT_ERROR(siC1mbr->getSizeVectorStarts() == 6, return, "cbc", "matrix by row: num elements");

#ifdef OSICBC_TEST_MTX_STRUCTURE
        const double * ev = siC1mbr->getElements();
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "cbc", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 1.0), {}, "cbc", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "cbc", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3],-1.0), {}, "cbc", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4],-1.0), {}, "cbc", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 2.0), {}, "cbc", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 1.1), {}, "cbc", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "cbc", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "cbc", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 2.8), {}, "cbc", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[10],-1.2), {}, "cbc", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "cbc", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "cbc", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "matrix by row: elements");

        const CoinBigIndex * mi = siC1mbr->getVectorStarts();
        OSIUNITTEST_ASSERT_ERROR(mi[0] ==  0, {}, "cbc", "matrix by row: vector starts");
        OSIUNITTEST_ASSERT_ERROR(mi[1] ==  5, {}, "cbc", "matrix by row: vector starts");
        OSIUNITTEST_ASSERT_ERROR(mi[2] ==  7, {}, "cbc", "matrix by row: vector starts");
        OSIUNITTEST_ASSERT_ERROR(mi[3] ==  9, {}, "cbc", "matrix by row: vector starts");
        OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "cbc", "matrix by row: vector starts");
        OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "cbc", "matrix by row: vector starts");

        const int * ei = siC1mbr->getIndices();
        OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "cbc", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "cbc", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "cbc", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "cbc", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "cbc", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "cbc", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "cbc", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "cbc", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "cbc", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "cbc", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "cbc", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "cbc", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "cbc", "matrix by row: indices");
#else	// OSICBC_TEST_MTX_STRUCTURE

        CoinPackedMatrix exmip1Mtx ;
        exmip1Mtx.reverseOrderedCopyOf(BuildExmip1Mtx()) ;
        OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*siC1mbr), {}, "cbc", "matrix by row");
#endif	// OSICBC_TEST_MTX_STRUCTURE

        OSIUNITTEST_ASSERT_WARNING(siC1rs  == siC1.getRowSense(), {}, "cbc", "row sense");
        OSIUNITTEST_ASSERT_WARNING(siC1rhs == siC1.getRightHandSide(), {}, "cbc", "right hand side");
        OSIUNITTEST_ASSERT_WARNING(siC1rr  == siC1.getRowRange(), {}, "cbc", "row range");

        // Change CBC Model by adding free row
        OsiRowCut rc;
        rc.setLb(-COIN_DBL_MAX);
        rc.setUb( COIN_DBL_MAX);
        OsiCuts cuts;
        cuts.insert(rc);
        siC1.applyCuts(cuts);

        siC1rs  = siC1.getRowSense();
        OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "cbc", "row sense after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "cbc", "row sense after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "cbc", "row sense after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "cbc", "row sense after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "cbc", "row sense after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[5] == 'N', {}, "cbc", "row sense after adding row");

        siC1rhs = siC1.getRightHandSide();
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "cbc", "right hand side after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "cbc", "right hand side after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "cbc", "right hand side after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "cbc", "right hand side after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "cbc", "right hand side after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[5],0.0), {}, "cbc", "right hand side after adding row");

        siC1rr  = siC1.getRowRange();
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "cbc", "row range after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "cbc", "row range after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "cbc", "row range after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "cbc", "row range after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "cbc", "row range after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[5],0.0), {}, "cbc", "row range after adding row");

        lhs = siC1;
      }

      // Test that lhs has correct values even though siC1 has gone out of scope    
      const char * lhsrs  = lhs.getRowSense();
      OSIUNITTEST_ASSERT_ERROR(lhsrs[0] == 'G', {}, "cbc", "row sense after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhsrs[1] == 'L', {}, "cbc", "row sense after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhsrs[2] == 'E', {}, "cbc", "row sense after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhsrs[3] == 'R', {}, "cbc", "row sense after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhsrs[4] == 'R', {}, "cbc", "row sense after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhsrs[5] == 'N', {}, "cbc", "row sense after assignment");
      
      const double * lhsrhs = lhs.getRightHandSide();
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[0],2.5), {}, "cbc", "right hand side after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[1],2.1), {}, "cbc", "right hand side after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[2],4.0), {}, "cbc", "right hand side after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[3],5.0), {}, "cbc", "right hand side after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[4],15.), {}, "cbc", "right hand side after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[5],0.0), {}, "cbc", "right hand side after assignment");
      
      const double *lhsrr = lhs.getRowRange();
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[0],0.0), {}, "cbc", "row range after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[1],0.0), {}, "cbc", "row range after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[2],0.0), {}, "cbc", "row range after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[3],5.0-1.8), {}, "cbc", "row range after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[4],15.0-3.0), {}, "cbc", "row range after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[5],0.0), {}, "cbc", "row range after assignment");
      
      const CoinPackedMatrix * lhsmbr = lhs.getMatrixByRow();
      OSIUNITTEST_ASSERT_ERROR(lhsmbr != NULL, {}, "cbc", "matrix by row after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhsmbr->getMajorDim()    ==  6, return, "cbc", "matrix by row after assignment: major dim");
      OSIUNITTEST_ASSERT_ERROR(lhsmbr->getNumElements() == 14, return, "cbc", "matrix by row after assignment: num elements");


#ifdef OSICBC_TEST_MTX_STRUCTURE
      const double * ev = lhsmbr->getElements();
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "cbc", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 1.0), {}, "cbc", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "cbc", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3],-1.0), {}, "cbc", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4],-1.0), {}, "cbc", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 2.0), {}, "cbc", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 1.1), {}, "cbc", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "cbc", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "cbc", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 2.8), {}, "cbc", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[10],-1.2), {}, "cbc", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "cbc", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "cbc", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "cbc", "matrix by row after assignment: elements");
      
      const CoinBigIndex * mi = lhsmbr->getVectorStarts();
      OSIUNITTEST_ASSERT_ERROR(mi[0] ==  0, {}, "cbc", "matrix by row after assignment: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[1] ==  5, {}, "cbc", "matrix by row after assignment: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[2] ==  7, {}, "cbc", "matrix by row after assignment: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[3] ==  9, {}, "cbc", "matrix by row after assignment: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "cbc", "matrix by row after assignment: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "cbc", "matrix by row after assignment: vector starts");
      
      const int * ei = lhsmbr->getIndices();
      OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "cbc", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "cbc", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "cbc", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "cbc", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "cbc", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "cbc", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "cbc", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "cbc", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "cbc", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "cbc", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "cbc", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "cbc", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "cbc", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "cbc", "matrix by row after assignment: indices");
#else	// OSICBC_TEST_MTX_STRUCTURE

/*
  This admittedly looks bogus, but it's the equivalent operation on the matrix
  for inserting a cut of the form -Inf <= +Inf (i.e., a cut with no
  coefficients).
*/
      CoinPackedMatrix exmip1Mtx ;
      exmip1Mtx.reverseOrderedCopyOf(BuildExmip1Mtx()) ;
      CoinPackedVector freeRow ;
      exmip1Mtx.appendRow(freeRow) ;
      OSIUNITTEST_ASSERT_ERROR(exmip1Mtx.isEquivalent(*lhsmbr), {}, "cbc", "matrix by row after assignment");
#endif	// OSICBC_TEST_MTX_STRUCTURE
    }
  }

  // Test add/delete columns
  {    
    OsiCbcSolverInterface m;
    std::string fn = mpsDir+"p0033";
    m.readMps(fn.c_str(),"mps");
    double inf = m.getInfinity();

    CoinPackedVector c0;
    c0.insert(0, 4);
    c0.insert(1, 1);
    m.addCol(c0, 0, inf, 3);
    m.initialSolve();
    double objValue = m.getObjValue();
    CoinRelFltEq eq(1.0e-2);
    OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "cbc", "objvalue after adding col");

    // Try deleting first column that's nonbasic at lower bound (0).
    int * d = new int[1];
    CoinWarmStartBasis *cwsb = dynamic_cast<CoinWarmStartBasis *>(m.getWarmStart()) ;
    OSIUNITTEST_ASSERT_ERROR(cwsb != NULL, {}, "cbc", "get warmstart basis");
    CoinWarmStartBasis::Status stati ;
    int iCol ;
    for (iCol = 0 ;  iCol < cwsb->getNumStructural() ; iCol++)
    { stati = cwsb->getStructStatus(iCol) ;
      if (stati == CoinWarmStartBasis::atLowerBound) break ; }
    d[0]=iCol;
    m.deleteCols(1,d);
    delete [] d;
    delete cwsb;
    d=NULL;
    m.resolve();
    objValue = m.getObjValue();
    OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "clp", "objvalue after deleting first col");

    // Try deleting column we added. If basic, go to initialSolve as deleting
    // basic variable trashes basis required for warm start.
    iCol = m.getNumCols()-1;
    cwsb = dynamic_cast<CoinWarmStartBasis *>(m.getWarmStart()) ;
    stati =  cwsb->getStructStatus(iCol) ;
    delete cwsb;
    m.deleteCols(1,&iCol);
    if (stati == CoinWarmStartBasis::basic)
    { m.initialSolve() ; }
    else
    { m.resolve(); }
    objValue = m.getObjValue();
    OSIUNITTEST_ASSERT_ERROR(eq(objValue,2520.57), {}, "clp", "objvalue after deleting added col");
  }

  // Build a model
  {    
    OsiCbcSolverInterface model;
    std::string fn = mpsDir+"p0033";
    model.readMps(fn.c_str(),"mps");
    // Point to data
    int numberRows = model.getNumRows();
    const double * rowLower = model.getRowLower();
    const double * rowUpper = model.getRowUpper();
    int numberColumns = model.getNumCols();
    const double * columnLower = model.getColLower();
    const double * columnUpper = model.getColUpper();
    const double * columnObjective = model.getObjCoefficients();
    // get row copy
    CoinPackedMatrix rowCopy = *model.getMatrixByRow();
    const int * column = rowCopy.getIndices();
    const int * rowLength = rowCopy.getVectorLengths();
    const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
    const double * element = rowCopy.getElements();
    
    // solve
    model.initialSolve();
    // Now build new model
    CoinModel build;
    // Row bounds
    int iRow;
    for (iRow=0;iRow<numberRows;iRow++) {
      build.setRowBounds(iRow,rowLower[iRow],rowUpper[iRow]);
    }
    // Column bounds and objective
    int iColumn;
    for (iColumn=0;iColumn<numberColumns;iColumn++) {
      build.setColumnLower(iColumn,columnLower[iColumn]);
      build.setColumnUpper(iColumn,columnUpper[iColumn]);
      build.setObjective(iColumn,columnObjective[iColumn]);
    }
    // Adds elements one by one by row (backwards by row)
    for (iRow=numberRows-1;iRow>=0;iRow--) {
      int start = rowStart[iRow];
      for (int j=start;j<start+rowLength[iRow];j++) 
        build(iRow,column[j],element[j]);
    }
    // Now create Model
    OsiCbcSolverInterface model2;
    model2.loadFromCoinModel(build);
    model2.initialSolve();
    // Save - should be continuous
    model2.writeMps("continuous");
    int * whichInteger = new int[numberColumns];
    for (iColumn=0;iColumn<numberColumns;iColumn++) 
      whichInteger[iColumn]=iColumn;
    // mark as integer
    model2.setInteger(whichInteger,numberColumns);
    delete [] whichInteger;
    // save - should be integer
    model2.writeMps("integer");
    
    // Now do with strings attached
    // Save build to show how to go over rows
    CoinModel saveBuild = build;
    build = CoinModel();
    // Column bounds
    for (iColumn=0;iColumn<numberColumns;iColumn++) {
      build.setColumnLower(iColumn,columnLower[iColumn]);
      build.setColumnUpper(iColumn,columnUpper[iColumn]);
    }
    // Objective - half the columns as is and half with multiplier of "1.0+multiplier"
    // Pick up from saveBuild (for no reason at all)
    for (iColumn=0;iColumn<numberColumns;iColumn++) {
      double value = saveBuild.objective(iColumn);
      if (iColumn*2<numberColumns) {
        build.setObjective(iColumn,columnObjective[iColumn]);
      } else {
        // create as string
        char temp[100];
        sprintf(temp,"%g + abs(%g*multiplier)",value,value);
        build.setObjective(iColumn,temp);
      }
    }
    // It then adds rows one by one but for half the rows sets their values
    //      with multiplier of "1.0+1.5*multiplier"
    for (iRow=0;iRow<numberRows;iRow++) {
      if (iRow*2<numberRows) {
        // add row in simple way
        int start = rowStart[iRow];
        build.addRow(rowLength[iRow],column+start,element+start,
                     rowLower[iRow],rowUpper[iRow]);
      } else {
        // As we have to add one by one let's get from saveBuild
        CoinModelLink triple=saveBuild.firstInRow(iRow);
        while (triple.column()>=0) {
          int iColumn = triple.column();
          if (iColumn*2<numberColumns) {
            // just value as normal
            build(iRow,triple.column(),triple.value());
          } else {
            // create as string
            char temp[100];
            sprintf(temp,"%g + (1.5*%g*multiplier)",triple.value(), triple.value());
            build(iRow,iColumn,temp);
          }
          triple=saveBuild.next(triple);
        }
        // but remember to do rhs
        build.setRowLower(iRow,rowLower[iRow]);
        build.setRowUpper(iRow,rowUpper[iRow]);
      }
    }
    // If small switch on error printing
    if (numberColumns<50)
      build.setLogLevel(1);
    // should fail as we never set multiplier
    OSIUNITTEST_ASSERT_ERROR(model2.loadFromCoinModel(build) != 0, {}, "cbc", "build model with missing multipliers");
    build.associateElement("multiplier",0.0);
    OSIUNITTEST_ASSERT_ERROR(model2.loadFromCoinModel(build) == 0, {}, "cbc", "build model");
    model2.initialSolve();
    // It then loops with multiplier going from 0.0 to 2.0 in increments of 0.1
    for (double multiplier=0.0;multiplier<2.0;multiplier+= 0.1) {
      build.associateElement("multiplier",multiplier);
      OSIUNITTEST_ASSERT_ERROR(model2.loadFromCoinModel(build,true) == 0, {}, "cbc", "build model with increasing multiplier");
      model2.resolve();
    }
  }

  // branch and bound
  {    
    OsiCbcSolverInterface m;
    std::string fn = mpsDir+"p0033";
    m.readMps(fn.c_str(),"mps");
    m.initialSolve();
    //m.messageHandler()->setLogLevel(0);
    m.getModelPtr()->messageHandler()->setLogLevel(0);
    m.branchAndBound();
  }

  // branch and bound using CbcModel!!!!!!!
  {    
    OsiCbcSolverInterface mm;
    OsiCbcSolverInterface m(&mm);
    std::string fn = mpsDir+"p0033";
    m.readMps(fn.c_str(),"mps");
    m.initialSolve();
    m.branchAndBound();
  }

  // Do common solverInterface testing 
  {
    OsiCbcSolverInterface m;
    OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir);
  }
  {
    OsiCbcSolverInterface mm;
    OsiCbcSolverInterface m(&mm);
    OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir);
  }
}
Exemple #19
0
int main( int argc, char **argv )
{
    if ( argc < 2 )
    {
        printf("Invalid number of parameters!\n");
        exit( EXIT_FAILURE );
    }

    char problemName[ 256 ];
    getFileName( problemName, argv[1] );

    clock_t start = clock();
    OsiClpSolverInterface *realSolver = new OsiClpSolverInterface();
    realSolver->getModelPtr()->setPerturbation(50); /* makes CLP faster for hard instances */
    OsiSolverInterface *solver = (OsiSolverInterface*) realSolver;

    parseParameters( argc, argv );
    readLP( solver, argv[1] );

    FILE *log = NULL;
    if(!output.empty())
    {
        log = fopen(output.c_str(), "a");
        if(!log)
        {
            printf("Could not open the file!\n");
            exit(EXIT_FAILURE);
        }
    }

    const int numCols = solver->getNumCols(), numRows = solver->getNumRows();
    int pass = 0, newCuts = 0, totalCuts = 0;
    double pTime, opt, cgTime;
    CGraph *cgraph = NULL;

    if(sepMethod == Npsep)
    	cgraph = build_cgraph_osi( solver );

    if(!optFile.empty())
    {
        getOptimals();
        if(optimals.find(problemName) == optimals.end())
        {
            fprintf(stderr, "ERROR: optimal value not found!\n");
            exit(EXIT_FAILURE);
        }
        opt = optimals[problemName];
    }

    solver->initialSolve();

    if (!solver->isProvenOptimal())
    {
        if (solver->isAbandoned())
        {
            fprintf( stderr, "LP solver abandoned due to numerical dificulties.\n" );
            exit( EXIT_FAILURE );
        }
        if (solver->isProvenPrimalInfeasible())
        {
            fprintf( stderr, "LP solver says PRIMAL INFEASIBLE.\n" );
            exit( EXIT_FAILURE );
        }
        if (solver->isProvenDualInfeasible())
        {
            fprintf( stderr, "LP solver says DUAL INFEASIBLE.\n" );
            exit( EXIT_FAILURE );
        }
        if (solver->isPrimalObjectiveLimitReached())
        {
            fprintf( stderr, "LP solver says isPrimalObjectiveLimitReached.\n" );
            exit( EXIT_FAILURE );
        }
        if (solver->isDualObjectiveLimitReached())
        {
            fprintf( stderr, "LP solver says isDualObjectiveLimitReached.\n" );
            exit( EXIT_FAILURE );
        }
        if (solver->isIterationLimitReached())
        {
            fprintf( stderr, "LP solver says isIterationLimitReached.\n" );
            exit( EXIT_FAILURE );
        }

        fprintf( stderr, "ERROR: Could not solve LP relaxation to optimality. Checking status...\n" );
        exit( EXIT_FAILURE );
    }

    double initialBound = solver->getObjValue();
    printf("%.2lf %d %d %.7lf", ((double)(clock()-start)) / ((double)CLOCKS_PER_SEC), pass, 0, solver->getObjValue());
    if(!optFile.empty())
    {
        printf(" %.7lf %.7lf", opt, abs_mip_gap(solver->getObjValue(), opt));
    }
    printf("\n");

    do
    {
        clock_t startSep = clock();
        newCuts = 0;

        switch (sepMethod)
        {
            case Npsep:
            {
                CglEClique cliqueGen;
                OsiCuts cuts;
                CglTreeInfo info;
                info.level = 0;
                info.pass = 1;
                vector<string> varNames = getVarNames(solver->getColNames(), numCols);
                cliqueGen.parseParameters( argc, (const char**)argv );
                cliqueGen.setCGraph( cgraph );
                cliqueGen.setGenOddHoles( true ); //allow (or not) inserting odd hole cuts
                cliqueGen.colNames = &varNames;
                cliqueGen.generateCuts( *solver, cuts, info );
                newCuts = cuts.sizeCuts();
                solver->applyCuts( cuts );
            }
            break;

            case CglSepM:
            {
                CglClique cliqueGen;
                OsiCuts cuts;
                CglTreeInfo info;
                info.level = 0;
                info.pass = 1;
                cliqueGen.setMinViolation( MIN_VIOLATION );
                cliqueGen.setStarCliqueReport(false);
                cliqueGen.setRowCliqueReport(false);
                cliqueGen.generateCuts( *solver, cuts, info );
                newCuts = cuts.sizeCuts();
                solver->applyCuts( cuts );
            }
            break;

            Default:
            {
            	fprintf( stderr, "Separation Method does not recognized!\n" );
                exit( EXIT_FAILURE );
            }
        }

        pTime = ((double)(clock()-start)) / ((double)CLOCKS_PER_SEC);
        if(pTime > MAX_TIME) break;

        totalCuts += newCuts;
        ++pass;

        if (newCuts)
        {
            solver->resolve();
            if (!solver->isProvenOptimal())
            {
                if (solver->isAbandoned())
                {
                    fprintf( stderr, "LP solver abandoned due to numerical dificulties.\n" );
                    exit( EXIT_FAILURE );
                }
                if (solver->isProvenPrimalInfeasible())
                {
                    fprintf( stderr, "LP solver says PRIMAL INFEASIBLE.\n" );
                    exit( EXIT_FAILURE );
                }
                if (solver->isProvenDualInfeasible())
                {
                    fprintf( stderr, "LP solver says DUAL INFEASIBLE.\n" );
                    exit( EXIT_FAILURE );
                }
                if (solver->isPrimalObjectiveLimitReached())
                {
                    fprintf( stderr, "LP solver says isPrimalObjectiveLimitReached.\n" );
                    exit( EXIT_FAILURE );
                }
                if (solver->isDualObjectiveLimitReached())
                {
                    fprintf( stderr, "LP solver says isDualObjectiveLimitReached.\n" );
                    exit( EXIT_FAILURE );
                }
                if (solver->isIterationLimitReached())
                {
                    fprintf( stderr, "LP solver says isIterationLimitReached.\n" );
                    exit( EXIT_FAILURE );
                }

                fprintf( stderr, "ERROR: Could not solve LP relaxation. Exiting.\n" );
                exit( EXIT_FAILURE );
            }

            pTime = ((double)(clock()-start)) / ((double)CLOCKS_PER_SEC);
            if(pTime > MAX_TIME) break;

            double sepTime = ((double)(clock()-startSep)) / ((double)CLOCKS_PER_SEC);
            printf("%.2lf %d %d %.7lf", sepTime, pass, newCuts, solver->getObjValue());
            if(!optFile.empty())
                printf(" %.7lf %.7lf", opt, abs_mip_gap(solver->getObjValue(), opt));
            printf("\n");
        }
    }
    while ( (newCuts>0) && (pass<MAX_PASSES) ) ;

    if(log)
    {
        double totalTime = ((double)(clock()-start)) / ((double)CLOCKS_PER_SEC);
        fprintf(log, "%s %.2lf %d %d %.7lf", problemName, totalTime, pass - 1, totalCuts, solver->getObjValue());
        if(!optFile.empty())
            fprintf(log, " %.7lf", abs_mip_gap(solver->getObjValue(), opt));
        fprintf(log, "\n");
    }

    if(cgraph)
    	cgraph_free( &cgraph );

   	delete realSolver;

    return EXIT_SUCCESS;
}
Exemple #20
0
//-------------------------------------------------------------------
// Generate Stored cuts
//-------------------------------------------------------------------
void
CglStored::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
			const CglTreeInfo /*info*/) const
{
  // Get basic problem information
  const double * solution = si.getColSolution();
  int numberRowCuts = cuts_.sizeRowCuts();
  for (int i=0;i<numberRowCuts;i++) {
    const OsiRowCut * rowCutPointer = cuts_.rowCutPtr(i);
    double violation = rowCutPointer->violated(solution);
    if (violation>=requiredViolation_)
      cs.insert(*rowCutPointer);
  }
  if (probingInfo_) {
    int number01 = probingInfo_->numberIntegers();
    const cliqueEntry * entry = probingInfo_->fixEntries();
    const int * toZero = probingInfo_->toZero();
    const int * toOne = probingInfo_->toOne();
    const int * integerVariable = probingInfo_->integerVariable();
    const double * lower = si.getColLower();
    const double * upper = si.getColUpper();
    OsiRowCut cut;
    int column[2];
    double element[2];
    for (int i=0;i<number01;i++) {
      int iColumn=integerVariable[i];
      if (upper[iColumn]==lower[iColumn])
	continue;
      double value1 = solution[iColumn];
      for (int j=toZero[i];j<toOne[i];j++) {
	int jColumn=sequenceInCliqueEntry(entry[j]);
	if (jColumn<number01) {
	  jColumn=integerVariable[jColumn];
	  assert (jColumn>=0);
	  double value2 = solution[jColumn];
	  if (oneFixesInCliqueEntry(entry[j])) {
	    double violation = 1.0-value1-value2;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %d + %d >=1\n",iColumn,jColumn);
	      cut.setLb(1.0);
	      cut.setUb(COIN_DBL_MAX);
	      column[0]=iColumn;
	      element[0]=1.0;
	      column[1]=jColumn;
	      element[1]= 1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  } else {
	    double violation = value2-value1;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %d >= %d\n",iColumn,jColumn);
	      cut.setLb(0.0);
	      cut.setUb(COIN_DBL_MAX);
	      column[0]=iColumn;
	      element[0]=1.0;
	      column[1]=jColumn;
	      element[1]= -1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  }
	} else {
	  jColumn -= number01; // not 0-1
	  double value2 = solution[jColumn];
	  double lowerValue = lower[jColumn];
	  double upperValue = upper[jColumn];
	  if (oneFixesInCliqueEntry(entry[j])) {
	    double violation = upperValue-value1*(upperValue-lowerValue)-value2;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %g*%d + %d >=%g\n",(upperValue-lowerValue),iColumn,jColumn,upperValue);
	      cut.setLb(upperValue);
	      cut.setUb(COIN_DBL_MAX);
	      column[0]=iColumn;
	      element[0]=upperValue-lowerValue;
	      column[1]=jColumn;
	      element[1]= 1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  } else {
	    double violation = value2-value1*(upperValue-lowerValue)-lowerValue;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %g*%d >= %d -%g\n",(upperValue-lowerValue),iColumn,jColumn,lowerValue);
	      cut.setLb(-lowerValue);
	      cut.setUb(COIN_DBL_MAX);
	      column[0]=iColumn;
	      element[0]=upperValue-lowerValue;
	      column[1]=jColumn;
	      element[1]= -1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  }
	}
      }
      for (int j=toOne[i];j<toZero[i+1];j++) {
	int jColumn=sequenceInCliqueEntry(entry[j]);
	if (jColumn<number01) {
	  jColumn=integerVariable[jColumn];
	  assert (jColumn>=0);
	  double value2 = solution[jColumn];
	  if (oneFixesInCliqueEntry(entry[j])) {
	    double violation = value1-value2;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %d <= %d\n",iColumn,jColumn);
	      cut.setLb(-COIN_DBL_MAX);
	      cut.setUb(0.0);
	      column[0]=iColumn;
	      element[0]=1.0;
	      column[1]=jColumn;
	      element[1]= -1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  } else {
	    double violation = value1+value2-1.0;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %d + %d <=1\n",iColumn,jColumn);
	      cut.setLb(-COIN_DBL_MAX);
	      cut.setUb(1.0);
	      column[0]=iColumn;
	      element[0]=1.0;
	      column[1]=jColumn;
	      element[1]= 1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  }
	} else {
	  jColumn -= number01; // not 0-1
	  double value2 = solution[jColumn];
	  double lowerValue = lower[jColumn];
	  double upperValue = upper[jColumn];
	  if (oneFixesInCliqueEntry(entry[j])) {
	    double violation = lowerValue +(upperValue-lowerValue)*value1-value2;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %g*%d <= %d -%g\n",(upperValue-lowerValue),iColumn,jColumn,lowerValue);
	      cut.setLb(-COIN_DBL_MAX);
	      cut.setUb(-lowerValue);
	      column[0]=iColumn;
	      element[0]=upperValue-lowerValue;
	      column[1]=jColumn;
	      element[1]= -1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  } else {
	    double violation = (upperValue-lowerValue)*value1+value2-upperValue;
	    if (violation>requiredViolation_) {
	      //printf("XXX can do %g*%d + %d <=%g\n",(upperValue-lowerValue),iColumn,jColumn,upperValue);
	      cut.setLb(-COIN_DBL_MAX);
	      cut.setUb(upperValue);
	      column[0]=iColumn;
	      element[0]=upperValue-lowerValue;
	      column[1]=jColumn;
	      element[1]= 1.0;
	      cut.setEffectiveness(violation);
	      cut.setRow(2,column,element,false);
	      cs.insert(cut);
	    }
	  }
	}
      }
    }
  }
}
/** Get an inner-approximation constraint obtained by drawing a chord linking the two given points x and x2. 
 * This only applies to nonlinear constraints featuring univariate functions (f(x) <= y).**/
bool
HeuristicInnerApproximation::getMyInnerApproximation(Bonmin::OsiTMINLPInterface &si, OsiCuts &cs, int ind,
    const double * x, const double * x2) {

  int n, m, nnz_jac_g, nnz_h_lag;
  Ipopt::TNLP::IndexStyleEnum index_style;
  Bonmin::TMINLP2TNLP * problem = si.problem(); 
  problem->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style);
  double infty = si.getInfinity();


  CoinPackedVector cut;
  double lb = -infty;
  double ub = 0;


  double g = 0;
  double g2 = 0;
  double diff = 0;
  double a = 0;
  problem->eval_gi(n, x, 1, ind, g);
  problem->eval_gi(n, x2, 1, ind, g2);
  Bonmin::vector<int> jCol(n);
  int nnz;
  problem->eval_grad_gi(n, x2, 0, ind, nnz, jCol(), NULL);
  Bonmin::vector<double> jValues(nnz);
  problem->eval_grad_gi(n, x2, 0, ind, nnz, NULL, jValues());
  bool add = false;
  //printf("const %i nnz %i\n", ind, nnz);
  for (int i = 0; i < nnz; i++) {
    const int &colIdx = jCol[i];
    if(index_style == Ipopt::TNLP::FORTRAN_STYLE) jCol[i]--;
    diff = x[colIdx] - x2[colIdx];

    if (fabs(diff) >= 1e-8) {
       a = (g - g2) / diff;
       cut.insert(colIdx, a);
       ub = (a * x[colIdx] - g) - fabs(a * x[colIdx] - g)*1e-6;
       //printf("const %i col %i p[col] %g pp[col] %g g %g g2 %g diff %g\n",ind, colIdx, x[colIdx], x2[colIdx], g, g2, diff);
       add = true;
    } else {
       cut.insert(colIdx, jValues[i]);
       //printf("const %i col %i val %g\n",ind, colIdx, jValues[i]);
    }
  }

  if (add) {

    OsiRowCut newCut;
    newCut.setGloballyValidAsInteger(1);
    newCut.setLb(lb);
    
      //********* Perspective Extension ********//
    int binary_id = 0; // index corresponding to the binary variable activating the corresponding constraint
    const int* ids = problem->get_const_xtra_id(); // vector of indices corresponding to the binary variable activating the corresponding constraint
    // Get the index of the corresponding indicator binary variable
    binary_id = (ids == NULL) ? -1 : ids[ind];
    if(binary_id>0) {// If this hyperplane is a linearization of a disjunctive constraint, we link its righthand side to the corresponding indicator binary variable
        cut.insert(binary_id, -ub); // ∂x ≤ ub => ∂x - ub*z ≤ 0
        newCut.setUb(0);
    }
    else
        newCut.setUb(ub);
    //********* Perspective Extension ********//

    newCut.setRow(cut);
    cs.insert(newCut);
    //newCut.print();
    return true;
  }
  return false;
}
Exemple #22
0
//-----------------------------------------------------------------------------
// Generate Lift-and-Project cuts
//------------------------------------------------------------------- 
void CglLiftAndProject::generateCuts(const OsiSolverInterface& si, OsiCuts& cs,
				     const CglTreeInfo /*info*/)
{
  // Assumes the mixed 0-1 problem 
  //
  //   min {cx: <Atilde,x> >= btilde} 
  //
  // is in canonical form with all bounds,
  // including x_t>=0, -x_t>=-1 for x_t binary,
  // explicitly stated in the constraint matrix. 
  // See ~/COIN/Examples/Cgl2/cgl2.cpp 
  // for a general purpose "convert" function. 

  // Reference [BCC]: Balas, Ceria, and Corneujols,
  // "A lift-and-project cutting plane algorithm
  // for mixed 0-1 program", Math Prog 58, (1993) 
  // 295-324.

  // This implementation uses Normalization 1.

  // Given canonical problem and
  // the lp-relaxation solution, x,
  // the LAP cut generator attempts to construct
  // a cut for every x_j such that 0<x_j<1
  // [BCC:307]
 

  // x_j is the strictly fractional binary variable
  // the cut is generated from
  int j = 0; 

  // Get basic problem information
  // let Atilde be an m by n matrix
  const int m = si.getNumRows(); 
  const int n = si.getNumCols(); 
  const double * x = si.getColSolution();

  // Remember - Atildes may have gaps..
  const CoinPackedMatrix * Atilde = si.getMatrixByRow();
  const double * AtildeElements =  Atilde->getElements();
  const int * AtildeIndices =  Atilde->getIndices();
  const CoinBigIndex * AtildeStarts = Atilde->getVectorStarts();
  const int * AtildeLengths = Atilde->getVectorLengths();  
  const int AtildeFullSize = AtildeStarts[m];
  const double * btilde = si.getRowLower();

  // Set up memory for system (10) [BCC:307]
  // (the problem over the norm intersected 
  //  with the polar cone)
  // 
  // min <<x^T,Atilde^T>,u> + x_ju_0
  // s.t.
  //     <B,w> = (0,...,0,beta_,beta)^T
  //        w  is nonneg for all but the
  //           last two entries, which are free.
  // where 
  // w = (u,v,v_0,u_0)in BCC notation 
  //      u and v are m-vectors; u,v >=0
  //      v_0 and u_0 are free-scalars, and
  //  
  // B = Atilde^T  -Atilde^T  -e_j e_j
  //     btilde^T   e_0^T      0   0
  //     e_0^T      btilde^T   1   0

  // ^T indicates Transpose
  // e_0 is a (AtildeNCols x 1) vector of all zeros 
  // e_j is e_0 with a 1 in the jth position

  // Storing B in column order. B is a (n+2 x 2m+2) matrix 
  // But need to allow for possible gaps in Atilde.
  // At each iteration, only need to change 2 cols and objfunc
  // Sane design of OsiSolverInterface does not permit mucking
  // with matrix.
  // Because we must delete and add cols to alter matrix,
  // and we can only add columns on the end of the matrix
  // put the v_0 and u_0 columns on the end.
  // rather than as described in [BCC]
 
  // Initially allocating B with space for v_0 and u_O cols
  // but not populating, for efficiency.

  // B without u_0 and v_0 is a (n+2 x 2m) size matrix.

  int twoM = 2*m;
  int BNumRows = n+2;
  int BNumCols = twoM+2;
  int BFullSize = 2*AtildeFullSize+twoM+3;
  double * BElements = new double[BFullSize];
  int * BIndices = new int[BFullSize];
  CoinBigIndex * BStarts = new CoinBigIndex [BNumCols+1];
  int * BLengths = new int[BNumCols];


  int i, ij, k=0;
  int nPlus1=n+1;
  int offset = AtildeStarts[m]+m;
  for (i=0; i<m; i++){
    for (ij=AtildeStarts[i];ij<AtildeStarts[i]+AtildeLengths[i];ij++){
      BElements[k]=AtildeElements[ij];
      BElements[k+offset]=-AtildeElements[ij];
      BIndices[k]= AtildeIndices[ij];
      BIndices[k+offset]= AtildeIndices[ij];

      k++;
    }
    BElements[k]=btilde[i];
    BElements[k+offset]=btilde[i];
    BIndices[k]=n;
    BIndices[k+offset]=nPlus1;
    BStarts[i]= AtildeStarts[i]+i;
    BStarts[i+m]=offset+BStarts[i];// = AtildeStarts[m]+m+AtildeStarts[i]+i
    BLengths[i]= AtildeLengths[i]+1;
    BLengths[i+m]= AtildeLengths[i]+1;
    k++;
  }

  BStarts[twoM]=BStarts[twoM-1]+BLengths[twoM-1];

  // Cols that will be deleted each iteration
  int BNumColsLessOne=BNumCols-1;
  int BNumColsLessTwo=BNumCols-2;
  const int delCols[2] = {BNumColsLessOne, BNumColsLessTwo};

  // Set lower bound on u and v
  // u_0, v_0 will be reset as free
  const double solverINFINITY = si.getInfinity();
  double * BColLowers = new double[BNumCols];
  double * BColUppers = new double[BNumCols];
  CoinFillN(BColLowers,BNumCols,0.0);  
  CoinFillN(BColUppers,BNumCols,solverINFINITY); 

  // Set row lowers and uppers.
  // The rhs is zero, for but the last two rows.
  // For these the rhs is beta_
  double * BRowLowers = new double[BNumRows];
  double * BRowUppers = new double[BNumRows];
  CoinFillN(BRowLowers,BNumRows,0.0);  
  CoinFillN(BRowUppers,BNumRows,0.0);
  BRowLowers[BNumRows-2]=beta_;
  BRowUppers[BNumRows-2]=beta_;
  BRowLowers[BNumRows-1]=beta_;
  BRowUppers[BNumRows-1]=beta_;


  // Calculate base objective <<x^T,Atilde^T>,u>
  // Note: at each iteration coefficient u_0
  //       changes to <x^T,e_j>
  //       w=(u,v,beta,v_0,u_0) size 2m+3
  //       So, BOjective[2m+2]=x[j]
  double * BObjective= new double[BNumCols];
  double * Atildex = new double[m];
  CoinFillN(BObjective,BNumCols,0.0);
  Atilde->times(x,Atildex); // Atildex is size m, x is size n
  CoinDisjointCopyN(Atildex,m,BObjective); 

  // Number of cols and size of Elements vector
  // in B without the v_0 and u_0 cols
  int BFullSizeLessThree = BFullSize-3;

  // Load B matrix into a column orders CoinPackedMatrix
  CoinPackedMatrix * BMatrix = new CoinPackedMatrix(true, BNumRows,
						  BNumColsLessTwo, 
						  BFullSizeLessThree,
						  BElements,BIndices, 
						  BStarts,BLengths);
  // Assign problem into a solver interface 
  // Note: coneSi will cleanup the memory itself
  OsiSolverInterface * coneSi = si.clone(false);
  coneSi->assignProblem (BMatrix, BColLowers, BColUppers, 
		      BObjective,
		      BRowLowers, BRowUppers);

  // Problem sense should default to "min" by default, 
  // but just to be virtuous...
  coneSi->setObjSense(1.0);

  // The plot outline from here on down:
  // coneSi has been assigned B without the u_0 and v_0 columns
  // Calculate base objective <<x^T,Atilde^T>,u>
  // bool haveWarmStart = false;
  // For (j=0; j<n, j++)
  //   if (!isBinary(x_j) || x_j<=0 || x_j>=1) continue;
  //   // IMPROVEME: if(haveWarmStart) check if j attractive
  //   add {-e_j,0,-1} matrix column for v_0
  //   add {e_j,0,0} matrix column for u_0
  //   objective coefficient for u_0 is  x_j 
  //   if (haveWarmStart) 
  //      set warmstart info
  //   solve min{objw:Bw=0; w>=0,except v_0, u_0 free}
  //   if (bounded)
  //      get warmstart info
  //      haveWarmStart=true;
  //      ustar = optimal u solution
  //      ustar_0 = optimal u_0 solution
  //      alpha^T= <ustar^T,Atilde> -ustar_0e_j^T
  //      (double check <alpha^T,x> >= beta_ should be violated)
  //      add <alpha^T,x> >= beta_ to cutset 
  //   endif
  //   delete column for u_0 // this deletes all column info.
  //   delete column for v_0
  // endFor
  // clean up memory
  // return 0;

  int * nVectorIndices = new int[n];
  CoinIotaN(nVectorIndices, n, 0);

  bool haveWarmStart = false;
  bool equalObj1, equalObj2;
  CoinRelFltEq eq;

  double v_0Elements[2] = {-1,1};
  double u_0Elements[1] = {1};

  CoinWarmStart * warmStart = 0;

  double * ustar = new double[m];
  CoinFillN(ustar, m, 0.0);

  double* alpha = new double[n];
  CoinFillN(alpha, n, 0.0);

  for (j=0;j<n;j++){
    if (!si.isBinary(j)) continue; // Better to ask coneSi? No! 
                                   // coneSi has no binInfo.
    equalObj1=eq(x[j],0);
    equalObj2=eq(x[j],1);
    if (equalObj1 || equalObj2) continue;
    // IMPROVEME: if (haveWarmStart) check if j attractive;

    // AskLL:wanted to declare u_0 and v_0 packedVec outside loop
    // and setIndices, but didn't see a method to do that(?)
    // (Could "insert". Seems inefficient)
    int v_0Indices[2]={j,nPlus1};
    int u_0Indices[1]={j};
    // 
    CoinPackedVector  v_0(2,v_0Indices,v_0Elements,false);
    CoinPackedVector  u_0(1,u_0Indices,u_0Elements,false);

#if CGL_DEBUG
    const CoinPackedMatrix *see1 = coneSi->getMatrixByRow();
#endif

    coneSi->addCol(v_0,-solverINFINITY,solverINFINITY,0);
    coneSi->addCol(u_0,-solverINFINITY,solverINFINITY,x[j]);
    if(haveWarmStart) {
      coneSi->setWarmStart(warmStart);
      coneSi->resolve();
    }
    else {

#if CGL_DEBUG
      const CoinPackedMatrix *see2 = coneSi->getMatrixByRow();
#endif

      coneSi->initialSolve();
    }
    if(coneSi->isProvenOptimal()){
      warmStart = coneSi->getWarmStart();
      haveWarmStart=true;
      const double * wstar = coneSi->getColSolution();
      CoinDisjointCopyN(wstar, m, ustar);
      Atilde->transposeTimes(ustar,alpha);
      alpha[j]+=wstar[BNumCols-1]; 
      
#if debug
      int p;
      double sum;
      for(p=0;p<n;p++)sum+=alpha[p]*x[p];
      if (sum<=beta_){
	throw CoinError("Cut not violated",
			"cutGeneration",
			"CglLiftAndProject");
      }
#endif

      // add <alpha^T,x> >= beta_ to cutset
      OsiRowCut rc;
      rc.setRow(n,nVectorIndices,alpha);
      rc.setLb(beta_);
      rc.setUb(solverINFINITY);
      cs.insert(rc);
    }
    // delete col for u_o and v_0
    coneSi->deleteCols(2,delCols);

    // clean up memory
  }
  // clean up
  delete [] alpha;
  delete [] ustar;
  delete [] nVectorIndices;
  // BMatrix, BColLowers,BColUppers, BObjective, BRowLowers, BRowUppers
  // are all freed by OsiSolverInterface destructor (?)
  delete [] BLengths;
  delete [] BStarts;
  delete [] BIndices;
  delete [] BElements;
}
Exemple #23
0
int main(int argc, char **argv) 
{
  char *f_name_lp, *last_dot_pos, f_name[256], *f_name_pos;
  int i, ncol;

  if((argc < 2) || (argc > 2)) {
    printf("### ERROR: main(): Usage: One of the following\ncgl_data_test input_file_name.mps\ncgl_data_test input_file_name.lp\n");
    exit(1);
  }

  f_name_lp = strdup(argv[1]);
  f_name_pos = strrchr(f_name_lp, '/');
  if(f_name_pos != NULL) {
    strcpy(f_name, &(f_name_pos[1]));
  }
  else {
    strcpy(f_name, f_name_lp);
  }
  last_dot_pos = strrchr(f_name, '.');
  if(last_dot_pos != NULL) {
    last_dot_pos = '\0';
  }

  OsiClpSolverInterface *clp = new OsiClpSolverInterface;
  clp->messageHandler()->setLogLevel(0);
  if(strcmp(&(f_name_lp[strlen(f_name_lp)-3]), ".lp") == 0) {
    clp->readLp(f_name_lp);    
  }
  else {
    if(strcmp(&(f_name_lp[strlen(f_name_lp)-4]), ".mps") == 0) {
      clp->readMps(f_name_lp);    
    }
    else {
      printf("### ERROR: unrecognized file type\n");
      exit(1);
    }
  }
  ncol = clp->getNumCols();
  clp->initialSolve();

  printf("LP value: %12.2f\n", clp->getObjValue());

  OsiCuts cuts;

  // Define parameters for CglRedSplit generator
  CglParam cpar;
  cpar.setMAX_SUPPORT(ncol+1);
  CglRedSplitParam rspar(cpar);

  // Create a cut generator with the given parameters
  CglRedSplit cutGen(rspar);

  char *colType = new char[ncol];
  for(i=0; i<ncol; i++) {
    if(clp->isContinuous(i)) {
      colType[i] = 'C';
    }
    else {
      colType[i] = 'I';
    }
  }

  int round, max_rounds = 10;
  for(round=0; round<max_rounds; round++) {
    cutGen.generateCuts(*clp, cuts);

    int ncuts = cuts.sizeRowCuts();

    const OsiRowCut **newRowCuts = new const OsiRowCut * [ncuts];
    for(i=0; i<ncuts; i++) {
      newRowCuts[i] = &cuts.rowCut(i); 
    }
    clp->applyRowCuts(ncuts, newRowCuts);
    delete[] newRowCuts;

    printf("round %4d: %4d generated cuts  new objective value: %12.2f\n", 
	   round, ncuts, clp->getObjValue());

    clp->resolve();  

    if(clp->isAbandoned()) {
      printf("###ERROR: Numerical difficulties in Solver\n");
      exit(1);
    }
  
    if(clp->isProvenPrimalInfeasible()) {
      printf("### WARNING: Problem is infeasible\n");
      exit(1);
    }
  }

  delete clp;
  free(f_name_lp);
  delete[] colType;

  return(0);
}
void OsiSpxSolverInterfaceUnitTest( const std::string & mpsDir, const std::string & netlibDir )
{
  // Test default constructor
  {
    OsiSpxSolverInterface m;
    OSIUNITTEST_ASSERT_ERROR(m.soplex_      != NULL, {}, "SoPlex", "default constructor");
    OSIUNITTEST_ASSERT_ERROR(m.getNumCols() == 0,    {}, "SoPlex", "default constructor");
    OSIUNITTEST_ASSERT_ERROR(m.rowsense_    == NULL, {}, "SoPlex", "default constructor");
    OSIUNITTEST_ASSERT_ERROR(m.rhs_         == NULL, {}, "SoPlex", "default constructor");
    OSIUNITTEST_ASSERT_ERROR(m.rowrange_    == NULL, {}, "SoPlex", "default constructor");
    OSIUNITTEST_ASSERT_ERROR(m.colsol_      == NULL, {}, "SoPlex", "default constructor");
    OSIUNITTEST_ASSERT_ERROR(m.rowsol_      == NULL, {}, "SoPlex", "default constructor");
    OSIUNITTEST_ASSERT_ERROR(m.matrixByRow_ == NULL, {}, "SoPlex", "default constructor");
    OSIUNITTEST_ASSERT_ERROR(m.matrixByCol_ == NULL, {}, "SoPlex", "default constructor");
    OSIUNITTEST_ASSERT_ERROR(m.getApplicationData() == NULL, {}, "SoPlex", "default constructor");
    int i=2346;
    m.setApplicationData(&i);
    OSIUNITTEST_ASSERT_ERROR(*((int *)(m.getApplicationData())) == i, {}, "SoPlex", "set application data");
  }

  {    
    CoinRelFltEq eq;
    OsiSpxSolverInterface m;
    std::string fn = mpsDir+"exmip1";
    m.readMps(fn.c_str(),"mps");
//    int ad = 13579;
//    m.setApplicationData(&ad);
//    OSIUNITTEST_ASSERT_ERROR(*((int *)(m.getApplicationData())) == ad, {}, "SoPlex", "set application data");

    {
      const CoinPackedMatrix * colCopy = m.getMatrixByCol();
      OSIUNITTEST_ASSERT_ERROR(colCopy->getNumCols()  == 8, {}, "SoPlex", "exmip1 matrix");
      OSIUNITTEST_ASSERT_ERROR(colCopy->getMajorDim() == 8, {}, "SoPlex", "exmip1 matrix");
      OSIUNITTEST_ASSERT_ERROR(colCopy->getNumRows()  == 5, {}, "SoPlex", "exmip1 matrix");
      OSIUNITTEST_ASSERT_ERROR(colCopy->getMinorDim() == 5, {}, "SoPlex", "exmip1 matrix");
      OSIUNITTEST_ASSERT_ERROR(colCopy->getVectorLengths()[7] == 2, {}, "SoPlex", "exmip1 matrix");
      CoinPackedMatrix revColCopy;
      revColCopy.reverseOrderedCopyOf(*colCopy);
      CoinPackedMatrix rev2ColCopy;      
      rev2ColCopy.reverseOrderedCopyOf(revColCopy);
      OSIUNITTEST_ASSERT_ERROR(rev2ColCopy.getNumCols()  == 8, {}, "SoPlex", "twice reverse matrix copy");
      OSIUNITTEST_ASSERT_ERROR(rev2ColCopy.getMajorDim() == 8, {}, "SoPlex", "twice reverse matrix copy");
      OSIUNITTEST_ASSERT_ERROR(rev2ColCopy.getNumRows()  == 5, {}, "SoPlex", "twice reverse matrix copy");
      OSIUNITTEST_ASSERT_ERROR(rev2ColCopy.getMinorDim() == 5, {}, "SoPlex", "twice reverse matrix copy");
      OSIUNITTEST_ASSERT_ERROR(rev2ColCopy.getVectorLengths()[7] == 2, {}, "SoPlex", "twice reverse matrix copy");
    }

    // Test copy constructor and assignment operator
    {
      OsiSpxSolverInterface lhs;
      {      
        OsiSpxSolverInterface im(m);   
        OsiSpxSolverInterface imC1(im);
        OsiSpxSolverInterface imC2(im);
        
        lhs = imC2;
      }
      // Test that lhs has correct values even though rhs has gone out of scope
      OSIUNITTEST_ASSERT_ERROR(lhs.getNumCols() == m.getNumCols(), {}, "SoPlex", "copy constructor");
      OSIUNITTEST_ASSERT_ERROR(lhs.getNumRows() == m.getNumRows(), {}, "SoPlex", "copy constructor");
    }
    
    // Test clone
    {
      OsiSpxSolverInterface soplexSi(m);
      OsiSolverInterface * siPtr = &soplexSi;
      OsiSolverInterface * siClone = siPtr->clone();
      OsiSpxSolverInterface * soplexClone = dynamic_cast<OsiSpxSolverInterface*>(siClone);
      OSIUNITTEST_ASSERT_ERROR(soplexClone != NULL, {}, "SoPlex", "clone");
      OSIUNITTEST_ASSERT_ERROR(soplexClone->getNumRows() == soplexSi.getNumRows(), {}, "SoPlex", "clone");
      OSIUNITTEST_ASSERT_ERROR(soplexClone->getNumCols() == m.getNumCols(), {}, "SoPlex", "clone");
      
      delete siClone;
    }
   
    // test infinity
    {
      OsiSpxSolverInterface si;
      OSIUNITTEST_ASSERT_ERROR(si.getInfinity() == soplex::infinity, {}, "SoPlex", "value for infinity");
    }     

    {    
      OsiSpxSolverInterface soplexSi(m);
      int nc = soplexSi.getNumCols();
      int nr = soplexSi.getNumRows();
      const double * cl = soplexSi.getColLower();
      const double * cu = soplexSi.getColUpper();
      const double * rl = soplexSi.getRowLower();
      const double * ru = soplexSi.getRowUpper();

      OSIUNITTEST_ASSERT_ERROR(nc == 8, return, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(nr == 5, return, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cl[0],2.5), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cl[1],0.0), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cu[1],4.1), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(cu[2],1.0), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(rl[0],2.5), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(rl[4],3.0), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(ru[1],2.1), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(ru[4],15.), {}, "SoPlex", "read and copy exmip1");
      
      double newCs[8] = {1., 2., 3., 4., 5., 6., 7., 8.};
      soplexSi.setColSolution(newCs);
      const double * cs = soplexSi.getColSolution();
      OSIUNITTEST_ASSERT_ERROR(eq(cs[0],1.0), {}, "SoPlex", "set col solution");
      OSIUNITTEST_ASSERT_ERROR(eq(cs[7],8.0), {}, "SoPlex", "set col solution");
      {
        OsiSpxSolverInterface solnSi(soplexSi);
        const double * cs = solnSi.getColSolution();
        OSIUNITTEST_ASSERT_ERROR(eq(cs[0],1.0), {}, "SoPlex", "set col solution and copy");
        OSIUNITTEST_ASSERT_ERROR(eq(cs[7],8.0), {}, "SoPlex", "set col solution and copy");
      }

      OSIUNITTEST_ASSERT_ERROR(!eq(cl[3],1.2345), {}, "SoPlex", "set col lower");
      soplexSi.setColLower( 3, 1.2345 );
      OSIUNITTEST_ASSERT_ERROR( eq(cl[3],1.2345), {}, "SoPlex", "set col lower");
      
      OSIUNITTEST_ASSERT_ERROR(!eq(cu[4],10.2345), {}, "SoPlex", "set col upper");
      soplexSi.setColUpper( 4, 10.2345 );
      OSIUNITTEST_ASSERT_ERROR( eq(cu[4],10.2345), {}, "SoPlex", "set col upper");

      OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[0], 1.0), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[1], 0.0), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[2], 0.0), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[3], 0.0), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[4], 2.0), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[5], 0.0), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[6], 0.0), {}, "SoPlex", "read and copy exmip1");
      OSIUNITTEST_ASSERT_ERROR(eq(soplexSi.getObjCoefficients()[7],-1.0), {}, "SoPlex", "read and copy exmip1");
    }
    
    // Test getMatrixByRow method
    { 
      const OsiSpxSolverInterface si(m);
      const CoinPackedMatrix * smP = si.getMatrixByRow();
      
      OSIUNITTEST_ASSERT_ERROR(smP->getMajorDim()    ==  5, return, "SoPlex", "getMatrixByRow: major dim");
      OSIUNITTEST_ASSERT_ERROR(smP->getNumElements() == 14, return, "SoPlex", "getMatrixByRow: num elements");

      CoinRelFltEq eq;
      const double * ev = smP->getElements();
      OSIUNITTEST_ASSERT_ERROR(eq(ev[0],   3.0), {}, "SoPlex", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[1],   1.0), {}, "SoPlex", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[2],  -2.0), {}, "SoPlex", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[3],  -1.0), {}, "SoPlex", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[4],  -1.0), {}, "SoPlex", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[5],   2.0), {}, "SoPlex", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[6],   1.1), {}, "SoPlex", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[7],   1.0), {}, "SoPlex", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[8],   1.0), {}, "SoPlex", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[9],   2.8), {}, "SoPlex", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[10], -1.2), {}, "SoPlex", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[11],  5.6), {}, "SoPlex", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[12],  1.0), {}, "SoPlex", "getMatrixByRow: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[13],  1.9), {}, "SoPlex", "getMatrixByRow: elements");
      
      const int * mi = smP->getVectorStarts();
      OSIUNITTEST_ASSERT_ERROR(mi[0] ==  0, {}, "SoPlex", "getMatrixByRow: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[1] ==  5, {}, "SoPlex", "getMatrixByRow: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[2] ==  7, {}, "SoPlex", "getMatrixByRow: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[3] ==  9, {}, "SoPlex", "getMatrixByRow: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "SoPlex", "getMatrixByRow: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "SoPlex", "getMatrixByRow: vector starts");
      
      const int * ei = smP->getIndices();
      OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "SoPlex", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "SoPlex", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "SoPlex", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "SoPlex", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "SoPlex", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "SoPlex", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "SoPlex", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "SoPlex", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "SoPlex", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "SoPlex", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "SoPlex", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "SoPlex", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "SoPlex", "getMatrixByRow: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "SoPlex", "getMatrixByRow: indices");
    }
    //--------------
    // Test rowsense, rhs, rowrange, getMatrixByRow
    {
      OsiSpxSolverInterface lhs;
      {     
        OsiSpxSolverInterface siC1(m);
        OSIUNITTEST_ASSERT_WARNING(siC1.rowrange_ == NULL, {}, "SoPlex", "row range");
        OSIUNITTEST_ASSERT_WARNING(siC1.rowsense_ == NULL, {}, "SoPlex", "row sense");
        OSIUNITTEST_ASSERT_WARNING(siC1.rhs_ == NULL, {}, "SoPlex", "right hand side");
        OSIUNITTEST_ASSERT_WARNING(siC1.matrixByRow_ == NULL, {}, "SoPlex", "matrix by row");
        OSIUNITTEST_ASSERT_WARNING(siC1.colsol_ == NULL, {}, "SoPlex", "col solution");
        OSIUNITTEST_ASSERT_WARNING(siC1.rowsol_ == NULL, {}, "SoPlex", "row solution");

        const char   * siC1rs  = siC1.getRowSense();
        OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "SoPlex", "row sense");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "SoPlex", "row sense");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "SoPlex", "row sense");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "SoPlex", "row sense");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "SoPlex", "row sense");
        
        const double * siC1rhs = siC1.getRightHandSide();
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "SoPlex", "right hand side");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "SoPlex", "right hand side");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "SoPlex", "right hand side");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "SoPlex", "right hand side");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "SoPlex", "right hand side");
        
        const double * siC1rr  = siC1.getRowRange();
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "SoPlex", "row range");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "SoPlex", "row range");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "SoPlex", "row range");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "SoPlex", "row range");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "SoPlex", "row range");
        
        const CoinPackedMatrix * siC1mbr = siC1.getMatrixByRow();
        OSIUNITTEST_ASSERT_ERROR(siC1mbr != NULL, {}, "SoPlex", "matrix by row");
        OSIUNITTEST_ASSERT_ERROR(siC1mbr->getMajorDim()    ==  5, return, "SoPlex", "matrix by row: major dim");
        OSIUNITTEST_ASSERT_ERROR(siC1mbr->getNumElements() == 14, return, "SoPlex", "matrix by row: num elements");
        
        const double * ev = siC1mbr->getElements();
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "SoPlex", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 1.0), {}, "SoPlex", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "SoPlex", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3],-1.0), {}, "SoPlex", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4],-1.0), {}, "SoPlex", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 2.0), {}, "SoPlex", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 1.1), {}, "SoPlex", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "SoPlex", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "SoPlex", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 2.8), {}, "SoPlex", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[10],-1.2), {}, "SoPlex", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "SoPlex", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "SoPlex", "matrix by row: elements");
        OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "SoPlex", "matrix by row: elements");

        const CoinBigIndex * mi = siC1mbr->getVectorStarts();
        OSIUNITTEST_ASSERT_ERROR(mi[0] ==  0, {}, "SoPlex", "matrix by row: vector starts");
        OSIUNITTEST_ASSERT_ERROR(mi[1] ==  5, {}, "SoPlex", "matrix by row: vector starts");
        OSIUNITTEST_ASSERT_ERROR(mi[2] ==  7, {}, "SoPlex", "matrix by row: vector starts");
        OSIUNITTEST_ASSERT_ERROR(mi[3] ==  9, {}, "SoPlex", "matrix by row: vector starts");
        OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "SoPlex", "matrix by row: vector starts");
        OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "SoPlex", "matrix by row: vector starts");
        
        const int * ei = siC1mbr->getIndices();
        OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "SoPlex", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "SoPlex", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "SoPlex", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "SoPlex", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "SoPlex", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "SoPlex", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "SoPlex", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "SoPlex", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "SoPlex", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "SoPlex", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "SoPlex", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "SoPlex", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "SoPlex", "matrix by row: indices");
        OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "SoPlex", "matrix by row: indices");

        OSIUNITTEST_ASSERT_WARNING(siC1rs  == siC1.getRowSense(), {}, "SoPlex", "row sense");
        OSIUNITTEST_ASSERT_WARNING(siC1rhs == siC1.getRightHandSide(), {}, "SoPlex", "right hand side");
        OSIUNITTEST_ASSERT_WARNING(siC1rr  == siC1.getRowRange(), {}, "SoPlex", "row range");

        // Change SOPLEX Model by adding free row
        OsiRowCut rc;
        rc.setLb(-COIN_DBL_MAX);
        rc.setUb( COIN_DBL_MAX);
        OsiCuts cuts;
        cuts.insert(rc);
        siC1.applyCuts(cuts);
             
        // Since model was changed, test that cached data is now freed.
        OSIUNITTEST_ASSERT_ERROR(siC1.rowrange_ == NULL, {}, "SoPlex", "free cached data after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1.rowsense_ == NULL, {}, "SoPlex", "free cached data after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1.rhs_ == NULL, {}, "SoPlex", "free cached data after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1.matrixByRow_ == NULL, {}, "SoPlex", "free cached data after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1.matrixByCol_ == NULL, {}, "SoPlex", "free cached data after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1.colsol_ == NULL, {}, "SoPlex", "free cached data after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1.rowsol_ == NULL, {}, "SoPlex", "free cached data after adding row");

        siC1rs  = siC1.getRowSense();
        OSIUNITTEST_ASSERT_ERROR(siC1rs[0] == 'G', {}, "SoPlex", "row sense after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[1] == 'L', {}, "SoPlex", "row sense after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[2] == 'E', {}, "SoPlex", "row sense after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[3] == 'R', {}, "SoPlex", "row sense after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[4] == 'R', {}, "SoPlex", "row sense after adding row");
        OSIUNITTEST_ASSERT_ERROR(siC1rs[5] == 'N', {}, "SoPlex", "row sense after adding row");

        siC1rhs = siC1.getRightHandSide();
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[0],2.5), {}, "SoPlex", "right hand side after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[1],2.1), {}, "SoPlex", "right hand side after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[2],4.0), {}, "SoPlex", "right hand side after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[3],5.0), {}, "SoPlex", "right hand side after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[4],15.), {}, "SoPlex", "right hand side after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rhs[5],0.0), {}, "SoPlex", "right hand side after adding row");

        siC1rr  = siC1.getRowRange();
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[0],0.0), {}, "SoPlex", "row range after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[1],0.0), {}, "SoPlex", "row range after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[2],0.0), {}, "SoPlex", "row range after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[3],5.0-1.8), {}, "SoPlex", "row range after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[4],15.0-3.0), {}, "SoPlex", "row range after adding row");
        OSIUNITTEST_ASSERT_ERROR(eq(siC1rr[5],0.0), {}, "SoPlex", "row range after adding row");
    
        lhs = siC1;
      }
      // Test that lhs has correct values even though siC1 has gone out of scope    
      OSIUNITTEST_ASSERT_ERROR(lhs.rowrange_ == NULL, {}, "SoPlex", "freed origin after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhs.rowsense_ == NULL, {}, "SoPlex", "freed origin after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhs.rhs_ == NULL, {}, "SoPlex", "freed origin after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhs.matrixByRow_ == NULL, {}, "SoPlex", "freed origin after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhs.matrixByCol_ == NULL, {}, "SoPlex", "freed origin after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhs.colsol_ == NULL, {}, "SoPlex", "freed origin after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhs.rowsol_ == NULL, {}, "SoPlex", "freed origin after assignment");

      const char * lhsrs  = lhs.getRowSense();
      OSIUNITTEST_ASSERT_ERROR(lhsrs[0] == 'G', {}, "SoPlex", "row sense after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhsrs[1] == 'L', {}, "SoPlex", "row sense after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhsrs[2] == 'E', {}, "SoPlex", "row sense after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhsrs[3] == 'R', {}, "SoPlex", "row sense after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhsrs[4] == 'R', {}, "SoPlex", "row sense after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhsrs[5] == 'N', {}, "SoPlex", "row sense after assignment");
      
      const double * lhsrhs = lhs.getRightHandSide();
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[0],2.5), {}, "SoPlex", "right hand side after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[1],2.1), {}, "SoPlex", "right hand side after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[2],4.0), {}, "SoPlex", "right hand side after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[3],5.0), {}, "SoPlex", "right hand side after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[4],15.), {}, "SoPlex", "right hand side after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrhs[5],0.0), {}, "SoPlex", "right hand side after assignment");
      
      const double *lhsrr = lhs.getRowRange();
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[0],0.0), {}, "SoPlex", "row range after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[1],0.0), {}, "SoPlex", "row range after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[2],0.0), {}, "SoPlex", "row range after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[3],5.0-1.8), {}, "SoPlex", "row range after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[4],15.0-3.0), {}, "SoPlex", "row range after assignment");
      OSIUNITTEST_ASSERT_ERROR(eq(lhsrr[5],0.0), {}, "SoPlex", "row range after assignment");
      
      const CoinPackedMatrix * lhsmbr = lhs.getMatrixByRow();
      OSIUNITTEST_ASSERT_ERROR(lhsmbr != NULL, {}, "SoPlex", "matrix by row after assignment");
      OSIUNITTEST_ASSERT_ERROR(lhsmbr->getMajorDim()    ==  6, return, "SoPlex", "matrix by row after assignment: major dim");
      OSIUNITTEST_ASSERT_ERROR(lhsmbr->getNumElements() == 14, return, "SoPlex", "matrix by row after assignment: num elements");

      const double * ev = lhsmbr->getElements();
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 0], 3.0), {}, "SoPlex", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 1], 1.0), {}, "SoPlex", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 2],-2.0), {}, "SoPlex", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 3],-1.0), {}, "SoPlex", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 4],-1.0), {}, "SoPlex", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 5], 2.0), {}, "SoPlex", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 6], 1.1), {}, "SoPlex", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 7], 1.0), {}, "SoPlex", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 8], 1.0), {}, "SoPlex", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[ 9], 2.8), {}, "SoPlex", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[10],-1.2), {}, "SoPlex", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[11], 5.6), {}, "SoPlex", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[12], 1.0), {}, "SoPlex", "matrix by row after assignment: elements");
      OSIUNITTEST_ASSERT_ERROR(eq(ev[13], 1.9), {}, "SoPlex", "matrix by row after assignment: elements");
      
      const CoinBigIndex * mi = lhsmbr->getVectorStarts();
      OSIUNITTEST_ASSERT_ERROR(mi[0] ==  0, {}, "SoPlex", "matrix by row after assignment: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[1] ==  5, {}, "SoPlex", "matrix by row after assignment: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[2] ==  7, {}, "SoPlex", "matrix by row after assignment: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[3] ==  9, {}, "SoPlex", "matrix by row after assignment: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[4] == 11, {}, "SoPlex", "matrix by row after assignment: vector starts");
      OSIUNITTEST_ASSERT_ERROR(mi[5] == 14, {}, "SoPlex", "matrix by row after assignment: vector starts");
      
      const int * ei = lhsmbr->getIndices();
      OSIUNITTEST_ASSERT_ERROR(ei[ 0] == 0, {}, "SoPlex", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 1] == 1, {}, "SoPlex", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 2] == 3, {}, "SoPlex", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 3] == 4, {}, "SoPlex", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 4] == 7, {}, "SoPlex", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 5] == 1, {}, "SoPlex", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 6] == 2, {}, "SoPlex", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 7] == 2, {}, "SoPlex", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 8] == 5, {}, "SoPlex", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[ 9] == 3, {}, "SoPlex", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[10] == 6, {}, "SoPlex", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[11] == 0, {}, "SoPlex", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[12] == 4, {}, "SoPlex", "matrix by row after assignment: indices");
      OSIUNITTEST_ASSERT_ERROR(ei[13] == 7, {}, "SoPlex", "matrix by row after assignment: indices");
    }
    
    //--------------    
  }

    
  // Do common solverInterface testing by calling the
  // base class testing method.
  {
    OsiSpxSolverInterface m;
    OsiSolverInterfaceCommonUnitTest(&m, mpsDir,netlibDir);
  }
}
//--------------------------------------------------------------------------
// test cut debugger methods.
void
OsiRowCutDebuggerUnitTest(const OsiSolverInterface * baseSiP, const std::string & mpsDir)
{
  
  CoinRelFltEq eq;
  
  // Test default constructor
  {
    OsiRowCutDebugger r;
    OSIUNITTEST_ASSERT_ERROR(r.integerVariable_ == NULL, {}, "osirowcutdebugger", "default constructor");
    OSIUNITTEST_ASSERT_ERROR(r.knownSolution_   == NULL, {}, "osirowcutdebugger", "default constructor");
    OSIUNITTEST_ASSERT_ERROR(r.numberColumns_   == 0,    {}, "osirowcutdebugger", "default constructor");
  }
  
  {
    // Get non trivial instance
    OsiSolverInterface * imP = baseSiP->clone();
    std::string fn = mpsDir+"exmip1";
    imP->readMps(fn.c_str(),"mps");
    OSIUNITTEST_ASSERT_ERROR(imP->getNumRows() == 5, {}, "osirowcutdebugger", "read exmip1");
    
    /*
      Activate the debugger. The garbled name here is deliberate; the
      debugger should isolate the portion of the string between '/' and
      '.' (in normal use, this would be the base file name, stripped of
      the prefix and extension).
    */
    imP->activateRowCutDebugger("ab cd /x/ /exmip1.asc");
    
    int i;
    
    // return debugger
    const OsiRowCutDebugger * debugger = imP->getRowCutDebugger();
    OSIUNITTEST_ASSERT_ERROR(debugger != NULL, {}, "osirowcutdebugger", "return debugger");
    OSIUNITTEST_ASSERT_ERROR(debugger->numberColumns_ == 8, {}, "osirowcutdebugger", "return debugger");
    
    const bool type[]={0,0,1,1,0,0,0,0};
    const double values[]= {2.5, 0, 1, 1, 0.5, 3, 0, 0.26315789473684253};
    CoinPackedVector objCoefs(8,imP->getObjCoefficients());
   
    bool type_ok = true;
#if 0
    for (i=0;i<8;i++)
      type_ok &= type[i] == debugger->integerVariable_[i];
    OSIUNITTEST_ASSERT_ERROR(type_ok, {}, "osirowcutdebugger", "???");
#endif
    
    double objValue = objCoefs.dotProduct(values);
    double debuggerObjValue = objCoefs.dotProduct(debugger->knownSolution_);
    OSIUNITTEST_ASSERT_ERROR(eq(objValue, debuggerObjValue), {}, "osirowcutdebugger", "objective value");
    
    OsiRowCutDebugger rhs;
    {
      OsiRowCutDebugger rC1(*debugger);

      OSIUNITTEST_ASSERT_ERROR(rC1.numberColumns_ == 8, {}, "osirowcutdebugger", "copy constructor");
      type_ok = true;
      for (i=0;i<8;i++)
      	type_ok &= type[i] == rC1.integerVariable_[i];
      OSIUNITTEST_ASSERT_ERROR(type_ok, {}, "osirowcutdebugger", "copy constructor");
      OSIUNITTEST_ASSERT_ERROR(eq(objValue,objCoefs.dotProduct(rC1.knownSolution_)), {}, "osirowcutdebugger", "copy constructor");
      
      rhs = rC1;
      OSIUNITTEST_ASSERT_ERROR(rhs.numberColumns_ == 8, {}, "osirowcutdebugger", "assignment operator");
      type_ok = true;
      for (i=0;i<8;i++)
      	type_ok &= type[i] == rhs.integerVariable_[i];
      OSIUNITTEST_ASSERT_ERROR(type_ok, {}, "osirowcutdebugger", "assignment operator");
      OSIUNITTEST_ASSERT_ERROR(eq(objValue,objCoefs.dotProduct(rhs.knownSolution_)), {}, "osirowcutdebugger", "assignment operator");
    }
    // Test that rhs has correct values even though lhs has gone out of scope
    OSIUNITTEST_ASSERT_ERROR(rhs.numberColumns_ == 8, {}, "osirowcutdebugger", "assignment operator");
    type_ok = true;
    for (i=0;i<8;i++)
    	type_ok &= type[i] == rhs.integerVariable_[i];
    OSIUNITTEST_ASSERT_ERROR(type_ok, {}, "osirowcutdebugger", "assignment operator");
    OSIUNITTEST_ASSERT_ERROR(eq(objValue,objCoefs.dotProduct(rhs.knownSolution_)), {}, "osirowcutdebugger", "assignment operator");

    OsiRowCut cut[2];
    
    const int ne = 3;
    int inx[ne] = { 0, 2, 3 };
    double el[ne] = { 1., 1., 1. };
    cut[0].setRow(ne,inx,el);
    cut[0].setUb(5.);
    
    el[1]=5;
    cut[1].setRow(ne,inx,el);
    cut[1].setUb(5);
    OsiCuts cs; 
    cs.insert(cut[0]);
    cs.insert(cut[1]);
    OSIUNITTEST_ASSERT_ERROR(!debugger->invalidCut(cut[0]), {}, "osirowcutdebugger", "recognize (in)valid cut");
    OSIUNITTEST_ASSERT_ERROR( debugger->invalidCut(cut[1]), {}, "osirowcutdebugger", "recognize (in)valid cut");
    OSIUNITTEST_ASSERT_ERROR(debugger->validateCuts(cs,0,2) == 1, {}, "osirowcutdebugger", "recognize (in)valid cut");
    OSIUNITTEST_ASSERT_ERROR(debugger->validateCuts(cs,0,1) == 0, {}, "osirowcutdebugger", "recognize (in)valid cut");
    delete imP;
  }
}
//--------------------------------------------------------------------------
// test the simple rounding cut generators methods.
void
CglSimpleRoundingUnitTest(
  const OsiSolverInterface * baseSiP,
  const std::string mpsDir )
{

  // Test default constructor
  {
    CglSimpleRounding cg;
  }

  // Test copy & assignment
  {
    CglSimpleRounding rhs;
    {
      CglSimpleRounding cg;
      CglSimpleRounding cgC(cg);
      rhs=cg;
    }
  }

  // Test gcd and gcdn
  {
    CglSimpleRounding cg;
    int v = cg.gcd(122,356);
    assert(v==2);
    v=cg.gcd(356,122);
    assert(v==2);
    v=cg.gcd(54,67);
    assert(v==1);
    v=cg.gcd(67,54);
    assert(v==1);
    v=cg.gcd(485,485);
    assert(v==485);
    v=cg.gcd(17*13,17*23);
    assert( v==17);
    v=cg.gcd(17*13*5,17*23);
    assert( v==17);
    v=cg.gcd(17*13*23,17*23);
    assert(v==17*23);

    int a[4] = {12, 20, 32, 400};
    v= cg.gcdv(4,a);
    assert(v== 4);
    int b[4] = {782, 4692, 51, 2754};
    v= cg.gcdv(4,b);
    assert(v== 17);
    int c[4] = {50, 40, 30, 10};
    v= cg.gcdv(4,c);
    assert(v== 10);
  }


  // Test generate cuts method on exmip1.5.mps
  {
    CglSimpleRounding cg;
    
    OsiSolverInterface * siP = baseSiP->clone();
    std::string fn = mpsDir+"exmip1.5.mps";
    siP->readMps(fn.c_str(),"");
    OsiCuts cuts;
    cg.generateCuts(*siP,cuts);

    // there should be 3 cuts
    int nRowCuts = cuts.sizeRowCuts();
    assert(nRowCuts==3);

    // get the last "sr"=simple rounding cut that was derived
    OsiRowCut srRowCut2 = cuts.rowCut(2); 
    CoinPackedVector srRowCutPV2 = srRowCut2.row();

    // this is what the last cut should look like: i.e. the "solution"
    const int solSize = 2;
    int solCols[solSize]={2,3};
    double solCoefs[solSize]={5.0, 4.0};
    OsiRowCut solRowCut;
    solRowCut.setRow(solSize,solCols,solCoefs);
    solRowCut.setLb(-COIN_DBL_MAX);
    solRowCut.setUb(2.0);

    // Test for equality between the derived cut and the solution cut

    // Note: testing two OsiRowCuts are equal invokes testing two
    // CoinPackedVectors are equal which invokes testing two doubles
    // are equal.  Usually not a good idea to test that two doubles are equal, 
    // but in this cut the "doubles" represent integer values. Also allow that
    // different solvers have different orderings in packed vectors, which may
    // not match the ordering defined for solRowCut.

    assert(srRowCut2.OsiCut::operator==(solRowCut)) ;
    assert(srRowCut2.row().isEquivalent(solRowCut.row())) ;
    assert(srRowCut2.lb() == solRowCut.lb()) ;
    assert(srRowCut2.ub() == solRowCut.ub()) ;

    delete siP;
  }

  // Test generate cuts method on p0033
  {
    CglSimpleRounding cg;
    
    OsiSolverInterface * siP = baseSiP->clone();
    std::string fn = mpsDir+"p0033";
    siP->readMps(fn.c_str(),"mps");
    OsiCuts cuts;
    cg.generateCuts(*siP,cuts);

    // p0033 is the optimal solution to p0033
    int objIndices[14] = { 
       0,  6,  7,  9, 13, 17, 18,
      22, 24, 25, 26, 27, 28, 29 };
    CoinPackedVector p0033(14,objIndices,1.0);

    // test that none of the generated cuts
    // chops off the optimal solution
    int nRowCuts = cuts.sizeRowCuts();
    OsiRowCut rcut;
    CoinPackedVector rpv;
    int i;
    for (i=0; i<nRowCuts; i++){
      rcut = cuts.rowCut(i);
      rpv = rcut.row();
      double p0033Sum = (rpv*p0033).sum();
      double rcutub = rcut.ub();
      assert (p0033Sum <= rcutub);
    }

    // test that the cuts improve the 
    // lp objective function value
    siP->initialSolve();
    double lpRelaxBefore=siP->getObjValue();
    OsiSolverInterface::ApplyCutsReturnCode rc = siP->applyCuts(cuts);
    siP->resolve();
    double lpRelaxAfter=siP->getObjValue(); 
#ifdef CGL_DEBUG
    printf("\n\nOrig LP min=%f\n",lpRelaxBefore);
    printf("Final LP min=%f\n\n",lpRelaxAfter);
#endif
    assert( lpRelaxBefore < lpRelaxAfter );

    delete siP;

  }


}
Exemple #27
0
/** Standard cut generation methods. */
void
OaDecompositionBase::generateCuts(const OsiSolverInterface &si,  OsiCuts & cs,
    const CglTreeInfo info) {
  if (nlp_ == NULL) {
    throw CoinError("Error in cut generator for outer approximation no NLP ipopt assigned", "generateCuts", "OaDecompositionBase");
  }

  // babInfo is used to communicate with the b-and-b solver (Cbc or Bcp).
  BabInfo * babInfo = dynamic_cast<BabInfo *> (si.getAuxiliaryInfo());
  assert(babInfo);
  assert(babInfo->babPtr());
  numSols_ = babInfo->babPtr()->model().getSolutionCount ();
  CglTreeInfo info_copy = info;
  const CbcNode * node = babInfo->babPtr()->model().currentNode();
  info_copy.level = (node == NULL) ? 0 : babInfo->babPtr()->model().currentNode()->depth();
  if(babInfo->hasSolution()) numSols_ ++;
  if (babInfo)
    if (!babInfo->mipFeasible())
      return;

  //Get the continuous solution
  const double *colsol = si.getColSolution();


  vector<double> savedColLower(nlp_->getNumCols());
  CoinCopyN(nlp_->getColLower(), nlp_->getNumCols(), savedColLower());
  vector<double> savedColUpper(nlp_->getNumCols());
  CoinCopyN(nlp_->getColUpper(), nlp_->getNumCols(), savedColUpper());


  OsiBranchingInformation brInfo(nlp_, false);
  brInfo.solution_ = colsol;
  //Check integer infeasibility
  bool isInteger = integerFeasible(*nlp_, brInfo, parameters_.cbcIntegerTolerance_,
                              objects_, nObjects_);


  //Check nodeNumber if it did not change scan savedCuts_ if one is violated force it and exit
  int nodeNumber = babInfo->babPtr()->model().getNodeCount();
  if(nodeNumber == currentNodeNumber_){
#ifdef OA_DEBUG
    printf("OA decomposition recalled from the same node!\n");
#endif
    int numCuts = savedCuts_.sizeRowCuts();
    for(int i = 0 ; i < numCuts ; i++){
       //Check if cuts off solution
       if(savedCuts_.rowCut(i).violated(colsol) > 0.){
#ifdef OA_DEBUG
         printf("A violated saved cut has been found\n");
#endif
         savedCuts_.rowCut(i).setEffectiveness(9.99e99);
         cs.insert(savedCuts_.rowCut(i));
         savedCuts_.eraseRowCut(i);
         return;
         i--; numCuts--;
       }
    }
  }
  else {
    currentNodeNumber_ = nodeNumber;
    savedCuts_.dumpCuts();
  } 
         
  if (!isInteger) {
    if (!doLocalSearch(babInfo))//create sub mip solver.
      return;
  }

  //get the current cutoff
  double cutoff;
  si.getDblParam(OsiDualObjectiveLimit, cutoff);

  // Save solvers state if needed

  solverManip * lpManip = NULL;
  if (lp_ != NULL) {
      assert(lp_ == &si);
      lpManip = new solverManip(lp_, true, leaveSiUnchanged_, true, true);
  }
  else {
    lpManip = new solverManip(si);
  }
  lpManip->setObjects(objects_, nObjects_);

  double milpBound = performOa(cs, *lpManip, babInfo, cutoff, info_copy);

  if(babInfo->hasSolution()){
     babInfo->babPtr()->model().setSolutionCount (numSols_ - 1);
  }

  //Transmit the bound found by the milp
  {
    if (milpBound>-1e100)
    {
      // Also store into solver
      if (babInfo)
        babInfo->setMipBound(milpBound);
    }
  }  //Clean everything :

  //  Reset the two solvers
  if (leaveSiUnchanged_)
    lpManip->restore();
  delete lpManip;

  nlp_->setColLower(savedColLower());
  nlp_->setColUpper(savedColUpper());

  return;
}
Exemple #28
0
//-------------------------------------------------------------
void
CglZeroHalf::generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
				const CglTreeInfo info)
{
  if (mnz_) {
    int cnum=0,cnzcnt=0;
    int *cbeg=NULL, *ccnt=NULL,*cind=NULL,*cval=NULL,*crhs=NULL;
    char *csense=NULL;
    const double * solution = si.getColSolution();
    if ((flags_&1)==0) {
      // redo bounds
      const double * columnLower = si.getColLower();
      const double * columnUpper = si.getColUpper();
      int numberColumns = si.getNumCols();
      for (int iColumn=0;iColumn<numberColumns;iColumn++) {
	if (vlb_[iColumn]!=COIN_INT_MAX) {
	  int ilo,iup;
	  double lo = columnLower[iColumn];
	  if (lo<-COIN_INT_MAX)
	    lo=-COIN_INT_MAX;
	  ilo= static_cast<int> (ceil(lo));
	  double up = columnUpper[iColumn];
	  if (up>COIN_INT_MAX)
	    up=COIN_INT_MAX;
	  iup= static_cast<int> (floor(up));
	  vlb_[iColumn]=ilo;
	  vub_[iColumn]=iup;
	}
      }
    }
    if (true) {
    cutInfo_.sep_012_cut(mr_,mc_,mnz_,
				 mtbeg_,mtcnt_, mtind_, mtval_,
				 vlb_, vub_,
				 mrhs_, msense_,
				 solution,
				 info.inTree ? false : true,
				 &cnum,&cnzcnt,
				 &cbeg,&ccnt,&cind,&cval,&crhs,&csense);
    } else {
      int k = 4*mr_+2*mnz_;
      int * temp = new int[k];
      int * mtbeg = temp;
      int * mtcnt = mtbeg + mr_;
      int * mtind = mtcnt+mr_;
      int * mtval = mtind+mnz_;
      int * mrhs = mtval+mnz_;
      char * msense = reinterpret_cast<char*> (mrhs+mr_);
      int i;
      k=0;
      int kel=0;
      for (i=0;i<mr_;i++) {
	int kel2=kel;
	int rhs = mrhs_[i];
	for (int j=mtbeg_[i];j<mtbeg_[i]+mtcnt_[i];j++) {
	  int iColumn=mtind_[j];
	  int value=mtval_[j];
	  if (vlb_[iColumn]<vub_[iColumn]) {
	    mtind[kel]=mtind_[j];
	    mtval[kel++]=mtval_[j];
	  } else {
	    rhs -= vlb_[iColumn]*value;
	  }
	}
	if (kel>kel2) {
	  mtcnt[k]=kel-kel2;
	  mtbeg[k]=kel2;
	  mrhs[k]=rhs;
	  msense[k++]=msense_[i];
	}
      }
      if (kel) {
	cutInfo_.sep_012_cut(k,mc_,kel,
				 mtbeg,mtcnt, mtind, mtval,
				 vlb_, vub_,
				 mrhs, msense,
				 solution,
				 info.inTree ? false : true,
				 &cnum,&cnzcnt,
				 &cbeg,&ccnt,&cind,&cval,&crhs,&csense);
      }
      delete [] temp;
    }
    if (cnum) {
      // add cuts
      double * element = new double[mc_];
      for (int i=0;i<cnum;i++) {
	int n = ccnt[i];
	int start = cbeg[i];
	for (int j=0;j<n;j++) 
	  element[j]=cval[start+j];
	OsiRowCut rc;
	if (csense[i]=='L') {
	  rc.setLb(-COIN_DBL_MAX);
	  rc.setUb(crhs[i]);
	} else if (csense[i]=='G') {
	  rc.setLb(crhs[i]);
	  rc.setUb(COIN_DBL_MAX);
	} else {
	  abort();
	}
	rc.setRow(n,cind+start,element,false);
	if ((flags_&1)!=0)
	  rc.setGloballyValid();
	//double violation = rc.violated(solution);
	//if (violation>1.0e-6)
	  cs.insert(rc);
	  //else
	  //printf("violation of %g\n",violation);
      }
      delete [] element;
      free(cbeg); 
      free(ccnt);
      free(cind);
      free(cval);
      free(crhs);
      free(csense);
    }
  }
}
// Solve
int CouenneFeasPump::milpPhase (double *nSol, double *iSol, int niter, int *nsuciter) {

  const int depth = (model_ && (model_ -> currentNode ())) ? model_ -> currentNode () -> depth () : 0;

  double time0 = CoinCpuTime();

  // INTEGER PART /////////////////////////////////////////////////////////

  // Solve IP using nSol as the initial point to minimize weighted
  // l-1 distance from. If nSol==NULL, the MILP is created using the
  // original milp's LP solution.
            
  double z = solveMILP (nSol, iSol, niter, nsuciter);

  // if no MILP solution was found, bail out

  bool try_again = false;

  if (!iSol || z >= COIN_DBL_MAX/2) {

    problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: could not find IP solution\n");

    // find non-tabu solution in the solution pool
    while (!pool_ -> Set (). empty ()) {

      // EXTRACT the closest (to nSol) IP solution from the pool
      pool_ -> findClosestAndReplace (iSol, iSol, problem_ -> nVars ());

      CouenneFPsolution newSol (problem_, iSol);

      // we found a solution that is not in the tabu list
      if (tabuPool_ . find (newSol) == tabuPool_ . end ()) {

	try_again = true;
	break;
      }
    }

    if (!try_again) { // try moving around current solution 

      // SCIP could not find a MILP solution and we're somewhat
      // locked. Round current solution and feed it to the NLP. This
      // is better than just bailing out.

      int n = problem_ -> nVars ();

      if (!iSol)
	iSol = new double [n];

      for (int i=0; i<n; i++)
	iSol [i] = (problem_ -> Var (i) -> isInteger ()) ? 
	  COUENNE_round (nSol [i]) : 
	  nSol [i];
    }
 
    // if (!try_again) { // nothing to do, bail out	
    // 	problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: could not find from pool either, bailing out\n");
    // 	break;
    // }
  }

  bool isChecked = false;

  // If a solution was found, but is in the tabu list, two choices:
  //
  // 1) the pool is empty: do a round of cuts and repeat;
  //
  // 2) the pool is nonempty: extract the best solution from the
  //    pool and use it instead

  CouenneFPsolution checkedSol (problem_, iSol, false); // false is for not allocating space for this

  if (tabuPool_. find (checkedSol) == tabuPool_ . end ())

    tabuPool_. insert (CouenneFPsolution (problem_, iSol)); // only insertion to tabu pool: we check its feasibility now

  else {

    problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: found solution is tabu\n");

    // Current solution was visited before. Replace it with another
    // MILP solution from the pool, if any.

    if         (tabuMgt_ == FP_TABU_NONE) break;

    else   if ((tabuMgt_ == FP_TABU_POOL) && !(pool_ -> Set (). empty ())) {

      // try to find non-tabu solution in the solution pool
      do {

	// retrieve the top solution from the pool
	pool_ -> findClosestAndReplace (iSol, nSol, problem_ -> nVars ());

	CouenneFPsolution newSol (problem_, iSol);

	// we found a solution that is not in the tabu list
	if (tabuPool_. find (newSol) == tabuPool_ . end ())
	  break;

	// the pool is empty -> bail out
	if (pool_ -> Set ().empty ())
	  {
	    delete[] iSol;
	    iSol = NULL;
	  }

      } while( !pool_ -> Set ().empty() );

    } else if (((tabuMgt_ == FP_TABU_CUT)   ||  
		((pool_ -> Set (). empty ()) && iSol))) {

      OsiCuts cs;

      problem_   -> domain () -> push (problem_ -> nVars (), iSol, milp_ -> getColLower (), milp_ -> getColUpper (), false); // don't copy vectors
      couenneCG_ -> genRowCuts (*milp_, cs, 0, NULL); // remaining three arguments NULL by default
      problem_   -> domain () -> pop ();

      if (cs.sizeRowCuts ()) {

	milp_ -> applyCuts (cs);

	if (nSep++ < nSepRounds_)
	  continue;

      } else break; // nothing left to do, just bail out

    } else if ((tabuMgt_ == FP_TABU_PERTURB) && iSol) {

      // perturb solution	

      const CouNumber 
	*lb = milp_ -> getColLower (),
	*ub = milp_ -> getColUpper ();

      double 
	downMoves = 0.,
	upMoves   = 0.;

      int startIndex = (int) floor (CoinDrand48 () * problem_ -> nOrigVars ());

      for (int ii = problem_ -> nOrigVars (); ii--; lb++, ub++) {

	if (problem_ -> Var (ii) -> Multiplicity () <= 0)
	  continue;

	// make perturbation start from pseudo-random points

	int i = (startIndex + ii) % problem_ -> nOrigVars ();

	if (problem_ -> Var (i) -> isInteger ()) {

	  double
	    rnd  = CoinDrand48 (), 
	    down = 0.,
	    up   = 1.;

	  // if there is room on the left (resp. right) of the
	  // solution, consider moving down (resp. up). Make moves
	  // less likely as we don't want to perturb too many
	  // variables

#define RND_DECR_EXPONENT .5

	  if (iSol [i] >= lb [i] + 1.) down =      1. / pow (1. + (downMoves += 1.), RND_DECR_EXPONENT);
	  if (iSol [i] <= ub [i] - 1.) up   = 1. - 1. / pow (1. + (upMoves   += 1.), RND_DECR_EXPONENT);

	  if      (rnd < down) iSol [i] -= 1.;
	  else if (rnd > up)   iSol [i] += 1.;
	}
      }
    }
  } 

  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: checking IP solution for feasibility\n");

  isChecked = problem_ -> checkNLP0 (iSol, z, true, 
				     false, // don't care about obj
				     true,  // stop at first violation
				     true); // checkAll

  // Possible improvement: if IP-infeasible or if z does not improve
  // the best solution found so far, then try the following:
  //
  // 1) Fix integer variables to IP solution's corresponding components
  // 2) Solve restriction with original obj
  // 3) While not found (MI)NLP solution or
  //          solution MINLP infeasible or
  //          z not better
  // 4)   Get solution x* from pool
  // 5)   Solve with original objective
  // 6) Done
  // 7) If found solution, set it, otherwise keep previously found (IP-feasible) one

  if ((!isChecked ||                     // not MINLP feasible
       z > problem_ -> getCutOff ())) {  // not improving

    problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: infeasible/non-improving (feas==%d, z=%g, cutoff=%g), looping on pool\n", isChecked, z, problem_->getCutOff ());

    bool try_again;

    do {

      try_again = false;

      if (CoinCpuTime () > problem_ -> getMaxCpuTime ())
	break;

      // Check if fixing integers to those in iSol yields an
      // infeasible problem. If so, don't optimize
      if (fixIntVariables (iSol)) {

	nlp_ -> setInitSol (iSol);

	if (problem_ -> Jnlst () -> ProduceOutput (J_ALL, J_NLPHEURISTIC)) {
	  printf ("----------------------- Solving NLP:\n");
	  problem_ -> print ();
	  printf ("-----------------------\n");
	}

	status = app_ -> OptimizeTNLP (nlp_);

	if (nlp_ -> getSolution ()) { // check if non-NULL
	  if  (nSol)  CoinCopyN       (nlp_ -> getSolution (), problem_ -> nVars (), nSol);
	  else nSol = CoinCopyOfArray (nlp_ -> getSolution (), problem_ -> nVars ());
	}

	if (nlp_ -> getSolution () && (problem_ -> Jnlst () -> ProduceOutput (J_ALL, J_NLPHEURISTIC))) { // check if non-NULL
	  printf ("######################## NLP solution (loop through pool):\n");
	  for (int i=0; i< problem_ -> nVars ();) {
	    printf ("%+e ", nlp_ -> getSolution () [i]);
	    if (!(++i % 15)) printf ("\n");
	  }
	}

	z = nlp_ -> getSolValue ();

	if (z < problem_ -> getCutOff ()) // don't waste time if not improving

	  isChecked = problem_ -> checkNLP0 (nSol, z, true, 
					     false, // don't care about obj
					     true,  // stop at first violation
					     true); // checkAll

	if (isChecked && (z < problem_ -> getCutOff ())) 
	  break;
      } 

      // find non-tabu solution in the solution pool
      while (!pool_ -> Set (). empty ()) {

	// EXTRACT the closest (to nSol) IP solution from the pool
	pool_ -> findClosestAndReplace (iSol, nSol, problem_ -> nVars ());

	CouenneFPsolution newSol (problem_, iSol);

	// we found a solution that is not in the tabu list
	if (tabuPool_ . find (newSol) == tabuPool_ . end ()) {
	  try_again = true;
	  break;
	}
      } 

    } while (try_again);
  }

  // Whatever the previous block yielded, we are now going to check
  // if we have a new solution, and if so we save it.

  if (isChecked) {

    problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: IP solution is MINLP feasible\n");

    // solution is MINLP feasible! Save it.

    retval = 1;
    objVal = z;

    // Found a MINLP-feasible solution, but to keep diversity do NOT
    // use the best available. Just use this.
    //
    // #ifdef FM_CHECKNLP2
    // #  ifdef FM_TRACE_OPTSOL
    //       problem_->getRecordBestSol()->update();
    //       best = problem_->getRecordBestSol()->getSol();
    //       objVal = problem_->getRecordBestSol()->getVal();
    // #  else /* not FM_TRACE_OPTSOL */
    //       best = problem_->getRecordBestSol()->getModSol(problem_->nVars());
    //       objVal = z;
    // #  endif /* not FM_TRACE_OPTSOL */
    // #else /* not FM_CHECKNLP2 */
    // #  ifdef FM_TRACE_OPTSOL
    //       problem_->getRecordBestSol()->update(iSol, problem_->nVars(),
    // 					   z, problem_->getFeasTol());
    //       best = problem_->getRecordBestSol()->getSol();
    //       objVal = problem_->getRecordBestSol()->getVal();
    // #  else /* not FM_TRACE_OPTSOL */

    best = iSol;

    //       objVal = z;
    // #  ifdef FM_TRACE_OPTSOL
    //       problem_->getRecordBestSol()->update();
    //       best = problem_->getRecordBestSol()->getSol();
    //       objVal = problem_->getRecordBestSol()->getVal();
    // #  endif /* not FM_TRACE_OPTSOL */
    // #endif /* not FM_CHECKNLP2 */

    if (z < problem_ -> getCutOff ()) {

      problem_ -> setCutOff (objVal);

      t_chg_bounds *chg_bds = NULL;

      if (objInd >= 0) {
	chg_bds = new t_chg_bounds [problem_ -> nVars ()];
	chg_bds [objInd].setUpper (t_chg_bounds::CHANGED); 
      }

      // If, with new cutoff, bound tightening clears the whole
      // feasible set, stop
      bool is_still_feas = problem_ -> btCore (chg_bds);

      if (chg_bds)
	delete [] chg_bds;

      // don't tighten MILP if BT says it's infeasible

      if (!is_still_feas)
	break;

      // Update lb/ub on milp and nlp here
      const CouNumber 
	*plb = problem_ -> Lb (),
	*pub = problem_ -> Ub (),
	*mlb = milp_    -> getColLower (),
	*mub = milp_    -> getColUpper ();

      for (int i=problem_ -> nVars (), j=0; i--; ++j, ++plb, ++pub) {

	bool neglect = problem_ -> Var (j) -> Multiplicity () <= 0;

	if (*plb > *mlb++) milp_ -> setColLower (j, neglect ? 0. : *plb);
	if (*pub < *mub++) milp_ -> setColUpper (j, neglect ? 0. : *pub);
      }
    }

    break;

  } else {

    problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: IP solution NOT MINLP feasible\n");

    if (milpCuttingPlane_ == FP_CUT_EXTERNAL || 
	milpCuttingPlane_ == FP_CUT_POST) {

      // Solution is IP- but not MINLP feasible: it might get cut by
      // linearization cuts. If so, add a round of cuts and repeat.

      OsiCuts cs;

      problem_   -> domain () -> push (milp_);
      couenneCG_ -> genRowCuts (*milp_, cs, 0, NULL); // remaining three arguments NULL by default
      problem_   -> domain () -> pop ();

      if (cs.sizeRowCuts ()) { 

	// the (integer, NLP infeasible) solution could be separated

	milp_ -> applyCuts (cs);

	// found linearization cut, now re-solve MILP (not quite a FP)
	if (milpCuttingPlane_ == FP_CUT_EXTERNAL && 
	    nSep++ < nSepRounds_)
	  continue;
      }
    }
  }
}
void CglOddHole::generateCuts(const OsiRowCutDebugger * /*debugger*/,
			      const CoinPackedMatrix & rowCopy, 
				 const double * solution, 
			      const double * dj, OsiCuts & cs,
				 const int * suitableRow,
			      const int * fixedColumn,
			      const CglTreeInfo info,
			      bool packed)
{
  CoinPackedMatrix columnCopy = rowCopy;
  columnCopy.reverseOrdering();

  // Get basic problem information
  int nRows=columnCopy.getNumRows(); 
  int nCols=columnCopy.getNumCols(); 
  
  const int * column = rowCopy.getIndices();
  const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
  const int * rowLength = rowCopy.getVectorLengths(); 
  
  const int * row = columnCopy.getIndices();
  const CoinBigIndex * columnStart = columnCopy.getVectorStarts();
  const int * columnLength = columnCopy.getVectorLengths(); 

  // we need only look at suitable rows and variables with unsatisfied 0-1
  // lookup from true row to compressed matrix
  int * mrow = new int[nRows];
  // lookup from true column to compressed
  int * lookup = new int[nCols];
  // number of columns in compressed matrix
  int nSmall=0;
  int i;
  //do lookup from true sequence to compressed
  int n=0;
  for (i=0;i<nRows;i++) {
    if (suitableRow[i]>0) {
      mrow[i]=n++;
    } else {
      mrow[i]=-1;
    }
  }
  for (i=0;i<nCols;i++) {
    if (!fixedColumn[i]) {
      lookup[i]=nSmall++;
    } else {
      lookup[i]=-1;
    }
  }
  int nSmall2=2*nSmall;
  // we don't know how big matrix will be
#define MAXELS 50000
  int maxels=MAXELS;
  //How do I do reallocs in C++?
  // 1.0 - value x(i) - value x(j) for each node pair (or reverse if cover) 
  double * cost = reinterpret_cast<double *> (malloc(maxels*sizeof(double)));
  // arc i.e. j which can be reached from i
  int * to= reinterpret_cast<int *> (malloc(maxels*sizeof(int)));
  //original row for each arc
  int * rowfound=reinterpret_cast<int *> (malloc(maxels*sizeof(int)));
  // start of each column
  int * starts=new int[2*nSmall+1];
  starts[0]=0;
  // useful array for marking if already connected
  int * mark =new int[nSmall2];
  memset(mark,0,nSmall2*sizeof(int));
  n=0; //number of elements in matrix
  for (i=0;i<nCols;i++) {
    int icol=lookup[i];
    if (icol>=0) {
      // column in compressed matrix
      int k;
      double dd=1.0000001-solution[i];
      mark[icol]=1;
      // reallocate if matrix reached size limit
      if (n+nCols>maxels) {
	maxels*=2;
	cost=reinterpret_cast<double *> (realloc(cost,maxels*sizeof(double)));
	to=reinterpret_cast<int *> (realloc(to,maxels*sizeof(int)));
	rowfound=reinterpret_cast<int *> (realloc(rowfound,maxels*sizeof(int)));
      }
      // get all other connected variables
      for (k=columnStart[i];k<columnStart[i]+columnLength[i];k++) {
	int irow=row[k];
	int jrow=mrow[irow];
	// but only if row in compressed matrix
	if (jrow>=0) {
	  int j;
	  for (j=rowStart[irow];j<rowStart[irow]+rowLength[irow];j++) {
	    int jcol=column[j];
	    int kcol=lookup[jcol];
	    if (kcol>=0&&!mark[kcol]) {
	      cost[n]=dd-solution[jcol];
	      to[n]=kcol;
	      rowfound[n++]=irow;//original row
	      mark[kcol]=1;
	    }
	  }
	}
      }
      starts[icol+1]=n;
      // zero out markers for next column
      mark[icol]=0;
      for (k=starts[icol];k<starts[icol+1];k++) {
	int ito=to[k];
	if (ito<0||ito>=nSmall) abort();
	mark[to[k]]=0;
      }
    }
  }
  //if cover then change sign - otherwise make sure positive
  if (packed) {
    for (i=0;i<n;i++) {
      if (cost[i]<1.0e-10) {
	cost[i]=1.0e-10;
      }
    }
  } else {
    for (i=0;i<n;i++) {
      cost[i]=-cost[i];
      if (cost[i]<1.0e-10) {
	cost[i]=1.0e-10;
      }
    }
  }
  // we are going to double size 

  if (2*n>maxels) {
    maxels=2*n;
    cost=reinterpret_cast<double *> (realloc(cost,maxels*sizeof(double)));
    to=reinterpret_cast<int *> (realloc(to,maxels*sizeof(int)));
    rowfound=reinterpret_cast<int *> (realloc(rowfound,maxels*sizeof(int)));
  }
  /* copy and make bipartite*/

  for (i=0;i<nSmall;i++) {
    int k,j=i+nSmall;
    for (k=starts[i];k<starts[i+1];k++) {
      int ito=to[k];
      to[n]=ito;
      to[k]=ito+nSmall;
      cost[n]=cost[k];
      rowfound[n++]=rowfound[k];;
    }
    starts[j+1]=n;
  }
  //random numbers to winnow out duplicate cuts
  double * check = new double[nCols];
  if (info.randomNumberGenerator) {
    const CoinThreadRandom * randomGenerator = info.randomNumberGenerator;
    for (i=0;i<nCols;i++) {
      check[i]=randomGenerator->randomDouble();
    }
  } else {
    CoinSeedRandom(13579);
    for (i=0;i<nCols;i++) {
      check[i]=CoinDrand48(); // NOT on a thread by thread basis
    }
  }

  // Shortest path algorithm from Dijkstra - is there a better one?

  typedef struct {
    double cost; //cost to starting node
    int back; //previous node
  } Path;
  typedef struct {
    double cost; //cost to starting node
    int node; //node
  } Item;
  Item * stack = new Item [nSmall2];
  Path * path = new Path [nSmall2];
  // arrays below are used only if looks promising
  // allocate here
  // we don't know how many cuts will be generated
  int ncuts=0;
  int maxcuts=1000;
  double * hash = reinterpret_cast<double *> (malloc(maxcuts*sizeof(double)));
  // to clean (should not be needed)
  int * clean = new int[nSmall2];
  int * candidate = new int[CoinMax(nSmall2,nCols)];
  double * element = new double[nCols];
  // in case we want to sort
  double_double_int_triple * sortit = 
    new double_double_int_triple [nCols];
  memset(mark,0,nSmall2*sizeof(int));
  int * countcol = new int[nCols];
  memset(countcol,0,nCols*sizeof(int));
  int bias = packed ? 0 : 1; //amount to add before halving
  // If nSmall large then should do a randomized subset
  // Improvement 1
  int icol;
  for (icol=0;icol<nSmall;icol++) {
    int j;
    int jcol=icol+nSmall;
    int istack=1;
    for (j=0;j<nSmall2;j++) {
      path[j].cost=1.0e70;
      path[j].back=nSmall2+1;
    }
    path[icol].cost=0.0;
    path[icol].back=-1;
    stack[0].cost=0.0;
    stack[0].node=icol;
    mark[icol]=1;
    while(istack) {
      Item thisItem=stack[--istack];
      double thisCost=thisItem.cost;
      int inode=thisItem.node;
      int k;
      mark[inode]=0; //say available for further work
      // See if sorting every so many would help (and which way)?
      // Improvement 2
      for (k=starts[inode];k<starts[inode+1];k++) {
	int jnode=to[k];
	if (!mark[jnode]&&thisCost+cost[k]<path[jnode].cost-1.0e-12) {
	  path[jnode].cost=thisCost+cost[k];
	  path[jnode].back=inode;
	  // add to stack
	  stack[istack].cost=path[jnode].cost;
	  stack[istack++].node=jnode;
	  mark[jnode]=1;
#ifdef CGL_DEBUG
	  assert (istack<=nSmall2);
#endif
	}
      }
    }
    bool good=(path[jcol].cost<0.9999);

    if (good)  { /* try */
      int ii;
      int nrow2=0;
      int nclean=0;
      double sum=0;
#ifdef CGL_DEBUG
      printf("** %d ",jcol-nSmall);
#endif
      ii=1;
      candidate[0]=jcol;
      while(jcol!=icol) {
	int jjcol;
	jcol=path[jcol].back;
	if (jcol>=nSmall) {
	  jjcol=jcol-nSmall;
	} else {
	  jjcol=jcol;
	}
#ifdef CGL_DEBUG
	printf(" %d",jjcol);
#endif
	if (mark[jjcol]) {
	  // good=false;
	  // probably means this is from another cycle (will have been found)
	  // one of cycles must be zero cost
	  // printf("variable already on chain!\n");
	} else {
	  mark[jjcol]=1;
	  clean[nclean++]=jjcol;
	  candidate[ii++]=jcol;
#ifdef CGL_DEBUG
	  assert (ii<=nSmall2);
#endif
	}
      }
#ifdef CGL_DEBUG
      printf("\n");
#endif
      for (j=0;j<nclean;j++) {
	int k=clean[j];
	mark[k]=0;
      }
      if (good) {
	int k;
	for (k=ii-1;k>0;k--) {
	  int jk,kk=candidate[k];
	  int ix=0;
	  for (jk=starts[kk];jk<starts[kk+1];jk++) {
	    int ito=to[jk];
	    if (ito==candidate[k-1]) {
	      ix=1;
	      // back to original row
	      mrow[nrow2++]=rowfound[jk];
	      break;
	    }
	  }
	  if (!ix) {
	    good=false;
	  }
	}
	if ((nrow2&1)!=1) {
	  good=false;
	}
	if (good) {
	  int nincut=0;
	  for (k=0;k<nrow2;k++) {
	    int j,irow=mrow[k];
	    for (j=rowStart[irow];j<rowStart[irow]+rowLength[irow];j++) {
	      int icol=column[j];
	      if (!countcol[icol]) candidate[nincut++]=icol;
	      countcol[icol]++;
	    }
	  }
#ifdef CGL_DEBUG
	  printf("true constraint %d",nrow2);
#endif
	  nrow2=nrow2>>1;
	  double rhs=nrow2; 
	  if (!packed) rhs++; // +1 for cover
	  ii=0;
	  for (k=0;k<nincut;k++) {
	    int jcol=candidate[k];
	    if (countcol[jcol]) {
#ifdef CGL_DEBUG
	      printf(" %d %d",jcol,countcol[jcol]);
#endif
	      int ihalf=(countcol[jcol]+bias)>>1;
	      if (ihalf) {
		element[ii]=ihalf;
		sum+=solution[jcol]*element[ii];
		/*printf("%d %g %g\n",jcol,element[ii],sumall[jcol]);*/
		candidate[ii++]=jcol;
	      }
	      countcol[jcol]=0;
	    }
	  }
#ifdef CGL_DEBUG
          printf("\n");
#endif
	  OsiRowCut rc;
	  double violation=0.0;
	  if (packed) {
	    violation = sum-rhs;
	    rc.setLb(-COIN_DBL_MAX);
	    rc.setUb(rhs);   
	  } else {
	    // other way for cover
	    violation = rhs-sum;
	    rc.setUb(COIN_DBL_MAX);
	    rc.setLb(rhs);   
	  }
	  if (violation<minimumViolation_) {
#ifdef CGL_DEBUG
	    printf("why no cut\n");
#endif
	    good=false;
	  } else {
	    if (static_cast<double> (ii) * minimumViolationPer_>violation||
		ii>maximumEntries_) {
#ifdef CGL_DEBUG
	      printf("why no cut\n");
#endif
	      if (packed) {
		// sort and see if we can get down to length
		// relax by taking out ones with solution 0.0
		nincut=ii;
		for (k=0;k<nincut;k++) {
		  int jcol=candidate[k];
		  double value = fabs(dj[jcol]);
		  if (solution[jcol])
		  value = -solution[jcol];
		  sortit[k].dj=value;
		  sortit[k].element=element[k];
		  sortit[k].sequence=jcol;
		}
		// sort 
		std::sort(sortit,sortit+nincut,double_double_int_triple_compare());
		nincut = CoinMin(nincut,maximumEntries_);
		sum=0.0;
		for (k=0;k<nincut;k++) {
		  int jcol=sortit[k].sequence;
		  candidate[k]=jcol;
		  element[k]=sortit[k].element;
		  sum+=solution[jcol]*element[k];
		}
		violation = sum-rhs;
		ii=nincut;
		if (violation<minimumViolation_) {
		  good=false;
		}
	      } else { 
		good=false;
	      }
	    }
	  }
	  if (good) {
	    //this assumes not many cuts
	    int j;
#if 0
	    double value=0.0;
	    for (j=0;j<ii;j++) {
	      int icol=candidate[j];
	      value += check[icol]*element[j];
	    }
#else
            CoinPackedVector candidatePv(ii,candidate,element);
            candidatePv.sortIncrIndex();
            double value = candidatePv.dotProduct(check);
#endif

	    for (j=0;j<ncuts;j++) {
	      if (value==hash[j]) {
		//could check equality - quicker just to assume
		break;
	      }
	    }
	    if (j==ncuts) {
	      //new
	      if (ncuts==maxcuts) {
		maxcuts *= 2;
		hash = reinterpret_cast<double *> (realloc(hash,maxcuts*sizeof(double)));
	      }
	      hash[ncuts++]=value;
	      rc.setRow(ii,candidate,element);
#ifdef CGL_DEBUG
	      printf("sum %g rhs %g %d\n",sum,rhs,ii);
	      if (debugger) 
		assert(!debugger->invalidCut(rc)); 
#endif
	      cs.insert(rc);
	    }
	  }
	}
	/* end of adding cut */
      }
    }
  }
  delete [] countcol;
  delete [] element;
  delete [] candidate;
  delete [] sortit;
  delete [] clean;
  delete [] path;
  delete [] stack;
  free(hash);
  delete [] check;
  delete [] mark;
  delete [] starts;
  delete [] lookup;
  delete [] mrow;
  free(rowfound);
  free(to);
  free(cost);
}