/*
* ClusteringTree.java
*
* Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
*
* This file is part of BEAST.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package dr.evolution.tree;
import dr.evolution.distance.DistanceMatrix;
/**
* An abstract base class for clustering algorithms from pairwise distances
*
* @version $Id: ClusteringTree.java,v 1.8 2005/05/24 20:25:56 rambaut Exp $
*
* @author Andrew Rambaut
* @author Alexei Drummond
*/
public abstract class ClusteringTree extends SimpleTree {
/**
* constructor ClusteringTree
*
* @param distanceMatrix distance matrix
*/
public ClusteringTree(DistanceMatrix distanceMatrix, int minimumTaxa) {
this.distanceMatrix = distanceMatrix;
if (distanceMatrix.getTaxonCount() < minimumTaxa) {
throw new IllegalArgumentException("less than " + minimumTaxa + " taxa in distance matrix");
}
init(distanceMatrix);
while (true) {
findNextPair();
if (numClusters < minimumTaxa)
break;
newCluster();
}
finish();
}
//
// Protected and Private stuff
//
protected double getDist(int a, int b) {
return distance[alias[a]][alias[b]];
}
protected void init(DistanceMatrix distanceMatrix) {
numClusters = distanceMatrix.getTaxonCount();
clusters = new SimpleNode[numClusters];
distance = new double[numClusters][numClusters];
for (int i = 0; i < numClusters; i++) {
for (int j = 0; j < numClusters; j++) {
distance[i][j] = distanceMatrix.getElement(i, j);
}
}
for (int i = 0; i < numClusters; i++) {
clusters[i] = new SimpleNode();
clusters[i].setTaxon(distanceMatrix.getTaxon(i));
}
alias = new int[numClusters];
tipCount = new int[numClusters];
for (int i = 0; i < numClusters; i++) {
alias[i] = i;
tipCount[i] = 1;
}
}
protected void newCluster() {
newCluster = new SimpleNode();
newCluster.setHeight(newNodeHeight());
newCluster.addChild(clusters[abi]);
newCluster.addChild(clusters[abj]);
clusters[abi] = newCluster;
clusters[abj] = null;
// Update distances
for (int k = 0; k < numClusters; k++) {
if (k != besti && k != bestj) {
int ak = alias[k];
distance[ak][abi] = distance[abi][ak] = updatedDistance(besti, bestj, k);
distance[ak][abj] = distance[abj][ak] = -1.0;
}
}
distance[abi][abi] = 0.0;
distance[abj][abj] = -1.0;
// Update alias
for (int i = bestj; i < numClusters-1; i++) {
alias[i] = alias[i+1];
}
tipCount[abi] += tipCount[abj];
tipCount[abj] = 0;
numClusters--;
}
protected void finish() {
adoptNodes(newCluster);
distance = null;
}
protected abstract void findNextPair();
protected abstract double newNodeHeight();
protected abstract double updatedDistance(int i, int j, int k);
protected DistanceMatrix distanceMatrix;
protected int numClusters;
protected SimpleNode[] clusters;
protected SimpleNode newCluster;
protected int besti, abi;
protected int bestj, abj;
protected int[] tipCount;
protected int[] alias;
protected double[][] distance;
protected int minimumTaxa;
}