📄 bbsubs.c
字号:
/*********************************************************************** File: bbsubs.c Rev: a-1 Date: 02/28/2001 Copyright (c) 1995, 2001 by David M. Warme************************************************************************ Low-level subtroutines of the branch-and-cut.************************************************************************ Modification Log: a-1: 02/28/2001 warme : Split off from bb.c. Changes for 3.1 release.************************************************************************/#include "bb.h"#include "bbsubs.h"#include "config.h"#include "constrnt.h"#include "steiner.h"#include "ub.h"/* * Global Routines */void add_bbnode (struct bbinfo *, int, int, double);void append_node_to_tree (struct bbnode *, struct bbtree *);void bbheap_insert (struct bbnode *, struct bbtree *, int);struct bbtree * create_bbtree (int);void delete_node_from_bbtree (struct bbnode *, struct bbtree *);void destroy_bbinfo (struct bbinfo *);void shutdown_lp_solver (void);void startup_lp_solver (void);#if defined(CPLEX) #if CPLEX >= 40 CPXENVptr cplex_env; #endif#endif/* * Local Routines */static void bbheap_delete (struct bbnode *, struct bbtree *, int);static void bbheap_free (struct bbheap *);static void bbheap_init (struct bbheap *, bbheap_func_t *);static void destroy_bbnode (struct bbnode *);static int node_is_better (struct bbnode *, struct bbnode *);static int node_is_worse (struct bbnode *, struct bbnode *);#ifdef CPLEXstatic void startup_cplex (void);#endif/* * This routine does everything needed to start up whichever * LP solver we are using. */ voidstartup_lp_solver (void){#ifdef CPLEX startup_cplex ();#endif /* Nothing for lp_solve... */}/* * This routine does everything needed to shut down whichever * LP solver we are using. */ voidshutdown_lp_solver (void){#if defined (CPLEX) AND (CPLEX >= 40) /* Shut down CPLEX... */ if (CPXcloseCPLEX (&cplex_env) NE 0) { fprintf (stderr, "Warning: Unable to close CPLEX.\n"); }#endif /* Nothing for lp_solve... */}/* * This routine performs everything needed to start up the * newer versions of CPLEX. */#if defined(CPLEX) AND (CPLEX >= 40) static voidstartup_cplex (void){int status;FILE * fp;CPXCHANNELptr _res, _warn, _error, _log;char msg [512];#ifdef HAVE_STDERR_IS_LVALUE { FILE * esave; /* Flush the #@!$% CPLEX startup banner! */ esave = stderr; stderr = fopen ("/dev/null", "w");#endif cplex_env = _MYCPX_openCPLEX (&status);#ifdef HAVE_STDERR_IS_LVALUE /* Undo flushing of stderr... */ fp = stderr; stderr = esave; fclose (fp); }#endif if (cplex_env EQ NULL) { if (CPXgeterrorstring (NULL, status, msg) EQ NULL) { strcpy (msg, "No CPLEX error message."); } fprintf (stderr, "%s\n", msg); goto shutdown; } /* Get rid of CPLEX's default message destinations. */ CPXgetchannels (cplex_env, &_res, &_warn, &_error, &_log); CPXdisconnectchannel (cplex_env, _res); CPXdisconnectchannel (cplex_env, _warn); CPXdisconnectchannel (cplex_env, _error); CPXdisconnectchannel (cplex_env, _log); CPXsetintparam (cplex_env, CPX_PARAM_SCRIND, 0); fp = fopen ("cplex.log", "a"); if (fp EQ NULL) { perror ("cplex.log"); goto shutdown; } /* Send all log stuff to the cplex.log file. */ CPXsetlogfile (cplex_env, fp); /* But discard the results stuff... */ CPXdisconnectchannel (cplex_env, _res); /* CPLEX is now ready to roll! */ return; /* Something didn't work -- shut down CPLEX and get out. */shutdown: CPXcloseCPLEX (&cplex_env); exit (1);}#endif/* * This routine performs everything needed to start up older * versions of CPLEX. */#if defined(CPLEX) AND (CPLEX < 40) static voidstartup_cplex (void){ /* Older CPLEX library isn't as noisy! */ _MYCPX_setlogfile (stderr);}#endif/* * This routine adds a new node to the branch-and-bound tree. */ voidadd_bbnode (struct bbinfo * bbip, /* IN - branch-and-bound info */int var, /* IN - variable to branch on */int dir, /* IN - branch direction */double z /* IN - value to give to node */){int i;int j;int n;int nedges;int nmasks;struct bbnode * parent;struct bbtree * tp;struct bbnode * p;struct bbnode * p1;struct bbnode * p2;struct bbnode ** tmp1;struct bbnode ** tmp2; if (z >= bbip -> best_z) { /* Node is already worse than the cutoff value! */ /* Don't bother adding it to the tree! */ return; } parent = bbip -> node; /* current node becomes parent */ tp = bbip -> bbtree; /* tree to insert in */ tracef (" %% @NC %4d %4d x%d = %d %f\n", tp -> snum, parent -> num, var, dir, z); nmasks = tp -> nmasks; nedges = bbip -> cip -> num_edges; /* Get a new tree node... */ p = tp -> free; if (p NE NULL) { tp -> free = p -> next; } else { p = NEW (struct bbnode); p -> x = NEWA (nedges, double); p -> zlb = NEWA (2 * nedges, double); p -> fixed = NEWA (nmasks, bitmap_t); p -> value = NEWA (nmasks, bitmap_t); p -> bheur = NEWA (nedges, double); } p -> z = z; p -> optimal = FALSE; p -> num = (tp -> snum)++; p -> iter = 0; p -> parent = parent -> num; p -> var = var; p -> dir = dir; p -> depth = 1 + parent -> depth; if (dir EQ 0) { p -> br1cnt = parent -> br1cnt; } else { p -> br1cnt = parent -> br1cnt + 1; } p -> cpiter = -1; /* force re-solve of LP. */ /* Get most up-to-date fixed variables... */ for (i = 0; i < nmasks; i++) { p -> fixed [i] = bbip -> fixed [i]; p -> value [i] = bbip -> value [i]; } SETBIT (p -> fixed, var); if (dir EQ 0) { CLRBIT (p -> value, var); } else { SETBIT (p -> value, var); } p -> n_uids = 0; p -> bc_uids = NULL; p -> bc_row = NULL; p -> rstat = NULL; p -> cstat = NULL; /* Copy parent's LP solution, etc. */ memcpy (p -> x, parent -> x, nedges * sizeof (p -> x [0])); memcpy (p -> zlb, parent -> zlb, nedges * (2 * sizeof (p -> zlb [0]))); memcpy (p -> bheur, parent -> bheur, nedges * sizeof (p -> bheur [0])); /* Save the current basis (actually the parent's basis) */ /* into this node. */ save_node_basis (p, bbip); /* Insert node into depth-first list... */ p1 = tp -> first; if (p1 NE NULL) { p1 -> prev = p; } p -> next = p1; p -> prev = NULL; tp -> first = p; /* Insert node into "best-node" heap... */ bbheap_insert (p, tp, BEST_NODE_HEAP); /* Insert node into "worst-node" heap... */ bbheap_insert (p, tp, WORST_NODE_HEAP);}/* * Append the given branch-and-bound node to the given tree. It is added * to the END of the node list, and sorted into each of the heaps. */ voidappend_node_to_tree (struct bbnode * p, /* IN - node to append to tree */struct bbtree * tp /* IN - tree to append it to */){struct bbnode * p1; p1 = tp -> first; if (p1 EQ NULL) { tp -> first = p; } else { while (p1 -> next NE NULL) { p1 = p1 -> next; } p1 -> next = p; } p -> next = NULL; p -> prev = p1; bbheap_insert (p, tp, BEST_NODE_HEAP); bbheap_insert (p, tp, WORST_NODE_HEAP);}/* * This routine deletes an arbitrary node from an arbitrary position * within the given branch-and-bound tree. */ voiddelete_node_from_bbtree (struct bbnode * p, /* IN - node to delete */struct bbtree * tp /* IN - tree to delete it from */){struct bbnode * p1;struct bbnode * p2; /* Delete it from LIFO list... */ p1 = p -> prev; p2 = p -> next; if (p1 NE NULL) { p1 -> next = p2; } else { tp -> first = p2; } if (p2 NE NULL) { p2 -> prev = p1; } p -> next = NULL; p -> prev = NULL; /* Delete it from the best-node heap... */ bbheap_delete (p, tp, BEST_NODE_HEAP); /* Delete it from the worst-node heap... */ bbheap_delete (p, tp, WORST_NODE_HEAP);}/* * This routine creates an initial, empty branch-and-bound tree. */ struct bbtree *create_bbtree (int nmasks /* IN - number of edge masks */){struct bbtree * tp; tp = NEW (struct bbtree); tp -> first = NULL; tp -> free = NULL; tp -> snum = 0; tp -> nmasks = nmasks; tp -> node_policy = NN_BEST_NODE; /* Initialize best and worst order heaps */ bbheap_init (&(tp -> heap [BEST_NODE_HEAP]), node_is_better); bbheap_init (&(tp -> heap [WORST_NODE_HEAP]), node_is_worse); return (tp);}/* * This routine initializes a branch-and-bound node heap. */ static voidbbheap_init (struct bbheap * hp, /* IN - the heap to initialize */bbheap_func_t * funcp /* IN - node comparison function */){ hp -> array = NEWA (INIT_HSIZE, struct bbnode *); hp -> hsize = INIT_HSIZE; hp -> nheap = 0; hp -> is_parent_funcp = funcp;} static voidbbheap_free (struct bbheap * hp /* IN - heap to free up */){int i; for (i = 0; i < hp -> nheap; i++) { destroy_bbnode (hp -> array [i]); } free ((char *) (hp -> array));}/* * This routine adds the given branch-and-bound node to the specified * heap of the given branch-and-bound tree. */ voidbbheap_insert (struct bbnode * p, /* IN - node to insert */struct bbtree * tp, /* IN - branch-and-bound tree with heaps */int heap_no /* IN - heap number to insert node into */){int i;int j;int n;struct bbheap * hp;struct bbnode ** tmp;struct bbnode * p2;bbheap_func_t * is_parent; /* Use specified heap... */ hp = &(tp -> heap [heap_no]); /* Verify sufficient heap space to hold new node... */ n = hp -> nheap; if (n >= hp -> hsize) { tmp = NEWA (2 * n, struct bbnode *); for (i = 0; i < n; i++) { tmp [i] = hp -> array [i]; } free ((char *) (hp -> array)); hp -> array = tmp; hp -> hsize = 2 * n; } is_parent = hp -> is_parent_funcp; /* Insert node into heap by placing it at the end of */ /* the array and sifting up... */ for (i = n; i > 0;) { j = ((i - 1) >> 1); p2 = hp -> array [j]; if (is_parent (p2, p)) break; p2 -> index [heap_no] = i; hp -> array [i] = p2; i = j; } p -> index [heap_no] = i; hp -> array [i] = p; hp -> nheap = n + 1;}/* * This routine deletes a single node from the specified heap of the * given branch-and-bound tree. */ static voidbbheap_delete (struct bbnode * p, /* IN - the node to delete from the heap */struct bbtree * tp, /* IN - branch-and-bound tree with heaps */int heap_no /* IN - heap number from which to delete */){int i;int j;int n;struct bbheap * hp;struct bbnode * p1;struct bbnode * p2;struct bbnode * p3;bbheap_func_t * is_parent; /* Use proper heap to delete from... */ hp = &(tp -> heap [heap_no]); n = hp -> nheap; if ((n <= 0) OR (n > hp -> hsize)) { fatal ("delete_bbheap: Bug 1."); } /* Deleting from a heap requires three steps: */ /* 1. Move the last node into the deleted node's */ /* current position. */ /* 2. Sift this replacement node up. */ /* 3. Sift this replacement node down. */ /* Get position of node being deleted... */ i = p -> index [heap_no]; if (i >= n) { fatal ("delete_bbheap: Bug 2."); } if (hp -> array [i] NE p) { fatal ("delete_bbheap: Bug 3."); } /* Deleted node is no longer in the array... */ p -> index [heap_no] = -1; /* Heap now has one fewer element in it... */ --n; hp -> nheap = n; if (n <= 0) { /* Heap is now empty -- done! */ return; } /* Move last heap element into vacated spot. */ p1 = hp -> array [n]; if (p1 EQ p) { /* Deleting last item from heap -- we are done! */ return; } if (p1 -> index [heap_no] NE n) { fatal ("delete_bbheap: Bug 4."); } /* We now assume that node "p1" will be in position "i"... */ is_parent = hp -> is_parent_funcp; /* First sift up... */ while (i > 0) { j = ((i - 1) >> 1); p2 = hp -> array [j]; if (is_parent (p2, p1)) break; p2 -> index [heap_no] = i; hp -> array [i] = p2; i = j; } /* Now sift down... */ while (i < n) { j = (i << 1) + 1; if (j >= n) break; p2 = hp -> array [j]; if ((j + 1) < n) { p3 = hp -> array [j + 1]; if (is_parent (p3, p2)) { ++j; p2 = p3; } } if (is_parent (p1, p2)) break; p2 -> index [heap_no] = i; hp -> array [i] = p2; i = j; } p1 -> index [heap_no] = i; hp -> array [i] = p1; hp -> nheap = n;}/* * This routine returns TRUE if-and-only-if node 1 is "better" than * node 2 -- in other words, node 1 must be above node 2 in the * "best-node" heap. */ static intnode_is_better (struct bbnode * p1, /* IN - node 1 */struct bbnode * p2 /* IN - node 2 */){ if (p1 -> z < p2 -> z) return (TRUE); if (p1 -> z > p2 -> z) return (FALSE); /* Objective values are equal -- use node creation */ /* order to break the tie. What we want to achieve is */ /* that the "var=0" and "var=1" children of a node */ /* (which will have equal objective values) get taken */ /* from the "best-node" heap in proper order with */ /* respect to the UP_FIRST switch. (The node that was */ /* created last should be taken from the heap first.) */ if (p1 -> num >= p2 -> num) return (TRUE); return (FALSE);}/* * This routine returns TRUE if-and-only-if node 1 is "worse" than * node 2 -- in other words, node 2 must be above node 2 in the * "worst-node" heap. */ static intnode_is_worse (struct bbnode * p1, /* IN - node 1 */struct bbnode * p2 /* IN - node 2 */){ return (p1 -> z >= p2 -> z);}/* * This routine destroys the given branch-and-bound info structure, * freeing all of the memory it points to. */ voiddestroy_bbinfo (struct bbinfo * bbip /* IN - branch-and-bound info */){struct bbtree * bbtree;struct bbnode * p1;struct bbnode * p2; shutdown_heuristic_upper_bound (bbip -> ubip); if (bbip -> statp NE NULL) { free ((char *) (bbip -> statp)); } bbip -> value = NULL; bbip -> fixed = NULL; free ((char *) (bbip -> dj)); if (bbip -> slack NE NULL) { free ((char *) (bbip -> slack)); } bbip -> node = NULL; free ((char *) (bbip -> smt)); bbtree = bbip -> bbtree; if (bbtree NE NULL) { p1 = bbtree -> free; for (;;) { if (p1 EQ NULL) break; p2 = p1 -> next; destroy_bbnode (p1); p1 = p2; } bbtree -> first = NULL; bbtree -> free = NULL; bbheap_free (&(bbtree -> heap [BEST_NODE_HEAP])); bbheap_free (&(bbtree -> heap [WORST_NODE_HEAP])); free ((char *) bbtree); } if (bbip -> cpool NE NULL) { free_constraint_pool (bbip -> cpool); } if (bbip -> lp NE NULL) { destroy_initial_formulation (bbip); } if (bbip -> lpmem NE NULL) { free ((char *) (bbip -> lpmem)); } /* This items all belong to the cinfo. Just zap them. */ bbip -> cip = NULL; bbip -> tmap = NULL; bbip -> fset_mask = NULL; free ((char *) bbip);}/* * Destroy the given branch-and-bound node, freeing all of the memory * it refers to. */ static voiddestroy_bbnode (struct bbnode * p /* IN - node to destroy */){ free ((char *) (p -> fixed)); free ((char *) (p -> value)); if (p -> x NE NULL) { free ((char *) (p -> x)); } if (p -> zlb NE NULL) { free ((char *) (p -> zlb)); } if (p -> bc_uids NE NULL) { free ((char *) (p -> bc_uids)); } if (p -> bc_row NE NULL) { free ((char *) (p -> bc_row)); } if (p -> rstat NE NULL) { free ((char *) (p -> rstat)); } if (p -> cstat NE NULL) { free ((char *) (p -> cstat)); } free ((char *) (p -> bheur)); free ((char *) p);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -