BonNWayObject.cpp
Go to the documentation of this file.
1 // $Id$
2 // Copyright (C) 2002, International Business Machines
3 // Corporation and others. All Rights Reserved.
4 // This code is licensed under the terms of the Eclipse Public License (EPL).
5 
6 // Edwin 11/9/2009-- carved out of CbcBranchActual
7 
8 #include <cassert>
9 #include <cstdlib>
10 #include <cmath>
11 #include <cfloat>
12 #include <climits>
13 
14 
15 #include "CoinTypes.hpp"
16 #include "OsiSolverInterface.hpp"
17 #include "OsiSolverBranch.hpp"
18 #include "BonNWayObject.hpp"
19 #include "CoinSort.hpp"
20 #include "CoinError.hpp"
21 
22 //#define FULL_PRINT
23 namespace Bonmin {
24 //##############################################################################
25 
26 // Default Constructor
28  : OsiObject(),
29  members_(),
30  consequence_(NULL),
31  quicky_(false),
32  only_frac_branch_(0)
33 {
34 }
35 
36 // Useful constructor (which are integer indices)
37 BonNWayObject::BonNWayObject (int numberMembers,
38  const int * which, int identifier):
39  OsiObject(),
40  members_(numberMembers),
41  quicky_(false),
42  only_frac_branch_(0)//INT_MAX)
43 {
44  if (numberMembers) {
45  memcpy(members_.data(), which, numberMembers*sizeof(int));
46  } else {
47  }
48  consequence_ = NULL;
49 }
50 
51 // Copy constructor
53  : OsiObject(rhs), members_(rhs.members_), quicky_(rhs.quicky_), only_frac_branch_(rhs.only_frac_branch_)
54 {
55  consequence_ = NULL;
56  if (members_.size()) {
57  if (rhs.consequence_) {
59  for (size_t i = 0; i < members_.size(); i++) {
60  if (rhs.consequence_[i])
61  consequence_[i] = rhs.consequence_[i]->clone();
62  else
63  consequence_[i] = NULL;
64  }
65  }
66  } else {
67  }
68 }
69 
70 // Clone
71 OsiObject *
73 {
74  return new BonNWayObject(*this);
75 }
76 
77 // Assignment operator
80 {
81  if (this != &rhs) {
82  OsiObject::operator=(rhs);
83  members_ = rhs.members_;
84  quicky_ = rhs.quicky_;
86  if (consequence_) {
87  for (size_t i = 0; i < members_.size(); i++)
88  delete consequence_[i];
89  delete [] consequence_;
90  consequence_ = NULL;
91  }
92  if (rhs.consequence_) {
94  for (size_t i = 0; i < members_.size(); i++) {
95  if (rhs.consequence_[i])
96  consequence_[i] = rhs.consequence_[i]->clone();
97  else
98  consequence_[i] = NULL;
99  }
100  }
101  }
102  return *this;
103 }
104 
105 // Destructor
107 {
108  if (consequence_) {
109  for (size_t i = 0; i < members_.size(); i++)
110  delete consequence_[i];
111  delete [] consequence_;
112  }
113 }
114 // Set up a consequence for a single member
115 void
116 BonNWayObject::setConsequence(int iMember, const n_way_consequences& consequence)
117 {
118  if (!consequence_) {
119  consequence_ = new n_way_consequences* [members_.size()];
120  for (size_t i = 0; i < members_.size(); i++)
121  consequence_[i] = NULL;
122  }
123  consequence_[iMember] = consequence.clone();
124 }
125 
126 // Applies a consequence for a single member
127 void
128 BonNWayObject::applyConsequence(OsiSolverInterface * solver, int iSequence, int state) const
129 {
130  assert (state == -9999 || state == 9999);
131  if (consequence_) {
132  n_way_consequences* consequence = consequence_[iSequence];
133  if (consequence)
134  consequence->applyToSolver(solver, state);
135  }
136 }
137 double
138 BonNWayObject::infeasibility(const OsiBranchingInformation * info,
139  int &preferredWay) const
140 {
141  int numberUnsatis = 0;
142  size_t j;
143  const double * solution = info->solution_;
144  const double * lower = info->lower_;
145  const double * upper = info->upper_;
146  double largestValue = 0.0;
147 
148  double integerTolerance = info->integerTolerance_;
149 
150  for (j = 0; j < members_.size(); j++) {
151  int iColumn = members_[j];
152  double value = solution[iColumn];
153  value = CoinMax(value, lower[iColumn]);
154  value = CoinMin(value, upper[iColumn]);
155  double distance = CoinMin(value - lower[iColumn], upper[iColumn] - value);
156  if (distance > integerTolerance) {
157  numberUnsatis++;
158  largestValue = CoinMax(distance, largestValue);
159  }
160  }
161  preferredWay = 1;
162  if (numberUnsatis) {
163  return largestValue;
164  } else {
165  return 0.0; // satisfied
166  }
167 }
168 
169 // This looks at solution and sets bounds to contain solution
170 double
171 BonNWayObject::feasibleRegion(OsiSolverInterface * solver,
172  const OsiBranchingInformation * info) const
173 {
174  size_t j;
175  const double * solution = info->solution_;
176  const double * lower = info->lower_;
177  const double * upper = info->upper_;
178  double integerTolerance = info->integerTolerance_;
179  double r_val = 0;
180  for (j = 0; j < members_.size(); j++) {
181  int iColumn = members_[j];
182  double value = solution[iColumn];
183  value = CoinMax(value, lower[iColumn]);
184  value = CoinMin(value, upper[iColumn]);
185  if (value >= upper[iColumn] - integerTolerance) {
186  r_val += value - upper[iColumn];
187  solver->setColLower(iColumn, upper[iColumn]);
188  } else {
189  assert (value <= lower[iColumn] + integerTolerance);
190  r_val += value - lower[iColumn];
191  solver->setColUpper(iColumn, lower[iColumn]);
192  }
193  }
194  return r_val;
195 }
196 
197 OsiBranchingObject *
198 BonNWayObject::createBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int way) const
199 {
200 
201  const double * solution = info->solution_;
202  const double * lower = info->lower_;
203  const double * upper = info->upper_;
204  double integerTolerance = info->integerTolerance_;
205  double cutoff = info->cutoff_;
206  std::vector<int> list;
207  list.reserve(members_.size());
208  std::vector<double> sort;
209  sort.reserve(members_.size());
210 
211  int n_skipped = 0;
212  std::list<int> skipped;
213 
214  for (size_t j = 0; j < members_.size(); j++) {
215  const int& iColumn = members_[j];
216  double value = solution[iColumn];
217  value = CoinMax(value, lower[iColumn]);
218  value = CoinMin(value, upper[iColumn]);
219  if (upper[iColumn] > lower[iColumn]) {
220  if(bounds_.size() && bounds_[j] > cutoff) {
221  //printf("Fathom branch on bound %i : %g > %g\n", j, bounds_[j], cutoff);
222  continue;
223  }
224  if( (quicky_ || info->depth_ > only_frac_branch_ ) && fabs(solution[iColumn] - lower[iColumn]) < integerTolerance){
225  if(info->depth_ > only_frac_branch_) {
226  n_skipped++;
227  //printf("Skipping variable %i\n", iColumn);
228  skipped.push_back(static_cast<int>(j));
229  continue;
230  }
231  }
232  double distance = upper[iColumn] - value;
233  list.push_back(static_cast<int>(j));
234  sort.push_back(distance);
235  }
236  }
237 
238  if(n_skipped == 1) {//False subset put back the missing since branching up allows applying consequences
239  const int& iColumn = members_[skipped.front()];
240  double value = solution[iColumn];
241  value = CoinMax(value, lower[iColumn]);
242  value = CoinMin(value, upper[iColumn]);
243  double distance = upper[iColumn] - value;
244  list.push_back(skipped.front());
245  sort.push_back(distance);
246  skipped.pop_front();
247  n_skipped --;
248  }
249 
250  // sort
251  CoinSort_2(sort.data(), sort.data() + sort.size(), list.data());
252  // create object
253  OsiBranchingObject * branch;
254 
255  //if(n_skipped) printf("Creating branch n_skipped is %i numberFree %i\n", n_skipped, numberFree);
256  branch = new BonNWayBranchingObject(solver, this, list, skipped);
257  return branch;
258 }
259 
260 
261 // Default Constructor
263  : OsiBranchingObject(), object_(NULL),
264  order_(), skipped_()
265 {
266 }
267 
268 // Useful constructor
270  const BonNWayObject * nway,
271  const std::vector<int>& order, const std::list<int> &skipped)
272  : OsiBranchingObject(solver, 0.5), order_(order), skipped_(skipped)
273 {
274  numberBranches_ = static_cast<int>(order_.size()) + (!skipped.empty());
275  object_ = nway;
276 }
277 
278 // Copy constructor
280  OsiBranchingObject(rhs), object_(rhs.object_),
281  order_(rhs.order_), skipped_(rhs.skipped_)
282 {
283  object_ = rhs.object_;
284 }
285 
286 // Assignment operator
289 {
290  if (this != &rhs) {
291  OsiBranchingObject::operator=(rhs);
292  object_ = rhs.object_;
293  order_ = rhs.order_;
294  skipped_ = rhs.skipped_;
295  }
296  return *this;
297 }
298 OsiBranchingObject *
300 {
301  return (new BonNWayBranchingObject(*this));
302 }
303 
304 
305 // Destructor
307 {
308 }
309 
310 double
311 BonNWayBranchingObject::branch(OsiSolverInterface * solver)
312 {
313  int which = branchIndex_;
314  branchIndex_++;
315  if(!skipped_.empty() && branchIndex_ == static_cast<int>(order_.size())){//We are branching on a subset last branch fixes all in subset to 0
316  which = -1; // Simply done by setting which to a dummy value;
317  }
318  return branch(solver, which);
319 }
320 
321 double
322 BonNWayBranchingObject::branch(OsiSolverInterface * solver, int which)
323 {
324  const double * lower = solver->getColLower();
325  const double * upper = solver->getColUpper();
326  const int * members = object_->members();
327  for (size_t j = 0; j < order_.size(); j++) {
328  const int& iSequence = order_[j];
329  const int& iColumn = members[iSequence];
330  if (j != which) {
331  solver->setColUpper(iColumn, lower[iColumn]);
332  assert (lower[iColumn] > -1.0e20);
333  } else {
334  solver->setColLower(iColumn, upper[iColumn]);
335 #ifdef FULL_PRINT
336  printf("Up Fix %d to %g\n", iColumn, upper[iColumn]);
337 #endif
338  assert (upper[iColumn] < 1.0e20);
339  // apply any consequences
340  object_->applyConsequence(solver, iSequence, 9999);
341  }
342  }
343  if(which != -1){
344  for(std::list<int>::iterator k = skipped_.begin() ; k != skipped_.end() ; k++){
345  assert(upper[members[*k]] > lower[members[*k]] + 0.5);
346  solver->setColUpper(members[*k], lower[members[*k]]);
347  }
348  }
349  return 0.0;
350 }
351 
352 }
353 
std::vector< int > members_
data
void fint fint fint real fint real real real real real real real real real fint real fint fint fint real fint fint fint fint * info
virtual OsiObject * clone() const
Clone.
virtual ~BonNWayObject()
Destructor.
virtual OsiBranchingObject * createBranch(OsiSolverInterface *solver, const OsiBranchingInformation *info, int way) const
Creates a branching object.
const BonNWayObject * object_
Points back to object.
BonNWayObject & operator=(const BonNWayObject &rhs)
Assignment operator.
int only_frac_branch_
Only branch on fractional variables (last branch puts all of them to 0)
bool quicky_
Quicky only branch up on variables with non zero value.
void applyConsequence(OsiSolverInterface *solver, int iSequence, int state) const
Applies a consequence for a single member.
static char * j
Definition: OSdtoa.cpp:3622
BonNWayBranchingObject & operator=(const BonNWayBranchingObject &rhs)
void setConsequence(int iMember, const n_way_consequences &consequence)
Set up a consequence for a single member.
n_way_consequences ** consequence_
Consequences (normally NULL)
virtual double branch(OsiSolverInterface *solver)
Does next branch and updates state.
void fint fint * k
const int * members() const
Members (indices in range 0 ... numberColumns-1)
static int
Definition: OSdtoa.cpp:2173
virtual double feasibleRegion(OsiSolverInterface *solver, const OsiBranchingInformation *info) const
This looks at solution and sets bounds to contain solution.
N way branching Object class.
void applyToSolver(OsiSolverInterface *solver, int state) const
std::list< int > skipped_
Is only branching on a subset of variables (has to do a last branch with all variables in order set t...
std::vector< double > bounds_
Bounds on the members.
n_way_consequences * clone() const
double distance(const double *p1, const double *p2, int size, double k=2.)
compute Euclidean distance between two points (most likely LP solutions) l_2 norm by default...
std::vector< int > order_
order of branching
virtual double infeasibility(const OsiBranchingInformation *info, int &preferredWay) const
Infeasibility - large is 0.5 (and 0.5 will give this)
virtual OsiBranchingObject * clone() const
Clone.