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

BCP_lp_msg_node_send.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_problem_core.hpp"
00007 #include "BCP_branch.hpp"
00008 #include "BCP_warmstart.hpp"
00009 #include "BCP_lp.hpp"
00010 #include "BCP_lp_user.hpp"
00011 #include "BCP_lp_branch.hpp"
00012 #include "BCP_lp_node.hpp"
00013 #include "BCP_lp_functions.hpp"
00014 
00015 #include "BCP_USER.hpp"
00016 
00017 //#############################################################################
00018 static inline void BCP_lp_pack_core(BCP_lp_prob& p);
00019 static inline void BCP_lp_pack_noncore_vars(BCP_lp_prob& p,
00020                                             BCP_vec<int>& deleted_pos);
00021 static inline void BCP_lp_pack_noncore_cuts(BCP_lp_prob& p,
00022                                             BCP_vec<int>& deleted_pos);
00023 static inline void BCP_lp_pack_indexed_pricing(BCP_lp_prob& p);
00024 static inline void BCP_lp_pack_warmstart(BCP_lp_prob& p,
00025                                          BCP_vec<int>& del_vars,
00026                                          BCP_vec<int>& del_cuts);
00027 static inline void BCP_lp_pack_user_data(BCP_lp_prob& p);
00028 
00029 //-----------------------------------------------------------------------------
00030 
00031 static inline int BCP_lp_pack_branching_info(BCP_lp_prob& p,
00032                                              BCP_presolved_lp_brobj* brobj);
00033 
00034 //#############################################################################
00035 
00036 static inline void
00037 BCP_lp_pack_core(BCP_lp_prob& p)
00038 {
00039    if (p.core->varnum() + p.core->cutnum() > 0){
00040       BCP_problem_core_change exp_bc(p.core->varnum(), p.node->vars,
00041                                  p.core->cutnum(), p.node->cuts);
00042       switch (p.node->tm_storage.core_change){
00043        case BCP_Storage_WrtCore:
00044          {
00045             BCP_problem_core_change wrtcore_bc(BCP_Storage_WrtCore,
00046                                            *p.core_as_change, exp_bc);
00047             wrtcore_bc.pack(p.msg_buf);
00048          }
00049          break;
00050 
00051        case BCP_Storage_Explicit:
00052          exp_bc.pack(p.msg_buf);
00053          break;
00054 
00055        case BCP_Storage_WrtParent:
00056          {
00057             BCP_problem_core_change wrtparent_bc(BCP_Storage_WrtParent,
00058                                              p.parent->core_as_change, exp_bc);
00059             BCP_problem_core_change wrtcore_bc(BCP_Storage_WrtCore,
00060                                            *p.core_as_change, exp_bc);
00061             if (exp_bc.pack_size() <= wrtparent_bc.pack_size()){
00062                if (exp_bc.pack_size() <= wrtcore_bc.pack_size()){
00063                   exp_bc.pack(p.msg_buf);
00064                }else{
00065                   wrtcore_bc.pack(p.msg_buf);
00066                }
00067             }else{
00068                if (wrtparent_bc.pack_size() < wrtcore_bc.pack_size()){
00069                   wrtparent_bc.pack(p.msg_buf);
00070                }else{
00071                   wrtcore_bc.pack(p.msg_buf);
00072                }
00073             }
00074          }
00075          break;
00076 
00077        default: // including BCP_Storage_NoData
00078          throw BCP_fatal_error("BCP_lp_pack_core() : Bad storage.\n");
00079       }
00080       // look ahead (the current node may become the parent) and replace the
00081       // parent's core to be exp_bc
00082       p.parent->core_as_change.swap(exp_bc);
00083    }
00084 }
00085 
00086 //#############################################################################
00087 
00088 static inline void
00089 BCP_lp_pack_noncore_vars(BCP_lp_prob& p, BCP_vec<int>& deleted_pos)
00090 {
00091    // create the BCP_var_set_change describing the current node.
00092    // must create a WrtParent listing as well as an Explicit listing since the
00093    // set pf deleted vars will be needed when the warmstart info is put
00094    // together.
00095    deleted_pos.clear();
00096    BCP_var_set_change desc(p.node->vars.entry(p.core->varnum()),
00097                            p.node->vars.end());
00098 
00099    if (p.node->tm_storage.var_change == BCP_Storage_WrtParent) {
00100       BCP_var_set_change change(p.node->vars.entry(p.core->varnum()),
00101                                 p.node->vars.end(),
00102                                 p.parent->added_vars_index,
00103                                 p.parent->added_vars_desc);
00104 
00105       deleted_pos.append(change._del_change_pos.begin(),
00106                          change._del_change_pos.entry(change.deleted_num()));
00107 
00108       // if the TM storage is WrtParent then pack the shorter
00109       if (desc.pack_size() > change.pack_size())
00110          desc.swap(change);
00111    }
00112 
00113    // Now desc holds the right description (Explicit or WrtParent, who knows?)
00114    // Pack it.
00115    p.pack_var_set_change(desc);
00116 }
00117 
00118 //#############################################################################
00119 
00120 static inline void
00121 BCP_lp_pack_noncore_cuts(BCP_lp_prob& p, BCP_vec<int>& deleted_pos)
00122 {
00123    // create the BCP_cut_set_change describing the current node.
00124    // must create a WrtParent listing as well as an Explicit listing since the
00125    // set pf deleted cuts will be needed when the warmstart info is put
00126    // together.
00127    deleted_pos.clear();
00128    BCP_cut_set_change desc(p.node->cuts.entry(p.core->cutnum()),
00129                            p.node->cuts.end());
00130    
00131    if (p.node->tm_storage.cut_change == BCP_Storage_WrtParent) {
00132       BCP_cut_set_change change(p.node->cuts.entry(p.core->cutnum()),
00133                                 p.node->cuts.end(),
00134                                 p.parent->added_cuts_index,
00135                                 p.parent->added_cuts_desc);
00136 
00137       deleted_pos.append(change._del_change_pos.begin(),
00138                          change._del_change_pos.entry(change.deleted_num()));
00139 
00140       // if the TM storage is WrtParent then pack the shorter
00141       if (desc.pack_size() > change.pack_size())
00142          desc.swap(change);
00143    }
00144 
00145    // Now desc holds the right description (Explicit or WrtParent, who knows?)
00146    // Pack it.
00147    p.pack_cut_set_change(desc);
00148 }
00149 
00150 //#############################################################################
00151 
00152 static inline void
00153 BCP_lp_pack_indexed_pricing(BCP_lp_prob& p)
00154 {
00155    BCP_indexed_pricing_list& indexed_pricing = p.node->indexed_pricing;
00156    if (p.node->tm_storage.indexed_pricing != BCP_Storage_WrtParent) {
00157       // if ! BCP_PriceIndexedVars then storage will be NoData, so OK.
00158       indexed_pricing.pack(p.msg_buf);
00159    } else {
00160       BCP_indexed_pricing_list* pricing_change =
00161          indexed_pricing.as_change(p.parent->indexed_pricing);
00162       if (pricing_change->pack_size() < indexed_pricing.pack_size())
00163          pricing_change->pack(p.msg_buf);
00164       else
00165          indexed_pricing.pack(p.msg_buf);
00166       delete pricing_change;   pricing_change = 0;
00167    }
00168 }
00169 
00170 //#############################################################################
00171 
00172 static inline void
00173 BCP_lp_pack_warmstart(BCP_lp_prob& p,
00174                       BCP_vec<int>& del_vars, BCP_vec<int>& del_cuts)
00175 {
00176    bool has_data = p.node->warmstart != 0;
00177    p.msg_buf.pack(has_data);
00178 
00179    if (has_data) {
00180       if (p.node->tm_storage.warmstart != BCP_Storage_WrtParent) {
00181         p.user->pack_warmstart(p.node->warmstart, p.msg_buf);
00182       } else {
00183         double petol = 0.0;
00184         double detol = 0.0;
00185         p.lp_solver->getDblParam(OsiPrimalTolerance, petol);
00186         p.lp_solver->getDblParam(OsiDualTolerance, detol);
00187         // this return an explicit storage if that's shorter!
00188         BCP_warmstart* ws_change =
00189           p.node->warmstart->as_change(p.parent->warmstart,
00190                                        del_vars, del_cuts, petol, detol);
00191         p.user->pack_warmstart(ws_change, p.msg_buf);
00192         delete ws_change;
00193         ws_change = 0;
00194       }
00195    }      
00196 }
00197 
00198 //#############################################################################
00199 
00200 static inline void BCP_lp_pack_user_data(BCP_lp_prob& p)
00201 {
00202    bool has_data = p.node->user_data != 0;
00203    p.msg_buf.pack(has_data);
00204 
00205    if (has_data) {
00206       p.user->pack_user_data(p.node->user_data, p.msg_buf);
00207    }
00208 }
00209 
00210 //#############################################################################
00211 
00212 static inline int
00213 BCP_lp_pack_branching_info(BCP_lp_prob& p, BCP_presolved_lp_brobj* lp_brobj)
00214 {
00215    const int child_num = lp_brobj->candidate()->child_num;
00216 
00217    // collect the lower bounds on the children
00218    BCP_vec<double> lpobj;
00219    lpobj.reserve(child_num);
00220    for (int i = 0; i < child_num; ++i) {
00221       lpobj.unchecked_push_back(lp_brobj->lpres(i).objval());
00222    }
00223 
00224    // The qualities are the same (for now) as the lpobjs
00225    BCP_vec<double> qualities(lpobj);
00226 
00227    const BCP_vec<BCP_child_action>& action = lp_brobj->action();
00228    const BCP_vec<BCP_user_data*>& user_data = lp_brobj->user_data();
00229 
00230    // now pack all those stuff
00231    BCP_buffer& buf = p.msg_buf;
00232    buf.pack(p.node->dive).pack(action).pack(qualities).pack(lpobj);
00233 
00234    for (int i = 0; i < child_num; ++i) {
00235       const int has_user_data = user_data[i] == 0 ? 0 : 1;
00236       buf.pack(has_user_data);
00237       if (has_user_data == 1) {
00238          p.user->pack_user_data(user_data[i], buf);
00239       }
00240    }
00241 
00242    BCP_internal_brobj int_brobj(*lp_brobj->candidate());
00243    int_brobj.pack(buf);
00244 
00245    int keep = -1;
00246    if (p.node->dive != BCP_DoNotDive){
00247       for (int i = child_num - 1; i >= 0; --i)
00248          if (action[i] == BCP_KeepChild)
00249             if (keep == -1)
00250                keep = i;
00251             else
00252                throw BCP_fatal_error("LP : Can't keep more than one child!\n");
00253    }
00254    return keep;
00255 }
00256 
00257 //#############################################################################
00258 
00259 // brobj is 0, msgtag is 'real' when invoked from fathom().
00260 // brobj is 'real', msgtag is BCP_Msg_NoMessage when invoked from branch()
00261 
00262 int BCP_lp_send_node_description(BCP_lp_prob& p,
00263                                  BCP_presolved_lp_brobj* brobj,
00264                                  BCP_message_tag msgtag)
00265 {
00266    BCP_buffer& buf = p.msg_buf;
00267    BCP_lp_node& node = *p.node;
00268 
00269    // let's start with saying who this node is and what is the lb we got
00270    buf.clear();
00271    buf.pack(node.index).pack(node.quality).pack(node.true_lower_bound);
00272 
00273    const bool send_desc = brobj || p.param(BCP_lp_par::SendFathomedNodeDesc);
00274 
00275    buf.pack(send_desc);
00276 
00277    // Send the node description only if this node is branched on (i.e., brobj
00278    // is non-null) or we got to send the description of fathomed nodes, too.
00279    if (send_desc) {
00280       // Pack the core (WrtCore, WrtParent or Explicit)
00281       BCP_lp_pack_core(p);  // BCP_problem_core_change
00282       // pack the indexed/algo var set change (or pack them explicitly)
00283       BCP_vec<int> del_vars;
00284       BCP_lp_pack_noncore_vars(p, del_vars);
00285 
00286       BCP_vec<int> del_cuts;
00287       BCP_lp_pack_noncore_cuts(p, del_cuts);
00288 
00289       // pack the pricing status
00290       BCP_lp_pack_indexed_pricing(p);
00291 
00292       // At this point there aren't supposed to be any ws info. It was deleted
00293       // when the lp formulation was created. Test this.
00294       if (p.node->warmstart) {
00295          throw BCP_fatal_error("\
00296 LP: there is ws info in BCP_lp_send_node_description()!\n");
00297       }
00298       // get and pack the warmstart info
00299       CoinWarmStart* ws = p.lp_solver->getWarmStart();
00300       p.node->warmstart = BCP_lp_convert_CoinWarmStart(p, ws);
00301       BCP_lp_pack_warmstart(p, del_vars, del_cuts);
00302       BCP_lp_pack_user_data(p);
00303    }
00304 
00305    int keep = -1;
00306 
00307    if (brobj) {
00308       // we came here from branch()
00309       // pack the branching info, 'keep' will tell whether we wish to dive
00310       keep = BCP_lp_pack_branching_info(p, brobj);
00311       // In a single process environment (message driven) the reaction in the
00312       // TM to the send below will reset p.node->dive. In a multi-process
00313       // environment p.node->dive will remain Unknown. This will help later
00314       // (20 lines below) to decide whether we have to get the diving info or
00315       // not.
00316       p.node->dive = BCP_UnknownDivingStatus;
00317       p.msg_env->send(p.tree_manager,
00318                       BCP_Msg_NodeDescriptionWithBranchingInfo, buf);
00319    }else{
00320       // we came from fathom()
00321       p.msg_env->send(p.tree_manager, msgtag, buf);
00322    }
00323 
00324    if (keep == -1){
00325       // we don't wan't to dive (or we came from fathom()),
00326       // don't wait for the names of the ones not having global internal index
00327       return -1;
00328    }
00329 
00330    // We did want to dive
00331 
00332    // In the single process environment the diving info already came back
00333    // (when the TM processes the branching info) and p.node->dive is set.
00334    // Otherwise we got to receive the diving info here.
00335    if (p.node->dive == BCP_UnknownDivingStatus) {
00336       // We got to receive the diving information by hand
00337       p.msg_buf.clear();
00338       p.msg_env->receive(p.tree_manager, BCP_Msg_DivingInfo, buf, -1);
00339       BCP_lp_unpack_diving_info(p, p.msg_buf);
00340    }
00341 
00342    // BCP_lp_unpack_diving_info() sets p.node->index to the new index if
00343    // diving is to be done, or to -1 if diving is not allowed.
00344    if (p.node->index == -1) {
00345       keep = -1;
00346       // At this point brobj cannot be empty.
00347       // We must reset the child to be kept, too.
00348       brobj->keep_no_child();
00349    }
00350    return keep;
00351 }
00352 
00353 //#############################################################################

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