BCP_lp_branch.cpp
Go to the documentation of this file.
1 // Copyright (C) 2000, International Business Machines
2 // Corporation and others. All Rights Reserved.
3 // #include <cfloat>
4 #include <numeric>
5 #include <algorithm>
6 
7 #include "CoinSort.hpp"
8 
9 #include "BCP_math.hpp"
10 #include "BCP_vector.hpp"
11 #include "BCP_lp_branch.hpp"
12 
13 #include "OsiSolverInterface.hpp"
14 #include "OsiBranchingObject.hpp"
15 
16 #include "BCP_var.hpp"
17 #include "BCP_cut.hpp"
18 #include "BCP_lp_result.hpp"
19 
20 //#############################################################################
21 
22 static void
23 BCP_reset_pos(BCP_vec<int>& pos, const int start)
24 {
25  int i = pos.size();
26  while (--i >= 0) {
27  if (pos[i] < 0) {
28  pos[i] = (start - 1) - pos[i];
29  }
30  }
31 }
32 
33 //#############################################################################
34 
35 static void BCP_reorder_pos(const int child_num,
36  BCP_vec<int>& positions, BCP_vec<double>& bounds)
37 {
38  const int size = positions.size();
39  if (size <= 1)
40  return;
41 
42  BCP_vec<int> perm;
43  perm.reserve(size);
44  for (int i = 0; i < size; ++i)
45  perm.unchecked_push_back(i);
46  // order the pair list based on the first entry (pos)
47  CoinSort_2(positions.begin(), positions.end(), perm.begin());
48 
49  // apply the permutation to each block in bounds
50  BCP_vec<double> new_bd;
51  new_bd.reserve(bounds.size());
52  const BCP_vec<int>::const_iterator lastpos = perm.end();
53  for (int i = 0; i < child_num; ++i){
54  BCP_vec<double>::const_iterator old_bd = bounds.entry(2 * size * i);
56  for ( ; pos != lastpos; ++pos) {
57  const int bd_pos = *pos << 1;
58  new_bd.unchecked_push_back(*(old_bd + bd_pos));
59  new_bd.unchecked_push_back(*(old_bd + (bd_pos+1)));
60  }
61  }
62  bounds = new_bd;
63 }
64 
65 //#############################################################################
66 
69  const int* order) :
70  child_num(2),
71  vars_to_add(0), cuts_to_add(0),
72  forced_var_pos(new BCP_vec<int>(1,-1)), forced_cut_pos(0),
73  forced_var_bd(new BCP_vec<double>(4,0.0)), forced_cut_bd(0),
74  implied_var_pos(0), implied_cut_pos(0),
75  implied_var_bd(0), implied_cut_bd(0),
76  objval_(0), termcode_(0)
77 {
80  fvp[0] = o.originalObject()->columnNumber();
81  memcpy(&fvb[0], o.childBounds(order[0]), 2*sizeof(double));
82  memcpy(&fvb[2], o.childBounds(order[1]), 2*sizeof(double));
83 }
84 
85 //#############################################################################
86 
88 BCP_lp_branching_object(const OsiSolverInterface* osi,
90  const int* order) :
91  child_num(2),
92  vars_to_add(0), cuts_to_add(0),
93  forced_var_pos(0), forced_cut_pos(0),
94  forced_var_bd(0), forced_cut_bd(0),
95  implied_var_pos(0), implied_cut_pos(0),
96  implied_var_bd(0), implied_cut_bd(0),
97  objval_(0), termcode_(0)
98 {
99  const OsiSOS* sos = dynamic_cast<const OsiSOS*>(o.originalObject());
100  const int * which = sos->members();
101  const double * weights = sos->weights();
102  const double value = o.value();
103  int i;
104 
105  const double* clb = osi->getColLower();
106  const double* cub = osi->getColUpper();
107 
108  const int len = sos->numberMembers();
109  forced_var_pos = new BCP_vec<int>(sos->members(), sos->members()+len);
110  forced_var_bd = new BCP_vec<double>(4*len, 0.0);
112  double* downchildBounds = NULL;
113  double* upchildBounds = NULL;
114  if ( order[0] == 0) {
115  downchildBounds = &fvb[0];
116  upchildBounds = &fvb[2*len];
117  } else {
118  downchildBounds = &fvb[2*len];
119  upchildBounds = &fvb[0];
120  }
121  for (i = 0; i < len; ++i) {
122  const int pos = which[i];
123  downchildBounds[2*i] = upchildBounds[2*i] = clb[pos];
124  downchildBounds[2*i+1] = upchildBounds[2*i+1] = cub[pos];
125  }
126  // upper bounds in child 0
127  for (i = 0; i < len; ++i) {
128  if (weights[i] > value)
129  break;
130  }
131  assert (i < len);
132  for ( ; i < len; ++i) {
133  downchildBounds[2*i+1] = 0.0;
134  }
135  // upper bounds in child 1
136  for (i = 0 ; i < len; ++i) {
137  if (weights[i] >= value)
138  break;
139  else
140  upchildBounds[2*i+1] = 0.0;
141  }
142  assert ( i < len);
143 }
144 
145 //#############################################################################
146 
147 void
149  const int added_cuts_start)
150 {
151  if (vars_to_add){
152  if (forced_var_pos)
153  BCP_reset_pos(*forced_var_pos, added_vars_start);
154  if (implied_var_pos)
155  BCP_reset_pos(*implied_var_pos, added_vars_start);
156  }
157  if (cuts_to_add){
158  if (forced_cut_pos)
159  BCP_reset_pos(*forced_cut_pos, added_cuts_start);
160  if (implied_cut_pos)
161  BCP_reset_pos(*implied_cut_pos, added_cuts_start);
162  }
163 
164  // reorder the positions so that it's increasing everywhere
165  if (forced_var_pos)
167  if (implied_var_pos)
169  if (forced_cut_pos)
171  if (implied_cut_pos)
173 }
174 
175 //#############################################################################
176 
177 void
179  const int child_ind) const
180 {
181  if (forced_var_pos) {
182  const int len = forced_var_pos->size();
183  lp->setColSetBounds(forced_var_pos->begin(), forced_var_pos->end(),
184  forced_var_bd->entry(2 * len * child_ind));
185  }
186  if (implied_var_pos) {
187  const int len = implied_var_pos->size();
188  lp->setColSetBounds(implied_var_pos->begin(), implied_var_pos->end(),
189  implied_var_bd->entry(2 * len * child_ind));
190  }
191  if (forced_cut_pos) {
192  const int len = forced_cut_pos->size();
193  lp->setRowSetBounds(forced_cut_pos->begin(), forced_cut_pos->end(),
194  forced_cut_bd->entry(2 * len * child_ind));
195  }
196  if (implied_cut_pos) {
197  const int len = implied_cut_pos->size();
198  lp->setRowSetBounds(implied_cut_pos->begin(), implied_cut_pos->end(),
199  implied_cut_bd->entry(2 * len * child_ind));
200  }
201 }
202 
203 //#############################################################################
204 
205 void
207  const double * x,
208  const double * obj) const
209 {
210  printf(" (");
211  if (forced_var_pos) {
212  const int ind = (*forced_var_pos)[0];
213  if (ind < orig_varnum) {
214  printf("%i,%.4f,%.4f", ind, x[ind], obj[ind]);
215  } else {
216  // must be a var added in branching
217  printf(";%i,-,-", ind);
218  }
219  const int size = forced_var_pos->size();
220  for (int i = 1; i < size; ++i) {
221  const int ind = (*forced_var_pos)[i];
222  if (ind < orig_varnum) {
223  printf(";%i,%.4f,%.4f", ind, x[ind], obj[ind]);
224  } else {
225  // must be a var added in branching
226  printf(";%i,-,-", ind);
227  }
228  }
229  }
230  printf(" / ");
231  if (forced_cut_pos) {
232  printf("%i", (*forced_cut_pos)[0]);
233  const int size = forced_cut_pos->size();
234  for (int i = 1; i < size; ++i)
235  printf(";%i", (*forced_cut_pos)[i]);
236  }
237  printf(" )");
238 }
239 
240 //#############################################################################
241 
242 void BCP_presolved_lp_brobj::fake_objective_values(const double itlim_objval)
243 {
244  for (int i = _candidate->child_num - 1; i >= 0; --i){
245  const int tc = _lpres[i]->termcode();
247  _lpres[i]->fake_objective_value(BCP_DBL_MAX);
248  continue;
249  }
250  // *THINK* : what to do in these cases?
253  _lpres[i]->fake_objective_value(itlim_objval);
254  continue;
255  }
256  }
257 }
258 
260  const BCP_vec<int>& termcode,
261  const double itlim_objval)
262 {
263  for (int i = _candidate->child_num - 1; i >= 0; --i) {
264  const int tc = termcode[i];
266  _lpres[i]->fake_objective_value(BCP_DBL_MAX);
267  continue;
268  }
269  // *THINK* : what to do in these cases?
272  _lpres[i]->fake_objective_value(itlim_objval);
273  continue;
274  }
275  _lpres[i]->fake_objective_value(obj[i]);
276  }
277 }
278 
279 bool BCP_presolved_lp_brobj::fathomable(const double objval_limit) const
280 {
281  // If ALL descendants in cand terminated with primal infeasibility
282  // or high cost, that proves that the current node can be fathomed.
283  for (int i = _candidate->child_num - 1; i >= 0; --i) {
284  const int tc = _lpres[i]->termcode();
285  if (! ((tc & BCP_ProvenPrimalInf) ||
286  (tc & BCP_DualObjLimReached) ||
287  ((tc & BCP_ProvenOptimal) && _lpres[i]->objval() > objval_limit)))
288  return false;
289  }
290  return true;
291 }
292 
294 {
295  for (int i = _candidate->child_num - 1; i >= 0; --i)
296  if (_lpres[i]->termcode() == BCP_Abandoned)
297  return true;
298  return false;
299 }
BCP_vec< double > * implied_var_bd
void apply_child_bd(OsiSolverInterface *lp, const int child_ind) const
This method invokes the appropriate methods of lp to apply the forced and implied bound changes of th...
BCP_vec< int > * implied_var_pos
static void BCP_reset_pos(BCP_vec< int > &pos, const int start)
pos
position where the operator should be printed when printing the expression
void print_branching_info(const int orig_varnum, const double *x, const double *obj) const
This method prints out some information about the branching object.
void set_objective_values(const BCP_vec< double > &obj, const BCP_vec< int > &termcode, const double itlim_objval)
Set the appropriate fields of all _lpres to the given termcode and objval if the termcode is &quot;normal&quot;...
BCP_vec< BCP_lp_result * > _lpres
A vector of lp results holding the actual presolved data.
This class exist only so that we can extract information from OsiIntegerBranchingObject.
const double * childBounds(int i) const
iterator begin()
Return an iterator to the beginning of the object.
Definition: BCP_vector.hpp:99
bool had_numerical_problems() const
Return true if at least one child had numerical difficulties while presolving.
BCP_vec< double > * forced_var_bd
Contains the actual bounds for the variables indexed by forced_var_pos.
void reserve(const size_t n)
Reallocate the object to make space for n entries.
bool fathomable(const double objval_limit) const
Return true if every children can be fathomed.
#define BCP_DBL_MAX
Definition: BCP_math.hpp:6
BCP_vec< int > * implied_cut_pos
BCP_lp_branching_object(const BCP_lp_branching_object &)
The copy constructor is declared but not defined to disable it.
BCP_vec< int > * forced_cut_pos
Positions of cuts whose bounds change (&quot;forcibly&quot;, by branching) in the children. ...
void fint fint fint real fint real real real real real real real real real fint real fint * lp
int child_num
The number of children for this branching object.
BCP_vec< double > * forced_cut_bd
Contains the actual bounds for the cuts indexed by forced_cut_pos.
BCP_vec< BCP_var * > * vars_to_add
Variables to be added to the formulation.
static int
Definition: OSdtoa.cpp:2173
BCP_vec< double > * implied_cut_bd
BCP_vec< int > * forced_var_pos
Positions of variables whose bounds change (&quot;forcibly&quot;, by branching) in the children.
size_t size() const
Return the current number of entries.
Definition: BCP_vector.hpp:116
iterator end()
Return an iterator to the end of the object.
Definition: BCP_vector.hpp:104
BCP_vec< BCP_cut * > * cuts_to_add
Cuts to be added to the formulation.
void unchecked_push_back(const_reference x)
Append x to the end of the vector.
This class exist only so that we can extract information from OsiIntegerBranchingObject.
iterator entry(const int i)
Return an iterator to the i-th entry.
Definition: BCP_vector.hpp:109
BCP_lp_branching_object * _candidate
A pointer to the branching object (created internally or by the user) whose presolved data is stored ...
void fake_objective_values(const double itlim_objval)
Examine the termination codes for the children and for those that do not have a valid lower bound fak...
void init_pos_for_added(const int added_vars_start, const int added_cuts_start)
This method &quot;cleans up&quot; the positions and bounds.
static void BCP_reorder_pos(const int child_num, BCP_vec< int > &positions, BCP_vec< double > &bounds)
void fint fint fint real fint real * x