/src/coin/Symphony/tm_func.cpp
C++ | 3610 lines | 2853 code | 361 blank | 396 comment | 753 complexity | 576e13ef396bf1259b1880890d7790fe MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0
Large files files are truncated, but you can click here to view the full file
- /*===========================================================================*/
- /* */
- /* This file is part of the SYMPHONY MILP Solver Framework. */
- /* */
- /* SYMPHONY was jointly developed by Ted Ralphs (ted@lehigh.edu) and */
- /* Laci Ladanyi (ladanyi@us.ibm.com). */
- /* */
- /* (c) Copyright 2000-2011 Ted Ralphs. All Rights Reserved. */
- /* */
- /* This software is licensed under the Eclipse Public License. Please see */
- /* accompanying file for terms. */
- /* */
- /*===========================================================================*/
- #define COMPILING_FOR_TM
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #if !defined(_MSC_VER) && !defined(__MNO_CYGWIN) && defined(SIGHANDLER)
- #include <signal.h>
- #if !defined(HAS_SRANDOM)
- extern int srandom PROTO((unsigned seed));
- #endif
- #if !defined(HAS_RANDOM)
- extern long random PROTO((void));
- #endif
- #endif
- #ifdef _OPENMP
- #include "omp.h"
- #endif
- #if !defined (_MSC_VER)
- #include <unistd.h> /* this defines sleep() */
- #endif
- #include "sym_tm.h"
- #include "sym_constants.h"
- #include "sym_types.h"
- #include "sym_macros.h"
- #include "sym_messages.h"
- #include "sym_proccomm.h"
- #include "sym_timemeas.h"
- #include "sym_pack_cut.h"
- #include "sym_pack_array.h"
- #ifdef COMPILE_IN_LP
- #include "sym_lp.h"
- #endif
- #ifdef COMPILE_IN_TM
- #include "sym_master.h"
- #else
- #include "sym_cp.h"
- #endif
- int c_count = 0;
- /*===========================================================================*/
- /*===========================================================================*\
- * This file contains basic functions associated with the treemanager process
- \*===========================================================================*/
- /*===========================================================================*/
- /*===========================================================================*\
- * This function receives the intitial parameters and data and sets up
- * the tree manager data structures, etc.
- \*===========================================================================*/
- int tm_initialize(tm_prob *tm, base_desc *base, node_desc *rootdesc)
- {
- #ifndef COMPILE_IN_TM
- int r_bufid, bytes, msgtag, i;
- #endif
- FILE *f = NULL;
- tm_params *par;
- bc_node *root = (bc_node *) calloc(1, sizeof(bc_node));
- #ifdef COMPILE_IN_LP
- int i;
- #else
- #ifdef COMPILE_IN_TM
- int i;
- #endif
- int s_bufid;
- #endif
- int *termcodes = NULL;
- #if !defined(_MSC_VER) && !defined(__MNO_CYGWIN) && defined(SIGHANDLER)
- signal(SIGINT, sym_catch_c);
- #endif
- par = &tm->par;
- #ifdef _OPENMP
- tm->rpath =
- (bc_node ***) calloc(par->max_active_nodes, sizeof(bc_node **));
- tm->rpath_size = (int *) calloc(par->max_active_nodes, sizeof(int));
- tm->bpath =
- (branch_desc **) calloc(par->max_active_nodes, sizeof(branch_desc *));
- tm->bpath_size = (int *) calloc(par->max_active_nodes, sizeof(int));
- termcodes = (int *) calloc(par->max_active_nodes, sizeof(int));
- #else
- tm->rpath = (bc_node ***) calloc(1, sizeof(bc_node **));
- tm->rpath_size = (int *) calloc(1, sizeof(int));
- tm->bpath = (branch_desc **) calloc(1, sizeof(branch_desc *));
- tm->bpath_size = (int *) calloc(1, sizeof(int));
- termcodes = (int *) calloc(1, sizeof(int));
- #endif
- /*------------------------------------------------------------------------*\
- * Receives data from the master
- \*------------------------------------------------------------------------*/
- #ifdef COMPILE_IN_TM
- tm->bvarnum = base->varnum;
- tm->bcutnum = base->cutnum;
- #else
- r_bufid = receive_msg(ANYONE, TM_DATA);
- bufinfo(r_bufid, &bytes, &msgtag, &tm->master);
- receive_char_array((char *)par, sizeof(tm_params));
- receive_char_array(&tm->has_ub, 1);
- if (tm->has_ub)
- receive_dbl_array(&tm->ub, 1);
- receive_char_array(&tm->has_ub_estimate, 1);
- if (tm->has_ub_estimate)
- receive_dbl_array(&tm->ub_estimate, 1);
- READ_STR_LIST(par->lp_mach_num, MACH_NAME_LENGTH,
- par->lp_machs[0], par->lp_machs);
- READ_STR_LIST(par->cg_mach_num, MACH_NAME_LENGTH,
- par->cg_machs[0], par->cg_machs);
- READ_STR_LIST(par->cp_mach_num, MACH_NAME_LENGTH,
- par->cp_machs[0], par->cp_machs);
- receive_int_array(&tm->bvarnum, 1);
- receive_int_array(&tm->bcutnum, 1);
- #ifdef TRACE_PATH
- receive_int_array(&tm->feas_sol_size, 1);
- if (tm->feas_sol_size){
- tm->feas_sol = (int *) calloc (tm->feas_sol_size, sizeof(int));
- receive_int_array(tm->feas_sol, tm->feas_sol_size);
- }
- #endif
- freebuf(r_bufid);
- #endif
- SRANDOM(par->random_seed);
- #ifdef COMPILE_IN_LP
- #ifdef _OPENMP
- omp_set_dynamic(FALSE);
- omp_set_num_threads(par->max_active_nodes);
- #else
- par->max_active_nodes = 1;
- #endif
- tm->active_nodes = (bc_node **) calloc(par->max_active_nodes, sizeof(bc_node *));
- #ifndef COMPILE_IN_TM
- tm->lpp = (lp_prob **)
- malloc(par->max_active_nodes * sizeof(lp_prob *));
- for (i = 0; i < par->max_active_nodes; i++){
- tm->lpp[i] = (lp_prob *) calloc(1, sizeof(lp_prob));
- tm->lpp[i]->proc_index = i;
- }
- #ifdef COMPILE_IN_CG
- tm->cgp = (cg_prob **) malloc(par->max_active_nodes * sizeof(cg_prob *));
- for (i = 0; i < par->max_active_nodes; i++)
- tm->lpp[i]->cgp = tm->cgp[i] = (cg_prob *) calloc(1, sizeof(cg_prob));
- par->use_cg = FALSE;
- #endif
- #endif
- #pragma omp parallel for shared(tm)
- for (i = 0; i < par->max_active_nodes; i++){
- if ((termcodes[i] = lp_initialize(tm->lpp[i], 0)) < 0){
- printf("LP initialization failed with error code %i in thread %i\n\n",
- termcodes[i], i);
- }
- tm->lpp[i]->tm = tm;
- }
- tm->lp.free_num = par->max_active_nodes;
- for (i = 0; i < par->max_active_nodes; i++){
- if (termcodes[i] < 0){
- int tmp = termcodes[i];
- FREE(termcodes);
- return(tmp);
- }
- }
- #else
- tm->active_nodes =
- (bc_node **) malloc(par->max_active_nodes * sizeof(bc_node *));
- /*------------------------------------------------------------------------*\
- * Start the lp, cg processes and send cg tid's to the lp's.
- * Also, start the cp, sp processes.
- \*------------------------------------------------------------------------*/
- tm->lp = start_processes(tm, par->max_active_nodes, par->lp_exe,
- par->lp_debug, par->lp_mach_num, par->lp_machs);
- #endif
- #pragma omp critical (cut_pool)
- if (!tm->cuts){
- tm->cuts = (cut_data **) malloc(BB_BUNCH * sizeof(cut_data *));
- }
- if (par->use_cg){
- #ifndef COMPILE_IN_CG
- tm->cg = start_processes(tm, par->max_active_nodes, par->cg_exe,
- par->cg_debug, par->cg_mach_num, par->cg_machs);
- #ifdef COMPILE_IN_LP
- for (i = 0; i < par->max_active_nodes; i++)
- tm->lpp[i]->cut_gen = tm->cg.procs[i];
- #else
- for (i = 0; i < tm->lp.procnum; i++){
- s_bufid = init_send(DataInPlace);
- send_int_array(tm->cg.procs + i, 1);
- send_msg(tm->lp.procs[i], LP__CG_TID_INFO);
- }
- #endif
- #endif
- }
- if (par->max_cp_num){
- #ifdef COMPILE_IN_CP
- #ifndef COMPILE_IN_TM
- tm->cpp = (cut_pool **) malloc(par->max_cp_num * sizeof(cut_pool *));
- #endif
- for (i = 0; i < par->max_cp_num; i++){
- #ifndef COMPILE_IN_TM
- tm->cpp[i] = (cut_pool *) calloc(1, sizeof(cut_pool));
- #endif
- cp_initialize(tm->cpp[i], tm->master);
- }
- tm->cp.free_num = par->max_cp_num;
- tm->cp.procnum = par->max_cp_num;
- tm->cp.free_ind = (int *) malloc(par->max_cp_num * ISIZE);
- for (i = par->max_cp_num - 1; i >= 0; i--)
- tm->cp.free_ind[i] = i;
- #else
- tm->cp = start_processes(tm, par->max_cp_num, par->cp_exe,
- par->cp_debug, par->cp_mach_num, par->cp_machs);
- #endif
- tm->nodes_per_cp = (int *) calloc(tm->par.max_cp_num, ISIZE);
- tm->active_nodes_per_cp = (int *) calloc(tm->par.max_cp_num, ISIZE);
- }else{
- #ifdef COMPILE_IN_CP
- tm->cpp = (cut_pool **) calloc(1, sizeof(cut_pool *));
- #endif
- }
- /*------------------------------------------------------------------------*\
- * Receive the root node and send out initial data to the LP processes
- \*------------------------------------------------------------------------*/
- FREE(termcodes);
- if (tm->par.warm_start){
- if (!tm->rootnode){
- if (!(f = fopen(tm->par.warm_start_tree_file_name, "r"))){
- printf("Error reading warm start file %s\n\n",
- tm->par.warm_start_tree_file_name);
- return(ERROR__READING_WARM_START_FILE);
- }
- read_tm_info(tm, f);
- }else{
- free(root);
- root = tm->rootnode;
- }
- read_subtree(tm, root, f);
- if (f)
- fclose(f);
- if (!tm->rootnode){
- if (!read_tm_cut_list(tm, tm->par.warm_start_cut_file_name)){
- printf("Error reading warm start file %s\n\n",
- tm->par.warm_start_cut_file_name);
- return(ERROR__READING_WARM_START_FILE);
- }
- }
- tm->rootnode = root;
- if(root->node_status != NODE_STATUS__WARM_STARTED)
- root->node_status = NODE_STATUS__ROOT;
- }else{
- #ifdef COMPILE_IN_TM
- (tm->rootnode = root)->desc = *rootdesc;
- /* Copy the root description in case it is still needed */
- root->desc.uind.list = (int *) malloc(rootdesc->uind.size*ISIZE);
- memcpy((char *)root->desc.uind.list, (char *)rootdesc->uind.list,
- rootdesc->uind.size*ISIZE);
- root->bc_index = tm->stat.created++;
- root->lower_bound = -MAXDOUBLE;
- tm->stat.tree_size++;
- insert_new_node(tm, root);
- tm->phase = 0;
- tm->lb = 0;
- #else
- r_bufid = receive_msg(tm->master, TM_ROOT_DESCRIPTION);
- receive_node_desc(tm, root);
- if (root->desc.cutind.size > 0){ /* Hey we got cuts, too! Unpack them. */
- unpack_cut_set(tm, 0, 0, NULL);
- }
- freebuf(r_bufid);
- #endif
- #ifdef TRACE_PATH
- root->optimal_path = TRUE;
- #endif
- }
- return(FUNCTION_TERMINATED_NORMALLY);
- }
- /*===========================================================================*/
- /*===========================================================================*\
- * This is the main loop that solves the problem
- \*===========================================================================*/
- int solve(tm_prob *tm)
- {
- #ifndef COMPILE_IN_LP
- int r_bufid;
- #endif
- int termcode = 0;
- double start_time = tm->start_time;
- double no_work_start, ramp_up_tm = 0, ramp_down_time = 0;
- char ramp_down = FALSE, ramp_up = TRUE;
- double then, then2, then3, now;
- double timeout2 = 30, timeout3 = tm->par.logging_interval, timeout4 = 10;
- /*------------------------------------------------------------------------*\
- * The Main Loop
- \*------------------------------------------------------------------------*/
- no_work_start = wall_clock(NULL);
- termcode = TM_UNFINISHED;
- for (; tm->phase <= 1; tm->phase++){
- if (tm->phase == 1 && !tm->par.warm_start){
- if ((termcode = tasks_before_phase_two(tm)) ==
- FUNCTION_TERMINATED_NORMALLY){
- termcode = TM_FINISHED; /* Continue normally */
- }
- }
- then = wall_clock(NULL);
- then2 = wall_clock(NULL);
- then3 = wall_clock(NULL);
- #pragma omp parallel default(shared)
- {
- #ifdef _OPENMP
- int i, thread_num = omp_get_thread_num();
- #else
- int i, thread_num = 0;
- #endif
- while (tm->active_node_num > 0 || tm->samephase_candnum > 0){
- /*------------------------------------------------------------------*\
- * while there are nodes being processed or while there are nodes
- * waiting to be processed, continue to execute this loop
- \*------------------------------------------------------------------*/
- i = NEW_NODE__STARTED;
- while (tm->lp.free_num > 0 && (tm->par.time_limit >= 0.0 ?
- (wall_clock(NULL) - start_time < tm->par.time_limit) : TRUE) &&
- (tm->par.node_limit >= 0 ?
- tm->stat.analyzed < tm->par.node_limit : TRUE) &&
- ((tm->has_ub && (tm->par.gap_limit >= 0.0)) ?
- fabs(100*(tm->ub-tm->lb)/tm->ub) > tm->par.gap_limit : TRUE)
- && !(tm->par.find_first_feasible && tm->has_ub) && c_count <= 0){
- if (tm->samephase_candnum > 0){
- #pragma omp critical (tree_update)
- i = start_node(tm, thread_num);
- }else{
- i = NEW_NODE__NONE;
- }
- if (i != NEW_NODE__STARTED)
- break;
- if (ramp_up){
- ramp_up_tm += (wall_clock(NULL) -
- no_work_start) * (tm->lp.free_num + 1);
- }
- if (ramp_down){
- ramp_down_time += (wall_clock(NULL) -
- no_work_start) * (tm->lp.free_num + 1);
- }
- if (!tm->lp.free_num){
- ramp_down = FALSE;
- ramp_up = FALSE;
- }else if (ramp_up){
- no_work_start = wall_clock(NULL);
- }else{
- ramp_down = TRUE;
- no_work_start = wall_clock(NULL);
- }
- #ifdef COMPILE_IN_LP
- #ifdef _OPENMP
- if (tm->par.verbosity > 0)
- printf("Thread %i now processing node %i\n", thread_num,
- tm->lpp[thread_num]->bc_index);
- #endif
- if(tm->par.node_selection_rule == DEPTH_FIRST_THEN_BEST_FIRST &&
- tm->has_ub){
- tm->par.node_selection_rule = LOWEST_LP_FIRST;
- }
- switch(process_chain(tm->lpp[thread_num])){
- case FUNCTION_TERMINATED_NORMALLY:
- break;
- case ERROR__NO_BRANCHING_CANDIDATE:
- termcode = TM_ERROR__NO_BRANCHING_CANDIDATE;
- break;
- case ERROR__ILLEGAL_RETURN_CODE:
- termcode = TM_ERROR__ILLEGAL_RETURN_CODE;
- break;
- case ERROR__NUMERICAL_INSTABILITY:
- termcode = TM_ERROR__NUMERICAL_INSTABILITY;
- break;
- case ERROR__COMM_ERROR:
- termcode = TM_ERROR__COMM_ERROR;
- case ERROR__USER:
- termcode = TM_ERROR__USER;
- break;
- case ERROR__DUAL_INFEASIBLE:
- if(tm->lpp[thread_num]->bc_index < 1 ) {
- termcode = TM_UNBOUNDED;
- }else{
- termcode = TM_ERROR__NUMERICAL_INSTABILITY;
- }
- break;
- }
- #endif
- #pragma omp master
- {
- now = wall_clock(NULL);
- if (now - then2 > timeout2){
- if(tm->par.verbosity >= -1 ){
- print_tree_status(tm);
- }
- then2 = now;
- }
- if (now - then3 > timeout3){
- write_log_files(tm);
- then3 = now;
- }
- }
- }
- if (c_count > 0){
- termcode = TM_SIGNAL_CAUGHT;
- c_count = 0;
- break;
- }
- if (tm->par.time_limit >= 0.0 &&
- wall_clock(NULL) - start_time > tm->par.time_limit &&
- termcode != TM_FINISHED){
- termcode = TM_TIME_LIMIT_EXCEEDED;
- break;
- }
- if (tm->par.node_limit >= 0 && tm->stat.analyzed >=
- tm->par.node_limit && termcode != TM_FINISHED){
- if (tm->active_node_num + tm->samephase_candnum > 0){
- termcode = TM_NODE_LIMIT_EXCEEDED;
- }else{
- termcode = TM_FINISHED;
- }
- break;
- }
- if (tm->par.find_first_feasible && tm->has_ub){
- termcode = TM_FINISHED;
- break;
- }
- if (i == NEW_NODE__ERROR){
- termcode = SOMETHING_DIED;
- break;
- }
- if (tm->has_ub && (tm->par.gap_limit >= 0.0)){
- find_tree_lb(tm);
- if (fabs(100*(tm->ub-tm->lb)/tm->ub) <= tm->par.gap_limit){
- if (tm->lb < tm->ub){
- termcode = TM_TARGET_GAP_ACHIEVED;
- }else{
- termcode = TM_FINISHED;
- }
- break;
- }
- }
- if (i == NEW_NODE__NONE && tm->active_node_num == 0)
- break;
- #ifndef COMPILE_IN_LP
- struct timeval timeout = {5, 0};
- r_bufid = treceive_msg(ANYONE, ANYTHING, &timeout);
- if (r_bufid && !process_messages(tm, r_bufid)){
- find_tree_lb(tm);
- termcode = SOMETHING_DIED;
- break;
- }
- #endif
- now = wall_clock(NULL);
- if (now - then > timeout4){
- if (!processes_alive(tm)){
- find_tree_lb(tm);
- termcode = SOMETHING_DIED;
- break;
- }
- then = now;
- }
- #pragma omp master
- {
- for (i = 0; i < tm->par.max_active_nodes; i++){
- if (tm->active_nodes[i]){
- break;
- }
- }
- if (i == tm->par.max_active_nodes){
- tm->active_node_num = 0;
- }
- if (now - then2 > timeout2){
- if(tm->par.verbosity >=0 ){
- print_tree_status(tm);
- }
- then2 = now;
- }
- if (now - then3 > timeout3){
- write_log_files(tm);
- then3 = now;
- }
- }
- }
- }
- if(termcode == TM_UNBOUNDED) break;
- if (tm->samephase_candnum + tm->active_node_num == 0){
- termcode = TM_FINISHED;
- }
- if (tm->nextphase_candnum == 0)
- break;
- if (termcode != TM_UNFINISHED)
- break;
- }
- find_tree_lb(tm);
- tm->comp_times.ramp_up_tm = ramp_up_tm;
- tm->comp_times.ramp_down_time = ramp_down_time;
- write_log_files(tm);
- return(termcode);
- }
- /*===========================================================================*/
- /*==========================================================================*\
- * Write out the log files
- \*==========================================================================*/
- void write_log_files(tm_prob *tm)
- {
- #if !defined(COMPILE_IN_LP) || !defined(COMPILE_IN_CP)
- int s_bufid;
- #endif
- if (tm->par.logging){
- write_tm_info(tm, tm->par.tree_log_file_name, NULL, FALSE);
- write_subtree(tm->rootnode, tm->par.tree_log_file_name, NULL, TRUE,
- tm->par.logging);
- if (tm->par.logging != VBC_TOOL)
- write_tm_cut_list(tm, tm->par.cut_log_file_name, FALSE);
- }
- if (tm->par.max_cp_num > 0 && tm->par.cp_logging){
- #if defined(COMPILE_IN_LP) && defined(COMPILE_IN_CP)
- write_cp_cut_list(tm->cpp[0], tm->cpp[0]->par.log_file_name,
- FALSE);
- #else
- s_bufid = init_send(DataInPlace);
- send_msg(tm->cp.procs[0], WRITE_LOG_FILE);
- #endif
- }
- }
- /*===========================================================================*/
- /*==========================================================================*\
- * Prints out the current size of the tree and the gap *
- \*==========================================================================*/
- void print_tree_status(tm_prob *tm)
- {
- double elapsed_time;
- double obj_ub = SYM_INFINITY, obj_lb = -SYM_INFINITY;
- #ifdef SHOULD_SHOW_MEMORY_USAGE
- int i;
- int pid;
- int tmp_int;
- long unsigned vsize;
- char tmp_str[100], proc_filename[100];
- FILE *proc_file;
- double vsize_in_mb;
- #endif
- #if 0
- int *widths;
- double *gamma;
- int last_full_level = 0, max_width = 0, num_nodes_estimate = 1;
- int first_waist_level = 0, last_waist_level = 0, waist_level = 0;
- double average_node_time, estimated_time_remaining, user_time = 0.0;
- widths = (int *) calloc (tm->stat.max_depth + 1, ISIZE);
- gamma = (double *) calloc (tm->stat.max_depth + 1, DSIZE);
- calculate_widths(tm->rootnode, widths);
- last_full_level = tm->stat.max_depth;
- for (i = tm->stat.max_depth - 1; i > 0; i--){
- if ((double)(widths[i])/(double)(widths[i - 1]) < 2){
- last_full_level = i - 1;
- }
- if (widths[i] > max_width){
- max_width = widths[i];
- last_waist_level = i;
- first_waist_level = i;
- }
- if (widths[i] == max_width){
- first_waist_level = i;
- }
- }
- waist_level = (first_waist_level + last_waist_level)/2;
- for (i = 0; i < tm->stat.max_depth; i++){
- if (i < last_full_level){
- gamma[i] = 2.0;
- }else if (i < waist_level){
- gamma[i] = 2.0 - (double)((i - last_full_level + 1))/
- (double)((waist_level - last_full_level + 1));
- }else{
- gamma[i] = 1.0 - (double)(i - waist_level + 1)/
- (double)(tm->stat.max_depth - waist_level + 1);
- }
- }
- for (i = 1; i < tm->stat.max_depth; i++){
- gamma[i] *= gamma[i - 1];
- num_nodes_estimate += (int)(gamma[i] + 0.5);
- }
- elapsed_time = wall_clock(NULL) - tm->start_time;
- average_node_time = elapsed_time/tm->stat.analyzed;
- estimated_time_remaining =
- MAX(average_node_time*(num_nodes_estimate - tm->stat.analyzed), 0);
- #else
- elapsed_time = wall_clock(NULL) - tm->start_time;
- #endif
- #ifdef SHOULD_SHOW_MEMORY_USAGE
- pid = getpid();
- //printf("process id = %d\n",pid);
- sprintf(proc_filename,"/proc/%d/stat",pid);
- proc_file = fopen (proc_filename, "r");
- fscanf (proc_file, "%d %s %s", &tmp_int, tmp_str, tmp_str);
- for (i=0; i<19;i++) {
- fscanf (proc_file, "%d", &tmp_int);
- }
- fscanf (proc_file, "%lu", &vsize);
- fclose(proc_file);
- //printf("vsize = %lu\n",vsize);
- vsize_in_mb = vsize/1024.0/1024.0;
- if (tm->stat.max_vsize<vsize_in_mb) {
- tm->stat.max_vsize = vsize_in_mb;
- }
- printf("memory: %.2f MB ", vsize_in_mb);
- #endif
- printf("done: %i ", tm->stat.analyzed-tm->active_node_num);
- printf("left: %i ", tm->samephase_candnum+tm->active_node_num);
- if (tm->has_ub) {
- if (tm->obj_sense == SYM_MAXIMIZE){
- obj_lb = -tm->ub + tm->obj_offset;
- printf("lb: %.2f ", obj_lb);
- }else{
- obj_ub = tm->ub + tm->obj_offset;
- printf("ub: %.2f ", obj_ub);
- }
- } else {
- if (tm->obj_sense == SYM_MAXIMIZE){
- printf("lb: ?? ");
- }else{
- printf("ub: ?? ");
- }
- }
- find_tree_lb(tm);
- if(tm->lb > -SYM_INFINITY){
- if (tm->obj_sense == SYM_MAXIMIZE){
- obj_ub = -tm->lb + tm->obj_offset;
- printf("ub: %.2f ", obj_ub);
- }else{
- obj_lb = tm->lb + tm->obj_offset;
- printf("lb: %.2f ", obj_lb);
- }
- }else{
- if (tm->obj_sense == SYM_MAXIMIZE){
- printf("ub: ?? ");
- }else{
- printf("lb: ?? ");
- }
- }
- if (tm->has_ub && tm->ub && tm->lb > -SYM_INFINITY){
- printf("gap: %.2f ", fabs(100*(obj_ub-obj_lb)/obj_ub));
- }
- printf("time: %i\n", (int)(elapsed_time));
- #if 0
- printf("Estimated nodes remaining: %i\n", num_nodes_estimate);
- printf("Estimated time remaining: %i\n",
- (int)(estimated_time_remaining));
- #endif
- if (tm->par.vbc_emulation == VBC_EMULATION_FILE){
- FILE *f;
- #pragma omp critical(write_vbc_emulation_file)
- if (!(f = fopen(tm->par.vbc_emulation_file_name, "a"))){
- printf("\nError opening vbc emulation file\n\n");
- }else{
- PRINT_TIME(tm, f);
- fprintf(f, "L %.2f \n", tm->lb);
- fclose(f);
- }
- }else if (tm->par.vbc_emulation == VBC_EMULATION_LIVE){
- printf("$L %.2f\n", tm->lb);
- }
- #if 0
- FREE(widths);
- FREE(gamma);
- #endif
- }
- /*===========================================================================*/
- void calculate_widths(bc_node *node, int* widths)
- {
- int i;
- widths[node->bc_level] += 1;
- for (i = 0; i < node->bobj.child_num; i ++){
- calculate_widths(node->children[i], widths);
- }
- }
- /*===========================================================================*/
- /*===========================================================================*\
- * This function picks the "best" node off the active node list
- \*===========================================================================*/
- int start_node(tm_prob *tm, int thread_num)
- {
- int lp_ind, get_next, ind;
- bc_node *best_node = NULL;
- double time;
- time = wall_clock(NULL);
- /*------------------------------------------------------------------------*\
- * First choose the "best" node from the list of candidate nodes.
- * If the list for the current phase is empty then we return NEW_NODE__NONE.
- * Also, if the lower bound on the "best" node is above the current UB then
- * we just move that node the list of next phase candidates.
- \*------------------------------------------------------------------------*/
- get_next = TRUE;
- while (get_next){
- if ((best_node = del_best_node(tm)) == NULL)
- return(NEW_NODE__NONE);
- if (best_node->node_status == NODE_STATUS__WARM_STARTED){
- if(best_node->lower_bound >= MAXDOUBLE)
- break;
- }
- /* if no UB yet or lb is lower than UB then go ahead */
- if (!tm->has_ub ||
- (tm->has_ub && best_node->lower_bound < tm->ub-tm->par.granularity))
- break;
- /* ok, so we do have an UB and lb is higher than the UB. */
- /* in this switch we assume that there are only two phases! */
- switch (((best_node->desc.nf_status) << 8) + tm->phase){
- case (NF_CHECK_NOTHING << 8) + 0: /* prune these */
- case (NF_CHECK_NOTHING << 8) + 1:
- if(!tm->par.sensitivity_analysis){
- if (tm->par.max_cp_num > 0 && best_node->cp){
- #ifdef COMPILE_IN_CP
- ind = best_node->cp;
- #else
- ind = find_process_index(&tm->cp, best_node->cp);
- #endif
- tm->nodes_per_cp[ind]--;
- if (tm->nodes_per_cp[ind] + tm->active_nodes_per_cp[ind] == 0)
- tm->cp.free_ind[tm->cp.free_num++] = ind;
- }
- best_node->node_status = NODE_STATUS__PRUNED;
- best_node->feasibility_status = OVER_UB_PRUNED;
- if (tm->par.verbosity > 0){
- printf("++++++++++++++++++++++++++++++++++++++++++++++++++\n");
- printf("+ TM: Pruning NODE %i LEVEL %i instead of sending it.\n",
- best_node->bc_index, best_node->bc_level);
- printf("++++++++++++++++++++++++++++++++++++++++++++++++++\n");
- }
- if (tm->par.keep_description_of_pruned == KEEP_ON_DISK_VBC_TOOL ||
- tm->par.keep_description_of_pruned == KEEP_ON_DISK_FULL ||
- tm->par.keep_description_of_pruned == DISCARD){
- if (tm->par.keep_description_of_pruned ==
- KEEP_ON_DISK_VBC_TOOL ||
- tm->par.keep_description_of_pruned == KEEP_ON_DISK_FULL){
- #pragma omp critical (write_pruned_node_file)
- write_pruned_nodes(tm, best_node);
- }
- #if 0
- if (tm->par.vbc_emulation == VBC_EMULATION_FILE_NEW) {
- purge_pruned_nodes(tm, best_node, VBC_PRUNED_FATHOMED);
- } else {
- purge_pruned_nodes(tm, best_node, VBC_PRUNED);
- }
- #else
- purge_pruned_nodes(tm, best_node, VBC_PRUNED);
- #endif
- }
- break;
- }
- case (NF_CHECK_ALL << 8) + 1: /* work on these */
- case (NF_CHECK_UNTIL_LAST << 8) + 1:
- case (NF_CHECK_AFTER_LAST << 8) + 1:
- get_next = FALSE;
- break;
- default:
- /* i.e., phase == 0 and nf_status != NF_CHECK_NOTHING */
- if (!(tm->par.colgen_strat[0] & FATHOM__GENERATE_COLS__RESOLVE)){
- REALLOC(tm->nextphase_cand, bc_node *, tm->nextphase_cand_size,
- tm->nextphase_candnum+1, BB_BUNCH);
- tm->nextphase_cand[tm->nextphase_candnum++] = best_node;
- }else{
- get_next = FALSE;
- }
- break;
- }
- }
- /* Assign a free lp process */
- #ifdef COMPILE_IN_LP
- lp_ind = thread_num;
- #else
- lp_ind = tm->lp.free_ind[--tm->lp.free_num];
- best_node->lp = tm->lp.procs[lp_ind];
- best_node->cg = tm->par.use_cg ? tm->cg.procs[lp_ind] : 0;
- #endif
- /* assign pools, too */
- best_node->cp = assign_pool(tm, best_node->cp, &tm->cp,
- tm->active_nodes_per_cp, tm->nodes_per_cp);
- if (best_node->cp < 0) return(NEW_NODE__ERROR);
- /* It's time to put together the node and send it out */
- tm->active_nodes[lp_ind] = best_node;
- tm->active_node_num++;
- tm->stat.analyzed++;
- send_active_node(tm,best_node,tm->par.colgen_strat[tm->phase],thread_num);
- tm->comp_times.start_node += wall_clock(NULL) - time;
- return(NEW_NODE__STARTED);
- }
- /*===========================================================================*/
- /*===========================================================================*\
- * Returns the "best" active node and deletes it from the list
- \*===========================================================================*/
- bc_node *del_best_node(tm_prob *tm)
- {
- bc_node **list = tm->samephase_cand;
- int size = tm->samephase_candnum;
- bc_node *temp = NULL, *best_node;
- int pos, ch;
- int rule = tm->par.node_selection_rule;
- if (size == 0)
- return(NULL);
- best_node = list[1];
- temp = list[1] = list[size];
- tm->samephase_candnum = --size;
- if (tm->par.verbosity > 10)
- if (tm->samephase_candnum % 10 == 0)
- printf("\nTM: tree size: %i , %i\n\n",
- tm->samephase_candnum, tm->nextphase_candnum);
- pos = 1;
- while ((ch=2*pos) < size){
- if (node_compar(rule, list[ch], list[ch+1]))
- ch++;
- if (node_compar(rule, list[ch], temp)){
- list[pos] = temp;
- return(best_node);
- }
- list[pos] = list[ch];
- pos = ch;
- }
- if (ch == size){
- if (node_compar(rule, temp, list[ch])){
- list[pos] = list[ch];
- pos = ch;
- }
- }
- list[pos] = temp;
- return(best_node);
- }
- /*===========================================================================*/
- /*===========================================================================*\
- * Insert a new active node into the active node list (kept as a binary tree)
- \*===========================================================================*/
- void insert_new_node(tm_prob *tm, bc_node *node)
- {
- int pos, ch, size = tm->samephase_candnum;
- bc_node **list;
- int rule = tm->par.node_selection_rule;
- tm->samephase_candnum = pos = ++size;
- if (tm->par.verbosity > 10)
- if (tm->samephase_candnum % 10 == 0)
- printf("\nTM: tree size: %i , %i\n\n",
- tm->samephase_candnum, tm->nextphase_candnum);
- REALLOC(tm->samephase_cand, bc_node *,
- tm->samephase_cand_size, size + 1, BB_BUNCH);
- list = tm->samephase_cand;
- while ((ch=pos>>1) != 0){
- if (node_compar(rule, list[ch], node)){
- list[pos] = list[ch];
- pos = ch;
- }else{
- break;
- }
- }
- list[pos] = node;
- }
- /*===========================================================================*/
- /*===========================================================================*\
- * This is the node comparison function used to order the list of active
- * Nodes are ordered differently depending on what the comparison rule is
- \*===========================================================================*/
- int node_compar(int rule, bc_node *node0, bc_node *node1)
- {
- switch(rule){
- case LOWEST_LP_FIRST:
- return(node1->lower_bound < node0->lower_bound ? 1:0);
- case HIGHEST_LP_FIRST:
- return(node1->lower_bound > node0->lower_bound ? 1:0);
- case BREADTH_FIRST_SEARCH:
- return(node1->bc_level < node0->bc_level ? 1:0);
- case DEPTH_FIRST_SEARCH:
- case DEPTH_FIRST_THEN_BEST_FIRST:
- return(node1->bc_level > node0->bc_level ? 1:0);
- }
- return(0); /* fake return */
- }
- /*===========================================================================*/
- /*===========================================================================*\
- * Nodes by default inherit their parent's pools. However if there is a free
- * pool then the node is moved over to the free pool.
- \*===========================================================================*/
- int assign_pool(tm_prob *tm, int oldpool, process_set *pools,
- int *active_nodes_per_pool, int *nodes_per_pool)
- {
- int oldind = -1, ind, pool;
- #ifndef COMPILE_IN_CP
- int s_bufid, r_bufid;
- struct timeval timeout = {5, 0};
- #endif
- if (pools->free_num == 0){
- /* No change in the pool assigned to this node */
- return(oldpool);
- }
- if (oldpool > 0){
- #ifdef COMPILE_IN_CP
- oldind = oldpool;
- #else
- oldind = find_process_index(pools, oldpool);
- #endif
- if (nodes_per_pool[oldind] == 1){
- nodes_per_pool[oldind]--;
- active_nodes_per_pool[oldind]++;
- return(oldpool);
- }
- }
- ind = pools->free_ind[--pools->free_num];
- #ifdef COMPILE_IN_CP
- pool = ind;
- #else
- pool = pools->procs[ind];
- #endif
- if (! oldpool){
- /* If no pool is assigned yet then just assign the free one */
- active_nodes_per_pool[ind] = 1;
- return(pool);
- }
- /* finally when we really move the node from one pool to another */
- nodes_per_pool[oldind]--;
- active_nodes_per_pool[ind] = 1;
- #ifdef COMPILE_IN_CP
- /*FIXME: Multiple Pools won't work in shared memory mode until I fill this
- in.*/
- #else
- s_bufid = init_send(DataInPlace);
- send_int_array(&oldpool, 1);
- send_msg(pool, POOL_YOU_ARE_USELESS);
- s_bufid = init_send(DataInPlace);
- send_int_array(&pool, 1);
- send_msg(oldpool, POOL_COPY_YOURSELF);
- freebuf(s_bufid);
- do{
- r_bufid = treceive_msg(pool, POOL_USELESSNESS_ACKNOWLEDGED, &timeout);
- if (r_bufid == 0)
- if (pstat(pool) != PROCESS_OK) return(NEW_NODE__ERROR);
- }while (r_bufid == 0);
- freebuf(r_bufid);
- #endif
- return(pool);
- }
- /*===========================================================================*/
- /*===========================================================================*\
- * Takes the branching object description and sets up data structures
- * for the resulting children and adds them to the list of candidates.
- \*===========================================================================*/
- int generate_children(tm_prob *tm, bc_node *node, branch_obj *bobj,
- double *objval, int *feasible, char *action,
- int olddive, int *keep, int new_branching_cut)
- {
- node_desc *desc;
- int np_cp = 0, np_sp = 0;
- int dive = DO_NOT_DIVE, i;
- bc_node *child;
- int child_num;
- #ifdef TRACE_PATH
- int optimal_path = -1;
- #endif
- /* before we start to generate the children we must figure out if we'll
- * dive so that we can put the kept child into the right location */
- if (*keep >= 0 && (olddive == CHECK_BEFORE_DIVE || olddive == DO_DIVE))
- dive = olddive == DO_DIVE ? DO_DIVE : shall_we_dive(tm, objval[*keep]);
- node->children = (bc_node **) calloc(bobj->child_num, sizeof(bc_node *));
- if (node->bc_level == tm->stat.max_depth)
- tm->stat.max_depth++;
- child_num = bobj->child_num;
- #ifdef TRACE_PATH
- if (node->optimal_path && tm->feas_sol_size){
- for (i = 0; i < tm->feas_sol_size; i++)
- if (tm->feas_sol[i] == bobj->name)
- break;
- if (i < tm->feas_sol_size)
- optimal_path = 1;
- else
- optimal_path = 0;
- printf("\n\nNode %i is on the optimal path\n\n",
- tm->stat.tree_size + optimal_path);
- }
- #endif
- for (i = 0; i < child_num; i++){
- child = node->children[i] = (bc_node *) calloc(1, sizeof(bc_node));
- child->bc_index = tm->stat.tree_size++;
- child->bc_level = node->bc_level + 1;
- child->lower_bound = objval[i];
- #ifdef COMPILE_IN_LP
- child->update_pc = bobj->is_est[i] ? TRUE : FALSE;
- #endif
- child->parent = node;
- if (tm->par.verbosity > 10){
- printf("Generating node %i from %i...\n", child->bc_index,
- node->bc_index);
- }
- if (tm->par.vbc_emulation == VBC_EMULATION_FILE){
- FILE *f;
- #pragma omp critical(write_vbc_emulation_file)
- if (!(f = fopen(tm->par.vbc_emulation_file_name, "a"))){
- printf("\nError opening vbc emulation file\n\n");
- }else{
- PRINT_TIME(tm, f);
- fprintf(f, "N %i %i %i\n", node->bc_index+1, child->bc_index+1,
- feasible[i] ? VBC_FEAS_SOL_FOUND :
- ((dive != DO_NOT_DIVE && *keep == i) ?
- VBC_ACTIVE_NODE : VBC_CAND_NODE));
- fclose(f);
- }
- } else if (tm->par.vbc_emulation == VBC_EMULATION_FILE_NEW) {
- FILE *f;
- #pragma omp critical(write_vbc_emulation_file)
- if (!(f = fopen(tm->par.vbc_emulation_file_name, "a"))){
- printf("\nError opening vbc emulation file\n\n");
- }else{
- PRINT_TIME2(tm, f);
- char reason[50];
- char branch_dir = 'M';
- sprintf (reason, "%s %i %i", "candidate", child->bc_index+1,
- node->bc_index+1);
- if (child->bc_index>0){
- if (node->children[0]==child) {
- branch_dir = node->bobj.sense[0];
- /*branch_dir = 'L';*/
- } else {
- branch_dir = node->bobj.sense[1];
- /*branch_dir = 'R';*/
- }
- if (branch_dir == 'G') {
- branch_dir = 'R';
- }
- }
- if (action[i] == PRUNE_THIS_CHILD_FATHOMABLE ||
- action[i] == PRUNE_THIS_CHILD_INFEASIBLE){
- sprintf(reason,"%s %c", reason, branch_dir);
- }else{
- sprintf(reason,"%s %c %f", reason, branch_dir,
- child->lower_bound);
- }
- fprintf(f,"%s\n",reason);
- fclose(f);
- }
- }else if (tm->par.vbc_emulation == VBC_EMULATION_LIVE){
- printf("$N %i %i %i\n", node->bc_index+1, child->bc_index+1,
- feasible[i] ? VBC_FEAS_SOL_FOUND :
- ((dive != DO_NOT_DIVE && *keep == i) ?
- VBC_ACTIVE_NODE: VBC_CAND_NODE));
- }
- #ifdef TRACE_PATH
- if (optimal_path == i)
- child->optimal_path = TRUE;
- #endif
- tm->stat.created++;
- #ifndef ROOT_NODE_ONLY
- if (action[i] == PRUNE_THIS_CHILD ||
- action[i] == PRUNE_THIS_CHILD_FATHOMABLE ||
- action[i] == PRUNE_THIS_CHILD_INFEASIBLE ||
- (tm->has_ub && tm->ub - tm->par.granularity < objval[i] &&
- node->desc.nf_status == NF_CHECK_NOTHING)){
- /* this last can happen if the TM got the new bound but it hasn't
- * been propagated to the LP yet */
- #else /*We only want to process the root node in this case - discard others*/
- if (TRUE){
- #endif
- if (tm->par.verbosity > 0){
- printf("++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
- printf("+ TM: Pruning NODE %i LEVEL %i while generating it.\n",
- child->bc_index, child->bc_level);
- printf("++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
- }
- child->node_status = NODE_STATUS__PRUNED;
- #ifdef TRACE_PATH
- if (child->optimal_path){
- printf("\n\nAttempting to prune the optimal path!!!!!!!!!\n\n");
- sleep(600);
- if (tm->par.logging){
- write_tm_info(tm, tm->par.tree_log_file_name, NULL, FALSE);
- write_subtree(tm->rootnode, tm->par.tree_log_file_name, NULL,
- TRUE, tm->par.logging);
- write_tm_cut_list(tm, tm->par.cut_log_file_name, FALSE);
- }
- exit(1);
- }
- #endif
- if (tm->par.keep_description_of_pruned == DISCARD ||
- tm->par.keep_description_of_pruned == KEEP_ON_DISK_VBC_TOOL){
- child->parent = node;
- if (tm->par.keep_description_of_pruned == KEEP_ON_DISK_VBC_TOOL)
- #pragma omp critical (write_pruned_node_file)
- write_pruned_nodes(tm, child);
- if (tm->par.vbc_emulation == VBC_EMULATION_FILE_NEW) {
- int vbc_node_pr_reason;
- switch (action[i]) {
- case PRUNE_THIS_CHILD_INFEASIBLE:
- vbc_node_pr_reason = VBC_PRUNED_INFEASIBLE;
- break;
- case PRUNE_THIS_CHILD_FATHOMABLE:
- vbc_node_pr_reason = VBC_PRUNED_FATHOMED;
- break;
- default:
- vbc_node_pr_reason = VBC_PRUNED;
- }
- /* following is no longer needed because this care is taken
- * care of in install_new_ub
- */
- /*
- if (feasible[i]) {
- vbc_node_pr_reason = VBC_FEAS_SOL_FOUND;
- }
- */
- #pragma omp critical (tree_update)
- purge_pruned_nodes(tm, child, vbc_node_pr_reason);
- } else {
- #pragma omp critical (tree_update)
- purge_pruned_nodes(tm, child, feasible[i] ? VBC_FEAS_SOL_FOUND :
- VBC_PRUNED);
- }
- if (--child_num == 0){
- *keep = -1;
- return(DO_NOT_DIVE);
- }
- if (*keep == child_num) *keep = i;
- #ifdef TRACE_PATH
- if (optimal_path == child_num) optimal_path = i;
- #endif
- action[i] = action[child_num];
- objval[i] = objval[child_num];
- feasible[i--] = feasible[child_num];
- continue;
- }
- }else{
- child->node_status = NODE_STATUS__CANDIDATE;
- /* child->lp = child->cg = 0; zeroed out by calloc */
- child->cp = node->cp;
- }
- #ifdef DO_TESTS
- if (child->lower_bound < child->parent->lower_bound - .01){
- printf("#######Error: Child's lower bound (%.3f) is less than ",
- child->lower_bound);
- printf("parent's (%.3f)\n", child->parent->lower_bound);
- }
- if (child->lower_bound < tm->rootnode->lower_bound - .01){
- printf("#######Error: Node's lower bound (%.3f) is less than ",
- child->lower_bound);
- printf("root's (%.3f)\n", tm->rootnode->lower_bound);
- }
- #endif
- /* child->children = NULL; zeroed out by calloc */
- /* child->child_num = 0; zeroed out by calloc */
- /* child->died = 0; zeroed out by calloc */
- desc = &child->desc;
- /* all this is set by calloc
- * desc->uind.type = 0; WRT_PARENT and no change
- * desc->uind.size = 0;
- * desc->uind.added = 0;
- * desc->uind.list = NULL;
- * desc->not_fixed.type = 0; WRT_PARENT and no change
- * desc->not_fixed.size = 0;
- * desc->not_fixed.added = 0;
- * desc->not_fixed.list = NULL;
- * desc->cutind.type = 0; WRT_PARENT and no change
- * desc->cutind.size = 0;
- * desc->cutind.added = 0;
- * desc->cutind.list = NULL;
- * desc->basis.basis_exists = FALSE; This has to be validated!!!
- * desc->basis.{[base,extra][rows,vars]}
- .type = 0; WRT_PARENT and no change
- .size = 0;
- .list = NULL;
- .stat = NULL;
- */
- if (node->desc.basis.basis_exists){
- desc->basis.basis_exists = TRUE;
- }
- /* If we have a non-base, new branching cut then few more things
- might have to be fixed */
- if (new_branching_cut && bobj->name >= 0){
- /* Fix cutind and the basis description */
- desc->cutind.size = 1;
- desc->cutind.added = 1;
- desc->cutind.list = (int *) malloc(ISIZE);
- desc->cutind.list[0] = bobj->name;
- if (desc->basis.basis_exists){
- desc->basis.extrarows.size = 1;
- desc->basis.extrarows.list = (int *) malloc(ISIZE);
- desc->basis.extrarows.list[0] = bobj->name;
- desc->basis.extrarows.stat = (int *) malloc(ISIZE);
- desc->basis.extrarows.stat[0] = SLACK_BASIC;
- }
- }
- desc->desc_size = node->desc.desc_size;
- desc->desc = node->desc.desc;
- desc->nf_status = node->desc.nf_status;
- #ifdef SENSITIVITY_ANALYSIS
- if (tm->par.sensitivity_analysis &&
- action[i] != PRUNE_THIS_CHILD_INFEASIBLE){
- child->duals = bobj->duals[i];
- bobj->duals[i] = 0;
- }
- #endif
- if (child->node_status != NODE_STATUS__PRUNED && feasible[i]){
- if(tm->par.keep_description_of_pruned == KEEP_IN_MEMORY){
- child->sol_size = bobj->sol_sizes[i];
- child->sol_ind = bobj->sol_inds[i];
- bobj->sol_inds[i]=0;
- child->sol = bobj->solutions[i];
- bobj->solutions[i] = 0;
- child->feasibility_status = NOT_PRUNED_HAS_CAN_SOLUTION;
- }
- }
- if (child->node_status == NODE_STATUS__PRUNED){
- if(tm->par.keep_description_of_pruned == KEEP_IN_MEMORY){
- child->feasibility_status = OVER_UB_PRUNED;
- if (feasible[i]){
- child->sol_size = bobj->sol_sizes[i];
- child->sol_ind = bobj->sol_inds[i];
- bobj->sol_inds[i] = 0;
- child->sol = bobj->solutions[i];
- bobj->solutions[i] = 0;
- child->feasibility_status = FEASIBLE_PRUNED;
- }
- if (action[i] == PRUNE_THIS_CHILD_INFEASIBLE){
- child->feasibility_status = INFEASIBLE_PRUNED;
- }
- }
- #ifdef TRACE_PATH
- if (child->optimal_path){
- printf("\n\nAttempting to prune the optimal path!!!!!!!!!\n\n");
- sleep(600);
- if (tm->par.logging){
- write_tm_info(tm, tm->par.tree_log_file_name, NULL, FALSE);
- write_subtree(tm->rootnode, tm->par.tree_log_file_name, NULL,
- TRUE, tm->par.logging);
- write_tm_cut_list(tm, tm->par.cut_log_file_name, FALSE);
- }
- exit(1);
- }
- #endif
- if (tm->par.keep_description_of_pruned == KEEP_ON_DISK_FULL ||
- tm->par.keep_description_of_pruned == KEEP_ON_DISK_VBC_TOOL){
- #pragma omp critical (write_pruned_node_file)
- write_pruned_nodes(tm, child);
- #pragma omp critical (tree_update)
- if (tm->par.vbc_emulation== VBC_EMULATION_FILE_NEW) {
- int vbc_node_pr_reason;
- switch (action[i]) {
- case PRUNE_THIS_CHILD_INFEASIBLE:
- vbc_node_pr_reason = VBC_PRUNED_INFEASIBLE;
- break;
- case PRUNE_THIS_CHILD_FATHOMABLE:
- vbc_node_pr_reason = VBC_PRUNED_FATHOMED;
- break;
- default:
- vbc_node_pr_reason = VBC_PRUNED;
- }
- /* following is no longer needed because this care is taken
- * care of in install_new_ub
- */
- /*
- if (feasible[i]) {
- vbc_node_pr_reason = VBC_FEAS_SOL_FOUND;
- }
- */
- purge_pruned_nodes(tm, child, vbc_node_pr_reason);
- } else {
- purge_pruned_nodes(tm, child, feasible[i] ? VBC_FEAS_SOL_FOUND :
- VBC_PRUNED);
- }
- if (--child_num == 0){
- *keep = -1;
- return(DO_NOT_DIVE);
- }
- if (*keep == child_num) *keep = i;
- #ifdef TRACE_PATH
- if (optimal_path == child_num) optimal_path = i;
- #endif
- action[i] = action[child_num];
- objval[i] = objval[child_num];
- feasible[i--] = feasible[child_num];
- }
- continue;
- }
- if (tm->phase == 0 &&
- !(tm->par.colgen_strat[0] & FATHOM__GENERATE_COLS__RESOLVE) &&
- (feasible[i] == LP_D_UNBOUNDED ||
- (tm->has_ub && tm->ub - tm->par.granularity < child->lower_bound))){
- /* it is kept for the next phase (==> do not dive) */
- if (*keep == i)
- dive = DO_NOT_DIVE;
- REALLOC(tm->nextphase_cand, bc_node *,
- tm->nextphase_cand_size, tm->nextphase_candnum+1, BB_BUNCH);
- tm->nextphase_cand[tm->nextphase_candnum++] = child;
- np_cp++;
- np_sp++;
- }else{
- /* it will be processed in this phase (==> insert it if not kept) */
- if (*keep != i || dive == DO_NOT_DIVE){
- #pragma omp critical (tree_update)
- insert_new_node(tm, child);
- np_cp++;
- np_sp++;
- }
- }
- }
- if (node->cp)
- #ifdef COMPILE_IN_CP
- tm->nodes_per_cp[node->cp] += np_cp;
- #else
- tm->nodes_per_cp[find_process_index(&tm->cp, node->cp)] += np_cp;
- #endif
- return(dive);
- }
- /*===========================================================================*/
- /*===========================================================================*\
- * Determines whether or not the LP process should keep one of the
- * children resulting from branching or whether it should get a new node
- * from the candidate list.
- \*===========================================================================*/
- char shall_we_dive(tm_prob *tm, double objval)
- {
- char dive;
- int i, k;
- double rand_num, average_lb;
- double cutoff = 0;
- double etol = 1e-3;
- if (tm->par.time_limit >= 0.0 &&
- wall_clock(NULL) - tm->start_time >= tm->par.time_limit){
- return(FALSE);
- }
- if (tm->par.node_limit >= 0 && tm->stat.analyzed >= tm->par.node_limit){
- return(FALSE);
- }
- if (tm->has_ub && (tm->par.gap_limit >= 0.0)){
- find_tree_lb(tm);
- if (100*(tm->ub-tm->lb)/(fabs(tm->ub)+etol) <= tm->par.gap_limit){
- return(FALSE);
- }
- }
- rand_num = ((double)(RANDOM()))/((double)(MAXINT));
- if (tm->par.unconditional_dive_frac > 1 - rand_num){
- dive = CHECK_BEFORE_DIVE;
- }else{
- switch(tm->par.diving_strategy){
- case BEST_ESTIMATE:
- if (tm->has_ub_estimate){
- if (objval > tm->ub_estimate){
- dive = DO_NOT_DIVE;
- tm->stat.diving_halts++;
- }else{
- dive = CHECK_BEFORE_DIVE;
- }
- break;
- }
- case COMP_BEST_K:
- average_lb = 0;
- #pragma omp critical (tree_update)
- for (k = 0, i = MIN(tm->samephase_candnum, tm->par.diving_k);
- i > 0; i--)
- if (tm->samephase_cand[i]->lower_bound < MAXDOUBLE/2){
- average_lb += tm->samephase_cand[i]->lower_bound;
- k++;
- }
- if (k){
- average_lb /= k;
- }else{
- dive = CHECK_BEFORE_DIVE;
- break;
- }
- if (fabs(average_lb) < etol) {
- average_lb = (average_lb > 0) ? etol : -etol;
- if (fabs(objval) < etol) {
- objval = (objval > 0) ? etol : -etol;
- }
- }
- if (fabs((objval/average_lb)-1) > tm->par.diving_threshold){
- dive = DO_NOT_DIVE;
- tm->stat.diving_halts++;
- }else{
- dive = CHECK_BEFORE_DIVE;
- }
- break;
- case COMP_BEST_K_GAP:
- average_lb = 0;
- for (k = 0, i = MIN(tm->samephase_candnum, tm->par.diving_k);
- i > 0; i--)
- if (tm->samephase_cand[i]->lower_bound < MAXDOUBLE/2){
- average_lb += tm->samephase_cand[i]->lower_bound;
- k++;
- }
- if (k){
- average_lb /= k;
- }else{
- dive = CHECK_BEFORE_DIVE;
- break;
- }
- if (tm->has_ub)
- cutoff = tm->par.diving_threshold*(tm->ub - average_lb);
- else
- cutoff = (1 + tm->par.diving_threshold)*average_lb;
- if (objval > average_lb + cutoff){
- dive = DO_NOT_DIVE;
- tm->stat.diving_halts++;
- }else{
- dive = CHECK_BEFORE_DIVE;
- }
- break;
- default:
- printf("Unknown diving strategy -- diving by default\n");
- dive = DO_DIVE;
- break;
- }
- }
- return(dive);
- }
- /*===========================================================================*/
- /*===========================================================================*\
- * This routine is entirely for saving memory. If there is no need to
- * keep the description of the pruned nodes in memory, they are freed as
- * soon as they are no longer needed. This can set off a chain reaction
- * of other nodes that are no longer needed.
- \*===========================================================================*/
- int purge_pruned_nodes(tm_prob *tm, bc_node *node, int category)
- {
- int i, new_child_num;
- branch_obj *bobj = &node->parent->bobj;
- char reason[30];
- char branch_dir = 'M';
- if (tm->par.vbc_emulation != VBC_EMULATION_FILE_NEW &&
- (category == VBC_PRUNED_INFEASIBLE || category == VBC_PRUNED_FATHOMED
- || category == VBC_IGNORE)) {
- printf("Error in purge_pruned_nodes.");
- printf("category refers to VBC_EMULATION_FILE_NEW");
- printf("when it is not used.\n");
- exit(456);
- }
- if (tm->par.vbc_emulation == VBC_EMULATION_FILE_NEW) {
- switch (category) {
- case VBC_PRUNED_INFEASIBLE:
- sprintf(reason,"%s","infeasible");
- sprintf(reason,"%s %i %i",reason, node->bc_index+1,
- node->parent->bc_index+1);
- if (node->bc_index>0) {
- if (node->parent->children[0]==node) {
- branch_dir = node->parent->bobj.sense[0];
- /*branch_dir = 'L';*/
- } else {
- branch_dir = node->parent->bobj.sense[1];
- /*branch_dir = 'R';*/
- }
- if (branch_dir == 'G') {
- branch_dir = 'R';
- }
- }
- sprintf(reason,"%s %c %s", reason, branch_dir, "\n");
- break;
- case VBC_PRUNED_FATHOMED:
- sprintf(reason,"%s","fathomed");
- sprintf(reason,"%s %i %i",reason, node->bc_index+1,
- node->parent->bc_index+1);
- if (node->bc_index>0) {
- if (node->parent->children[0]==node) {
- branch_dir = node->parent->bobj.sense[0];
- /*branch_dir = 'L';*/
- } else {
- branch_dir = node->parent->bobj.sense[1];
- /*branch_dir = 'R';*/
- }
- if (branch_dir == 'G') {
- branch_dir = 'R';
- }
- }
- sprintf(reason,"%s %c %s", reason, branch_dir, "\…
Large files files are truncated, but you can click here to view the full file