// ***********************************************************************
// *** COPYRIGHT NOTICE **************************************************
// rbtree - red-black tree (self-balancing binary tree data structure)
// Copyright (C) 2004 Aaron Clauset
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 
// See http://www.gnu.org/licenses/gpl.txt for more details.
// 
// ***********************************************************************
// Author       : Aaron Clauset  ( aaronc@santafe.edu |
//                                 http://www.santafe.edu/~aaronc/ ) 
// Collaborators: Cristopher Moore and Mark Newman
// Project      : Hierarchical Random Graphs
// Location     : University of New Mexico, Dept. of Computer Science
//                AND Santa Fe Institute 
// Created      : Spring 2004
// Modified     : many, many times
//
// ***********************************************************************

#include "hrg_rbtree.h"
#include "hrg_dendro.h"
#include "hrg_graph.h"
#include "hrg_splittree_eq.h"
#include "hrg_graph_simp.h"

#include "igraph_hrg.h"
#include "igraph_constructors.h"
#include "igraph_random.h"

using namespace fitHRG;

// ******** Red-Black Tree Methods ***************************************

rbtree::rbtree() {
  root = new elementrb;
  leaf = new elementrb;

  leaf->parent = root;
  
  root->left = leaf;
  root->right = leaf;
  support = 0;
}

rbtree::~rbtree() {
  if (root != NULL && 
      (root->left != leaf || root->right != leaf)) { 
    deleteSubTree(root); 
  }
  if (root) delete root;
  delete leaf;
  support = 0;
  root = 0;
  leaf = 0;
}

void rbtree::deleteTree() { 
  if (root != NULL) { deleteSubTree(root); }
} // does not leak memory

void rbtree::deleteSubTree(elementrb *z) {
  if (z->left  != leaf) { deleteSubTree(z->left);  }
  if (z->right != leaf) { deleteSubTree(z->right); }
  delete z;
}

// ******** Search Functions *********************************************
// public search function - if there exists a elementrb in the tree
// with key=searchKey, it returns TRUE and foundNode is set to point
// to the found node; otherwise, it sets foundNode=NULL and returns
// FALSE
elementrb* rbtree::findItem(const int searchKey) {
  elementrb *current=root;

  // empty tree; bail out
  if (current->key==-1) { return NULL; }

  while (current != leaf) {
    // left-or-right?
    if (searchKey < current->key) {
      // try moving down-left
      if (current->left  != leaf) { 
	current = current->left;  
      } else { 
	//   failure; bail out
	return NULL; 
      }	
    } else {
      // left-or-right?
      if (searchKey > current->key) {
	// try moving down-left
	if (current->right  != leaf) { 
	  current = current->right;  
	} else { 
	  // failure; bail out
	  return NULL; 
	}
      } else { 
	// found (searchKey==current->key)
	return current; 
      }
    }
  }
  return NULL;
}

int rbtree::returnValue(const int searchKey) {
  elementrb* test = findItem(searchKey);
  if (!test) { return 0; } else { return test->value; }
}


// ******** Return Item Functions ****************************************

int* rbtree::returnArrayOfKeys() {
  int* array;
  array = new int [support];
  bool flag_go = true;
  int index = 0;
  elementrb *curr;

  if (support == 1) { 
    array[0] = root->key; 
  } else if (support == 2) {
    array[0] = root->key;
    if (root->left == leaf) { 
      array[1] = root->right->key; 
    } else { 
      array[1] = root->left->key; 
    }
  } else {
    for (int i=0; i<support; i++) { array[i] = -1; }
    // non-recursive traversal of tree structure
    curr = root;
    curr->mark = 1;
    while (flag_go) {
      // - is it time, and is left child the leaf node?
      if (curr->mark == 1 && curr->left == leaf) {
	curr->mark = 2;	
      }
      // - is it time, and is right child the leaf node?
      if (curr->mark == 2 && curr->right == leaf) {
	curr->mark = 3;	
      }
      if (curr->mark == 1) {
	// - go left
	curr->mark = 2;
	curr = curr->left;
	curr->mark = 1;
      } else if (curr->mark == 2) {
	// - else go right
	curr->mark = 3;
	curr = curr->right;
	curr->mark = 1;
      } else {
	// - else go up a level
	curr->mark = 0;
	array[index++] = curr->key;
	curr = curr->parent;
	if (curr == NULL) { flag_go = false; }
      }
    }
  }
	
  return array;
}

list* rbtree::returnListOfKeys() {
  keyValuePair *curr, *prev;
  list *head=0, *tail=0, *newlist;

  curr = returnTreeAsList();
  while (curr != NULL) {
    newlist = new list;
    newlist->x = curr->x;
    if (head == NULL) { 
      head       = newlist; tail = head;    
    } else { 
      tail->next = newlist; tail = newlist; 
    }
    prev = curr;
    curr = curr->next;
    delete prev;
    prev = NULL;
  }
  return head;
}

keyValuePair* rbtree::returnTreeAsList() {
  // pre-order traversal
  keyValuePair  *head, *tail;

  head = new keyValuePair;
  head->x = root->key;
  head->y = root->value;
  tail = head;
  
  if (root->left  != leaf) { tail = returnSubtreeAsList(root->left,  tail); }
  if (root->right != leaf) { tail = returnSubtreeAsList(root->right, tail); }
  
  if (head->x == -1) { return NULL; /* empty tree */ } else { return head; }
}

keyValuePair* rbtree::returnSubtreeAsList(elementrb *z, keyValuePair *head) {
  keyValuePair *newnode, *tail;
	
  newnode = new keyValuePair;
  newnode->x = z->key;
  newnode->y = z->value;
  head->next = newnode;
  tail = newnode;
	
  if (z->left  != leaf) { tail = returnSubtreeAsList(z->left,  tail); }
  if (z->right != leaf) { tail = returnSubtreeAsList(z->right, tail); }
	
  return tail;
}

keyValuePair rbtree::returnMaxKey() {
  keyValuePair themax;
  elementrb *current;
  current  = root;

  // search to bottom-right corner of tree
  while (current->right != leaf) { 
    current  = current->right; 
  }
  themax.x = current->key;
  themax.y = current->value;

  return themax;
}

keyValuePair rbtree::returnMinKey() {
  keyValuePair themin;
  elementrb *current;
  current = root;
  // search to bottom-left corner of tree
  while (current->left != leaf) {
    current = current->left; 
  }
  themin.x = current->key;
  themin.y = current->value;
  
  return themin;
}

// private functions for deleteItem() (although these could easily be
// made public, I suppose) 
elementrb* rbtree::returnMinKey(elementrb *z) {
  elementrb *current;

  current = z;
  // search to bottom-right corner of tree
  while (current->left != leaf) {
		current = current->left; 
  }
  return current;
}

elementrb* rbtree::returnSuccessor(elementrb *z) {
  elementrb *current, *w;
	
  w = z;
  // if right-subtree exists, return min of it
  if (w->right != leaf) {
    return returnMinKey(w->right); 
  }
  // else search up in tree
  current = w->parent;
  while ((current!=NULL) && (w==current->right)) {
    w = current;
    // move up in tree until find a non-right-child
    current = current->parent;
  }
  return current;
}

int rbtree::returnNodecount() { return support; }

// ******** Insert Functions *********************************************
// public insert function
void rbtree::insertItem(int newKey, int newValue) {
	
  // first we check to see if newKey is already present in the tree;
  // if so, we do nothing; if not, we must find where to insert the
  // key
  elementrb *newNode, *current;

  // find newKey in tree; return pointer to it O(log k)
  current = findItem(newKey);
  if (current == NULL) {
    newNode = new elementrb;    // elementrb for the rbtree
    newNode->key = newKey;
    newNode->value = newValue;
    newNode->color = true;	// new nodes are always RED
    newNode->parent = NULL;	// new node initially has no parent
    newNode->left = leaf;	// left leaf
    newNode->right = leaf;	// right leaf
    support++;			// increment node count in rbtree
		
    // must now search for where to insert newNode, i.e., find the
    // correct parent and set the parent and child to point to each
    // other properly
    current = root;
    if (current->key==-1) {	     // insert as root
      delete root;		     // delete old root
      root = newNode;		     // set root to newNode
      leaf->parent = newNode;	     // set leaf's parent
      current = leaf;		     // skip next loop
    }
		
    // search for insertion point
    while (current != leaf) {
      // left-or-right?
      if (newKey < current->key) {
	// try moving down-left
	if (current->left  != leaf) { 
	  current = current->left;  
	} else {
	  // else found new parent
	  newNode->parent = current; // set parent
	  current->left = newNode;   // set child
	  current = leaf;	     // exit search
	}
      } else {
	// try moving down-right
	if (current->right != leaf) { 
	  current = current->right; 
	} else {
	  // else found new parent
	  newNode->parent = current; // set parent
	  current->right = newNode;  // set child
	  current = leaf;	     // exit search
	}
      }
    }

    // now do the house-keeping necessary to preserve the red-black
    // properties 
    insertCleanup(newNode);
  }
  return;
}

// private house-keeping function for insertion
void rbtree::insertCleanup(elementrb *z) {
	
  // fix now if z is root
  if (z->parent==NULL) {
    z->color = false; 
    return; 
  }

  elementrb *temp;

  // while z is not root and z's parent is RED
  while (z->parent!=NULL && z->parent->color) {
    if (z->parent == z->parent->parent->left) {

      // z's parent is LEFT-CHILD

      temp = z->parent->parent->right;   // grab z's uncle
      if (temp->color) {
	z->parent->color = false;        // color z's parent BLACK  (Case 1)
	temp->color = false;             // color z's uncle BLACK   (Case 1)
	z->parent->parent->color = true; // color z's grandpar. RED (Case 1)
	z = z->parent->parent;	         // set z = z's grandparent (Case 1)
      } else {
	if (z == z->parent->right) {
	  // z is RIGHT-CHILD
	  z = z->parent;	         // set z = z's parent      (Case 2)
	  rotateLeft(z);	         // perform left-rotation   (Case 2)
	}
	z->parent->color = false;        // color z's parent BLACK  (Case 3)
	z->parent->parent->color = true; // color z's grandpar. RED (Case 3)
	rotateRight(z->parent->parent);  // perform right-rotation  (Case 3)
      }
    } else {

      // z's parent is RIGHT-CHILD      

      temp = z->parent->parent->left;    // grab z's uncle
      if (temp->color) {
	z->parent->color = false;        // color z's parent BLACK  (Case 1)
	temp->color = false;	         // color z's uncle BLACK   (Case 1)
	z->parent->parent->color = true; // color z's grandpar. RED (Case 1)
	z = z->parent->parent;	         // set z = z's grandparent (Case 1)
      } else {
	if (z == z->parent->left) { 
	  // z is LEFT-CHILD
	  z = z->parent;                 // set z = z's parent      (Case 2)
	  rotateRight(z);                // perform right-rotation  (Case 2)
	}
	z->parent->color = false;        // color z's parent BLACK  (Case 3)
	z->parent->parent->color = true; // color z's grandpar. RED (Case 3)
	rotateLeft(z->parent->parent);	 // perform left-rotation   (Case 3)
      }
    }
  }

  root->color = false;		         // color the root BLACK
  return;
}

// ******** Delete
// ******** Functions *********************************************

void rbtree::replaceItem(int key, int newValue) {
  elementrb* ptr;
  ptr = findItem(key);
  ptr->value = newValue;
  return;
}
 
void rbtree::incrementValue(int key) {
  elementrb* ptr;
  ptr = findItem(key);
  ptr->value = 1+ptr->value;
  return;
}

// public delete function
void rbtree::deleteItem(int killKey) {
  elementrb *x, *y, *z;
	
  z = findItem(killKey);
  if (z == NULL) { return; } 	  // item not present; bail out

  if (support==1) {		  // attempt to delete the root
    root->key = -1;		  // restore root node to default state
    root->value = -1;
    root->color = false;
    root->parent = NULL;
    root->left = leaf;
    root->right = leaf;
    support--;			  // set support to zero
    return;			  // exit - no more work to do
  }
	
  if (z != NULL) {
    support--;		 	  // decrement node count
    if ((z->left == leaf) || (z->right==leaf)) {
      y = z;	                  // case of less than two children, 
				  // set y to be z
    } else { 
      y = returnSuccessor(z);  	  // set y to be z's key-successor
    } 

    if (y->left!=leaf) {
      x = y->left;		  // pick y's one child (left-child)
    } else { 
      x = y->right;	  	  // (right-child)
    }
    x->parent = y->parent;        // make y's child's parent be y's parent

    if (y->parent==NULL) { 
      root = x;			  // if y is the root, x is now root
    } else {
      if (y == y->parent->left) { // decide y's relationship with y's parent
	y->parent->left  = x;     // replace x as y's parent's left child
      } else {
	y->parent->right = x;     // replace x as y's parent's left child
      }
    }

    if (y!=z) {			  // insert y into z's spot
      z->key = y->key;		  // copy y data into z
      z->value = y->value;
    }

    // do house-keeping to maintain balance
    if (y->color==false) { deleteCleanup(x); }

    delete y;
    y = NULL;
  }
		
  return;
}

