// ******************** FlopCpp ********************************************** // File: MP_model.hpp // **************************************************************************** #ifndef _MP_model_hpp_ #define _MP_model_hpp_ #include #include #include #include #include #include // This is necessary for PFunc and windows, so do a #ifdef around it //#include //#include #include "MP_expression.hpp" #include "MP_constraint.hpp" #include "MP_random_data.hpp" using std::vector; using std::set; class OsiSolverInterface; //Forward declarations for generateScenarioTree and private variable declaration class SmiCoreData; class SmiScnModel; namespace flopc { /* Library instance description */ //typedef ::pfunc::generator my_pfunc; /*function object*/ // forward declarations class MP_variable; class MP_index; class MP_set; struct Uniform01Generator; // Forward declaration for googletest class MP_modelTest; /** @brief Inteface for hooking up to internal flopc++ message handling. @ingroup PublicInterface In more advanced use of FlopC++, it may be desirable to get access to internal calls for messages. In essence, sub-class this Messenger class, and register it with the MP_model. Also overload whichever message events you wish to handle. */ class Messenger { public: virtual void logMessage(int level, const char * const msg); friend class MP_model; private: virtual void constraintDebug(string name, const vector& cfs) const; virtual void objectiveDebug(const vector& cfs) const; virtual void solutionStatus(const OsiSolverInterface* Solver); virtual void statistics(int bm, int m, int bn, int n, int nz); virtual void generationTime(double t); protected: virtual ~Messenger() {} }; /** Internal use: used when Normal output is selected. Uses cout. @ingroup INTERNAL_USE */ class NormalMessenger : public Messenger { friend class MP_model; private: virtual void statistics(int bm, int m, int bn, int n, int nz); virtual void generationTime(double t); virtual void solutionStatus(const OsiSolverInterface* Solver); }; /** Internal use: used when Verbose output is selected. Uses cout. @ingroup INTERNAL_USE */ class VerboseMessenger : public NormalMessenger { friend class MP_model; private: virtual void constraintDebug(string name, const vector& cfs) const; virtual void objectiveDebug(const vector& cfs) const; }; /** @brief This is the anchor point for all constructs in a FlopC++ model. @ingroup PublicInterface The constructors take an OsiSolverInterface, and (optionally) a replacemente for the Messenger class. There are some built-in changes to the verbosity for output.
The main methods to use are: @li add(MP_constraint & c) @li add(MP_variable* v) @li maximize() and minimize()
The main ideas are to construct a model, construct domains where things are defined over, then construct variables, constraints, and add them in. Finally, one attaches data and the model is "complete". Then minimize is called, the model is attached and the OsiSolverInterface is called. @note There are variations on adding objectives and maximize/minimize @see verbose() @see silent(). @see Messenger */ class MP_model { friend class MP_constraint; friend class MP_variable; //For testing purposes friend class MP_modelTest; public: /// used when calling the solve() method. typedef enum {MINIMIZE=1, MAXIMIZE=-1} MP_direction; /** @brief Reflects the state of the solution from solve() */ typedef enum { /// if the solve method is called and the optimal solution found. OPTIMAL, /// if solve is called and solver finds model primal infeasible. PRIMAL_INFEASIBLE, /// if solve is called and solver finds the model dual infeasible. DUAL_INFEASIBLE, /// if solve is called and solver abandons the problem /// (time?, iter limit?) ABANDONED, /// A solver is placed in the constructor, /// but it is not yet attached or solved. SOLVER_ONLY, /// A solver is attached, but not yet solved ATTACHED, /// No solver is attached. DETACHED } MP_status; static const std::string stageString; /// Constructs an MP_model from an OsiSolverInterface *. MP_model(OsiSolverInterface* s, Messenger* m = new NormalMessenger, unsigned int seed = 0); ~MP_model(); /** @brief Returns the current status of the model-solver interaction. This method will return the current understanding of the model in regard to the solver's state. @note It is not kept up to date if a call is made directly to the solver. Only if the MP_model interface is used. @see MP_status */ MP_status getStatus()const { return mSolverState; } /// used to silence FlopC++ void silent() { delete messenger; messenger = new Messenger; } /// used to help understanding and debugging FlopC++'s behavior. void verbose() { delete messenger; messenger = new VerboseMessenger; } /// allows for replacement of the solver used. void setSolver(OsiSolverInterface* s) { Solver = s; } /// allows access to the OsiSolverInterface * OsiSolverInterface* operator->() { return Solver; } const OsiSolverInterface* operator->() const { return Solver; } /// Adds a constrataint block to the model. MP_model& add(MP_constraint& constraint); /** Binds the data and calls the solver to maximize the current objective expression */ void maximize(); /** Binds the data and calls the solver to maximize the parameter obj objective expression */ void maximize(const MP_expression &obj); /** Binds the data and calls the solver to minimize the current objective expression */ void minimize(); /** Binds the data and calls the solver to minimize the parameter obj objective expression */ void minimize(const MP_expression &obj); /** Binds the data and calls the solver to minimize maximum value of the parameter obj objective expression */ void minimize_max(MP_set& d, const MP_expression &obj); /// sets the "current objective" to the parameter o void setObjective(const MP_expression& o); /** @brief attaches the symantic representation of a model and data to a particular OsiSolverInterface @note this is called as a part of minimize(), maximize(), and minimize_max(); This takes the symantic representation of the model, generates coefficients for the matrices and adds them into the OsiSolverInterface. The OsiSolverInterface may be specified at construction time, or as late as the call to attach() */ void attach(OsiSolverInterface *solver = 0); /** @brief detaches an OsiSolverInterface object from the model. In essence, this will clean up any intermediate storage. A model may then be attached to another solverInterface. @note a solver may only be attached to one solver at a time @todo verify that on "attach", old solver is detached. */ void detach(); void solveWS(); void solveEEV(); /** calls the appropriate solving methods in the OsiSolverInterface. @note this is called as a part of minimize(), maximize(), and minimize_max() It expects that the object function is already set and only the direction is to be specified. @todo should the direction be defaulted? */ int * getRowStage(); int * getColStage(); MP_model::MP_status solve(const MP_model::MP_direction &dir); /** Accessors for the results after a call to maximize()/minimize() @todo should these be private with accessors? What if not set yet? @todo what if not a complete result? What if only one LP in the IP? */ /** Useful for getting an appropriate value to pass in as "infinity" @note some solvers may be more or less sensitive to the value. */ double getInfinity() const; /// Adds a variable to the MP_model. void add(MP_variable* v); /// Adds a constraint to the MP_model void addRow(const Constraint& constraint); /** Can be used to get the default model @todo explain the default and current model concepts. */ static MP_model &getDefaultModel(); /** Can be used to get the current model @todo explain the default and current model concepts. */ static MP_model *getCurrentModel(); /** Gets the current messenger. */ Messenger *getMessenger(){ return messenger; } MP_stage getStage() const { return stage; } void setStage(const MP_stage& val) { stage = val; } MP_scenario_set getScenSet() const { return scenSet; } void setScenSet(const flopc::MP_scenario_set& val) { scenSet = val; } void setProbabilities(const MP_data& prob); std::vector getProbabilities(); //////////////////////////////////////////////////////////////////////////////////////////////////// /// @fn void SampleSize(int val) /// /// @brief Sample size. /// /// @author Wolf /// @date 21.05.2010 /// /// @param val The value. //////////////////////////////////////////////////////////////////////////////////////////////////// void setSampleSize(int val) { defaultSampleSize = val; }; int getSampleSize() { return defaultSampleSize; }; //////////////////////////////////////////////////////////////////////////////////////////////////// /// @fn void setSampleOnlyScenarioGeneration(bool sampleOnly, int sampleSize = 0) /// /// @brief Sets a sample only scenario generation process. No recombining of the sampled values is done. Therefore a default sample size for all random /// variables is necessary. /// /// @author Wolf /// @date 21.05.2010 /// /// @param sampleOnly true to sample only. /// @param sampleSize Size of the sample. //////////////////////////////////////////////////////////////////////////////////////////////////// void setSampleOnlyScenarioGeneration(bool sampleOnly, int sampleSize ) { this->sampleOnly = sampleOnly; defaultSampleSize = sampleSize; doSample = true; } void setSample(bool sample) { doSample = sample; } bool getSample() { return doSample; } void enableSemanticCheck(bool semanticCheck); bool checkSemantic(); const SmiScnModel* getSmi() const { return smiModel; } SmiScnModel* getSmi() { return smiModel; } OsiSolverInterface* Solver; boost::shared_ptr getUniformGenerator(){ return uniformGenerator; } unsigned int getSeed(); private: typedef std::set::iterator varIt; typedef std::set::iterator conIt; typedef std::set::iterator randomVarIt; static MP_model& default_model; static MP_model* current_model; MP_model(const MP_model&); MP_model& operator=(const MP_model&); //Transfer Coefficients from v to av, build rhs and sort coefficients static void assemble(vector& v, vector< boost::shared_ptr >& av); //count number of constraints and add offests void add(MP_constraint* constraint); void attachStochastic(); //Sample RandomVariates void sampleRandomVariates(std::vector >& rv); SmiScnModel* generateScenarioTree(const std::vector< std::vector > >& randomVariableVector, SmiCoreData* smiCore); //SmiScnModel* generateScenario(MP_model* flopModel, const std::vector< std::vector< flopc::RandomVariable* > >& randomVariableVector, SmiCoreData* smiCore,int scen, int branchStage); bool differFromPrevious(const std::vector > >& randomVariableVector,int curStage,int curScen,int compareScen); Messenger* messenger; MP_stage stage; MP_scenario_set scenSet; MP_expression Objective; // We have sets of MP_variables and MP_constraints, as well as set of RandomVariable's. Is this the most efficient way to handle it? set Constraints; set Variables; std::vector< std::set > RandomVariables; std::vector probabilities; int defaultSampleSize; bool sampleOnly; bool doSample; bool semantic; private: int m; int realm; int n; int realn; int nz; int realnz; int *Cst; int *Clg; int *Rnr; double *Elm; double *bl; double *bu; double *c; double *l; double *u; int *colStage; int *rowStage; int *colIndirection; //Redirect from FlopC++ Variable Index to Index used by Solver (in case of stochastic variables only..) int *rowIndirection; MP_status mSolverState; boost::shared_ptr uniformGenerator; public: //TODO: As long as we have no correct OsiStochasticSolverInterface, this will do SmiScnModel *smiModel; }; /// allows print of result from call to solve(); std::ostream &operator<<(std::ostream &os, const MP_model::MP_status &condition); /// allows print of direction used when calling solve. (MIN/MAX) std::ostream &operator<<(std::ostream &os, const MP_model::MP_direction &direction); std::string printMatrix(CoinPackedMatrix* matrix_,int n, int m, double* clo, double* cup, double* obj, double* rlo, double* rup,int* colStage,int* rowStage); //TODO: Read back solution values // two possibilities: Read back values so they are stored in the variable // Always use values provided by solver. } // End of namespace flopc #endif