// (C) Copyright International Business Machines Corporation, Carnegie Mellon University 2004, 2007 // All Rights Reserved. // This code is published under the Eclipse Public License. // // Authors : // Pierre Bonami, Carnegie Mellon University, // Carl D. Laird, Carnegie Mellon University, // Andreas Waechter, International Business Machines Corporation // // Date : 12/01/2004 #ifndef OsiTMINLPInterface_H #define OsiTMINLPInterface_H #define INT_BIAS 0e-8 #include #include #include "OsiSolverInterface.hpp" #include "CoinWarmStartBasis.hpp" #include "BonCutStrengthener.hpp" //#include "BonRegisteredOptions.hpp" namespace Bonmin { class TMINLP; class TMINLP2TNLP; class TMINLP2OsiLP; class TNLP2FPNLP; class TNLPSolver; class RegisteredOptions; class StrongBranchingSolver; /** Solvers for solving nonlinear programs.*/ enum Solver{ EIpopt=0 /** Ipopt interior point algorithm.*/, EFilterSQP /** filterSQP Sequential Quadratic Programming algorithm.*/, EAll/** Use all solvers.*/ }; /** This is class provides an Osi interface for a Mixed Integer Linear Program expressed as a TMINLP (so that we can use it for example as the continuous solver in Cbc). */ class OsiTMINLPInterface : public OsiSolverInterface { friend class BonminParam; public: //############################################################################# /**Error class to throw exceptions from OsiTMINLPInterface. * Inherited from CoinError, we just want to have a different class to be able to catch * errors thrown by OsiTMINLPInterface. */ class SimpleError : public CoinError { private: SimpleError(); public: ///Alternate constructor using strings SimpleError(std::string message, std::string methodName, std::string f = std::string(), int l = -1) : CoinError(message,methodName,std::string("OsiTMINLPInterface"), f, l) {} } ; #ifdef __LINE__ #define SimpleError(x, y) SimpleError((x), (y), __FILE__, __LINE__) #endif // Error when problem is not solved TNLPSolver::UnsolvedError * newUnsolvedError(int num, Ipopt::SmartPtr problem, std::string name){ return app_->newUnsolvedError(num, problem, name); } //############################################################################# enum WarmStartModes{ None, FakeBasis, Optimum, InteriorPoint}; /** Type of the messages specifically written by OsiTMINLPInterface.*/ enum MessagesTypes{ SOLUTION_FOUND/**found a feasible solution*/, INFEASIBLE_SOLUTION_FOUND/**found an infeasible problem*/, UNSOLVED_PROBLEM_FOUND/**found an unsolved problem*/, WARNING_RESOLVING /** Warn that a problem is resolved*/, WARN_SUCCESS_WS/** Problem not solved with warm start but solved without*/, WARN_SUCCESS_RANDOM/** Subproblem not solve with warm start but solved with random point*/, WARN_CONTINUING_ON_FAILURE/** a failure occured but is continuing*/, SUSPECT_PROBLEM/** Output the number of the problem.*/, SUSPECT_PROBLEM2/** Output the number of the problem.*/, IPOPT_SUMMARY /** Output summary statistics on Ipopt solution.*/, BETTER_SOL /** Found a better solution with random values.*/, LOG_HEAD/** Head of "civilized" log.*/, LOG_FIRST_LINE/** First line (first solve) of log.*/, LOG_LINE/**standard line (retry solving) of log.*/, ALTERNATE_OBJECTIVE/** Recomputed integer feasible with alternate objective function*/, WARN_RESOLVE_BEFORE_INITIAL_SOLVE /** resolve() has been called but there was no previous call to initialSolve(). */, ERROR_NO_TNLPSOLVER /** Trying to access non-existent TNLPSolver*/, WARNING_NON_CONVEX_OA /** Warn that there are equality or ranged constraints and OA may works bad.*/, SOLVER_DISAGREE_STATUS /** Different solver gives different status for problem.*/, SOLVER_DISAGREE_VALUE /** Different solver gives different optimal value for problem.*/, OSITMINLPINTERFACE_DUMMY_END }; //############################################################################# /** Messages written by an OsiTMINLPInterface. */ class Messages : public CoinMessages { public: /// Constructor Messages(); }; //############################################################################# /**@name Constructors and destructors */ //@{ /// Default Constructor OsiTMINLPInterface(); /** Facilitator to initialize interface. */ void initialize(Ipopt::SmartPtr roptions, Ipopt::SmartPtr options, Ipopt::SmartPtr journalist, const std::string & prefix, Ipopt::SmartPtr tminlp); /** Facilitator to initialize interface. */ void initialize(Ipopt::SmartPtr roptions, Ipopt::SmartPtr options, Ipopt::SmartPtr journalist, Ipopt::SmartPtr tminlp){ initialize(roptions, options, journalist, "bonmin.", tminlp); } /** Set the model to be solved by interface.*/ void setModel(Ipopt::SmartPtr tminlp); /** Set the solver to be used by interface.*/ void setSolver(Ipopt::SmartPtr app); /** Sets the TMINLP2TNLP to be used by the interface.*/ void use(Ipopt::SmartPtr tminlp2tnlp); /** Copy constructor */ OsiTMINLPInterface (const OsiTMINLPInterface &); /** Virtual copy constructor */ OsiSolverInterface * clone(bool copyData = true) const; /// Assignment operator OsiTMINLPInterface & operator=(const OsiTMINLPInterface& rhs); /// Destructor virtual ~OsiTMINLPInterface (); /// Read parameter file void readOptionFile(const std::string & fileName); /// Retrieve OsiTMINLPApplication option list const Ipopt::SmartPtr options() const; /// Retrieve OsiTMINLPApplication option list Ipopt::SmartPtr options(); const char * prefix() const{ if(!IsValid(app_)) { messageHandler()->message(ERROR_NO_TNLPSOLVER, messages_)<prefix(); } //@} //--------------------------------------------------------------------------- /**@name Solve methods */ //@{ /// Solve initial continuous relaxation virtual void initialSolve(); /// Solve initial continuous relaxation (precising from where) virtual void initialSolve(const char * whereFrom); /** Resolve the continuous relaxation after problem modification. initialSolve may or may not have been called before this is called. In any case, this must solve the problem, and speed the process up if it can reuse any remnants of data that might exist from a previous solve. */ virtual void resolve(); /** Resolve the continuous relaxation after problem modification. initialSolve may or may not have been called before this is called. In any case, this must solve the problem, and speed the process up if it can reuse any remnants of data that might exist from a previous solve. */ virtual void resolve(const char * whereFrom); /** Resolve the problem with different random starting points to try to find a better solution (only makes sense for a non-convex problem.*/ virtual void resolveForCost(int numretry, bool keepWs); /** Method to be called when a problem has failed to be solved. Will try to resolve it with different settings. */ virtual void resolveForRobustness(int numretry); /// Nescessary for compatibility with OsiSolverInterface but does nothing. virtual void branchAndBound() { throw SimpleError("Function not implemented for OsiTMINLPInterface","branchAndBound()"); } //@} //--------------------------------------------------------------------------- ///@name Methods returning info on how the solution process terminated //@{ /// Are there a numerical difficulties? virtual bool isAbandoned() const; /// Is optimality proven? virtual bool isProvenOptimal() const; /// Is primal infeasiblity proven? virtual bool isProvenPrimalInfeasible() const; /// Is dual infeasiblity proven? virtual bool isProvenDualInfeasible() const; /// Is the given primal objective limit reached? virtual bool isPrimalObjectiveLimitReached() const; /// Is the given dual objective limit reached? virtual bool isDualObjectiveLimitReached() const; /// Iteration limit reached? virtual bool isIterationLimitReached() const; ///Warn solver that branch-and-bound is continuing after a failure void continuingOnAFailure() { hasContinuedAfterNlpFailure_ = true; } //Added by Claudia double getNewCutoffDecr() { return newCutoffDecr; } void setNewCutoffDecr(double d) { newCutoffDecr = d; } /// Did we continue on a failure bool hasContinuedOnAFailure() { return hasContinuedAfterNlpFailure_; } /// tell to ignore the failures (don't throw, don't fathom, don't report) void ignoreFailures() { pretendFailIsInfeasible_ = 2; } /// Force current solution to be infeasible void forceInfeasible() { problem_->set_obj_value(1e200); } /// Force current solution to be branched on (make it fractionnal with small objective) void forceBranchable() { problem_->set_obj_value(-1e200); problem_->force_fractionnal_sol(); } //@} //--------------------------------------------------------------------------- /**@name Parameter set/get methods The set methods return true if the parameter was set to the given value, false otherwise. There can be various reasons for failure: the given parameter is not applicable for the solver (e.g., refactorization frequency for the clp algorithm), the parameter is not yet implemented for the solver or simply the value of the parameter is out of the range the solver accepts. If a parameter setting call returns false check the details of your solver. The get methods return true if the given parameter is applicable for the solver and is implemented. In this case the value of the parameter is returned in the second argument. Otherwise they return false. */ //@{ // Set an integer parameter bool setIntParam(OsiIntParam key, int value); // Set an double parameter bool setDblParam(OsiDblParam key, double value); // Set a string parameter bool setStrParam(OsiStrParam key, const std::string & value); // Get an integer parameter bool getIntParam(OsiIntParam key, int& value) const; // Get an double parameter bool getDblParam(OsiDblParam key, double& value) const; // Get a string parameter bool getStrParam(OsiStrParam key, std::string& value) const; // Get the push values for starting point inline double getPushFact() const { return pushValue_; } //@} //--------------------------------------------------------------------------- /**@name Problem information methods These methods call the solver's query routines to return information about the problem referred to by the current object. Querying a problem that has no data associated with it result in zeros for the number of rows and columns, and NULL pointers from the methods that return vectors. Const pointers returned from any data-query method are valid as long as the data is unchanged and the solver is not called. */ //@{ /// Get number of columns virtual int getNumCols() const; /// Get number of rows virtual int getNumRows() const; ///get name of variables const OsiSolverInterface::OsiNameVec& getVarNames() ; /// Get pointer to array[getNumCols()] of column lower bounds virtual const double * getColLower() const; /// Get pointer to array[getNumCols()] of column upper bounds virtual const double * getColUpper() const; /** Get pointer to array[getNumRows()] of row constraint senses.
  • 'L': <= constraint
  • 'E': = constraint
  • 'G': >= constraint
  • 'R': ranged constraint
  • 'N': free constraint