void rbtree::deleteCleanup(elementrb *x) {
  elementrb *w, *t;
  
  // until x is the root, or x is RED
  while ((x != root) && (x->color==false)) {
    if (x==x->parent->left) {	  // branch on x being a LEFT-CHILD
      w = x->parent->right;	  // grab x's sibling
      if (w->color==true) {	  // if x's sibling is RED
	w->color = false;	  // color w BLACK (case 1)
	x->parent->color = true;  // color x's parent RED            (case 1)
	rotateLeft(x->parent);    // left rotation on x's parent     (case 1)
	w = x->parent->right;     // make w be x's right sibling     (case 1)
      }
      if ((w->left->color==false) && (w->right->color==false)) {
	w->color = true;	  // color w RED                     (case 2)
	x = x->parent;		  // examine x's parent              (case 2)
      } else {
	if (w->right->color==false) {
	  w->left->color = false; // color w's left child BLACK	     (case 3)
	  w->color = true;	  // color w RED                     (case 3)
	  t = x->parent;	  // store x's parent                (case 3)
	  rotateRight(w);	  // right rotation on w             (case 3)
	  x->parent = t;	  // restore x's parent              (case 3)
	  w = x->parent->right;	  // make w be x's right sibling     (case 3)
	}
	w->color = x->parent->color; // w's color := x's parent's    (case 4)
	x->parent->color = false; // color x's parent BLACK          (case 4)
	w->right->color	= false;  // color w's right child BLACK     (case 4)
	rotateLeft(x->parent);    // left rotation on x's parent     (case 4)
	x = root;                 // finished work. bail out         (case 4)
      }
    } else {			    // x is RIGHT-CHILD
      w = x->parent->left;	    // grab x's sibling
      if (w->color==true) {	    // if x's sibling is RED
	w->color = false;	    // color w BLACK                 (case 1)
	x->parent->color    = true; // color x's parent RED          (case 1)
	rotateRight(x->parent);	    // right rotation on x's parent  (case 1)
	w = x->parent->left;        // make w be x's left sibling    (case 1)
      }
      if ((w->right->color==false) && (w->left->color==false)) {
	w->color = true;	    // color w RED                   (case 2)
	x= x->parent;		    // examine x's parent            (case 2)
      } else {
	if (w->left->color==false) {
	  w->right->color = false;  // color w's right child BLACK   (case 3)
	  w->color = true;	    // color w RED                   (case 3)
	  t = x->parent;	    // store x's parent              (case 3)
	  rotateLeft(w);	    // left rotation on w            (case 3)
	  x->parent = t;	    // restore x's parent            (case 3)
	  w = x->parent->left;	    // make w be x's left sibling    (case 3)
	}
	w->color = x->parent->color; // w's color := x's parent's    (case 4)
	x->parent->color    = false; // color x's parent BLACK       (case 4)
	w->left->color = false;      // color w's left child BLACK   (case 4)
	rotateRight(x->parent);      // right rotation on x's parent (case 4)
	x = root;		     // x is now the root            (case 4)
      }
    }
  }
  x->color = false;		     // color x (the root) BLACK (exit)

  return;
}

// ******** Rotation Functions ******************************************

void rbtree::rotateLeft(elementrb *x) {
  elementrb *y;
  // do pointer-swapping operations for left-rotation
  y = x->right;		     // grab right child
  x->right = y->left;	     // make x's RIGHT-CHILD be y's LEFT-CHILD
  y->left->parent = x;	     // make x be y's LEFT-CHILD's parent
  y->parent = x->parent;     // make y's new parent be x's old parent

  if (x->parent==NULL) { 
    root = y;			// if x was root, make y root
  } else {
    // if x is LEFT-CHILD, make y be x's parent's
    if (x == x->parent->left) { 
      x->parent->left  = y;	// left-child
    } else { 
      x->parent->right = y;	//  right-child
    }
  }
  y->left   = x;		// make x be y's LEFT-CHILD
  x->parent = y;		// make y be x's parent
 
  return;
}

void rbtree::rotateRight(elementrb *y) {
  elementrb *x;
  // do pointer-swapping operations for right-rotation
  x = y->left;		  // grab left child
  y->left = x->right;	  // replace left child yith x's right subtree
  x->right->parent = y;	  // replace y as x's right subtree's parent
 
  x->parent = y->parent;  // make x's new parent be y's old parent

  // if y was root, make x root
  if (y->parent==NULL) { 
    root = x; 
  } else {
    // if y is RIGHT-CHILD, make x be y's parent's
    if (y == y->parent->right) {
      // right-child
      y->parent->right = x; 
    } else { 
      // left-child
      y->parent->left = x; 
    }
  }
  x->right  = y;		// make y be x's RIGHT-CHILD
  y->parent = x;		// make x be y's parent
 
  return;
}

// ***********************************************************************
// *** COPYRIGHT NOTICE **************************************************
// dendro.h - hierarchical random graph (hrg) data structure
// Copyright (C) 2005-2009 Aaron Clauset
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 
// See http://www.gnu.org/licenses/gpl.txt for more details.
// 
// ***********************************************************************
// Author       : Aaron Clauset  ( aaronc@santafe.edu |
//                                 http://www.santafe.edu/~aaronc/ ) 
// Collaborators: Cristopher Moore and Mark E.J. Newman
// Project      : Hierarchical Random Graphs
// Location     : University of New Mexico, Dept. of Computer Science
//                AND Santa Fe Institute 
// Created      : 26 October 2005 - 7 December 2005
// Modified     : 23 December 2007 (cleaned up for public consumption)
//
// ***********************************************************************
// 
// Maximum likelihood dendrogram data structure. This is the heart of
// the HRG algorithm: all manipulations are done here and all data is
// stored here. The data structure uses the separate graph data
// structure to store the basic adjacency information (in a
// dangerously mutable way).
// 
// ***********************************************************************

// ******** Dendrogram Methods *******************************************

dendro::dendro(): root(0), internal(0), leaf(0), d(0), splithist(0),
		  paths(0), ctree(0), cancestor(0), g(0) { }
dendro::~dendro() {
  list *curr, *prev;
  
  if (g)        { delete    g;         g        =0; } // O(m)
  if (internal) { delete [] internal;  internal =0; } // O(n)
  if (leaf)     { delete [] leaf;      leaf     =0; } // O(n)
  if (d)        { delete    d;         d        =0; } // O(n)
  if (splithist){ delete    splithist; splithist=0; } // potentially long

  if (paths) { 
    for (int i=0; i<n; i++) { 
      curr = paths[i]; 
      while (curr) { 
	prev = curr;   
	curr = curr->next;   
	delete prev;   
	prev = 0; 
      } 
      paths[i] = 0; 
    } 
    delete [] paths; 
  } 
  paths=0;

  if (ctree)    { delete [] ctree;     ctree     = 0; } // O(n)
  if (cancestor){ delete [] cancestor; cancestor = 0; } // O(n)
}

// *********************************************************************

void dendro::binarySearchInsert(elementd* x, elementd* y) {
  if (y->p < x->p) {		// go to left subtree
    if (x->L == NULL) {		// check if left subtree is empty
      x->L = y;			// make x left child
      y->M = x;			// make y parent of child
      return;
    } else { 
      binarySearchInsert(x->L, y); 
    }
  } else {			// go to right subtree
    if (x->R == NULL) {		// check if right subtree is empty
      x->R = y;			// make x right child
      y->M = x;			// make y parent of child
      return;
    } else { 
      binarySearchInsert(x->R, y); 
    }
  }
  return;
}

// **********************************************************************

list* dendro::binarySearchFind(const double v) {
  list *head = NULL, *tail = NULL, *newlist;
  elementd *current = root;
  bool flag_stopSearch = false;
 
  while (!flag_stopSearch) {	// continue until we're finished
    newlist    = new list;	// add this node to the path
    newlist->x = current->label;
    if (current == root) { 
      head = newlist; tail = head;    
    } else { 
      tail->next = newlist; tail = newlist; 
    }
    if (v < current->p) {	// now try left subtree
      if (current->L->type == GRAPH) { 
        flag_stopSearch = true;       
      } else { 
        current = current->L; 
      }
    } else {			// else try right subtree
      if (current->R->type == GRAPH) { 
        flag_stopSearch = true;       
      } else  { 
        current = current->R; 
      }
    }
  }
  return head;
}

// ***********************************************************************

string dendro::buildSplit(elementd* thisNode) {
  // A "split" is defined as the bipartition of vertices into the sets
  // of leaves below the internal vertex in the tree (denoted by "C"),
  // and those above it (denoted as "M"). For simplicity, we represent
  // this bipartition as a character string of length n, where the ith
  // character denotes the partition membership (C,M) of the ith leaf
  // node.

  bool flag_go = true;
  const short int k = 1+DENDRO+GRAPH;
  elementd* curr;
  split sp;

  sp.initializeSplit(n);      // default split string O(n)
 
  curr = thisNode;	      // - set start node as top this sub-tree
  curr->type = k+1;	      // - initialize in-order tree traversal
  while (flag_go) { 

    // - is it time, and is left child a graph node?
    if (curr->type == k+1 && curr->L->type == GRAPH) {
      sp.s[curr->L->index] = 'C'; // - mark this leaf
      curr->type = k+2;
    }

    // - is it time, and is right child a graph node?
    if (curr->type == k+2 && curr->R->type == GRAPH) {
      sp.s[curr->R->index] = 'C'; // - mark this leaf
      curr->type           = k+3;
    }
    if (curr->type == k+1) {	  // - go left
      curr->type = k+2;
      curr       = curr->L;
      curr->type = k+1; }
    else if (curr->type == k+2) { // - else go right
      curr->type = k+3;
      curr       = curr->R;
      curr->type = k+1; 
    } else {		  	  // - else go up a level
      curr->type = DENDRO;
      if (curr->index == thisNode->index || curr->M == NULL) { 
	flag_go = false; curr = NULL; 
      } else { 
	curr = curr->M; 
      }
    }
  }

  // any leaf that was not already marked must be in the remainder of
  // the tree
  for (int i=0; i<n; i++) { if (sp.s[i] != 'C') { sp.s[i] = 'M'; } }

  return sp.s;
}

// **********************************************************************

