00001
00002
00003 #include <cstdio>
00004 #include <cerrno>
00005 #include <cmath>
00006 #include <queue>
00007
00008 #include "CoinTime.hpp"
00009
00010 #include "BCP_os.hpp"
00011
00012 #include "BCP_USER.hpp"
00013 #include "BCP_string.hpp"
00014 #include "BCP_vector.hpp"
00015 #include "BCP_buffer.hpp"
00016 #include "BCP_message.hpp"
00017 #include "BCP_var.hpp"
00018 #include "BCP_cut.hpp"
00019 #include "BCP_node_change.hpp"
00020 #include "BCP_tm.hpp"
00021 #include "BCP_tm_functions.hpp"
00022 #include "BCP_main_fun.hpp"
00023
00024 #include "BCP_tm_user.hpp"
00025 #include "BCP_lp_user.hpp"
00026
00027 #include "BCP_message_single.hpp"
00028
00029
00030
00031 int main(int argc, char* argv[])
00032 {
00033 USER_initialize* user_init = BCP_user_init();
00034
00035 BCP_message_environment* msg_env = user_init->msgenv_init();
00036 {
00037 BCP_single_environment* single_env =
00038 dynamic_cast<BCP_single_environment*>(msg_env);
00039 if (single_env) {
00040
00041
00042
00043 single_env->set_arguments(argc, argv);
00044 }
00045 }
00046
00047 BCP_proc_id* my_id = msg_env->register_process();
00048 if (my_id == 0) {
00049
00050 delete msg_env;
00051 throw BCP_fatal_error("Exiting.\n");
00052 }
00053 BCP_proc_id* parent = msg_env->parent_process();
00054
00055
00056
00057 if (! parent) {
00058 BCP_tm_main(msg_env, user_init, my_id, argc, argv);
00059 } else {
00060 if (argc != 1) {
00061 throw BCP_fatal_error("The slaves do not take any argument!\n");
00062 }
00063 BCP_buffer msg_buf;
00064 msg_env->receive(parent, BCP_Msg_AnyMessage, msg_buf, -1);
00065 if (msg_buf.msgtag() != BCP_Msg_ProcessType) {
00066 throw BCP_fatal_error("The first message is not ProcessType!!!\n");
00067 }
00068
00069 BCP_process_t ptype;
00070 msg_buf.unpack(ptype);
00071 switch (ptype) {
00072 case BCP_ProcessType_LP:
00073 BCP_lp_main(msg_env, user_init, my_id, parent);
00074 break;
00075 case BCP_ProcessType_CP:
00076
00077 break;
00078 case BCP_ProcessType_VP:
00079
00080 break;
00081 case BCP_ProcessType_CG:
00082 BCP_cg_main(msg_env, user_init, my_id, parent);
00083 break;
00084 case BCP_ProcessType_VG:
00085 BCP_vg_main(msg_env, user_init, my_id, parent);
00086 break;
00087 case BCP_ProcessType_Any:
00088 throw BCP_fatal_error("New process identity is BCP_ProcessType_Any!\n");
00089 case BCP_ProcessType_TM:
00090 throw BCP_fatal_error("New process identity is BCP_ProcessType_TM!\n");
00091 }
00092 }
00093 delete parent;
00094 delete my_id;
00095 delete msg_env;
00096 delete user_init;
00097
00098 return 0;
00099 }
00100
00101
00102
00103 void
00104 BCP_tm_main(BCP_message_environment* msg_env,
00105 USER_initialize* user_init,
00106 BCP_proc_id* my_id,
00107 const int argnum, const char* const * arglist)
00108 {
00109
00110 BCP_tm_prob p;
00111
00112
00113 BCP_tm_parse_command_line(p, argnum, arglist);
00114
00115 BCP_buffer msg_buf;
00116 p.msg_env = msg_env;
00117 p.start_time = CoinCpuTime();
00118
00119 FILE* logfile = 0;
00120
00121 const BCP_string& log = p.par.entry(BCP_tm_par::LogFileName);
00122 if (! (p.par.entry(BCP_tm_par::LogFileName) == "")) {
00123 int len = log.length();
00124 char *logname = new char[len + 300];
00125 memcpy(logname, log.c_str(), len);
00126 memcpy(logname + len, "-tm-", 4);
00127 len += 4;
00128 gethostname(logname + len, 255);
00129 len = strlen(logname);
00130 logname[len++] = '-';
00131 sprintf(logname + len, "%i", static_cast<int>(getpid()));
00132 logfile = freopen(logname, "a", stdout);
00133 if (logfile == 0) {
00134 fprintf(stderr, "Error while redirecting stdout: %i\n", errno);
00135 abort();
00136 }
00137 setvbuf(logfile, NULL, _IOLBF, 0);
00138 delete[] logname;
00139 } else {
00140 setvbuf(stdout, NULL, _IOLBF, 0);
00141 }
00142
00143
00144
00145
00146
00147
00148
00149 p.user = user_init->tm_init(p, argnum, arglist);
00150 p.user->setTmProblemPointer(&p);
00151
00152 if (!p.param(BCP_tm_par::DoBranchAndCut)){
00153 printf("\n**********************************************\n");
00154 printf("* Heuristics Finished!!!!!!! *\n");
00155 printf("* Now displaying stats and best solution.... *\n");
00156 printf("**********************************************\n\n");
00157
00158
00159
00160
00161 delete my_id; my_id = 0;
00162 delete msg_env; msg_env = 0;
00163 exit(0);
00164 }
00165
00166
00167
00168 BCP_tm_start_processes(p);
00169
00170
00171
00172 BCP_tm_notify_processes(p);
00173
00174
00175 if (p.param(BCP_tm_par::CpProcessNum) > 0) {
00176 for (int i = p.slaves.cp->size() - 1; i >= 0; --i)
00177 p.leaves_per_cp.
00178 push_back( std::make_pair(p.slaves.cp->procs()[i]->clone(), 0) );
00179 }
00180 if (p.param(BCP_tm_par::VpProcessNum) > 0) {
00181 for (int i = p.slaves.vp->size() - 1; i >= 0; --i)
00182 p.leaves_per_vp.
00183 push_back( std::make_pair(p.slaves.vp->procs()[i]->clone(), 0) );
00184 }
00185
00186
00187 p.core = BCP_tm_create_core(p);
00188 p.core_as_change = new BCP_problem_core_change;
00189 *p.core_as_change = *p.core;
00190
00191 BCP_tm_distribute_core(p);
00192
00193 BCP_tm_distribute_user_info(p);
00194
00195
00196
00197
00198
00199 BCP_tm_node* root = BCP_tm_create_root(p);
00200
00201 p.next_phase_nodes.push_back(root);
00202 p.search_tree.insert(root);
00203
00204 BCP_sanity_checks(p);
00205
00206
00207
00208
00209 bool something_died = false;
00210 for ( p.phase = 0; true ; ++p.phase) {
00211
00212
00213
00214 BCP_tm_tasks_before_new_phase(p);
00215
00216 something_died = BCP_tm_do_one_phase(p);
00217
00218
00219 if (p.next_phase_nodes.size() == 0 || something_died)
00220 break;
00221 }
00222
00223
00224
00225
00226
00227
00228
00229 BCP_tm_idle_processes(p);
00230
00231 BCP_tm_wrapup(&p, 0, 0, 0, true);
00232
00233
00234 BCP_tm_stop_processes(p);
00235
00236 if (logfile)
00237 fclose(logfile);
00238 }
00239
00240
00241
00242 bool BCP_tm_do_one_phase(BCP_tm_prob& p)
00243 {
00244 BCP_buffer& buf = p.msg_buf;
00245
00246
00247 while (!p.candidates.empty() > 0 || p.slaves.lp->busy_num() > 0){
00248
00249 if (BCP_tm_start_new_nodes(p) == BCP_NodeStart_Error)
00250
00251 return true;
00252
00253
00254 buf.clear();
00255 p.msg_env->receive(BCP_AnyProcess, BCP_Msg_AnyMessage, buf,
00256 p.slaves.lp->busy_num() == 0 ?
00257 0 : p.param(BCP_tm_par::TmTimeout));
00258 p.process_message();
00259 }
00260 return false;
00261 }
00262
00263
00264
00265 BCP_problem_core* BCP_tm_create_core(BCP_tm_prob& p)
00266 {
00267 BCP_vec<BCP_var_core*> bvars;
00268 BCP_vec<BCP_cut_core*> bcuts;
00269 BCP_lp_relax* matrix = 0;
00270
00271 p.user->initialize_core(bvars, bcuts, matrix);
00272
00273 const int bvarnum = bvars.size();
00274 if (bvarnum > 0) {
00275 BCP_IndexType i = p.next_var_index_set_start;
00276 for (i = 0; i < bvarnum; ++i) {
00277 BCP_var_core* var = bvars[i];
00278
00279 if (var->var_type() != BCP_ContinuousVar) {
00280 var->set_lb(floor(var->lb()+1e-8));
00281 var->set_ub(ceil(var->ub()-1e-8));
00282 }
00283 var->set_bcpind(i);
00284 p.vars[i] = new BCP_var_core(*var);
00285 }
00286 p.next_var_index_set_start = i;
00287 }
00288
00289 const int bcutnum = bcuts.size();
00290 if (bcutnum > 0) {
00291 BCP_IndexType i = p.next_cut_index_set_start;
00292 for (i = 0; i < bcutnum; ++i) {
00293 BCP_cut_core* cut = bcuts[i];
00294 cut->set_bcpind(i);
00295 p.cuts[i] = new BCP_cut_core(*cut);
00296 }
00297 p.next_cut_index_set_start = i;
00298 }
00299
00300 if (!matrix)
00301 matrix = new BCP_lp_relax;
00302
00303 return new BCP_problem_core(bvars, bcuts, matrix);
00304 }
00305
00306
00307
00308 static inline BCP_cut*
00309 BCP_tm_unpack_root_cut(BCP_tm_prob& tm)
00310 {
00311 BCP_cut* cut;
00312 BCP_buffer& buf = tm.msg_buf;
00313 BCP_object_t obj_t;
00314 int index;
00315 double lb, ub;
00316 BCP_obj_status stat;
00317 buf.unpack(obj_t).unpack(stat).unpack(lb).unpack(ub);
00318 switch (obj_t) {
00319 case BCP_CoreObj:
00320 cut = new BCP_cut_core(lb, ub);
00321 break;
00322 case BCP_IndexedObj:
00323 buf.unpack(index);
00324 cut = new BCP_cut_indexed(index, lb, ub);
00325 break;
00326 case BCP_AlgoObj:
00327 cut = tm.user->unpack_cut_algo(buf);
00328 cut->change_bounds(lb, ub);
00329 break;
00330 default:
00331 throw BCP_fatal_error("BCP_tm_unpack_root_cut: unexpected obj_t.\n");
00332 }
00333 cut->set_bcpind(0);
00334 cut->set_status(stat);
00335
00336 return cut;
00337 }
00338
00339
00340
00341 BCP_tm_node* BCP_tm_create_root(BCP_tm_prob& p)
00342 {
00343 BCP_vec<BCP_var*> added_vars;
00344 BCP_vec<BCP_cut*> added_cuts;
00345 BCP_user_data* user_data = 0;
00346 BCP_pricing_status pricing_status = BCP_PriceNothing;
00347
00348
00349 const BCP_string& cutfile = p.param(BCP_tm_par::ReadRootCutsFrom);
00350 if (cutfile.length() > 0) {
00351 BCP_buffer& buf = p.msg_buf;
00352 buf.clear();
00353 FILE* f = fopen(cutfile.c_str(), "r");
00354 size_t size;
00355 if (fread(&size, 1, sizeof(size), f) != sizeof(size))
00356 throw BCP_fatal_error("ReadRootCutsFrom read error.\n");
00357 char * data = new char[size];
00358 if (fread(data, 1, size, f) != size)
00359 throw BCP_fatal_error("ReadRootCutsFrom read error.\n");
00360 fclose(f);
00361 buf.set_content(data, size, 0, BCP_Msg_NoMessage);
00362 delete[] data;
00363
00364 int num;
00365 buf.unpack(num);
00366 added_cuts.reserve(added_cuts.size() + num);
00367 for (int i = 0; i < num; ++i) {
00368 added_cuts.unchecked_push_back(BCP_tm_unpack_root_cut(p));
00369 }
00370 }
00371
00372 p.user->create_root(added_vars, added_cuts, user_data, pricing_status);
00373
00374 BCP_node_change* root_changes = new BCP_node_change;
00375 root_changes->core_change._storage = BCP_Storage_WrtCore;
00376 root_changes->indexed_pricing.set_status(pricing_status);
00377
00378 if (added_vars.size() > 0) {
00379 BCP_vec<BCP_var*>::iterator vi = added_vars.begin();
00380 const BCP_vec<BCP_var*>::iterator lastvi = added_vars.end();
00381 root_changes->var_change._change.reserve(added_vars.size());
00382 BCP_IndexType i = p.next_var_index_set_start;
00383 while (vi != lastvi) {
00384 BCP_var* var = *vi;
00385 p.vars[i] = var;
00386 var->set_bcpind(i++);
00387
00388 if (var->var_type() != BCP_ContinuousVar) {
00389 var->set_lb(floor(var->lb()+1e-8));
00390 var->set_ub(ceil(var->ub()-1e-8));
00391 }
00392 root_changes->var_change._change.
00393 unchecked_push_back(BCP_obj_change(var->lb(), var->ub(),
00394 var->status()));
00395 ++vi;
00396 }
00397 p.next_var_index_set_start = i;
00398 root_changes->var_change._new_vars.swap(added_vars);
00399 }
00400
00401 if (added_cuts.size() > 0) {
00402 BCP_vec<BCP_cut*>::iterator ci = added_cuts.begin();
00403 const BCP_vec<BCP_cut*>::iterator lastci = added_cuts.end();
00404 root_changes->cut_change._change.reserve(added_cuts.size());
00405 BCP_IndexType i = p.next_cut_index_set_start;
00406 while (ci != lastci) {
00407 BCP_cut* cut = *ci;
00408 p.cuts[i] = cut;
00409 cut->set_bcpind(i++);
00410 root_changes->cut_change._change.
00411 unchecked_push_back(BCP_obj_change(cut->lb(), cut->ub(),
00412 cut->status()));
00413 ++ci;
00414 }
00415 p.next_cut_index_set_start = i;
00416 root_changes->cut_change._new_cuts.swap(added_cuts);
00417 }
00418
00419 BCP_tm_node* root = new BCP_tm_node(0, root_changes);
00420
00421 root->_user_data = user_data;
00422
00423 return root;
00424 }
00425
00426
00427
00428 void BCP_tm_tasks_before_new_phase(BCP_tm_prob& p)
00429 {
00430 if (p.param(BCP_tm_par::TmVerb_NewPhaseStart)) {
00431 printf("############################################################\n");
00432 printf("TM: Starting phase %i\n", p.phase);
00433 printf("############################################################\n");
00434 }
00435
00436 BCP_tm_node* root = 0;
00437
00438 if (p.phase > 0) {
00439
00440
00441 BCP_tm_notify_about_new_phase(p);
00442
00443 if (p.phase == 1 &&
00444 p.search_tree.size() > 1 &&
00445 p.param(BCP_tm_par::PriceInRootBeforePhase2)) {
00446
00447
00448
00449
00450
00451 p.flags.root_pricing_unpacked = false;
00452 p.current_phase_colgen = BCP_GenerateColumns;
00453 root = p.search_tree.root();
00454 root->_desc->indexed_pricing.
00455 set_status(BCP_PriceAfterLastIndexedToPrice);
00456 #ifdef BCP_DEBUG
00457 if (root->lp != 0 || root->cg != 0 || root->vg != 0)
00458 throw BCP_fatal_error("\
00459 TM: At least on of lp/cg/vg of the root is non-0 (before repricing).\n");
00460 #endif
00461
00462 if (! BCP_tm_assign_processes(p, root)) {
00463
00464 }
00465
00466 BCP_tm_send_node(p, root, BCP_Msg_RootToPrice);
00467 }
00468
00469
00470 BCP_tm_wrapup(&p, 0, 0, 0, false);
00471
00472
00473 if (p.param(BCP_tm_par::TrimTreeBeforeNewPhase) && p.has_ub())
00474 BCP_tm_trim_tree_wrapper(p, true );
00475 }
00476
00477
00478
00479 p.current_phase_colgen = BCP_DoNotGenerateColumns_Fathom;
00480 p.user->init_new_phase(p.phase, p.current_phase_colgen);
00481
00482 for (int i = p.next_phase_nodes.size() - 1; i >= 0; --i) {
00483 p.candidates.insert(p.next_phase_nodes[i]);
00484 }
00485
00486 p.next_phase_nodes.clear();
00487
00488 if (root && !p.flags.root_pricing_unpacked) {
00489
00490
00491
00492 p.msg_env->receive(root->lp, BCP_Msg_PricedRoot, p.msg_buf, -1);
00493 BCP_tm_unpack_priced_root(p, p.msg_buf);
00494 }
00495
00496
00497 if (p.phase == 0 && p.param(BCP_tm_par::PriceInRootBeforePhase2)) {
00498 if (p.current_phase_colgen != BCP_DoNotGenerateColumns_Send) {
00499 printf("#########################################################\n");
00500 printf("TM: *WARNING* *WARNING* *WARNING* *WARNING* *WARNING*\n");
00501 printf(" PriceInRootBeforePhase2 is set yet the column \n");
00502 printf(" generation strategy is set to ");
00503 switch (p.current_phase_colgen) {
00504 case BCP_DoNotGenerateColumns_Fathom:
00505 printf("BCP_DoNotGenerateColumns_Fathom"); break;
00506 case BCP_GenerateColumns:
00507 printf("BCP_GenerateColumns"); break;
00508 case BCP_DoNotGenerateColumns_Send:
00509 break;
00510 }
00511 printf(" in the first phase!\n");
00512 printf(" The strategy is reset to BCP_DoNotGenerateColumns_Send\n");
00513 printf("#########################################################\n");
00514 }
00515 }
00516 }
00517
00518
00519
00520