1 // ******************** FlopCpp ********************************************** 2 // File: MP_model.hpp 3 // $Id$ 4 // Author: Tim Helge Hultberg (thh@mat.ua.pt) 5 // Copyright (C) 2003 Tim Helge Hultberg 6 // All Rights Reserved. 7 // **************************************************************************** 8 9 #ifndef _MP_model_hpp_ 10 #define _MP_model_hpp_ 11 12 #include <ostream> 13 #include <vector> 14 #include <set> 15 #include <string> 16 17 #include "MP_expression.hpp" 18 #include "MP_constraint.hpp" 19 #include <CoinPackedVector.hpp> 20 class OsiSolverInterface; 21 22 namespace flopc { 23 24 class MP_variable; 25 class MP_index; 26 class MP_set; 27 28 /** @brief Inteface for hooking up to internal flopc++ message handling. 29 @ingroup PublicInterface 30 In more advanced use of FlopC++, it may be desirable to get access to 31 internal calls for messages. In essence, sub-class this Messenger 32 class, and register it with the MP_model. Also overload whichever 33 message events you wish to handle. 34 */ 35 class Messenger { 36 public: logMessage(int level,const char * const msg)37 virtual void logMessage(int level, const char * const msg){} 38 friend class MP_model; 39 private: constraintDebug(std::string name,const std::vector<Coef> & cfs)40 virtual void constraintDebug(std::string name, const std::vector<Coef>& cfs) {} objectiveDebug(const std::vector<Coef> & cfs)41 virtual void objectiveDebug(const std::vector<Coef>& cfs) {} statistics(int bm,int m,int bn,int n,int nz)42 virtual void statistics(int bm, int m, int bn, int n, int nz) {} generationTime(double t)43 virtual void generationTime(double t) {} 44 protected: ~Messenger()45 virtual ~Messenger() {} 46 }; 47 48 /** Internal use: used when Normal output is selected. Uses cout. 49 @ingroup INTERNAL_USE 50 */ 51 class NormalMessenger : public Messenger { 52 friend class MP_model; 53 private: 54 virtual void statistics(int bm, int m, int bn, int n, int nz); 55 virtual void generationTime(double t); 56 }; 57 58 /** Internal use: used when Verbose output is selected. Uses cout. 59 @ingroup INTERNAL_USE 60 */ 61 class VerboseMessenger : public NormalMessenger { 62 friend class MP_model; 63 private: 64 virtual void constraintDebug(std::string name, const std::vector<Coef>& cfs); 65 virtual void objectiveDebug(const std::vector<Coef>& cfs); 66 }; 67 68 /** @brief This is the anchor point for all constructs in a FlopC++ model. 69 @ingroup PublicInterface 70 The constructors take an OsiSolverInterface, and (optionally) a 71 replacemente for the Messenger class. 72 There are some built-in changes to the verbosity for output. 73 <br> 74 The main methods to use are: 75 @li add(MP_constraint & c) 76 @li add(MP_variable* v) 77 @li maximize() and minimize() 78 <br> 79 The main ideas are to construct a model, construct domains where 80 things are defined over, then construct variables, constraints, and 81 add them in. Finally, one attaches data and the model is "complete". 82 Then minimize is called, the model is attached and the 83 OsiSolverInterface is called. 84 @note There are variations on adding objectives and maximize/minimize 85 @see verbose() 86 @see silent(). 87 @see Messenger 88 */ 89 class MP_model { 90 friend class MP_constraint; 91 public: 92 /// used when calling the solve() method. 93 typedef enum {MINIMIZE=1, MAXIMIZE=-1} MP_direction; 94 95 /** @brief Reflects the state of the solution from solve() 96 */ 97 typedef enum { 98 /// if the solve method is called and the optimal solution found. 99 OPTIMAL, 100 /// if solve is called and solver finds model primal infeasible. 101 PRIMAL_INFEASIBLE, 102 /// if solve is called and solver finds the model dual infeasible. 103 DUAL_INFEASIBLE, 104 /// if solve is called and solver abandons the problem 105 /// (time?, iter limit?) 106 ABANDONED, 107 /// A solver is placed in the constructor, 108 /// but it is not yet attached or solved. 109 SOLVER_ONLY, 110 /// A solver is attached, but not yet solved 111 ATTACHED, 112 /// No solver is attached. 113 DETACHED 114 } MP_status; 115 116 /// Constructs an MP_model from an OsiSolverInterface *. 117 MP_model(OsiSolverInterface* s, Messenger* m = new NormalMessenger); 118 ~MP_model()119 ~MP_model() { 120 delete messenger; 121 } 122 123 /** @brief Returns the current status of the model-solver interaction. 124 This method will return the current understanding of the model in 125 regard to the solver's state. 126 @note It is not kept up to date if a call is made directly to the 127 solver. Only if the MP_model interface is used. 128 @see MP_status 129 */ getStatus() const130 MP_status getStatus()const { 131 return mSolverState; 132 } 133 /// used to silence FlopC++ silent()134 void silent() { 135 delete messenger; 136 messenger = new Messenger; 137 } 138 /// used to help understanding and debugging FlopC++'s behavior. verbose()139 void verbose() { 140 delete messenger; 141 messenger = new VerboseMessenger; 142 } 143 144 /// allows for replacement of the solver used. setSolver(OsiSolverInterface * s)145 void setSolver(OsiSolverInterface* s) { 146 Solver = s; 147 } 148 149 /// allows access to the OsiSolverInterface * operator ->()150 OsiSolverInterface* operator->() { 151 return Solver; 152 } 153 154 /// Adds a constrataint block to the model. 155 MP_model& add(MP_constraint& c); 156 157 /** Binds the data and calls the solver to maximize the current 158 objective expression 159 */ 160 void maximize(); 161 /** Binds the data and calls the solver to maximize the parameter obj 162 objective expression 163 */ 164 void maximize(const MP_expression &obj); 165 /** Binds the data and calls the solver to minimize the current 166 objective expression 167 */ 168 void minimize(); 169 /** Binds the data and calls the solver to minimize the parameter obj 170 objective expression 171 */ 172 void minimize(const MP_expression &obj); 173 174 /** Binds the data and calls the solver to minimize maximum value of 175 the parameter obj objective expression 176 */ 177 void minimize_max(MP_set& d, const MP_expression &obj); 178 179 /// sets the "current objective" to the parameter o 180 void setObjective(const MP_expression& o); 181 /** @brief attaches the symantic representation of a model and data to 182 a particular OsiSolverInterface 183 @note this is called as a part of minimize(), maximize(), and 184 minimize_max(); 185 This takes the symantic representation of the model, generates 186 coefficients for the matrices and 187 adds them into the OsiSolverInterface. The OsiSolverInterface may 188 be specified at construction time, 189 or as late as the call to attach() 190 */ 191 void attach(OsiSolverInterface *solver=NULL); 192 /** @brief detaches an OsiSolverInterface object from the model. 193 In essence, this will clean up any intermediate storage. A model 194 may then be attached to another solverInterface. 195 @note a solver may only be attached to one solver at a time 196 @todo verify that on "attach", old solver is detached. 197 */ 198 void detach(); 199 /** calls the appropriate solving methods in the OsiSolverInterface. 200 @note this is called as a part of minimize(), maximize(), and 201 minimize_max() 202 It expects that the object function is already set and only the 203 direction is to be specified. 204 @todo should the direction be defaulted? 205 */ 206 MP_model::MP_status solve(const MP_model::MP_direction &dir); 207 /** Accessors for the results after a call to maximize()/minimize() 208 @todo should these be private with accessors? What if not set yet? 209 @todo what if not a complete result? What if only one LP in the IP? 210 */ 211 const double* solution; 212 const double* reducedCost; 213 const double* rowPrice; 214 const double* rowActivity; 215 /** Useful for getting an appropriate value to pass in as "infinity" 216 @note some solvers may be more or less sensitive to the value. 217 */ 218 double getInfinity() const; 219 220 /// Adds a variable to the MP_model. 221 void add(MP_variable* v); 222 /// Adds a constraint to the MP_model 223 void addRow(const Constraint& c); 224 225 /** Can be used to get the default model 226 @todo explain the default and current model concepts. 227 */ 228 static MP_model &getDefaultModel(); 229 /** Can be used to get the current model 230 @todo explain the default and current model concepts. 231 */ 232 static MP_model *getCurrentModel(); 233 /** Gets the current messenger. 234 */ getMessenger()235 Messenger *getMessenger(){ 236 return messenger; 237 } 238 private: 239 typedef std::set<MP_variable* >::iterator varIt; 240 typedef std::set<MP_constraint* >::iterator conIt; 241 static MP_model& default_model; 242 static MP_model* current_model; 243 MP_model(const MP_model&); 244 MP_model& operator=(const MP_model&); 245 246 Messenger* messenger; 247 248 249 static void assemble(std::vector<Coef>& v, std::vector<Coef>& av); 250 void add(MP_constraint* c); 251 MP_expression Objective; 252 std::set<MP_constraint *> Constraints; 253 std::set<MP_variable *> Variables; 254 public: 255 /// @todo should this be private? 256 OsiSolverInterface* Solver; 257 private: 258 int m; 259 int n; 260 int nz; 261 int *Cst; 262 int *Clg; 263 int *Rnr; 264 double *Elm; 265 double *bl; 266 double *bu; 267 double *c; 268 double *l; 269 double *u; 270 MP_status mSolverState; 271 }; 272 273 /// allows print of result from call to solve(); 274 std::ostream &operator<<(std::ostream &os, 275 const MP_model::MP_status &condition); 276 /// allows print of direction used when calling solve. (MIN/MAX) 277 std::ostream &operator<<(std::ostream &os, 278 const MP_model::MP_direction &direction); 279 280 } // End of namespace flopc 281 #endif 282