void dendro::buildDendrogram() {
 
  /* the initialization of the dendrogram structure goes like this: 
   * 1) we allocate space for the n-1 internal nodes of the
   *    dendrogram, and then the n leaf nodes 
   * 2) we build a random binary tree structure out of the internal
   *    nodes by assigning each a uniformly random value over [0,1] and
   *    then inserting it into the tree according to the  
   *    binary-search rule.
   * 3) next, we make a random permutation of the n leaf nodes and add
   *    them to the dendrogram D by replacing the emptpy spots in-order
   * 4) then, we compute the path from the root to each leaf and store
   *    that in each leaf (this is prep work for the next step)
   * 5) finally, we compute the values for nL, nR, e (and thus p) and
   *    the label for each internal node by allocating each of the m
   *    edges in g to the appropriate internal node 
   */
 
  // --- Initialization and memory allocation for data structures 
  // After allocating the memory for D and G, we need to mark the
  // nodes for G as being non-internal vertices, and then insert them
  // into a random binary tree structure. For simplicity, we make the
  // first internal node in the array the root.

  n = g->numNodes();		  // size of graph
  leaf = new elementd [n];	  // allocate memory for G, O(n)
  internal  = new elementd [n-1]; // allocate memory for D, O(n)
  d = new interns(n-2);	          // allocate memory for internal
				  // edges of D, O(n) 
  for (int i=0; i<n; i++) {	  // initialize leaf nodes
    leaf[i].type   = GRAPH;
    leaf[i].label  = i;
    leaf[i].index  = i;
    leaf[i].n = 1;
  }

 // initialize internal nodes
  root = &internal[0];
  root->label = 0;
  root->index = 0;
  root->p = RNG_UNIF01();

  // insert remaining internal vertices, O(n log n)
  for (int i=1; i<(n-1); i++) {
    internal[i].label = i;
    internal[i].index = i;
    internal[i].p = RNG_UNIF01();
    binarySearchInsert(root, &internal[i]);
  }
 
  // --- Hang leaf nodes off end of dendrogram O(n log n)
  // To impose this random hierarchical relationship on G, we first
  // take a random permutation of the leaf vertices and then replace
  // the NULLs at the bottom of the tree in-order with the leafs. As a
  // hack to ensure that we can find the leafs later using a binary
  // search, we assign each of them the p value of their parent,
  // perturbed slightly so as to preserve the binary search property.

  block* array; array = new block [n];
  for (int i=0; i<n; i++) { array[i].x = RNG_UNIF01();  array[i].y = i; }
  QsortMain(array, 0, n-1);

  int k=0;			// replace NULLs with leaf nodes, and
  for (int i=0; i<(n-1); i++) { // maintain binary search property, O(n)
    if (internal[i].L == NULL) {
      internal[i].L = &leaf[array[k].y];
      leaf[array[k].y].M = &internal[i];
      leaf[array[k++].y].p = internal[i].p - 0.0000000000001;
    }
    if (internal[i].R == NULL) {
      internal[i].R = &leaf[array[k].y];
      leaf[array[k].y].M = &internal[i];
      leaf[array[k++].y].p = internal[i].p + 0.0000000000001;
    }
  }
  delete [] array;

  // --- Compute the path from root -> leaf for each leaf O(n log n) 
  // Using the binary search property, we can find each leaf node in
  // O(log n) time. The binarySearchFind() function returns the list
  // of internal node indices that the search crossed, in the order of
  // root -> ... -> leaf, for use in the subsequent few operations.

  if (paths != NULL) { 
    list *curr, *prev; 
    for (int i=0; i<n; i++) { 
      curr = paths[i]; 
      while (curr != NULL) { 
	prev = curr;
	curr = curr->next;  
	delete prev;
	prev = NULL; 
      } 
      paths[i] = NULL; 
    } 
    delete [] paths; 
  }
  paths = NULL;
  paths = new list* [n];
  for (int i=0; i<n; i++) { paths[i] = binarySearchFind(leaf[i].p); }
 
  // --- Count e for each internal node O(m)
  // To count the number of edges that span the L and R subtrees for
  // each internal node, we use the path information we just
  // computed. Then, we loop over all edges in G and find the common
  // ancestor in D of the two endpoints and increment that internal
  // node's e count. This process takes O(m) time because in a roughly
  // balanced binary tree (given by our random dendrogram), the vast
  // majority of vertices take basically constant time to find their
  // common ancestor. Note that because our adjacency list is
  // symmetric, we overcount each e by a factor of 2, so we need to
  // correct this after.

  elementd* ancestor; edge* curr;
  for (int i=0; i<(n-1); i++) { internal[i].e = 0; internal[i].label = -1; }
  for (int i=0; i<n; i++) {
    curr = g->getNeighborList(i);
    while (curr != NULL) {
      ancestor = findCommonAncestor(paths, i, curr->x);
      ancestor->e += 1;
      curr = curr->next;
    }
  }
  for (int i=0; i<(n-1); i++) { internal[i].e /= 2; }   

  // --- Count n for each internal node O(n log n)
  // To tabulate the number of leafs in each subtree rooted at an
  // internal node, we use the path information computed above.
  for (int i=0; i<n; i++) {
    ancestor = &leaf[i];
    ancestor = ancestor->M;
    while (ancestor != NULL) {
      ancestor->n++;
      ancestor = ancestor->M;
    }
  }
 
  // --- Label all internal vertices O(n log n)
  // We want to label each internal vertex with the smallest leaf
  // index of its children. This will allow us to collapse many
  // leaf-orderings into a single dendrogram structure that is
  // independent of child-exhanges (since these have no impact on the
  // likelihood of the hierarchical structure). To do this, we loop
  // over the leaf vertices from smallest to largest and walk along
  // that leaf's path from the root. If we find an unlabeled internal
  // node, then we mark it with this leaf's index.

  for (int i=0; i<n; i++) {
    ancestor = &leaf[i];
    while (ancestor != NULL) {
      if (ancestor->label == -1 || ancestor->label > leaf[i].label) { 
	ancestor->label = leaf[i].label; 
      }
      ancestor = ancestor->M;
    }
  }
 
  // --- Exchange children to enforce order-property O(n)
  // We state that the order-property requires that an internal node's
  // label is the smallest index of its left subtree. The dendrogram
  // so far doesn't reflect this, so we need to step through each
  // internal vertex and make that adjustment (swapping nL and nR if
  // we make a change).

  elementd *tempe;
  for (int i=0; i<(n-1); i++) {
    if (internal[i].L->label > internal[i].label) {
      tempe = internal[i].L;
      internal[i].L = internal[i].R;
      internal[i].R = tempe;
    }
  }

  // --- Tabulate internal dendrogram edges O(n^2)
  // For the MCMC moves later on, we'll need to be able to choose,
  // uniformly at random, an internal edge of the dendrogram to
  // manipulate. There are always n-2 of them, and we can find them
  // simply by scanning across the internal vertices and observing
  // which have children that are also internal vertices. Note: very
  // important that the order property be enforced before this step is
  // taken; otherwise, the internal edges wont reflect the actual
  // dendrogram structure.
 
  for (int i=0; i<(n-1); i++) {
    if (internal[i].L->type == DENDRO) { 
      d->addEdge(i, internal[i].L->index, LEFT); 
    }
    if (internal[i].R->type == DENDRO) { 
      d->addEdge(i, internal[i].R->index, RIGHT); 
    }
  } 
 
  // --- Clear memory for paths O(n log n)
  // Now that we're finished using the paths, we need to deallocate
  // them manually.

  list *current, *previous;
  for (int i=0; i<n; i++) {
    current = paths[i];
    while (current) {
      previous = current; 
      current = current->next;
      delete previous;
      previous = NULL; 
    }
    paths[i] = NULL;
  }
  delete [] paths;
  paths = NULL;
 
  // --- Compute p_i for each internal node O(n)
  // Each internal node's p_i = e_i / (nL_i*nR_i), and now that we
  // have each of those pieces, we may calculate this value for each
  // internal node. Given these, we can then calculate the
  // log-likelihood of the entire dendrogram structure \log(L) =
  // \sum_{i=1}^{n} ( ( e_i \log[p_i] ) + ( (nL_i*nR_i - e_i)
  // \log[1-p_i] ) )

  L = 0.0; double dL;
  int nL_nR, ei;
  for (int i=0; i<(n-1); i++) {
    nL_nR = internal[i].L->n*internal[i].R->n;
    ei = internal[i].e;
    internal[i].p = (double)(ei) / (double)(nL_nR);
    if (ei == 0 || ei == nL_nR) { 
      dL = 0.0; 
    } else { 
      dL = ei * log(internal[i].p) + (nL_nR - ei) * log(1.0-internal[i].p); 
    }
    internal[i].logL = dL;
    L += dL;
  }
 
  for (int i=0; i<(n-1); i++) {
    if (internal[i].label > internal[i].L->label) {
      tempe = internal[i].L;
      internal[i].L = internal[i].R;
      internal[i].R = tempe;
    }
  }
 
  // Dendrogram is now built

  return;
}

// ***********************************************************************

void dendro::clearDendrograph() {
  // Clear out the memory and references used by the dendrograph
  // structure - this is  intended to be called just before an
  // importDendrogramStructure call so as to avoid memory leaks and
  // overwriting the references therein. 

  if (g        != NULL) { delete    g;        g        = NULL; } // O(m)
  if (leaf     != NULL) { delete [] leaf;     leaf     = NULL; } // O(n)
  if (internal != NULL) { delete [] internal; internal = NULL; } // O(n)
  if (d        != NULL) { delete    d;     d           = NULL; } // O(n)
  root = NULL;
 
  return;
}

// **********************************************************************

int dendro::computeEdgeCount(const int a, const short int atype, 
			     const int b, const short int btype) {
  // This function computes the number of edges that cross between the
  // subtree internal[a] and the subtree internal[b]. To do this, we
  // use an array A[1..n] integers which take values -1 if A[i] is in
  // the subtree defined by internal[a], +1 if A[i] is in the subtree
  // internal[b], and 0 otherwise. Taking the smaller of the two sets,
  // we then scan over the edges attached  to that set of vertices and
  // count the number of endpoints we see in the other set.
 
  bool flag_go    = true;
  int nA, nB;
  int         count = 0;
  const short int k = 1+DENDRO+GRAPH;

  elementd* curr;
 
  // First, we push the leaf nodes in the L and R subtrees into
  // balanced binary tree structures so that we can search them
  // quickly later on. 

  if (atype == GRAPH) {
    // default case, subtree A is size 1
    // insert single node as member of left subtree
    subtreeL.insertItem(a,-1);
    nA = 1; // 
  } else {
    // explore subtree A, O(|A|)
    curr  = &internal[a];
    curr->type = k+1;
    nA = 0;
    while (flag_go) {
      if (curr->index == internal[a].M->index) {
	internal[a].type = DENDRO;
	flag_go = false;
      } else {
	// - is it time, and is left child a graph node?
	if (curr->type == k+1 && curr->L->type == GRAPH) {
	  subtreeL.insertItem(curr->L->index, -1);
	  curr->type = k+2;
	  nA++;
	}
	// - is it time, and is right child a graph node?
	if (curr->type == k+2 && curr->R->type == GRAPH) {
	  subtreeL.insertItem(curr->R->index, -1);
	  curr->type = k+3;
	  nA++;
	}
	if (curr->type == k+1) {      // - go left
	  curr->type = k+2;
	  curr       = curr->L;
	  curr->type = k+1; }
	else if (curr->type == k+2) { // - else go right
	  curr->type = k+3;
	  curr       = curr->R;
	  curr->type = k+1; 
	} else {		      // - else go up a level
	  curr->type = DENDRO; 
	  curr       = curr->M;
	  if (curr == NULL) {
	    flag_go = false;
	  }
	}
      }
    }
  }
 
  if (btype == GRAPH) {
    // default case, subtree A is size 1
    // insert node as single member of right subtree
    subtreeR.insertItem(b,1);
    nB = 1;
  } else {
    flag_go = true;
    // explore subtree B, O(|B|)
    curr = &internal[b];
    curr->type = k+1;
    nB  = 0;
    while (flag_go) {
      if (curr->index == internal[b].M->index) {
	internal[b].type = DENDRO;
	flag_go = false;
      } else {
	// - is it time, and is left child a graph node?
	if (curr->type == k+1 && curr->L->type == GRAPH) {
	  subtreeR.insertItem(curr->L->index, 1);
	  curr->type = k+2;
	  nB++;
	}
	// - is it time, and is right child a graph node?
	if (curr->type == k+2 && curr->R->type == GRAPH) {
	  subtreeR.insertItem(curr->R->index, 1);
	  curr->type = k+3;
	  nB++;
	}
	if (curr->type == k+1) {      // - look left
	  curr->type = k+2; 
	  curr       = curr->L;
	  curr->type = k+1; }
	else if (curr->type == k+2) { // - look right
	  curr->type = k+3;
	  curr       = curr->R;
	  curr->type = k+1;
	} else {		      // - else go up a level
	  curr->type = DENDRO;
	  curr       = curr->M;
	  if (curr == NULL) {
	    flag_go = false;
	  }
	}
      }
    }
  }

  // Now, we take the smaller subtree and ask how many of its
  // emerging edges have their partner in the other subtree. O(|A| log
  // |A|) time 

  edge* current;
  int*  treeList;
  if (nA < nB) {
    // subtreeL is smaller
    treeList = subtreeL.returnArrayOfKeys();
    for (int i=0; i<nA; i++) {
      current = g->getNeighborList(treeList[i]);
      // loop over each of its neighbors v_j
      while (current != NULL) {
	// to see if v_j is in A
	if (subtreeR.findItem(current->x) != NULL) { count++; }
	current = current->next;
      }
      subtreeL.deleteItem(treeList[i]);
    }
    delete [] treeList;
    treeList = subtreeR.returnArrayOfKeys();
    for (int i=0; i<nB; i++) { subtreeR.deleteItem(treeList[i]); }
    delete [] treeList;
  } else {
    // subtreeR is smaller
    treeList = subtreeR.returnArrayOfKeys();
    for (int i=0; i<nB; i++) {
      current = g->getNeighborList(treeList[i]);
      // loop over each of its neighbors v_j
      while (current != NULL) {
	// to see if v_j is in B
	if (subtreeL.findItem(current->x) != NULL) { count++; }
	current = current->next;
      }
      subtreeR.deleteItem(treeList[i]);
    }
    delete [] treeList;
    treeList = subtreeL.returnArrayOfKeys();
    for (int i=0; i<nA; i++) { subtreeL.deleteItem(treeList[i]); }
    delete [] treeList;
  }

  return count;
}

// ***********************************************************************

int dendro::countChildren(const string s) {
  int len = s.size();
  int numC = 0;
  for (int i=0; i<len; i++) {
    if (s[i] == 'C') { numC++; }
  }
  return numC;
}

// ***********************************************************************

void dendro::cullSplitHist() {
  string* array;
  int tot, leng;
 
  array = splithist->returnArrayOfKeys();
  tot   = splithist->returnTotal();
  leng  = splithist->returnNodecount();
  for (int i=0; i<leng; i++) {
    if ((splithist->returnValue(array[i]) / tot) < 0.5) { 
      splithist->deleteItem(array[i]); 
    }
  }
  delete [] array; array = NULL;
 
  return;
}

// **********************************************************************

elementd* dendro::findCommonAncestor(list** paths, const int i, const int j) {
  list* headOne = paths[i];
  list* headTwo = paths[j];
  elementd* lastStep = NULL;
  while (headOne->x == headTwo->x) {
    lastStep = &internal[headOne->x];
    headOne  = headOne->next;
    headTwo  = headTwo->next;
    if (headOne == NULL || headTwo == NULL) { break; }
  }
  return lastStep; // Returns address of an internal node; do not deallocate
}

// **********************************************************************

int dendro::getConsensusSize() {
  string    *array;
  double     value, tot;
  int  numSplits, numCons;
  numSplits = splithist->returnNodecount();
  array     = splithist->returnArrayOfKeys();
  tot       = splithist->returnTotal();
  numCons = 0;
  for (int i=0; i<numSplits; i++) {
    value = splithist->returnValue(array[i]);
    if (value / tot > 0.5) { numCons++; }
  }
  delete [] array; array = NULL;
  return numCons;
}

// **********************************************************************

splittree* dendro::getConsensusSplits() {
  string    *array;
  splittree *consensusTree;
  double     value, tot;
  consensusTree  = new splittree;
  int numSplits;
 
  // We look at all of the splits in our split histogram and add any
  // one that's in the majority to our consensusTree, which we then
  // return (note that consensusTree needs to be deallocated by the
  // user).
  numSplits = splithist->returnNodecount();
  array     = splithist->returnArrayOfKeys();
  tot       = splithist->returnTotal();
  for (int i=0; i<numSplits; i++) {
    value = splithist->returnValue(array[i]);
    if (value / tot > 0.5) { 
      consensusTree->insertItem(array[i], value / tot); 
    }
  }
  delete [] array; array = NULL;
  return consensusTree;
}

// ***********************************************************************

double dendro::getLikelihood() { return L; }

// ***********************************************************************

void dendro::getSplitList(splittree* split_tree) {
  string sp;
  for (int i=0; i<(n-1); i++) {
    sp = d->getSplit(i);
    if (!sp.empty() && sp[1] != '-') { split_tree->insertItem(sp,0.0); }
  }
  return;
}

