summaryrefslogtreecommitdiff
path: root/build/Bonmin/include/coin/CglFlowCover.hpp
blob: eea070f609cbe16a199e3b9ea81ae0b57092ade6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
// $Id: CglFlowCover.hpp 1119 2013-04-06 20:24:18Z stefan $
//-----------------------------------------------------------------------------
// name:     Cgl Lifted Simple Generalized Flow Cover Cut Generator
// author:   Yan Xu                email: yan.xu@sas.com
//           Jeff Linderoth        email: jtl3@lehigh.edu
//           Martin Savelsberg     email: martin.savelsbergh@isye.gatech.edu
// date:     05/01/2003
// comments: please scan this file for '???' and read the comments
//-----------------------------------------------------------------------------
// Copyright (C) 2003, Yan Xu, Jeff Linderoth, Martin Savelsberg and others. 
// All Rights Reserved.
// This code is published under the Eclipse Public License.

#ifndef CglFlowCover_H
#define CglFlowCover_H

#include <iostream>

#include "CoinError.hpp"

#include "CglCutGenerator.hpp"

//=============================================================================

//=============================================================================

/** This enumerative constant describes the various col types.*/
enum CglFlowColType {
    /** The column(variable) is a negative binary variable.*/
    CGLFLOW_COL_BINNEG  = -2,
    /** The column is a negative continous variable.*/
    CGLFLOW_COL_CONTNEG,
    /** The column is a positive continous variable.*/
    CGLFLOW_COL_CONTPOS =  1,
    /** The column is a positive binary variable.*/
    CGLFLOW_COL_BINPOS
};

enum CglFlowColStatus{
};

/** This enumerative constant describes the various stati of vars in 
    a cut or not.*/
enum CglFlowColCut{
    /** The column is NOT in cover.*/
    CGLFLOW_COL_OUTCUT = 0,
    /** The column is in cover now. */
    CGLFLOW_COL_INCUT,
    /** The column is decided to be in cover. */
    CGLFLOW_COL_INCUTDONE,
    /** The column is in L-. */
    CGLFLOW_COL_INLMIN,
    /** The column is decided to be in L-. */
    CGLFLOW_COL_INLMINDONE,
    /** The column is in L--.*/
    CGLFLOW_COL_INLMINMIN,
    /** This enumerative constant describes the various stati of vars in 
                   determining the cover.*/
    /** The column is a prime candidate. */
    CGLFLOW_COL_PRIME,
    /** The column is a secondary candidate. */
    CGLFLOW_COL_SECONDARY
};

/** This enumerative constant describes the various row types.*/
enum CglFlowRowType {
    /** The row type of this row is NOT defined yet.*/
    CGLFLOW_ROW_UNDEFINED,
    /** After the row is flipped to 'L', the row has exactly two variables: 
	one is negative binary and the other is continous, and the RHS 
	is zero.*/
    CGLFLOW_ROW_VARUB,
    /** After the row is flipped to 'L', the row has exactlytwo variables: 
	one is positive binary and the other is continous, and the RHS 
	is zero.*/
    CGLFLOW_ROW_VARLB,
    /** The row sense is 'E', the row has exactly two variables: 
	one is binary and the other is a continous, and the RHS is zero.*/ 
    CGLFLOW_ROW_VAREQ,
    /** Rows can not be classfied into other types and the row sense 
	is NOT 'E'.*/
    CGLFLOW_ROW_MIXUB,
    /** Rows can not be classfied into other types and the row sense is 'E'.*/
    CGLFLOW_ROW_MIXEQ,
    /** All variables are NOT binary and the row sense is NOT 'E'. */
    CGLFLOW_ROW_NOBINUB,
    /** All variables are NOT binary and the row sense is 'E'. */
    CGLFLOW_ROW_NOBINEQ,
    /** The row has one binary and 2 or more other types of variables and 
	the row sense is NOT 'E'. */
    CGLFLOW_ROW_SUMVARUB,
    /** The row has one binary and 2 or more other types of variables and 
	the row sense is 'E'. */
    CGLFLOW_ROW_SUMVAREQ,
    /** All variables are binary. */
    CGLFLOW_ROW_UNINTERSTED
};

//=============================================================================

/** Variable upper bound class. */
class CglFlowVUB
{
protected:
    int    varInd_;            /** The index of the associated 0-1 variable.*/
    double upper_;             /** The Value of the associated upper bound.*/ 

public:
    CglFlowVUB() : varInd_(-1), upper_(-1) {}
    
