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
|
// $Id: CbcSOS.hpp 2070 2014-09-08 09:24:45Z forrest $
// Copyright (C) 2002, International Business Machines
// Corporation and others. All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).
// Edwin 11/9/2009-- carved out of CbcBranchActual
#ifndef CbcSOS_H
#define CbcSOS_H
/** \brief Branching object for Special Ordered Sets of type 1 and 2.
SOS1 are an ordered set of variables where at most one variable can be
non-zero. SOS1 are commonly defined with binary variables (interpreted as
selection between alternatives) but this is not necessary. An SOS1 with
all binary variables is a special case of a clique (setting any one
variable to 1 forces all others to 0).
In theory, the implementation makes no assumptions about integrality in
Type 1 sets. In practice, there are places where the code seems to have been
written with a binary SOS mindset. Current development of SOS branching
objects is proceeding in OsiSOS.
SOS2 are an ordered set of variables in which at most two consecutive
variables can be non-zero and must sum to 1 (interpreted as interpolation
between two discrete values). By definition the variables are non-integer.
*/
class CbcSOS : public CbcObject {
public:
// Default Constructor
CbcSOS ();
/** \brief Constructor with SOS type and member information
Type specifies SOS 1 or 2. Identifier is an arbitrary value.
Which should be an array of variable indices with numberMembers entries.
Weights can be used to assign arbitrary weights to variables, in the order
they are specified in which. If no weights are provided, a default array of
0, 1, 2, ... is generated.
*/
CbcSOS (CbcModel * model, int numberMembers,
const int * which, const double * weights, int identifier,
int type = 1);
// Copy constructor
CbcSOS ( const CbcSOS &);
/// Clone
virtual CbcObject * clone() const;
// Assignment operator
CbcSOS & operator=( const CbcSOS& rhs);
// Destructor
virtual ~CbcSOS ();
/// Infeasibility - large is 0.5
virtual double infeasibility(const OsiBranchingInformation * info,
int &preferredWay) const;
using CbcObject::feasibleRegion ;
/// This looks at solution and sets bounds to contain solution
virtual void feasibleRegion();
/// Creates a branching object
virtual CbcBranchingObject * createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) ;
/** Pass in information on branch just done and create CbcObjectUpdateData instance.
If object does not need data then backward pointer will be NULL.
Assumes can get information from solver */
virtual CbcObjectUpdateData createUpdateInformation(const OsiSolverInterface * solver,
const CbcNode * node,
const CbcBranchingObject * branchingObject);
/// Update object by CbcObjectUpdateData
virtual void updateInformation(const CbcObjectUpdateData & data) ;
using CbcObject::solverBranch ;
/** Create an OsiSolverBranch object
This returns NULL if branch not represented by bound changes
*/
virtual OsiSolverBranch * solverBranch() const;
/// Redoes data when sequence numbers change
virtual void redoSequenceEtc(CbcModel * model, int numberColumns, const int * originalColumns);
/// Construct an OsiSOS object
OsiSOS * osiObject(const OsiSolverInterface * solver) const;
/// Number of members
inline int numberMembers() const {
return numberMembers_;
}
/// Members (indices in range 0 ... numberColumns-1)
inline const int * members() const {
return members_;
}
/// SOS type
inline int sosType() const {
return sosType_;
}
/// Down number times
inline int numberTimesDown() const {
return numberTimesDown_;
}
/// Up number times
inline int numberTimesUp() const {
return numberTimesUp_;
}
/** Array of weights */
inline const double * weights() const {
return weights_;
}
/// Set number of members
inline void setNumberMembers(int n) {
numberMembers_ = n;
}
/// Members (indices in range 0 ... numberColumns-1)
inline int * mutableMembers() const {
return members_;
}
/** Array of weights */
inline double * mutableWeights() const {
return weights_;
}
/** \brief Return true if object can take part in normal heuristics
*/
virtual bool canDoHeuristics() const {
return (sosType_ == 1 && integerValued_);
}
/// Set whether set is integer valued or not
inline void setIntegerValued(bool yesNo) {
integerValued_ = yesNo;
}
private:
/// data
/// Members (indices in range 0 ... numberColumns-1)
int * members_;
/** \brief Weights for individual members
Arbitrary weights for members. Can be used to attach meaning to variable
values independent of objective coefficients. For example, if the SOS set
comprises binary variables used to choose a facility of a given size, the
weight could be the corresponding facilty size. Fractional values of the
SOS variables can then be used to estimate ideal facility size.
Weights cannot be completely arbitrary. From the code, they must be
differ by at least 1.0e-7
*/
double * weights_;
/// Current pseudo-shadow price estimate down
mutable double shadowEstimateDown_;
/// Current pseudo-shadow price estimate up
mutable double shadowEstimateUp_;
/// Down pseudo ratio
double downDynamicPseudoRatio_;
/// Up pseudo ratio
double upDynamicPseudoRatio_;
/// Number of times we have gone down
int numberTimesDown_;
/// Number of times we have gone up
int numberTimesUp_;
/// Number of members
int numberMembers_;
/// SOS type
int sosType_;
/// Whether integer valued
bool integerValued_;
/// Whether odd values e.g. negative
bool oddValues_;
};
/** Branching object for Special ordered sets
Variable_ is the set id number (redundant, as the object also holds a
pointer to the set.
*/
class CbcSOSBranchingObject : public CbcBranchingObject {
public:
// Default Constructor
CbcSOSBranchingObject ();
// Useful constructor
CbcSOSBranchingObject (CbcModel * model, const CbcSOS * clique,
int way,
double separator);
// Copy constructor
CbcSOSBranchingObject ( const CbcSOSBranchingObject &);
// Assignment operator
CbcSOSBranchingObject & operator=( const CbcSOSBranchingObject& rhs);
/// Clone
virtual CbcBranchingObject * clone() const;
// Destructor
virtual ~CbcSOSBranchingObject ();
using CbcBranchingObject::branch ;
/// Does next branch and updates state
virtual double branch();
/** Update bounds in solver as in 'branch' and update given bounds.
branchState is -1 for 'down' +1 for 'up' */
virtual void fix(OsiSolverInterface * solver,
double * lower, double * upper,
int branchState) const ;
/** Reset every information so that the branching object appears to point to
the previous child. This method does not need to modify anything in any
solver. */
virtual void previousBranch() {
CbcBranchingObject::previousBranch();
computeNonzeroRange();
}
using CbcBranchingObject::print ;
/** \brief Print something about branch - only if log level high
*/
virtual void print();
/** Return the type (an integer identifier) of \c this */
virtual CbcBranchObjType type() const {
return SoSBranchObj;
}
/** Compare the original object of \c this with the original object of \c
brObj. Assumes that there is an ordering of the original objects.
This method should be invoked only if \c this and brObj are of the same
type.
Return negative/0/positive depending on whether \c this is
smaller/same/larger than the argument.
*/
virtual int compareOriginalObject(const CbcBranchingObject* brObj) const;
/** Compare the \c this with \c brObj. \c this and \c brObj must be os the
same type and must have the same original object, but they may have
different feasible regions.
Return the appropriate CbcRangeCompare value (first argument being the
sub/superset if that's the case). In case of overlap (and if \c
replaceIfOverlap is true) replace the current branching object with one
whose feasible region is the overlap.
*/
virtual CbcRangeCompare compareBranchingObject
(const CbcBranchingObject* brObj, const bool replaceIfOverlap = false);
/** Fill out the \c firstNonzero_ and \c lastNonzero_ data members */
void computeNonzeroRange();
private:
/// data
const CbcSOS * set_;
/// separator
double separator_;
/** The following two members describe the range in the members_ of the
original object that whose upper bound is not fixed to 0. This is not
necessary for Cbc to function correctly, this is there for heuristics so
that separate branching decisions on the same object can be pooled into
one branching object. */
int firstNonzero_;
int lastNonzero_;
};
#endif
|