// ***********************************************************************

double dendro::getSplitTotalWeight() { 
  if (splithist) { return splithist->returnTotal(); } else { return 0; }
}

// ***********************************************************************

bool dendro::importDendrogramStructure(const igraph_hrg_t *hrg) {
  n=igraph_hrg_size(hrg);
  
  // allocate memory for G, O(n)
  leaf = new elementd[n];
  // allocate memory for D, O(n)
  internal = new elementd[n-1];
  // allocate memory for internal edges of D, O(n)
  d = new interns(n-2);

  // initialize leaf nodes
  for (int i=0; i<n; i++) {
    leaf[i].type  = GRAPH;
    leaf[i].label = i;
    leaf[i].index = i;
    leaf[i].n     = 1;
  }

  // initialize internal nodes
  root = &internal[0];
  root->label=0;
  for (int i=1; i<n-1; i++) {
    internal[i].index = i;
    internal[i].label = -1;
  }

  // import basic structure from hrg object, O(n)  
  for (int i=0; i<n-1; i++) {
    int L=VECTOR(hrg->left)[i];
    int R=VECTOR(hrg->right)[i];
    
    if (L < 0) { 
      internal[i].L = &internal[-L-1]; 
      internal[-L-1].M = &internal[i];
    } else {
      internal[i].L = &leaf[L];
      leaf[L].M = &internal[i];
    }
    
    if (R < 0) { 
      internal[i].R = &internal[-R-1];
      internal[-R-1].M = &internal[i];
    } else {
      internal[i].R = &leaf[R];
      leaf[R].M = &internal[i];
    }
    
    internal[i].p = VECTOR(hrg->prob)[i];
    internal[i].e = VECTOR(hrg->edges)[i];
    internal[i].n = VECTOR(hrg->vertices)[i];
    internal[i].index = i;
  }
  
  // --- Label all internal vertices O(n log n)
  elementd *curr;
  for (int i=0; i<n; i++) {
    curr=&leaf[i];
    while (curr) { 
      if (curr->label == -1 || curr->label > leaf[i].label) {
	curr->label = leaf[i].label; 
      } 
      curr = curr -> M;
    }
  }
  
  // --- Exchange children to enforce order-property O(n)
  elementd *tempe;
  for (int i=0; i<n-1; i++) {
    if (internal[i].L->label > internal[i].label) {
      tempe          = internal[i].L;
      internal[i].L  = internal[i].R;
      internal[i].R  = tempe;
    }
  }
  
  // --- Tabulate internal dendrogram edges O(n)
  for (int i=0; i<(n-1); i++) {
    if (internal[i].L->type == DENDRO) { 
      d->addEdge(i, internal[i].L->index, LEFT);  
    }
    if (internal[i].R->type == DENDRO) { 
      d->addEdge(i, internal[i].R->index, RIGHT); 
    }
  }
  
  // --- Compute p_i for each internal node O(n)
  // Each internal node's p_i = e_i / (nL_i*nR_i), and now that we
  // have each of those pieces, we may calculate this value for each
  // internal node. Given these, we can then calculate the
  // log-likelihood of the entire dendrogram structure 
  // \log(L) = \sum_{i=1}^{n} ( ( e_i \log[p_i] ) + 
  // ( (nL_i*nR_i - e_i) \log[1-p_i] ) )
  L = 0.0; double dL;
  int nL_nR, ei;
  for (int i=0; i<(n-1); i++) {
    nL_nR = internal[i].L->n*internal[i].R->n;
    ei    = internal[i].e;
    if (ei == 0 || ei == nL_nR) { 
      dL = 0.0; 
    } else { 
      dL = (double)(ei) * log(internal[i].p) + 
	(double)(nL_nR - ei) * log(1.0-internal[i].p); 
    }
    internal[i].logL = dL;
    L += dL;
  }
  
  return true;
}

// ***********************************************************************

void dendro::makeRandomGraph() {
  if (g != NULL) { delete g; } g = NULL; g = new graph(n);

  list *curr, *prev; 
  if (paths) { 
    for (int i=0; i<n; i++) { 
      curr = paths[i]; 
      while (curr != NULL) {
	prev = curr;   
	curr = curr->next;
	delete prev;
	prev = NULL; 
      }
      paths[i] = NULL;
    }
    delete [] paths;
  }
 // build paths from root O(n d)
  paths = new list* [n];
  for (int i=0; i<n; i++) { paths[i] = reversePathToRoot(i); }
 
  elementd* commonAncestor;
 // O((h+d)*n^2) - h: height of D; d: average degree in G
  for (int i=0; i<n; i++) {
    // decide neighbors of v_i
    for (int j=(i+1); j<n; j++) {
      commonAncestor = findCommonAncestor(paths,i,j);
      if (RNG_UNIF01() < commonAncestor->p) { 
	if (!(g->doesLinkExist(i,j))) { g->addLink(i,j); }
	if (!(g->doesLinkExist(j,i))) { g->addLink(j,i); }
      }
    }
  }
 
  for (int i=0; i<n; i++) { 
    curr = paths[i]; 
    while (curr != NULL) { 
      prev = curr; 
      curr = curr->next;
      delete prev;
      prev = NULL; 
    }
    paths[i] = NULL; 
  }
  delete [] paths; // delete paths data structure O(n log n)
  paths = NULL;

  return;
}

// **********************************************************************

bool dendro::monteCarloMove(double& delta, bool& ftaken, const double T) {
  // A single MC move begins with the selection of a random internal
  // edge (a,b) of the dendrogram. This also determines the three
  // subtrees i, j, k that we will rearrange, and we choose uniformly
  // from among the options. 
  // 
  // If (a,b) is a left-edge, then we have ((i,j),k), and moves
  // ((i,j),k) -> ((i,k),j) (alpha move)
  //           -> (i,(j,k)) + enforce order-property for (j,k) (beta move)
  // 
  // If (a,b) is a right-edge, then we have (i,(j,k)), and moves
  // (i,(j,k)) -> ((i,k),j) (alpha move)
  //           -> ((i,j),k) (beta move)
  // 
  // For each of these moves, we need to know what the change in
  // likelihood will be, so that we can determine with what
  // probability we execute the move.
 
  elementd *temp;
  ipair *tempPair;
  int x, y, e_x, e_y, n_i, n_j, n_k, n_x, n_y;
  short int t;
  double p_x, p_y, L_x, L_y, dLogL;
  string new_split;
 
  // The remainder of the code executes a single MCMC move, where we
  // sample the dendrograms proportionally to their likelihoods (i.e.,
  // temperature=1, if you're comparing it to the usual MCMC
  // framework).

  delta    = 0.0;
  ftaken   = false;
  tempPair = d->getRandomEdge(); // returns address; no need to deallocate
  x        = tempPair->x;        // copy contents of referenced random edge
  y        = tempPair->y;        // into local variables
  t        = tempPair->t;
 
  if (t == LEFT) {
    if (RNG_UNIF01() < 0.5) { // ## LEFT ALPHA move: ((i,j),k) -> ((i,k),j)
      // We need to calculate the change in the likelihood (dLogL)
      // that would result from this move. Most of the information
      // needed to do this is already available, the exception being
      // e_ik, the number of edges that span the i and k subtrees. I
      // use a slow algorithm O(n) to do this, since I don't know of a
      // better way at this point. (After several attempts to find a
      // faster method, no luck.)

      n_i = internal[y].L->n;
      n_j = internal[y].R->n;
      n_k = internal[x].R->n;
 
      n_y = n_i*n_k;
      e_y = computeEdgeCount(internal[y].L->index, internal[y].L->type, 
			     internal[x].R->index, internal[x].R->type);
      p_y  = (double)(e_y) / (double)(n_y);
      if (e_y == 0 || e_y == n_y) { 
	L_y = 0.0; 
      } else { 
	L_y = (double)(e_y) * log(p_y) + (double)(n_y - e_y) * log(1.0-p_y); 
      }

      n_x  = (n_i+n_k)*n_j;
      e_x  = internal[x].e + internal[y].e - e_y; // e_yj
      p_x  = (double)(e_x) / (double)(n_x);
      if (e_x == 0 || e_x == n_x) { 
	L_x = 0.0; 
      } else { 
	L_x = (double)(e_x) * log(p_x) + (double)(n_x - e_x) * log(1.0-p_x); 
      }
 
      dLogL = (L_x - internal[x].logL) + (L_y - internal[y].logL);
      if ((dLogL > 0.0) || (RNG_UNIF01() < exp(T*dLogL))) {

	// make LEFT ALPHA move

	ftaken = true;
	d->swapEdges(x, internal[x].R->index, RIGHT, y, 
		     internal[y].R->index, RIGHT);
	temp             = internal[x].R; // - swap j and k
	internal[x].R    = internal[y].R;
	internal[y].R    = temp;
	internal[x].R->M = &internal[x];  // - adjust parent pointers
	internal[y].R->M = &internal[y]; 
	internal[y].n    = n_i + n_k;     // - update n for [y]
	internal[x].e    = e_x;	          // - update e_i for [x] and [y]
	internal[y].e    = e_y; 
	internal[x].p    = p_x;           // - update p_i for [x] and [y]
	internal[y].p    = p_y;
	internal[x].logL = L_x;           // - update L_i for [x] and [y]
	internal[y].logL = L_y;
	// - order-property maintained
	L  += dLogL;		          // - update LogL
	delta            = dLogL;
 
      }      
    } else {

      // ## LEFT BETA move:  ((i,j),k) -> (i,(j,k))
      
      n_i = internal[y].L->n;
      n_j = internal[y].R->n;
      n_k = internal[x].R->n;
 
      n_y  = n_j*n_k;
      e_y  = computeEdgeCount(internal[y].R->index, internal[y].R->type,
			      internal[x].R->index, internal[x].R->type);
      p_y  = (double)(e_y) / (double)(n_y);
      if (e_y == 0 || e_y == n_y)   { L_y = 0.0; }
      else { L_y = (double)(e_y) * log(p_y) + 
	  (double)(n_y - e_y) * log(1.0-p_y); }
 
      n_x  = (n_j+n_k)*n_i;
      e_x  = internal[x].e + internal[y].e - e_y; // e_yj
      p_x  = (double)(e_x) / (double)(n_x);
      if (e_x == 0 || e_x == n_x) { 
	L_x = 0.0; 
      } else { 
	L_x = (double)(e_x) * log(p_x) + (double)(n_x - e_x) * log(1.0-p_x); 
      }
 
      dLogL = (L_x - internal[x].logL) + (L_y - internal[y].logL);
      if ((dLogL > 0.0) || (RNG_UNIF01() < exp(T*dLogL))) {
	
	// make LEFT BETA move
	
	ftaken = true;
	d->swapEdges(y, internal[y].L->index, LEFT, y, 
		     internal[y].R->index, RIGHT);
	temp   = internal[y].L;		  // - swap L and R of [y]
	internal[y].L    = internal[y].R;
	internal[y].R    = temp; 
	d->swapEdges(x, internal[x].R->index, RIGHT,
		     y, internal[y].R->index, RIGHT);
	temp   = internal[x].R;		  // - swap i and k
	internal[x].R    = internal[y].R; 
	internal[y].R    = temp;
	internal[x].R->M = &internal[x];  // - adjust parent pointers
	internal[y].R->M = &internal[y]; 
	d->swapEdges(x, internal[x].L->index, LEFT,
		     x, internal[x].R->index, RIGHT);
	temp   = internal[x].L;		  // - swap L and R of [x]
	internal[x].L    = internal[x].R;
	internal[x].R    = temp;
	internal[y].n    = n_j + n_k;     // - update n
	internal[x].e    = e_x;		  // - update e_i
	internal[y].e    = e_y;
	internal[x].p    = p_x;           // - update p_i
	internal[y].p    = p_y;
	internal[x].logL = L_x;           // - update logL_i
	internal[y].logL = L_y;
	if (internal[y].R->label < internal[y].L->label) {
	  // - enforce order-property if necessary
	  d->swapEdges(y, internal[y].L->index, LEFT,
		       y, internal[y].R->index, RIGHT);
	  temp = internal[y].L;	
	  internal[y].L = internal[y].R; 
	  internal[y].R = temp;
	} // 
	internal[y].label = internal[y].L->label;
	L += dLogL;		   // - update LogL
	delta = dLogL;
      }
    }
  } else {

    // right-edge: t == RIGHT
    
    if (RNG_UNIF01() < 0.5) {
      
      // alpha move: (i,(j,k)) -> ((i,k),j)
      
      n_i = internal[x].L->n;
      n_j = internal[y].L->n;
      n_k = internal[y].R->n;
 
      n_y  = n_i*n_k;
      e_y  = computeEdgeCount(internal[x].L->index, internal[x].L->type,
			      internal[y].R->index, internal[y].R->type);
      p_y  = (double)(e_y) / (double)(n_y);
      if (e_y == 0 || e_y == n_y)   { 
	L_y = 0.0; 
      } else { 
	L_y = (double)(e_y) * log(p_y) + (double)(n_y - e_y) * log(1.0-p_y); 
      }
 
      n_x  = (n_i+n_k)*n_j;
      e_x  = internal[x].e + internal[y].e - e_y; // e_yj
      p_x  = (double)(e_x) / (double)(n_x);
      if (e_x == 0 || e_x == n_x) {
	L_x = 0.0; 
      } else {
	L_x = (double)(e_x) * log(p_x) + (double)(n_x - e_x) * log(1.0-p_x); 
      }

      dLogL = (L_x - internal[x].logL) + (L_y - internal[y].logL);
      if ((dLogL > 0.0) || (RNG_UNIF01() < exp(T*dLogL))) { 
	
	// make RIGHT ALPHA move
	
	ftaken = true;
	d->swapEdges(x, internal[x].L->index, LEFT,
		     x, internal[x].R->index, RIGHT);
	temp    = internal[x].L;	   // - swap L and R of [x]
	internal[x].L     = internal[x].R;
	internal[x].R     = temp; 
	d->swapEdges(y, internal[y].L->index, LEFT,
		     x, internal[x].R->index, RIGHT);
	temp    = internal[y].L;	   // - swap i and j
	internal[y].L     = internal[x].R;
	internal[x].R     = temp;
	internal[x].R->M  = &internal[x];  // - adjust parent pointers
	internal[y].L->M  = &internal[y];
	internal[y].n     = n_i + n_k;	   // - update n
	internal[x].e     = e_x;	   // - update e_i
	internal[y].e     = e_y;
	internal[x].p     = p_x;           // - update p_i
	internal[y].p     = p_y;
	internal[x].logL  = L_x;           // - update logL_i
	internal[y].logL  = L_y;
	internal[y].label = internal[x].label; // - update order property
	L   += dLogL;			       // - update LogL
	delta             = dLogL;
      }
    } else {
      
      // beta move:  (i,(j,k)) -> ((i,j),k)
      
      n_i = internal[x].L->n;
      n_j = internal[y].L->n;
      n_k = internal[y].R->n;
 
      n_y  = n_i*n_j;
      e_y  = computeEdgeCount(internal[x].L->index, internal[x].L->type,
			      internal[y].L->index, internal[y].L->type);
      p_y  = (double)(e_y) / (double)(n_y);
      if (e_y == 0 || e_y == n_y)   { 
	L_y = 0.0; 
      } else {
	L_y = (double)(e_y) * log(p_y) + (double)(n_y - e_y) * log(1.0-p_y); 
      }
 
      n_x  = (n_i+n_j)*n_k;
      e_x  = internal[x].e + internal[y].e - e_y; // e_yk
      p_x  = (double)(e_x) / (double)(n_x);
      if (e_x == 0 || e_x == n_x) { 
	L_x = 0.0; 
      } else { 
	L_x = (double)(e_x) * log(p_x) + (double)(n_x - e_x) * log(1.0-p_x); 
      }

      dLogL = (L_x - internal[x].logL) + (L_y - internal[y].logL);
      if ((dLogL > 0.0) || (RNG_UNIF01() < exp(T*dLogL))) { 
	
	// make RIGHT BETA move
	
	ftaken = true;
	d->swapEdges(x, internal[x].L->index, LEFT, 
		     x, internal[x].R->index, RIGHT);
	temp    = internal[x].L;	   // - swap L and R of [x]
	internal[x].L     = internal[x].R;
	internal[x].R     = temp; 
	d->swapEdges(x, internal[x].R->index, RIGHT,
		     y, internal[y].R->index, RIGHT);
	temp    = internal[x].R;	   // - swap i and k
	internal[x].R     = internal[y].R;
	internal[y].R     = temp;
	internal[x].R->M  = &internal[x];  // - adjust parent pointers
	internal[y].R->M  = &internal[y];
	d->swapEdges(y, internal[y].L->index, LEFT,
		     y, internal[y].R->index, RIGHT);
	temp    = internal[y].L;	   // - swap L and R of [y]
	internal[y].L     = internal[y].R;
	internal[y].R     = temp; 
	internal[y].n     = n_i + n_j;	   // - update n
	internal[x].e     = e_x;	   // - update e_i
	internal[y].e     = e_y;
	internal[x].p     = p_x;	   // - update p_i
	internal[y].p     = p_y;
	internal[x].logL  = L_x;	   // - update logL_i
	internal[y].logL  = L_y;
	internal[y].label = internal[x].label; // - order-property
	L   += dLogL;			       // - update LogL
	delta             = dLogL;
      }
    }  
  }
  return true;
}

