afa49f8318fdcd16205bc6cbc55d293d208fc5bd
angie
  Tue May 10 11:37:29 2011 -0700
Feature #3711 bugfix: handle 0 or 1 items correctly in hacTree andVCF track handler's haplotype clustering.

diff --git src/lib/hacTree.c src/lib/hacTree.c
index eda012f..f7e4bdc 100644
--- src/lib/hacTree.c
+++ src/lib/hacTree.c
@@ -52,33 +52,36 @@
     leafWraps[i].node = &(leafNodes[i]);
     leafWraps[i].cmpF = cmpF;
     leafWraps[i].extraData = extraData;
     }
 qsort(leafWraps, itemCount, sizeof(struct sortWrapper), sortWrapCmp);
 return leafWraps;
 }
 
 INLINE void initNode(struct hacTree *node, const struct hacTree *left, const struct hacTree *right,
 		     hacDistanceFunction *distF, hacMergeFunction *mergeF, void *extraData)
 /* Initialize node to have left and right as its children.  Leave parent pointers
  * alone -- they would be unstable during tree construction. */
 {
 node->left = (struct hacTree *)left;
 node->right = (struct hacTree *)right;
+if (left != NULL && right != NULL)
+    {
 node->childDistance = distF(left->itemOrCluster, right->itemOrCluster, extraData);
 node->itemOrCluster = mergeF(left->itemOrCluster, right->itemOrCluster, extraData);
 }
+}
 
 INLINE struct hacTree preClusterNodes(const struct sortWrapper *leafWraps, int i, int runLength,
 				      hacDistanceFunction *distF, hacMergeFunction *mergeF,
 				      void *extraData, struct lm *localMem)
 /* Caller has allocated a node, and this returns what to store there:
  * a recursively constructed cluster of nodes extracted from wrapped
  * leafNodes (leafWraps) starting at i, for runLength items. */
 {
 struct hacTree ret = {NULL, NULL, NULL, NULL, 0, NULL};
 if (runLength > 2)
     {
     struct hacTree *newClusters = lmAlloc(localMem, 2 * sizeof(struct hacTree));
     int halfLength = runLength/2;
     newClusters[0] = preClusterNodes(leafWraps, i, halfLength,
 				     distF, mergeF, extraData, localMem);
@@ -123,36 +126,42 @@
 return newLeaves;
 }
 
 static struct hacTree *pairUpItems(const struct slList *itemList, int itemCount,
 				   int *retPairCount, struct lm *localMem,
 				   hacDistanceFunction *distF, hacMergeFunction *mergeF,
 				   hacCmpFunction *cmpF, void *extraData)
 /* Allocate & initialize leaf nodes and all possible pairings of leaf nodes
  * which will be our seed clusters.  If cmpF is given, pre-sort the leaf nodes
  * and pre-cluster identical leaves before generating seed clusters. */
 {
 struct hacTree *leafNodes = leafNodesFromItems(itemList, itemCount, localMem);
 if (cmpF != NULL)
     leafNodes = sortAndPreCluster(leafNodes, &itemCount, localMem,
 				  distF, mergeF, cmpF, extraData);
-int pairCount = itemCount * (itemCount-1) / 2;
+int pairCount = (itemCount == 1) ? 1 : (itemCount * (itemCount-1) / 2);
 struct hacTree *pairPool = lmAlloc(localMem, pairCount * sizeof(struct hacTree));
+if (itemCount == 1)
+    initNode(pairPool, leafNodes, NULL, distF, mergeF, extraData);
+else
+    {
 int i, j, pairIx;
 for (i=0, pairIx=0;  i < itemCount-1;  i++)
     for (j=i+1;  j < itemCount;  j++, pairIx++)
-	initNode(&(pairPool[pairIx]), &(leafNodes[i]), &(leafNodes[j]), distF, mergeF, extraData);
+	    initNode(&(pairPool[pairIx]), &(leafNodes[i]), &(leafNodes[j]), distF, mergeF,
+		     extraData);
+    }
 *retPairCount = pairCount;
 return pairPool;
 }
 
 struct hacTree *hacTreeFromItems(const struct slList *itemList, struct lm *localMem,
 				 hacDistanceFunction *distF, hacMergeFunction *mergeF,
 				 hacCmpFunction *cmpF, void *extraData)
 /* Using distF, mergeF, optionally cmpF and binary tree operations,
  * perform a hierarchical agglomerative (bottom-up) clustering of
  * items.  To free the resulting tree, lmCleanup(&localMem). */
 //
 // Implementation:
 //
 // Create a pool containing all pairs of items (N*(N-1)/2), and build
 // a hierarchical binary tree of items from the bottom up.  In each