PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/src/coin/Symphony/tm_func.cpp

https://github.com/jinankjain/ogdf
C++ | 3610 lines | 2853 code | 361 blank | 396 comment | 753 complexity | 576e13ef396bf1259b1880890d7790fe MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0
  1. /*===========================================================================*/
  2. /* */
  3. /* This file is part of the SYMPHONY MILP Solver Framework. */
  4. /* */
  5. /* SYMPHONY was jointly developed by Ted Ralphs (ted@lehigh.edu) and */
  6. /* Laci Ladanyi (ladanyi@us.ibm.com). */
  7. /* */
  8. /* (c) Copyright 2000-2011 Ted Ralphs. All Rights Reserved. */
  9. /* */
  10. /* This software is licensed under the Eclipse Public License. Please see */
  11. /* accompanying file for terms. */
  12. /* */
  13. /*===========================================================================*/
  14. #define COMPILING_FOR_TM
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <math.h>
  19. #if !defined(_MSC_VER) && !defined(__MNO_CYGWIN) && defined(SIGHANDLER)
  20. #include <signal.h>
  21. #if !defined(HAS_SRANDOM)
  22. extern int srandom PROTO((unsigned seed));
  23. #endif
  24. #if !defined(HAS_RANDOM)
  25. extern long random PROTO((void));
  26. #endif
  27. #endif
  28. #ifdef _OPENMP
  29. #include "omp.h"
  30. #endif
  31. #if !defined (_MSC_VER)
  32. #include <unistd.h> /* this defines sleep() */
  33. #endif
  34. #include "sym_tm.h"
  35. #include "sym_constants.h"
  36. #include "sym_types.h"
  37. #include "sym_macros.h"
  38. #include "sym_messages.h"
  39. #include "sym_proccomm.h"
  40. #include "sym_timemeas.h"
  41. #include "sym_pack_cut.h"
  42. #include "sym_pack_array.h"
  43. #ifdef COMPILE_IN_LP
  44. #include "sym_lp.h"
  45. #endif
  46. #ifdef COMPILE_IN_TM
  47. #include "sym_master.h"
  48. #else
  49. #include "sym_cp.h"
  50. #endif
  51. int c_count = 0;
  52. /*===========================================================================*/
  53. /*===========================================================================*\
  54. * This file contains basic functions associated with the treemanager process
  55. \*===========================================================================*/
  56. /*===========================================================================*/
  57. /*===========================================================================*\
  58. * This function receives the intitial parameters and data and sets up
  59. * the tree manager data structures, etc.
  60. \*===========================================================================*/
  61. int tm_initialize(tm_prob *tm, base_desc *base, node_desc *rootdesc)
  62. {
  63. #ifndef COMPILE_IN_TM
  64. int r_bufid, bytes, msgtag, i;
  65. #endif
  66. FILE *f = NULL;
  67. tm_params *par;
  68. bc_node *root = (bc_node *) calloc(1, sizeof(bc_node));
  69. #ifdef COMPILE_IN_LP
  70. int i;
  71. #else
  72. #ifdef COMPILE_IN_TM
  73. int i;
  74. #endif
  75. int s_bufid;
  76. #endif
  77. int *termcodes = NULL;
  78. #if !defined(_MSC_VER) && !defined(__MNO_CYGWIN) && defined(SIGHANDLER)
  79. signal(SIGINT, sym_catch_c);
  80. #endif
  81. par = &tm->par;
  82. #ifdef _OPENMP
  83. tm->rpath =
  84. (bc_node ***) calloc(par->max_active_nodes, sizeof(bc_node **));
  85. tm->rpath_size = (int *) calloc(par->max_active_nodes, sizeof(int));
  86. tm->bpath =
  87. (branch_desc **) calloc(par->max_active_nodes, sizeof(branch_desc *));
  88. tm->bpath_size = (int *) calloc(par->max_active_nodes, sizeof(int));
  89. termcodes = (int *) calloc(par->max_active_nodes, sizeof(int));
  90. #else
  91. tm->rpath = (bc_node ***) calloc(1, sizeof(bc_node **));
  92. tm->rpath_size = (int *) calloc(1, sizeof(int));
  93. tm->bpath = (branch_desc **) calloc(1, sizeof(branch_desc *));
  94. tm->bpath_size = (int *) calloc(1, sizeof(int));
  95. termcodes = (int *) calloc(1, sizeof(int));
  96. #endif
  97. /*------------------------------------------------------------------------*\
  98. * Receives data from the master
  99. \*------------------------------------------------------------------------*/
  100. #ifdef COMPILE_IN_TM
  101. tm->bvarnum = base->varnum;
  102. tm->bcutnum = base->cutnum;
  103. #else
  104. r_bufid = receive_msg(ANYONE, TM_DATA);
  105. bufinfo(r_bufid, &bytes, &msgtag, &tm->master);
  106. receive_char_array((char *)par, sizeof(tm_params));
  107. receive_char_array(&tm->has_ub, 1);
  108. if (tm->has_ub)
  109. receive_dbl_array(&tm->ub, 1);
  110. receive_char_array(&tm->has_ub_estimate, 1);
  111. if (tm->has_ub_estimate)
  112. receive_dbl_array(&tm->ub_estimate, 1);
  113. READ_STR_LIST(par->lp_mach_num, MACH_NAME_LENGTH,
  114. par->lp_machs[0], par->lp_machs);
  115. READ_STR_LIST(par->cg_mach_num, MACH_NAME_LENGTH,
  116. par->cg_machs[0], par->cg_machs);
  117. READ_STR_LIST(par->cp_mach_num, MACH_NAME_LENGTH,
  118. par->cp_machs[0], par->cp_machs);
  119. receive_int_array(&tm->bvarnum, 1);
  120. receive_int_array(&tm->bcutnum, 1);
  121. #ifdef TRACE_PATH
  122. receive_int_array(&tm->feas_sol_size, 1);
  123. if (tm->feas_sol_size){
  124. tm->feas_sol = (int *) calloc (tm->feas_sol_size, sizeof(int));
  125. receive_int_array(tm->feas_sol, tm->feas_sol_size);
  126. }
  127. #endif
  128. freebuf(r_bufid);
  129. #endif
  130. SRANDOM(par->random_seed);
  131. #ifdef COMPILE_IN_LP
  132. #ifdef _OPENMP
  133. omp_set_dynamic(FALSE);
  134. omp_set_num_threads(par->max_active_nodes);
  135. #else
  136. par->max_active_nodes = 1;
  137. #endif
  138. tm->active_nodes = (bc_node **) calloc(par->max_active_nodes, sizeof(bc_node *));
  139. #ifndef COMPILE_IN_TM
  140. tm->lpp = (lp_prob **)
  141. malloc(par->max_active_nodes * sizeof(lp_prob *));
  142. for (i = 0; i < par->max_active_nodes; i++){
  143. tm->lpp[i] = (lp_prob *) calloc(1, sizeof(lp_prob));
  144. tm->lpp[i]->proc_index = i;
  145. }
  146. #ifdef COMPILE_IN_CG
  147. tm->cgp = (cg_prob **) malloc(par->max_active_nodes * sizeof(cg_prob *));
  148. for (i = 0; i < par->max_active_nodes; i++)
  149. tm->lpp[i]->cgp = tm->cgp[i] = (cg_prob *) calloc(1, sizeof(cg_prob));
  150. par->use_cg = FALSE;
  151. #endif
  152. #endif
  153. #pragma omp parallel for shared(tm)
  154. for (i = 0; i < par->max_active_nodes; i++){
  155. if ((termcodes[i] = lp_initialize(tm->lpp[i], 0)) < 0){
  156. printf("LP initialization failed with error code %i in thread %i\n\n",
  157. termcodes[i], i);
  158. }
  159. tm->lpp[i]->tm = tm;
  160. }
  161. tm->lp.free_num = par->max_active_nodes;
  162. for (i = 0; i < par->max_active_nodes; i++){
  163. if (termcodes[i] < 0){
  164. int tmp = termcodes[i];
  165. FREE(termcodes);
  166. return(tmp);
  167. }
  168. }
  169. #else
  170. tm->active_nodes =
  171. (bc_node **) malloc(par->max_active_nodes * sizeof(bc_node *));
  172. /*------------------------------------------------------------------------*\
  173. * Start the lp, cg processes and send cg tid's to the lp's.
  174. * Also, start the cp, sp processes.
  175. \*------------------------------------------------------------------------*/
  176. tm->lp = start_processes(tm, par->max_active_nodes, par->lp_exe,
  177. par->lp_debug, par->lp_mach_num, par->lp_machs);
  178. #endif
  179. #pragma omp critical (cut_pool)
  180. if (!tm->cuts){
  181. tm->cuts = (cut_data **) malloc(BB_BUNCH * sizeof(cut_data *));
  182. }
  183. if (par->use_cg){
  184. #ifndef COMPILE_IN_CG
  185. tm->cg = start_processes(tm, par->max_active_nodes, par->cg_exe,
  186. par->cg_debug, par->cg_mach_num, par->cg_machs);
  187. #ifdef COMPILE_IN_LP
  188. for (i = 0; i < par->max_active_nodes; i++)
  189. tm->lpp[i]->cut_gen = tm->cg.procs[i];
  190. #else
  191. for (i = 0; i < tm->lp.procnum; i++){
  192. s_bufid = init_send(DataInPlace);
  193. send_int_array(tm->cg.procs + i, 1);
  194. send_msg(tm->lp.procs[i], LP__CG_TID_INFO);
  195. }
  196. #endif
  197. #endif
  198. }
  199. if (par->max_cp_num){
  200. #ifdef COMPILE_IN_CP
  201. #ifndef COMPILE_IN_TM
  202. tm->cpp = (cut_pool **) malloc(par->max_cp_num * sizeof(cut_pool *));
  203. #endif
  204. for (i = 0; i < par->max_cp_num; i++){
  205. #ifndef COMPILE_IN_TM
  206. tm->cpp[i] = (cut_pool *) calloc(1, sizeof(cut_pool));
  207. #endif
  208. cp_initialize(tm->cpp[i], tm->master);
  209. }
  210. tm->cp.free_num = par->max_cp_num;
  211. tm->cp.procnum = par->max_cp_num;
  212. tm->cp.free_ind = (int *) malloc(par->max_cp_num * ISIZE);
  213. for (i = par->max_cp_num - 1; i >= 0; i--)
  214. tm->cp.free_ind[i] = i;
  215. #else
  216. tm->cp = start_processes(tm, par->max_cp_num, par->cp_exe,
  217. par->cp_debug, par->cp_mach_num, par->cp_machs);
  218. #endif
  219. tm->nodes_per_cp = (int *) calloc(tm->par.max_cp_num, ISIZE);
  220. tm->active_nodes_per_cp = (int *) calloc(tm->par.max_cp_num, ISIZE);
  221. }else{
  222. #ifdef COMPILE_IN_CP
  223. tm->cpp = (cut_pool **) calloc(1, sizeof(cut_pool *));
  224. #endif
  225. }
  226. /*------------------------------------------------------------------------*\
  227. * Receive the root node and send out initial data to the LP processes
  228. \*------------------------------------------------------------------------*/
  229. FREE(termcodes);
  230. if (tm->par.warm_start){
  231. if (!tm->rootnode){
  232. if (!(f = fopen(tm->par.warm_start_tree_file_name, "r"))){
  233. printf("Error reading warm start file %s\n\n",
  234. tm->par.warm_start_tree_file_name);
  235. return(ERROR__READING_WARM_START_FILE);
  236. }
  237. read_tm_info(tm, f);
  238. }else{
  239. free(root);
  240. root = tm->rootnode;
  241. }
  242. read_subtree(tm, root, f);
  243. if (f)
  244. fclose(f);
  245. if (!tm->rootnode){
  246. if (!read_tm_cut_list(tm, tm->par.warm_start_cut_file_name)){
  247. printf("Error reading warm start file %s\n\n",
  248. tm->par.warm_start_cut_file_name);
  249. return(ERROR__READING_WARM_START_FILE);
  250. }
  251. }
  252. tm->rootnode = root;
  253. if(root->node_status != NODE_STATUS__WARM_STARTED)
  254. root->node_status = NODE_STATUS__ROOT;
  255. }else{
  256. #ifdef COMPILE_IN_TM
  257. (tm->rootnode = root)->desc = *rootdesc;
  258. /* Copy the root description in case it is still needed */
  259. root->desc.uind.list = (int *) malloc(rootdesc->uind.size*ISIZE);
  260. memcpy((char *)root->desc.uind.list, (char *)rootdesc->uind.list,
  261. rootdesc->uind.size*ISIZE);
  262. root->bc_index = tm->stat.created++;
  263. root->lower_bound = -MAXDOUBLE;
  264. tm->stat.tree_size++;
  265. insert_new_node(tm, root);
  266. tm->phase = 0;
  267. tm->lb = 0;
  268. #else
  269. r_bufid = receive_msg(tm->master, TM_ROOT_DESCRIPTION);
  270. receive_node_desc(tm, root);
  271. if (root->desc.cutind.size > 0){ /* Hey we got cuts, too! Unpack them. */
  272. unpack_cut_set(tm, 0, 0, NULL);
  273. }
  274. freebuf(r_bufid);
  275. #endif
  276. #ifdef TRACE_PATH
  277. root->optimal_path = TRUE;
  278. #endif
  279. }
  280. return(FUNCTION_TERMINATED_NORMALLY);
  281. }
  282. /*===========================================================================*/
  283. /*===========================================================================*\
  284. * This is the main loop that solves the problem
  285. \*===========================================================================*/
  286. int solve(tm_prob *tm)
  287. {
  288. #ifndef COMPILE_IN_LP
  289. int r_bufid;
  290. #endif
  291. int termcode = 0;
  292. double start_time = tm->start_time;
  293. double no_work_start, ramp_up_tm = 0, ramp_down_time = 0;
  294. char ramp_down = FALSE, ramp_up = TRUE;
  295. double then, then2, then3, now;
  296. double timeout2 = 30, timeout3 = tm->par.logging_interval, timeout4 = 10;
  297. /*------------------------------------------------------------------------*\
  298. * The Main Loop
  299. \*------------------------------------------------------------------------*/
  300. no_work_start = wall_clock(NULL);
  301. termcode = TM_UNFINISHED;
  302. for (; tm->phase <= 1; tm->phase++){
  303. if (tm->phase == 1 && !tm->par.warm_start){
  304. if ((termcode = tasks_before_phase_two(tm)) ==
  305. FUNCTION_TERMINATED_NORMALLY){
  306. termcode = TM_FINISHED; /* Continue normally */
  307. }
  308. }
  309. then = wall_clock(NULL);
  310. then2 = wall_clock(NULL);
  311. then3 = wall_clock(NULL);
  312. #pragma omp parallel default(shared)
  313. {
  314. #ifdef _OPENMP
  315. int i, thread_num = omp_get_thread_num();
  316. #else
  317. int i, thread_num = 0;
  318. #endif
  319. while (tm->active_node_num > 0 || tm->samephase_candnum > 0){
  320. /*------------------------------------------------------------------*\
  321. * while there are nodes being processed or while there are nodes
  322. * waiting to be processed, continue to execute this loop
  323. \*------------------------------------------------------------------*/
  324. i = NEW_NODE__STARTED;
  325. while (tm->lp.free_num > 0 && (tm->par.time_limit >= 0.0 ?
  326. (wall_clock(NULL) - start_time < tm->par.time_limit) : TRUE) &&
  327. (tm->par.node_limit >= 0 ?
  328. tm->stat.analyzed < tm->par.node_limit : TRUE) &&
  329. ((tm->has_ub && (tm->par.gap_limit >= 0.0)) ?
  330. fabs(100*(tm->ub-tm->lb)/tm->ub) > tm->par.gap_limit : TRUE)
  331. && !(tm->par.find_first_feasible && tm->has_ub) && c_count <= 0){
  332. if (tm->samephase_candnum > 0){
  333. #pragma omp critical (tree_update)
  334. i = start_node(tm, thread_num);
  335. }else{
  336. i = NEW_NODE__NONE;
  337. }
  338. if (i != NEW_NODE__STARTED)
  339. break;
  340. if (ramp_up){
  341. ramp_up_tm += (wall_clock(NULL) -
  342. no_work_start) * (tm->lp.free_num + 1);
  343. }
  344. if (ramp_down){
  345. ramp_down_time += (wall_clock(NULL) -
  346. no_work_start) * (tm->lp.free_num + 1);
  347. }
  348. if (!tm->lp.free_num){
  349. ramp_down = FALSE;
  350. ramp_up = FALSE;
  351. }else if (ramp_up){
  352. no_work_start = wall_clock(NULL);
  353. }else{
  354. ramp_down = TRUE;
  355. no_work_start = wall_clock(NULL);
  356. }
  357. #ifdef COMPILE_IN_LP
  358. #ifdef _OPENMP
  359. if (tm->par.verbosity > 0)
  360. printf("Thread %i now processing node %i\n", thread_num,
  361. tm->lpp[thread_num]->bc_index);
  362. #endif
  363. if(tm->par.node_selection_rule == DEPTH_FIRST_THEN_BEST_FIRST &&
  364. tm->has_ub){
  365. tm->par.node_selection_rule = LOWEST_LP_FIRST;
  366. }
  367. switch(process_chain(tm->lpp[thread_num])){
  368. case FUNCTION_TERMINATED_NORMALLY:
  369. break;
  370. case ERROR__NO_BRANCHING_CANDIDATE:
  371. termcode = TM_ERROR__NO_BRANCHING_CANDIDATE;
  372. break;
  373. case ERROR__ILLEGAL_RETURN_CODE:
  374. termcode = TM_ERROR__ILLEGAL_RETURN_CODE;
  375. break;
  376. case ERROR__NUMERICAL_INSTABILITY:
  377. termcode = TM_ERROR__NUMERICAL_INSTABILITY;
  378. break;
  379. case ERROR__COMM_ERROR:
  380. termcode = TM_ERROR__COMM_ERROR;
  381. case ERROR__USER:
  382. termcode = TM_ERROR__USER;
  383. break;
  384. case ERROR__DUAL_INFEASIBLE:
  385. if(tm->lpp[thread_num]->bc_index < 1 ) {
  386. termcode = TM_UNBOUNDED;
  387. }else{
  388. termcode = TM_ERROR__NUMERICAL_INSTABILITY;
  389. }
  390. break;
  391. }
  392. #endif
  393. #pragma omp master
  394. {
  395. now = wall_clock(NULL);
  396. if (now - then2 > timeout2){
  397. if(tm->par.verbosity >= -1 ){
  398. print_tree_status(tm);
  399. }
  400. then2 = now;
  401. }
  402. if (now - then3 > timeout3){
  403. write_log_files(tm);
  404. then3 = now;
  405. }
  406. }
  407. }
  408. if (c_count > 0){
  409. termcode = TM_SIGNAL_CAUGHT;
  410. c_count = 0;
  411. break;
  412. }
  413. if (tm->par.time_limit >= 0.0 &&
  414. wall_clock(NULL) - start_time > tm->par.time_limit &&
  415. termcode != TM_FINISHED){
  416. termcode = TM_TIME_LIMIT_EXCEEDED;
  417. break;
  418. }
  419. if (tm->par.node_limit >= 0 && tm->stat.analyzed >=
  420. tm->par.node_limit && termcode != TM_FINISHED){
  421. if (tm->active_node_num + tm->samephase_candnum > 0){
  422. termcode = TM_NODE_LIMIT_EXCEEDED;
  423. }else{
  424. termcode = TM_FINISHED;
  425. }
  426. break;
  427. }
  428. if (tm->par.find_first_feasible && tm->has_ub){
  429. termcode = TM_FINISHED;
  430. break;
  431. }
  432. if (i == NEW_NODE__ERROR){
  433. termcode = SOMETHING_DIED;
  434. break;
  435. }
  436. if (tm->has_ub && (tm->par.gap_limit >= 0.0)){
  437. find_tree_lb(tm);
  438. if (fabs(100*(tm->ub-tm->lb)/tm->ub) <= tm->par.gap_limit){
  439. if (tm->lb < tm->ub){
  440. termcode = TM_TARGET_GAP_ACHIEVED;
  441. }else{
  442. termcode = TM_FINISHED;
  443. }
  444. break;
  445. }
  446. }
  447. if (i == NEW_NODE__NONE && tm->active_node_num == 0)
  448. break;
  449. #ifndef COMPILE_IN_LP
  450. struct timeval timeout = {5, 0};
  451. r_bufid = treceive_msg(ANYONE, ANYTHING, &timeout);
  452. if (r_bufid && !process_messages(tm, r_bufid)){
  453. find_tree_lb(tm);
  454. termcode = SOMETHING_DIED;
  455. break;
  456. }
  457. #endif
  458. now = wall_clock(NULL);
  459. if (now - then > timeout4){
  460. if (!processes_alive(tm)){
  461. find_tree_lb(tm);
  462. termcode = SOMETHING_DIED;
  463. break;
  464. }
  465. then = now;
  466. }
  467. #pragma omp master
  468. {
  469. for (i = 0; i < tm->par.max_active_nodes; i++){
  470. if (tm->active_nodes[i]){
  471. break;
  472. }
  473. }
  474. if (i == tm->par.max_active_nodes){
  475. tm->active_node_num = 0;
  476. }
  477. if (now - then2 > timeout2){
  478. if(tm->par.verbosity >=0 ){
  479. print_tree_status(tm);
  480. }
  481. then2 = now;
  482. }
  483. if (now - then3 > timeout3){
  484. write_log_files(tm);
  485. then3 = now;
  486. }
  487. }
  488. }
  489. }
  490. if(termcode == TM_UNBOUNDED) break;
  491. if (tm->samephase_candnum + tm->active_node_num == 0){
  492. termcode = TM_FINISHED;
  493. }
  494. if (tm->nextphase_candnum == 0)
  495. break;
  496. if (termcode != TM_UNFINISHED)
  497. break;
  498. }
  499. find_tree_lb(tm);
  500. tm->comp_times.ramp_up_tm = ramp_up_tm;
  501. tm->comp_times.ramp_down_time = ramp_down_time;
  502. write_log_files(tm);
  503. return(termcode);
  504. }
  505. /*===========================================================================*/
  506. /*==========================================================================*\
  507. * Write out the log files
  508. \*==========================================================================*/
  509. void write_log_files(tm_prob *tm)
  510. {
  511. #if !defined(COMPILE_IN_LP) || !defined(COMPILE_IN_CP)
  512. int s_bufid;
  513. #endif
  514. if (tm->par.logging){
  515. write_tm_info(tm, tm->par.tree_log_file_name, NULL, FALSE);
  516. write_subtree(tm->rootnode, tm->par.tree_log_file_name, NULL, TRUE,
  517. tm->par.logging);
  518. if (tm->par.logging != VBC_TOOL)
  519. write_tm_cut_list(tm, tm->par.cut_log_file_name, FALSE);
  520. }
  521. if (tm->par.max_cp_num > 0 && tm->par.cp_logging){
  522. #if defined(COMPILE_IN_LP) && defined(COMPILE_IN_CP)
  523. write_cp_cut_list(tm->cpp[0], tm->cpp[0]->par.log_file_name,
  524. FALSE);
  525. #else
  526. s_bufid = init_send(DataInPlace);
  527. send_msg(tm->cp.procs[0], WRITE_LOG_FILE);
  528. #endif
  529. }
  530. }
  531. /*===========================================================================*/
  532. /*==========================================================================*\
  533. * Prints out the current size of the tree and the gap *
  534. \*==========================================================================*/
  535. void print_tree_status(tm_prob *tm)
  536. {
  537. double elapsed_time;
  538. double obj_ub = SYM_INFINITY, obj_lb = -SYM_INFINITY;
  539. #ifdef SHOULD_SHOW_MEMORY_USAGE
  540. int i;
  541. int pid;
  542. int tmp_int;
  543. long unsigned vsize;
  544. char tmp_str[100], proc_filename[100];
  545. FILE *proc_file;
  546. double vsize_in_mb;
  547. #endif
  548. #if 0
  549. int *widths;
  550. double *gamma;
  551. int last_full_level = 0, max_width = 0, num_nodes_estimate = 1;
  552. int first_waist_level = 0, last_waist_level = 0, waist_level = 0;
  553. double average_node_time, estimated_time_remaining, user_time = 0.0;
  554. widths = (int *) calloc (tm->stat.max_depth + 1, ISIZE);
  555. gamma = (double *) calloc (tm->stat.max_depth + 1, DSIZE);
  556. calculate_widths(tm->rootnode, widths);
  557. last_full_level = tm->stat.max_depth;
  558. for (i = tm->stat.max_depth - 1; i > 0; i--){
  559. if ((double)(widths[i])/(double)(widths[i - 1]) < 2){
  560. last_full_level = i - 1;
  561. }
  562. if (widths[i] > max_width){
  563. max_width = widths[i];
  564. last_waist_level = i;
  565. first_waist_level = i;
  566. }
  567. if (widths[i] == max_width){
  568. first_waist_level = i;
  569. }
  570. }
  571. waist_level = (first_waist_level + last_waist_level)/2;
  572. for (i = 0; i < tm->stat.max_depth; i++){
  573. if (i < last_full_level){
  574. gamma[i] = 2.0;
  575. }else if (i < waist_level){
  576. gamma[i] = 2.0 - (double)((i - last_full_level + 1))/
  577. (double)((waist_level - last_full_level + 1));
  578. }else{
  579. gamma[i] = 1.0 - (double)(i - waist_level + 1)/
  580. (double)(tm->stat.max_depth - waist_level + 1);
  581. }
  582. }
  583. for (i = 1; i < tm->stat.max_depth; i++){
  584. gamma[i] *= gamma[i - 1];
  585. num_nodes_estimate += (int)(gamma[i] + 0.5);
  586. }
  587. elapsed_time = wall_clock(NULL) - tm->start_time;
  588. average_node_time = elapsed_time/tm->stat.analyzed;
  589. estimated_time_remaining =
  590. MAX(average_node_time*(num_nodes_estimate - tm->stat.analyzed), 0);
  591. #else
  592. elapsed_time = wall_clock(NULL) - tm->start_time;
  593. #endif
  594. #ifdef SHOULD_SHOW_MEMORY_USAGE
  595. pid = getpid();
  596. //printf("process id = %d\n",pid);
  597. sprintf(proc_filename,"/proc/%d/stat",pid);
  598. proc_file = fopen (proc_filename, "r");
  599. fscanf (proc_file, "%d %s %s", &tmp_int, tmp_str, tmp_str);
  600. for (i=0; i<19;i++) {
  601. fscanf (proc_file, "%d", &tmp_int);
  602. }
  603. fscanf (proc_file, "%lu", &vsize);
  604. fclose(proc_file);
  605. //printf("vsize = %lu\n",vsize);
  606. vsize_in_mb = vsize/1024.0/1024.0;
  607. if (tm->stat.max_vsize<vsize_in_mb) {
  608. tm->stat.max_vsize = vsize_in_mb;
  609. }
  610. printf("memory: %.2f MB ", vsize_in_mb);
  611. #endif
  612. printf("done: %i ", tm->stat.analyzed-tm->active_node_num);
  613. printf("left: %i ", tm->samephase_candnum+tm->active_node_num);
  614. if (tm->has_ub) {
  615. if (tm->obj_sense == SYM_MAXIMIZE){
  616. obj_lb = -tm->ub + tm->obj_offset;
  617. printf("lb: %.2f ", obj_lb);
  618. }else{
  619. obj_ub = tm->ub + tm->obj_offset;
  620. printf("ub: %.2f ", obj_ub);
  621. }
  622. } else {
  623. if (tm->obj_sense == SYM_MAXIMIZE){
  624. printf("lb: ?? ");
  625. }else{
  626. printf("ub: ?? ");
  627. }
  628. }
  629. find_tree_lb(tm);
  630. if(tm->lb > -SYM_INFINITY){
  631. if (tm->obj_sense == SYM_MAXIMIZE){
  632. obj_ub = -tm->lb + tm->obj_offset;
  633. printf("ub: %.2f ", obj_ub);
  634. }else{
  635. obj_lb = tm->lb + tm->obj_offset;
  636. printf("lb: %.2f ", obj_lb);
  637. }
  638. }else{
  639. if (tm->obj_sense == SYM_MAXIMIZE){
  640. printf("ub: ?? ");
  641. }else{
  642. printf("lb: ?? ");
  643. }
  644. }
  645. if (tm->has_ub && tm->ub && tm->lb > -SYM_INFINITY){
  646. printf("gap: %.2f ", fabs(100*(obj_ub-obj_lb)/obj_ub));
  647. }
  648. printf("time: %i\n", (int)(elapsed_time));
  649. #if 0
  650. printf("Estimated nodes remaining: %i\n", num_nodes_estimate);
  651. printf("Estimated time remaining: %i\n",
  652. (int)(estimated_time_remaining));
  653. #endif
  654. if (tm->par.vbc_emulation == VBC_EMULATION_FILE){
  655. FILE *f;
  656. #pragma omp critical(write_vbc_emulation_file)
  657. if (!(f = fopen(tm->par.vbc_emulation_file_name, "a"))){
  658. printf("\nError opening vbc emulation file\n\n");
  659. }else{
  660. PRINT_TIME(tm, f);
  661. fprintf(f, "L %.2f \n", tm->lb);
  662. fclose(f);
  663. }
  664. }else if (tm->par.vbc_emulation == VBC_EMULATION_LIVE){
  665. printf("$L %.2f\n", tm->lb);
  666. }
  667. #if 0
  668. FREE(widths);
  669. FREE(gamma);
  670. #endif
  671. }
  672. /*===========================================================================*/
  673. void calculate_widths(bc_node *node, int* widths)
  674. {
  675. int i;
  676. widths[node->bc_level] += 1;
  677. for (i = 0; i < node->bobj.child_num; i ++){
  678. calculate_widths(node->children[i], widths);
  679. }
  680. }
  681. /*===========================================================================*/
  682. /*===========================================================================*\
  683. * This function picks the "best" node off the active node list
  684. \*===========================================================================*/
  685. int start_node(tm_prob *tm, int thread_num)
  686. {
  687. int lp_ind, get_next, ind;
  688. bc_node *best_node = NULL;
  689. double time;
  690. time = wall_clock(NULL);
  691. /*------------------------------------------------------------------------*\
  692. * First choose the "best" node from the list of candidate nodes.
  693. * If the list for the current phase is empty then we return NEW_NODE__NONE.
  694. * Also, if the lower bound on the "best" node is above the current UB then
  695. * we just move that node the list of next phase candidates.
  696. \*------------------------------------------------------------------------*/
  697. get_next = TRUE;
  698. while (get_next){
  699. if ((best_node = del_best_node(tm)) == NULL)
  700. return(NEW_NODE__NONE);
  701. if (best_node->node_status == NODE_STATUS__WARM_STARTED){
  702. if(best_node->lower_bound >= MAXDOUBLE)
  703. break;
  704. }
  705. /* if no UB yet or lb is lower than UB then go ahead */
  706. if (!tm->has_ub ||
  707. (tm->has_ub && best_node->lower_bound < tm->ub-tm->par.granularity))
  708. break;
  709. /* ok, so we do have an UB and lb is higher than the UB. */
  710. /* in this switch we assume that there are only two phases! */
  711. switch (((best_node->desc.nf_status) << 8) + tm->phase){
  712. case (NF_CHECK_NOTHING << 8) + 0: /* prune these */
  713. case (NF_CHECK_NOTHING << 8) + 1:
  714. if(!tm->par.sensitivity_analysis){
  715. if (tm->par.max_cp_num > 0 && best_node->cp){
  716. #ifdef COMPILE_IN_CP
  717. ind = best_node->cp;
  718. #else
  719. ind = find_process_index(&tm->cp, best_node->cp);
  720. #endif
  721. tm->nodes_per_cp[ind]--;
  722. if (tm->nodes_per_cp[ind] + tm->active_nodes_per_cp[ind] == 0)
  723. tm->cp.free_ind[tm->cp.free_num++] = ind;
  724. }
  725. best_node->node_status = NODE_STATUS__PRUNED;
  726. best_node->feasibility_status = OVER_UB_PRUNED;
  727. if (tm->par.verbosity > 0){
  728. printf("++++++++++++++++++++++++++++++++++++++++++++++++++\n");
  729. printf("+ TM: Pruning NODE %i LEVEL %i instead of sending it.\n",
  730. best_node->bc_index, best_node->bc_level);
  731. printf("++++++++++++++++++++++++++++++++++++++++++++++++++\n");
  732. }
  733. if (tm->par.keep_description_of_pruned == KEEP_ON_DISK_VBC_TOOL ||
  734. tm->par.keep_description_of_pruned == KEEP_ON_DISK_FULL ||
  735. tm->par.keep_description_of_pruned == DISCARD){
  736. if (tm->par.keep_description_of_pruned ==
  737. KEEP_ON_DISK_VBC_TOOL ||
  738. tm->par.keep_description_of_pruned == KEEP_ON_DISK_FULL){
  739. #pragma omp critical (write_pruned_node_file)
  740. write_pruned_nodes(tm, best_node);
  741. }
  742. #if 0
  743. if (tm->par.vbc_emulation == VBC_EMULATION_FILE_NEW) {
  744. purge_pruned_nodes(tm, best_node, VBC_PRUNED_FATHOMED);
  745. } else {
  746. purge_pruned_nodes(tm, best_node, VBC_PRUNED);
  747. }
  748. #else
  749. purge_pruned_nodes(tm, best_node, VBC_PRUNED);
  750. #endif
  751. }
  752. break;
  753. }
  754. case (NF_CHECK_ALL << 8) + 1: /* work on these */
  755. case (NF_CHECK_UNTIL_LAST << 8) + 1:
  756. case (NF_CHECK_AFTER_LAST << 8) + 1:
  757. get_next = FALSE;
  758. break;
  759. default:
  760. /* i.e., phase == 0 and nf_status != NF_CHECK_NOTHING */
  761. if (!(tm->par.colgen_strat[0] & FATHOM__GENERATE_COLS__RESOLVE)){
  762. REALLOC(tm->nextphase_cand, bc_node *, tm->nextphase_cand_size,
  763. tm->nextphase_candnum+1, BB_BUNCH);
  764. tm->nextphase_cand[tm->nextphase_candnum++] = best_node;
  765. }else{
  766. get_next = FALSE;
  767. }
  768. break;
  769. }
  770. }
  771. /* Assign a free lp process */
  772. #ifdef COMPILE_IN_LP
  773. lp_ind = thread_num;
  774. #else
  775. lp_ind = tm->lp.free_ind[--tm->lp.free_num];
  776. best_node->lp = tm->lp.procs[lp_ind];
  777. best_node->cg = tm->par.use_cg ? tm->cg.procs[lp_ind] : 0;
  778. #endif
  779. /* assign pools, too */
  780. best_node->cp = assign_pool(tm, best_node->cp, &tm->cp,
  781. tm->active_nodes_per_cp, tm->nodes_per_cp);
  782. if (best_node->cp < 0) return(NEW_NODE__ERROR);
  783. /* It's time to put together the node and send it out */
  784. tm->active_nodes[lp_ind] = best_node;
  785. tm->active_node_num++;
  786. tm->stat.analyzed++;
  787. send_active_node(tm,best_node,tm->par.colgen_strat[tm->phase],thread_num);
  788. tm->comp_times.start_node += wall_clock(NULL) - time;
  789. return(NEW_NODE__STARTED);
  790. }
  791. /*===========================================================================*/
  792. /*===========================================================================*\
  793. * Returns the "best" active node and deletes it from the list
  794. \*===========================================================================*/
  795. bc_node *del_best_node(tm_prob *tm)
  796. {
  797. bc_node **list = tm->samephase_cand;
  798. int size = tm->samephase_candnum;
  799. bc_node *temp = NULL, *best_node;
  800. int pos, ch;
  801. int rule = tm->par.node_selection_rule;
  802. if (size == 0)
  803. return(NULL);
  804. best_node = list[1];
  805. temp = list[1] = list[size];
  806. tm->samephase_candnum = --size;
  807. if (tm->par.verbosity > 10)
  808. if (tm->samephase_candnum % 10 == 0)
  809. printf("\nTM: tree size: %i , %i\n\n",
  810. tm->samephase_candnum, tm->nextphase_candnum);
  811. pos = 1;
  812. while ((ch=2*pos) < size){
  813. if (node_compar(rule, list[ch], list[ch+1]))
  814. ch++;
  815. if (node_compar(rule, list[ch], temp)){
  816. list[pos] = temp;
  817. return(best_node);
  818. }
  819. list[pos] = list[ch];
  820. pos = ch;
  821. }
  822. if (ch == size){
  823. if (node_compar(rule, temp, list[ch])){
  824. list[pos] = list[ch];
  825. pos = ch;
  826. }
  827. }
  828. list[pos] = temp;
  829. return(best_node);
  830. }
  831. /*===========================================================================*/
  832. /*===========================================================================*\
  833. * Insert a new active node into the active node list (kept as a binary tree)
  834. \*===========================================================================*/
  835. void insert_new_node(tm_prob *tm, bc_node *node)
  836. {
  837. int pos, ch, size = tm->samephase_candnum;
  838. bc_node **list;
  839. int rule = tm->par.node_selection_rule;
  840. tm->samephase_candnum = pos = ++size;
  841. if (tm->par.verbosity > 10)
  842. if (tm->samephase_candnum % 10 == 0)
  843. printf("\nTM: tree size: %i , %i\n\n",
  844. tm->samephase_candnum, tm->nextphase_candnum);
  845. REALLOC(tm->samephase_cand, bc_node *,
  846. tm->samephase_cand_size, size + 1, BB_BUNCH);
  847. list = tm->samephase_cand;
  848. while ((ch=pos>>1) != 0){
  849. if (node_compar(rule, list[ch], node)){
  850. list[pos] = list[ch];
  851. pos = ch;
  852. }else{
  853. break;
  854. }
  855. }
  856. list[pos] = node;
  857. }
  858. /*===========================================================================*/
  859. /*===========================================================================*\
  860. * This is the node comparison function used to order the list of active
  861. * Nodes are ordered differently depending on what the comparison rule is
  862. \*===========================================================================*/
  863. int node_compar(int rule, bc_node *node0, bc_node *node1)
  864. {
  865. switch(rule){
  866. case LOWEST_LP_FIRST:
  867. return(node1->lower_bound < node0->lower_bound ? 1:0);
  868. case HIGHEST_LP_FIRST:
  869. return(node1->lower_bound > node0->lower_bound ? 1:0);
  870. case BREADTH_FIRST_SEARCH:
  871. return(node1->bc_level < node0->bc_level ? 1:0);
  872. case DEPTH_FIRST_SEARCH:
  873. case DEPTH_FIRST_THEN_BEST_FIRST:
  874. return(node1->bc_level > node0->bc_level ? 1:0);
  875. }
  876. return(0); /* fake return */
  877. }
  878. /*===========================================================================*/
  879. /*===========================================================================*\
  880. * Nodes by default inherit their parent's pools. However if there is a free
  881. * pool then the node is moved over to the free pool.
  882. \*===========================================================================*/
  883. int assign_pool(tm_prob *tm, int oldpool, process_set *pools,
  884. int *active_nodes_per_pool, int *nodes_per_pool)
  885. {
  886. int oldind = -1, ind, pool;
  887. #ifndef COMPILE_IN_CP
  888. int s_bufid, r_bufid;
  889. struct timeval timeout = {5, 0};
  890. #endif
  891. if (pools->free_num == 0){
  892. /* No change in the pool assigned to this node */
  893. return(oldpool);
  894. }
  895. if (oldpool > 0){
  896. #ifdef COMPILE_IN_CP
  897. oldind = oldpool;
  898. #else
  899. oldind = find_process_index(pools, oldpool);
  900. #endif
  901. if (nodes_per_pool[oldind] == 1){
  902. nodes_per_pool[oldind]--;
  903. active_nodes_per_pool[oldind]++;
  904. return(oldpool);
  905. }
  906. }
  907. ind = pools->free_ind[--pools->free_num];
  908. #ifdef COMPILE_IN_CP
  909. pool = ind;
  910. #else
  911. pool = pools->procs[ind];
  912. #endif
  913. if (! oldpool){
  914. /* If no pool is assigned yet then just assign the free one */
  915. active_nodes_per_pool[ind] = 1;
  916. return(pool);
  917. }
  918. /* finally when we really move the node from one pool to another */
  919. nodes_per_pool[oldind]--;
  920. active_nodes_per_pool[ind] = 1;
  921. #ifdef COMPILE_IN_CP
  922. /*FIXME: Multiple Pools won't work in shared memory mode until I fill this
  923. in.*/
  924. #else
  925. s_bufid = init_send(DataInPlace);
  926. send_int_array(&oldpool, 1);
  927. send_msg(pool, POOL_YOU_ARE_USELESS);
  928. s_bufid = init_send(DataInPlace);
  929. send_int_array(&pool, 1);
  930. send_msg(oldpool, POOL_COPY_YOURSELF);
  931. freebuf(s_bufid);
  932. do{
  933. r_bufid = treceive_msg(pool, POOL_USELESSNESS_ACKNOWLEDGED, &timeout);
  934. if (r_bufid == 0)
  935. if (pstat(pool) != PROCESS_OK) return(NEW_NODE__ERROR);
  936. }while (r_bufid == 0);
  937. freebuf(r_bufid);
  938. #endif
  939. return(pool);
  940. }
  941. /*===========================================================================*/
  942. /*===========================================================================*\
  943. * Takes the branching object description and sets up data structures
  944. * for the resulting children and adds them to the list of candidates.
  945. \*===========================================================================*/
  946. int generate_children(tm_prob *tm, bc_node *node, branch_obj *bobj,
  947. double *objval, int *feasible, char *action,
  948. int olddive, int *keep, int new_branching_cut)
  949. {
  950. node_desc *desc;
  951. int np_cp = 0, np_sp = 0;
  952. int dive = DO_NOT_DIVE, i;
  953. bc_node *child;
  954. int child_num;
  955. #ifdef TRACE_PATH
  956. int optimal_path = -1;
  957. #endif
  958. /* before we start to generate the children we must figure out if we'll
  959. * dive so that we can put the kept child into the right location */
  960. if (*keep >= 0 && (olddive == CHECK_BEFORE_DIVE || olddive == DO_DIVE))
  961. dive = olddive == DO_DIVE ? DO_DIVE : shall_we_dive(tm, objval[*keep]);
  962. node->children = (bc_node **) calloc(bobj->child_num, sizeof(bc_node *));
  963. if (node->bc_level == tm->stat.max_depth)
  964. tm->stat.max_depth++;
  965. child_num = bobj->child_num;
  966. #ifdef TRACE_PATH
  967. if (node->optimal_path && tm->feas_sol_size){
  968. for (i = 0; i < tm->feas_sol_size; i++)
  969. if (tm->feas_sol[i] == bobj->name)
  970. break;
  971. if (i < tm->feas_sol_size)
  972. optimal_path = 1;
  973. else
  974. optimal_path = 0;
  975. printf("\n\nNode %i is on the optimal path\n\n",
  976. tm->stat.tree_size + optimal_path);
  977. }
  978. #endif
  979. for (i = 0; i < child_num; i++){
  980. child = node->children[i] = (bc_node *) calloc(1, sizeof(bc_node));
  981. child->bc_index = tm->stat.tree_size++;
  982. child->bc_level = node->bc_level + 1;
  983. child->lower_bound = objval[i];
  984. #ifdef COMPILE_IN_LP
  985. child->update_pc = bobj->is_est[i] ? TRUE : FALSE;
  986. #endif
  987. child->parent = node;
  988. if (tm->par.verbosity > 10){
  989. printf("Generating node %i from %i...\n", child->bc_index,
  990. node->bc_index);
  991. }
  992. if (tm->par.vbc_emulation == VBC_EMULATION_FILE){
  993. FILE *f;
  994. #pragma omp critical(write_vbc_emulation_file)
  995. if (!(f = fopen(tm->par.vbc_emulation_file_name, "a"))){
  996. printf("\nError opening vbc emulation file\n\n");
  997. }else{
  998. PRINT_TIME(tm, f);
  999. fprintf(f, "N %i %i %i\n", node->bc_index+1, child->bc_index+1,
  1000. feasible[i] ? VBC_FEAS_SOL_FOUND :
  1001. ((dive != DO_NOT_DIVE && *keep == i) ?
  1002. VBC_ACTIVE_NODE : VBC_CAND_NODE));
  1003. fclose(f);
  1004. }
  1005. } else if (tm->par.vbc_emulation == VBC_EMULATION_FILE_NEW) {
  1006. FILE *f;
  1007. #pragma omp critical(write_vbc_emulation_file)
  1008. if (!(f = fopen(tm->par.vbc_emulation_file_name, "a"))){
  1009. printf("\nError opening vbc emulation file\n\n");
  1010. }else{
  1011. PRINT_TIME2(tm, f);
  1012. char reason[50];
  1013. char branch_dir = 'M';
  1014. sprintf (reason, "%s %i %i", "candidate", child->bc_index+1,
  1015. node->bc_index+1);
  1016. if (child->bc_index>0){
  1017. if (node->children[0]==child) {
  1018. branch_dir = node->bobj.sense[0];
  1019. /*branch_dir = 'L';*/
  1020. } else {
  1021. branch_dir = node->bobj.sense[1];
  1022. /*branch_dir = 'R';*/
  1023. }
  1024. if (branch_dir == 'G') {
  1025. branch_dir = 'R';
  1026. }
  1027. }
  1028. if (action[i] == PRUNE_THIS_CHILD_FATHOMABLE ||
  1029. action[i] == PRUNE_THIS_CHILD_INFEASIBLE){
  1030. sprintf(reason,"%s %c", reason, branch_dir);
  1031. }else{
  1032. sprintf(reason,"%s %c %f", reason, branch_dir,
  1033. child->lower_bound);
  1034. }
  1035. fprintf(f,"%s\n",reason);
  1036. fclose(f);
  1037. }
  1038. }else if (tm->par.vbc_emulation == VBC_EMULATION_LIVE){
  1039. printf("$N %i %i %i\n", node->bc_index+1, child->bc_index+1,
  1040. feasible[i] ? VBC_FEAS_SOL_FOUND :
  1041. ((dive != DO_NOT_DIVE && *keep == i) ?
  1042. VBC_ACTIVE_NODE: VBC_CAND_NODE));
  1043. }
  1044. #ifdef TRACE_PATH
  1045. if (optimal_path == i)
  1046. child->optimal_path = TRUE;
  1047. #endif
  1048. tm->stat.created++;
  1049. #ifndef ROOT_NODE_ONLY
  1050. if (action[i] == PRUNE_THIS_CHILD ||
  1051. action[i] == PRUNE_THIS_CHILD_FATHOMABLE ||
  1052. action[i] == PRUNE_THIS_CHILD_INFEASIBLE ||
  1053. (tm->has_ub && tm->ub - tm->par.granularity < objval[i] &&
  1054. node->desc.nf_status == NF_CHECK_NOTHING)){
  1055. /* this last can happen if the TM got the new bound but it hasn't
  1056. * been propagated to the LP yet */
  1057. #else /*We only want to process the root node in this case - discard others*/
  1058. if (TRUE){
  1059. #endif
  1060. if (tm->par.verbosity > 0){
  1061. printf("++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
  1062. printf("+ TM: Pruning NODE %i LEVEL %i while generating it.\n",
  1063. child->bc_index, child->bc_level);
  1064. printf("++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
  1065. }
  1066. child->node_status = NODE_STATUS__PRUNED;
  1067. #ifdef TRACE_PATH
  1068. if (child->optimal_path){
  1069. printf("\n\nAttempting to prune the optimal path!!!!!!!!!\n\n");
  1070. sleep(600);
  1071. if (tm->par.logging){
  1072. write_tm_info(tm, tm->par.tree_log_file_name, NULL, FALSE);
  1073. write_subtree(tm->rootnode, tm->par.tree_log_file_name, NULL,
  1074. TRUE, tm->par.logging);
  1075. write_tm_cut_list(tm, tm->par.cut_log_file_name, FALSE);
  1076. }
  1077. exit(1);
  1078. }
  1079. #endif
  1080. if (tm->par.keep_description_of_pruned == DISCARD ||
  1081. tm->par.keep_description_of_pruned == KEEP_ON_DISK_VBC_TOOL){
  1082. child->parent = node;
  1083. if (tm->par.keep_description_of_pruned == KEEP_ON_DISK_VBC_TOOL)
  1084. #pragma omp critical (write_pruned_node_file)
  1085. write_pruned_nodes(tm, child);
  1086. if (tm->par.vbc_emulation == VBC_EMULATION_FILE_NEW) {
  1087. int vbc_node_pr_reason;
  1088. switch (action[i]) {
  1089. case PRUNE_THIS_CHILD_INFEASIBLE:
  1090. vbc_node_pr_reason = VBC_PRUNED_INFEASIBLE;
  1091. break;
  1092. case PRUNE_THIS_CHILD_FATHOMABLE:
  1093. vbc_node_pr_reason = VBC_PRUNED_FATHOMED;
  1094. break;
  1095. default:
  1096. vbc_node_pr_reason = VBC_PRUNED;
  1097. }
  1098. /* following is no longer needed because this care is taken
  1099. * care of in install_new_ub
  1100. */
  1101. /*
  1102. if (feasible[i]) {
  1103. vbc_node_pr_reason = VBC_FEAS_SOL_FOUND;
  1104. }
  1105. */
  1106. #pragma omp critical (tree_update)
  1107. purge_pruned_nodes(tm, child, vbc_node_pr_reason);
  1108. } else {
  1109. #pragma omp critical (tree_update)
  1110. purge_pruned_nodes(tm, child, feasible[i] ? VBC_FEAS_SOL_FOUND :
  1111. VBC_PRUNED);
  1112. }
  1113. if (--child_num == 0){
  1114. *keep = -1;
  1115. return(DO_NOT_DIVE);
  1116. }
  1117. if (*keep == child_num) *keep = i;
  1118. #ifdef TRACE_PATH
  1119. if (optimal_path == child_num) optimal_path = i;
  1120. #endif
  1121. action[i] = action[child_num];
  1122. objval[i] = objval[child_num];
  1123. feasible[i--] = feasible[child_num];
  1124. continue;
  1125. }
  1126. }else{
  1127. child->node_status = NODE_STATUS__CANDIDATE;
  1128. /* child->lp = child->cg = 0; zeroed out by calloc */
  1129. child->cp = node->cp;
  1130. }
  1131. #ifdef DO_TESTS
  1132. if (child->lower_bound < child->parent->lower_bound - .01){
  1133. printf("#######Error: Child's lower bound (%.3f) is less than ",
  1134. child->lower_bound);
  1135. printf("parent's (%.3f)\n", child->parent->lower_bound);
  1136. }
  1137. if (child->lower_bound < tm->rootnode->lower_bound - .01){
  1138. printf("#######Error: Node's lower bound (%.3f) is less than ",
  1139. child->lower_bound);
  1140. printf("root's (%.3f)\n", tm->rootnode->lower_bound);
  1141. }
  1142. #endif
  1143. /* child->children = NULL; zeroed out by calloc */
  1144. /* child->child_num = 0; zeroed out by calloc */
  1145. /* child->died = 0; zeroed out by calloc */
  1146. desc = &child->desc;
  1147. /* all this is set by calloc
  1148. * desc->uind.type = 0; WRT_PARENT and no change
  1149. * desc->uind.size = 0;
  1150. * desc->uind.added = 0;
  1151. * desc->uind.list = NULL;
  1152. * desc->not_fixed.type = 0; WRT_PARENT and no change
  1153. * desc->not_fixed.size = 0;
  1154. * desc->not_fixed.added = 0;
  1155. * desc->not_fixed.list = NULL;
  1156. * desc->cutind.type = 0; WRT_PARENT and no change
  1157. * desc->cutind.size = 0;
  1158. * desc->cutind.added = 0;
  1159. * desc->cutind.list = NULL;
  1160. * desc->basis.basis_exists = FALSE; This has to be validated!!!
  1161. * desc->basis.{[base,extra][rows,vars]}
  1162. .type = 0; WRT_PARENT and no change
  1163. .size = 0;
  1164. .list = NULL;
  1165. .stat = NULL;
  1166. */
  1167. if (node->desc.basis.basis_exists){
  1168. desc->basis.basis_exists = TRUE;
  1169. }
  1170. /* If we have a non-base, new branching cut then few more things
  1171. might have to be fixed */
  1172. if (new_branching_cut && bobj->name >= 0){
  1173. /* Fix cutind and the basis description */
  1174. desc->cutind.size = 1;
  1175. desc->cutind.added = 1;
  1176. desc->cutind.list = (int *) malloc(ISIZE);
  1177. desc->cutind.list[0] = bobj->name;
  1178. if (desc->basis.basis_exists){
  1179. desc->basis.extrarows.size = 1;
  1180. desc->basis.extrarows.list = (int *) malloc(ISIZE);
  1181. desc->basis.extrarows.list[0] = bobj->name;
  1182. desc->basis.extrarows.stat = (int *) malloc(ISIZE);
  1183. desc->basis.extrarows.stat[0] = SLACK_BASIC;
  1184. }
  1185. }
  1186. desc->desc_size = node->desc.desc_size;
  1187. desc->desc = node->desc.desc;
  1188. desc->nf_status = node->desc.nf_status;
  1189. #ifdef SENSITIVITY_ANALYSIS
  1190. if (tm->par.sensitivity_analysis &&
  1191. action[i] != PRUNE_THIS_CHILD_INFEASIBLE){
  1192. child->duals = bobj->duals[i];
  1193. bobj->duals[i] = 0;
  1194. }
  1195. #endif
  1196. if (child->node_status != NODE_STATUS__PRUNED && feasible[i]){
  1197. if(tm->par.keep_description_of_pruned == KEEP_IN_MEMORY){
  1198. child->sol_size = bobj->sol_sizes[i];
  1199. child->sol_ind = bobj->sol_inds[i];
  1200. bobj->sol_inds[i]=0;
  1201. child->sol = bobj->solutions[i];
  1202. bobj->solutions[i] = 0;
  1203. child->feasibility_status = NOT_PRUNED_HAS_CAN_SOLUTION;
  1204. }
  1205. }
  1206. if (child->node_status == NODE_STATUS__PRUNED){
  1207. if(tm->par.keep_description_of_pruned == KEEP_IN_MEMORY){
  1208. child->feasibility_status = OVER_UB_PRUNED;
  1209. if (feasible[i]){
  1210. child->sol_size = bobj->sol_sizes[i];
  1211. child->sol_ind = bobj->sol_inds[i];
  1212. bobj->sol_inds[i] = 0;
  1213. child->sol = bobj->solutions[i];
  1214. bobj->solutions[i] = 0;
  1215. child->feasibility_status = FEASIBLE_PRUNED;
  1216. }
  1217. if (action[i] == PRUNE_THIS_CHILD_INFEASIBLE){
  1218. child->feasibility_status = INFEASIBLE_PRUNED;
  1219. }
  1220. }
  1221. #ifdef TRACE_PATH
  1222. if (child->optimal_path){
  1223. printf("\n\nAttempting to prune the optimal path!!!!!!!!!\n\n");
  1224. sleep(600);
  1225. if (tm->par.logging){
  1226. write_tm_info(tm, tm->par.tree_log_file_name, NULL, FALSE);
  1227. write_subtree(tm->rootnode, tm->par.tree_log_file_name, NULL,
  1228. TRUE, tm->par.logging);
  1229. write_tm_cut_list(tm, tm->par.cut_log_file_name, FALSE);
  1230. }
  1231. exit(1);
  1232. }
  1233. #endif
  1234. if (tm->par.keep_description_of_pruned == KEEP_ON_DISK_FULL ||
  1235. tm->par.keep_description_of_pruned == KEEP_ON_DISK_VBC_TOOL){
  1236. #pragma omp critical (write_pruned_node_file)
  1237. write_pruned_nodes(tm, child);
  1238. #pragma omp critical (tree_update)
  1239. if (tm->par.vbc_emulation== VBC_EMULATION_FILE_NEW) {
  1240. int vbc_node_pr_reason;
  1241. switch (action[i]) {
  1242. case PRUNE_THIS_CHILD_INFEASIBLE:
  1243. vbc_node_pr_reason = VBC_PRUNED_INFEASIBLE;
  1244. break;
  1245. case PRUNE_THIS_CHILD_FATHOMABLE:
  1246. vbc_node_pr_reason = VBC_PRUNED_FATHOMED;
  1247. break;
  1248. default:
  1249. vbc_node_pr_reason = VBC_PRUNED;
  1250. }
  1251. /* following is no longer needed because this care is taken
  1252. * care of in install_new_ub
  1253. */
  1254. /*
  1255. if (feasible[i]) {
  1256. vbc_node_pr_reason = VBC_FEAS_SOL_FOUND;
  1257. }
  1258. */
  1259. purge_pruned_nodes(tm, child, vbc_node_pr_reason);
  1260. } else {
  1261. purge_pruned_nodes(tm, child, feasible[i] ? VBC_FEAS_SOL_FOUND :
  1262. VBC_PRUNED);
  1263. }
  1264. if (--child_num == 0){
  1265. *keep = -1;
  1266. return(DO_NOT_DIVE);
  1267. }
  1268. if (*keep == child_num) *keep = i;
  1269. #ifdef TRACE_PATH
  1270. if (optimal_path == child_num) optimal_path = i;
  1271. #endif
  1272. action[i] = action[child_num];
  1273. objval[i] = objval[child_num];
  1274. feasible[i--] = feasible[child_num];
  1275. }
  1276. continue;
  1277. }
  1278. if (tm->phase == 0 &&
  1279. !(tm->par.colgen_strat[0] & FATHOM__GENERATE_COLS__RESOLVE) &&
  1280. (feasible[i] == LP_D_UNBOUNDED ||
  1281. (tm->has_ub && tm->ub - tm->par.granularity < child->lower_bound))){
  1282. /* it is kept for the next phase (==> do not dive) */
  1283. if (*keep == i)
  1284. dive = DO_NOT_DIVE;
  1285. REALLOC(tm->nextphase_cand, bc_node *,
  1286. tm->nextphase_cand_size, tm->nextphase_candnum+1, BB_BUNCH);
  1287. tm->nextphase_cand[tm->nextphase_candnum++] = child;
  1288. np_cp++;
  1289. np_sp++;
  1290. }else{
  1291. /* it will be processed in this phase (==> insert it if not kept) */
  1292. if (*keep != i || dive == DO_NOT_DIVE){
  1293. #pragma omp critical (tree_update)
  1294. insert_new_node(tm, child);
  1295. np_cp++;
  1296. np_sp++;
  1297. }
  1298. }
  1299. }
  1300. if (node->cp)
  1301. #ifdef COMPILE_IN_CP
  1302. tm->nodes_per_cp[node->cp] += np_cp;
  1303. #else
  1304. tm->nodes_per_cp[find_process_index(&tm->cp, node->cp)] += np_cp;
  1305. #endif
  1306. return(dive);
  1307. }
  1308. /*===========================================================================*/
  1309. /*===========================================================================*\
  1310. * Determines whether or not the LP process should keep one of the
  1311. * children resulting from branching or whether it should get a new node
  1312. * from the candidate list.
  1313. \*===========================================================================*/
  1314. char shall_we_dive(tm_prob *tm, double objval)
  1315. {
  1316. char dive;
  1317. int i, k;
  1318. double rand_num, average_lb;
  1319. double cutoff = 0;
  1320. double etol = 1e-3;
  1321. if (tm->par.time_limit >= 0.0 &&
  1322. wall_clock(NULL) - tm->start_time >= tm->par.time_limit){
  1323. return(FALSE);
  1324. }
  1325. if (tm->par.node_limit >= 0 && tm->stat.analyzed >= tm->par.node_limit){
  1326. return(FALSE);
  1327. }
  1328. if (tm->has_ub && (tm->par.gap_limit >= 0.0)){
  1329. find_tree_lb(tm);
  1330. if (100*(tm->ub-tm->lb)/(fabs(tm->ub)+etol) <= tm->par.gap_limit){
  1331. return(FALSE);
  1332. }
  1333. }
  1334. rand_num = ((double)(RANDOM()))/((double)(MAXINT));
  1335. if (tm->par.unconditional_dive_frac > 1 - rand_num){
  1336. dive = CHECK_BEFORE_DIVE;
  1337. }else{
  1338. switch(tm->par.diving_strategy){
  1339. case BEST_ESTIMATE:
  1340. if (tm->has_ub_estimate){
  1341. if (objval > tm->ub_estimate){
  1342. dive = DO_NOT_DIVE;
  1343. tm->stat.diving_halts++;
  1344. }else{
  1345. dive = CHECK_BEFORE_DIVE;
  1346. }
  1347. break;
  1348. }
  1349. case COMP_BEST_K:
  1350. average_lb = 0;
  1351. #pragma omp critical (tree_update)
  1352. for (k = 0, i = MIN(tm->samephase_candnum, tm->par.diving_k);
  1353. i > 0; i--)
  1354. if (tm->samephase_cand[i]->lower_bound < MAXDOUBLE/2){
  1355. average_lb += tm->samephase_cand[i]->lower_bound;
  1356. k++;
  1357. }
  1358. if (k){
  1359. average_lb /= k;
  1360. }else{
  1361. dive = CHECK_BEFORE_DIVE;
  1362. break;
  1363. }
  1364. if (fabs(average_lb) < etol) {
  1365. average_lb = (average_lb > 0) ? etol : -etol;
  1366. if (fabs(objval) < etol) {
  1367. objval = (objval > 0) ? etol : -etol;
  1368. }
  1369. }
  1370. if (fabs((objval/average_lb)-1) > tm->par.diving_threshold){
  1371. dive = DO_NOT_DIVE;
  1372. tm->stat.diving_halts++;
  1373. }else{
  1374. dive = CHECK_BEFORE_DIVE;
  1375. }
  1376. break;
  1377. case COMP_BEST_K_GAP:
  1378. average_lb = 0;
  1379. for (k = 0, i = MIN(tm->samephase_candnum, tm->par.diving_k);
  1380. i > 0; i--)
  1381. if (tm->samephase_cand[i]->lower_bound < MAXDOUBLE/2){
  1382. average_lb += tm->samephase_cand[i]->lower_bound;
  1383. k++;
  1384. }
  1385. if (k){
  1386. average_lb /= k;
  1387. }else{
  1388. dive = CHECK_BEFORE_DIVE;
  1389. break;
  1390. }
  1391. if (tm->has_ub)
  1392. cutoff = tm->par.diving_threshold*(tm->ub - average_lb);
  1393. else
  1394. cutoff = (1 + tm->par.diving_threshold)*average_lb;
  1395. if (objval > average_lb + cutoff){
  1396. dive = DO_NOT_DIVE;
  1397. tm->stat.diving_halts++;
  1398. }else{
  1399. dive = CHECK_BEFORE_DIVE;
  1400. }
  1401. break;
  1402. default:
  1403. printf("Unknown diving strategy -- diving by default\n");
  1404. dive = DO_DIVE;
  1405. break;
  1406. }
  1407. }
  1408. return(dive);
  1409. }
  1410. /*===========================================================================*/
  1411. /*===========================================================================*\
  1412. * This routine is entirely for saving memory. If there is no need to
  1413. * keep the description of the pruned nodes in memory, they are freed as
  1414. * soon as they are no longer needed. This can set off a chain reaction
  1415. * of other nodes that are no longer needed.
  1416. \*===========================================================================*/
  1417. int purge_pruned_nodes(tm_prob *tm, bc_node *node, int category)
  1418. {
  1419. int i, new_child_num;
  1420. branch_obj *bobj = &node->parent->bobj;
  1421. char reason[30];
  1422. char branch_dir = 'M';
  1423. if (tm->par.vbc_emulation != VBC_EMULATION_FILE_NEW &&
  1424. (category == VBC_PRUNED_INFEASIBLE || category == VBC_PRUNED_FATHOMED
  1425. || category == VBC_IGNORE)) {
  1426. printf("Error in purge_pruned_nodes.");
  1427. printf("category refers to VBC_EMULATION_FILE_NEW");
  1428. printf("when it is not used.\n");
  1429. exit(456);
  1430. }
  1431. if (tm->par.vbc_emulation == VBC_EMULATION_FILE_NEW) {
  1432. switch (category) {
  1433. case VBC_PRUNED_INFEASIBLE:
  1434. sprintf(reason,"%s","infeasible");
  1435. sprintf(reason,"%s %i %i",reason, node->bc_index+1,
  1436. node->parent->bc_index+1);
  1437. if (node->bc_index>0) {
  1438. if (node->parent->children[0]==node) {
  1439. branch_dir = node->parent->bobj.sense[0];
  1440. /*branch_dir = 'L';*/
  1441. } else {
  1442. branch_dir = node->parent->bobj.sense[1];
  1443. /*branch_dir = 'R';*/
  1444. }
  1445. if (branch_dir == 'G') {
  1446. branch_dir = 'R';
  1447. }
  1448. }
  1449. sprintf(reason,"%s %c %s", reason, branch_dir, "\n");
  1450. break;
  1451. case VBC_PRUNED_FATHOMED:
  1452. sprintf(reason,"%s","fathomed");
  1453. sprintf(reason,"%s %i %i",reason, node->bc_index+1,
  1454. node->parent->bc_index+1);
  1455. if (node->bc_index>0) {
  1456. if (node->parent->children[0]==node) {
  1457. branch_dir = node->parent->bobj.sense[0];
  1458. /*branch_dir = 'L';*/
  1459. } else {
  1460. branch_dir = node->parent->bobj.sense[1];
  1461. /*branch_dir = 'R';*/
  1462. }
  1463. if (branch_dir == 'G') {
  1464. branch_dir = 'R';
  1465. }
  1466. }
  1467. sprintf(reason,"%s %c %s", reason, branch_dir, "\n");
  1468. break;
  1469. case VBC_FEAS_SOL_FOUND:
  1470. /* This case has already been dealt in install_new_ub(), hence
  1471. * commented out
  1472. */
  1473. /* sprintf(reason,"%s","integer");
  1474. sprintf(reason,"%s %i %i",reason, node->bc_index+1,
  1475. node->parent->bc_index+1);
  1476. if (node->parent->children[0]==node) {
  1477. branch_dir = 'L';
  1478. } else {
  1479. branch_dir = 'R';
  1480. }
  1481. sprintf(reason,"%s %c %f\n", reason, branch_dir, tm->ub);
  1482. break;
  1483. */
  1484. default:
  1485. category = VBC_IGNORE;
  1486. break;
  1487. }
  1488. }
  1489. if (node->parent == NULL){
  1490. return(1);
  1491. }
  1492. if (category == VBC_IGNORE) {
  1493. #if 0
  1494. PRINT(tm->par.verbosity, 1,
  1495. ("ignoring vbc update in purge_pruned_nodes"));
  1496. #endif
  1497. } else if (tm->par.vbc_emulation == VBC_EMULATION_FILE){
  1498. FILE *f;
  1499. #pragma omp critical(write_vbc_emulation_file)
  1500. if (!(f = fopen(tm->par.vbc_emulation_file_name, "a"))){
  1501. printf("\nError opening vbc emulation file\n\n");
  1502. }else{
  1503. PRINT_TIME(tm, f);
  1504. fprintf(f, "P %i %i\n", node->bc_index+1, category);
  1505. fclose(f);
  1506. }
  1507. } else if (tm->par.vbc_emulation == VBC_EMULATION_LIVE){
  1508. printf("$P %i %i\n", node->bc_index+1, category);
  1509. } else if (tm->par.vbc_emulation == VBC_EMULATION_FILE_NEW) {
  1510. FILE *f;
  1511. #pragma omp critical(write_vbc_emulation_file)
  1512. if (!(f = fopen(tm->par.vbc_emulation_file_name, "a"))){
  1513. printf("\nError opening vbc emulation file\n\n");
  1514. }else{
  1515. PRINT_TIME2(tm, f);
  1516. fprintf(f, "%s", reason);
  1517. fclose(f);
  1518. }
  1519. }
  1520. if ((new_child_num = --bobj->child_num) == 0){
  1521. if (tm->par.vbc_emulation == VBC_EMULATION_FILE_NEW) {
  1522. purge_pruned_nodes(tm, node->parent, VBC_IGNORE);
  1523. } else {
  1524. purge_pruned_nodes(tm, node->parent, category);
  1525. }
  1526. }else{
  1527. for (i = 0; i <= bobj->child_num; i++){
  1528. if (node->parent->children[i] == node){
  1529. if (i == new_child_num){
  1530. node->parent->children[i] = NULL;
  1531. }else{
  1532. node->parent->children[i]=node->parent->children[new_child_num];
  1533. bobj->sense[i] = bobj->sense[new_child_num];
  1534. bobj->rhs[i] = bobj->rhs[new_child_num];
  1535. bobj->range[i] = bobj->range[new_child_num];
  1536. bobj->branch[i] = bobj->branch[new_child_num];
  1537. }
  1538. }
  1539. }
  1540. }
  1541. free_tree_node(node);
  1542. return(1);
  1543. }
  1544. /*===========================================================================*\
  1545. * This routine is for writing the pruned nodes to disk before deleting them
  1546. * from memory.
  1547. \*===========================================================================*/
  1548. int write_pruned_nodes(tm_prob *tm, bc_node *node)
  1549. {
  1550. FILE *f = NULL;
  1551. branch_obj *bobj = &node->parent->bobj;
  1552. if (tm->par.keep_description_of_pruned == KEEP_ON_DISK_FULL ||
  1553. tm->par.keep_description_of_pruned == KEEP_ON_DISK_VBC_TOOL){
  1554. if (!(f = fopen(tm->par.pruned_node_file_name, "a"))){
  1555. printf("\nError opening pruned node file\n\n");
  1556. return(0);
  1557. }
  1558. }
  1559. if (node->parent == NULL){
  1560. return(1);
  1561. }
  1562. if (bobj->child_num == 1){
  1563. write_pruned_nodes(tm, node->parent);
  1564. }
  1565. if (tm->par.keep_description_of_pruned == KEEP_ON_DISK_VBC_TOOL){
  1566. if (node->parent)
  1567. fprintf(f, "%i %i\n", node->parent->bc_index + 1, node->bc_index + 1);
  1568. fclose(f);
  1569. }else if (tm->par.keep_description_of_pruned == KEEP_ON_DISK_FULL){
  1570. write_node(node, tm->par.pruned_node_file_name, f, TRUE);
  1571. fclose(f);
  1572. }
  1573. return(1);
  1574. }
  1575. /*===========================================================================*/
  1576. /*===========================================================================*\
  1577. * Find the index of a particular process in a list
  1578. \*===========================================================================*/
  1579. int find_process_index(process_set *pset, int tid)
  1580. {
  1581. int i = pset->procnum-1, *procs = pset->procs;
  1582. for ( ; i >= 0 && procs[i] != tid; i--);
  1583. #ifdef DO_TESTS
  1584. if (i == -1){
  1585. printf("TM: process index not found !!!\n\n");
  1586. exit(-5);
  1587. }
  1588. #endif
  1589. return(i);
  1590. }
  1591. /*===========================================================================*/
  1592. void mark_lp_process_free(tm_prob *tm, int lp, int cp)
  1593. {
  1594. int ind;
  1595. if (tm->cp.procnum > 0){
  1596. #ifdef COMPILE_IN_CP
  1597. ind = cp;
  1598. #else
  1599. ind = find_process_index(&tm->cp, cp);
  1600. #endif
  1601. tm->active_nodes_per_cp[ind]--;
  1602. if (tm->nodes_per_cp[ind] + tm->active_nodes_per_cp[ind] == 0)
  1603. tm->cp.free_ind[tm->cp.free_num++] = ind;
  1604. }
  1605. tm->active_nodes[lp] = NULL;
  1606. tm->lp.free_ind[tm->lp.free_num++] = lp;
  1607. tm->active_node_num--;
  1608. }
  1609. /*===========================================================================*/
  1610. int add_cut_to_list(tm_prob *tm, cut_data *cut)
  1611. {
  1612. #pragma omp critical (cut_pool)
  1613. {
  1614. REALLOC(tm->cuts, cut_data *, tm->allocated_cut_num, tm->cut_num + 1,
  1615. (tm->cut_num / tm->stat.created + 5) * BB_BUNCH);
  1616. cut->name = tm->cut_num;
  1617. tm->cuts[tm->cut_num++] = cut;
  1618. }
  1619. return(cut->name);
  1620. }
  1621. /*===========================================================================*/
  1622. /*===========================================================================*\
  1623. * Installs a new upper bound and cleans up the candidate list
  1624. \*===========================================================================*/
  1625. void install_new_ub(tm_prob *tm, double new_ub, int opt_thread_num,
  1626. int bc_index, char branching, int feasible){
  1627. bc_node *node, *temp, **list;
  1628. int rule, pos, prev_pos, last, i;
  1629. tm->has_ub = TRUE;
  1630. tm->ub = new_ub;
  1631. #ifdef COMPILE_IN_LP
  1632. tm->opt_thread_num = opt_thread_num;
  1633. #endif
  1634. if (tm->par.vbc_emulation == VBC_EMULATION_FILE){
  1635. FILE *f;
  1636. #pragma omp critical(write_vbc_emulation_file)
  1637. if (!(f = fopen(tm->par.vbc_emulation_file_name, "a"))){
  1638. printf("\nError opening vbc emulation file\n\n");
  1639. }else{
  1640. PRINT_TIME(tm, f);
  1641. fprintf(f, "U %.2f\n", new_ub);
  1642. fclose(f);
  1643. }
  1644. }else if (tm->par.vbc_emulation == VBC_EMULATION_LIVE){
  1645. printf("$U %.2f\n", new_ub);
  1646. }else if (tm->par.vbc_emulation == VBC_EMULATION_FILE_NEW &&
  1647. (feasible == IP_FEASIBLE || feasible == IP_HEUR_FEASIBLE)){
  1648. FILE *f;
  1649. // char reason[30];
  1650. char branch_dir = 'M';
  1651. if (!(f = fopen(tm->par.vbc_emulation_file_name, "a"))){
  1652. printf("\nError opening vbc emulation file\n\n");
  1653. }else if ((feasible == IP_FEASIBLE && branching) ||
  1654. (feasible == IP_HEUR_FEASIBLE)) {
  1655. #pragma omp critical(write_vbc_emulation_file)
  1656. PRINT_TIME2(tm, f);
  1657. fprintf(f, "%s %f %i\n", "heuristic", new_ub, bc_index+1);
  1658. }else if (feasible == IP_FEASIBLE && !branching){
  1659. node = tm->active_nodes[opt_thread_num];
  1660. if (node->bc_index>0) {
  1661. if (node->parent->children[0]==node) {
  1662. branch_dir = node->parent->bobj.sense[0];
  1663. /*branch_dir = 'L';*/
  1664. } else {
  1665. branch_dir = node->parent->bobj.sense[1];
  1666. /*branch_dir = 'R';*/
  1667. }
  1668. if (branch_dir == 'G') {
  1669. branch_dir = 'R';
  1670. }
  1671. }
  1672. PRINT_TIME2(tm, f);
  1673. if (node->bc_index){
  1674. fprintf (f, "%s %i %i %c %f\n", "integer", node->bc_index+1,
  1675. node->parent->bc_index+1, branch_dir, new_ub);
  1676. }else{
  1677. fprintf (f, "%s %i %i %c %f\n", "integer", 1, 0, 'M', new_ub);
  1678. }
  1679. }
  1680. if (f){
  1681. fclose(f);
  1682. }
  1683. }
  1684. /* Remove nodes that can now be fathomed from the list */
  1685. #pragma omp critical (tree_update)
  1686. {
  1687. rule = tm->par.node_selection_rule;
  1688. list = tm->samephase_cand;
  1689. char has_exchanged = FALSE;
  1690. for (last = i = tm->samephase_candnum; i > 0; i--){
  1691. has_exchanged = FALSE;
  1692. node = list[i];
  1693. if (tm->has_ub &&
  1694. node->lower_bound >= tm->ub-tm->par.granularity){
  1695. if (i != last){
  1696. list[i] = list[last];
  1697. for (prev_pos = i, pos = i/2; pos >= 1;
  1698. prev_pos = pos, pos /= 2){
  1699. if (node_compar(rule, list[pos], list[prev_pos])){
  1700. temp = list[prev_pos];
  1701. list[prev_pos] = list[pos];
  1702. list[pos] = temp;
  1703. has_exchanged = TRUE;
  1704. }else{
  1705. break;
  1706. }
  1707. }
  1708. }
  1709. tm->samephase_cand[last] = NULL;
  1710. last--;
  1711. if (tm->par.verbosity > 0){
  1712. printf("+++++++++++++++++++++++++++++++++++++++++++++++++++\n");
  1713. printf("+ TM: Pruning NODE %i LEVEL %i after new incumbent.\n",
  1714. node->bc_index, node->bc_level);
  1715. printf("+++++++++++++++++++++++++++++++++++++++++++++++++++\n");
  1716. }
  1717. if (tm->par.keep_description_of_pruned == DISCARD ||
  1718. tm->par.keep_description_of_pruned ==
  1719. KEEP_ON_DISK_VBC_TOOL){
  1720. if (tm->par.keep_description_of_pruned ==
  1721. KEEP_ON_DISK_VBC_TOOL)
  1722. #pragma omp critical (write_pruned_node_file)
  1723. write_pruned_nodes(tm, node);
  1724. if (tm->par.vbc_emulation == VBC_EMULATION_FILE_NEW) {
  1725. purge_pruned_nodes(tm, node,
  1726. VBC_PRUNED_FATHOMED);
  1727. } else {
  1728. purge_pruned_nodes(tm, node, VBC_PRUNED);
  1729. }
  1730. }
  1731. }
  1732. if (has_exchanged) {
  1733. /*
  1734. * if exchanges have taken place, node[i] should be
  1735. * checked again for pruning
  1736. */
  1737. i++;
  1738. }
  1739. }
  1740. tm->samephase_candnum = last;
  1741. }
  1742. }
  1743. /*===========================================================================*/
  1744. /*===========================================================================*\
  1745. * This routine takes the description of the node after processing and
  1746. * compares it to the description before processing. Then it updates
  1747. * data structures appropriately. The other functions below are all
  1748. * related to this one.
  1749. \*===========================================================================*/
  1750. void merge_descriptions(node_desc *old_node, node_desc *new_node)
  1751. {
  1752. if (old_node->basis.basis_exists && new_node->basis.basis_exists){
  1753. merge_base_stat(&old_node->basis.basevars, &new_node->basis.basevars);
  1754. merge_extra_array_and_stat(&old_node->uind, &old_node->basis.extravars,
  1755. &new_node->uind, &new_node->basis.extravars);
  1756. merge_base_stat(&old_node->basis.baserows, &new_node->basis.baserows);
  1757. merge_extra_array_and_stat(&old_node->cutind,&old_node->basis.extrarows,
  1758. &new_node->cutind,&new_node->basis.extrarows);
  1759. }else{
  1760. old_node->basis = new_node->basis;
  1761. merge_arrays(&old_node->uind, &new_node->uind);
  1762. merge_arrays(&old_node->cutind, &new_node->cutind);
  1763. #ifdef COMPILE_IN_LP
  1764. memset((char *)&(new_node->basis), 0, sizeof(basis_desc));
  1765. #endif
  1766. }
  1767. old_node->nf_status = new_node->nf_status;
  1768. if (new_node->nf_status == NF_CHECK_AFTER_LAST ||
  1769. new_node->nf_status == NF_CHECK_UNTIL_LAST){
  1770. merge_arrays(&old_node->not_fixed, &new_node->not_fixed);
  1771. }else{
  1772. FREE(old_node->not_fixed.list);
  1773. }
  1774. }
  1775. /*===========================================================================*/
  1776. void merge_base_stat(double_array_desc *dad, double_array_desc *moddad)
  1777. {
  1778. if (moddad->type == EXPLICIT_LIST){
  1779. FREE(dad->list);
  1780. FREE(dad->stat);
  1781. *dad = *moddad;
  1782. #ifdef COMPILE_IN_LP
  1783. moddad->stat = NULL;
  1784. #endif
  1785. return;
  1786. }
  1787. /* we've got a diff list against the old list */
  1788. if (moddad->size > 0) { /* if there is a change */
  1789. if (dad->type == EXPLICIT_LIST){
  1790. /* just overwrite the changes */
  1791. int i;
  1792. int *oldstat = dad->stat;
  1793. int newsize = moddad->size;
  1794. int *newlist = moddad->list;
  1795. int *newstat = moddad->stat;
  1796. for (i = newsize - 1; i >= 0; i--)
  1797. oldstat[newlist[i]] = newstat[i];
  1798. }else{
  1799. merge_double_array_descs(dad, moddad);
  1800. }
  1801. }
  1802. }
  1803. /*===========================================================================*/
  1804. void merge_extra_array_and_stat(array_desc *ad, double_array_desc *dad,
  1805. array_desc *modad, double_array_desc *moddad)
  1806. {
  1807. if (moddad->type != WRT_PARENT){
  1808. /* If moddad is explicit then just use it */
  1809. FREE(dad->list);
  1810. FREE(dad->stat);
  1811. *dad = *moddad;
  1812. #ifdef COMPILE_IN_LP
  1813. moddad->stat = NULL;
  1814. #endif
  1815. }else{
  1816. /* So moddad is WRT. Then dad must be WRT, too!! */
  1817. /* First throw out from dad everything that's just been deleted */
  1818. int newdeled = modad->size - modad->added;
  1819. int *newtodel = modad->list + modad->added;
  1820. int i, j, k, nextdel;
  1821. if (newdeled > 0 && dad->size > 0){
  1822. int dsize = dad->size;
  1823. int *dlist = dad->list;
  1824. int *dstat = dad->stat;
  1825. k = j = 0;
  1826. for (i = 0; i < newdeled; ){
  1827. nextdel = newtodel[i];
  1828. for (; j < dsize && dlist[j] < nextdel; ){
  1829. dlist[k] = dlist[j];
  1830. dstat[k++] = dstat[j++];
  1831. }
  1832. if (j == dsize){
  1833. break;
  1834. }else{ /* in this case dlist[j] >= nextdel */
  1835. i++;
  1836. if (dlist[j] == nextdel)
  1837. j++;
  1838. }
  1839. }
  1840. while (j < dsize){
  1841. dlist[k] = dlist[j];
  1842. dstat[k++] = dstat[j++];
  1843. }
  1844. dad->size = k;
  1845. }
  1846. /* Now merge the remaining dad and moddad together */
  1847. merge_double_array_descs(dad, moddad);
  1848. }
  1849. /* dad is fine now. Update ad */
  1850. merge_arrays(ad, modad);
  1851. }
  1852. /*===========================================================================*/
  1853. /*===========================================================================*\
  1854. * Merge the old and new changes together, in case of identical
  1855. * userindices the newer value overrides the older
  1856. \*===========================================================================*/
  1857. void merge_double_array_descs(double_array_desc *dad,
  1858. double_array_desc *moddad)
  1859. {
  1860. if (moddad->size != 0){
  1861. if (dad->size == 0){
  1862. *dad = *moddad;
  1863. #ifdef COMPILE_IN_LP
  1864. moddad->stat = moddad->list = NULL;
  1865. #endif
  1866. }else{
  1867. int i, j, k;
  1868. int oldsize = dad->size;
  1869. int *oldlist = dad->list;
  1870. int *oldstat = dad->stat;
  1871. int newsize = moddad->size;
  1872. int *newlist = moddad->list;
  1873. int *newstat = moddad->stat;
  1874. int *dlist = dad->list = (int *) malloc((oldsize+newsize) * ISIZE);
  1875. int *dstat = dad->stat = (int *) malloc((oldsize+newsize) * ISIZE);
  1876. for (k = 0, i = j = 0; i < oldsize && j < newsize; ){
  1877. if (oldlist[i] < newlist[j]){
  1878. dlist[k] = oldlist[i];
  1879. dstat[k++] = oldstat[i++];
  1880. }else{
  1881. if (oldlist[i] == newlist[j])
  1882. i++;
  1883. dlist[k] = newlist[j];
  1884. dstat[k++] = newstat[j++];
  1885. }
  1886. }
  1887. while (i < oldsize){
  1888. dlist[k] = oldlist[i];
  1889. dstat[k++] = oldstat[i++];
  1890. }
  1891. while (j < newsize){
  1892. dlist[k] = newlist[j];
  1893. dstat[k++] = newstat[j++];
  1894. }
  1895. dad->size = k;
  1896. FREE(oldlist);
  1897. FREE(oldstat);
  1898. FREE(moddad->list);
  1899. FREE(moddad->stat);
  1900. }
  1901. }
  1902. }
  1903. /*===========================================================================*/
  1904. void merge_arrays(array_desc *array, array_desc *adesc)
  1905. {
  1906. if (adesc->type != WRT_PARENT){
  1907. /* Replace the old with the new one */
  1908. FREE(array->list);
  1909. *array = *adesc;
  1910. #ifdef COMPILE_IN_LP
  1911. adesc->list = NULL;
  1912. #endif
  1913. return;
  1914. }
  1915. if (adesc->size == 0){
  1916. /* No change, leave the old description alone. */
  1917. return;
  1918. }
  1919. if (array->size == 0){
  1920. /* The old size is 0 (the new type is still WRT_PARENT).
  1921. If the old type was WRT_PARENT then we can simply replace it with
  1922. the new WRT_PARENT data.
  1923. If it was EXPLICIT_LIST with nothing in it, then... contradiction!
  1924. it would be shorter to explicitly list the new stuff then wrt an
  1925. empty explicit list. */
  1926. *array = *adesc;
  1927. #ifdef COMPILE_IN_LP
  1928. adesc->list = NULL;
  1929. #endif
  1930. }else{
  1931. /* OK, array is either WRT or EXP.
  1932. But!!! If array is EXP then array->added is set to array->size, so
  1933. we can handle it exactly as if it were WRT!
  1934. */
  1935. /* Now comes the ugly part... we had an old WRT list and got a new
  1936. one wrt to the old (none of them is empty)... Create a correct one
  1937. now.
  1938. For extra vars/rows the basis status further complicates things.
  1939. If we had the basis stati stored as EXP, then we don't have to worry
  1940. about it, since we are going to receive an EXP. But if it was WRT
  1941. then we must delete the from the basis stati list the extras to be
  1942. deleted according to the new description! */
  1943. int i, j, k, *list;
  1944. int newsize = adesc->size;
  1945. int newadded = adesc->added;
  1946. int *newtoadd = adesc->list;
  1947. int newdeled = newsize - newadded;
  1948. int *newtodel = newtoadd + newadded;
  1949. int oldadded = array->added;
  1950. int *oldtoadd = array->list;
  1951. int olddeled = array->size - oldadded;
  1952. int *oldtodel = oldtoadd + oldadded;
  1953. /* cancel those both in oldtoadd and newdeled; also those both in
  1954. newtoadd and olddeled.
  1955. Then the unions of oldtoadd-newtodel and oldtodel-newtoadd will be
  1956. the correct list. */
  1957. /* First count the number of collisions and mark the colliding ones */
  1958. k = 0;
  1959. for (i = j = 0; i < oldadded && j < newdeled; ){
  1960. if (oldtoadd[i] < newtodel[j]) i++;
  1961. else if (oldtoadd[i] > newtodel[j]) j++;
  1962. else{
  1963. oldtoadd[i] = newtodel[j] = -1;
  1964. i++;
  1965. j++;
  1966. k++;
  1967. }
  1968. }
  1969. for (i = j = 0; i < newadded && j < olddeled; ){
  1970. if (newtoadd[i] < oldtodel[j]) i++;
  1971. else if (newtoadd[i] > oldtodel[j]) j++;
  1972. else{
  1973. newtoadd[i] = oldtodel[j] = -1;
  1974. i++;
  1975. j++;
  1976. k++;
  1977. }
  1978. }
  1979. array->size = array->size + newsize - 2 * k;
  1980. if (array->size == 0){
  1981. /* Nothing is left, great! */
  1982. array->added = 0;
  1983. FREE(adesc->list);
  1984. FREE(array->list);
  1985. }else{
  1986. array->list = list = (int *) malloc(array->size * ISIZE);
  1987. for (i = j = k = 0; i < oldadded && j < newadded; ){
  1988. if (oldtoadd[i] == -1) i++;
  1989. else if (newtoadd[j] == -1) j++;
  1990. else if (oldtoadd[i] < newtoadd[j]) list[k++] = oldtoadd[i++];
  1991. else /* can't be == */ list[k++] = newtoadd[j++];
  1992. }
  1993. for ( ; i < oldadded; i++)
  1994. if (oldtoadd[i] != -1) list[k++] = oldtoadd[i];
  1995. for ( ; j < newadded; j++)
  1996. if (newtoadd[j] != -1) list[k++] = newtoadd[j];
  1997. array->added = k;
  1998. for (i = j = 0; i < olddeled && j < newdeled; ){
  1999. if (oldtodel[i] == -1) i++;
  2000. else if (newtodel[j] == -1) j++;
  2001. else if (oldtodel[i] < newtodel[j]) list[k++] = oldtodel[i++];
  2002. else /* can't be == */ list[k++] = newtodel[j++];
  2003. }
  2004. for ( ; i < olddeled; i++)
  2005. if (oldtodel[i] != -1) list[k++] = oldtodel[i];
  2006. for ( ; j < newdeled; j++)
  2007. if (newtodel[j] != -1) list[k++] = newtodel[j];
  2008. FREE(adesc->list); /* adesc->list */
  2009. FREE(oldtoadd); /* the old array->list */
  2010. }
  2011. }
  2012. }
  2013. /*===========================================================================*/
  2014. /*===========================================================================*\
  2015. * This routine modifies a list of integers, by deleting those listed in
  2016. * todel and adding those listed in toadd. todel is a subset of iarray,
  2017. * toadd has no common element with iarray.
  2018. \*===========================================================================*/
  2019. void modify_list(array_desc *origad, array_desc *modad)
  2020. {
  2021. int j, k, l, nextdel;
  2022. int added = modad->added;
  2023. int *toadd = modad->list;
  2024. int deled = modad->size - modad->added;
  2025. int *todel = toadd + added;
  2026. int size = origad->size;
  2027. int *origlist = origad->list;
  2028. if (deled){
  2029. /* l is the location where we copy to; and k is where we copy from */
  2030. l = k = 0;
  2031. for (j = 0; j < deled; k++, j++){
  2032. nextdel = todel[j];
  2033. for (; origlist[k] != nextdel; origlist[l++] = origlist[k++]);
  2034. }
  2035. for (; k < size; origlist[l++] = origlist[k++]);
  2036. size = l;
  2037. }
  2038. if (added){
  2039. /* add toadd to origlist */
  2040. for (l = size+added-1, k = added-1, j = size-1; k >= 0 && j >= 0; ){
  2041. if (origlist[j] > toadd[k])
  2042. origlist[l--] = origlist[j--];
  2043. else
  2044. origlist[l--] = toadd[k--];
  2045. }
  2046. if (k >= 0)
  2047. memcpy(origlist, toadd, (k+1) * ISIZE);
  2048. size += added;
  2049. }
  2050. origad->size = size;
  2051. }
  2052. /*===========================================================================*/
  2053. void modify_list_and_stat(array_desc *origad, int *origstat,
  2054. array_desc *modad, double_array_desc *moddad)
  2055. {
  2056. int i, j, k, l, nextdel;
  2057. int added = modad->added;
  2058. int *toadd = modad->list;
  2059. int deled = modad->size - modad->added;
  2060. int *todel = toadd + added;
  2061. int size = origad->size;
  2062. int *origlist = origad->list;
  2063. /* First modify origad, and at the same time delete the appropriate entries
  2064. from origstat as well as insert phony ones where needed */
  2065. if (deled){
  2066. /* l is the location where we copy to; and k is where we copy from */
  2067. l = k = 0;
  2068. for (j = 0; j < deled; k++, j++){
  2069. nextdel = todel[j];
  2070. for (; origlist[k] != nextdel; ){
  2071. origstat[l] = origstat[k];
  2072. origlist[l++] = origlist[k++];
  2073. }
  2074. }
  2075. for (; k < size; ){
  2076. origstat[l] = origstat[k];
  2077. origlist[l++] = origlist[k++];
  2078. }
  2079. size = l;
  2080. }
  2081. if (added){
  2082. /* add toadd to origlist */
  2083. for (l = size+added-1, k = added-1, j = size-1; k >= 0 && j >= 0; )
  2084. if (origlist[j] > toadd[k]){
  2085. origstat[l] = origstat[j];
  2086. origlist[l--] = origlist[j--];
  2087. }else{
  2088. origstat[l] = INVALID_BASIS_STATUS;
  2089. origlist[l--] = toadd[k--];
  2090. }
  2091. if (k >= 0){
  2092. for ( ; k >= 0; ){
  2093. origstat[l] = INVALID_BASIS_STATUS;
  2094. origlist[l--] = toadd[k--];
  2095. }
  2096. }
  2097. size += added;
  2098. }
  2099. origad->size = size;
  2100. #ifdef DO_TM_BASIS_TESTS
  2101. if (origad->size == 0 && moddad->size > 0){
  2102. printf("TM: Problem with storing the basis!!\n\n");
  2103. exit(990);
  2104. }
  2105. #endif
  2106. /* Now adjust the basis stati */
  2107. if (origad->size > 0 && moddad->size > 0){
  2108. int *modlist = moddad->list;
  2109. int *modstat = moddad->stat;
  2110. for (i = moddad->size - 1, j = origad->size - 1; i >= 0 && j >= 0; j--){
  2111. if (origlist[j] == modlist[i])
  2112. origstat[j] = modstat[i--];
  2113. #ifdef DO_TM_BASIS_TESTS
  2114. else if (origlist[j] < modlist[i]){
  2115. printf("TM: Problem with storing the basis!!\n\n");
  2116. exit(990);
  2117. }
  2118. #endif
  2119. }
  2120. #ifdef DO_TM_BASIS_TESTS
  2121. if (i >= 0){
  2122. printf("TM: Problem with storing the basis!!\n\n");
  2123. exit(990);
  2124. }
  2125. #endif
  2126. }
  2127. #ifdef DO_TM_BASIS_TESTS
  2128. for (j = origad->size - 1; j >= 0; j--){
  2129. if (origstat[j] == INVALID_BASIS_STATUS){
  2130. printf("TM: Problem with storing the basis!!\n\n");
  2131. exit(990);
  2132. }
  2133. }
  2134. #endif
  2135. }
  2136. /*===========================================================================*/
  2137. /*===========================================================================*\
  2138. * Do some tasks before phase 2. Thes are:
  2139. * - price out variables in the root if requested
  2140. * - build up the samephase_cand binary tree
  2141. * - inform everyone about it
  2142. \*===========================================================================*/
  2143. int tasks_before_phase_two(tm_prob *tm)
  2144. {
  2145. #if !defined(COMPILE_IN_TM)||(defined(COMPILE_IN_TM)&&!defined(COMPILE_IN_LP))
  2146. int s_bufid;
  2147. #endif
  2148. #ifdef COMPILE_IN_LP
  2149. int num_threads = 1;
  2150. #else
  2151. int r_bufid, msgtag, bytes, sender, not_fixed_size;
  2152. #endif
  2153. int i;
  2154. bc_node *n;
  2155. int termcode = 0;
  2156. #ifdef COMPILE_IN_LP
  2157. #ifdef _OPENMP
  2158. num_threads = omp_get_num_threads();
  2159. #endif
  2160. for (i = 0; i < num_threads; i++){
  2161. free_node_desc(&tm->lpp[i]->desc);
  2162. tm->lpp[i]->phase = 1;
  2163. }
  2164. #else
  2165. /* Notify the LPs about the start of the second phase and get back the
  2166. timing data for the first phase */
  2167. s_bufid = init_send(DataInPlace);
  2168. msend_msg(tm->lp.procs, tm->lp.procnum, LP__SECOND_PHASE_STARTS);
  2169. #endif
  2170. if (tm->par.price_in_root && tm->has_ub){
  2171. /* put together a message and send it out to an LP process. At this
  2172. point tm->rootnode->{lp,cg,cp,sp} should still be set to wherever
  2173. it was first processed */
  2174. #ifdef DO_TESTS
  2175. if ((!tm->rootnode->lp) ||
  2176. (!tm->rootnode->cg && tm->par.use_cg) ||
  2177. (!tm->rootnode->cp && tm->cp.procnum > 0)){
  2178. printf("When trying to send root for repricing, the root doesn't\n");
  2179. printf(" have some process id correctly set!\n\n");
  2180. exit(-100);
  2181. }
  2182. #endif
  2183. send_active_node(tm, tm->rootnode, COLGEN_REPRICING, 0);
  2184. }
  2185. /* trim the tree */
  2186. tm->stat.leaves_before_trimming = tm->nextphase_candnum;
  2187. if (tm->par.trim_search_tree && tm->has_ub)
  2188. tm->stat.tree_size -= trim_subtree(tm, tm->rootnode);
  2189. /* while the LP is working, build up the samephase_cand binary tree */
  2190. REALLOC(tm->samephase_cand, bc_node *,
  2191. tm->samephase_cand_size, tm->nextphase_candnum + 1, BB_BUNCH);
  2192. for (i = 0; i < tm->nextphase_candnum; i++){
  2193. if ((n = tm->nextphase_cand[i])){
  2194. if (n->bc_index >= 0){
  2195. insert_new_node(tm, n);
  2196. }else{
  2197. free_tree_node(n);
  2198. }
  2199. }
  2200. }
  2201. tm->stat.leaves_after_trimming = tm->samephase_candnum;
  2202. if ((termcode = receive_lp_timing(tm)) < 0)
  2203. return(SOMETHING_DIED);
  2204. if (tm->par.price_in_root && tm->has_ub){
  2205. /* receive what the LP has to say, what is the new not_fixed list.
  2206. * also, incorporate that list into the not_fixed field of everything */
  2207. #ifdef COMPILE_IN_LP
  2208. switch(process_chain(tm->lpp[0])){
  2209. case FUNCTION_TERMINATED_NORMALLY:
  2210. break;
  2211. case ERROR__NO_BRANCHING_CANDIDATE:
  2212. return(TM_ERROR__NO_BRANCHING_CANDIDATE);
  2213. case ERROR__ILLEGAL_RETURN_CODE:
  2214. return(TM_ERROR__ILLEGAL_RETURN_CODE);
  2215. case ERROR__NUMERICAL_INSTABILITY:
  2216. return(TM_ERROR__NUMERICAL_INSTABILITY);
  2217. case ERROR__USER:
  2218. return(TM_ERROR__USER);
  2219. }
  2220. #else
  2221. char go_on;
  2222. int nsize, nf_status;
  2223. do{
  2224. r_bufid = receive_msg(tm->rootnode->lp, ANYTHING);
  2225. bufinfo(r_bufid, &bytes, &msgtag, &sender);
  2226. switch (msgtag){
  2227. case LP__NODE_DESCRIPTION:
  2228. n = (bc_node *) calloc(1, sizeof(bc_node));
  2229. receive_node_desc(tm, n);
  2230. tm->stat.root_lb = n->lower_bound;
  2231. if (n->node_status == NODE_STATUS__PRUNED){
  2232. /* Field day! Proved optimality! */
  2233. free_subtree(tm->rootnode);
  2234. tm->rootnode = n;
  2235. tm->samephase_candnum = tm->nextphase_candnum = 0;
  2236. return (FUNCTION_TERMINATED_NORMALLY);
  2237. }
  2238. /* Otherwise in 'n' we have the new description of the root node.
  2239. We don't care about the cuts, just the not fixed variables.
  2240. We got to pay attention to changes in uind and not_fixed.
  2241. We won't change the uind in root but put every change into
  2242. not_fixed.
  2243. The new not_fixed list will comprise of the vars added to uind
  2244. and whatever is in the new not_fixed. */
  2245. if (n->desc.uind.size > 0){
  2246. array_desc *uind = &n->desc.uind;
  2247. array_desc *ruind = &tm->rootnode->desc.uind;
  2248. int usize = uind->size;
  2249. int rusize = ruind->size;
  2250. int *ulist = uind->list;
  2251. int *rulist = ruind->list;
  2252. int j, k;
  2253. /* Kick out from uind those in root's uind */
  2254. for (i = 0, j = 0, k = 0; i < usize && j < rusize; ){
  2255. if (ulist[i] < rulist[j]){
  2256. /* a new element in uind */
  2257. ulist[k++] = ulist[i++];
  2258. }else if (ulist[i] < rulist[j]){
  2259. /* something got kicked out of ruind */
  2260. j++;
  2261. }else{ /* ulist[i] == rulist[j] */
  2262. /* It just stayed there peacefully */
  2263. i++; j++;
  2264. }
  2265. }
  2266. if (i < usize){
  2267. /* The rest are new */
  2268. for ( ; i < usize; i++, k++)
  2269. ulist[k] = ulist[i];
  2270. }
  2271. if ((usize = k) > 0){
  2272. if ((nsize = n->desc.not_fixed.size) == 0){
  2273. /* All we got is from uind */
  2274. n->desc.not_fixed.size = usize;
  2275. n->desc.not_fixed.list = ulist;
  2276. uind->list = NULL;
  2277. }else{
  2278. /* Now merge whatever is left in ulist with not_fixed.
  2279. Note that the two lists are disjoint. */
  2280. int *not_fixed = (int *) malloc((usize + nsize) * ISIZE);
  2281. int *nlist = n->desc.not_fixed.list;
  2282. for (not_fixed_size=i=j=k=0; i < usize && j < nsize;
  2283. not_fixed_size++){
  2284. if (ulist[i] < nlist[j]){
  2285. not_fixed[k++] = ulist[i++];
  2286. }else if (ulist[i] > nlist[j]){
  2287. not_fixed[k++] = nlist[j++];
  2288. }else{
  2289. not_fixed[k++] = nlist[j++];
  2290. i++;
  2291. }
  2292. }
  2293. if (i < usize)
  2294. memcpy(not_fixed+k, ulist+i, (usize-i)*ISIZE);
  2295. if (j < nsize)
  2296. memcpy(not_fixed+k, nlist+j, (nsize-j)*ISIZE);
  2297. FREE(nlist);
  2298. n->desc.not_fixed.size = not_fixed_size;
  2299. n->desc.not_fixed.list = not_fixed;
  2300. }
  2301. }
  2302. }
  2303. /* OK, now every new thingy is in n->desc.not_fixed */
  2304. nsize = n->desc.not_fixed.size;
  2305. if (nsize == 0){
  2306. /* Field day! Proved optimality!
  2307. Caveats:
  2308. This proves optimality, but the current tree may not contain
  2309. this proof, since the cuts used in pricing out might be
  2310. different from those originally in the root.
  2311. For now just accept this sad fact and report optimality.
  2312. Later, when the tree could be written out on disk, take care
  2313. of writing out BOTH root descriptions to prove optimality.
  2314. FIXME */
  2315. if (tm->par.keep_description_of_pruned){
  2316. /* We got to write it out here. */
  2317. }
  2318. free_tree_node(n);
  2319. tm->samephase_candnum = tm->nextphase_candnum = 0;
  2320. return(FUNCTION_TERMINATED_NORMALLY);
  2321. }else{
  2322. tm->rootnode->desc.not_fixed.list = n->desc.not_fixed.list;
  2323. n->desc.not_fixed.list = NULL;
  2324. if (nsize > tm->par.not_fixed_storage_size){
  2325. tm->rootnode->desc.not_fixed.size =
  2326. tm->par.not_fixed_storage_size;
  2327. nf_status = NF_CHECK_AFTER_LAST;
  2328. }else{
  2329. tm->rootnode->desc.not_fixed.size = nsize;
  2330. nf_status = NF_CHECK_UNTIL_LAST;
  2331. }
  2332. }
  2333. propagate_nf_status(tm->rootnode, nf_status);
  2334. tm->stat.nf_status = nf_status;
  2335. tm->stat.vars_not_priced = tm->rootnode->desc.not_fixed.size;
  2336. free_tree_node(n);
  2337. go_on = FALSE;
  2338. break;
  2339. case UPPER_BOUND:
  2340. process_ub_message(tm);
  2341. go_on = TRUE;
  2342. break;
  2343. case LP__CUT_NAMES_REQUESTED:
  2344. unpack_cut_set(tm, sender, 0, NULL);
  2345. go_on = TRUE;
  2346. break;
  2347. default: /* We shouldn't get anything else */
  2348. printf("Unexpected message at repricing! (%i)\n\n", msgtag);
  2349. return(ERROR__COMM_ERROR);
  2350. }
  2351. }while (go_on);
  2352. #endif
  2353. }
  2354. #ifdef COMPILE_IN_TM
  2355. if (tm->samephase_candnum > 0){
  2356. printf( "\n");
  2357. printf( "**********************************************\n");
  2358. printf( "* Branch and Cut First Phase Finished!!!! *\n");
  2359. printf( "* Now displaying stats and best solution... *\n");
  2360. printf( "**********************************************\n\n");
  2361. print_statistics(&(tm->comp_times), &(tm->stat), &(tm->lp_stat),
  2362. tm->ub, tm->lb, 0,
  2363. tm->start_time, wall_clock(NULL),
  2364. tm->obj_offset,
  2365. tm->obj_sense, tm->has_ub,NULL);
  2366. }
  2367. #else
  2368. /* Report to the master all kind of statistics */
  2369. s_bufid = init_send(DataInPlace);
  2370. send_char_array((char *)&tm->comp_times, sizeof(node_times));
  2371. send_char_array((char *)&tm->lp_stat, sizeof(lp_stat_desc));
  2372. send_dbl_array(&tm->lb, 1);
  2373. send_char_array((char *)&tm->stat, sizeof(tm_stat));
  2374. send_msg(tm->master, TM_FIRST_PHASE_FINISHED);
  2375. #endif
  2376. tm->nextphase_candnum = 0;
  2377. return(FUNCTION_TERMINATED_NORMALLY);
  2378. }
  2379. /*===========================================================================*/
  2380. /*===========================================================================*\
  2381. * For now we'll trim the tree only between phases when nothing is processed.
  2382. * Reason: It's kinda ugly to cut off a subtree when several of its nodes
  2383. * might be processed. Nevertheless, this should be done sooner or later.
  2384. *
  2385. * FIXME!
  2386. *
  2387. \*===========================================================================*/
  2388. int trim_subtree(tm_prob *tm, bc_node *n)
  2389. {
  2390. int i, deleted = 0, not_pruned = 0;
  2391. /* Theer isn't anything to do if this is a leaf. */
  2392. if (n->bobj.child_num == 0)
  2393. return(0);
  2394. /* There isn't anything to do if all children are pruned, and we are
  2395. better off to go down if only one is not pruned. */
  2396. for (i = n->bobj.child_num - 1; i >= 0; i--)
  2397. if (n->children[i]->node_status != NODE_STATUS__PRUNED)
  2398. if (++not_pruned > 1)
  2399. break;
  2400. if (not_pruned == 0)
  2401. return(0);
  2402. if (not_pruned == 1){
  2403. for (i = n->bobj.child_num - 1; i >= 0; i--)
  2404. if (n->children[i]->node_status != NODE_STATUS__PRUNED){
  2405. deleted = trim_subtree(tm, n->children[i]);
  2406. break;
  2407. }
  2408. return(deleted);
  2409. }
  2410. /* So there are at least two not pruned. */
  2411. for (i = n->bobj.child_num - 1; i >= 0; i--)
  2412. if (n->children[i]->lower_bound + tm->par.granularity < tm->ub)
  2413. break;
  2414. /* if all children have high objval */
  2415. if (i < 0){
  2416. /* put back this node into the nodes_per_... stuff */
  2417. if (tm->par.max_cp_num > 0 && n->cp)
  2418. #ifdef COMPILE_IN_CP
  2419. tm->nodes_per_cp[n->cp]++;
  2420. #else
  2421. tm->nodes_per_cp[find_process_index(&tm->cp, n->cp)]++;
  2422. #endif
  2423. /* also put the node on the nextphase list */
  2424. REALLOC(tm->nextphase_cand, bc_node *,
  2425. tm->nextphase_cand_size, tm->nextphase_candnum+1, BB_BUNCH);
  2426. tm->nextphase_cand[tm->nextphase_candnum++] = n;
  2427. /* get rid of the children */
  2428. for (i = n->bobj.child_num - 1; i >= 0; i--)
  2429. deleted += mark_subtree(tm, n->children[i]);
  2430. /* free the children description */
  2431. FREE(n->children);
  2432. n->bobj.child_num = 0;
  2433. #ifndef MAX_CHILDREN_NUM
  2434. FREE(n->bobj.sense);
  2435. FREE(n->bobj.rhs);
  2436. FREE(n->bobj.range);
  2437. FREE(n->bobj.branch);
  2438. #endif
  2439. FREE(n->bobj.solutions); //added by asm4
  2440. }else{
  2441. /* try to trim every child */
  2442. for (i = n->bobj.child_num - 1; i >= 0; i--)
  2443. deleted += trim_subtree(tm, n->children[i]);
  2444. }
  2445. return(deleted);
  2446. }
  2447. /*===========================================================================*/
  2448. int mark_subtree(tm_prob *tm, bc_node *n)
  2449. {
  2450. int i, deleted = 0;
  2451. /* mark the node trimmed */
  2452. if (n->bobj.child_num == 0){
  2453. /* if this was a leaf and it is not pruned,
  2454. delete it from the nodes_per_... stuff */
  2455. if (n->node_status != NODE_STATUS__PRUNED){
  2456. if (tm->par.max_cp_num > 0 && n->cp){
  2457. #ifdef COMPILE_IN_CP
  2458. i = n->cp;
  2459. #else
  2460. i = find_process_index(&tm->cp, n->cp);
  2461. #endif
  2462. tm->nodes_per_cp[i]--;
  2463. if (tm->nodes_per_cp[i] + tm->active_nodes_per_cp[i] == 0)
  2464. tm->cp.free_ind[tm->cp.free_num++] = i;
  2465. }
  2466. n->bc_index = -1;
  2467. }else{
  2468. /* if it was pruned already the free it now */
  2469. free_tree_node(n);
  2470. }
  2471. }else{
  2472. /* if non-leaf then process the children recursively and then free
  2473. the node */
  2474. for (i = n->bobj.child_num - 1; i >= 0; i--)
  2475. deleted += mark_subtree(tm, n->children[i]);
  2476. free_tree_node(n);
  2477. }
  2478. return(++deleted);
  2479. }
  2480. /*===========================================================================*/
  2481. void propagate_nf_status(bc_node *n, int nf_status)
  2482. {
  2483. int i;
  2484. for (i = n->bobj.child_num - 1; i >= 0; i--)
  2485. propagate_nf_status(n->children[i], nf_status);
  2486. n->desc.nf_status = nf_status;
  2487. }
  2488. /*===========================================================================*/
  2489. /*===========================================================================*\
  2490. * The functions below are for logging. They write out all necessary
  2491. * data to a file so that a warmstart can be made.
  2492. \*===========================================================================*/
  2493. int write_node(bc_node *node, char *file, FILE* f, char append)
  2494. {
  2495. int i;
  2496. char close = FALSE;
  2497. if (!f){
  2498. if (!(f = fopen(file, append ? "a" : "w"))){
  2499. printf("\nError opening node file\n\n");
  2500. return(0);
  2501. }
  2502. close = TRUE;
  2503. }
  2504. if (append)
  2505. fprintf(f, "\n");
  2506. fprintf(f, "NODE INDEX: %i\n", node->bc_index);
  2507. fprintf(f, "NODE LEVEL: %i\n", node->bc_level);
  2508. fprintf(f, "LOWER BOUND: %f\n", node->lower_bound);
  2509. fprintf(f, "NODE STATUS: %i\n", (int)node->node_status);
  2510. #ifdef TRACE_PATH
  2511. fprintf(f, "OPTIMAL PATH: %i\n", (int)node->optimal_path);
  2512. #endif
  2513. if (node->parent)
  2514. fprintf(f, "PARENT INDEX: %i\n", node->parent->bc_index);
  2515. else
  2516. fprintf(f, "PARENT INDEX: -1\n");
  2517. fprintf(f, "CHILDREN: %i %i %i\n", (int)node->bobj.type,
  2518. node->bobj.name, node->bobj.child_num);
  2519. for (i = 0; i < node->bobj.child_num; i++)
  2520. fprintf(f, "%i %c %f %f %i\n", node->children[i]->bc_index,
  2521. node->bobj.sense[i], node->bobj.rhs[i],
  2522. node->bobj.range[i], node->bobj.branch[i]);
  2523. fprintf(f, "NODE DESCRIPTION: %i\n", node->desc.nf_status);
  2524. fprintf(f, "USER INDICES: %i %i %i\n", (int)node->desc.uind.type,
  2525. node->desc.uind.size, node->desc.uind.added);
  2526. for (i = 0; i < node->desc.uind.size; i++)
  2527. fprintf(f, "%i\n", node->desc.uind.list[i]);
  2528. fprintf(f, "NOT FIXED: %i %i %i\n", (int)node->desc.not_fixed.type,
  2529. node->desc.not_fixed.size, node->desc.not_fixed.added);
  2530. for (i = 0; i < node->desc.not_fixed.size; i++)
  2531. fprintf(f, "%i\n", node->desc.not_fixed.list[i]);
  2532. fprintf(f, "CUT INDICES: %i %i %i\n", (int)node->desc.cutind.type,
  2533. node->desc.cutind.size, node->desc.cutind.added);
  2534. for (i = 0; i < node->desc.cutind.size; i++)
  2535. fprintf(f, "%i\n", node->desc.cutind.list[i]);
  2536. fprintf(f, "BASIS: %i\n", (int)node->desc.basis.basis_exists);
  2537. fprintf(f, "BASE VARIABLES: %i %i\n", (int)node->desc.basis.basevars.type,
  2538. node->desc.basis.basevars.size);
  2539. if (node->desc.basis.basevars.type == WRT_PARENT)
  2540. for (i = 0; i < node->desc.basis.basevars.size; i++)
  2541. fprintf(f, "%i %i\n", node->desc.basis.basevars.list[i],
  2542. node->desc.basis.basevars.stat[i]);
  2543. else
  2544. for (i = 0; i < node->desc.basis.basevars.size; i++)
  2545. fprintf(f, "%i\n", node->desc.basis.basevars.stat[i]);
  2546. fprintf(f, "EXTRA VARIABLES: %i %i\n", (int)node->desc.basis.extravars.type,
  2547. node->desc.basis.extravars.size);
  2548. if (node->desc.basis.extravars.type == WRT_PARENT)
  2549. for (i = 0; i < node->desc.basis.extravars.size; i++)
  2550. fprintf(f, "%i %i\n", node->desc.basis.extravars.list[i],
  2551. node->desc.basis.extravars.stat[i]);
  2552. else
  2553. for (i = 0; i < node->desc.basis.extravars.size; i++)
  2554. fprintf(f, "%i\n", node->desc.basis.extravars.stat[i]);
  2555. fprintf(f, "BASE ROWS: %i %i\n", (int)node->desc.basis.baserows.type,
  2556. node->desc.basis.baserows.size);
  2557. if (node->desc.basis.baserows.type == WRT_PARENT)
  2558. for (i = 0; i < node->desc.basis.baserows.size; i++)
  2559. fprintf(f, "%i %i\n", node->desc.basis.baserows.list[i],
  2560. node->desc.basis.baserows.stat[i]);
  2561. else
  2562. for (i = 0; i < node->desc.basis.baserows.size; i++)
  2563. fprintf(f, "%i\n", node->desc.basis.baserows.stat[i]);
  2564. fprintf(f, "EXTRA ROWS: %i %i\n", (int)node->desc.basis.extrarows.type,
  2565. node->desc.basis.extrarows.size);
  2566. if (node->desc.basis.extrarows.type == WRT_PARENT)
  2567. for (i = 0; i < node->desc.basis.extrarows.size; i++)
  2568. fprintf(f, "%i %i\n", node->desc.basis.extrarows.list[i],
  2569. node->desc.basis.extrarows.stat[i]);
  2570. else
  2571. for (i = 0; i < node->desc.basis.extrarows.size; i++)
  2572. fprintf(f, "%i\n", node->desc.basis.extrarows.stat[i]);
  2573. if (close)
  2574. fclose(f);
  2575. return(1);
  2576. }
  2577. /*===========================================================================*/
  2578. int read_node(tm_prob *tm, bc_node *node, FILE *f, int **children)
  2579. {
  2580. int i, parent = 0, tmp = 0;
  2581. char str1[10], str2[10];
  2582. if (f){
  2583. fscanf(f, "%s %s %i", str1, str2, &node->bc_index);
  2584. fscanf(f, "%s %s %i", str1, str2, &node->bc_level);
  2585. fscanf(f, "%s %s %lf", str1, str2, &node->lower_bound);
  2586. fscanf(f, "%s %s %i", str1, str2, &tmp);
  2587. node->node_status = (char)tmp;
  2588. #ifdef TRACE_PATH
  2589. fscanf(f, "%s %s %i\n", str1, str2, &tmp);
  2590. node->optimal_path = (char)tmp;
  2591. #endif
  2592. fscanf(f, "%s %s %i", str1, str2, &parent);
  2593. fscanf(f, "%s %i %i %i", str1, &tmp,
  2594. &node->bobj.name, &node->bobj.child_num);
  2595. node->bobj.type = (char)tmp;
  2596. if (node->bobj.child_num){
  2597. #ifndef MAX_CHILDREN_NUM
  2598. node->bobj.sense = malloc(node->bobj.child_num*sizeof(char));
  2599. node->bobj.rhs = (double *) malloc(node->bobj.child_num*DSIZE);
  2600. node->bobj.range = (double *) malloc(node->bobj.child_num*DSIZE);
  2601. node->bobj.branch = (int *) malloc(node->bobj.child_num*ISIZE);
  2602. #endif
  2603. *children = (int *) malloc(node->bobj.child_num*ISIZE);
  2604. for (i = 0; i < node->bobj.child_num; i++)
  2605. fscanf(f, "%i %c %lf %lf %i", *children+i, node->bobj.sense+i,
  2606. node->bobj.rhs+i, node->bobj.range+i, node->bobj.branch+i);
  2607. }
  2608. fscanf(f, "%s %s %i", str1, str2, &node->desc.nf_status);
  2609. fscanf(f, "%s %s %i %i %i", str1, str2, &tmp, &node->desc.uind.size,
  2610. &node->desc.uind.added);
  2611. node->desc.uind.type = (char)tmp;
  2612. if (node->desc.uind.size){
  2613. node->desc.uind.list = (int *) malloc(node->desc.uind.size*ISIZE);
  2614. for (i = 0; i < node->desc.uind.size; i++)
  2615. fscanf(f, "%i", node->desc.uind.list+i);
  2616. }
  2617. fscanf(f, "%s %s %i %i %i", str1, str2, &tmp,
  2618. &node->desc.not_fixed.size, &node->desc.not_fixed.added);
  2619. node->desc.not_fixed.type = (char)tmp;
  2620. if (node->desc.not_fixed.size){
  2621. node->desc.not_fixed.list =
  2622. (int *) malloc(node->desc.not_fixed.size*ISIZE);
  2623. for (i = 0; i < node->desc.not_fixed.size; i++)
  2624. fscanf(f, "%i", node->desc.not_fixed.list+i);
  2625. }
  2626. fscanf(f, "%s %s %i %i %i", str1, str2, &tmp,
  2627. &node->desc.cutind.size, &node->desc.cutind.added);
  2628. node->desc.cutind.type = (char)tmp;
  2629. if (node->desc.cutind.size){
  2630. node->desc.cutind.list = (int *) malloc(node->desc.cutind.size*ISIZE);
  2631. for (i = 0; i < node->desc.cutind.size; i++)
  2632. fscanf(f, "%i", node->desc.cutind.list+i);
  2633. }
  2634. fscanf(f, "%s %i", str1, &tmp);
  2635. node->desc.basis.basis_exists = (char)tmp;
  2636. fscanf(f, "%s %s %i %i", str1, str2, &tmp,
  2637. &node->desc.basis.basevars.size);
  2638. node->desc.basis.basevars.type = (char)tmp;
  2639. if (node->desc.basis.basevars.size){
  2640. node->desc.basis.basevars.stat =
  2641. (int *) malloc(node->desc.basis.basevars.size*ISIZE);
  2642. if (node->desc.basis.basevars.type == WRT_PARENT){
  2643. node->desc.basis.basevars.list =
  2644. (int *) malloc(node->desc.basis.basevars.size*ISIZE);
  2645. for (i = 0; i < node->desc.basis.basevars.size; i++)
  2646. fscanf(f, "%i %i", node->desc.basis.basevars.list+i,
  2647. node->desc.basis.basevars.stat+i);
  2648. }else{
  2649. for (i = 0; i < node->desc.basis.basevars.size; i++)
  2650. fscanf(f, "%i", node->desc.basis.basevars.stat+i);
  2651. }
  2652. }
  2653. fscanf(f, "%s %s %i %i", str1, str2, &tmp,
  2654. &node->desc.basis.extravars.size);
  2655. node->desc.basis.extravars.type = (char)tmp;
  2656. if (node->desc.basis.extravars.size){
  2657. node->desc.basis.extravars.stat =
  2658. (int *) malloc(node->desc.basis.extravars.size*ISIZE);
  2659. if (node->desc.basis.extravars.type == WRT_PARENT){
  2660. node->desc.basis.extravars.list =
  2661. (int *) malloc(node->desc.basis.extravars.size*ISIZE);
  2662. for (i = 0; i < node->desc.basis.extravars.size; i++)
  2663. fscanf(f, "%i %i", node->desc.basis.extravars.list+i,
  2664. node->desc.basis.extravars.stat+i);
  2665. }else{
  2666. for (i = 0; i < node->desc.basis.extravars.size; i++)
  2667. fscanf(f, "%i", node->desc.basis.extravars.stat+i);
  2668. }
  2669. }
  2670. fscanf(f, "%s %s %i %i", str1, str2, &tmp,
  2671. &node->desc.basis.baserows.size);
  2672. node->desc.basis.baserows.type = (char)tmp;
  2673. if (node->desc.basis.baserows.size){
  2674. node->desc.basis.baserows.stat =
  2675. (int *) malloc(node->desc.basis.baserows.size*ISIZE);
  2676. if (node->desc.basis.baserows.type == WRT_PARENT){
  2677. node->desc.basis.baserows.list =
  2678. (int *) malloc(node->desc.basis.baserows.size*ISIZE);
  2679. for (i = 0; i < node->desc.basis.baserows.size; i++)
  2680. fscanf(f, "%i %i", node->desc.basis.baserows.list+i,
  2681. node->desc.basis.baserows.stat+i);
  2682. }else{
  2683. for (i = 0; i < node->desc.basis.baserows.size; i++)
  2684. fscanf(f, "%i", node->desc.basis.baserows.stat+i);
  2685. }
  2686. }
  2687. fscanf(f, "%s %s %i %i", str1, str2, &tmp,
  2688. &node->desc.basis.extrarows.size);
  2689. node->desc.basis.extrarows.type = (char)tmp;
  2690. if (node->desc.basis.extrarows.size){
  2691. node->desc.basis.extrarows.stat =
  2692. (int *) malloc(node->desc.basis.extrarows.size*ISIZE);
  2693. if (node->desc.basis.extrarows.type == WRT_PARENT){
  2694. node->desc.basis.extrarows.list =
  2695. (int *) malloc(node->desc.basis.extrarows.size*ISIZE);
  2696. for (i = 0; i < node->desc.basis.extrarows.size; i++)
  2697. fscanf(f, "%i %i", node->desc.basis.extrarows.list+i,
  2698. node->desc.basis.extrarows.stat+i);
  2699. }else{
  2700. for (i = 0; i < node->desc.basis.extrarows.size; i++)
  2701. fscanf(f, "%i", node->desc.basis.extrarows.stat+i);
  2702. }
  2703. }
  2704. }
  2705. switch (node->node_status){
  2706. case NODE_STATUS__HELD:
  2707. REALLOC(tm->nextphase_cand, bc_node *,
  2708. tm->nextphase_cand_size, tm->nextphase_candnum+1, BB_BUNCH);
  2709. tm->nextphase_cand[tm->nextphase_candnum++] = node;
  2710. /* update the nodes_per_... stuff */
  2711. /* the active_nodes_per_... will be updated when the LP__IS_FREE
  2712. message comes */
  2713. if (node->cp)
  2714. #ifdef COMPILE_IN_CP
  2715. tm->nodes_per_cp[node->cp]++;
  2716. #else
  2717. tm->nodes_per_cp[find_process_index(&tm->cp, node->cp)]++;
  2718. #endif
  2719. break;
  2720. case NODE_STATUS__ROOT:
  2721. tm->rootnode = node;
  2722. break;
  2723. case NODE_STATUS__WARM_STARTED:
  2724. case NODE_STATUS__CANDIDATE:
  2725. #pragma omp critical (tree_update)
  2726. insert_new_node(tm, node);
  2727. break;
  2728. }
  2729. return(parent);
  2730. }
  2731. /*===========================================================================*/
  2732. int write_subtree(bc_node *root, char *file, FILE *f, char append, int logging)
  2733. {
  2734. int i;
  2735. char close = FALSE;
  2736. if (!f){
  2737. if (!(f = fopen(file, append ? "a" : "w"))){
  2738. printf("\nError opening subtree file\n\n");
  2739. return(0);
  2740. }
  2741. close = TRUE;
  2742. }
  2743. if (logging == VBC_TOOL){
  2744. if (root->parent)
  2745. fprintf(f, "%i %i\n", root->parent->bc_index + 1, root->bc_index + 1);
  2746. }else{
  2747. write_node(root, file, f, append);
  2748. }
  2749. for (i = 0; i < root->bobj.child_num; i++)
  2750. write_subtree(root->children[i], file, f, TRUE, logging);
  2751. if (close)
  2752. fclose(f);
  2753. return(1);
  2754. }
  2755. /*===========================================================================*/
  2756. int read_subtree(tm_prob *tm, bc_node *root, FILE *f)
  2757. {
  2758. int parent, i;
  2759. int *children;
  2760. parent = read_node(tm, root, f, &children);
  2761. if (f && root->bobj.child_num){
  2762. root->children = (bc_node **)
  2763. malloc(root->bobj.child_num*sizeof(bc_node *));
  2764. for (i = 0; i < root->bobj.child_num; i++){
  2765. root->children[i] = (bc_node *) calloc(1, sizeof(bc_node));
  2766. root->children[i]->parent = root;
  2767. }
  2768. }
  2769. for (i = 0; i < root->bobj.child_num; i++){
  2770. read_subtree(tm, root->children[i], f);
  2771. }
  2772. return(parent);
  2773. }
  2774. /*===========================================================================*/
  2775. int write_tm_cut_list(tm_prob *tm, char *file, char append)
  2776. {
  2777. FILE *f;
  2778. int i, j;
  2779. if (!(f = fopen(file, append ? "a" : "w"))){
  2780. printf("\nError opening cut file\n\n");
  2781. return(0);
  2782. }
  2783. fprintf(f, "CUTNUM: %i %i\n", tm->cut_num, tm->allocated_cut_num);
  2784. for (i = 0; i < tm->cut_num; i++){
  2785. fprintf(f, "%i %i %i %c %i %f %f\n", tm->cuts[i]->name,
  2786. tm->cuts[i]->size, (int)tm->cuts[i]->type, tm->cuts[i]->sense,
  2787. (int)tm->cuts[i]->branch, tm->cuts[i]->rhs, tm->cuts[i]->range);
  2788. for (j = 0; j < tm->cuts[i]->size; j++)
  2789. fprintf(f, "%i ", (int)tm->cuts[i]->coef[j]);
  2790. fprintf(f, "\n");
  2791. }
  2792. fclose(f);
  2793. return(1);
  2794. }
  2795. /*===========================================================================*/
  2796. int read_tm_cut_list(tm_prob *tm, char *file)
  2797. {
  2798. FILE *f;
  2799. int i, j, tmp1 = 0, tmp2 = 0;
  2800. char str[20];
  2801. if (!(f = fopen(file, "r"))){
  2802. printf("\nError opening cut file\n\n");
  2803. return(0);
  2804. }
  2805. fscanf(f, "%s %i %i", str, &tm->cut_num, &tm->allocated_cut_num);
  2806. tm->cuts = (cut_data **) malloc(tm->allocated_cut_num*sizeof(cut_data *));
  2807. for (i = 0; i < tm->cut_num; i++){
  2808. tm->cuts[i] = (cut_data *) malloc(sizeof(cut_data));
  2809. fscanf(f, "%i %i %i %c %i %lf %lf", &tm->cuts[i]->name,
  2810. &tm->cuts[i]->size, &tmp1, &tm->cuts[i]->sense,
  2811. &tmp2, &tm->cuts[i]->rhs, &tm->cuts[i]->range);
  2812. tm->cuts[i]->type = (char)tmp1;
  2813. tm->cuts[i]->branch = (char)tmp2;
  2814. tm->cuts[i]->coef = (char *) malloc(tm->cuts[i]->size*sizeof(char));
  2815. for (j = 0; j < tm->cuts[i]->size; j++){
  2816. fscanf(f, "%i ", &tmp1);
  2817. tm->cuts[i]->coef[j] = (char)tmp1;
  2818. }
  2819. }
  2820. fclose(f);
  2821. return(1);
  2822. }
  2823. /*===========================================================================*/
  2824. int write_tm_info(tm_prob *tm, char *file, FILE* f, char append)
  2825. {
  2826. char close = FALSE;
  2827. if (!f){
  2828. if (!(f = fopen(file, append ? "a" : "w"))){
  2829. printf("\nError opening TM info file\n\n");
  2830. return(0);
  2831. }
  2832. close = TRUE;
  2833. }
  2834. if (tm->par.logging == VBC_TOOL){
  2835. fprintf(f, "#TYPE: COMPLETE TREE\n");
  2836. fprintf(f, "#TIME: NOT\n");
  2837. fprintf(f, "#BOUNDS: NONE\n");
  2838. fprintf(f, "#INFORMATION: EXCEPTION\n");
  2839. fprintf(f, "#NODE_NUMBER: NONE\n");
  2840. if (close)
  2841. fclose(f);
  2842. return(1);
  2843. }
  2844. fprintf(f, "UPPER BOUND: ");
  2845. if (tm->has_ub)
  2846. fprintf(f, " %f\n", tm->ub);
  2847. else
  2848. fprintf(f, "\n");
  2849. fprintf(f, "LOWER BOUND: %f\n", tm->lb);
  2850. fprintf(f, "PHASE: %i\n", tm->phase);
  2851. fprintf(f, "ROOT LB: %f\n", tm->stat.root_lb);
  2852. fprintf(f, "MAX DEPTH: %i\n", tm->stat.max_depth);
  2853. fprintf(f, "CHAINS: %i\n", tm->stat.chains);
  2854. fprintf(f, "DIVING HALTS: %i\n", tm->stat.diving_halts);
  2855. fprintf(f, "TREE SIZE: %i\n", tm->stat.tree_size);
  2856. fprintf(f, "NODES CREATED: %i\n", tm->stat.created);
  2857. fprintf(f, "NODES ANALYZED: %i\n", tm->stat.analyzed);
  2858. fprintf(f, "LEAVES BEFORE: %i\n", tm->stat.leaves_before_trimming);
  2859. fprintf(f, "LEAVES AFTER: %i\n", tm->stat.leaves_after_trimming);
  2860. fprintf(f, "NF STATUS: %i\n", (int)tm->stat.nf_status);
  2861. fprintf(f, "TIMING:\n");
  2862. fprintf(f, " COMM: %f\n", tm->comp_times.communication);
  2863. fprintf(f, " LP: %f\n", tm->comp_times.lp);
  2864. fprintf(f, " SEPARATION: %f\n", tm->comp_times.separation);
  2865. fprintf(f, " FIXING: %f\n", tm->comp_times.fixing);
  2866. fprintf(f, " PRICING: %f\n", tm->comp_times.pricing);
  2867. fprintf(f, " BRANCHING: %f\n", tm->comp_times.strong_branching);
  2868. fprintf(f, " CUT POOL: %f\n", tm->comp_times.cut_pool);
  2869. fprintf(f, " REAL TIME: %f\n", wall_clock(NULL) - tm->start_time);
  2870. if (close)
  2871. fclose(f);
  2872. return(1);
  2873. }
  2874. /*===========================================================================*/
  2875. int read_tm_info(tm_prob *tm, FILE *f)
  2876. {
  2877. char str1[20], str2[20];
  2878. int tmp = 0;
  2879. double previous_elapsed_time = 0;
  2880. if (!f)
  2881. return(0);
  2882. fscanf(f, "%s %s", str1, str2);
  2883. if (fscanf(f, "%lf", &tm->ub) != 0)
  2884. tm->has_ub = TRUE;
  2885. fscanf(f, "%s %s %lf", str1, str2, &tm->lb);
  2886. fscanf(f, "%s %i", str1, &tm->phase);
  2887. fscanf(f, "%s %s %lf", str1, str2, &tm->stat.root_lb);
  2888. fscanf(f, "%s %s %i", str1, str2, &tm->stat.max_depth);
  2889. fscanf(f, "%s %i", str1, &tm->stat.chains);
  2890. fscanf(f, "%s %s %i", str1, str2, &tm->stat.diving_halts);
  2891. fscanf(f, "%s %s %i", str1, str2, &tm->stat.tree_size);
  2892. fscanf(f, "%s %s %i", str1, str2, &tm->stat.created);
  2893. fscanf(f, "%s %s %i", str1, str2, &tm->stat.analyzed);
  2894. fscanf(f, "%s %s %i", str1, str2, &tm->stat.leaves_before_trimming);
  2895. fscanf(f, "%s %s %i", str1, str2, &tm->stat.leaves_after_trimming);
  2896. fscanf(f, "%s %s %i", str1, str2, &tmp);
  2897. tm->stat.nf_status = (char)tmp;
  2898. fscanf(f, "%s", str1);
  2899. fscanf(f, "%s %lf", str1, &tm->comp_times.communication);
  2900. fscanf(f, "%s %lf", str1, &tm->comp_times.lp);
  2901. fscanf(f, "%s %lf", str1, &tm->comp_times.separation);
  2902. fscanf(f, "%s %lf", str1, &tm->comp_times.fixing);
  2903. fscanf(f, "%s %lf", str1, &tm->comp_times.pricing);
  2904. fscanf(f, "%s %lf", str1, &tm->comp_times.strong_branching);
  2905. fscanf(f, "%s %s %lf", str1, str2, &tm->comp_times.cut_pool);
  2906. fscanf(f, "%s %s %lf\n", str1, str2, &previous_elapsed_time);
  2907. tm->start_time -= previous_elapsed_time;
  2908. return(1);
  2909. }
  2910. /*===========================================================================*/
  2911. int write_base(base_desc *base, char *file, FILE *f, char append)
  2912. {
  2913. int i;
  2914. char close = FALSE;
  2915. if (!f){
  2916. if (!(f = fopen(file, append ? "a" : "w"))){
  2917. printf("\nError opening base file\n\n");
  2918. return(0);
  2919. }
  2920. close = TRUE;
  2921. }
  2922. fprintf(f, "BASE DESCRIPTION: %i %i\n", base->varnum, base->cutnum);
  2923. for (i = 0; i < base->varnum; i++)
  2924. fprintf(f, "%i\n", base->userind[i]);
  2925. if (close)
  2926. fclose(f);
  2927. return(1);
  2928. }
  2929. /*===========================================================================*/
  2930. int read_base(base_desc *base, FILE *f)
  2931. {
  2932. char str1[20], str2[20];
  2933. int i;
  2934. fscanf(f, "%s %s %i %i", str1, str2, &base->varnum, &base->cutnum);
  2935. base->userind = (int *) malloc(base->varnum*ISIZE);
  2936. for (i = 0; i < base->varnum; i++)
  2937. fscanf(f, "%i", base->userind+i);
  2938. return(1);
  2939. }
  2940. /*===========================================================================*/
  2941. /*===========================================================================*\
  2942. * Cleanup. Free the datastructure.
  2943. \*===========================================================================*/
  2944. void free_tm(tm_prob *tm)
  2945. {
  2946. int i;
  2947. cut_data **cuts = tm->cuts;
  2948. #ifdef _OPENMP
  2949. int num_threads = tm->par.max_active_nodes;
  2950. #else
  2951. int num_threads = 1;
  2952. #endif
  2953. #if defined(COMPILE_IN_TM) && defined(COMPILE_IN_LP)
  2954. for (i = 0; i < num_threads; i++)
  2955. free_lp(tm->lpp[i]);
  2956. FREE(tm->lpp);
  2957. #ifdef COMPILE_IN_CG
  2958. FREE(tm->cgp);
  2959. #endif
  2960. #endif
  2961. if (tm->par.lp_machs){
  2962. FREE(tm->par.lp_machs[0]);
  2963. FREE(tm->par.lp_machs);
  2964. }
  2965. if (tm->par.cg_machs){
  2966. FREE(tm->par.cg_machs[0]);
  2967. FREE(tm->par.cg_machs);
  2968. }
  2969. if (tm->par.cp_machs){
  2970. FREE(tm->par.cp_machs[0]);
  2971. FREE(tm->par.cp_machs);
  2972. }
  2973. FREE(tm->lp.procs);
  2974. FREE(tm->lp.free_ind);
  2975. FREE(tm->cg.procs);
  2976. FREE(tm->cg.free_ind);
  2977. FREE(tm->cp.procs);
  2978. FREE(tm->cp.free_ind);
  2979. FREE(tm->nodes_per_cp);
  2980. FREE(tm->active_nodes_per_cp);
  2981. FREE(tm->active_nodes);
  2982. FREE(tm->samephase_cand);
  2983. FREE(tm->nextphase_cand);
  2984. #ifndef COMPILE_IN_TM
  2985. /* Go over the tree and free the nodes */
  2986. free_subtree(tm->rootnode);
  2987. #endif
  2988. /* Go over the cuts stored and free them all */
  2989. #pragma omp critical (cut_pool)
  2990. if (cuts){
  2991. for (i = tm->cut_num - 1; i >= 0; i--)
  2992. if (cuts[i]){
  2993. FREE(cuts[i]->coef);
  2994. FREE(cuts[i]);
  2995. }
  2996. FREE(tm->cuts);
  2997. }
  2998. #pragma omp critical (tmp_memory)
  2999. {
  3000. FREE(tm->tmp.i);
  3001. FREE(tm->tmp.c);
  3002. FREE(tm->tmp.d);
  3003. }
  3004. /*get rid of the added pointers for sens.analysis*/
  3005. for (i = 0; i < num_threads; i++){
  3006. if(tm->rpath[i])
  3007. if(tm->rpath[i][0])
  3008. tm->rpath[i][0] = NULL;
  3009. FREE(tm->bpath[i]);
  3010. FREE(tm->rpath[i]);
  3011. }
  3012. FREE(tm->rpath);
  3013. FREE(tm->rpath_size);
  3014. FREE(tm->bpath);
  3015. FREE(tm->bpath_size);
  3016. if (tm->reduced_costs) {
  3017. for (i=0; i<tm->reduced_costs->num_rcs; i++) {
  3018. FREE(tm->reduced_costs->indices[i]);
  3019. FREE(tm->reduced_costs->values[i]);
  3020. FREE(tm->reduced_costs->lb[i]);
  3021. FREE(tm->reduced_costs->ub[i]);
  3022. }
  3023. FREE(tm->reduced_costs->indices);
  3024. FREE(tm->reduced_costs->values);
  3025. FREE(tm->reduced_costs->lb);
  3026. FREE(tm->reduced_costs->ub);
  3027. FREE(tm->reduced_costs->cnt);
  3028. FREE(tm->reduced_costs->obj);
  3029. FREE(tm->reduced_costs);
  3030. }
  3031. if (tm->pcost_down) {
  3032. FREE(tm->pcost_down);
  3033. FREE(tm->pcost_up);
  3034. FREE(tm->br_rel_down);
  3035. FREE(tm->br_rel_up);
  3036. FREE(tm->br_rel_cand_list);
  3037. FREE(tm->br_rel_down_min_level);
  3038. FREE(tm->br_rel_up_min_level);
  3039. }
  3040. FREE(tm);
  3041. }
  3042. /*===========================================================================*/
  3043. void free_subtree(bc_node *n)
  3044. {
  3045. int i;
  3046. if (n == NULL) return;
  3047. for (i = n->bobj.child_num - 1; i >= 0; i--)
  3048. free_subtree(n->children[i]);
  3049. free_tree_node(n);
  3050. }
  3051. /*===========================================================================*/
  3052. void free_tree_node(bc_node *n)
  3053. {
  3054. FREE(n->sol);
  3055. FREE(n->sol_ind);
  3056. #ifdef SENSITIVITY_ANALYSIS
  3057. FREE(n->duals);
  3058. #endif
  3059. FREE(n->children);
  3060. #ifndef MAX_CHILDREN_NUM
  3061. FREE(n->bobj.sense);
  3062. FREE(n->bobj.rhs);
  3063. FREE(n->bobj.range);
  3064. FREE(n->bobj.branch);
  3065. #endif
  3066. FREE(n->bobj.solutions); //added by asm4
  3067. FREE(n->desc.uind.list);
  3068. free_basis(&n->desc.basis);
  3069. FREE(n->desc.not_fixed.list);
  3070. FREE(n->desc.cutind.list);
  3071. FREE(n->desc.desc);
  3072. if (n->desc.bnd_change) {
  3073. FREE(n->desc.bnd_change->index);
  3074. FREE(n->desc.bnd_change->lbub);
  3075. FREE(n->desc.bnd_change->value);
  3076. FREE(n->desc.bnd_change);
  3077. }
  3078. FREE(n);
  3079. }
  3080. /*===========================================================================*/
  3081. void free_basis(basis_desc *basis)
  3082. {
  3083. FREE(basis->basevars.list);
  3084. FREE(basis->basevars.stat);
  3085. FREE(basis->extravars.list);
  3086. FREE(basis->extravars.stat);
  3087. FREE(basis->baserows.list);
  3088. FREE(basis->baserows.stat);
  3089. FREE(basis->extrarows.list);
  3090. FREE(basis->extrarows.stat);
  3091. }
  3092. /*===========================================================================*/
  3093. /*===========================================================================*\
  3094. * This function shuts down the treemanager
  3095. \*===========================================================================*/
  3096. int tm_close(tm_prob *tm, int termcode)
  3097. {
  3098. #ifndef COMPILE_IN_TM
  3099. int s_bufid;
  3100. #endif
  3101. #ifdef COMPILE_IN_LP
  3102. lp_prob **lp = tm->lpp;
  3103. #endif
  3104. #ifndef COMPILE_IN_CP
  3105. int r_bufid = 0, new_cuts;
  3106. struct timeval timeout = {5, 0};
  3107. double new_time;
  3108. #endif
  3109. int i;
  3110. #if defined(DO_TESTS) && 0
  3111. if (tm->cp.free_num != tm->cp.procnum)
  3112. printf(" Something is fishy! tm->cp.freenum != tm->cp.procnum\n");
  3113. #endif
  3114. if (tm->par.vbc_emulation == VBC_EMULATION_LIVE){
  3115. printf("$#END_OF_OUTPUT");
  3116. }
  3117. /*------------------------------------------------------------------------*\
  3118. * Kill the processes. Some of them will send back statistics.
  3119. \*------------------------------------------------------------------------*/
  3120. #ifndef COMPILE_IN_LP
  3121. stop_processes(&tm->lp);
  3122. #endif
  3123. #ifndef COMPILE_IN_CG
  3124. stop_processes(&tm->cg);
  3125. #endif
  3126. #ifndef COMPILE_IN_CP
  3127. stop_processes(&tm->cp);
  3128. #endif
  3129. /*------------------------------------------------------------------------*\
  3130. * Receive statistics from the cutpools
  3131. \*------------------------------------------------------------------------*/
  3132. #ifdef COMPILE_IN_CP
  3133. if (tm->cpp){
  3134. for (i = 0; i < tm->par.max_cp_num; i++){
  3135. tm->comp_times.cut_pool += tm->cpp[i]->cut_pool_time;
  3136. tm->stat.cuts_in_pool += tm->cpp[i]->cut_num;
  3137. tm->cpp[i]->msgtag = YOU_CAN_DIE;
  3138. cp_close(tm->cpp[i]);
  3139. }
  3140. FREE(tm->cpp);
  3141. }
  3142. #else
  3143. for (i = 0; i < tm->par.max_cp_num;){
  3144. r_bufid = treceive_msg(tm->cp.procs[i], POOL_TIME, &timeout);
  3145. if (r_bufid > 0){
  3146. receive_dbl_array(&new_time, 1);
  3147. receive_int_array(&new_cuts, 1);
  3148. tm->comp_times.cut_pool += new_time;
  3149. tm->stat.cuts_in_pool += new_cuts;
  3150. i++;
  3151. }else{
  3152. if (pstat(tm->cp.procs[i]) != PROCESS_OK)
  3153. i++;
  3154. }
  3155. }
  3156. freebuf(r_bufid);
  3157. #endif
  3158. /* Receive timing from the LPs */
  3159. if (receive_lp_timing(tm) < 0){
  3160. printf("\nWarning: problem receiving LP timing. LP process is dead\n\n");
  3161. }
  3162. #ifdef COMPILE_IN_LP
  3163. for (i = 0; i < tm->par.max_active_nodes; i ++){
  3164. lp_close(lp[i]);
  3165. }
  3166. #endif
  3167. tm->stat.root_lb = tm->rootnode->lower_bound;
  3168. find_tree_lb(tm);
  3169. return(termcode);
  3170. #ifndef COMPILE_IN_TM
  3171. /*------------------------------------------------------------------------*\
  3172. * Send back the statistics to the master
  3173. \*------------------------------------------------------------------------*/
  3174. s_bufid = init_send(DataInPlace);
  3175. send_char_array((char *)&tm->comp_times, sizeof(node_times));
  3176. send_char_array((char *)&tm->lp_stat, sizeof(lp_stat_desc));
  3177. send_dbl_array(&tm->lb, 1);
  3178. send_char_array((char *)&tm->stat, sizeof(tm_stat));
  3179. send_msg(tm->master, termcode);
  3180. freebuf(s_bufid);
  3181. free_tm(tm);
  3182. #endif
  3183. return(termcode);
  3184. }
  3185. /*===========================================================================*/
  3186. /*===========================================================================*/
  3187. #if !defined(_MSC_VER) && !defined(__MNO_CYGWIN) && defined(SIGHANDLER)
  3188. void sym_catch_c(int num)
  3189. {
  3190. sigset_t mask_set;
  3191. sigset_t old_set;
  3192. /* SIGTSTP ? */
  3193. signal(SIGINT, sym_catch_c);
  3194. char temp [MAX_LINE_LENGTH + 1];
  3195. sigfillset(&mask_set);
  3196. sigprocmask(SIG_SETMASK, &mask_set, &old_set);
  3197. strcpy(temp, "");
  3198. printf("\nDo you want to abort immediately, exit gracefully (from the current solve call only), or continue? [a/e/c]: ");
  3199. fflush(stdout);
  3200. fgets(temp, MAX_LINE_LENGTH, stdin);
  3201. if(temp[1] == '\n' && (temp[0] == 'a' || temp[0] == 'A')){
  3202. printf("\nTerminating...\n");
  3203. fflush(stdout);
  3204. exit(0);
  3205. }else if(temp[1] == '\n' && (temp[0] == 'e' || temp[0] == 'E')){
  3206. c_count++;
  3207. } else{
  3208. printf("\nContinuing...\n");
  3209. fflush(stdout);
  3210. c_count = 0;
  3211. }
  3212. }
  3213. #endif
  3214. /*===========================================================================*/
  3215. /*
  3216. * Find the lowerbound of the current branch-and-cut tree and save it in
  3217. * tm->lb
  3218. */
  3219. int find_tree_lb(tm_prob *tm)
  3220. {
  3221. double lb = MAXDOUBLE;
  3222. bc_node **samephase_cand;
  3223. if (tm->samephase_candnum > 0 || tm->active_node_num > 0) {
  3224. if (tm->par.node_selection_rule == LOWEST_LP_FIRST) {
  3225. lb = tm->samephase_cand[1]->lower_bound; /* [0] is a dummy */
  3226. } else {
  3227. samephase_cand = tm->samephase_cand;
  3228. for (int i = tm->samephase_candnum; i >= 1; i--){
  3229. if (samephase_cand[i]->lower_bound < lb) {
  3230. lb = samephase_cand[i]->lower_bound;
  3231. }
  3232. }
  3233. }
  3234. } else {
  3235. /* there are no more nodes left. */
  3236. lb = tm->ub;
  3237. }
  3238. /*
  3239. if (lb >= MAXDOUBLE / 2){
  3240. lb = tm->ub;
  3241. }
  3242. */
  3243. tm->lb = lb;
  3244. return 0;
  3245. }
  3246. /*===========================================================================*/