BM_lp.cpp
Go to the documentation of this file.
1 // (C) Copyright International Business Machines Corporation 2006, 2007
2 // All Rights Reserved.
3 // This code is published under the Eclipse Public License.
4 //
5 // Authors :
6 // Laszlo Ladanyi, International Business Machines Corporation
7 // Pierre Bonami, Carnegie Mellon University
8 
9 #include "OsiClpSolverInterface.hpp"
10 #include "BM.hpp"
11 #include "BCP_message_mpi.hpp"
12 #include "BCP_lp_node.hpp"
13 #include "BCP_lp.hpp"
14 
15 #include "BonOACutGenerator2.hpp"
16 #include "BonEcpCuts.hpp"
17 #include "BonOaNlpOptim.hpp"
18 
19 // The following is included for "min"
20 #include "CoinFinite.hpp"
21 
22 #ifndef BM_DEBUG_PRINT
23 #define BM_DEBUG_PRINT 0
24 #endif
25 
26 static char prefix[100];
27 
28 //#############################################################################
29 
31  BCP_lp_user(),
32  in_strong(0),
33  bonmin_(),
34  objInd_(NULL),
35  objNum_(0),
36  infInd_(NULL),
37  infUseful_(NULL),
38  infNum_(0),
39  feasInd_(NULL),
40  feasUseful_(NULL),
41  feasNum_(0),
42  sbResult_(NULL),
43  bestSbResult_(NULL)
44 {
45 }
46 
47 /****************************************************************************/
48 
50 {
51  delete[] objInd_;
52  delete[] infInd_;
53  delete[] infUseful_;
54  delete[] feasInd_;
55  delete[] feasUseful_;
56  delete[] sbResult_;
57 }
58 
59 /****************************************************************************/
60 
61 OsiSolverInterface *
63 {
64 #ifdef COIN_HAS_MPI
65  sprintf(prefix, "%i", getLpProblemPointer()->get_process_id());
66 #else
67  prefix[0] = 0;
68 #endif
69 
70  OsiSolverInterface* solver = NULL;
71  if (bonmin_.getAlgorithm() == 0) {
72  // Pure B&B
73  solver = bonmin_.nonlinearSolver()->clone();
74  } else {
75  OsiClpSolverInterface * clp = new OsiClpSolverInterface;
76  OsiBabSolver babSolver(3);
77  babSolver.setSolver(clp);
78  clp->setAuxiliaryInfo(&babSolver);
79  clp->messageHandler()->setLogLevel(0);
80  setOsiBabSolver(dynamic_cast<OsiBabSolver *>(clp->getAuxiliaryInfo()));
81  solver = clp;
82  }
83  return solver;
84 }
85 
86 /****************************************************************************/
87 
88 void
90  const BCP_vec<BCP_cut*>& cuts,
91  const BCP_vec<BCP_obj_status>& vs,
92  const BCP_vec<BCP_obj_status>& cs,
93  BCP_vec<int>& var_changed_pos,
94  BCP_vec<double>& var_new_bd,
95  BCP_vec<int>& cut_changed_pos,
96  BCP_vec<double>& cut_new_bd)
97 {
98  node_start_time = CoinWallclockTime();
99  BM_node* data = dynamic_cast<BM_node*>(get_user_data());
101 
102  if (bonmin_.getAlgorithm() != 0) {
103  // Not pure BB, so an LP solver will be used. Now we have to...
104 
105  // First copy the bounds into nlp. That way all the branching decisions
106  // will be transferred over.
107  int i;
108 
109  OsiSolverInterface * osi = getLpProblemPointer()->lp_solver;
111  nlp.setColLower(osi->getColLower());
112  nlp.setColUpper(osi->getColUpper());
113 
114  // Carry the changes over to the object lists in nlp
115  const int numObj = nlp.numberObjects();
116  OsiObject** nlpObj = nlp.objects();
117  for (i = 0; i < numObj; ++i) {
118  OsiSimpleInteger* io = dynamic_cast<OsiSimpleInteger*>(nlpObj[i]);
119  if (io) {
120  io->resetBounds(&nlp);
121  } else {
122  // The rest is OsiSOS where we don't need to do anything
123  break;
124  }
125  }
126 
127  // copy over the OsiObjects from the nlp solver
128  osi->addObjects(nlp.numberObjects(), nlp.objects());
129  }
130 
131  in_strong = 0;
132 }
133 
134 /************************************************************************/
135 void
136 BM_lp::load_problem(OsiSolverInterface& osi, BCP_problem_core* core,
137  BCP_var_set& vars, BCP_cut_set& cuts)
138 {
139  if (bonmin_.getAlgorithm() != 0) {
140  // We are doing hybrid, so osi is an LP solver. Call the default.
141  BCP_lp_user::load_problem(osi, core, vars, cuts);
142  return;
143  }
144  // Otherwise we do B&B and osi is an NLP solver.
145  // There is no need to fill it with the data from bonmin_.nonlinearSolver()
146  // since osi is a clone() of the master_lp in the BCP_lp object, and the
147  // master_lp is a clone() of bonmin_.nonlinearSolver(), and that clone()
148  // copies the data as well.
149 }
150 
151 /************************************************************************/
152 void
153 BM_lp::modify_lp_parameters(OsiSolverInterface* lp, bool in_strong_branching)
154  // Called each time the node LP is solved
155 {
156  if (in_strong_branching) {
157  in_strong = 1;
158  // lp->setIntParam(OsiMaxNumIterationHotStart, 50);
159  }
160 }
161 
162 /****************************************************************************/
163 
166  const BCP_vec<BCP_var*>& vars,
167  const BCP_vec<BCP_cut*>& cuts)
168 {
169  if (bonmin_.getAlgorithm() == 0) {
170  // if pure B&B
171  return test_feasibility_BB(lp_result, vars);
172  } else {
173  return test_feasibility_hybrid(lp_result, vars, cuts);
174  }
175  return NULL; // fake return to quiet gcc
176 }
177 
178 /****************************************************************************/
179 
182  const BCP_vec<BCP_var*>& vars)
183 {
184  // We can just take the primal solution and test whether it satisfies
185  // integrality requirements
186  BCP_solution_generic* sol = test_full(lpres, vars, integerTolerance_);
187  if (sol) {
188  sol->set_objective_value(lpres.objval());
189 #if (BM_DEBUG_PRINT != 0)
190  printf("LP %.3f: Solution found. node: %i depth: %i value: %f\n",
191  CoinWallclockTime() - start_time(),
192  current_index(), current_level(), lpres.objval());
193 #endif
194  }
195  return sol;
196 }
197 
198 /****************************************************************************/
199 
202  const BCP_vec<BCP_var*>& vars,
203  const BCP_vec<BCP_cut*>& cuts)
204 {
205  /* First test that the integrality requirements are met. */
206  BCP_solution_generic* gsol = test_full(lp_result, vars, integerTolerance_);
207  if (! gsol) {}
208 
209  /* TODO:
210  don't test feasibility in every node
211  */
212 
213 
214  OsiSolverInterface * osi = getLpProblemPointer()->lp_solver;
215 
216  // Don't test feasibility if the node LP was infeasible
217  if (osi->isProvenPrimalInfeasible() ) {
218  return NULL;
219  }
220 
221  // The babSolver info used is the one containted in osi
222  OsiBabSolver * babSolver =
223  dynamic_cast<OsiBabSolver *> (osi->getAuxiliaryInfo());
224  babSolver->setSolver(*bonmin_.nonlinearSolver());
225  //Last cut generator is used to check feasibility
226  bonmin_.cutGenerators().back().cgl->generateCuts(*osi, cuts_);
227  const int numvar = vars.size();
228  double* solverSol = new double[numvar];
229  double objValue = 1e200;
230 
231  BCP_solution_generic* sol = NULL;
232  if (babSolver->solution(objValue, solverSol, numvar)) {
233  sol = new BCP_solution_generic(false);
234  // Just copy the solution stored in solver to sol
235  for (int i = 0 ; i < numvar ; i++) {
236  if (solverSol[i] > lp_result.primalTolerance())
237  sol->add_entry(vars[i], solverSol[i]);
238  }
239  sol->set_objective_value(objValue);
240  }
241  delete[] solverSol;
242  return sol;
243 }
244 
245 /****************************************************************************/
246 
247 void
249  const BCP_vec<BCP_var*>& vars,
250  const BCP_vec<BCP_cut*>& cuts,
251  BCP_vec<BCP_cut*>& new_cuts,
252  BCP_vec<BCP_row*>& new_rows)
253 {
254  if (bonmin_.getAlgorithm() > 0) { /* if not pure B&B */
255  /* TODO:
256  don't invoke all of them, only the *good* ones. figure out
257  some measurement of how good a generator is.
258  */
259 
260  OsiSolverInterface& si = *getLpProblemPointer()->lp_solver;
261  double rand;
262  Bonmin::BabSetupBase::CuttingMethods::const_iterator end = bonmin_.cutGenerators().end();
263  end--;//have to go back one element because last cut generator checks feasibility
264 
265  /* FIXME: fill out the tree info! */
266  CglTreeInfo info;
267  for(Bonmin::BabSetupBase::CuttingMethods::const_iterator i = bonmin_.cutGenerators().begin() ;
268  i != end ; i++){
269  rand = 1 - CoinDrand48();
270  if(i->frequency > rand){
271  i->cgl->generateCuts(si, cuts_, info);
272  }
273  }
274 
275  // fill cuts
276  // eventually fill rows if not in strong branching
277  int numCuts = cuts_.sizeRowCuts();
278  for(int i = 0 ; i < numCuts ; i++) {
279  const OsiRowCut& cut = cuts_.rowCut(i);
280  new_cuts.push_back(new BB_cut(cut));
281  const CoinPackedVector& row = cut.row();
282  new_rows.push_back(new BCP_row(row, cut.lb(), cut.ub()));
283  }
284  }
285  cuts_.dumpCuts();
286 }
287 
288 /****************************************************************************/
289 
290 void
291 BM_lp::cuts_to_rows(const BCP_vec<BCP_var*>& vars, // on what to expand
292  BCP_vec<BCP_cut*>& cuts, // what to expand
293  BCP_vec<BCP_row*>& rows, // the expanded rows
294  // things that the user can use for lifting cuts if allowed
295  const BCP_lp_result& lpres,
296  BCP_object_origin origin, bool allow_multiple)
297 {
298  const int numCuts = cuts.size();
299  for (int i = 0; i < numCuts; ++i) {
300  BB_cut* cut = dynamic_cast<BB_cut*>(cuts[i]);
301  if (!cut) {
302  throw BCP_fatal_error("Non-\"BB_cut\" in cuts_to_rows!\n");
303  }
304  const CoinPackedVector& row = cut->row();
305  rows.push_back(new BCP_row(row, cuts[i]->lb(), cuts[i]->ub()));
306  }
307  cuts_.dumpCuts();
308 }
309 
310 /****************************************************************************/
311 
312 double
313 BM_lp::compute_lower_bound(const double old_lower_bound,
314  const BCP_lp_result& lpres,
315  const BCP_vec<BCP_var*>& vars,
316  const BCP_vec<BCP_cut*>& cuts)
317 {
318  double bd;
319  if (bonmin_.getAlgorithm() == 0) {
320  /* if pure B&B */
321  bd = lpres.objval();
322  } else {
323  /* FIXME: what the heck was this...
324  bd = CoinMax(babSolver_.mipBound(), lpres.objval());
325  */
326  }
327  return CoinMax(bd, old_lower_bound);
328 }
329 
330 /*---------------------------------------------------------------------------*/
BCP_object_origin
This enumerative constant describes the origin (originating process) of an object (variable or cut)...
Definition: BCP_enum.hpp:249
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)
Convert (and possibly lift) a set of cuts into corresponding rows for the current LP relaxation...
Definition: BM_lp.cpp:291
This class describes the core of the MIP problem, the variables/cuts in it as well as the matrix corr...
double * feasUseful_
Definition: BM.hpp:317
Definition: BM.hpp:26
void setOsiBabSolver(OsiBabSolver *ptr)
Definition: BCP_lp_user.hpp:98
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 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.
Definition: BM_lp.cpp:165
BM_lp()
Definition: BM_lp.cpp:30
virtual void load_problem(OsiSolverInterface &osi, BCP_problem_core *core, BCP_var_set &vars, BCP_cut_set &cuts)
Load the problem specified by core, vars, and cuts into the solver interface.
Definition: BM_lp.cpp:136
This is class provides an Osi interface for a Mixed Integer Linear Program expressed as a TMINLP (so ...
OsiSolverInterface * clone(bool copyData=true) const
Virtual copy constructor.
double node_start_time
The time when we started to process the node.
Definition: BM.hpp:327
int current_level() const
Return the level of the search tree node being processed.
Definition: BCP_lp_user.cpp:32
int current_index() const
Return the internal index of the search tree node being processed.
Definition: BCP_lp_user.cpp:33
OsiCuts cuts_
Definition: BM.hpp:297
double start_time() const
Return when the LP process started.
Definition: BCP_lp_user.cpp:35
This class is just a collection of pointers to cuts with a number of methods to manipulate these cuts...
Definition: BCP_cut.hpp:279
int in_strong
Definition: BM.hpp:278
void push_back(const_reference x)
Append x to the end of the vector.
The BCP_lp_user class is the base class from which the user can derive a problem specific class to be...
Definition: BCP_lp_user.hpp:75
void set_objective_value(double v)
Set the objective value of the solution.
virtual void modify_lp_parameters(OsiSolverInterface *lp, bool in_strong_branching)
Definition: BM_lp.cpp:153
int * feasInd_
Definition: BM.hpp:316
int numNlpFailed_
A counter for how many times in a row did the NLP code fail.
Definition: BM.hpp:295
virtual void setColUpper(int elementIndex, double elementValue)
Set a single column upper bound.
Bonmin::Algorithm getAlgorithm()
Get the algorithm used.
virtual OsiSolverInterface * initialize_solver_interface()
Create LP solver environment.
Definition: BM_lp.cpp:62
double integerTolerance_
Definition: BM.hpp:289
Bonmin::BonminAmplSetup bonmin_
This contains the setup for running Bonmin in particular nlp solver, continuous solver, cut generators,...
Definition: BM.hpp:287
int * infInd_
Every time when branching decisions are to be made, we create 6 arrays, 3 for those objects that are ...
Definition: BM.hpp:313
int numNlpFailed_
A counter for how many times in a row did the NLP code fail.
Definition: BM.hpp:32
BCP_solution * test_feasibility_hybrid(const BCP_lp_result &lp_result, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts)
Definition: BM_lp.cpp:201
BCP_user_data * get_user_data()
Return a pointer to the BCP_user_data structure the user (may have) stored in this node...
Definition: BCP_lp_user.cpp:36
double primalTolerance() const
Return the primal tolerance of the solver.
void fint fint fint real fint real real real real real real real real real fint real fint * lp
BCP_lp_prob * getLpProblemPointer()
Get the pointer.
Definition: BCP_lp_user.hpp:95
fint end
OsiSolverInterface * lp_solver
A class that holds the methods about how to pack things.
Definition: BCP_lp.hpp:137
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 > &vs, const BCP_vec< BCP_obj_status > &cs, BCP_vec< int > &var_changed_pos, BCP_vec< double > &var_new_bd, BCP_vec< int > &cut_changed_pos, BCP_vec< double > &cut_new_bd)
Initializing a new search tree node.
Definition: BM_lp.cpp:89
double objval() const
Simple representation of a cut by storing non zero coefficients only.
Definition: BB_cut.hpp:64
void add_entry(BCP_var *var, double value)
Append a variable and the corresponding value to the end of the appropriate vectors.
int * objInd_
These are the indices of the integral (i.e., things that can be branched on) objects in the solver...
Definition: BM.hpp:302
Currently there isn&#39;t any error handling in BCP.
Definition: BCP_error.hpp:20
double * infUseful_
Definition: BM.hpp:314
size_t size() const
Return the current number of entries.
Definition: BCP_vector.hpp:116
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)
Generate cuts within the LP process.
Definition: BM_lp.cpp:248
This class is just a collection of pointers to variables with a number of methods to manipulate these...
Definition: BCP_var.hpp:316
virtual ~BM_lp()
Definition: BM_lp.cpp:49
OsiTMINLPInterface * nonlinearSolver()
Pointer to the non-linear solver used.
BCP_solution * test_feasibility_BB(const BCP_lp_result &lp_result, const BCP_vec< BCP_var * > &vars)
Definition: BM_lp.cpp:181
static char prefix[100]
Definition: BM_lp.cpp:26
BM_SB_result * sbResult_
This is where we keep the results in case of distributed strong branching.
Definition: BM.hpp:322
This class holds the results after solving an LP relaxation.
virtual double compute_lower_bound(const double old_lower_bound, const BCP_lp_result &lpres, const BCP_vec< BCP_var * > &vars, const BCP_vec< BCP_cut * > &cuts)
Compute a true lower bound for the subproblem.
Definition: BM_lp.cpp:313
virtual void setColLower(int elementIndex, double elementValue)
Set a single column lower bound.
virtual void load_problem(OsiSolverInterface &osi, BCP_problem_core *core, BCP_var_set &vars, BCP_cut_set &cuts)
Load the problem specified by core, vars, and cuts into the solver interface.
This class holds a MIP feasible primal solution.
CuttingMethods & cutGenerators()
list of cutting planes methods to apply with their frequencies.
BCP_solution_generic * test_full(const BCP_lp_result &lpres, const BCP_vec< BCP_var * > &vars, const double etol) const
Test whether the variables specified as integers are really integer.
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.