    CglFlowVUB(const CglFlowVUB& source) { 
	varInd_= source.varInd_; 
	upper_ = source.upper_; 
    } 
    
    CglFlowVUB& operator=(const CglFlowVUB& rhs) { 
	if (this == &rhs) 
	    return *this;
	varInd_= rhs.varInd_; 
	upper_ = rhs.upper_; 
	return *this; 
  }
    
    /**@name Query and set functions for associated 0-1 variable index 
       and value.
    */ 
    //@{  
    inline int    getVar() const          { return varInd_; }
    inline double getVal() const          { return upper_; }
    inline void   setVar(const int v)     { varInd_ = v; }
    inline void   setVal(const double v)  { upper_ = v; }
    //@}
};

//=============================================================================

/** Variable lower bound class, which is the same as vub. */
typedef CglFlowVUB CglFlowVLB;

/** Overloaded operator<< for printing VUB and VLB.*/
std::ostream& operator<<( std::ostream& os, const CglFlowVUB &v );

//=============================================================================

/** 
 *  Lifed Simple Generalized Flow Cover Cut Generator Class. 
 */
class CglFlowCover : public CglCutGenerator {
    friend void CglFlowCoverUnitTest(const OsiSolverInterface * siP,
				     const std::string mpdDir );
    
public:
    
    /** 
     *  Do the following tasks:
     *  <ul>
     *  <li> classify row types 
     *  <li> indentify vubs and vlbs
     *  </ul>
     *  This function is called by 
     *  <CODE>generateCuts(const OsiSolverInterface & si, OsiCuts & cs)</CODE>.
   */
    void flowPreprocess(const OsiSolverInterface& si);

    /**@name Generate Cuts */
    //@{
    /** Generate Lifed Simple Generalized flow cover cuts for the model data 
	contained in si. The generated cuts are inserted into and returned 
	in the collection of cuts cs. 
    */
    virtual void generateCuts(const OsiSolverInterface & si, OsiCuts & cs,
			      const CglTreeInfo info = CglTreeInfo());
    //@}

    /**@name Functions to query and set maximum number of cuts can be 
       generated. */
    //@{
    inline int getMaxNumCuts() const { return maxNumCuts_; }
    inline void setMaxNumCuts(int mc) { maxNumCuts_ = mc; }
    //@}
  
    /**@name Functions to query and set the number of cuts have been
       generated. */
    //@{
    static int getNumFlowCuts() { return numFlowCuts_; }
    static void setNumFlowCuts(int fc) { numFlowCuts_ = fc; }
    static void incNumFlowCuts(int fc = 1) { numFlowCuts_ += fc; } 
    //@}

    //-------------------------------------------------------------------------
    /**@name Constructors and destructors */
    //@{
    /// Default constructor 
    CglFlowCover ();

    /// Copy constructor 
    CglFlowCover (
	const CglFlowCover &);

    /// Clone
    virtual CglCutGenerator * clone() const;

    /// Assignment operator 
    CglFlowCover &
    operator=(
	const CglFlowCover& rhs);
    
    /// Destructor 
    virtual
    ~CglFlowCover ();
    /// Create C++ lines to get to current state
    virtual std::string generateCpp( FILE * fp);
    //@}

private:
    //-------------------------------------------------------------------------
    // Private member functions

    /** Based a given row, a LP solution and other model data, this function
	tries to generate a violated lifted simple generalized flow cover. 
    */
    bool generateOneFlowCut( const OsiSolverInterface & si, 
			     const int rowLen,
			     int* ind,
			     double* coef,
			     char sense,
			     double rhs,
			     OsiRowCut& flowCut,
			     double& violation );


    /** Transform a row from ">=" to "<=", and vice versa. */
    void flipRow(int rowLen, double* coef, double& rhs) const;

    /** Transform a row from ">=" to "<=", and vice versa. Have 'sense'. */
    void flipRow(int rowLen, double* coef, char& sen, double& rhs) const;

    /** Determine the type of a given row. */
    CglFlowRowType determineOneRowType(const OsiSolverInterface& si,
				       int rowLen, int* ind, 
				       double* coef, char sen, 
				       double rhs) const;
    /** Lift functions */
    void liftMinus(double &movement, /* Output */ 
		   int t,
		   int r,
		   double z,
		   double dPrimePrime, 
		   double lambda,
		    double ml,
		   double *M,
		   double *rho) const;