// **********************************************************************

void dendro::refreshLikelihood() {
  // recalculates the log-likelihood of the dendrogram structure
  L = 0.0; double dL;
  int nL_nR, ei;
  for (int i=0; i<(n-1); i++) {
    nL_nR = internal[i].L->n*internal[i].R->n;
    ei    = internal[i].e;
    internal[i].p = (double)(ei) / (double)(nL_nR);
    if (ei == 0 || ei == nL_nR) { 
      dL = 0.0; 
    } else { 
      dL = ei * log(internal[i].p) + (nL_nR - ei) * log(1.0-internal[i].p); 
    }
    internal[i].logL = dL;
    L += dL;
  }
  return;
}

// **********************************************************************

void dendro::QsortMain (block* array, int left, int right) {
  if (right > left) {
    int pivot = left;
    int part  = QsortPartition(array, left, right, pivot);
    QsortMain(array, left,   part-1);
    QsortMain(array, part+1, right  );
  }
  return;
}

int dendro::QsortPartition (block* array, int left, int right, int index) {
  block p_value, temp;
  p_value.x = array[index].x;
  p_value.y = array[index].y;
 
  // swap(array[p_value], array[right])
  temp.x = array[right].x;
  temp.y = array[right].y;
  array[right].x = array[index].x;
  array[right].y = array[index].y;
  array[index].x = temp.x;
  array[index].y = temp.y;
 
  int stored = left;
  for (int i=left; i<right; i++) {
    if (array[i].x <= p_value.x) {
      // swap(array[stored], array[i])
      temp.x = array[i].x;
      temp.y = array[i].y;
      array[i].x = array[stored].x; 
      array[i].y = array[stored].y;
      array[stored].x = temp.x;
      array[stored].y = temp.y;
      stored++;
    }
  }
  // swap(array[right], array[stored])
  temp.x = array[stored].x; 
  temp.y = array[stored].y;
  array[stored].x = array[right].x;
  array[stored].y = array[right].y;
  array[right].x = temp.x;
  array[right].y  = temp.y;
 
  return stored;
}

void dendro::recordConsensusTree(igraph_vector_t *parents, 
				 igraph_vector_t *weights) {
  
  keyValuePairSplit *curr, *prev;
  child *newChild;
  int orig_nodes=g->numNodes();
  
  // First, cull the split hist so that only splits with weight >= 0.5
  // remain 
  cullSplitHist();
  int treesize = splithist->returnNodecount();

  // Now, initialize the various arrays we use to keep track of the
  // internal structure of the consensus tree.
  ctree  = new cnode[treesize];
  cancestor = new int[n];
  for (int i=0; i<treesize; i++) { ctree[i].index = i;  }
  for (int i=0; i<n; i++)        { cancestor[i]   = -1; }
  int ii = 0;
 
  // To build the majority consensus tree, we do the following: For
  // each possible number of Ms in the split string (a number that
  // ranges from n-2 down to 0), and for each split with that number
  // of Ms, we create a new internal node of the tree, and connect the
  // oldest ancestor of each C to that node (at most once). Then, we
  // update our list of oldest ancestors to reflect this new join, and
  // proceed.
  for (int i=n-2; i>=0; i--) {
    // First, we get a list of all the splits with this exactly i Ms
    curr = splithist->returnTheseSplits(i);
    
    // Now we loop over that list
    while (curr != NULL) {
      splithist->deleteItem(curr->x);
      // add weight to this internal node
      ctree[ii].weight = curr->y; 
      // examine each letter of this split
      for (int j=0; j<n; j++) { 
	if (curr->x[j] == 'C') { 
	  // - node is child of this internal node
	  if (cancestor[j] == -1) {
	    // - first time this leaf has ever been seen
	    newChild        = new child;
	    newChild->type  = GRAPH;
	    newChild->index = j;
	    newChild->next  = NULL;
	    // - attach child to list
	    if (ctree[ii].lastChild == NULL) { 
	      ctree[ii].children  = newChild;
	      ctree[ii].lastChild = newChild;
	      ctree[ii].degree    = 1;
	    } else {
	      ctree[ii].lastChild->next = newChild;
	      ctree[ii].lastChild       = newChild;
	      ctree[ii].degree   += 1;
	    }
	  } else {
	    // - this leaf has been seen before
	    // If the parent of the ancestor of this leaf is the
	    // current internal node then this leaf is already a
	    // descendant of this internal node, and we can move on;
	    // otherwise, we need to add that ancestor to this
	    // internal node's child list, and update various
	    // relations
	    if (ctree[cancestor[j]].parent != ii) {
	      ctree[cancestor[j]].parent = ii;
	      newChild        = new child;
	      newChild->type  = DENDRO;
	      newChild->index = cancestor[j];
	      newChild->next  = NULL;
	      // - attach child to list
	      if (ctree[ii].lastChild == NULL) {
		ctree[ii].children  = newChild;
		ctree[ii].lastChild = newChild;
		ctree[ii].degree    = 1;
	      } else {
		ctree[ii].lastChild->next = newChild;
		ctree[ii].lastChild       = newChild;
		ctree[ii].degree   += 1;
	      }
	    }
	  }
	  // note new ancestry for this leaf
	  cancestor[j] = ii;
	}
      }
      // update internal node index
      ii++;
      prev = curr;
      curr = curr->next;
      delete prev;
    }
  }

  // Return the consensus tree
  igraph_vector_resize(parents, ii + orig_nodes);
  if (weights) { igraph_vector_resize(weights, ii); }

  for (int i=0; i<ii; i++) {
    child *sat, *sit=ctree[i].children;    
    while (sit) {
      VECTOR(*parents)[orig_nodes + i] = 
	ctree[i].parent < 0 ? -1 : orig_nodes + ctree[i].parent;
      if (sit->type == GRAPH) { 
	VECTOR(*parents)[sit->index] = orig_nodes + i;
      }
      sat=sit;
      sit=sit->next;
      delete sat;
    }
    if (weights) { VECTOR(*weights)[i] = ctree[i].weight; }
    ctree[i].children=0;
  }
  
  // Plus the isolate nodes
  for (int i=0; i<n; i++) {
    if (cancestor[i] == -1) {
      VECTOR(*parents)[i] = -1;
    }
  }    


}

// **********************************************************************

void dendro::recordDendrogramStructure(igraph_hrg_t *hrg) {
  for (int i=0; i<n-1; i++) {
    int li=internal[i].L->index;
    int ri=internal[i].R->index;
    VECTOR(hrg->left )[i] = internal[i].L->type == DENDRO ? -li-1 : li;
    VECTOR(hrg->right)[i] = internal[i].R->type == DENDRO ? -ri-1 : ri;
    VECTOR(hrg->prob )[i] = internal[i].p;
    VECTOR(hrg->edges)[i] = internal[i].e;
    VECTOR(hrg->vertices)[i] = internal[i].n;    
  }
}

void dendro::recordGraphStructure(igraph_t *graph) {
  igraph_vector_t edges;
  int no_of_nodes=g->numNodes();
  int no_of_edges=g->numLinks() / 2;
  int idx=0;

  igraph_vector_init(&edges, no_of_edges*2);
  IGRAPH_FINALLY(igraph_vector_destroy, &edges);

  for (int i=0; i<n; i++) {
    edge *curr = g->getNeighborList(i);
    while (curr) {
      if (i < curr->x) {
	VECTOR(edges)[idx++] = i;
	VECTOR(edges)[idx++] = curr->x;
      }
      curr = curr->next;
    }
  }
  
  igraph_create(graph, &edges, no_of_nodes, /* directed= */ 0);

  igraph_vector_destroy(&edges);
  IGRAPH_FINALLY_CLEAN(1);
}

// **********************************************************************

list* dendro::reversePathToRoot(const int leafIndex) {
  list *head, *subhead, *newlist;
  head = subhead = newlist = NULL;
  elementd *current = &leaf[leafIndex];
 
  // continue until we're finished
  while (current != NULL) {
    // add this node to the path
    newlist = new list;
    newlist->x = current->index;
    newlist->next = NULL;
    if (head == NULL) { 
      head    = newlist; 
    } else { 
      subhead = head;    
      head = newlist; 
      head->next = subhead; 
    }
    current = current->M;
  }
  return head;
}

// ***********************************************************************

bool dendro::sampleSplitLikelihoods(int &sample_num) {
  // In order to compute the majority agreement dendrogram at
  // equilibrium, we need to calculate the leaf partition defined by
  // each split (internal edge) of the tree. Because splits are only
  // defined on a Cayley tree, the buildSplit() function returns the
  // default "--...--"  string for the root and the root's left
  // child. When tabulating the frequency of splits, one of these
  // needs to be excluded.

  IGRAPH_UNUSED(sample_num);

  string* array;
  int     k;
  double  tot;

  string new_split;
  // To decompose the tree into its splits, we simply loop over all
  // the internal nodes and replace the old split for the ith internal
  // node with its new split. This is a bit time consuming to do
  // O(n^2), so try not to do this very often. Once the decomposition
  // is had, we insert them into the split histogram, which tracks the
  // cumulative weight for each respective split observed.
 
  if (splithist == NULL) { splithist = new splittree; }
  for (int i=0; i<(n-1); i++) {
    new_split = buildSplit(&internal[i]);
    d->replaceSplit(i, new_split);
    if (!new_split.empty() && new_split[1] != '-') {
      if (!splithist->insertItem(new_split, 1.0)) { return false; } 
    }
  }
  splithist->finishedThisRound();
 
  // For large graphs, the split histogram can get extremely large, so
  // we need to employ some measures to prevent it from swamping the
  // available memory. When the number of splits exceeds  a threshold
  // (say, a million), we progressively delete splits that have a
  // weight less than  a rising (k*0.001 of the total weight) fraction
  // of the splits, on the assumption that losing such weight is
  // unlikely to effect the ultimate split statistics. This deletion
  // procedure is slow O(m lg m), but should only happen very rarely.

  int split_max = n*500;
  int leng;
  if (splithist->returnNodecount() > split_max) {
    k=1;
    while (splithist->returnNodecount() > split_max) {
      array = splithist->returnArrayOfKeys();
      tot   = splithist->returnTotal();
      leng  = splithist->returnNodecount();
      for (int i=0; i<leng; i++) {
	if ((splithist->returnValue(array[i]) / tot) < k*0.001) { 
	  splithist->deleteItem(array[i]); 
	}
      }
      delete [] array; array = NULL;
      k++;
    }
  }
 
  return true;
}

