BB_lp.cpp
Go to the documentation of this file.
1 // Last edit: 1/21/09
2 //
3 // Name: BB_lp.cpp
4 // Author: Francois Margot
5 // Tepper School of Business
6 // Carnegie Mellon University, Pittsburgh, PA 15213
7 // email: fmargot@andrew.cmu.edu
8 // Date: 12/28/03
9 //-----------------------------------------------------------------------------
10 // Copyright (C) 2003, Francois Margot, International Business Machines
11 // Corporation and others. All Rights Reserved.
12 
13 #include <vector>
14 
15 #include "BB_lp.hpp"
16 #include "BB_cut.hpp"
17 #include "OsiClpSolverInterface.hpp"
18 
19 #include "BCP_math.hpp"
20 #include "BCP_lp.hpp"
21 #include "BCP_problem_core.hpp"
22 
23 using namespace std;
24 
25 /************************************************************************/
26 void
28 {
29  buf.unpack(p_desc);
30  EPS = p_desc->EPSILON;
31 }
32 
33 /************************************************************************/
34 OsiSolverInterface *
36 
37  // Called once at the beginning, from the root node
38 
39 {
40  OsiClpSolverInterface * clp = new OsiClpSolverInterface;
41  clp->messageHandler()->setLogLevel(0);
42 
43  // Comment out following line if using Cplex
44  clp->getModelPtr()->messageHandler()->setLogLevel(0);
45 
46  // Important if using Cplex
47  clp->setHintParam(OsiDoDualInResolve, true, OsiHintTry);
48 
49  return clp;
50 }
51 
52 /************************************************************************/
53 void
55  const BCP_vec<BCP_cut*>& cuts,
56  const BCP_vec<BCP_obj_status>& vstatus,
57  const BCP_vec<BCP_obj_status>& cstatus,
58  BCP_vec<int>& var_changed_pos,
59  BCP_vec<double>& var_new_bd,
60  BCP_vec<int>& cut_changed_pos,
61  BCP_vec<double>& cut_new_bd)
62 
63  // Called at the beginning of the optimization of a node.
64  // The node LP is not yet solved.
65 
66 {
67  in_strong = 0;
68 
69 #ifdef USER_DATA
70  MY_user_data *curr_ud = dynamic_cast<MY_user_data*> (get_user_data());
71  curr_ud->is_processed = 1;
72 #endif
73 
74 }
75 
76 /************************************************************************/
77 void
78 BB_lp::modify_lp_parameters(OsiSolverInterface* lp, const int changeType,
79  bool in_strong_branching)
80 
81  // Called each time the node LP is solved
82 
83 {
84  if (in_strong_branching) {
85  in_strong = 1;
86  lp->setIntParam(OsiMaxNumIterationHotStart, 50);
87  }
88 
89  // write the current LP in file lpnode.lp
90  lp->writeLp("lpnode", "lp");
91  cout << "LP node written in file lpnode.lp" << endl;
92 
93  // to write the current LP file in file lpnode.mps use the following:
94  // lp->writeMps("lpnode", "mps", 0.0);
95  // cout << "LP node written in file lpnode.mps" << endl;
96 
97 }
98 
99 /************************************************************************/
102  const BCP_vec<BCP_var*>& vars,
103  const BCP_vec<BCP_cut*>& cuts)
104 
105  // Called after each node LP has been solved.
106  // Called even if the node LP was infeasible
107  // Called also during strong branching
108 
109 {
110  // Don't test feasibility during strong branching
111 
112  if (in_strong) {
113  return(0);
114  }
115 
116  // Don't test feasibility if the node LP was infeasible or
117  // termination was not clean
118 
119  if(getLpProblemPointer()->lp_solver->isAbandoned() ||
120  getLpProblemPointer()->lp_solver->isProvenPrimalInfeasible() ||
121  getLpProblemPointer()->lp_solver->isDualObjectiveLimitReached() ||
122  getLpProblemPointer()->lp_solver->isIterationLimitReached()) {
123  return(0);
124  }
125 
126  int i, j, k, cn = p_desc->colnum;;
127  const double *x = lp_result.x();
128  double *check_lhs = new double[p_desc->indexed->getNumRows()];
129 
130  // check indexed constraints
131 
132  violated_cuts.clear();
133  p_desc->indexed->times(lp_result.x(), check_lhs);
134  for (i=0; i<p_desc->indexed->getNumRows(); ++i) {
135  if ((check_lhs[i] < p_desc->rlb_indexed[i] - EPS) ||
136  (check_lhs[i] > p_desc->rub_indexed[i] + EPS))
137  violated_cuts.push_back(i);
138  }
139 
140  delete[] check_lhs;
141 
142  OsiRowCut* rcut = new OsiRowCut();
143  int *cutind = new int[cn], cut_nz;
144  double* cutcoef = new double[cn], cutrhs = 1;
145 
146  // check algorithmic cuts
147 
148  for(i=0; i<cn; i++) {
149  j = (i+1) % cn;
150  k = (i+2) % cn;
151 
152  cutcoef[0] = 1;
153  cutcoef[1] = 1;
154  cutcoef[2] = 1;
155  cut_nz = 3;
156 
157  if(x[i] + x[j] + x[k] > 1 + EPS) {
158 
159  // cut is violated
160 
161  cutind[0] = i;
162  cutind[1] = j;
163  cutind[2] = k;
164 
165  rcut->setLb(-BCP_DBL_MAX);
166  rcut->setUb(cutrhs);
167  rcut->setRow(cut_nz, cutind, cutcoef);
168 
169  BB_cut* cut = new BB_cut(*rcut);
170  algo_cuts.push_back(cut);
171 
172  }
173  }
174 
175  delete rcut;
176  delete[] cutind;
177  delete[] cutcoef;
178 
179  // if all constraints are satisfied, check integrality of the vars
180 
181  return (violated_cuts.empty() + algo_cuts.empty() == 2 ?
182  BCP_lp_user::test_feasibility(lp_result, vars, cuts) : 0);
183 }
184 
185 /********************************************************************/
186 void
188  const BCP_vec<BCP_var*>& vars,
189  const BCP_vec<BCP_cut*>& cuts,
190  const BCP_vec<BCP_obj_status>& var_status,
191  const BCP_vec<BCP_obj_status>& cut_status,
192  const int var_bound_changes_since_logical_fixing,
193  BCP_vec<int>& changed_pos, BCP_vec<double>& new_bd)
194 
195  // Called at each iteration, after test_feasibility, if the node is not
196  // fathomable
197 {
198 }
199 
200 /************************************************************************/
201 void
203  const BCP_vec<BCP_var*>& vars,
204  const BCP_vec<BCP_cut*>& cuts,
205  BCP_vec<BCP_cut*>& new_cuts,
206  BCP_vec<BCP_row*>& new_rows)
207 
208  // Send to BCP the cuts generated in test_feasibility.
209  // Use this function to generate standard cuts (Knapsack covers,
210  // Lift-and-Project, odd holes, ...).
211 
212 {
213  int i;
214 
215  for (i=violated_cuts.size()-1; i>=0; --i) {
216  const int ind = violated_cuts[i];
217  new_cuts.push_back(new BB_indexed_cut(ind, p_desc->rlb_indexed[ind],
218  p_desc->rub_indexed[ind]));
219  }
220  cout << "generate_cuts_in_lp(): found " << new_cuts.size()
221  << " indexed cuts" << endl;
222 
223  for(i=algo_cuts.size()-1; i>=0; --i) {
224  new_cuts.push_back(algo_cuts[i]);
225  }
226  cout << "generate_cuts_in_lp(): found " << algo_cuts.size()
227  << " algorithmic cuts" << endl;
228 
229  algo_cuts.clear();
230 }
231 
232 /************************************************************************/
235  const BCP_vec<BCP_var*>& vars,
236  const BCP_vec<BCP_cut*>& cuts)
237 {
238 #ifdef HEUR_SOL
239 
240  // Simple rounding heuristic
241 
242  int i, j, k, cn = p_desc->colnum;
243  const double *x = lpres.x();
244  double *rounded_x = new double[cn];
245 
246  for(i=0; i<cn; i++) {
247  if(x[i] > 0.5 + EPS) {
248  rounded_x[i] = 1;
249  }
250  else {
251  rounded_x[i] = 0;
252  }
253  }
254 
255  // check if rounded_x is feasible or not
256 
257  int nb_rows_core = p_desc->core->getNumRows();
258  int nb_rows_indexed = p_desc->indexed->getNumRows();
259  int max_core_indexed;
260 
261  if(nb_rows_indexed > nb_rows_core) {
262  max_core_indexed = nb_rows_indexed;
263  }
264  else {
265  max_core_indexed = nb_rows_core;
266  }
267 
268  double *check_lhs = new double[max_core_indexed];
269 
270  // check core constraints
271 
272  p_desc->core->times(rounded_x, check_lhs);
273 
274  for (i=0; i<nb_rows_core; ++i) {
275  if ((check_lhs[i] < p_desc->rlb_core[i] - EPS) ||
276  (check_lhs[i] > p_desc->rub_core[i] + EPS)) {
277 
278  delete[] check_lhs;
279  delete[] rounded_x;
280  cout << "generate_heuristic_solution() returns nothing.\n"
281  << endl;
282  return(0);
283  }
284  }
285 
286  // check indexed constraints
287 
288  p_desc->indexed->times(rounded_x, check_lhs);
289  for (i=0; i<nb_rows_indexed; ++i) {
290  if ((check_lhs[i] < p_desc->rlb_indexed[i] - EPS) ||
291  (check_lhs[i] > p_desc->rub_indexed[i] + EPS)) {
292 
293  delete[] check_lhs;
294  delete[] rounded_x;
295  cout << "generate_heuristic_solution() returns nothing.\n"
296  << endl;
297  return(0);
298  }
299  }
300 
301  delete[] check_lhs;
302 
303  // check algorithmic constraints
304 
305  for(i=0; i<cn; i++) {
306  j = (i+1) % cn;
307  k = (i+2) % cn;
308 
309  if(x[i] + x[j] + x[k] > 1 + EPS) {
310 
311  delete[] rounded_x;
312  cout << "generate_heuristic_solution() returns nothing.\n"
313  << endl;
314  return(0);
315  }
316  }
317 
318  // rounded_x is feasible
319 
320  BCP_solution_generic *heur_sol = new BCP_solution_generic();
321  heur_sol->_delete_vars = false; // otherwise BCP will delete the variables
322  // appearing in the solution
323 
324  BCP_vec<BCP_var_core *> core_vars = getLpProblemPointer()->core->vars;
325  int ind;
326 
327  for(i=0; i<cn; i++) {
328  ind = core_vars[i]->bcpind();
329  if(rounded_x[ind] > EPS) {
330  heur_sol->add_entry(core_vars[i], rounded_x[ind]);
331  }
332  }
333 
334  delete[] rounded_x;
335  cout << "generate_heuristic_solution() returns a solution.\n"
336  << endl;
337  return(heur_sol);
338 
339 #else /* not HEUR_SOL */
340 
341  // return nothing
342 
343  return(0);
344 #endif
345 }
346 
347 /************************************************************************/
348 void
349 BB_lp::cuts_to_rows(const BCP_vec<BCP_var*>& vars, // on what to expand
350  BCP_vec<BCP_cut*>& cuts, // what to expand
351  BCP_vec<BCP_row*>& rows, // the expanded rows
352  // things that the user can use for lifting cuts if allowed
353  const BCP_lp_result& lpres,
354  BCP_object_origin origin, bool allow_multiple)
355 
356  // Required function when indexed or algorithmic cuts are used.
357  // Describes how to get a row of the matrix from the representation of the
358  // cut.
359 
360 {
361  const int cutnum = cuts.size();
362  for (int i=0; i<cutnum; ++i) {
363  const BB_indexed_cut *icut =
364  dynamic_cast<const BB_indexed_cut*>(cuts[i]);
365  if (icut) {
366  const int ind = icut->index();
367  rows.push_back(new BCP_row(p_desc->indexed->getVector(ind),
368  p_desc->rlb_indexed[ind],
369  p_desc->rub_indexed[ind]));
370  continue;
371  }
372 
373  const OsiRowCut* bcut = dynamic_cast<const BB_cut*>(cuts[i]);
374  if (bcut) {
375  rows.push_back(new BCP_row(bcut->row(), bcut->lb(), bcut->ub()));
376  continue;
377  }
378 
379  throw BCP_fatal_error("Unknown cut type in cuts_to_rows.\n");
380  }
381 }
382 
383 /********************************************************************/
386  const BCP_vec<BCP_var*>& vars,
387  const BCP_vec<BCP_cut*>& cuts,
388  const BCP_lp_var_pool& local_var_pool,
389  const BCP_lp_cut_pool& local_cut_pool,
391  bool force_branch)
392 {
393 #ifdef CUSTOM_BRANCH
394 
395  // Called at the end of each iteration. Possible return values are:
396 
397  // BCP_DoNotBranch_Fathomed : The node should be fathomed without branching
398 
399  // BCP_DoNotBranch : BCP should continue to work on this node
400 
401  // BCP_DoBranch : Branching must be done. In this case the
402  // method returns the branching object candidates
403  // in one of the arguments
404 
405  // Don't branch if cutting planes have been generated
406 
407  if(local_cut_pool.size() > 0) {
408 
409  cout << "select_branching_candidates() returns BCP_DoNotBranch"
410  << endl;
411 
412  return(BCP_DoNotBranch);
413  }
414  else {
415 
416  // Branch on the first fractional variable
417 
418  int i;
419  const double *x = lpres.x();
420  BCP_vec<int> select_pos;
421 
422  for(i=0; i<p_desc->colnum; i++) {
423 
424  if((x[i] > EPS) && (x[i] < 1-EPS)) {
425  select_pos.push_back(i);
426 
427  // put in cands all variables whose index are in select_pos
428 
429  append_branching_vars(lpres.x(), vars, select_pos, cands);
430 
431  cout << "Branching on variable: " << i << " (" << x[i]
432  << ") depth: " << current_level() << endl;
433  break;
434  }
435  }
436 
437  if (cands.size() == 0) {
438  throw BCP_fatal_error("select_banching_candidate() : No cut in pool but couldn't select branching variable.\n");
439  }
440 
441 
442  cout << "select_branching_candidates() returns BCP_DoBranch" << endl;
443 
444  return BCP_DoBranch;
445  }
446 
447 #else
448  return(BCP_lp_user::select_branching_candidates(lpres, vars, cuts,
449  local_var_pool,
450  local_cut_pool, cands,
451  force_branch));
452 #endif
453 }
454 
455 /**************************************************************************/
456 void
458  const int selected)
459 
460  // Given the branching decision (parameter "best"; "selected" is the
461  // index of the chosen branching decision in the candidate list),
462  // set the user data for the children.
463 
464 {
465 #ifdef USER_DATA
466  BCP_lp_branching_object *cand = best->candidate();
467  MY_user_data *curr_ud = dynamic_cast<MY_user_data*> (get_user_data());
468  real_user_data *curr_rud = curr_ud->p_rud;
469 
470  for(int i=0; i<cand->child_num; i++) {
471  MY_user_data *ud = new MY_user_data(curr_rud->max_card_set_zero);
472  real_user_data *rud = ud->p_rud;
473 
474  rud->card_set_zero = curr_rud->card_set_zero;
475 
476  for(int j=0; j<curr_rud->card_set_zero; j++) {
477  rud->set_zero[j] = curr_rud->set_zero[j];
478  }
479 
480  int ind_br = (*(cand->forced_var_pos))[0];
481 
482  if((*(cand->forced_var_bd))[2*i + 1] < EPS) {
483  rud->set_zero[curr_rud->card_set_zero] = ind_br;
484  (rud->card_set_zero)++;
485  }
486  best->user_data()[i] = ud;
487  }
488 #endif /* USER_DATA */
489 } /* set_user_data_for_children */
490 
491 
492 
493 
494 
virtual BCP_branching_decision select_branching_candidates(const BCP_lp_result &lpres, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts, const BCP_lp_var_pool &local_var_pool, const BCP_lp_cut_pool &local_cut_pool, BCP_vec< BCP_lp_branching_object * > &cands, bool force_branch=false)
Called at the end of each iteration.
Definition: BB_lp.cpp:385
BCP_object_origin
This enumerative constant describes the origin (originating process) of an object (variable or cut)...
Definition: BCP_enum.hpp:249
virtual OsiSolverInterface * initialize_solver_interface()
Called only once at the beginning, from the root node.
Definition: BB_lp.cpp:35
int index() const
Constructor from content of buffer.
Definition: BB_cut.hpp:57
BCP_buffer & unpack(T &value)
Unpack a single object of type T.
Definition: BCP_buffer.hpp:186
virtual void generate_cuts_in_lp(const BCP_lp_result &lpres, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts, BCP_vec< BCP_cut * > &new_cuts, BCP_vec< BCP_row * > &new_rows)
Cut generation.
Definition: BB_lp.cpp:202
bool _delete_vars
An indicator to show whether the pointers in _vars should be deleted upon destruction or not...
virtual void logical_fixing(const BCP_lp_result &lpres, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts, const BCP_vec< BCP_obj_status > &var_status, const BCP_vec< BCP_obj_status > &cut_status, const int var_bound_changes_since_logical_fixing, BCP_vec< int > &changed_pos, BCP_vec< double > &new_bd)
Perform fixing of variables.
Definition: BB_lp.cpp:187
virtual void unpack_module_data(BCP_buffer &buf)
Unpack data sent from the tree manager.
Definition: BB_lp.cpp:27
When doing a sprint sort of algorithm on the cuts (i.e., leave out a number of cuts at the beginning ...
Definition: BB_cut.hpp:19
BCP should continue to work on this node.
const double * x() const
int * set_zero
Variables that have been set to zero by branching decisions.
BCP_vec< double > * forced_var_bd
Contains the actual bounds for the variables indexed by forced_var_pos.
virtual void cuts_to_rows(const BCP_vec< BCP_var * > &vars, BCP_vec< BCP_cut * > &cuts, BCP_vec< BCP_row * > &rows, const BCP_lp_result &lpres, BCP_object_origin origin, bool allow_multiple)
Describes how to get a row of the matrix from the representation of the cut.
Definition: BB_lp.cpp:349
void push_back(const_reference x)
Append x to the end of the vector.
static char * j
Definition: OSdtoa.cpp:3622
real_user_data * p_rud
Pointer on an object holding the user data itself.
#define BCP_DBL_MAX
Definition: BCP_math.hpp:6
BCP_vec< BCP_user_data * > & user_data()
Return a reference to the user data vector.
virtual void initialize_new_search_tree_node(const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts, const BCP_vec< BCP_obj_status > &var_status, const BCP_vec< BCP_obj_status > &cut_status, BCP_vec< int > &var_changed_pos, BCP_vec< double > &var_new_bd, BCP_vec< int > &cut_changed_pos, BCP_vec< double > &cut_new_bd)
Initialize data members at the start of processing a new subproblem.
Definition: BB_lp.cpp:54
void fint fint fint real fint real real real real real real real real real fint real fint * lp
virtual BCP_branching_decision select_branching_candidates(const BCP_lp_result &lpres, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts, const BCP_lp_var_pool &local_var_pool, const BCP_lp_cut_pool &local_cut_pool, BCP_vec< BCP_lp_branching_object * > &cands, bool force_branch=false)
Decide whether to branch or not and select a set of branching candidates if branching is decided upon...
virtual BCP_solution * test_feasibility(const BCP_lp_result &lp_result, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts)
Test feasibility of the LP solution.
Definition: BB_lp.cpp:101
int card_set_zero
Number of variables set to zero by branching descisions.
int child_num
The number of children for this branching object.
Class handling user data.
void fint fint * k
This class describes a generic branching object.
BCP_branching_decision
This enumerative constant is the return value of the select_branching_candidates() method in [BCP_lp_...
Simple representation of a cut by storing non zero coefficients only.
Definition: BB_cut.hpp:64
Class taking care of interaction between user data and Bcp.
void add_entry(BCP_var *var, double value)
Append a variable and the corresponding value to the end of the appropriate vectors.
virtual BCP_solution * generate_heuristic_solution(const BCP_lp_result &lpres, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts)
Simple rounding heuristic.
Definition: BB_lp.cpp:234
virtual void modify_lp_parameters(OsiSolverInterface *lp, const int changeType, bool in_strong_branching)
Modify the parameters of the LP solver.
Definition: BB_lp.cpp:78
BCP_vec< int > * forced_var_pos
Positions of variables whose bounds change (&quot;forcibly&quot;, by branching) in the children.
virtual BCP_solution * test_feasibility(const BCP_lp_result &lp_result, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts)
Evaluate and return MIP feasibility of the current solution.
Currently there isn&#39;t any error handling in BCP.
Definition: BCP_error.hpp:20
int is_processed
Indicator for mmory management: If is_processed = 1, the associated user data may be erased...
A presolved branching object candidate.
size_t size() const
Return the current number of entries.
Definition: BCP_vector.hpp:116
This class describes the message buffer used for all processes of BCP.
Definition: BCP_buffer.hpp:39
int max_card_set_zero
Maximum number of variables that may be set to zero by branching decisions.
This class holds the results after solving an LP relaxation.
virtual void set_user_data_for_children(BCP_presolved_lp_brobj *best, const int selected)
Set up the user data for the children according to the chosen branching object.
Definition: BB_lp.cpp:457
Branching must be done.
BCP_lp_branching_object * candidate()
Return a pointer to the candidate.
This class holds a MIP feasible primal solution.
void fint fint fint real fint real * x
This class holds a row in a compressed form.
Definition: BCP_matrix.hpp:152
This is the abstract base class for a solution to a Mixed Integer Programming problem.