www.pudn.com > geosteiner-3.1.zip > 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 CPLEX
static void startup_cplex (void);
#endif
/*
* This routine does everything needed to start up whichever
* LP solver we are using.
*/
void
startup_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.
*/
void
shutdown_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
void
startup_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
void
startup_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.
*/
void
add_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.
*/
void
append_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.
*/
void
delete_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
void
bbheap_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
void
bbheap_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.
*/
void
bbheap_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
void
bbheap_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
int
node_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
int
node_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.
*/
void
destroy_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
void
destroy_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);
}