void dendro::sampleAdjacencyLikelihoods() {
  // Here, we sample the probability values associated with every
  // adjacency in A, weighted by their likelihood. The weighted
  // histogram is stored in the graph data structure, so we simply
  // need to add an observation to each node-pair that corresponds to
  // the associated branch point's probability and the dendrogram's
  // overall likelihood.

  double nn;
  double norm = ((double)(n) * (double)(n)) / 4.0;
 
  if (L > 0.0) { L = 0.0; }
  elementd* ancestor;
  list *currL, *prevL;
  if (paths != NULL) { 
    for (int i=0; i<n; i++) { 
      currL = paths[i]; 
      while (currL != NULL) { 
	prevL = currL;
	currL = currL->next;
	delete prevL;
	prevL = NULL; 
      }
      paths[i] = NULL; 
    }
    delete [] paths;
  }
  paths = NULL;
  paths = new list* [n];
  for (int i=0; i<n; i++) {
    // construct paths from root, O(n^2) at worst
    paths[i] = reversePathToRoot(i); 
  }

  // add obs for every node-pair, always O(n^2)
  for (int i=0; i<n; i++) {
    for (int j=i+1; j<n; j++) {
      // find internal node, O(n) at worst
      ancestor = findCommonAncestor(paths, i, j);
      nn = ((double)(ancestor->L->n) * (double)(ancestor->R->n)) / norm;
      // add obs of ->p to (i,j) histogram, and
      g->addAdjacencyObs(i, j, ancestor->p, nn);
      // add obs of ->p to (j,i) histogram
      g->addAdjacencyObs(j, i, ancestor->p, nn);
    }
  }

  // finish-up: upate total weight in histograms
  g->addAdjacencyEnd();
 
  return;
}

void dendro::resetDendrograph() {
  // Reset the dendrograph structure for the next trial
  if (leaf      != NULL) { delete [] leaf;     leaf      = NULL; } // O(n)
  if (internal  != NULL) { delete [] internal; internal  = NULL; } // O(n)
  if (d         != NULL) { delete d;           d         = NULL; } // O(n)
  root = NULL;
  if (paths != NULL) {
    list *curr, *prev; 
    for (int i=0; i<n; i++) {
      curr = paths[i];
      while (curr != NULL) {
	prev = curr;
	curr = curr->next;
	delete prev;
	prev = NULL;
      }
      paths[i] = NULL;
    }
    delete [] paths;
  } 
  paths = NULL;
  L = 1.0;
        
  return;
}

// **********************************************************************
// *** COPYRIGHT NOTICE *************************************************
// graph.h - graph data structure for hierarchical random graphs
// Copyright (C) 2005-2008 Aaron Clauset
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 
// See http://www.gnu.org/licenses/gpl.txt for more details.
// 
// **********************************************************************
// Author       : Aaron Clauset  ( aaronc@santafe.edu |
//                                 http://www.santafe.edu/~aaronc/ ) 
// Collaborators: Cristopher Moore and Mark E.J. Newman
// Project      : Hierarchical Random Graphs
// Location     : University of New Mexico, Dept. of Computer Science
//                AND Santa Fe Institute 
// Created      : 8 November 2005
// Modified     : 23 December 2007 (cleaned up for public consumption)
//
// ***********************************************************************
// 
// Graph data structure for hierarchical random graphs. The basic
// structure is an adjacency list of edges; however, many additional
// pieces of metadata are stored as well. Each node stores its
// external name, its degree and (if assigned) its group index.
// 
// ***********************************************************************

// ******** Constructor / Destructor *************************************

graph::graph(const int size, bool predict) : predict(predict)  {
  n = size;
  m = 0;
  nodes = new vert  [n];
  nodeLink = new edge* [n];
  nodeLinkTail   = new edge* [n];
  for (int i=0; i<n; i++) { nodeLink[i] = NULL; nodeLinkTail[i] = NULL; }
  if (predict) {
    A = new double** [n];
    for (int i=0; i<n; i++) {
      A[i] = new double* [n];
    }
    obs_count = 0;
    total_weight = 0.0;
    bin_resolution = 0.0;
    num_bins = 0;
  }
}

graph::~graph() {
  edge *curr, *prev;
  for (int i=0; i<n; i++) {
    curr = nodeLink[i];
    while (curr != NULL) {
      prev = curr;
      curr = curr->next;
      delete prev;
    }
  }
  delete [] nodeLink; nodeLink = NULL;
  delete [] nodeLinkTail;  nodeLinkTail   = NULL;
  delete [] nodes; nodes = NULL;
 
  if (predict) {
    for (int i=0; i<n; i++) {
      for (int j=0; j<n; j++) { delete [] A[i][j]; }
      delete [] A[i];
    }
    delete [] A; A = NULL;
  }
}

// **********************************************************************

bool graph::addLink(const int i, const int j) {
  // Adds the directed edge (i,j) to the adjacency list for v_i
  edge* newedge;
  if (i >= 0 && i < n && j >= 0 && j < n) {
    newedge  = new edge;
    newedge->x = j;
    if (nodeLink[i] == NULL) { 
      // first neighbor
      nodeLink[i]  = newedge;
      nodeLinkTail[i] = newedge;
      nodes[i].degree = 1;
    } else {
      // subsequent neighbor
      nodeLinkTail[i]->next = newedge;
      nodeLinkTail[i]       = newedge;
      nodes[i].degree++;
    }
    // increment edge count
    m++;
    return true;
  } else { return false; }
}

// ***********************************************************************

bool graph::addAdjacencyObs(const int i, const int j, 
			    const double probability, const double size) {
  // Adds the observation obs to the histogram of the edge (i,j)
  // Note: user must manually add observation to edge (j,i) by calling
  // this function with that argument
  if (bin_resolution > 0.0 && probability >= 0.0 && probability <= 1.0 
      && size >= 0.0 && size <= 1.0
      && i >= 0 && i < n && j >= 0 && j < n) {
    int index = (int)(probability/bin_resolution + 0.5);
    if (index < 0) { 
      index = 0; 
    } else if (index > num_bins) { 
      index = num_bins; 
    }
    
    // Add the weight to the proper probability bin
    if (A[i][j][index] < 0.5) { 
      A[i][j][index] = 1.0; 
    } else { 
      A[i][j][index] += 1.0; 
    }
    return true;
  }
  return false;
}

// **********************************************************************

void graph::addAdjacencyEnd() {
  // We need to also keep a running total of how much weight has been added
  // to the histogram, and the number of observations in the histogram.
  if (obs_count==0) { 
    total_weight  = 1.0; obs_count = 1; 
  } else {
    total_weight += 1.0; obs_count++;   
  }
  return;
}

bool graph::doesLinkExist(const int i, const int j) {
  // This function determines if the edge (i,j) already exists in the
  // adjacency list of v_i
  edge* curr;
  if (i >= 0 && i < n && j >= 0 && j < n) {
    curr = nodeLink[i];
    while (curr != NULL) {
      if (curr->x == j) { 
	return true; 
      }
      curr = curr->next;
    }
  }
  return false;
}

// **********************************************************************

int graph::getDegree(const int i) { 
  if (i >= 0 && i < n) { return nodes[i].degree; } else { return -1; } 
}

string graph::getName(const int i)  { 
  if (i >= 0 && i < n) { return nodes[i].name; } else { return ""; } 
}

// NOTE: Returns address; deallocation of returned object is dangerous
edge* graph::getNeighborList(const int i) { 
  if (i >= 0 && i < n) { return nodeLink[i]; } else { return NULL; } 
}

double* graph::getAdjacencyHist(const int i, const int j) {
  if (i >= 0 && i < n && j >= 0 && j < n) { 
    return A[i][j]; 
  } else { 
    return NULL; 
  }
}

// **********************************************************************

double graph::getAdjacencyAverage(const int i, const int j) {
  double average = 0.0;
  if (i != j) {
    for (int k=0; k<num_bins; k++) {
      if (A[i][j][k] > 0.0) { 
	average += (A[i][j][k] / total_weight)*((double)(k)*bin_resolution); 
      }
    }
  }
  return average;
}

int graph::numLinks() { return m; }

int graph::numNodes() { return n; }

double graph::getBinResolution() { return bin_resolution; }

int graph::getNumBins() { return num_bins; }

double graph::getTotalWeight() { return total_weight; }

// ***********************************************************************

void graph::resetAllAdjacencies() {
  for (int i=0; i<n; i++) { 
    for (int j=0; j<n; j++) { 
      for (int k=0; k<num_bins; k++) { 
	A[i][j][k] = 0.0; 
      } 
    } 
  }
  obs_count    = 0;
  total_weight = 0.0;
  return;
}

// **********************************************************************

void graph::resetAdjacencyHistogram(const int i, const int j) {
  if (i >= 0 && i < n && j >= 0 && j < n) { 
    for (int k=0; k<num_bins; k++) { 
      A[i][j][k] = 0.0; 
    } 
  }
  return;
}

// **********************************************************************

void graph::resetLinks() {
  edge *curr, *prev;
  for (int i=0; i<n; i++) {
    curr = nodeLink[i];
    while (curr != NULL) {
      prev = curr;
      curr = curr->next;
      delete prev;
    }
    nodeLink[i]     = NULL;
    nodeLinkTail[i] = NULL;
    nodes[i].degree = 0;
  }
  m = 0;
  return;
}

// **********************************************************************

void graph::setAdjacencyHistograms(const int bin_count) {
  // For all possible adjacencies, setup an edge histograms
  num_bins = bin_count+1;
  bin_resolution = 1.0 / (double)(bin_count);
  for (int i=0; i<n; i++) {
    for (int j=0; j<n; j++) {
      A[i][j] = new double [num_bins];
      for (int k=0; k<num_bins; k++) { A[i][j][k] = 0.0; }
    }
  }
  return;
}

bool graph::setName(const int i, const string text) { 
  if (i >= 0 && i < n) { 
    nodes[i].name = text; 
    return true; 
  } else { 
    return false; 
  } 
}

// **********************************************************************

interns::interns(const int n)  {
  q         = n;
  count     = 0;
  edgelist  = new ipair  [q];
  splitlist = new string [q+1];
  indexLUT  = new int*   [q+1];
  for (int i=0; i<(q+1); i++) {
    indexLUT[i]    = new int [2];
    indexLUT[i][0] = indexLUT[i][1] = -1;
  }
}
interns::~interns() {
  delete [] edgelist;
  delete [] splitlist;
  for (int i=0; i<(q+1); i++) { delete [] indexLUT[i]; }
  delete [] indexLUT;
}

// ***********************************************************************

// NOTE: Returns an address to another object -- do not deallocate
ipair* interns::getEdge(const int i) { return &edgelist[i]; }

// ***********************************************************************

// NOTE: Returns an address to another object -- do not deallocate
ipair* interns::getRandomEdge() { 
  return &edgelist[(int)(floor((double)(q)*RNG_UNIF01()))]; 
}

// ***********************************************************************

string interns::getSplit(const int i) { 
  if (i >= 0 && i <= q) { 
    return splitlist[i]; 
  } else { 
    return "";
  } 
}

// **********************************************************************

bool interns::addEdge(const int new_x, const int new_y, 
		      const short int new_type) {
  // This function adds a new edge (i,j,t,sp) to the list of internal
  // edges. After checking that the inputs fall in the appropriate
  // range of values, it records the new edgelist index in the
  // indexLUT and then puts the input values into that edgelist
  // location.

  if (count < q && new_x >= 0 && new_x < (q+1) && new_y >= 0 &&
      new_y < (q+2) && (new_type == LEFT || new_type == RIGHT)) {
    if (new_type == LEFT) { 
      indexLUT[new_x][0] = count; 
    } else { 
      indexLUT[new_x][1] = count; 
    }
    edgelist[count].x = new_x;
    edgelist[count].y = new_y;
    edgelist[count].t = new_type;
    count++;
    return true;
  } else { 
    return false; 
  }
}

// **********************************************************************

bool interns::replaceSplit(const int i, const string sp) {
  // When an internal edge is changed, its split must be replaced as
  // well. This function provides that access; it stores the split
  // defined by an internal edge (x,y) at the location [y], which
  // is unique.

  if (i >= 0 && i <= q) { splitlist[i] = sp; return true; }
  return false;
}

// ***********************************************************************

