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