Пример #1
0
bool SOS1Handler::isFeasible(ConstSolutionPtr sol, RelaxationPtr rel, bool &,
                             double &)
{
  SOSPtr sos;
  bool isfeas = true;
  int nz;
  const double* x = sol->getPrimal();

  for (SOSConstIterator siter=rel->sos1Begin(); siter!=rel->sos1End();
       ++siter) {
    sos = *siter;
    nz = 0;
    for (VariableConstIterator viter = sos->varsBegin(); viter!=sos->varsEnd();
         ++viter) {
      if (x[(*viter)->getIndex()]>zTol_) {
        ++nz;
        if (nz>1) {
          isfeas = false;
          break;
        }
      }
    }
    if (false == isfeas) {
      break;
    }
  }

#if SPEW
  logger_->msgStream(LogDebug) << me_ << "isFeasible = " << isfeas
                               << std::endl;
#endif
  return isfeas;
}
bool
MultilinearTermsHandler::isFeasible(ConstSolutionPtr sol, RelaxationPtr ,
                                    bool &, double &)
{
  const double *x = sol->getPrimal();
  bool is_feas = true;

#if defined(DEBUG_MULTILINEARTERMS_HANDLER)
  std::cout << "Checking feasibility: " << std::endl;
#endif

  for (ConstTermIterator it = termsR_.begin(); it != termsR_.end(); ++it) {
    ConstVariablePtr zt = it->first;
    SetOfVars const &jt = it->second;

    if (allVarsBinary_(jt)) continue;

    double zval = x[zt->getIndex()];
    double xval = 1.0;
    for(SetOfVars::const_iterator jt_it = jt.begin(); jt_it != jt.end(); ++jt_it) {
      xval *= x[(*jt_it)->getIndex()];
    }
#if defined(DEBUG_MULTILINEARTERMS_HANDLER)
    std::cout << "Term for variable: " << std::endl;
    zt->write(std::cout);
    std::cout << " has error: " << fabs(zval - xval) << std::endl;
#endif
    if (fabs(zval - xval) > eTol_) {
      is_feas = false;
      break;
    }
  }
  
  return(is_feas);
}
Пример #3
0
void ParQGHandler::separate(ConstSolutionPtr sol, NodePtr , RelaxationPtr rel,
                         CutManager *cutMan, SolutionPoolPtr s_pool, ModVector &,
                         ModVector &, bool *sol_found, SeparationStatus *status)
{
  double val;
  VariableType v_type;
  VariableConstIterator v_iter;
  const double *x = sol->getPrimal();
  *status = SepaContinue;

  for (v_iter = rel->varsBegin(); v_iter != rel->varsEnd(); ++v_iter) {
    v_type = (*v_iter)->getType();
    if (v_type == Binary || v_type == Integer) {
      val = x[(*v_iter)->getIndex()];
      if (fabs(val - floor(val+0.5)) > intTol_) {
#if SPEW
        logger_->msgStream(LogDebug) << me_ << "variable " <<
          (*v_iter)->getName() << " has fractional value = " << val <<
          std::endl;
#endif
        return;
      }
    }
  }
  cutIntSol_(sol, cutMan, s_pool, sol_found, status);
  return;
}
Пример #4
0
bool ParQGHandler::isFeasible(ConstSolutionPtr sol, RelaxationPtr, bool &,
                           double &)
{
  int error=0;
  double act, cUb;
  ConstraintPtr c;
  const double *x = sol->getPrimal();

  for (CCIter it=nlCons_.begin(); it!=nlCons_.end(); ++it) {
    c = *it;
    act = c->getActivity(x, &error);
    if (error == 0) {
      cUb = c->getUb();
      if ((act > cUb + solAbsTol_) &&
          (cUb == 0 || act > cUb + fabs(cUb)*solRelTol_)) {
#if SPEW
        logger_->msgStream(LogDebug) << me_ << "constraint " <<
          c->getName() << " violated with violation = " << act - cUb <<
          std::endl;
#endif
        return false;
      }
    }	else {
      logger_->msgStream(LogError) << me_ << c->getName() <<
        "constraint not defined at this point."<< std::endl;
#if SPEW
      logger_->msgStream(LogDebug) << me_ << "constraint " << c->getName() <<
        " not defined at this point." << std::endl;
#endif
      return false;
    }
  }

  if (oNl_) {
    error = 0;
    relobj_ = x[objVar_->getIndex()];
    act = minlp_->getObjValue(x, &error);
    if (error == 0) {
      if ((act > relobj_ + solAbsTol_) &&
          (relobj_ == 0 || (act > relobj_ + fabs(relobj_)*solRelTol_))) {
#if SPEW
        logger_->msgStream(LogDebug) << me_ << "objective violated with "
          << "violation = " << act - relobj_ << std::endl;
#endif
        return false;
      }
    }	else {
      logger_->msgStream(LogError) << me_
        <<"objective not defined at this point."<< std::endl;
      return false;
    }
  }
  return true;
}
Пример #5
0
bool CxUnivarHandler::isFeasible(ConstSolutionPtr sol, RelaxationPtr , bool &,
                                 double &)
{
  bool isfeas = true;
  CxUnivarConstraintIterator dit; 
  
  for (dit = cons_data_.begin(); dit != cons_data_.end(); ++dit) {
      if (!(*dit)->isFeasible(sol->getPrimal())) {
         isfeas = false;
         break;
      }	
  }

  return isfeas;

}
Пример #6
0
int main() 
{

  // Generate output.
  ofstream output;
  output.open("numknapcov.txt");
  // Generate input.
  ifstream input;
  input.open("list.txt");
  // Check if input is opened succesfully.
  if (input.is_open() == false) {
    cerr   << "Input file read error." << endl;
    output << "Input file read error." << endl;
    exit(0);
  }
  
  /********************************************************************************/
  // Headers for output data.
  output << "Statistics of knapsack cover cuts applied to root relaxation." << endl;
  output << "problem " << "vars " << "cons " << "lincons " << "knapcons " << "knapcov "
	 << "knaps " << "totalcuts " << "cuts " << "violknapcuts " << "initobj " 
	 << "endobj " << "gapclosed " << "timeinit " << "timecut " << "timemod" 
	 <<  endl;
  /********************************************************************************/

  // loop to test all problems in list.txt
  while (input.good()) {
    // problem name
    string pname;
    getline(input, pname);
    // At the end of file just exit from loop.
    if (pname.empty()) {
      break;
    }

    cout << "Problem considered is: " << pname << endl;

    // Real stuff begins.
    // Ampl interface, jacobian and hessian.
    MINOTAUR_AMPL::AMPLInterfacePtr iface = MINOTAUR_AMPL::AMPLInterfacePtr();  
    JacobianPtr jPtr;            //! Jacobian read from AMPL
    HessianOfLagPtr hPtr;        //! Hessian read from AMPL
  
    // environment, timers and options:
    EnvPtr env = (EnvPtr) new Environment();
    OptionDBPtr options;

    // problem to be solved.
    ProblemPtr minlp;
  
    // solver pointers, including status.
    FilterSQPEngine e(env);
    EngineStatus status;

    // Presolver.
    PresolverPtr pres;
  
    // give parameters.
    UInt argc2 = 2;
    std::string arg1 = "bnb";
    std::string arg2 = pname;
    char** argv2 = new char* [2];
    argv2[0] = &arg1[0];
    argv2[1] = &arg2[0];

    // Default options
    env->getOptions()->findBool("presolve")->setValue(false);
    env->getOptions()->findBool("use_native_cgraph")->setValue(true);
    env->getOptions()->findBool("nl_presolve")->setValue(false);
    // parse options
    env->readOptions(argc2, argv2);
    options = env->getOptions();
    options->findString("interface_type")->setValue("AMPL");

    // read minlp from AMPL.
    iface = (MINOTAUR_AMPL::AMPLInterfacePtr) new MINOTAUR_AMPL::AMPLInterface(env); 
    minlp = iface->readInstance(pname);

    // Timer is obtained.
    Timer * timer = env->getNewTimer();

    // Nonlinearize objective function.
    Bool MIPCONSIDERED = false;
    if (MIPCONSIDERED ==  true) {
      ObjectivePtr initobjfun = minlp->getObjective();
      if (initobjfun->getObjectiveType() == Maximize) {
    	cerr << "Objective type is Maximize, change it to Minimize." << endl;
    	exit(0);
      }
      LinearFunctionPtr lfinitobj = initobjfun->getLinearFunction();
      // NonlinearFunctionPtr nlfobj = (NonlinearFunctionPtr) new NonlinearFunction();
      CGraphPtr nlfobj = (CGraphPtr) new CGraph();
      logobj(lfinitobj, nlfobj);
      FunctionPtr logobjfun = (FunctionPtr) new Function(nlfobj);      
      ObjectiveType otyp = Minimize;
      minlp->changeObj(logobjfun, 0);
    }
    
    minlp->calculateSize();
    minlp->prepareForSolve();

    // Change format of problem to be suitable for Minotaur.
    HandlerVector handlers;
    // Use presolver to standardize problem.
    //pres = (PresolverPtr) new Presolver(minlp, env, handlers);
    //pres->standardize();

    minlp->calculateSize();
    minlp->prepareForSolve();
  
    minlp->setJacobian(jPtr);
    minlp->setHessian(hPtr);
    minlp->setNativeDer();

    minlp->calculateSize();
    minlp->prepareForSolve();
    minlp->setNativeDer();

    //minlp->write(std::cout);

    /**************************************************************/
    // Given problem statistics .
    // Number of variables.
    UInt numvars = minlp->getNumVars();
    // number of constraints.
    UInt numcons = minlp->getNumCons();
    // linear constraints.
    UInt numlin = minlp->getNumLinCons();
    /*************************************************************/

    // set option for engine to resolve to solve NLP repeatedly.
    // Probbaly does nothing.
    e.setOptionsForRepeatedSolve();

    // load problem.
    e.load(minlp);
      
    // Solve problem.
    timer->start();
    status = e.solve();

    /********************************************************************/
    // Solution time of relaxation.
    Double timeinit = timer->query();
    timer->stop();
    // Solution objective value
    Double initobj = e.getSolutionValue();
    /********************************************************************/

    std::cout << "Relaxation objective value = " << initobj << std::endl; 
  
    // Get solution from engine.
    ConstSolutionPtr sol = e.getSolution();
  
    // Construct relaxation.
    RelaxationPtr rel = (RelaxationPtr) new Relaxation(minlp);
    
    // Time for cut generation.
    timer->start();
    // Generate kanpsack cover cuts.
    CoverCutGeneratorPtr knapgen = 
      (CoverCutGeneratorPtr) new CoverCutGenerator(rel, sol, env);

    /*******************************************************************/
    Double timecut = timer->query();
    timer->stop();
    /*******************************************************************/


    // Get statistics of cut generator.
    ConstCovCutGenStatsPtr knapstats = knapgen->getStats();

    /*******************************************************************/
    // Knapsack cut generator statistics.
    // knapsack constraints.
    UInt numknap = (knapgen->getKnapsackList())->getNumKnaps();
    // knapsacks that has cover sets.
    UInt numknapcov = knapgen->getNumCons();
    // knapsack subproblems solved, i.e number of lifting subproblems solved.
    UInt knaps = knapstats->knaps;
    // cover cuts including duplicates.
    UInt totalcuts = knapstats->totalcuts;
    // cuts without duplicates.
    UInt numknapcuts = knapstats->cuts;
    // violated cuts.
    UInt violknapcuts = knapstats->violated;
    /*******************************************************************/


    std::cout << "Number of knapsack cover cuts to be applied is: " 
	      << knapstats->violated << std::endl;

    // Get the violated cuts from generator.
    CutVector knapcuts = knapgen->getViolatedCutList();

    // Iterators for cuts
    CutVectorConstIter it;
    CutVectorConstIter begin = knapcuts.begin();
    CutVectorConstIter end   = knapcuts.end();

    // Apply the cuts to the problem.
    // Violation list.
    DoubleVector knapviols = knapgen->getViolList();
    UInt curknap = 0;
    Double maxviol = 0.0;
    for (it=begin; it!=end; ++it) {
      std::cout << "Violation obtained from this constraint is: "
		<< knapviols[curknap] << std::endl;
      ConstraintPtr newcons = rel->newConstraint((*it)->getFunction(), (*it)->getLb(), (*it)->getUb());
      if (maxviol < knapviols[curknap]) {
	maxviol = knapviols[curknap];
      }
      // add constraint to engine does not do anything.
      // Thus, we add constraint to the relaxation and reload it to engine.
      // e.addConstraint(newcons);
    }


    /*******************************************************************/
    // Solution time of knapsack cover cuts added problem.
    Double timemod = 0.0;
    // Objective value after adding knapsack cover cuts.
    Double endobj = 0.0;
    // Gap closed by using knapsack cover cuts.
    Double gapknap = 0.0;
    /*******************************************************************/

    if (violknapcuts >= 1) {
      // Reload problem to engine.
      // Check if we should reload the modified problem.
      e.clear();
      const Double * xupdated;
      if (WARMSTART == 1) {
	// Set initial point as the solution of root solution.
	xupdated = sol->getPrimal();
	rel->setInitialPoint(xupdated);
      }

      // Load the modified problem.
      e.load(rel);
    
      // warmstart continues.
      if (WARMSTART == 1) {
	// Before presolve, we set initial primal and 
	// dual solutions as the root solution.
	SolutionPtr solupdated = (SolutionPtr) new Solution(initobj, xupdated, rel);
	// Create new dual solution.
	const Double * dualofvars = sol->getDualOfVars();
	solupdated->setDualOfVars(dualofvars);
	const Double * initdualofcons = sol->getDualOfCons();
	UInt numconsupdated = rel->getNumCons();
	Double * dualofcons = new Double[numconsupdated];
	memcpy(dualofcons, initdualofcons, numcons*sizeof(Double));
	for (UInt indexx = numcons; indexx < numconsupdated; ++indexx) {
	  dualofcons[indexx] = 0.0;
	}
	solupdated->setDualOfCons(dualofcons);
	FilterWSPtr warmstart = (FilterWSPtr) new FilterSQPWarmStart();
	warmstart->setPoint(solupdated);
	e.loadFromWarmStart(warmstart);

	delete [] dualofcons;
      }

      // Solution time after adding knapsack cover cuts to relaxation.
      timer->start();
      // Resolve the problem.
      e.solve();
    
      /*******************************************************************/
      // Solution time of knapsack cover cuts added problem.
      timemod = timer->query();
      timer->stop();
      // Objective value after adding knapsack cover cuts.
      endobj = e.getSolutionValue();
      // Gap closed by using knapsack cover cuts.
      gapknap = (endobj-initobj)/fabs(initobj) * 100;
      /*******************************************************************/
    } else {
      /*******************************************************************/
      // Solution time of knapsack cover cuts added problem.
      timemod = timeinit;
      // Objective value after adding knapsack cover cuts.
      endobj = initobj;
      // Gap closed by using knapsack cover cuts.
      gapknap = 0.0;
      /*******************************************************************/
    }


    std::cout << "Objective value of relaxation after adding cuts: "
	      << endobj << std::endl;

    cout << pname << " " << numvars  << " " << numcons << " " << numlin 
	 << " " << numknap
	 << " " << numknapcov << " " << knaps << " " << totalcuts
	 << " " << numknapcuts << " " << violknapcuts
	 << std::fixed << std::setprecision(2) 
	 << " " << initobj << " " << endobj
	 << " " << gapknap << " " << timeinit << " " << timecut
	 << " " << timemod << endl;

    if (numknap >= 1) {    
    // Save output data.
      output << pname << " " << numvars << " " << numcons << " " << numlin 
	     << " " << numknap
	     << " " << numknapcov << " " << knaps << " " << totalcuts
	     << " " << numknapcuts << " " << violknapcuts
	     << std::fixed << std::setprecision(2) 
	     << " " << initobj << " " << endobj
	     << " " << gapknap << " " << timeinit << " " << timecut
	     << " " << timemod << endl;
    }
      
    delete iface;
    delete [] argv2;
  }

  output.close();
  input.close();

  return 0;
}
Пример #7
0
Branches RandomBrancher::findBranches(RelaxationPtr rel, NodePtr ,
                                      ConstSolutionPtr sol,
                                      SolutionPoolPtr s_pool,
                                      BrancherStatus & br_status,
                                      ModVector &mods) 
{
  Branches branches;
  DoubleVector x(rel->getNumVars());
  BrVarCandSet cands;      // candidates from which to choose one.
  BrVarCandSet cands2;     // temporary set.
  BrCandVector gencands;
  BrCandVector gencands2;  // temporary set.
  BrCandPtr best_can = BrCandPtr(); // NULL
  bool is_inf = false;

  timer_->start();
  std::copy(sol->getPrimal(), sol->getPrimal()+rel->getNumVars(), x.begin());
  
  ++(stats_->calls);
  br_status = NotModifiedByBrancher;

  for (HandlerIterator h = handlers_.begin(); h != handlers_.end(); ++h) {
    // ask each handler to give some candidates
    (*h)->getBranchingCandidates(rel, x, mods, cands2, gencands2, is_inf);
    for (BrVarCandIter it = cands2.begin(); it != cands2.end(); ++it) {
      (*it)->setHandler(*h);
    }
    for (BrCandVIter it = gencands2.begin(); it != gencands2.end(); ++it) {
      (*it)->setHandler(*h);
    }
    cands.insert(cands2.begin(), cands2.end());
    gencands.insert(gencands.end(), gencands2.begin(), gencands2.end());
    cands2.clear();
    gencands2.clear();
    if (is_inf || mods.size()>0) {
      cands.clear();
      gencands.clear();
      if (is_inf) {
        br_status = PrunedByBrancher;
        stats_->time += timer_->query();
        timer_->stop();
        return branches;
      }
    }
  }

  if (cands.size() > 0) {
    BrVarCandIter it = cands.begin();

    std::advance(it,rand()%cands.size());
    best_can = *(it);
  } else if (gencands.size() > 0) {
    BrCandVIter it = gencands.begin();

    std::advance(it,rand()%gencands.size());
    best_can = *(it);
  }

  if (best_can) {
    best_can->setDir(DownBranch);

    branches = best_can->getHandler()->getBranches(best_can, x, rel, s_pool); 
#if SPEW
    logger_->msgStream(LogDebug) << me_ << "best candidate = "
                                 << best_can->getName() << std::endl;
#endif
  } else {
    assert(!"problem finding candidate in RandomBrancher");
  }

  stats_->time += timer_->query();
  timer_->stop();
  return branches;
}
Пример #8
0
void KnapCovHandler::separate(ConstSolutionPtr sol, NodePtr,
                              RelaxationPtr rel, CutManager * cmanager,
                              SolutionPoolPtr , bool * ,
                              SeparationStatus * status)
{
  // Check integer feasibility of sol, must add cuts if it is not integral.
  numvars_ = minlp_->getNumVars();
  VariableType type;
  const double * x = sol->getPrimal();
  // Is the relaxation solution is integer feasible.
  bool isintfeas = true;
  // Iterators for variables.
  VariableConstIterator it;
  VariableConstIterator begin = rel->varsBegin();
  VariableConstIterator end   = rel->varsEnd();
  // Temporary variable holder.
  ConstVariablePtr var; 
  // Value of variable.
  double value;
  bool separated = false;
  UInt n_added = 0;

  // Check if integrality is satisfied for each integer variable. 
  for (it=begin; it!=end; ++it) {
    var = *it;
    type = var->getType();
    if (type==Binary || type==Integer) {
      value = x[var->getIndex()];
      if (fabs(value - floor(value + 0.5)) > intTol_) {
        isintfeas = false;
        break;
      }
    }
  }

  if (isintfeas ==  false) {
    // We do another check in CoverCutGneerator for integrality, may be we
    // should eliminate it and use the one above.
    // Generate cover cuts from current relaxation.
    CoverCutGeneratorPtr cover = (CoverCutGeneratorPtr) new CoverCutGenerator(rel,sol, env_);
    // Add cuts to the relaxation by using cut manager.
    CutVector violatedcuts = cover->getViolatedCutList();
    CutIterator itc;
    CutIterator beginc = violatedcuts.begin();
    CutIterator endc   = violatedcuts.end();
    
    // Serdar I am not sure if we should add the constraints generated by
    // addCuts to the constraint vector of knapsack cover handler.
    // Currently CutMan2::addCuts does not add the cuts to the relaxation formulation.
    cmanager->addCuts(beginc, endc);
    cmanager->separate(rel, sol, &separated, &n_added);
    if (n_added>0) {
      *status = SepaResolve;
    }
    
    // Update statistics by using return from cover cut generator.
    ConstCovCutGenStatsPtr covstats = cover->getStats();
    // Later put the code below to updateStats function.
    stats_->knaps += covstats->knaps;
    stats_->cuts += covstats->cuts;
    stats_->extended += covstats->extended;
    stats_->simple += covstats->simple;
    stats_->gns += covstats->gns;
    stats_->singlectwo += covstats->singlectwo;    
  }

  
}
Пример #9
0
void LinFeasPump::implementFP_(const double*, SolutionPoolPtr s_pool)
{
  ConstSolutionPtr sol;
  const double* x_lp;
  double hash_val, f_nlp;
  UInt n_to_flip, k;
  SeparationStatus sep_status = SepaContinue;
  EngineStatus lp_status      = EngineUnknownStatus;
  NodePtr node                = NodePtr();
  bool to_continue            = true;
  bool is_feasible            = false;
  bool sol_found              = false;
  bool is_prob_infeasible     = prepareLP_();
  bool should_separate        = true;
  UInt max_NLP                = 10;
  UInt max_LP                 = 2000;
  UInt max_cycle              = 1000;
  UInt min_flip               = 2;
  UInt max_non_zero_obj       = 500;
  double inf_meas             = 0.0;
  int err;
  
  e_->setOptionsForSingleSolve();
  lpE_->solve();
  f_nlp = lpE_->getSolutionValue();
  sol   = lpE_->getSolution();
  should_separate = (p_->getObjective()->getFunction()->
                     getNumVars() > max_non_zero_obj) ? false : true;

  while(!is_feasible && stats_->numNLPs < max_NLP && statsLFP_->numLPs < max_LP
        && stats_->numCycles < max_cycle) {
    while(to_continue && statsLFP_->numLPs < max_LP 
        && stats_->numCycles < max_cycle) { 
      sol_found = false;
      constructObj_(r_, sol);
      lp_status = lpE_->solve();
      ++(statsLFP_->numLPs);
      if (!(lp_status == ProvenOptimal || lp_status == ProvenLocalOptimal)) {
        logger_->msgStream(LogDebug) << me_ << "LP relaxation is infeasible." 
          << std::endl;
        return;
      }
      sol         = lpE_->getSolution();
      x_lp        = sol->getPrimal();
      to_continue = isFrac_(x_lp);
      k           = std::max(min_flip, (UInt) ceil(sol->getObjValue()));
      n_to_flip   = std::min(k, p_->getSize()->bins);

      if (!to_continue) {
        is_feasible = qh_->isFeasible(sol, r_, is_prob_infeasible, inf_meas);
        if (is_feasible) {
#if SPEW
          logger_->msgStream(LogDebug) << me_ << "LP soln is feasible "
            << "to NLP" << std::endl;
#endif
          err = 0;
          statsLFP_->bestObjValue = p_->getObjective()->eval(x_lp, &err);
          convertSol_(s_pool, sol);
          sol_found = true;
        } else {
#if SPEW
          logger_->msgStream(LogDebug) << me_ << "LP soln is not feasible "
            << "to NLP." << std::endl;
#endif
        }
        break;
      }
      hash_val = hash_();
      if (cycle_(hash_val)) {
        perturb_(hash_val, n_to_flip);
      }
    } 
    if (!to_continue) {
      if (false==sol_found) {
        ++(stats_->numNLPs);
        qh_->separate(sol, node, r_, 0, s_pool, &sol_found, &sep_status);
        to_continue = true; //reset to continue after separating
#if SPEW
        logger_->msgStream(LogDebug) << me_ << "separation status = " 
          << sep_status << std::endl;
        //r_->write(logger_->msgStream(LogDebug));
        logger_->msgStream(LogDebug) << me_ << 
          "sol_found = " << sol_found << std::endl;
#endif
        if (SepaError==sep_status) {
          break; //exit pump
        }
        if (sol_found) {
          is_feasible = true;
        }
      }
    }
    if (is_feasible) {
#if SPEW
      logger_->msgStream(LogInfo) << me_ << "best solution value = " 
        << s_pool->getBestSolutionValue() << std::endl;
#endif
      if (getSolGap_(f_nlp, s_pool->getBestSolutionValue()) > 10 && 
          true==should_separate) {
        separatingCut_(f_nlp, s_pool);
        is_feasible = false;
      } else {
        break;
      }
    }
  }
  e_->setOptionsForRepeatedSolve();
}
Пример #10
0
void ParQGHandler::cutIntSol_(ConstSolutionPtr sol, CutManager *cutMan,
                           SolutionPoolPtr s_pool, bool *sol_found,
                           SeparationStatus *status)
{
  double nlpval = INFINITY;
  const double *lpx = sol->getPrimal(), *nlpx;
  relobj_ = (sol) ? sol->getObjValue() : -INFINITY;

  fixInts_(lpx);           // Fix integer variables
  solveNLP_();
  unfixInts_();            // Unfix integer variables
  switch(nlpStatus_) {
  case (ProvenOptimal):
  case (ProvenLocalOptimal):
    ++(stats_->nlpF);
    updateUb_(s_pool, &nlpval, sol_found);
    if ((relobj_ >= nlpval-npATol_) ||
        (nlpval != 0 && (relobj_ >= nlpval-fabs(nlpval)*npRTol_))) {
        *status = SepaPrune;
        break;
    } else {
      nlpx = nlpe_->getSolution()->getPrimal();
      oaCutToCons_(nlpx, lpx, cutMan, status);
      oaCutToObj_(nlpx, lpx, cutMan, status);
      break;
    }
  case (ProvenInfeasible):
  case (ProvenLocalInfeasible):
  case (ProvenObjectiveCutOff):
    ++(stats_->nlpI);
    nlpx = nlpe_->getSolution()->getPrimal();
    oaCutToCons_(nlpx, lpx, cutMan, status);
    break;
  case (EngineIterationLimit):
    ++(stats_->nlpIL);
    oaCutEngLim_(lpx, cutMan, status);
    break;
  case (FailedFeas):
  case (EngineError):
  case (FailedInfeas):
  case (ProvenUnbounded):
  case (ProvenFailedCQFeas):
  case (EngineUnknownStatus):
  case (ProvenFailedCQInfeas):
  default:
    logger_->msgStream(LogError) << me_ << "NLP engine status = "
      << nlpe_->getStatusString() << std::endl;
    logger_->msgStream(LogError)<< me_ << "No cut generated, may cycle!"
      << std::endl;
    *status = SepaError;
  }

 if (*status==SepaContinue) {
   // No linearizations are generated so prune the node
   *status = SepaPrune;
 }

#if SPEW
  logger_->msgStream(LogDebug) << me_ << "NLP solve status = "
    << nlpe_->getStatusString() << " and separation status = " << *status <<
    std::endl;
#endif
  return;
}