JAL-4134 catch NPE - though in principle this should never happen…
[jalview.git] / src / jalview / analysis / TreeBuilder.java
index 6d5b0fe..61f65ff 100644 (file)
@@ -1,59 +1,49 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview 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 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview 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 Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
 package jalview.analysis;
 
-import jalview.api.analysis.DistanceScoreModelI;
 import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.SimilarityParamsI;
-import jalview.api.analysis.SimilarityScoreModelI;
 import jalview.datamodel.AlignmentView;
+import jalview.datamodel.BinaryNode;
 import jalview.datamodel.CigarArray;
 import jalview.datamodel.SeqCigar;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.SequenceNode;
-import jalview.math.MatrixI;
 import jalview.viewmodel.AlignmentViewport;
 
 import java.util.BitSet;
 import java.util.Vector;
 
-public abstract class TreeBuilder
+public abstract class TreeBuilder extends TreeEngine
 {
   public static final String AVERAGE_DISTANCE = "AV";
 
   public static final String NEIGHBOUR_JOINING = "NJ";
 
-  protected Vector<BitSet> clusters;
-
   protected SequenceI[] sequences;
 
   public AlignmentView seqData;
 
-  protected BitSet done;
-
-  protected int noseqs;
-
-  int noClus;
-
-  protected MatrixI distances;
-
-  protected int mini;
-
-  protected int minj;
-
-  protected double ri;
-
-  protected double rj;
-
-  SequenceNode maxdist;
-
-  SequenceNode top;
-
-  double maxDistValue;
-
-  double maxheight;
-
-  int ycount;
-
-  Vector<SequenceNode> node;
+  private AlignmentView seqStrings;
 
   /**
    * Constructor
@@ -68,7 +58,7 @@ public abstract class TreeBuilder
     int start, end;
     boolean selview = av.getSelectionGroup() != null
             && av.getSelectionGroup().getSize() > 1;
-    AlignmentView seqStrings = av.getAlignmentView(selview);
+    seqStrings = av.getAlignmentView(selview);
     if (!selview)
     {
       start = 0;
@@ -79,8 +69,8 @@ public abstract class TreeBuilder
     {
       start = av.getSelectionGroup().getStartRes();
       end = av.getSelectionGroup().getEndRes() + 1;
-      this.sequences = av.getSelectionGroup().getSequencesInOrder(
-              av.getAlignment());
+      this.sequences = av.getSelectionGroup()
+              .getSequencesInOrder(av.getAlignment());
     }
 
     init(seqStrings, start, end);
@@ -94,115 +84,6 @@ public abstract class TreeBuilder
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param nd
-   *          DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
-  double findHeight(SequenceNode nd)
-  {
-    if (nd == null)
-    {
-      return maxheight;
-    }
-  
-    if ((nd.left() == null) && (nd.right() == null))
-    {
-      nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
-  
-      if (nd.height > maxheight)
-      {
-        return nd.height;
-      }
-      else
-      {
-        return maxheight;
-      }
-    }
-    else
-    {
-      if (nd.parent() != null)
-      {
-        nd.height = ((SequenceNode) nd.parent()).height + nd.dist;
-      }
-      else
-      {
-        maxheight = 0;
-        nd.height = (float) 0.0;
-      }
-  
-      maxheight = findHeight((SequenceNode) (nd.left()));
-      maxheight = findHeight((SequenceNode) (nd.right()));
-    }
-  
-    return maxheight;
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param nd
-   *          DOCUMENT ME!
-   */
-  void reCount(SequenceNode nd)
-  {
-    ycount = 0;
-    // _lycount = 0;
-    // _lylimit = this.node.size();
-    _reCount(nd);
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param nd
-   *          DOCUMENT ME!
-   */
-  void _reCount(SequenceNode nd)
-  {
-    // if (_lycount<_lylimit)
-    // {
-    // System.err.println("Warning: depth of _recount greater than number of nodes.");
-    // }
-    if (nd == null)
-    {
-      return;
-    }
-    // _lycount++;
-  
-    if ((nd.left() != null) && (nd.right() != null))
-    {
-  
-      _reCount((SequenceNode) nd.left());
-      _reCount((SequenceNode) nd.right());
-  
-      SequenceNode l = (SequenceNode) nd.left();
-      SequenceNode r = (SequenceNode) nd.right();
-  
-      nd.count = l.count + r.count;
-      nd.ycount = (l.ycount + r.ycount) / 2;
-    }
-    else
-    {
-      nd.count = 1;
-      nd.ycount = ycount++;
-    }
-    // _lycount--;
-  }
-
-  /**
-   * DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
-  public SequenceNode getTopNode()
-  {
-    return top;
-  }
-
-  /**
    * 
    * @return true if tree has real distances
    */
@@ -226,34 +107,6 @@ public abstract class TreeBuilder
   }
 
   /**
-   * Form clusters by grouping sub-clusters, starting from one sequence per
-   * cluster, and finishing when only two clusters remain
-   */
-  void cluster()
-  {
-    while (noClus > 2)
-    {
-      findMinDistance();
-  
-      joinClusters(mini, minj);
-  
-      noClus--;
-    }
-  
-    int rightChild = done.nextClearBit(0);
-    int leftChild = done.nextClearBit(rightChild + 1);
-  
-    joinClusters(leftChild, rightChild);
-    top = (node.elementAt(leftChild));
-  
-    reCount(top);
-    findHeight(top);
-    findMaxDist(top);
-  }
-
-  protected abstract double findMinDistance();
-
-  /**
    * Calculates the tree using the given score model and parameters, and the
    * configured tree type
    * <p>
@@ -268,93 +121,18 @@ public abstract class TreeBuilder
    */
   protected void computeTree(ScoreModelI sm, SimilarityParamsI scoreOptions)
   {
-    if (sm instanceof DistanceScoreModelI)
-    {
-      distances = ((DistanceScoreModelI) sm).findDistances(seqData,
-              scoreOptions);
-    }
-    else if (sm instanceof SimilarityScoreModelI)
-    {
-      /*
-       * compute similarity and invert it to give a distance measure
-       * reverseRange(true) converts maximum similarity to zero distance
-       */
-      MatrixI result = ((SimilarityScoreModelI) sm).findSimilarities(
-              seqData, scoreOptions);
-      result.reverseRange(true);
-      distances = result;
-    }
-  
+    distances = sm.findDistances(seqData, scoreOptions);
+
     makeLeaves();
-  
-    noClus = clusters.size();
-  
-    cluster();
-  }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param nd
-   *          DOCUMENT ME!
-   */
-  void findMaxDist(SequenceNode nd)
-  {
-    if (nd == null)
-    {
-      return;
-    }
-  
-    if ((nd.left() == null) && (nd.right() == null))
-    {
-      double dist = nd.dist;
-  
-      if (dist > maxDistValue)
-      {
-        maxdist = nd;
-        maxDistValue = dist;
-      }
-    }
-    else
-    {
-      findMaxDist((SequenceNode) nd.left());
-      findMaxDist((SequenceNode) nd.right());
-    }
-  }
+    noClus = clusters.size();
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param i
-   *          DOCUMENT ME!
-   * @param j
-   *          DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
-  protected double findr(int i, int j)
-  {
-    double tmp = 1;
-  
-    for (int k = 0; k < noseqs; k++)
-    {
-      if ((k != i) && (k != j) && (!done.get(k)))
-      {
-        tmp = tmp + distances.getValue(i, k);
-      }
-    }
-  
-    if (noClus > 2)
-    {
-      tmp = tmp / (noClus - 2);
-    }
-  
-    return tmp;
+    cluster();
   }
 
   protected void init(AlignmentView seqView, int start, int end)
   {
-    this.node = new Vector<SequenceNode>();
+    this.node = new Vector<BinaryNode>();
     if (seqView != null)
     {
       this.seqData = seqView;
@@ -370,14 +148,14 @@ public abstract class TreeBuilder
       sdata.addOperation(CigarArray.M, end - start + 1);
       this.seqData = new AlignmentView(sdata, start);
     }
-  
+
     /*
      * count the non-null sequences
      */
     noseqs = 0;
-  
+
     done = new BitSet();
-  
+
     for (SequenceI seq : sequences)
     {
       if (seq != null)
@@ -388,68 +166,16 @@ public abstract class TreeBuilder
   }
 
   /**
-   * Merges cluster(j) to cluster(i) and recalculates cluster and node distances
-   * 
-   * @param i
-   * @param j
-   */
-  void joinClusters(final int i, final int j)
-  {
-    double dist = distances.getValue(i, j);
-  
-    ri = findr(i, j);
-    rj = findr(j, i);
-  
-    findClusterDistance(i, j);
-  
-    SequenceNode sn = new SequenceNode();
-  
-    sn.setLeft((node.elementAt(i)));
-    sn.setRight((node.elementAt(j)));
-  
-    SequenceNode tmpi = (node.elementAt(i));
-    SequenceNode tmpj = (node.elementAt(j));
-  
-    findNewDistances(tmpi, tmpj, dist);
-  
-    tmpi.setParent(sn);
-    tmpj.setParent(sn);
-  
-    node.setElementAt(sn, i);
-  
-    /*
-     * move the members of cluster(j) to cluster(i)
-     * and mark cluster j as out of the game
-     */
-    clusters.get(i).or(clusters.get(j));
-    clusters.get(j).clear();
-    done.set(j);
-  }
-
-  protected abstract void findNewDistances(SequenceNode tmpi, SequenceNode tmpj,
-          double dist);
-
-  /**
-   * Calculates and saves the distance between the combination of cluster(i) and
-   * cluster(j) and all other clusters. The form of the calculation depends on
-   * the tree clustering method being used.
-   * 
-   * @param i
-   * @param j
-   */
-  protected abstract void findClusterDistance(int i, int j);
-
-  /**
    * Start by making a cluster for each individual sequence
    */
   void makeLeaves()
   {
     clusters = new Vector<BitSet>();
-  
+
     for (int i = 0; i < noseqs; i++)
     {
       SequenceNode sn = new SequenceNode();
-  
+
       sn.setElement(sequences[i]);
       sn.setName(sequences[i].getName());
       node.addElement(sn);
@@ -459,4 +185,9 @@ public abstract class TreeBuilder
     }
   }
 
+  public AlignmentView getOriginalData()
+  {
+    return seqStrings;
+  }
+
 }