Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members

BCP_lp_msgproc.cpp

00001 // Copyright (C) 2000, International Business Machines
00002 // Corporation and others.  All Rights Reserved.
00003 #include <functional>
00004 
00005 #include "BCP_message.hpp"
00006 #include "BCP_lp_user.hpp"
00007 #include "BCP_lp_node.hpp"
00008 #include "BCP_lp_pool.hpp"
00009 #include "BCP_lp.hpp"
00010 #include "BCP_lp_functions.hpp"
00011 
00012 //#############################################################################
00013 
00014 void BCP_lp_check_ub(BCP_lp_prob& p)
00015 {
00016    while (true){
00017       // call receive with 0 timeout => nonblocking
00018       p.msg_buf.clear();
00019       p.msg_env->receive(BCP_AnyProcess, BCP_Msg_UpperBound, p.msg_buf, 0);
00020       if (p.msg_buf.msgtag() == BCP_Msg_NoMessage)
00021          break;
00022       BCP_lp_process_ub_message(p, p.msg_buf);
00023    }
00024 }
00025 
00026 //#############################################################################
00027 
00028 void
00029 BCP_lp_prob::process_message()
00030 {
00031    BCP_cut* cut;
00032    BCP_var* var;
00033    const BCP_proc_id * cpid = node->cp;
00034    const BCP_proc_id * vpid = node->vp;
00035    bool dont_send_to_pool;
00036 
00037    int node_index;
00038    int node_itcnt;
00039 
00040    switch (msg_buf.msgtag()){
00041     case BCP_Msg_InitialUserInfo:
00042       throw BCP_fatal_error("\
00043 LP: BCP_Msg_InitialUserInfo arrived in BCP_lp_prob::process_message().\n");
00044 
00045     case BCP_Msg_CutIndexSet:
00046       msg_buf.unpack(next_cut_index).unpack(last_cut_index);
00047       break;
00048 
00049     case BCP_Msg_VarIndexSet:
00050       msg_buf.unpack(next_var_index).unpack(last_var_index);
00051       break;
00052 
00053     case BCP_Msg_CutDescription:
00054       cut = unpack_cut();
00055       if (param(BCP_lp_par::CompareNewCutsToOldOnes)){
00056          // check if we already have this cut in the local cut pool
00057          BCP_lp_cut_pool::iterator oldcut = local_cut_pool->begin();
00058          BCP_lp_cut_pool::iterator lastoldcut = local_cut_pool->end();
00059          while (oldcut != lastoldcut){
00060             switch (user->compare_cuts((*oldcut)->cut(), cut)){
00061              case BCP_FirstObjIsBetter:
00062              case BCP_ObjsAreSame:
00063                delete cut;   cut = 0;
00064                msg_buf.clear();
00065                return;
00066              case BCP_SecondObjIsBetter:
00067              case BCP_DifferentObjs:
00068                ++oldcut;
00069                break;
00070             }
00071          }
00072       }
00073 
00074       dont_send_to_pool =
00075          (! cpid || (cpid && cpid->is_same_process(msg_buf.sender())));
00076       if (no_more_cuts_cnt >= 0){ // we are waiting for cuts
00077          BCP_lp_cut_pool& cp = *local_cut_pool;
00078          const int old_cp_size = cp.size();
00079          BCP_vec<BCP_row*> rows;
00080          rows.reserve(1);
00081          BCP_vec<BCP_cut*> cuts(1, cut);
00082          user->cuts_to_rows(node->vars, cuts, rows, *lp_result,
00083                             cpid && cpid->is_same_process(msg_buf.sender()) ?
00084                             BCP_Object_FromPool : BCP_Object_FromGenerator,
00085                             true);
00086          const int cutnum = cuts.size();
00087          for (int i = 0; i < cutnum; ++i) {
00088             cut = cuts[i];
00089             cut->set_bcpind(-BCP_lp_next_cut_index(*this));
00090             cut->dont_send_to_pool(dont_send_to_pool);
00091             cp.push_back(new BCP_lp_waiting_row(cut, rows[i]));
00092          }
00093          // compute the violation(s)
00094          cp.compute_violations(*lp_result, cp.entry(old_cp_size), cp.end());
00095       }else{ // the cut arrived while we are waiting for new LP
00096          local_cut_pool->push_back(new BCP_lp_waiting_row(cut));
00097       }
00098       break;
00099 
00100     case BCP_Msg_NoMoreCuts:
00101       // no more cuts can be generated for the current LP solution and hence
00102       // calculation can resume
00103       double cutgen_time;
00104       msg_buf.unpack(node_index).unpack(node_itcnt).unpack(cutgen_time);
00105       stat.time_cut_generation += cutgen_time;
00106       if (no_more_cuts_cnt >= 0 &&
00107           node->index == node_index && node->iteration_count == node_itcnt)
00108          no_more_cuts_cnt--;
00109       break;
00110 
00111     case BCP_Msg_VarDescription:
00112       var = unpack_var();
00113       if (param(BCP_lp_par::CompareNewVarsToOldOnes)){
00114          // check if we already have this var in the local var pool
00115          BCP_lp_var_pool::iterator oldvar = local_var_pool->begin();
00116          BCP_lp_var_pool::iterator lastoldvar = local_var_pool->end();
00117          while (oldvar != lastoldvar){
00118             switch (user->compare_vars((*oldvar)->var(), var)){
00119              case BCP_FirstObjIsBetter:
00120              case BCP_ObjsAreSame:
00121                delete var;   var = 0;
00122                msg_buf.clear();
00123                return;
00124              case BCP_SecondObjIsBetter:
00125              case BCP_DifferentObjs:
00126                ++oldvar;
00127                break;
00128             }
00129          }
00130       }
00131 
00132       dont_send_to_pool =
00133          (! vpid || (vpid && vpid->is_same_process(msg_buf.sender())));
00134       if (no_more_vars_cnt >= 0){ // we are waiting for vars
00135          BCP_lp_var_pool& vp = *local_var_pool;
00136          const int old_vp_size = vp.size();
00137          BCP_vec<BCP_col*> cols;
00138          cols.reserve(1);
00139          BCP_vec<BCP_var*> vars(1, var);
00140          user->vars_to_cols(node->cuts, vars, cols, *lp_result,
00141                             vpid && vpid->is_same_process(msg_buf.sender()) ?
00142                             BCP_Object_FromPool : BCP_Object_FromGenerator,
00143                             true);
00144          const int varnum = vars.size();
00145          for (int i = 0; i < varnum; ++i) {
00146             var = vars[i];
00147             var->set_bcpind(-BCP_lp_next_var_index(*this));
00148             var->dont_send_to_pool(dont_send_to_pool);
00149             vp.push_back(new BCP_lp_waiting_col(var, cols[i]));
00150          }
00151          // compute the reduced_cost(s)
00152          vp.compute_red_costs(*lp_result, vp.entry(old_vp_size), vp.end());
00153       }else{ // the var arrived while we are waiting for new LP
00154          local_var_pool->push_back(new BCP_lp_waiting_col(var));
00155       }
00156       break;
00157 
00158     case BCP_Msg_NoMoreVars:
00159       // no more vars can be generated for the current LP solution and hence
00160       // calculation can resume
00161       double vargen_time;
00162       msg_buf.unpack(node_index).unpack(node_itcnt).unpack(vargen_time);
00163       stat.time_var_generation += vargen_time;
00164       if (no_more_vars_cnt >= 0 &&
00165           node->index == node_index && node->iteration_count == node_itcnt)
00166          no_more_vars_cnt--;
00167       break;
00168 
00169     case BCP_Msg_UpperBound:
00170       BCP_lp_process_ub_message(*this, msg_buf);
00171       break;
00172 
00173 #if 0
00174     case BCP_Msg_RootToPrice:
00175       BCP_lp_unpack_active_node(*this, msg_buf);
00176       // load the lp formulation into the lp solver
00177       BCP_lp_create_lp(p);
00178       BCP_lp_repricing(p);
00179       lp_solver->unload_lp();
00180       break;
00181 #endif
00182 
00183     case BCP_Msg_ActiveNodeData:
00184       BCP_lp_unpack_active_node(*this, msg_buf);
00185       // load the lp formulation into the lp solver
00186       lp_solver = master_lp->clone();
00187       if (! param(BCP_lp_par::SolveLpToOptimality))
00188          lp_solver->setDblParam(OsiDualObjectiveLimit, ub() - granularity());
00189       BCP_lp_create_lp(*this);
00190       BCP_lp_main_loop(*this);
00191       delete lp_solver;
00192       lp_solver = NULL;
00193       break;
00194 
00195     case BCP_Msg_DivingInfo:
00196       BCP_lp_unpack_diving_info(*this, msg_buf);
00197       break;
00198 
00199     case BCP_Msg_NextPhaseStarts:
00200       msg_buf.clear();
00201       // First send back timing data for the previous phase
00202       stat.pack(msg_buf);
00203       msg_env->send(tree_manager, BCP_Msg_LpStatistics, msg_buf);
00204       phase++;
00205       break;
00206 
00207     case BCP_Msg_FinishedBCP:
00208       // No need to clean up anything since the destructor of 'p' will do that.
00209       // However, send back the statistics.
00210       stat.pack(msg_buf);
00211       msg_env->send(tree_manager, BCP_Msg_LpStatistics, msg_buf);
00212       return;
00213 
00214 //     case BCP_Msg_UserMessageToLp:
00215 //       user->unpack_user_message(*this, msg_buf);
00216 //       msg_buf.clear();
00217 //       break;
00218 
00219     default:
00220       printf("Unknown message type arrived to LP: %i\n", msg_buf.msgtag());
00221       break;
00222    }
00223 
00224    msg_buf.clear();
00225 }
00226 
00227 //#############################################################################
00228 
00229 BCP_IndexType
00230 BCP_lp_next_var_index(BCP_lp_prob& p)
00231 {
00232    if (p.next_var_index == p.last_var_index) {
00233       BCP_buffer& buf = p.msg_buf;
00234       // get new set of indices
00235       buf.clear();
00236       p.msg_env->send(p.tree_manager, BCP_Msg_RequestVarIndexSet);
00237       // In a single process environment the new index range has already
00238       // been received (and unpacked), thus we've got to receive it only if
00239       // the range still has length 0.
00240       if (p.next_var_index == p.last_var_index) {
00241          p.msg_env->receive(p.tree_manager, BCP_Msg_VarIndexSet, buf, -1);
00242          p.process_message();
00243       }
00244    }
00245    const BCP_IndexType tmp = p.next_var_index++;
00246    return tmp;
00247 }
00248 
00249 //#############################################################################
00250 
00251 BCP_IndexType
00252 BCP_lp_next_cut_index(BCP_lp_prob& p)
00253 {
00254    if (p.next_cut_index == p.last_cut_index) {
00255       BCP_buffer& buf = p.msg_buf;
00256       // get new set of indices
00257       buf.clear();
00258       p.msg_env->send(p.tree_manager, BCP_Msg_RequestCutIndexSet);
00259       // In a single process environment the new index range has already
00260       // been received (and unpacked), thus we've got to receive it only if
00261       // the range still has length 0.
00262       if (p.next_cut_index == p.last_cut_index) {
00263          p.msg_env->receive(p.tree_manager, BCP_Msg_CutIndexSet, buf, -1);
00264          p.process_message();
00265       }
00266    }
00267    const BCP_IndexType tmp = p.next_cut_index++;
00268    return tmp;
00269 }
00270 
00271 //#############################################################################
00272 
00273 void BCP_lp_process_ub_message(BCP_lp_prob& p, BCP_buffer& buf)
00274 {
00275    double new_ub;
00276    buf.unpack(new_ub);
00277    if (! p.param(BCP_lp_par::SolveLpToOptimality) &&
00278        p.ub(new_ub) &&
00279        p.lp_solver)
00280      p.lp_solver->setDblParam(OsiDualObjectiveLimit, new_ub - p.granularity());
00281 }
00282 
00283 //#############################################################################
00284 
00285 void BCP_lp_send_cuts_to_cp(BCP_lp_prob& p, const int eff_cnt_limit)
00286 {
00287   if (! p.node->cp) // go back if no cut pool exists
00288     return;
00289 
00290   BCP_cut_set& cuts = p.node->cuts;
00291   BCP_cut_set::iterator cuti = cuts.entry(p.core->cutnum());
00292   const BCP_cut_set::const_iterator lastcuti = cuts.end();
00293   BCP_cut* cut;
00294   int cnt;
00295 
00296   // First count how many to send
00297   for (cnt = 0; cuti != lastcuti; ++cuti) {
00298     cut = *cuti;
00299     if (cut->effective_count() >= eff_cnt_limit &&
00300         ! cut->dont_send_to_pool())
00301       ++cnt;
00302   }
00303 
00304   if (cnt > 0){
00305     BCP_buffer& buf = p.msg_buf;
00306     buf.clear();
00307     buf.pack(cnt);
00308     // whatever is sent to the CP must have been generated at this level
00309     buf.pack(p.node->level);
00310     // pack the cuts
00311     cuti = cuts.entry(p.core->cutnum());
00312     for ( ; cuti != lastcuti; ++cuti) {
00313       cut = *cuti;
00314       if (cut->effective_count() >= eff_cnt_limit &&
00315           ! cut->dont_send_to_pool())
00316         p.pack_cut(BCP_ProcessType_CP, *cut);
00317       cut->dont_send_to_pool(true);
00318     }
00319 
00320     p.msg_env->send(p.node->cp, BCP_Msg_CutsToCutPool, buf);
00321     if (p.param(BCP_lp_par::LpVerb_CutsToCutPoolCount))
00322       printf("LP:   %i cuts sent to cutpool\n", cnt);
00323   }
00324 }
00325 
00326 //#############################################################################
00327 
00328 void BCP_lp_unpack_diving_info(BCP_lp_prob& p, BCP_buffer& buf)
00329 {
00330    buf.unpack(p.node->dive); // what's the new diving status?
00331    if (p.node->dive != BCP_DoNotDive){
00332       // do dive
00333       buf.unpack(p.node->index);
00334       // finally, a little cleaning for the new node
00335       p.node->level++;
00336       p.node->iteration_count = 0;
00337    } else {
00338       p.node->index = -1;
00339    }
00340 }

Generated on Wed Dec 3 14:32:28 2003 for BCP by doxygen 1.3.5