1 | // Copyright (C) 2000, International Business Machines |
2 | // Corporation and others. All Rights Reserved. |
3 | // This code is licensed under the terms of the Eclipse Public License (EPL). |
4 | |
5 | #ifndef OsiRowCutDebugger_H |
6 | #define OsiRowCutDebugger_H |
7 | |
8 | /*! \file OsiRowCutDebugger.hpp |
9 | |
10 | \brief Provides a facility to validate cut constraints to ensure that they |
11 | do not cut off a given solution. |
12 | */ |
13 | |
14 | #include <string> |
15 | |
16 | #include "OsiCuts.hpp" |
17 | #include "OsiSolverInterface.hpp" |
18 | |
19 | /*! \brief Validate cuts against a known solution |
20 | |
21 | OsiRowCutDebugger provides a facility for validating cuts against a known |
22 | solution for a problem. The debugger knows an optimal solution for many of |
23 | the miplib3 problems. Check the source for |
24 | #activate(const OsiSolverInterface&,const char*) |
25 | in OsiRowCutDebugger.cpp for the full set of known problems. |
26 | |
27 | A full solution vector can be supplied as a parameter with |
28 | (#activate(const OsiSolverInterface&,const double*,bool)). |
29 | Only the integer values need to be valid. |
30 | The default behaviour is to solve an lp relaxation with the integer |
31 | variables fixed to the specified values and use the optimal solution to fill |
32 | in the continuous variables in the solution. |
33 | The debugger can be instructed to preserve the continuous variables (useful |
34 | when debugging solvers where the linear relaxation doesn't capture all the |
35 | constraints). |
36 | |
37 | Note that the solution must match the problem held in the solver interface. |
38 | If you want to use the row cut debugger on a problem after applying presolve |
39 | transformations, your solution must match the presolved problem. (But see |
40 | #redoSolution().) |
41 | */ |
42 | class OsiRowCutDebugger { |
43 | friend void OsiRowCutDebuggerUnitTest(const OsiSolverInterface * siP, |
44 | const std::string & mpsDir); |
45 | |
46 | public: |
47 | |
48 | /*! @name Validate Row Cuts |
49 | |
50 | Check that the specified cuts do not cut off the known solution. |
51 | */ |
52 | //@{ |
53 | /*! \brief Check that the set of cuts does not cut off the solution known |
54 | to the debugger. |
55 | |
56 | Check if any generated cuts cut off the solution known to the debugger! |
57 | If so then print offending cuts. Return the number of invalid cuts. |
58 | */ |
59 | virtual int validateCuts(const OsiCuts & cs, int first, int last) const; |
60 | |
61 | /*! \brief Check that the cut does not cut off the solution known to the |
62 | debugger. |
63 | |
64 | Return true if cut is invalid |
65 | */ |
66 | virtual bool invalidCut(const OsiRowCut & rowcut) const; |
67 | |
68 | /*! \brief Returns true if the solution held in the solver is compatible |
69 | with the known solution. |
70 | |
71 | More specifically, returns true if the known solution satisfies the column |
72 | bounds held in the solver. |
73 | */ |
74 | bool onOptimalPath(const OsiSolverInterface &si) const; |
75 | //@} |
76 | |
77 | /*! @name Activate the Debugger |
78 | |
79 | The debugger is considered to be active when it holds a known solution. |
80 | */ |
81 | //@{ |
82 | /*! \brief Activate a debugger using the name of a problem. |
83 | |
84 | The debugger knows an optimal solution for most of miplib3. Check the |
85 | source code for the full list. Returns true if the debugger is |
86 | successfully activated. |
87 | */ |
88 | bool activate(const OsiSolverInterface &si, const char *model) ; |
89 | |
90 | /*! \brief Activate a debugger using a full solution array. |
91 | |
92 | The solution must have one entry for every variable, but only the entries |
93 | for integer values are used. By default the debugger will solve an lp |
94 | relaxation with the integer variables fixed and fill in values for the |
95 | continuous variables from this solution. If the debugger should preserve |
96 | the given values for the continuous variables, set \p keepContinuous to |
97 | \c true. |
98 | |
99 | Returns true if debugger activates successfully. |
100 | */ |
101 | bool activate(const OsiSolverInterface &si, const double* solution, |
102 | bool keepContinuous = false) ; |
103 | |
104 | /// Returns true if the debugger is active |
105 | bool active() const; |
106 | //@} |
107 | |
108 | /*! @name Query or Manipulate the Known Solution */ |
109 | //@{ |
110 | /// Return the known solution |
111 | inline const double * optimalSolution() const |
112 | { return knownSolution_;} |
113 | |
114 | /// Return the number of columns in the known solution |
115 | inline int numberColumns() const { return (numberColumns_) ; } |
116 | |
117 | /// Return the value of the objective for the known solution |
118 | inline double optimalValue() const { return knownValue_;} |
119 | |
120 | /*! \brief Edit the known solution to reflect column changes |
121 | |
122 | Given a translation array \p originalColumns[numberColumns] which can |
123 | translate current column indices to original column indices, this method |
124 | will edit the solution held in the debugger so that it matches the current |
125 | set of columns. |
126 | |
127 | Useful when the original problem is preprocessed prior to cut generation. |
128 | The debugger does keep a record of the changes. |
129 | */ |
130 | void redoSolution(int numberColumns, const int *originalColumns); |
131 | |
132 | /// Print optimal solution (returns -1 bad debug, 0 on optimal, 1 not) |
133 | int printOptimalSolution(const OsiSolverInterface & si) const; |
134 | //@} |
135 | |
136 | /**@name Constructors and Destructors */ |
137 | //@{ |
138 | /// Default constructor - no checking |
139 | OsiRowCutDebugger (); |
140 | |
141 | /*! \brief Constructor with name of model. |
142 | |
143 | See #activate(const OsiSolverInterface&,const char*). |
144 | */ |
145 | OsiRowCutDebugger(const OsiSolverInterface &si, const char *model) ; |
146 | |
147 | /*! \brief Constructor with full solution. |
148 | |
149 | See #activate(const OsiSolverInterface&,const double*,bool). |
150 | */ |
151 | OsiRowCutDebugger(const OsiSolverInterface &si, const double *solution, |
152 | bool enforceOptimality = false) ; |
153 | |
154 | /// Copy constructor |
155 | OsiRowCutDebugger(const OsiRowCutDebugger &); |
156 | |
157 | /// Assignment operator |
158 | OsiRowCutDebugger& operator=(const OsiRowCutDebugger& rhs); |
159 | |
160 | /// Destructor |
161 | virtual ~OsiRowCutDebugger (); |
162 | //@} |
163 | |
164 | private: |
165 | |
166 | // Private member data |
167 | |
168 | /**@name Private member data */ |
169 | //@{ |
170 | /// Value of known solution |
171 | double knownValue_; |
172 | |
173 | /*! \brief Number of columns in known solution |
174 | |
175 | This must match the number of columns reported by the solver. |
176 | */ |
177 | int numberColumns_; |
178 | |
179 | /// array specifying integer variables |
180 | bool * integerVariable_; |
181 | |
182 | /// array specifying known solution |
183 | double * knownSolution_; |
184 | //@} |
185 | }; |
186 | |
187 | #endif |
188 | |