    bool liftPlus(double &alpha, 
		 double &beta,
		 int r,
		 double m_j, 
		 double lambda,
		 double y_j,
		 double x_j,
		 double dPrimePrime,
		 double *M) const;
    

    //-------------------------------------------------------------------------
    //**@name Query and set the row type of a givne row. */
    //@{
    inline const CglFlowRowType* getRowTypes() const 
	{ return rowTypes_; }
    inline CglFlowRowType getRowType(const int i) const 
	{ return rowTypes_[i]; }
    /** Set rowtypes, take over the ownership. */
    inline void setRowTypes(CglFlowRowType* rt) 
	{ rowTypes_ = rt; rt = 0; }  
    inline void setRowTypes(const CglFlowRowType rt, const int i) {
	if (rowTypes_ != 0) 
	    rowTypes_[i] = rt;
	else {
	    std::cout << "ERROR: Should allocate memory for rowType_ before "
		      << "using it " << std::endl;
	    throw CoinError("Forgot to allocate memory for rowType_", 
			    "setRowType", "CglFlowCover");
	}
    }
    //@}
    
    //-------------------------------------------------------------------------
    //**@name Query and set vubs. */
    //@{
    inline const CglFlowVUB* getVubs() const          { return vubs_; }
    inline const CglFlowVUB& getVubs(int i) const     { return vubs_[i]; }
    /** Set CglFlowVUBs,take over the ownership. */
    inline void setVubs(CglFlowVUB* vubs) { vubs_ = vubs; vubs = 0; }
    inline void setVubs(const CglFlowVUB& vub, int i) { 
	if (vubs_ != 0) 
	    vubs_[i] = vub;
	else {
	    std::cout << "ERROR: Should allocate memory for vubs_ before "
		      << "using it " << std::endl;
	    throw CoinError("Forgot to allocate memory for vubs_", "setVubs",
			    "CglFlowCover");
	}
    }
    inline void printVubs(std::ostream& os) const {
	for (int i = 0; i < numCols_; ++i) {
	    os << "ix: " << i << ", " << vubs_[i];
	}
    }
    //@}

    //-------------------------------------------------------------------------
    //**@name Query and set vlbs. */
    //@{
    inline const CglFlowVLB* getVlbs() const          { return vlbs_; }
    inline const CglFlowVLB& getVlbs(int i) const     { return vlbs_[i]; }
    /** Set CglFlowVLBs,take over the ownership. */
    inline void setVlbs(CglFlowVLB* vlbs)          { vlbs_ = vlbs; vlbs = 0; }
    inline void setVlbs(const CglFlowVLB& vlb, int i) { 
	if (vlbs_ != 0) 
	    vlbs_[i] = vlb;
	else {
	    std::cout << "ERROR: Should allocate memory for vlbs_ before "
		      << "using it " << std::endl;
	    throw CoinError("Forgot to allocate memory for vlbs_", "setVlbs",
			    "CglFlowCover");
	}
    }
    //@}

private:
    //------------------------------------------------------------------------
    // Private member data
    
    /** The maximum number of flow cuts to be generated. Default is 1000. */
    int maxNumCuts_;
    /** Tolerance used for numerical purpose. */
    double EPSILON_;
    /** The variable upper bound of a flow is not indentified yet.*/
    int UNDEFINED_;
    /** Very large number. */
    double INFTY_;
    /** If violation of a cut is greater that this number, the cut is useful.*/
    double TOLERANCE_;
    /** First time preprocessing */
    bool firstProcess_;
    /** The number rows of the problem.*/
    int numRows_;
    /** The number columns of the problem.*/
    int numCols_;
    /** The number flow cuts found.*/
    static int numFlowCuts_;
    /** Indicate whether initial flow preprecessing has been done. */
    bool doneInitPre_;
    /** The array of CglFlowVUBs. */
    CglFlowVUB* vubs_;
    /** The array of CglFlowVLBs. */
    CglFlowVLB* vlbs_;
    /** CglFlowRowType of the rows in model. */
    CglFlowRowType* rowTypes_;
};

//#############################################################################
/** A function that tests the methods in the CglFlowCover class. The
    only reason for it not to be a member method is that this way it doesn't
    have to be compiled into the library. And that's a gain, because the
    library should be compiled with optimization on, but this method should be
    compiled with debugging. */
void CglFlowCoverUnitTest(const OsiSolverInterface * siP,
			  const std::string mpdDir );

#endif