bool interns::swapEdges(const int one_x, const int one_y, 
			const short int one_type, const int two_x, 
			const int two_y, const short int two_type) {
  // The moves on the dendrogram always swap edges, either of which
  // (or both, or neither) can by internal edges. So, this function
  // mirrors that operation for the internal edgelist and indexLUT.
 
  int index, jndex, temp;
  bool one_isInternal = false;
  bool two_isInternal = false;
 
  if (one_x >= 0 && one_x < (q+1) && two_x >= 0 && two_x < (q+1) && 
      (two_type == LEFT || two_type == RIGHT) && 
      one_y >= 0 && one_y < (q+2) && two_y >= 0 && 
      two_y < (q+2) && (one_type == LEFT || one_type == RIGHT)) {
 
    if (one_type == LEFT) { temp = 0; } else { temp = 1; }
    if (indexLUT[one_x][temp] > -1) { one_isInternal = true; }
    if (two_type == LEFT) { temp = 0; } else { temp = 1; }
    if (indexLUT[two_x][temp] > -1) { two_isInternal = true; }
 
    if (one_isInternal && two_isInternal) {
      if (one_type == LEFT)  { 
	index = indexLUT[one_x][0]; } else { index = indexLUT[one_x][1]; 
      }
      if (two_type == LEFT)  { 
	jndex = indexLUT[two_x][0]; } else { jndex = indexLUT[two_x][1]; 
      }
      temp              = edgelist[index].y;
      edgelist[index].y = edgelist[jndex].y;
      edgelist[jndex].y = temp;
 
    } else if (one_isInternal) {
      if (one_type == LEFT)  { 
	index = indexLUT[one_x][0]; indexLUT[one_x][0] = -1; 
      } else { 
	index = indexLUT[one_x][1]; indexLUT[one_x][1] = -1; 
      }
      edgelist[index].x = two_x;
      edgelist[index].t = two_type;
      if (two_type == LEFT) { 
	indexLUT[two_x][0] = index; 
      } else { 
	indexLUT[two_x][1] = index; 
      } // add new
 
    } else if (two_isInternal) {
      if (two_type == LEFT)  { 
	index = indexLUT[two_x][0]; indexLUT[two_x][0] = -1;
      } else { 
	index = indexLUT[two_x][1]; indexLUT[two_x][1] = -1; 
      }
      edgelist[index].x = one_x;
      edgelist[index].t = one_type;
      if (one_type == LEFT) { 
	indexLUT[one_x][0] = index; 
      } else { 
	indexLUT[one_x][1] = index; 
      } // add new
    } else { 
      ;
    } // else neither is internal

    return true;
  } else { return false; }
}

// ******** Red-Black Tree Methods ***************************************

splittree::splittree() {
  root = new elementsp;
  leaf = new elementsp;

  leaf->parent   = root;

  root->left = leaf;
  root->right    = leaf;
  support = 0;
  total_weight = 0.0;
  total_count = 0;
}

splittree::~splittree() {
  if (root != NULL && (root->left != leaf || root->right != leaf)) { 
    deleteSubTree(root); root = NULL;
  }
  support      = 0;
  total_weight = 0.0;
  total_count  = 0;
  if (root) delete root;
  delete leaf;
  root    = NULL;
  leaf    = NULL;
}

void splittree::deleteTree() { 
  if (root != NULL) { deleteSubTree(root); root = NULL; } 
  return; 
}

void splittree::deleteSubTree(elementsp *z) {
  if (z->left  != leaf) { deleteSubTree(z->left); z->left = NULL; }
  if (z->right != leaf) { deleteSubTree(z->right); z->right = NULL; }
  delete z;
  /* No point in setting z to NULL here because z is passed by value */
  /* z = NULL; */
  return;
}

// ******** Reset Functions *********************************************

// O(n lg n)
void splittree::clearTree() {
  string *array = returnArrayOfKeys();
  for (int i=0; i<support; i++) { deleteItem(array[i]); }
  delete [] array;
  return;
}

// ******** Search Functions *********************************************
// public search function - if there exists a elementsp in the tree
// with key=searchKey, it returns TRUE and foundNode is set to point
// to the found node; otherwise, it sets foundNode=NULL and returns
// FALSE
elementsp* splittree::findItem(const string searchKey) {

  elementsp *current=root;
  if (current->split.empty()) { return NULL; } // empty tree; bail out
  while (current != leaf) {
    if (searchKey.compare(current->split) < 0) { // left-or-right?
      // try moving down-left
      if (current->left  != leaf) {
	current = current->left;  
      } else { 
	// failure; bail out
	return NULL; 
      }
    } else { 
      if (searchKey.compare(current->split) > 0) {
	// left-or-right?
	if (current->right != leaf) { 
	  // try moving down-left
	  current = current->right;  
	}
	else { 
	  //   failure; bail out
	  return NULL; 
	}
      } else { 
	// found (searchKey==current->split)
	return current; 
      }
    }
  }
  return NULL;
}

double splittree::returnValue(const string searchKey) {
  elementsp* test = findItem(searchKey);
  if (test == NULL) { return 0.0; } else { return test->weight; }
}


// ******** Return Item Functions ***************************************
// public function which returns the tree, via pre-order traversal, as
// a linked list

string* splittree::returnArrayOfKeys() {
  string* array;
  array = new string [support];
  bool flag_go = true;
  int index = 0;
  elementsp *curr;
 
  if (support == 1) { 
    array[0] = root->split; 
  } else if (support == 2) {
    array[0] = root->split;
    if (root->left == leaf) { 
      array[1] = root->right->split; 
    } else {
      array[1] = root->left->split; 
    }
  } else {
    for (int i=0; i<support; i++) { array[i] = -1; }
    // non-recursive traversal of tree structure
    curr  = root;
    curr->mark = 1;
    while (flag_go) {
 
      // - is it time, and is left child the leaf node?
      if (curr->mark == 1 && curr->left == leaf) {
	curr->mark = 2;
      }
      // - is it time, and is right child the leaf node?
      if (curr->mark == 2 && curr->right == leaf) {
	curr->mark = 3;
      }
      if (curr->mark == 1) {		       // - go left
	curr->mark = 2;
	curr = curr->left;
	curr->mark = 1;
      } else if (curr->mark == 2) {	       // - else go right
	curr->mark = 3;
	curr = curr->right;
	curr->mark = 1;
      } else {				       // - else go up a level
	curr->mark = 0;
	array[index++] = curr->split;
	curr = curr->parent;
	if (curr == NULL) { flag_go = false; }
      }
    }
  }
 
  return array;
}

slist* splittree::returnListOfKeys() {
  keyValuePairSplit *curr, *prev;
  slist *head = NULL, *tail = NULL, *newlist;

  curr = returnTreeAsList();
  while (curr != NULL) {
    newlist = new slist;
    newlist->x = curr->x;
    if (head == NULL) { 
      head = newlist; tail = head;    
    } else { 
      tail->next = newlist; tail = newlist; 
    }
    prev = curr;
    curr = curr->next;
    delete prev;
    prev = NULL;
  }
  return head;
}

 // pre-order traversal
keyValuePairSplit* splittree::returnTreeAsList() {
  keyValuePairSplit  *head, *tail;

  head    = new keyValuePairSplit;
  head->x = root->split;
  head->y = root->weight;
  head->c = root->count;
  tail    = head;

  if (root->left  != leaf) { tail = returnSubtreeAsList(root->left,  tail); }
  if (root->right != leaf) { tail = returnSubtreeAsList(root->right, tail); }
 
  if (head->x.empty()) { return NULL; /* empty tree */ } else { return head; }
}

keyValuePairSplit* splittree::returnSubtreeAsList(elementsp *z,
						  keyValuePairSplit *head) {
  keyValuePairSplit *newnode, *tail;
 
  newnode    = new keyValuePairSplit;
  newnode->x = z->split;
  newnode->y = z->weight;
  newnode->c = z->count;
  head->next = newnode;
  tail       = newnode;
 
  if (z->left  != leaf) { tail = returnSubtreeAsList(z->left,  tail); }
  if (z->right != leaf) { tail = returnSubtreeAsList(z->right, tail); }
 
  return tail;
}

keyValuePairSplit splittree::returnMaxKey() {
  keyValuePairSplit themax;
  elementsp *current;
  current = root;
  // search to bottom-right corner of tree
  while (current->right != leaf) {
    current = current->right; 
  }
  themax.x = current->split;
  themax.y = current->weight;
 
  return themax;
}

keyValuePairSplit splittree::returnMinKey() {
  keyValuePairSplit themin;
  elementsp *current;
  current = root;
  // search to bottom-left corner of tree
  while (current->left != leaf) {
    current = current->left; 
  }
  themin.x = current->split;
  themin.y = current->weight;
 
  return themin;
}

// private functions for deleteItem() (although these could easily be
// made public, I suppose)
elementsp* splittree::returnMinKey(elementsp *z) {
  elementsp *current;

  current = z;
  // search to bottom-right corner of tree
  while (current->left != leaf) {
    current = current->left; 
  }
  // return pointer to the minimum
  return current;
}

elementsp* splittree::returnSuccessor(elementsp *z) {
  elementsp *current, *w;
 
  w = z;
 // if right-subtree exists, return min of it
  if (w->right != leaf) {
    return returnMinKey(w->right); 
  }
  // else search up in tree
  // move up in tree until find a non-right-child
  current = w->parent;
  while ((current!=NULL) && (w==current->right)) {
    w = current;
    current = current->parent;
  }
  return current;
}

int splittree::returnNodecount() { return support; }

keyValuePairSplit* splittree::returnTheseSplits(const int target) {
  keyValuePairSplit *head, *curr, *prev, *newhead, *newtail, *newpair;
  int count, len;
 
  head = returnTreeAsList();
  prev = newhead = newtail = newpair = NULL;
  curr = head;
 
  while (curr != NULL) {
    count = 0;
    len   = curr->x.size();
    for (int i=0; i<len; i++) { if (curr->x[i] == 'M') { count++; } }
    if (count == target && curr->x[1] != '*') {
      newpair       = new keyValuePairSplit;
      newpair->x    = curr->x;
      newpair->y    = curr->y;
      newpair->next = NULL;
      if (newhead == NULL) { 
	newhead = newpair; newtail = newpair; 
      } else {
	newtail->next = newpair; newtail = newpair; 
      }
    }
    prev = curr;
    curr = curr->next;
    delete prev;
    prev = NULL;
  }
 
  return newhead;
}

double splittree::returnTotal() { return total_weight; }

// ******** Insert Functions *********************************************

void splittree::finishedThisRound() {
  // We need to also keep a running total of how much weight has been
  // added to the histogram.
  if (total_count == 0) { 
    total_weight  = 1.0; total_count = 1; 
  } else { 
    total_weight += 1.0; total_count++; 
  }
  return;
} 

// public insert function
bool splittree::insertItem(string newKey, double newValue) {
 
  // first we check to see if newKey is already present in the tree;
  // if so, we do nothing; if not, we must find where to insert the
  // key
  elementsp *newNode, *current;
 
 // find newKey in tree; return pointer to it O(log k)
  current = findItem(newKey);
  if (current != NULL) {
    current->weight += 1.0;
    // And finally, we keep track of how many observations went into
    // the histogram 
    current->count++;
    return true;
  } else {
    newNode = new elementsp;	// elementsp for the splittree
    newNode->split = newKey;	//  store newKey
    newNode->weight = newValue;	//  store newValue
    newNode->color = true;	//  new nodes are always RED
    newNode->parent = NULL;	//  new node initially has no parent
    newNode->left = leaf;	//  left leaf
    newNode->right = leaf;	//  right leaf
    newNode->count = 1;
    support++;			// increment node count in splittree
 
    // must now search for where to insert newNode, i.e., find the
    // correct parent and set the parent and child to point to each
    // other properly 
    current = root;
    if (current->split.empty()) {	// insert as root
      delete root;		//   delete old root
      root = newNode;		//   set root to newNode
      leaf->parent   = newNode; //   set leaf's parent
      current = leaf;		//   skip next loop
    }
 
    // search for insertion point
    while (current != leaf) {
      // left-or-right?
      if (newKey.compare(current->split) < 0) {
	// try moving down-left
	if (current->left  != leaf) { 
	  current = current->left;  
	} else {
	  // else found new parent
	  newNode->parent = current; // set parent
	  current->left = newNode;   // set child
	  current = leaf;	     // exit search
	}
      } else { // 
	if (current->right != leaf) { 
	  // try moving down-right
	  current = current->right; 
	} else {
	  // else found new parent
	  newNode->parent = current; // set parent
	  current->right = newNode;  // set child
	  current = leaf;	     // exit search
	}
      }
    }

    // now do the house-keeping necessary to preserve the red-black
    // properties 
    insertCleanup(newNode);
 
  }
  return true;
}

// private house-keeping function for insertion
void splittree::insertCleanup(elementsp *z) {
 
  // fix now if z is root
  if (z->parent==NULL) {
    z->color = false; return; 
  }
  elementsp *temp;
  // while z is not root and z's parent is RED
  while (z->parent!=NULL && z->parent->color) {
    if (z->parent == z->parent->parent->left) {  // z's parent is LEFT-CHILD
      temp = z->parent->parent->right;		 // grab z's uncle
      if (temp->color) {
	z->parent->color = false;          // color z's parent BLACK (Case 1)
	temp->color = false;	           // color z's uncle BLACK  (Case 1)
	z->parent->parent->color = true;   // color z's grandpa  RED (Case 1)
	z = z->parent->parent;	           // set z = z's grandpa    (Case 1)
      } else {
	if (z == z->parent->right) {       // z is RIGHT-CHILD
	  z = z->parent;                   // set z = z's parent     (Case 2)
	  rotateLeft(z);                   // perform left-rotation  (Case 2)
	}
	z->parent->color = false;          // color z's parent BLACK (Case 3)
	z->parent->parent->color = true;   // color z's grandpa RED  (Case 3)
	rotateRight(z->parent->parent);    // perform right-rotation (Case 3)
      }
    } else {			           // z's parent is RIGHT-CHILD
      temp = z->parent->parent->left;      // grab z's uncle
      if (temp->color) {
	z->parent->color = false;          // color z's parent BLACK (Case 1)
	temp->color = false;               // color z's uncle BLACK  (Case 1)
	z->parent->parent->color = true;   // color z's grandpa RED  (Case 1)
	z = z->parent->parent;             // set z = z's grandpa    (Case 1)
      } else {
	if (z == z->parent->left) {        // z is LEFT-CHILD
	  z = z->parent;                   // set z = z's parent     (Case 2)
	  rotateRight(z);                  // perform right-rotation (Case 2)
	}
	z->parent->color = false;          // color z's parent BLACK (Case 3)
	z->parent->parent->color = true;   // color z's grandpa RED  (Case 3)
	rotateLeft(z->parent->parent);     // perform left-rotation  (Case 3)
      }
    }
  }

  root->color = false; // color the root BLACK
  return;
}

