BCP_lp_msgproc.cpp
Go to the documentation of this file.
1 // Copyright (C) 2000, International Business Machines
2 // Corporation and others. All Rights Reserved.
3 #include <functional>
4 
5 #include "BCP_message.hpp"
6 #include "BCP_lp_user.hpp"
7 #include "BCP_lp_node.hpp"
8 #include "BCP_lp_pool.hpp"
9 #include "BCP_lp.hpp"
10 #include "BCP_lp_functions.hpp"
11 
12 //#############################################################################
13 
15 {
16  while (true){
17  // call receive with 0 timeout => nonblocking
18  p.msg_buf.clear();
20  if (p.msg_buf.msgtag() == BCP_Msg_NoMessage)
21  break;
23  }
24 }
25 
26 //#############################################################################
27 
28 void
30 {
31  BCP_cut* cut;
32  BCP_var* var;
33  const int cpid = node->cp;
34  const int vpid = node->vp;
35 
36  int node_index;
37  int node_itcnt;
38 
39  switch (msg_buf.msgtag()){
40  case BCP_Msg_User:
42  break;
43 
45  throw BCP_fatal_error("\
46 LP: BCP_Msg_InitialUserInfo arrived in BCP_lp_prob::process_message().\n");
47 
50  break;
51 
54  break;
55 
57  cut = unpack_cut();
59  // check if we already have this cut in the local cut pool
62  while (oldcut != lastoldcut){
63  switch (user->compare_cuts((*oldcut)->cut(), cut)){
65  case BCP_ObjsAreSame:
66  delete cut; cut = 0;
67  msg_buf.clear();
68  return;
70  case BCP_DifferentObjs:
71  ++oldcut;
72  break;
73  }
74  }
75  }
76 
77  if (no_more_cuts_cnt >= 0){ // we are waiting for cuts
78  const bool from_pool = (cpid == msg_buf.sender());
80  const int old_cp_size = cp.size();
81  BCP_vec<BCP_row*> rows;
82  rows.reserve(1);
83  BCP_vec<BCP_cut*> cuts(1, cut);
84  user->cuts_to_rows(node->vars, cuts, rows, *lp_result,
85  cpid == msg_buf.sender() ?
87  true);
88  const int cutnum = cuts.size();
89  for (int i = 0; i < cutnum; ++i) {
90  cut = cuts[i];
91  if (! from_pool)
92  cut->set_bcpind(-BCP_lp_next_cut_index(*this));
93  cut->dont_send_to_pool(cpid == -1 || from_pool);
94  cp.push_back(new BCP_lp_waiting_row(cut, rows[i]));
95  }
96  // compute the violation(s)
97  cp.compute_violations(*lp_result, cp.entry(old_cp_size), cp.end());
98  }else{ // the cut arrived while we are waiting for new LP
100  }
101  break;
102 
103  case BCP_Msg_NoMoreCuts:
104  // no more cuts can be generated for the current LP solution and hence
105  // calculation can resume
106  double cutgen_time;
107  msg_buf.unpack(node_index).unpack(node_itcnt).unpack(cutgen_time);
108  stat.time_cut_generation += cutgen_time;
109  if (no_more_cuts_cnt >= 0 &&
110  node->index == node_index && node->iteration_count == node_itcnt)
112  break;
113 
115  var = unpack_var();
117  // check if we already have this var in the local var pool
120  while (oldvar != lastoldvar){
121  switch (user->compare_vars((*oldvar)->var(), var)){
123  case BCP_ObjsAreSame:
124  delete var; var = 0;
125  msg_buf.clear();
126  return;
128  case BCP_DifferentObjs:
129  ++oldvar;
130  break;
131  }
132  }
133  }
134 
135  if (no_more_vars_cnt >= 0){ // we are waiting for vars
136  const bool from_pool = (vpid == msg_buf.sender());
138  const int old_vp_size = vp.size();
139  BCP_vec<BCP_col*> cols;
140  cols.reserve(1);
141  BCP_vec<BCP_var*> vars(1, var);
142  user->vars_to_cols(node->cuts, vars, cols, *lp_result,
143  vpid == msg_buf.sender() ?
145  true);
146  const int varnum = vars.size();
147  for (int i = 0; i < varnum; ++i) {
148  var = vars[i];
149  if (! from_pool)
150  var->set_bcpind(-BCP_lp_next_var_index(*this));
151  var->dont_send_to_pool(vpid == -1 || from_pool);
152  vp.push_back(new BCP_lp_waiting_col(var, cols[i]));
153  }
154  // compute the reduced_cost(s)
155  vp.compute_red_costs(*lp_result, vp.entry(old_vp_size), vp.end());
156  }else{ // the var arrived while we are waiting for new LP
158  }
159  break;
160 
161  case BCP_Msg_NoMoreVars:
162  // no more vars can be generated for the current LP solution and hence
163  // calculation can resume
164  double vargen_time;
165  msg_buf.unpack(node_index).unpack(node_itcnt).unpack(vargen_time);
166  stat.time_var_generation += vargen_time;
167  if (no_more_vars_cnt >= 0 &&
168  node->index == node_index && node->iteration_count == node_itcnt)
170  break;
171 
172  case BCP_Msg_UpperBound:
174  break;
175 
177  {
179  delete warmstartRoot;
181  delete ws;
182  }
183  break;
184 
187  // load the lp formulation into the lp solver
188  lp_solver = master_lp->clone();
189  if (node->colgen != BCP_GenerateColumns) {
190  // FIXME: If we had a flag in the node that indicates not to
191  // generate cols in it and in its descendants then the dual obj
192  // limit could still be set...
193  lp_solver->setDblParam(OsiDualObjectiveLimit, ub() - granularity());
194  }
195  BCP_lp_create_lp(*this);
196  BCP_lp_main_loop(*this);
197  delete lp_solver;
198  lp_solver = NULL;
199  break;
200 
201  case BCP_Msg_DivingInfo:
203  break;
204 
206  msg_buf.clear();
207  // First send back timing data for the previous phase
208  stat.pack(msg_buf);
209  msg_env->send(get_parent() /*ree_manager*/,
211  phase++;
212  break;
213 
214  case BCP_Msg_FinishedBCP:
215  // No need to clean up anything since the destructor of 'p' will do that.
216  // However, send back the statistics.
217  stat.pack(msg_buf);
218  msg_env->send(get_parent() /*ree_manager*/,
220  return;
221 
222  default:
223  printf("Unknown message type arrived to LP: %i\n", msg_buf.msgtag());
224  break;
225  }
226 
227  msg_buf.clear();
228 }
229 
230 //#############################################################################
231 
232 int
234 {
235  if (p.next_var_index == p.last_var_index) {
236  BCP_buffer& buf = p.msg_buf;
237  // get new set of indices
238  buf.clear();
239  p.msg_env->send(p.get_parent() /*ree_manager*/,
241  // In a single process environment the new index range has already
242  // been received (and unpacked), thus we've got to receive it only if
243  // the range still has length 0.
244  if (p.next_var_index == p.last_var_index) {
245  p.msg_env->receive(p.get_parent() /*ree_manager*/,
246  BCP_Msg_VarIndexSet, buf, -1);
247  p.process_message();
248  }
249  }
250  const int tmp = p.next_var_index++;
251  return tmp;
252 }
253 
254 //#############################################################################
255 
256 int
258 {
259  if (p.next_cut_index == p.last_cut_index) {
260  BCP_buffer& buf = p.msg_buf;
261  // get new set of indices
262  buf.clear();
263  p.msg_env->send(p.get_parent() /*ree_manager*/,
265  // In a single process environment the new index range has already
266  // been received (and unpacked), thus we've got to receive it only if
267  // the range still has length 0.
268  if (p.next_cut_index == p.last_cut_index) {
269  p.msg_env->receive(p.get_parent() /*ree_manager*/,
270  BCP_Msg_CutIndexSet, buf, -1);
271  p.process_message();
272  }
273  }
274  const int tmp = p.next_cut_index++;
275  return tmp;
276 }
277 
278 //#############################################################################
279 
281 {
282  double new_ub;
283  buf.unpack(new_ub);
284  if (p.ub(new_ub) && p.lp_solver && p.node &&
286  // FIXME: If we had a flag in the node that indicates not to
287  // generate cols in it and in its descendants then the dual obj
288  // limit could still be set...
289  p.lp_solver->setDblParam(OsiDualObjectiveLimit,new_ub-p.granularity());
290  }
291 }
292 
293 //#############################################################################
294 
295 void BCP_lp_send_cuts_to_cp(BCP_lp_prob& p, const int eff_cnt_limit)
296 {
297  if (p.node->cp != -1) // go back if no cut pool exists
298  return;
299 
300  BCP_cut_set& cuts = p.node->cuts;
301  BCP_cut_set::iterator cuti = cuts.entry(p.core->cutnum());
302  const BCP_cut_set::const_iterator lastcuti = cuts.end();
303  BCP_cut* cut;
304  int cnt;
305 
306  // First count how many to send
307  for (cnt = 0; cuti != lastcuti; ++cuti) {
308  cut = *cuti;
309  if (cut->effective_count() >= eff_cnt_limit &&
310  ! cut->dont_send_to_pool())
311  ++cnt;
312  }
313 
314  if (cnt > 0){
315  BCP_buffer& buf = p.msg_buf;
316  buf.clear();
317  buf.pack(cnt);
318  // whatever is sent to the CP must have been generated at this level
319  buf.pack(p.node->level);
320  // pack the cuts
321  cuti = cuts.entry(p.core->cutnum());
322  for ( ; cuti != lastcuti; ++cuti) {
323  cut = *cuti;
324  if (cut->effective_count() >= eff_cnt_limit &&
325  ! cut->dont_send_to_pool())
326  p.pack_cut(*cut);
327  cut->dont_send_to_pool(true);
328  }
329 
330  if (p.node->cp != -1) {
333  printf("LP: %i cuts sent to cutpool\n", cnt);
334  }
335  }
336 }
337 
338 //#############################################################################
339 
341 {
342  buf.unpack(p.node->dive); // what's the new diving status?
343  if (p.node->dive != BCP_DoNotDive){
344  // do dive
345  buf.unpack(p.node->index);
346  // finally, a little cleaning for the new node
347  p.node->level++;
348  p.node->iteration_count = 0;
349  } else {
350  p.node->index = -1;
351  }
352 }
virtual void send(const int target, const BCP_message_tag tag)=0
Send an empty message (message tag only) to the process given by the frist argument.
Print the number of cuts sent from the LP to the cut pool.
BCP_buffer & pack(const T &value)
Pack a single object of type T.
Definition: BCP_buffer.hpp:177
BCP has finished.
The message contains the description of a cut.
BCP_lp_node * node
Description he current search tree node.
Definition: BCP_lp.hpp:168
void BCP_lp_unpack_active_node(BCP_lp_prob &p, BCP_buffer &buf)
Used to indicate that there is no message in the buffer of a process.
BCP_buffer & unpack(T &value)
Unpack a single object of type T.
Definition: BCP_buffer.hpp:186
void BCP_lp_unpack_diving_info(BCP_lp_prob &p, BCP_buffer &buf)
virtual void process_message(BCP_buffer &buf)
Process a message that has been sent by another process&#39; user part to this process&#39; user part...
virtual void receive(const int source, const BCP_message_tag tag, BCP_buffer &buf, const double timeout)=0
Blocking receive with timeout.
char param(BCP_lp_par::chr_params key) const
Definition: BCP_lp.hpp:275
bool dont_send_to_pool() const
Return whether the cut should be sent to the Cut Pool process.
Definition: BCP_cut.hpp:95
int BCP_lp_next_var_index(BCP_lp_prob &p)
int last_cut_index
Definition: BCP_lp.hpp:203
const int BCP_AnyProcess
Definition: BCP_message.hpp:21
BCP_var_set vars
double granularity() const
Definition: BCP_lp.hpp:289
The message contains the statistics the LP process collected.
Abstract base class that defines members common to all types of cuts.
Definition: BCP_cut.hpp:29
BCP_lp_statistics stat
Definition: BCP_lp.hpp:213
void set_bcpind(const int bcpind)
Set the internal index of the cut.
Definition: BCP_cut.hpp:149
Request an index set for variables to be genarated.
If true then the LP process will check each newly received cut whether it already exists in the local...
Request an index set for cuts to be generated.
void set_bcpind(const int bcpind)
Set the internal index of the variable.
Definition: BCP_var.hpp:176
OsiSolverInterface * master_lp
A class that holds the methods about how to pack things.
Definition: BCP_lp.hpp:135
BCP_diving_status dive
TM sends the description of a new search tree node.
virtual void process_message()
The two objects are the same.
Definition: BCP_enum.hpp:278
int sender() const
Return a const pointer to the process id of the sender of the message in the buffer.
Definition: BCP_buffer.hpp:93
iterator begin()
Return an iterator to the beginning of the object.
Definition: BCP_vector.hpp:99
int last_var_index
Definition: BCP_lp.hpp:199
NO OLD DOC.
Definition: BCP_lp.hpp:102
This class is just a collection of pointers to cuts with a number of methods to manipulate these cuts...
Definition: BCP_cut.hpp:279
void reserve(const size_t n)
Reallocate the object to make space for n entries.
virtual BCP_warmstart * unpack_warmstart(BCP_buffer &buf, bool report_if_default=false)
Unpack warmstarting information.
Definition: BCP_USER.hpp:74
TM sends diving information.
int next_cut_index
Definition: BCP_lp.hpp:201
Warmstarting information for the LP solver.
double time_var_generation
Definition: BCP_lp.hpp:63
void push_back(const_reference x)
Append x to the end of the vector.
Attempt column generation.
Definition: BCP_enum.hpp:73
BCP_cut_set cuts
int no_more_cuts_cnt
Definition: BCP_lp.hpp:226
virtual void vars_to_cols(const BCP_vec< BCP_cut * > &cuts, BCP_vec< BCP_var * > &vars, BCP_vec< BCP_col * > &cols, const BCP_lp_result &lpres, BCP_object_origin origin, bool allow_multiple)
Convert a set of variables into corresponding columns for the current LP relaxation.
BCP_lp_cut_pool * local_cut_pool
Definition: BCP_lp.hpp:193
int BCP_lp_next_cut_index(BCP_lp_prob &p)
BCP_lp_user * user
A class that holds the methods about how to pack things.
Definition: BCP_lp.hpp:131
virtual BCP_object_compare_result compare_vars(const BCP_var *v0, const BCP_var *v1)
Compare two generated variables.
virtual BCP_object_compare_result compare_cuts(const BCP_cut *c0, const BCP_cut *c1)
Compare two generated cuts.
OsiSolverInterface * lp_solver
A class that holds the methods about how to pack things.
Definition: BCP_lp.hpp:137
BCP_lp_result * lp_result
Definition: BCP_lp.hpp:185
CoinWarmStart * warmstartRoot
Description of the warmstart info from the end of the root node.
Definition: BCP_lp.hpp:174
size_t cutnum() const
Return the number of cuts in the core.
void BCP_lp_send_cuts_to_cp(BCP_lp_prob &p, const int eff_cnt_limit)
void compute_violations(const BCP_lp_result &lpres, BCP_lp_cut_pool::iterator first, BCP_lp_cut_pool::iterator last)
Definition: BCP_lp_pool.hpp:62
void BCP_lp_process_ub_message(BCP_lp_prob &p, BCP_buffer &buf)
The warmstart information at the end of the root.
The message contains the description of a variable.
void BCP_lp_create_lp(BCP_lp_prob &p)
int get_parent() const
Definition: BCP_process.hpp:25
virtual CoinWarmStart * convert_to_CoinWarmStart() const =0
Return an OsiWarmStart object that can be fed to the LP engine.
double ub() const
Definition: BCP_lp.hpp:300
The TM sends the initial user packed information to the slave process.
TM warns an LP process that the second phase will start.
BCP_lp_var_pool * local_var_pool
Definition: BCP_lp.hpp:191
void clear()
Completely clear the buffer.
Definition: BCP_buffer.hpp:168
BCP_message_tag msgtag() const
Return the message tag of the message in the buffer.
Definition: BCP_buffer.hpp:90
If true then the LP process will check each newly arrived variable whether it already exists in the l...
void fint fint fint real fint real real real real real real real real real fint real fint fint fint real * ws
The object is from a variable or cut pool.
Definition: BCP_enum.hpp:259
No more (violated) cuts could be found.
The two objects are comparable but the first object is better.
Definition: BCP_enum.hpp:280
void pack_cut(const BCP_cut &cut)
Definition: BCP_lp.cpp:174
Abstract base class that defines members common to all types of variables.
Definition: BCP_var.hpp:28
int effective_count() const
Return the effectiveness count of the cut (only in LP process).
Definition: BCP_cut.hpp:80
Currently there isn&#39;t any error handling in BCP.
Definition: BCP_error.hpp:20
BCP_cut * unpack_cut()
Definition: BCP_lp.cpp:197
bool dont_send_to_pool() const
Return whether the variable should be sent to the Variable Pool process.
Definition: BCP_var.hpp:102
void BCP_lp_check_ub(BCP_lp_prob &p)
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...
The object was generated by a variable or cut generator.
Definition: BCP_enum.hpp:257
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
Send index set for cuts to be generated in the future.
BCP_column_generation colgen
BCP_var * unpack_var()
Definition: BCP_lp.cpp:140
After branching all children must be returned to the Tree Manager and the LP process should wait for ...
This class describes the message buffer used for all processes of BCP.
Definition: BCP_buffer.hpp:39
No more (improving) variables could be found.
The two objects are not comparable or neither is better than the other.
Definition: BCP_enum.hpp:285
int no_more_vars_cnt
Definition: BCP_lp.hpp:230
BCP_problem_core * core
Definition: BCP_lp.hpp:153
The message contains cuts for the Cut Pool process.
Used by the user to send a message to the user portion of the other process.
void BCP_lp_main_loop(BCP_lp_prob &p)
Send index set for variables to be generated in the future.
BCP_message_environment * msg_env
A class that holds the methods about how to pack things.
Definition: BCP_lp.hpp:139
Any process to TM or TM to any process: a new upper bound found.
iterator entry(const int i)
Return an iterator to the i-th entry.
Definition: BCP_vector.hpp:109
The two objects are comparable but the second object is better.
Definition: BCP_enum.hpp:282
void pack(BCP_buffer &buf)
Definition: BCP_lp.cpp:21
double time_cut_generation
Definition: BCP_lp.hpp:61
BCP_buffer msg_buf
Definition: BCP_lp.hpp:239
int next_var_index
Definition: BCP_lp.hpp:197
void compute_red_costs(const BCP_lp_result &lpres, BCP_lp_var_pool::iterator first, BCP_lp_var_pool::iterator last)
BCP_user_pack * packer
A class that holds the methods about how to pack things.
Definition: BCP_lp.hpp:133