*/ virtual const char * getRowSense() const; /** Get pointer to array[getNumRows()] of rows right-hand sides
  • if rowsense()[i] == 'L' then rhs()[i] == rowupper()[i]
  • if rowsense()[i] == 'G' then rhs()[i] == rowlower()[i]
  • if rowsense()[i] == 'R' then rhs()[i] == rowupper()[i]
  • if rowsense()[i] == 'N' then rhs()[i] == 0.0
*/ virtual const double * getRightHandSide() const; /** Get pointer to array[getNumRows()] of row ranges.
  • if rowsense()[i] == 'R' then rowrange()[i] == rowupper()[i] - rowlower()[i]
  • if rowsense()[i] != 'R' then rowrange()[i] is 0.0
*/ virtual const double * getRowRange() const; /// Get pointer to array[getNumRows()] of row lower bounds virtual const double * getRowLower() const; /// Get pointer to array[getNumRows()] of row upper bounds virtual const double * getRowUpper() const; /** Get objective function sense (1 for min (default), -1 for max) * Always minimizes */ virtual double getObjSense() const { return 1; } /// Return true if column is continuous virtual bool isContinuous(int colNumber) const; /// Return true if column is binary virtual bool isBinary(int columnNumber) const; /** Return true if column is integer. Note: This function returns true if the the column is binary or a general integer. */ virtual bool isInteger(int columnNumber) const; /// Return true if column is general integer virtual bool isIntegerNonBinary(int columnNumber) const; /// Return true if column is binary and not fixed at either bound virtual bool isFreeBinary(int columnNumber) const; /// Get solver's value for infinity virtual double getInfinity() const; ///Get priorities on integer variables. const int * getPriorities() const { const TMINLP::BranchingInfo * branch = tminlp_->branchingInfo(); if(branch) return branch->priorities; else return NULL; } ///get prefered branching directions const int * getBranchingDirections() const { const TMINLP::BranchingInfo * branch = tminlp_->branchingInfo(); if(branch) return branch->branchingDirections; else return NULL; } const double * getUpPsCosts() const { const TMINLP::BranchingInfo * branch = tminlp_->branchingInfo(); if(branch) return branch->upPsCosts; else return NULL; } const double * getDownPsCosts() const { const TMINLP::BranchingInfo * branch = tminlp_->branchingInfo(); if(branch) return branch->downPsCosts; else return NULL; } //@} /**@name Methods related to querying the solution */ //@{ /// Get pointer to array[getNumCols()] of primal solution vector virtual const double * getColSolution() const; /// Get pointer to array[getNumRows()] of dual prices virtual const double * getRowPrice() const; /// Get a pointer to array[getNumCols()] of reduced costs virtual const double * getReducedCost() const; /** Get pointer to array[getNumRows()] of row activity levels (constraint matrix times the solution vector */ virtual const double * getRowActivity() const; /** Get how many iterations it took to solve the problem (whatever "iteration" mean to the solver. * \todo Figure out what it could mean for Ipopt. */ virtual int getIterationCount() const; /** get total number of calls to solve.*/ int nCallOptimizeTNLP() { return nCallOptimizeTNLP_; } /** get total time taken to solve NLP's. */ double totalNlpSolveTime() { return totalNlpSolveTime_; } /** get total number of iterations */ int totalIterations() { return totalIterations_; } //@} //------------------------------------------------------------------------- /**@name Methods to modify the objective, bounds, and solution */ //@{ /** Set a single column lower bound. Use -getInfinity() for -infinity. */ virtual void setColLower( int elementIndex, double elementValue ); /** Set a single column upper bound. Use getInfinity() for infinity. */ virtual void setColUpper( int elementIndex, double elementValue ); /** Set the lower bounds for all columns array [getNumCols()] is an array of values for the objective. */ virtual void setColLower(const double * array); /** Set the upper bounds for all columns array [getNumCols()] is an array of values for the objective. */ virtual void setColUpper(const double * array); /** Set a single row lower bound. Use -getInfinity() for -infinity. */ virtual void setRowLower( int elementIndex, double elementValue ); /** Set a single row upper bound. Use getInfinity() for infinity. */ virtual void setRowUpper( int elementIndex, double elementValue ); /** Set the type of a single row */ virtual void setRowType(int index, char sense, double rightHandSide, double range); /** \brief Set the objective function sense (disabled). * (1 for min (default), -1 for max) \todo Make it work. \bug Can not treat maximisation problems. */ virtual void setObjSense(double s); /** Set the primal solution variable values Set the values for the starting point. \warning getColSolution will never return this vector (unless it is optimal). */ virtual void setColSolution(const double *colsol); /** Set dual solution variable values. set the values for the starting point. \warning getRowPrice will never return this vector (unless it is optimal). */ virtual void setRowPrice(const double * rowprice); //@} //--------------------------------------------------------------------------- /**@name WarmStart related methods (those should really do nothing for the moment)*/ //@{ /*! \brief Get an empty warm start object This routine returns an empty CoinWarmStartBasis object. Its purpose is to provide a way to give a client a warm start basis object of the appropriate type, which can resized and modified as desired. */ virtual CoinWarmStart *getEmptyWarmStart () const; /** Get warmstarting information */ virtual CoinWarmStart* getWarmStart() const; /** Set warmstarting information. Return true/false depending on whether the warmstart information was accepted or not. */ virtual bool setWarmStart(const CoinWarmStart* warmstart); void setWarmStartMode(int mode) { warmStartMode_ = (WarmStartModes) mode; } WarmStartModes getWarmStartMode() { return warmStartMode_; } void randomStartingPoint(); //Returns true if a basis is available virtual bool basisIsAvailable() const { // Throw an exception throw SimpleError("Needs coding for this interface", "basisIsAvailable"); } //@} //------------------------------------------------------------------------- /**@name Methods to set variable type */ //@{ /** Set the index-th variable to be a continuous variable */ virtual void setContinuous(int index); /** Set the index-th variable to be an integer variable */ virtual void setInteger(int index); //@} //Set numIterationSuspect_ void setNumIterationSuspect(int value) { numIterationSuspect_ = value; } /**@name Dummy functions * Functions which have to be implemented in an OsiSolverInterface, * but which do not do anything (but throwing exceptions) here in the case of a * minlp solved using an nlp solver for continuous relaxations */ //@{ /** Cbc will understand that no matrix exsits if return -1 */ virtual int getNumElements() const { return -1; } /** This returns the objective function gradient at the current * point. It seems to be required for Cbc's pseudo cost * initialization */ virtual const double * getObjCoefficients() const; /** We have to keep this but it will return NULL. */ virtual const CoinPackedMatrix * getMatrixByRow() const { return NULL; } /** We have to keep this but it will return NULL. */ virtual const CoinPackedMatrix * getMatrixByCol() const { return NULL; } /** We have to keep this but it will throw an error. */ virtual void setObjCoeff( int elementIndex, double elementValue ) { throw SimpleError("OsiTMINLPInterface does not implement this function.", "setObjCoeff"); } /** We have to keep this but it will throw an error. */ virtual void addCol(const CoinPackedVectorBase& vec, const double collb, const double colub, const double obj) { throw SimpleError("OsiTMINLPInterface does not implement this function.", "addCol"); } /** We have to keep this but it will throw an error. */ virtual void deleteCols(const int num, const int * colIndices) { throw SimpleError("OsiTMINLPInterface does not implement this function.", "deleteCols"); } /** We have to keep this but it will throw an error. */ virtual void addRow(const CoinPackedVectorBase& vec, const double rowlb, const double rowub) { throw SimpleError("OsiTMINLPInterface does not implement this function.", "addRow"); } /** We have to keep this but it will throw an error. */ virtual void addRow(const CoinPackedVectorBase& vec, const char rowsen, const double rowrhs, const double rowrng) { throw SimpleError("OsiTMINLPInterface model does not implement this function.", "addRow"); } /** We have to keep this but it will throw an error. */ virtual void deleteRows(const int num, const int * rowIndices) { if(num) freeCachedRowRim(); problem_->removeCuts(num, rowIndices); } /** We have to keep this but it will throw an error */ virtual void loadProblem(const CoinPackedMatrix& matrix, const double* collb, const double* colub, const double* obj, const double* rowlb, const double* rowub) { throw SimpleError("OsiTMINLPInterface does not implement this function.", "loadProblem"); } /** We have to keep this but it will throw an error. */ virtual void assignProblem(CoinPackedMatrix*& matrix, double*& collb, double*& colub, double*& obj, double*& rowlb, double*& rowub) { throw SimpleError("OsiTMINLPInterface does not implement this function.", "assignProblem"); } /** We have to keep this but it will throw an error. */ virtual void loadProblem(const CoinPackedMatrix& matrix, const double* collb, const double* colub, const double* obj, const char* rowsen, const double* rowrhs, const double* rowrng) { throw SimpleError("OsiTMINLPInterface does not implement this function.", "loadProblem"); } /** We have to keep this but it will throw an error. */ virtual void assignProblem(CoinPackedMatrix*& matrix, double*& collb, double*& colub, double*& obj, char*& rowsen, double*& rowrhs, double*& rowrng) { throw SimpleError("OsiTMINLPInterface does not implement this function.", "assignProblem"); } /** We have to keep this but it will throw an error. */ virtual void loadProblem(const int numcols, const int numrows, const int* start, const int* index, const double* value, const double* collb, const double* colub, const double* obj, const double* rowlb, const double* rowub) { throw SimpleError("OsiTMINLPInterface does not implement this function.", "loadProblem"); } /** We have to keep this but it will throw an error. */ virtual void loadProblem(const int numcols, const int numrows, const int* start, const int* index, const double* value, const double* collb, const double* colub, const double* obj, const char* rowsen, const double* rowrhs, const double* rowrng) { throw SimpleError("OsiTMINLPInterface model does not implement this function.", "loadProblem"); } /** We have to keep this but it will throw an error. */ virtual int readMps(const char *filename, const char *extension = "mps") { throw SimpleError("OsiTMINLPInterface does not implement this function.", "readMps"); } /** We have to keep this but it will throw an error. */ virtual void writeMps(const char *filename, const char *extension = "mps", double objSense=0.0) const { throw SimpleError("OsiTMINLPInterface does not implement this function.", "writeMps"); } /** Throws an error */ virtual std::vector getDualRays(int maxNumRays, bool fullRay = false) const { throw SimpleError("OsiTMINLPInterface does not implement this function.", "getDualRays"); } /** Throws an error */ virtual std::vector getPrimalRays(int maxNumRays) const { throw SimpleError("OsiTMINLPInterface does not implement this function.", "getPrimalRays"); } //@} //--------------------------------------------------------------------------- /**@name Control of Ipopt output */ //@{ void setSolverOutputToDefault(){ app_->setOutputToDefault();} void forceSolverOutput(int log_level){ app_->forceSolverOutput(log_level);} //@} /**@name Sets and Getss */ //@{ /// Get objective function value (can't use default) virtual double getObjValue() const; //@} /** get pointer to the TMINLP2TNLP adapter */ const TMINLP2TNLP * problem() const { return GetRawPtr(problem_); } TMINLP2TNLP * problem() { return GetRawPtr(problem_); } const TMINLP * model() const { return GetRawPtr(tminlp_); } Bonmin::TMINLP * model() { return GetRawPtr(tminlp_); } const Bonmin::TNLPSolver * solver() const { return GetRawPtr(app_); } const std::list >& debug_apps() const{ return debug_apps_; } TNLPSolver * solver() { return GetRawPtr(app_); } /** \name Methods to build outer approximations */ //@{ /** \name Methods to build outer approximations */ //@{ /** \brief Extract a linear relaxation of the MINLP. * Use user-provided point to build first-order outer-approximation constraints at the optimum. * And put it in an OsiSolverInterface. */ virtual void extractLinearRelaxation(OsiSolverInterface &si, const double *x, bool getObj = 1); /** Add constraint corresponding to objective function.*/ virtual void addObjectiveFunction(OsiSolverInterface &si, const double * x); #if 1 /** \brief Extract a linear relaxation of the MINLP. * Solve the continuous relaxation and takes first-order outer-approximation constraints at the optimum. * The put everything in an OsiSolverInterface. */ virtual void extractLinearRelaxation(OsiSolverInterface &si, bool getObj = 1, bool solveNlp = 1){ if(solveNlp) initialSolve("build initial OA"); extractLinearRelaxation(si, getColSolution(), getObj); if(solveNlp){ app_->enableWarmStart(); setColSolution(problem()->x_sol()); setRowPrice(problem()->duals_sol()); } } #endif /** Get the outer approximation constraints at the current optimal point. If x2 is different from NULL only add cuts violated by x2. (Only get outer-approximations of nonlinear constraints of the problem.)*/ void getOuterApproximation(OsiCuts &cs, int getObj, const double * x2, bool global) { getOuterApproximation(cs, getColSolution(), getObj, x2, global); } /** Get the outer approximation constraints at provided point. If x2 is different from NULL only add cuts violated by x2. (Only get outer-approximations of nonlinear constraints of the problem.)*/ void getOuterApproximation(OsiCuts &cs, const double * x, int getObj, const double * x2, bool global){ getOuterApproximation(cs, x, getObj, x2, 0., global);} /** Get the outer approximation constraints at provided point. If x2 is different from NULL only add cuts violated by x2 by more than delta. (Only get outer-approximations of nonlinear constraints of the problem.)*/ virtual void getOuterApproximation(OsiCuts &cs, const double * x, int getObj, const double * x2, double theta, bool global); /** Get the outer approximation at provided point for given constraint. */ virtual void getConstraintOuterApproximation(OsiCuts & cs, int constraintNumber, const double * x, const double * x2, bool global); /** Get the outer approximation at current optimal point for given constraint. */ void getConstraintOuterApproximation(OsiCuts & cs, int constraintNumber, const double * x2, bool global){ getConstraintOuterApproximation(cs, constraintNumber, getColSolution(),x2,global); } /** Get a benders cut from solution.*/ void getBendersCut(OsiCuts &cs, bool global); /** Given a point x_bar this solves the problem of finding the point which minimize a convex *combination between the distance to x_bar and the original objective function f(x): * \f$ min a * (\sum\limits_{i=1}^n ||x_{ind[i]} -\overline{x}_i)||_L) + (1 - a)* s *f(x) \f$ * \return Distance between feasibility set a x_bar on components in ind * \param n number of elements in array x_bar and ind * \param s scaling of the original objective. * \param a Combination to take between feasibility and original objective (must be between 0 and 1). * \param L L-norm to use (can be either 1 or 2). */ double solveFeasibilityProblem(size_t n, const double * x_bar, const int* ind, double a, double s, int L); /** Given a point x_bar this solves the problem of finding the point which minimize * the distance to x_bar while satisfying the additional cutoff constraint: * \f$ min \sum\limits_{i=1}^n ||x_{ind[i]} -\overline{x}_i)||_L$ * \return Distance between feasibility set a x_bar on components in ind * \param n number of elements in array x_bar and ind * \param L L-norm to use (can be either 1 or 2). * \param cutoff objective function value of a known integer feasible solution */ double solveFeasibilityProblem(size_t n, const double * x_bar, const int* ind, int L, double cutoff); /** Given a point x_bar setup feasibility problem and switch so that every call to initialSolve or resolve will solve it.*/ void switchToFeasibilityProblem(size_t n, const double * x_bar, const int* ind, double a, double s, int L); /** Given a point x_bar setup feasibility problem and switch so that every call to initialSolve or resolve will solve it. This is to be used in the local branching heuristic */ void switchToFeasibilityProblem(size_t n, const double * x_bar, const int* ind, double rhs_local_branching_constraint); /** switch back to solving original problem.*/ void switchToOriginalProblem(); /** round solution and check its feasibility.*/ void round_and_check(double tolerance, OsiObject ** objects = 0, int nObjects = -1){ if(!problem_->check_solution(objects, nObjects)){ optimizationStatus_ = TNLPSolver::provenInfeasible; } } //@} /** \name output for OA cut generation \todo All OA code here should be moved to a separate class sometime.*/ //@{ /** OA Messages types.*/ enum OaMessagesTypes { CUT_NOT_VIOLATED_ENOUGH = 0/** Says that one cut has been generarted, where from, which is the violation.*/, VIOLATED_OA_CUT_GENERATED/** Cut is not violated enough, give violation.*/, OA_CUT_GENERATED/** Print the cut which has been generated.*/, OA_MESSAGES_DUMMY_END/** Dummy end.*/}; /** Class to store OA Messages.*/ class OaMessages :public CoinMessages{ public: /** Default constructor.*/ OaMessages(); }; /** Like a CoinMessageHandler but can print a cut also.*/ class OaMessageHandler : public CoinMessageHandler{ public: /** Default constructor.*/ OaMessageHandler():CoinMessageHandler(){ } /** Constructor to put to file pointer (fp won't be closed).*/ OaMessageHandler(FILE * fp):CoinMessageHandler(fp){ } /** Destructor.*/ virtual ~OaMessageHandler(){ } /** Copy constructor.*/ OaMessageHandler(const OaMessageHandler &other): CoinMessageHandler(other){} /** Constructor from a regular CoinMessageHandler.*/ OaMessageHandler(const CoinMessageHandler &other): CoinMessageHandler(other){} /** Assignment operator.*/ OaMessageHandler & operator=(const OaMessageHandler &rhs){ CoinMessageHandler::operator=(rhs); return *this;} /** Virtual copy */ virtual CoinMessageHandler* clone() const{ return new OaMessageHandler(*this);} /** print an OsiRowCut.*/ void print(OsiRowCut &row); }; void setOaMessageHandler(const CoinMessageHandler &handler){ delete oaHandler_; oaHandler_ = new OaMessageHandler(handler); } //@} //----------------------------------------------------------------------- /** Apply a collection of cuts. */ virtual ApplyCutsReturnCode applyCuts(const OsiCuts & cs, double effectivenessLb = 0.0){ freeCachedRowRim(); problem_->addCuts(cs); ApplyCutsReturnCode rc; return rc;} /** Add a collection of linear cuts to problem formulation.*/ virtual void applyRowCuts(int numberCuts, const OsiRowCut * cuts); /** Add a collection of linear cuts to the problem formulation */ virtual void applyRowCuts(int numberCuts, const OsiRowCut ** cuts) { if(numberCuts) freeCachedRowRim(); problem_->addCuts(numberCuts, cuts); } /** Get infinity norm of constraint violation for x. Put into obj the objective value of x.*/ double getConstraintsViolation(const double * x, double & obj); /** Get infinity norm of constraint violation for x and error in objective value where obj is the estimated objective value of x.*/ double getNonLinearitiesViolation(const double *x, const double obj); //--------------------------------------------------------------------------- void extractInterfaceParams(); /** To set some application specific defaults. */ virtual void setAppDefaultOptions(Ipopt::SmartPtr Options); /** Register all possible options to Bonmin */ static void registerOptions (Ipopt::SmartPtr roptions); Ipopt::SmartPtr regOptions(){ if(IsValid(app_)) return app_->roptions(); else return NULL; } /** @name Methods related to strong branching */ //@{ /// Set the strong branching solver void SetStrongBrachingSolver(Ipopt::SmartPtr strong_branching_solver); /// Create a hot start snapshot of the optimization process. In our /// case, we initialize the StrongBrachingSolver. virtual void markHotStart(); /// Optimize starting from the hot start snapshot. In our case, we /// call the StrongBranchingSolver to give us an approximate /// solution for the current state of the bounds virtual void solveFromHotStart(); /// Delete the hot start snapshot. In our case we deactivate the /// StrongBrachingSolver. virtual void unmarkHotStart(); //@} /// Get values of tiny_ and very_tiny_ void get_tolerances(double &tiny, double&very_tiny, double &rhsRelax, double &infty){ tiny = tiny_; very_tiny = veryTiny_; rhsRelax = rhsRelax_; infty = infty_; } void set_linearizer(Ipopt::SmartPtr linearizer); Ipopt::SmartPtr linearizer(); protected: //@} enum RandomGenerationType{ uniform =0, perturb=1, perturb_suffix=2}; /// Initialize data structures for storing the jacobian int initializeJacobianArrays(); ///@name Virtual callbacks for application specific stuff //@{ virtual std::string appName() { return "bonmin"; } //@} ///@name Protected methods //@{ /** Call Ipopt to solve or resolve the problem and check for errors.*/ void solveAndCheckErrors(bool doResolve, bool throwOnFailure, const char * whereFrom); /** Add a linear cut to the problem formulation. */ virtual void applyRowCut( const OsiRowCut & rc ) { const OsiRowCut * cut = &rc; problem_->addCuts(1, &cut); } /** We have to keep this but it will throw an error. */ virtual void applyColCut( const OsiColCut & cc ) { throw SimpleError("Ipopt model does not implement this function.", "applyColCut"); } // /** Read the name of the variables in an ampl .col file. */ // void readVarNames() const; //@} /**@name Model and solver */ //@{ /** TMINLP model.*/ Ipopt::SmartPtr tminlp_; /** Adapter for a MINLP to a NLP */ Ipopt::SmartPtr problem_; /** Problem currently optimized (may be problem_ or feasibilityProblem_)*/ Ipopt::SmartPtr problem_to_optimize_; /** Is true if and only if in feasibility mode.*/ bool feasibility_mode_; /** Solver for a TMINLP. */ Ipopt::SmartPtr app_; /** Alternate solvers for TMINLP.*/ std::list > debug_apps_; /** Do we use the other solvers?*/ bool testOthers_; //@} /** Warmstart information for reoptimization */ CoinWarmStart* warmstart_; /**@name Cached information on the problem */ //@{ /** Free cached data relative to variables */ void freeCachedColRim(); /** Free cached data relative to constraints */ void freeCachedRowRim(); /** Free all cached data*/ void freeCachedData(); /** Extract rowsense_ vector rhs_ vector and rowrange_ vector from the lower and upper bounds * on the constraints */ void extractSenseRhsAndRange() const; /// Pointer to dense vector of row sense indicators mutable char *rowsense_; /// Pointer to dense vector of row right-hand side values mutable double *rhs_; /// Pointer to dense vector of slack upper bounds for range constraints (undefined for non-range rows) mutable double *rowrange_; /** Pointer to dense vector of reduced costs \warning Always 0. with Ipopt*/ mutable double *reducedCosts_; /** DualObjectiveLimit is used to store the cutoff in Cbc*/ double OsiDualObjectiveLimit_; /** does the file variable names exists (will check automatically).*/ mutable bool hasVarNamesFile_; //@} /// number of time NLP has been solved int nCallOptimizeTNLP_; /// Total solution time of NLP double totalNlpSolveTime_; /// toatal number of iterations int totalIterations_; /// max radius for random point double maxRandomRadius_; /// Method to pick a random starting point. int randomGenerationType_; /// Maximum perturbation value double max_perturbation_; /// Ipopt value for pushing initial point inside the bounds double pushValue_; /// Number of times problem will be resolved in initialSolve (root node) int numRetryInitial_; /// Number of times problem will be resolved in resolve int numRetryResolve_; /// Number of times infeasible problem will be resolved. int numRetryInfeasibles_; /// Number of times problem will be resolved in case of a failure int numRetryUnsolved_; /// If infeasibility for a problem is less than this, let's be carrefull. It might be feasible double infeasibility_epsilon_; //Added by Claudia /// Dynamic cutOff_ int dynamicCutOff_; /// coeff_var_threshold_ double coeff_var_threshold_; /// first_perc_for_cutoff_decr_ double first_perc_for_cutoff_decr_; /// second_perc_for_cutoff_decr_ double second_perc_for_cutoff_decr_; /** Messages specific to an OsiTMINLPInterface. */ Messages messages_; /** If not 0 when a problem is not solved (failed to be solved) will pretend that it is infeasible. If == 1 will care (i.e. record the fact issue messages to user), if ==2 don't care (somebody else will) */ int pretendFailIsInfeasible_; mutable int pretendSucceededNext_; /** did we ever continue optimization ignoring a failure. */ bool hasContinuedAfterNlpFailure_; /** number iterations above which a problem is considered suspect (-1 is considered \f$+ \infty \f$). If in a call to solve a problem takes more than that number of iterations it will be output to files.*/ int numIterationSuspect_ ; /** Has problem been optimized since last change (include setColSolution). If yes getColSolution will return Ipopt point, otherwise will return initial point.*/ bool hasBeenOptimized_; /** A fake objective function (all variables to 1) to please Cbc pseudo costs initialization. AW: I changed this, it will now be the objective gradient at current point. */ mutable double * obj_; /** flag to say wether options have been printed or not.*/ static bool hasPrintedOptions; /** Adapter for TNLP to a feasibility problem */ Ipopt::SmartPtr feasibilityProblem_; /** Adapter for TMINLP to an Osi LP */ Ipopt::SmartPtr linearizer_; /** \name Arrays to store Jacobian matrix */ //@{ /** Row indices.*/ int * jRow_; /** Column indices.*/ int * jCol_; /** Values */ double * jValues_; /** Number of elements.*/ int nnz_jac; //@} ///Store the types of the constraints (linear and nonlinear). Ipopt::TNLP::LinearityType * constTypes_; /** Number of nonlinear constraint */ int nNonLinear_; /** Value for small non-zero element which we will try to remove cleanly in OA cuts.*/ double tiny_; /** Value for small non-zero element which we will take the risk to ignore in OA cuts.*/ double veryTiny_; /** Amount by which to relax OA constraints RHSes*/ double rhsRelax_; /** Value for infinity. */ double infty_; /** status of last optimization. */ TNLPSolver::ReturnStatus optimizationStatus_; /** Flag indicating if the warm start methods actually do something.*/ WarmStartModes warmStartMode_; /** Is it the first solve (for random starting point at root options).*/ bool firstSolve_; /** Object for strengthening cuts */ Ipopt::SmartPtr cutStrengthener_; /** \name output for OA cut generation \todo All OA code here should be moved to a separate class sometime.*/ //@{ /** OA Messages.*/ OaMessages oaMessages_; /** OA Message handler. */ OaMessageHandler * oaHandler_; //@} double newCutoffDecr; protected: /** Facilitator to create an application. */ void createApplication(Ipopt::SmartPtr roptions, Ipopt::SmartPtr options, Ipopt::SmartPtr journalist, const std::string & prefix); ///Constructor without model only for derived classes OsiTMINLPInterface(Ipopt::SmartPtr app); /** Internal set warm start.*/ bool internal_setWarmStart(const CoinWarmStart* ws); /** internal get warm start.*/ CoinWarmStart* internal_getWarmStart() const; /** Procedure that builds a fake basis. Only tries to make basis consistent with constraints activity.*/ CoinWarmStart* build_fake_basis() const; private: /** solver to be used for all strong branching solves */ Ipopt::SmartPtr strong_branching_solver_; /** status of last optimization before hot start was marked. */ TNLPSolver::ReturnStatus optimizationStatusBeforeHotStart_; static const char * OPT_SYMB; static const char * FAILED_SYMB; static const char * INFEAS_SYMB; static const char * TIME_SYMB; static const char * UNBOUND_SYMB; /** Get status as a char * for log.*/ const char * statusAsString(TNLPSolver::ReturnStatus r){ if(r == TNLPSolver::solvedOptimal || r == TNLPSolver::solvedOptimalTol){ return OPT_SYMB;} else if(r == TNLPSolver::provenInfeasible){ return INFEAS_SYMB;} else if(r == TNLPSolver::unbounded){ return UNBOUND_SYMB;} else if(r == TNLPSolver::timeLimit){ return TIME_SYMB;} else return FAILED_SYMB; } const char * statusAsString(){ return statusAsString(optimizationStatus_);} }; } #endif