lpsolver.h
Go to the documentation of this file.
1 /***************************************************************************
2  * *
3  * Copyright (C) 2007-2012 by Johan De Taeye, frePPLe bvba *
4  * *
5  * This library is free software; you can redistribute it and/or modify it *
6  * under the terms of the GNU Affero General Public License as published *
7  * by the Free Software Foundation; either version 3 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This library is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU Affero General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU Affero General Public *
16  * License along with this program. *
17  * If not, see <http://www.gnu.org/licenses/>. *
18  * *
19  ***************************************************************************/
20 
21 /** @file lpsolver.h
22  * @brief Header file for the module lp_solver.
23  *
24  * @namespace module_lp_solver
25  * @brief A solver module based on a linear programming algorithm.
26  *
27  * The solver is intended primarly for prototyping purposes. Cleaner and
28  * more performant alternatives are recommended for real production use.
29  *
30  * The module uses the "Gnu Linear Programming Kit" library (aka GLPK) to
31  * solve the LP model.<br>
32  * The solver works as follows:
33  * - The solver expects a <b>model file</b> and a <b>data file</b> as input.<br>
34  * The model file represents the mathematical representation of the
35  * problem to solve.<br>
36  * The data file holds the data to be loaded into the problem. If no
37  * data file is specified, the data section in the model file is used
38  * instead.<br>
39  * The user is responsible for creating these files. See the unit test
40  * lp_solver1 for an example.
41  * - The solver solves for a number of objectives in sequence.<br>
42  * After solving an objective's optimal value, the solver freezes the
43  * value as a constraint and start for the next objective. Subsequent
44  * objectives can thus never yield a solution that is suboptimal for the
45  * previous objectives.
46  * - After solving for all objectives the solution is written to a solution
47  * file.<br>
48  * The user is responsible for all processing of this solution file.
49  *
50  * The XML schema extension enabled by this module is (see mod_lpsolver.xsd):
51  * <PRE>
52  * <xsd:complexType name="solver_lp">
53  * <xsd:complexContent>
54  * <xsd:extension base="solver">
55  * <xsd:choice minOccurs="0" maxOccurs="unbounded">
56  * <xsd:element name="loglevel" type="loglevel" />
57  * <xsd:element name="minimum" type="xsd:boolean" />
58  * <xsd:element name="modelfile" type="xsd:normalizedString" />
59  * <xsd:element name="datafile" type="xsd:normalizedString" />
60  * <xsd:element name="solutionfile" type="xsd:normalizedString" />
61  * <xsd:element name="objective" type="xsd:normalizedString" />
62  * </xsd:choice>
63  * <xsd:attribute name="loglevel" type="loglevel" />
64  * <xsd:attribute name="minimum" type="xsd:boolean" />
65  * <xsd:attribute name="modelfile" type="xsd:normalizedString" />
66  * <xsd:attribute name="datafile" type="xsd:normalizedString" />
67  * <xsd:attribute name="solutionfile" type="xsd:normalizedString" />
68  * <xsd:attribute name="objective" type="xsd:normalizedString" />
69  * </xsd:extension>
70  * </xsd:complexContent>
71  * </xsd:complexType>
72  * </PRE>
73  */
74 
75 #include "frepple.h"
76 using namespace frepple;
77 
78 extern "C"
79 {
80 #if defined HAVE_GLPK_H || !defined HAVE_GLPK_GLPK_H
81 #include "glpk.h"
82 #else
83 #ifdef HAVE_GLPK_GLPK_H
84 #include "glpk/glpk.h"
85 #endif
86 #endif
87 }
88 
89 namespace module_lp_solver
90 {
91 
92 /** Initialization routine for the library. */
94 
95 /** @brief This class is a prototype of an Linear Programming (LP) Solver for
96  * the planning problem or a subset of it.
97  *
98  * The solver is intended primarly for prototyping purposes. Cleaner and
99  * more performant alternatives are recommended for real production use.
100  */
101 class LPSolver : public Solver
102 {
103  public:
104  /** This method creates a new column in the model for every demand. It's
105  * value represents the planned quantity of that demand.
106  * @exception DataException Generated when no calendar has been specified.
107  */
108  void solve(void* = NULL);
109 
110  /** Return the name of the GNU MathProg model file. */
111  string getModelFile() const {return modelfilename;}
112 
113  /** Update the name of the GNU MathProg model file. */
114  void setModelFile(const string& c) {modelfilename = c;}
115 
116  /** Return the name of the GNU MathProg data file. */
117  string getDataFile() const {return datafilename;}
118 
119  /** Update the name of the GNU MathProg data file. */
120  void setDataFile(const string& c) {datafilename = c;}
121 
122  /** Return the name of the solution file. */
123  string getSolutionFile() const {return solutionfilename;}
124 
125  /** Update the name of the solution file. <br>
126  * After running the solver the solution is written to this flat file.
127  */
128  void setSolutionFile(const string& c) {solutionfilename = c;}
129 
130  /** Returns true when the solver needs to minimize the objective(s).<br>
131  * Returns false when the solver needs to maximize the objective(s).
132  */
133  bool getMinimum() const {return minimum;}
134 
135  /** Update the solver direction: minimization or maximization. */
136  void setMinimum(bool m) {minimum = m;}
137 
138  /** Append a new objective to the list. */
139  void addObjective(const string& c) {objectives.push_back(c);}
140 
141  /** Return a reference to the list of objectives. */
142  const list<string>& getObjectives() const {return objectives;}
143 
144  virtual void writeElement(XMLOutput*, const Keyword&, mode=DEFAULT) const;
145  void endElement(XMLInput& pIn, const Attribute& pAttr, const DataElement& pElement);
146  virtual PyObject* getattro(const Attribute&);
147  virtual int setattro(const Attribute&, const PythonObject&);
148  static int initialize();
149 
150  /** Constructor. */
151  LPSolver(const string& n) : Solver(n), minimum(true) {initType(metadata);}
152 
153  /** Destructor. */
154  ~LPSolver() {};
155 
156  virtual const MetaClass& getType() const {return *metadata;}
157  static const MetaClass *metadata;
158  virtual size_t getSize() const {return sizeof(LPSolver);}
159 
160  private:
161  /** This is an auxilary function. GLPK requires names to contain only
162  * "graphic" characters. A space isn't one of those. Since our model
163  * can contain HasHierarchy names with a space, we call this function to
164  * replace the spaces with underscores.<br>
165  * Note however that we can't garantuee that the updated strings are
166  * all unique after the replacement!
167  */
168  static string replaceSpaces(const string&);
169 
170  /** This object is the interface with the GLPK structures. */
171  LPX* lp;
172 
173  /** Storing simplex configuration paramters. */
174  glp_smcp parameters;
175 
176  /** A list of model columns to use as objectives. */
177  list<string> objectives;
178 
179  /** Direction of the solver: minimization or maximization. */
180  bool minimum;
181 
182  /** Name of the model file.<br>
183  * This field is required.*/
184  string modelfilename;
185 
186  /** Name of the data file.<br>
187  * If the field is left empty, the data section in the model file is
188  * used instead.
189  */
190  string datafilename;
191 
192  /** Name of the solution file.<br>
193  * If the field is left empty, the solution is not exported.
194  */
195  string solutionfilename;
196 
197  /** A hook to intercept the terminal output of the solver library, and
198  * redirect it into the frePPLe log file.
199  */
200  static int solveroutputredirect(void* info, const char* msg)
201  {
202  logger << msg;
203  logger.flush();
204  return 1;
205  }
206 
207  /** Solve for a goal in a hierarchical sequence. */
208  void solveObjective(const string&);
209 };
210 
211 } // End namespace