// ******** Delete Functions ********************************************
// public delete function
void splittree::deleteItem(string killKey) {
  elementsp *x, *y, *z;
 
  z = findItem(killKey);
  if (z == NULL) { return; }	// item not present; bail out

  if (support==1) {		// -- attempt to delete the root
    root->split = "";		// restore root node to default state
    root->weight = 0.0;		// 
    root->color = false;	// 
    root->parent = NULL;	// 
    root->left = leaf;		// 
    root->right = leaf;		// 
    support--;			// set support to zero
    total_weight = 0.0;		// set total weight to zero
    total_count--;		// 
    return;			// exit - no more work to do
  }
 
  if (z != NULL) {
    support--;			// decrement node count
    if ((z->left == leaf) || (z->right==leaf)) { 
      // case of less than two children
      y = z; 			 // set y to be z
    } else { 
      y = returnSuccessor(z); 	 // set y to be z's key-successor
    } 
 
    if (y->left!=leaf) { 
      x = y->left;	 	 // pick y's one child (left-child)
    } else { 
      x = y->right;              // (right-child)
    } 
    x->parent = y->parent;       // make y's child's parent be y's parent

    if (y->parent==NULL) { 
      root = x;			 // if y is the root, x is now root
    } else {
      if (y == y->parent->left) {// decide y's relationship with y's parent
	y->parent->left  = x;    // replace x as y's parent's left child
      } else {
	y->parent->right = x; }  // replace x as y's parent's left child
    }

    if (y!=z) {			 // insert y into z's spot
      z->split = y->split;	 // copy y data into z
      z->weight = y->weight;	 // 
      z->count = y->count;	 // 
    }				 // 

    // do house-keeping to maintain balance
    if (y->color==false) { deleteCleanup(x); }
    delete y;			 // deallocate y
    y = NULL;			 // point y to NULL for safety
  }				 // 
 
  return;
}

void splittree::deleteCleanup(elementsp *x) {
  elementsp *w, *t;
  // until x is the root, or x is RED
  while ((x != root) && (x->color==false)) {
    if (x==x->parent->left) {	     // branch on x being a LEFT-CHILD
      w = x->parent->right;	     // grab x's sibling
      if (w->color==true) {	     // if x's sibling is RED
	w->color = false;	     // color w BLACK                (case 1)
	x->parent->color = true;     // color x's parent RED         (case 1)
	rotateLeft(x->parent);       // left rotation on x's parent  (case 1)
	w = x->parent->right;        // make w be x's right sibling  (case 1)
      }
      if ((w->left->color==false) && (w->right->color==false)) {
	w->color = true;	     // color w RED                  (case 2)
	x = x->parent;		     // examine x's parent           (case 2)
      } else {			     // 
	if (w->right->color==false) {
	  w->left->color = false;    // color w's left child BLACK   (case 3)
	  w->color = true;	     // color w RED                  (case 3)
	  t = x->parent;	     // store x's parent
	  rotateRight(w);	     // right rotation on w          (case 3)
	  x->parent = t;	     // restore x's parent
	  w = x->parent->right;      // make w be x's right sibling  (case 3)
	} // 
	w->color = x->parent->color; // w's color := x's parent's    (case 4)
	x->parent->color    = false; // color x's parent BLACK       (case 4)
	w->right->color = false;     // color w's right child BLACK  (case 4)
	rotateLeft(x->parent);       // left rotation on x's parent  (case 4)
	x = root;		     // finished work. bail out      (case 4)
      }				     // 
    } else {			     // x is RIGHT-CHILD
      w = x->parent->left;	     // grab x's sibling
      if (w->color==true) {	     // if x's sibling is RED
	w->color = false;	     // color w BLACK                (case 1)
	x->parent->color    = true;  // color x's parent RED         (case 1)
	rotateRight(x->parent);      // right rotation on x's parent (case 1)
	w = x->parent->left;         // make w be x's left sibling   (case 1)
      }
      if ((w->right->color==false) && (w->left->color==false)) {
	w->color = true;	     // color w RED                  (case 2)
	x= x->parent;		     // examine x's parent           (case 2)
      } else { // 
	if (w->left->color==false) { // 
	  w->right->color = false;   // color w's right child BLACK  (case 3)
	  w->color = true;	     // color w RED                  (case 3)
	  t = x->parent;	     // store x's parent
	  rotateLeft(w);	     // left rotation on w           (case 3)
	  x->parent = t;	     // restore x's parent
	  w = x->parent->left;	     // make w be x's left sibling   (case 3)
	} // 
	w->color = x->parent->color; // w's color := x's parent's    (case 4)
	x->parent->color    = false; // color x's parent BLACK       (case 4)
	w->left->color = false;      // color w's left child BLACK   (case 4)
	rotateRight(x->parent);      // right rotation on x's parent (case 4)
	x = root;                    // x is now the root            (case 4)
      }
    }
  }
  x->color = false;	   	     // color x (the root) BLACK (exit)

  return;
}

// ******** Rotation Functions *******************************************

void splittree::rotateLeft(elementsp *x) {
  elementsp *y;
  // do pointer-swapping operations for left-rotation
  y = x->right;		        // grab right child
  x->right = y->left;	        // make x's RIGHT-CHILD be y's LEFT-CHILD
  y->left->parent = x;	        // make x be y's LEFT-CHILD's parent
  y->parent = x->parent;        // make y's new parent be x's old parent

  if (x->parent==NULL) {
    root = y;		        // if x was root, make y root
  } else {		        // 
    if (x == x->parent->left) { // if x is LEFT-CHILD, make y be x's parent's
      x->parent->left  = y;	// left-child
    } else {
      x->parent->right = y;	// right-child
    }
  }
  y->left   = x;		// make x be y's LEFT-CHILD
  x->parent = y;		// make y be x's parent
 
  return;
}

void splittree::rotateRight(elementsp *y) {
  elementsp *x;
  // do pointer-swapping operations for right-rotation
  x = y->left;		         // grab left child
  y->left = x->right;	         // replace left child yith x's right subtree
  x->right->parent = y;	         // replace y as x's right subtree's parent
 
  x->parent = y->parent;         // make x's new parent be y's old parent
  if (y->parent==NULL) { 
    root = x;		 	 // if y was root, make x root
  } else {
    if (y == y->parent->right) { // if y is R-CHILD, make x be y's parent's
      y->parent->right = x;	 // right-child
    } else { 
      y->parent->left = x;	 // left-child
    }
  }
  x->right  = y;		 // make y be x's RIGHT-CHILD
  y->parent = x;		 // make x be y's parent
 
  return;
}

// ***********************************************************************
// *** COPYRIGHT NOTICE **************************************************
// graph_simp.h - graph data structure
// Copyright (C) 2006-2008 Aaron Clauset
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 
// See http://www.gnu.org/licenses/gpl.txt for more details.
// 
// ***********************************************************************
// Author       : Aaron Clauset  ( aaronc@santafe.edu |
//                                 http://www.santafe.edu/~aaronc/ ) 
// Collaborators: Cristopher Moore and Mark E.J. Newman
// Project      : Hierarchical Random Graphs
// Location     : University of New Mexico, Dept. of Computer Science
//                AND Santa Fe Institute 
// Created      : 21 June 2006
// Modified     : 23 December 2007 (cleaned up for public consumption)
//
// ************************************************************************

// ******** Constructor / Destructor *************************************

simpleGraph::simpleGraph(const int size): n(size), m(0), num_groups(0) {
  nodes = new simpleVert  [n];
  nodeLink = new simpleEdge* [n];
  nodeLinkTail = new simpleEdge* [n];
  A = new double* [n];
  for (int i=0; i<n; i++) {
    nodeLink[i] = NULL; nodeLinkTail[i] = NULL;
    A[i] = new double [n];
    for (int j=0; j<n; j++) { A[i][j] = 0.0; }
  }
  E = NULL;
}

simpleGraph::~simpleGraph() {
  simpleEdge *curr, *prev;
  for (int i=0; i<n; i++) {
    curr = nodeLink[i];
    delete [] A[i];
    while (curr != NULL) {
      prev = curr;
      curr = curr->next;
      delete prev;
    }
  }
  curr = NULL; prev = NULL;
  if (E != NULL) { delete [] E; E = NULL; }
  delete [] A; A = NULL;
  delete [] nodeLink; nodeLink = NULL;
  delete [] nodeLinkTail;  nodeLinkTail   = NULL;
  delete [] nodes; nodes = NULL;
}

// ***********************************************************************

bool simpleGraph::addGroup(const int i, const int group_index) {
  if (i >= 0 && i < n) {
    nodes[i].group_true = group_index;
    return true;
  } else { 
    return false; 
  }
}

// ***********************************************************************

bool simpleGraph::addLink(const int i, const int j) {
  // Adds the directed edge (i,j) to the adjacency list for v_i
  simpleEdge* newedge;
  if (i >= 0 && i < n && j >= 0 && j < n) {
    A[i][j] = 1.0;
    newedge  = new simpleEdge;
    newedge->x = j;
    if (nodeLink[i] == NULL) {	// first neighbor
      nodeLink[i]  = newedge;
      nodeLinkTail[i] = newedge;
      nodes[i].degree = 1;
    } else {			// subsequent neighbor
      nodeLinkTail[i]->next = newedge;
      nodeLinkTail[i]       = newedge;
      nodes[i].degree++;
    }
    m++;			// increment edge count
    newedge = NULL;
    return true;
  } else { return false; }
}

// ***********************************************************************

bool simpleGraph::doesLinkExist(const int i, const int j) {
  // This function determines if the edge (i,j) already exists in the
  // adjacency list of v_i
  if (i >= 0 && i < n && j >= 0 && j < n) { 
    if (A[i][j] > 0.1) {
      return true; 
    } else { 
      return false; 
    } 
  } else { 
    return false; 
  }
  return false;
}

// **********************************************************************

double simpleGraph::getAdjacency(const int i, const int j) {
  if (i >= 0 && i < n && j >= 0 && j < n) { 
    return A[i][j]; 
  } else { 
    return -1.0; 
  } 
}

int simpleGraph::getDegree(const int i) { 
  if (i >= 0 && i < n) {
    return nodes[i].degree;
  } else {
    return -1; 
  }
}

int simpleGraph::getGroupLabel(const int i) {
  if (i >= 0 && i < n) {
    return nodes[i].group_true;
  } else {
    return -1; 
  }
}

string simpleGraph::getName(const int i) { 
  if (i >= 0 && i < n) {
    return nodes[i].name;
  } else {
    return ""; 
  }
}

// NOTE: The following three functions return addresses; deallocation
// of returned object is dangerous 
simpleEdge* simpleGraph::getNeighborList(const int i) {
  if (i >= 0 && i < n) {
    return nodeLink[i];
  } else {
    return NULL; 
  }
}
// END-NOTE

// *********************************************************************

int simpleGraph::getNumGroups() { return num_groups; }
int simpleGraph::getNumLinks()  { return m; }
int simpleGraph::getNumNodes()  { return n; }
simpleVert* simpleGraph::getNode(const int i) { 
  if (i >= 0 && i<n) { 
    return &nodes[i];
  } else {
    return NULL;
  }
}

// **********************************************************************

bool simpleGraph::setName(const int i, const string text) {
  if (i >= 0 && i < n) { 
    nodes[i].name = text;
    return true; 
  } else {
    return false;
  }
}

// **********************************************************************

void simpleGraph::QsortMain (block* array, int left, int right) {
  if (right > left) {
    int pivot = left;
    int part  = QsortPartition(array, left, right, pivot);
    QsortMain(array, left,   part-1);
    QsortMain(array, part+1, right  );
  }
  return;
}

int simpleGraph::QsortPartition (block* array, int left, int right,
				 int index) {
  block p_value, temp;
  p_value.x = array[index].x;
  p_value.y = array[index].y;
 
  // swap(array[p_value], array[right])
  temp.x = array[right].x;
  temp.y = array[right].y;
  array[right].x = array[index].x;
  array[right].y = array[index].y;
  array[index].x = temp.x;
  array[index].y = temp.y;
 
  int stored = left;
  for (int i=left; i<right; i++) {
    if (array[i].x <= p_value.x) {
      // swap(array[stored], array[i])
      temp.x = array[i].x;
      temp.y = array[i].y;
      array[i].x = array[stored].x;
      array[i].y = array[stored].y;
      array[stored].x = temp.x;
      array[stored].y = temp.y;
      stored++;
    }
  }
  // swap(array[right], array[stored])
  temp.x = array[stored].x;
  temp.y = array[stored].y;
  array[stored].x = array[right].x;
  array[stored].y = array[right].y;
  array[right].x = temp.x; 
  array[right].y = temp.y;
 
  return stored;
}

// ***********************************************************************
