JAL-2403 JAL-1483 changes to ScoreModelI hierarchy and signatures to
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 23 Feb 2017 15:48:57 +0000 (15:48 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 23 Feb 2017 15:48:57 +0000 (15:48 +0000)
allow distance and similarity models to be used for Tree and PCA

28 files changed:
src/jalview/analysis/NJTree.java
src/jalview/analysis/PCA.java
src/jalview/analysis/scoremodels/FeatureDistanceModel.java
src/jalview/analysis/scoremodels/PIDDistanceModel.java
src/jalview/analysis/scoremodels/PairwiseDistanceModel.java [deleted file]
src/jalview/analysis/scoremodels/SWDistanceModel.java
src/jalview/analysis/scoremodels/ScoreMatrix.java
src/jalview/analysis/scoremodels/ScoreModels.java
src/jalview/api/analysis/DistanceModelI.java [deleted file]
src/jalview/api/analysis/DistanceScoreModelI.java [new file with mode: 0644]
src/jalview/api/analysis/PairwiseScoreModelI.java [moved from src/jalview/analysis/scoremodels/PairwiseScoreModelI.java with 95% similarity]
src/jalview/api/analysis/ScoreModelI.java [new file with mode: 0644]
src/jalview/api/analysis/SimilarityScoreModelI.java [new file with mode: 0644]
src/jalview/appletgui/TreeCanvas.java
src/jalview/appletgui/TreePanel.java
src/jalview/datamodel/SequenceNode.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/PCAPanel.java
src/jalview/gui/TreeCanvas.java
src/jalview/gui/TreeChooser.java
src/jalview/gui/TreePanel.java
src/jalview/jbgui/GPCAPanel.java
src/jalview/schemes/Blosum62ColourScheme.java
src/jalview/viewmodel/PCAModel.java
test/jalview/analysis/scoremodels/FeatureDistanceModelTest.java
test/jalview/analysis/scoremodels/ScoreMatrixTest.java
test/jalview/analysis/scoremodels/ScoreModelsTest.java
test/jalview/util/ComparisonTest.java

index 7140867..5f268ae 100644 (file)
@@ -21,7 +21,9 @@
 package jalview.analysis;
 
 import jalview.analysis.scoremodels.ScoreModels;
-import jalview.api.analysis.DistanceModelI;
+import jalview.api.analysis.DistanceScoreModelI;
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityScoreModelI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.BinaryNode;
 import jalview.datamodel.CigarArray;
@@ -31,6 +33,7 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.SequenceNode;
 import jalview.io.NewickFile;
+import jalview.math.MatrixI;
 
 import java.util.Enumeration;
 import java.util.List;
@@ -67,15 +70,15 @@ public class NJTree
 
   int noClus;
 
-  float[][] distance;
+  MatrixI distance;
 
   int mini;
 
   int minj;
 
-  float ri;
+  double ri;
 
-  float rj;
+  double rj;
 
   Vector<SequenceNode> groups = new Vector<SequenceNode>();
 
@@ -83,9 +86,9 @@ public class NJTree
 
   SequenceNode top;
 
-  float maxDistValue;
+  double maxDistValue;
 
-  float maxheight;
+  double maxheight;
 
   int ycount;
 
@@ -214,25 +217,25 @@ public class NJTree
    * 
    * @param sequence
    *          DOCUMENT ME!
-   * @param type
+   * @param treeType
    *          DOCUMENT ME!
-   * @param pwtype
+   * @param modelType
    *          DOCUMENT ME!
    * @param start
    *          DOCUMENT ME!
    * @param end
    *          DOCUMENT ME!
    */
-  public NJTree(SequenceI[] sequence, AlignmentView seqData, String type,
-          String pwtype, DistanceModelI sm, int start, int end)
+  public NJTree(SequenceI[] sqs, AlignmentView seqView, String treeType,
+          String modelType, ScoreModelI sm, int start, int end)
   {
-    this.sequence = sequence;
+    this.sequence = sqs;
     this.node = new Vector<SequenceNode>();
-    this.type = type;
-    this.pwtype = pwtype;
-    if (seqData != null)
+    this.type = treeType;
+    this.pwtype = modelType;
+    if (seqView != null)
     {
-      this.seqData = seqData;
+      this.seqData = seqView;
     }
     else
     {
@@ -246,16 +249,16 @@ public class NJTree
       this.seqData = new AlignmentView(sdata, start);
     }
     // System.err.println("Made seqData");// dbg
-    if (!(type.equals(NEIGHBOUR_JOINING)))
+    if (!(treeType.equals(NEIGHBOUR_JOINING)))
     {
-      type = AVERAGE_DISTANCE;
+      treeType = AVERAGE_DISTANCE;
     }
 
-    if (sm == null && !(pwtype.equals("PID")))
+    if (sm == null && !(modelType.equals("PID")))
     {
-      if (ScoreModels.getInstance().forName(pwtype) == null)
+      if (ScoreModels.getInstance().forName(modelType) == null)
       {
-        pwtype = "BLOSUM62";
+        modelType = "BLOSUM62";
       }
     }
 
@@ -271,7 +274,22 @@ public class NJTree
 
     noseqs = i++;
 
-    distance = findDistances(sm);
+    if (sm instanceof DistanceScoreModelI)
+    {
+      distance = ((DistanceScoreModelI) sm).findDistances(seqData);
+    }
+    else if (sm instanceof SimilarityScoreModelI)
+    {
+      /*
+       * compute similarity and invert it to give a distance measure
+       */
+      MatrixI result = ((SimilarityScoreModelI) sm)
+              .findSimilarities(seqData);
+      double maxScore = result.getMaxValue();
+      result.subtractAllFrom(maxScore);
+      distance = result;
+    }
+
     // System.err.println("Made distances");// dbg
     makeLeaves();
     // System.err.println("Made leaves");// dbg
@@ -453,7 +471,7 @@ public class NJTree
    */
   public Cluster joinClusters(int i, int j)
   {
-    float dist = distance[i][j];
+    double dist = distance.getValue(i, j);
 
     int noi = cluster.elementAt(i).value.length;
     int noj = cluster.elementAt(j).value.length;
@@ -520,7 +538,7 @@ public class NJTree
    *          DOCUMENT ME!
    */
   public void findNewNJDistances(SequenceNode tmpi, SequenceNode tmpj,
-          float dist)
+          double dist)
   {
 
     tmpi.dist = ((dist + ri) - rj) / 2;
@@ -548,10 +566,10 @@ public class NJTree
    *          DOCUMENT ME!
    */
   public void findNewDistances(SequenceNode tmpi, SequenceNode tmpj,
-          float dist)
+          double dist)
   {
-    float ih = 0;
-    float jh = 0;
+    double ih = 0;
+    double jh = 0;
 
     SequenceNode sni = tmpi;
     SequenceNode snj = tmpj;
@@ -586,13 +604,16 @@ public class NJTree
     int noj = cluster.elementAt(j).value.length;
 
     // New distances from cluster to others
-    float[] newdist = new float[noseqs];
+    double[] newdist = new double[noseqs];
 
     for (int l = 0; l < noseqs; l++)
     {
       if ((l != i) && (l != j))
       {
-        newdist[l] = ((distance[i][l] * noi) + (distance[j][l] * noj))
+        // newdist[l] = ((distance[i][l] * noi) + (distance[j][l] * noj))
+        // / (noi + noj);
+        newdist[l] = ((distance.getValue(i, l) * noi) + (distance.getValue(
+                j, l) * noj))
                 / (noi + noj);
       }
       else
@@ -603,8 +624,10 @@ public class NJTree
 
     for (int ii = 0; ii < noseqs; ii++)
     {
-      distance[i][ii] = newdist[ii];
-      distance[ii][i] = newdist[ii];
+      // distance[i][ii] = newdist[ii];
+      // distance[ii][i] = newdist[ii];
+      distance.setValue(i, ii, newdist[ii]);
+      distance.setValue(ii, i, newdist[ii]);
     }
   }
 
@@ -620,13 +643,16 @@ public class NJTree
   {
 
     // New distances from cluster to others
-    float[] newdist = new float[noseqs];
+    double[] newdist = new double[noseqs];
 
     for (int l = 0; l < noseqs; l++)
     {
       if ((l != i) && (l != j))
       {
-        newdist[l] = ((distance[i][l] + distance[j][l]) - distance[i][j]) / 2;
+        // newdist[l] = ((distance[i][l] + distance[j][l]) - distance[i][j]) /
+        // 2;
+        newdist[l] = (distance.getValue(i, l) + distance.getValue(j, l) - distance
+                .getValue(i, j)) / 2;
       }
       else
       {
@@ -636,8 +662,10 @@ public class NJTree
 
     for (int ii = 0; ii < noseqs; ii++)
     {
-      distance[i][ii] = newdist[ii];
-      distance[ii][i] = newdist[ii];
+      // distance[i][ii] = newdist[ii];
+      // distance[ii][i] = newdist[ii];
+      distance.setValue(i, ii, newdist[ii]);
+      distance.setValue(ii, i, newdist[ii]);
     }
   }
 
@@ -651,15 +679,16 @@ public class NJTree
    * 
    * @return DOCUMENT ME!
    */
-  public float findr(int i, int j)
+  public double findr(int i, int j)
   {
-    float tmp = 1;
+    double tmp = 1;
 
     for (int k = 0; k < noseqs; k++)
     {
       if ((k != i) && (k != j) && (done[k] != 1))
       {
-        tmp = tmp + distance[i][k];
+        // tmp = tmp + distance[i][k];
+        tmp = tmp + distance.getValue(i, k);
       }
     }
 
@@ -676,9 +705,9 @@ public class NJTree
    * 
    * @return DOCUMENT ME!
    */
-  public float findMinNJDistance()
+  public double findMinNJDistance()
   {
-    float min = 100000;
+    double min = Double.MAX_VALUE;
 
     for (int i = 0; i < (noseqs - 1); i++)
     {
@@ -686,7 +715,9 @@ public class NJTree
       {
         if ((done[i] != 1) && (done[j] != 1))
         {
-          float tmp = distance[i][j] - (findr(i, j) + findr(j, i));
+          // float tmp = distance[i][j] - (findr(i, j) + findr(j, i));
+          double tmp = distance.getValue(i, j)
+                  - (findr(i, j) + findr(j, i));
 
           if (tmp < min)
           {
@@ -707,9 +738,9 @@ public class NJTree
    * 
    * @return DOCUMENT ME!
    */
-  public float findMinDistance()
+  public double findMinDistance()
   {
-    float min = 100000;
+    double min = Double.MAX_VALUE;
 
     for (int i = 0; i < (noseqs - 1); i++)
     {
@@ -717,12 +748,14 @@ public class NJTree
       {
         if ((done[i] != 1) && (done[j] != 1))
         {
-          if (distance[i][j] < min)
+          // if (distance[i][j] < min)
+          if (distance.getValue(i, j) < min)
           {
             mini = i;
             minj = j;
 
-            min = distance[i][j];
+            // min = distance[i][j];
+            min = distance.getValue(i, j);
           }
         }
       }
@@ -734,24 +767,42 @@ public class NJTree
   /**
    * Calculate a distance matrix given the sequence input data and score model
    * 
-   * @return similarity matrix used to compute tree
+   * @return
    */
-  public float[][] findDistances(DistanceModelI _pwmatrix)
+  public MatrixI findDistances(ScoreModelI scoreModel)
   {
+    MatrixI result = null;
 
-    float[][] dist = new float[noseqs][noseqs];
-    if (_pwmatrix == null)
+    if (scoreModel == null)
     {
       // Resolve substitution model
-      _pwmatrix = ScoreModels.getInstance().forName(pwtype);
-      if (_pwmatrix == null)
+      scoreModel = ScoreModels.getInstance().forName(pwtype);
+      if (scoreModel == null)
       {
-        _pwmatrix = ScoreModels.getInstance().forName("BLOSUM62");
+        scoreModel = ScoreModels.getInstance().forName("BLOSUM62");
       }
     }
-    dist = _pwmatrix.findDistances(seqData);
-    return dist;
+    if (scoreModel instanceof DistanceScoreModelI)
+    {
+      result = ((DistanceScoreModelI) scoreModel).findDistances(seqData);
+    }
+    else if (scoreModel instanceof SimilarityScoreModelI)
+    {
+      /*
+       * compute similarity and invert it to give a distance measure
+       */
+      result = ((SimilarityScoreModelI) scoreModel)
+              .findSimilarities(seqData);
+      double maxScore = result.getMaxValue();
+      result.subtractAllFrom(maxScore);
+    }
+    else
+    {
+      System.err
+              .println("Unexpected type of score model, can't compute distances");
+    }
 
+    return result;
   }
 
   /**
@@ -914,7 +965,7 @@ public class NJTree
 
     if ((nd.left() == null) && (nd.right() == null))
     {
-      float dist = nd.dist;
+      double dist = nd.dist;
 
       if (dist > maxDistValue)
       {
@@ -944,7 +995,7 @@ public class NJTree
    * 
    * @return DOCUMENT ME!
    */
-  public float getMaxHeight()
+  public double getMaxHeight()
   {
     return maxheight;
   }
@@ -983,7 +1034,7 @@ public class NJTree
    * 
    * @return DOCUMENT ME!
    */
-  public float findHeight(SequenceNode nd)
+  public double findHeight(SequenceNode nd)
   {
     if (nd == null)
     {
@@ -1033,7 +1084,7 @@ public class NJTree
     {
       ycount = 0;
 
-      float tmpdist = maxdist.dist;
+      double tmpdist = maxdist.dist;
 
       // New top
       SequenceNode sn = new SequenceNode();
@@ -1324,6 +1375,7 @@ public class NJTree
  * @author $author$
  * @version $Revision$
  */
+// TODO what does this class have that int[] doesn't have already?
 class Cluster
 {
   int[] value;
index b6766c6..738da7d 100755 (executable)
  */
 package jalview.analysis;
 
-import jalview.analysis.scoremodels.PairwiseDistanceModel;
-import jalview.analysis.scoremodels.ScoreMatrix;
-import jalview.analysis.scoremodels.ScoreModels;
+import jalview.api.analysis.DistanceScoreModelI;
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityScoreModelI;
+import jalview.datamodel.AlignmentView;
 import jalview.math.MatrixI;
 
 import java.io.PrintStream;
@@ -42,56 +43,16 @@ public class PCA implements Runnable
 
   StringBuilder details = new StringBuilder(1024);
 
-  private String[] seqs;
+  private AlignmentView seqs;
 
-  private ScoreMatrix scoreMatrix;
+  private ScoreModelI scoreModel;
 
-  /**
-   * Creates a new PCA object. By default, uses blosum62 matrix to generate
-   * sequence similarity matrices
-   * 
-   * @param s
-   *          Set of amino acid sequences to perform PCA on
-   */
-  public PCA(String[] s)
-  {
-    this(s, false);
-  }
-
-  /**
-   * Creates a new PCA object. By default, uses blosum62 matrix to generate
-   * sequence similarity matrices
-   * 
-   * @param s
-   *          Set of sequences to perform PCA on
-   * @param nucleotides
-   *          if true, uses standard DNA/RNA matrix for sequence similarity
-   *          calculation.
-   */
-  public PCA(String[] s, boolean nucleotides)
-  {
-    this(s, nucleotides, null);
-  }
-
-  public PCA(String[] s, boolean nucleotides, String s_m)
+  public PCA(AlignmentView s, ScoreModelI sm)
   {
     this.seqs = s;
 
-    scoreMatrix = null;
-    String sm = s_m;
-    if (sm != null)
-    {
-      scoreMatrix = (ScoreMatrix) ((PairwiseDistanceModel) ScoreModels
-              .getInstance()
-              .forName(sm)).getScoreModel();
-    }
-    if (scoreMatrix == null)
-    {
-      // either we were given a non-existent score matrix or a scoremodel that
-      // isn't based on a pairwise symbol score matrix
-      scoreMatrix = ScoreModels.getInstance().getDefaultModel(!nucleotides);
-    }
-    details.append("PCA calculation using " + sm
+    scoreModel = sm;
+    details.append("PCA calculation using " + sm.getName()
             + " sequence similarity matrix\n========\n\n");
   }
 
@@ -212,7 +173,7 @@ public class PCA implements Runnable
               + (jvCalcMode ? "Jalview variant" : "Original SeqSpace")
               + "\n");
 
-      eigenvector = scoreMatrix.computePairwiseScores(seqs);
+      eigenvector = computeSimilarity(seqs);
 
       details.append(" --- OrigT * Orig ---- \n");
       eigenvector.print(ps, "%8.2f");
@@ -254,6 +215,38 @@ public class PCA implements Runnable
     // + (System.currentTimeMillis() - now) + "ms"));
   }
 
+  /**
+   * Computes a pairwise similarity matrix for the given sequence regions using
+   * the configured score model. If the score model is a similarity model, then
+   * it computes the result directly. If it is a distance model, then use it to
+   * compute pairwise distances, and convert these to similarity scores by
+   * substracting from the maximum value.
+   * 
+   * @param av
+   * @return
+   */
+  MatrixI computeSimilarity(AlignmentView av)
+  {
+    MatrixI result = null;
+    if (scoreModel instanceof SimilarityScoreModelI)
+    {
+      result = ((SimilarityScoreModelI) scoreModel).findSimilarities(av);
+    }
+    else if (scoreModel instanceof DistanceScoreModelI)
+    {
+      result = ((DistanceScoreModelI) scoreModel).findDistances(av);
+      double maxDistance = result.getMaxValue();
+      result.subtractAllFrom(maxDistance);
+    }
+    else
+    {
+      System.err
+              .println("Unexpected type of score model, cannot calculate similarity");
+    }
+
+    return result;
+  }
+
   public void setJvCalcMode(boolean calcMode)
   {
     this.jvCalcMode = calcMode;
@@ -268,6 +261,6 @@ public class PCA implements Runnable
   public int getHeight()
   {
     // TODO can any of seqs[] be null?
-    return seqs.length;
+    return seqs.getSequences().length;
   }
 }
index 04a7b14..9245898 100644 (file)
  */
 package jalview.analysis.scoremodels;
 
-import jalview.api.analysis.DistanceModelI;
+import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureRenderer;
+import jalview.api.analysis.DistanceScoreModelI;
 import jalview.api.analysis.ViewBasedAnalysisI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.SeqCigar;
 import jalview.datamodel.SequenceFeature;
+import jalview.math.Matrix;
+import jalview.math.MatrixI;
 import jalview.util.SetUtils;
 
 import java.util.HashMap;
@@ -33,13 +37,14 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-public class FeatureDistanceModel implements DistanceModelI, ViewBasedAnalysisI
+public class FeatureDistanceModel implements DistanceScoreModelI,
+        ViewBasedAnalysisI
 {
-  jalview.api.FeatureRenderer fr;
+  FeatureRenderer fr;
 
   @Override
-  public boolean configureFromAlignmentView(
-          jalview.api.AlignmentViewPanel view)
+  public boolean configureFromAlignmentView(AlignmentViewPanel view)
+
   {
     fr = view.cloneFeatureRenderer();
     return true;
@@ -53,16 +58,16 @@ public class FeatureDistanceModel implements DistanceModelI, ViewBasedAnalysisI
    * of columns processed.
    */
   @Override
-  public float[][] findDistances(AlignmentView seqData)
+  public MatrixI findDistances(AlignmentView seqData)
   {
     List<String> dft = fr.getDisplayedFeatureTypes();
     SeqCigar[] seqs = seqData.getSequences();
     int noseqs = seqs.length;
     int cpwidth = 0;// = seqData.getWidth();
-    float[][] distance = new float[noseqs][noseqs];
+    double[][] distances = new double[noseqs][noseqs];
     if (dft.isEmpty())
     {
-      return distance;
+      return new Matrix(distances);
     }
 
     // need to get real position for view position
@@ -94,7 +99,7 @@ public class FeatureDistanceModel implements DistanceModelI, ViewBasedAnalysisI
           {
             int seqDistance = SetUtils.countDisjunction(sfap.get(seqs[i]),
                     sfap.get(seqs[j]));
-            distance[i][j] += seqDistance;
+            distances[i][j] += seqDistance;
           }
         }
       }
@@ -103,16 +108,18 @@ public class FeatureDistanceModel implements DistanceModelI, ViewBasedAnalysisI
     /*
      * normalise the distance scores (summed over columns) by the
      * number of visible columns used in the calculation
+     * and fill in the bottom half of the matrix
      */
+    // TODO JAL-2424 cpwidth may be out by 1 - affects scores but not tree shape
     for (int i = 0; i < noseqs; i++)
     {
       for (int j = i + 1; j < noseqs; j++)
       {
-        distance[i][j] /= cpwidth;
-        distance[j][i] = distance[i][j];
+        distances[i][j] /= cpwidth;
+        distances[j][i] = distances[i][j];
       }
     }
-    return distance;
+    return new Matrix(distances);
   }
 
   /**
index f72b0fc..154ff02 100644 (file)
  */
 package jalview.analysis.scoremodels;
 
-import jalview.api.analysis.DistanceModelI;
+import jalview.api.analysis.DistanceScoreModelI;
 import jalview.datamodel.AlignmentView;
+import jalview.math.Matrix;
+import jalview.math.MatrixI;
 import jalview.util.Comparison;
 
-public class PIDDistanceModel implements DistanceModelI
+public class PIDDistanceModel implements DistanceScoreModelI
 {
 
   @Override
-  public float[][] findDistances(AlignmentView seqData)
+  public MatrixI findDistances(AlignmentView seqData)
   {
     String[] sequenceString = seqData
             .getSequenceStrings(Comparison.GAP_SPACE);
     int noseqs = sequenceString.length;
-    float[][] distance = new float[noseqs][noseqs];
+    double[][] distance = new double[noseqs][noseqs];
     for (int i = 0; i < (noseqs - 1); i++)
     {
       for (int j = i; j < noseqs; j++)
@@ -51,7 +53,7 @@ public class PIDDistanceModel implements DistanceModelI
         }
       }
     }
-    return distance;
+    return new Matrix(distance);
   }
 
   @Override
diff --git a/src/jalview/analysis/scoremodels/PairwiseDistanceModel.java b/src/jalview/analysis/scoremodels/PairwiseDistanceModel.java
deleted file mode 100644 (file)
index cb9ad07..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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.scoremodels;
-
-import jalview.api.analysis.DistanceModelI;
-import jalview.datamodel.AlignmentView;
-import jalview.util.Comparison;
-
-public class PairwiseDistanceModel implements DistanceModelI
-{
-  PairwiseScoreModelI scoreModel;
-
-  /**
-   * Constructor given something to provide pairwise scores for residues
-   * 
-   * @param sm
-   */
-  public PairwiseDistanceModel(PairwiseScoreModelI sm)
-  {
-    scoreModel = sm;
-  }
-
-  /**
-   * Returns a matrix of [i][j] values representing distances between pairs of
-   * sequences
-   */
-  @Override
-  public float[][] findDistances(AlignmentView seqData)
-  {
-    String[] sequenceString = seqData
-            .getSequenceStrings(Comparison.GAP_SPACE);
-    int noseqs = sequenceString.length;
-    float[][] distance = new float[noseqs][noseqs];
-
-    /*
-     * calculate similarity scores for the upper half of the matrix
-     * as [i, j] = the sum of pairwise scores of corresponding
-     * positions of sequence[i] and sequence[j]
-     */
-    float maxscore = 0;
-    int end = sequenceString[0].length();
-    for (int i = 0; i < (noseqs - 1); i++)
-    {
-      for (int j = i; j < noseqs; j++)
-      {
-        float score = 0;
-
-        for (int k = 0; k < end; k++)
-        {
-          try
-          {
-            score += scoreModel.getPairwiseScore(
-                    sequenceString[i].charAt(k),
-                    sequenceString[j].charAt(k));
-          } catch (Exception ex)
-          {
-            System.err.println("err creating " + getName() + " tree");
-            ex.printStackTrace();
-          }
-        }
-
-        distance[i][j] = score;
-
-        if (score > maxscore)
-        {
-          maxscore = score;
-        }
-      }
-    }
-
-    /*
-     * subtract similarity scores from the maximum value to
-     * convert to a distance measure; also populate the lower
-     * half of the result matrix with this value 
-     */
-    // FIXME this assumes the score matrix is symmetric - it may not be?
-    for (int i = 0; i < (noseqs - 1); i++)
-    {
-      for (int j = i; j < noseqs; j++)
-      {
-        distance[i][j] = maxscore - distance[i][j];
-        distance[j][i] = distance[i][j];
-      }
-    }
-    return distance;
-  }
-
-  @Override
-  public String getName()
-  {
-    return scoreModel.getName();
-  }
-
-  @Override
-  public boolean isDNA()
-  {
-    return scoreModel.isDNA();
-  }
-
-  @Override
-  public boolean isProtein()
-  {
-    return scoreModel.isProtein();
-  }
-
-  public PairwiseScoreModelI getScoreModel()
-  {
-    return scoreModel;
-  }
-}
index f63ee13..5e711db 100644 (file)
 package jalview.analysis.scoremodels;
 
 import jalview.analysis.AlignSeq;
-import jalview.api.analysis.DistanceModelI;
+import jalview.api.analysis.DistanceScoreModelI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.SequenceI;
+import jalview.math.Matrix;
+import jalview.math.MatrixI;
 import jalview.util.Comparison;
 
-public class SWDistanceModel implements DistanceModelI
+public class SWDistanceModel implements DistanceScoreModelI
 {
 
   @Override
-  public float[][] findDistances(AlignmentView seqData)
+  public MatrixI findDistances(AlignmentView seqData)
   {
     SequenceI[] sequenceString = seqData.getVisibleAlignment(
             Comparison.GAP_SPACE).getSequencesArray();
     int noseqs = sequenceString.length;
-    float[][] distance = new float[noseqs][noseqs];
+    double[][] distances = new double[noseqs][noseqs];
 
-    float max = -1;
+    double max = -1;
 
     for (int i = 0; i < (noseqs - 1); i++)
     {
@@ -48,11 +50,11 @@ public class SWDistanceModel implements DistanceModelI
         as.calcScoreMatrix();
         as.traceAlignment();
         as.printAlignment(System.out);
-        distance[i][j] = as.maxscore;
+        distances[i][j] = as.maxscore;
 
-        if (max < distance[i][j])
+        if (max < distances[i][j])
         {
-          max = distance[i][j];
+          max = distances[i][j];
         }
       }
     }
@@ -61,12 +63,12 @@ public class SWDistanceModel implements DistanceModelI
     {
       for (int j = i; j < noseqs; j++)
       {
-        distance[i][j] = max - distance[i][j];
-        distance[j][i] = distance[i][j];
+        distances[i][j] = max - distances[i][j];
+        distances[j][i] = distances[i][j];
       }
     }
 
-    return distance;
+    return new Matrix(distances);
   }
 
   @Override
index 9da28eb..efde30d 100644 (file)
  */
 package jalview.analysis.scoremodels;
 
+import jalview.api.analysis.PairwiseScoreModelI;
+import jalview.api.analysis.SimilarityScoreModelI;
+import jalview.datamodel.AlignmentView;
 import jalview.math.Matrix;
 import jalview.math.MatrixI;
 
 import java.util.Arrays;
 
-public class ScoreMatrix implements PairwiseScoreModelI
+public class ScoreMatrix implements SimilarityScoreModelI,
+        PairwiseScoreModelI
 {
+  /*
+   * Jalview 2.10.1 treated gaps as X (peptide) or N (nucleotide)
+   * for pairwise scoring; 2.10.2 uses gap score (last column) in
+   * score matrix (JAL-2397)
+   * Set this flag to true (via Groovy) for 2.10.1 behaviour
+   */
+  private static boolean scoreGapAsAny = false;
+
   public static final short UNMAPPED = (short) -1;
 
   private static final String BAD_ASCII_ERROR = "Unexpected character %s in getPairwiseScore";
@@ -334,7 +346,19 @@ public class ScoreMatrix implements PairwiseScoreModelI
    * <li>and so on</li>
    * </ul>
    */
-  public MatrixI computePairwiseScores(String[] seqs)
+  @Override
+  public MatrixI findSimilarities(AlignmentView seqstrings)
+  {
+    char gapChar = scoreGapAsAny ? (seqstrings.isNa() ? 'N' : 'X') : ' ';
+    String[] seqs = seqstrings.getSequenceStrings(gapChar);
+    return findSimilarities(seqs);
+  }
+
+  /**
+   * @param seqs
+   * @return
+   */
+  protected MatrixI findSimilarities(String[] seqs)
   {
     double[][] values = new double[seqs.length][];
     for (int row = 0; row < seqs.length; row++)
index 043e6fb..011d8ba 100644 (file)
@@ -1,6 +1,6 @@
 package jalview.analysis.scoremodels;
 
-import jalview.api.analysis.DistanceModelI;
+import jalview.api.analysis.ScoreModelI;
 import jalview.io.DataSourceType;
 import jalview.io.FileParse;
 import jalview.io.ScoreMatrixFile;
@@ -22,7 +22,7 @@ public class ScoreModels
 
   private static ScoreModels instance = new ScoreModels();
 
-  private Map<String, DistanceModelI> models;
+  private Map<String, ScoreModelI> models;
 
   public static ScoreModels getInstance()
   {
@@ -46,7 +46,7 @@ public class ScoreModels
     /*
      * using LinkedHashMap keeps models ordered as added
      */
-    models = new LinkedHashMap<String, DistanceModelI>();
+    models = new LinkedHashMap<String, ScoreModelI>();
     BLOSUM62 = loadScoreMatrix("scoreModel/blosum62.scm");
     PAM250 = loadScoreMatrix("scoreModel/pam250.scm");
     loadScoreMatrix("scoreModel/seqspace.scm");
@@ -84,34 +84,24 @@ public class ScoreModels
   }
 
   /**
-   * Registers a pairwise score model
-   * 
-   * @param sm
-   */
-  public void registerScoreModel(PairwiseScoreModelI sm)
-  {
-    registerScoreModel(new PairwiseDistanceModel(sm));
-  }
-
-  /**
    * Answers an iterable set of the registered score models. Currently these are
    * returned in the order in which they were registered.
    * 
    * @return
    */
-  public Iterable<DistanceModelI> getModels()
+  public Iterable<ScoreModelI> getModels()
   {
     return models.values();
   }
 
-  public DistanceModelI forName(String s)
+  public ScoreModelI forName(String s)
   {
     return models.get(s);
   }
 
-  public void registerScoreModel(DistanceModelI sm)
+  public void registerScoreModel(ScoreModelI sm)
   {
-    DistanceModelI sm2 = models.get(sm.getName());
+    ScoreModelI sm2 = models.get(sm.getName());
     if (sm2 != null)
     {
       System.err.println("Warning: replacing score model " + sm2.getName());
diff --git a/src/jalview/api/analysis/DistanceModelI.java b/src/jalview/api/analysis/DistanceModelI.java
deleted file mode 100644 (file)
index 3ceeed2..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.api.analysis;
-
-import jalview.datamodel.AlignmentView;
-
-/**
- * An interface that describes classes that can compute distances between pairs
- * of sequences in an alignment
- */
-public interface DistanceModelI
-{
-
-  float[][] findDistances(AlignmentView seqData);
-
-  String getName();
-
-  /**
-   * Answers true if this model is applicable for nucleotide data (so should be
-   * shown in menus in that context)
-   * 
-   * @return
-   */
-  boolean isDNA();
-
-  /**
-   * Answers true if this model is applicable for peptide data (so should be
-   * shown in menus in that context)
-   * 
-   * @return
-   */
-  boolean isProtein();
-
-}
diff --git a/src/jalview/api/analysis/DistanceScoreModelI.java b/src/jalview/api/analysis/DistanceScoreModelI.java
new file mode 100644 (file)
index 0000000..27003e8
--- /dev/null
@@ -0,0 +1,24 @@
+package jalview.api.analysis;
+
+import jalview.datamodel.AlignmentView;
+import jalview.math.MatrixI;
+
+/**
+ * A sequence distance score models, that provides a method to compute distances
+ * between pairs of sequences
+ * 
+ * @author gmcarstairs
+ *
+ */
+public interface DistanceScoreModelI extends ScoreModelI
+{
+  /**
+   * Returns a distance score for the given sequence regions, that is, a matrix
+   * whose value [i][j] is the distance of sequence i from sequence j by some
+   * measure
+   * 
+   * @param seqData
+   * @return
+   */
+  MatrixI findDistances(AlignmentView seqData);
+}
@@ -1,4 +1,4 @@
-package jalview.analysis.scoremodels;
+package jalview.api.analysis;
 
 /**
  * An interface that describes classes that can compute similarity (aka
diff --git a/src/jalview/api/analysis/ScoreModelI.java b/src/jalview/api/analysis/ScoreModelI.java
new file mode 100644 (file)
index 0000000..42f978c
--- /dev/null
@@ -0,0 +1,33 @@
+package jalview.api.analysis;
+
+import jalview.datamodel.AlignmentView;
+import jalview.math.MatrixI;
+
+public interface ScoreModelI
+{
+  /**
+   * Answers a name for the score model, suitable for display in menus. Names
+   * should be unique across score models in use.
+   * 
+   * @return
+   * @see jalview.analysis.scoremodels.ScoreModels#forName(String)
+   */
+  String getName();
+
+  /**
+   * Answers true if this model is applicable for nucleotide data (so should be
+   * shown in menus in that context)
+   * 
+   * @return
+   */
+  boolean isDNA();
+
+  /**
+   * Answers true if this model is applicable for peptide data (so should be
+   * shown in menus in that context)
+   * 
+   * @return
+   */
+  boolean isProtein();
+
+}
diff --git a/src/jalview/api/analysis/SimilarityScoreModelI.java b/src/jalview/api/analysis/SimilarityScoreModelI.java
new file mode 100644 (file)
index 0000000..96208a3
--- /dev/null
@@ -0,0 +1,24 @@
+package jalview.api.analysis;
+
+import jalview.datamodel.AlignmentView;
+import jalview.math.MatrixI;
+
+/**
+ * A class that provides a method to compute similarity scores of pairs of
+ * sequences
+ * 
+ * @author gmcarstairs
+ *
+ */
+public interface SimilarityScoreModelI extends ScoreModelI
+{
+  /**
+   * Returns a similarity score for the given sequence regions, that is, a
+   * matrix whose value [i][j] is the similarity of sequence i to sequence j by
+   * some measure
+   * 
+   * @param seqData
+   * @return
+   */
+  MatrixI findSimilarities(AlignmentView seqData);
+}
index e30879c..7040c42 100755 (executable)
@@ -146,7 +146,7 @@ public class TreeCanvas extends Panel implements MouseListener,
   }
 
   public void drawNode(Graphics g, SequenceNode node, float chunk,
-          float scale, int width, int offx, int offy)
+          double scale, int width, int offx, int offy)
   {
     if (node == null)
     {
@@ -157,8 +157,8 @@ public class TreeCanvas extends Panel implements MouseListener,
     {
       // Drawing leaf node
 
-      float height = node.height;
-      float dist = node.dist;
+      double height = node.height;
+      double dist = node.dist;
 
       int xstart = (int) ((height - dist) * scale) + offx;
       int xend = (int) (height * scale) + offx;
@@ -240,8 +240,8 @@ public class TreeCanvas extends Panel implements MouseListener,
       drawNode(g, (SequenceNode) node.right(), chunk, scale, width, offx,
               offy);
 
-      float height = node.height;
-      float dist = node.dist;
+      double height = node.height;
+      double dist = node.dist;
 
       int xstart = (int) ((height - dist) * scale) + offx;
       int xend = (int) (height * scale) + offx;
@@ -338,7 +338,7 @@ public class TreeCanvas extends Panel implements MouseListener,
 
     SequenceNode top = tree.getTopNode();
 
-    float wscale = (float) (width * .8 - offx * 2) / tree.getMaxHeight();
+    double wscale = (float) (width * .8 - offx * 2) / tree.getMaxHeight();
     if (top.count == 0)
     {
       top.count = ((SequenceNode) top.left()).count
@@ -350,7 +350,7 @@ public class TreeCanvas extends Panel implements MouseListener,
   }
 
   public void pickNode(Rectangle pickBox, SequenceNode node, float chunk,
-          float scale, int width, int offx, int offy)
+          double scale, int width, int offx, int offy)
   {
     if (node == null)
     {
@@ -359,7 +359,7 @@ public class TreeCanvas extends Panel implements MouseListener,
 
     if (node.left() == null && node.right() == null)
     {
-      float height = node.height;
+      double height = node.height;
       // float dist = node.dist;
 
       // int xstart = (int) ( (height - dist) * scale) + offx;
@@ -465,7 +465,7 @@ public class TreeCanvas extends Panel implements MouseListener,
     // for
     // scrollbar
 
-    float wscale = (width - labelLength - offx * 2) / tree.getMaxHeight();
+    double wscale = (width - labelLength - offx * 2) / tree.getMaxHeight();
 
     SequenceNode top = tree.getTopNode();
 
index 9ac6773..5b12fa6 100644 (file)
@@ -22,7 +22,7 @@ package jalview.appletgui;
 
 import jalview.analysis.NJTree;
 import jalview.analysis.scoremodels.ScoreModels;
-import jalview.api.analysis.DistanceModelI;
+import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.ViewBasedAnalysisI;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentView;
@@ -237,7 +237,7 @@ public class TreePanel extends EmbmenuFrame implements ActionListener,
           seqs = av.getSelectionGroup().getSequencesInOrder(
                   av.getAlignment());
         }
-        DistanceModelI sm = ScoreModels.getInstance().forName(pwtype);
+        ScoreModelI sm = ScoreModels.getInstance().forName(pwtype);
         if (sm instanceof ViewBasedAnalysisI)
         {
           try
@@ -251,13 +251,8 @@ public class TreePanel extends EmbmenuFrame implements ActionListener,
                     + sm.getName());
             q.printStackTrace();
           }
-          tree = new NJTree(seqs, seqStrings, type, pwtype, sm, start, end);
-        }
-        else
-        {
-          tree = new NJTree(seqs, seqStrings, type, pwtype, null, start,
-                  end);
         }
+        tree = new NJTree(seqs, seqStrings, type, pwtype, sm, start, end);
       }
 
       tree.reCount(tree.getTopNode());
index b2f054c..fa12419 100755 (executable)
@@ -31,13 +31,13 @@ import java.awt.Color;
 public class SequenceNode extends BinaryNode
 {
   /** DOCUMENT ME!! */
-  public float dist;
+  public double dist;
 
   /** DOCUMENT ME!! */
   public int count;
 
   /** DOCUMENT ME!! */
-  public float height;
+  public double height;
 
   /** DOCUMENT ME!! */
   public float ycount;
@@ -178,7 +178,9 @@ public class SequenceNode extends BinaryNode
       {
         char q = name.charAt(c);
         if ('0' <= q && q <= '9')
+        {
           continue;
+        }
         return true;
       }
     }
index 5f0e5d3..1162c53 100644 (file)
@@ -35,7 +35,7 @@ import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureSettingsControllerI;
 import jalview.api.SplitContainerI;
 import jalview.api.ViewStyleI;
-import jalview.api.analysis.DistanceModelI;
+import jalview.api.analysis.ScoreModelI;
 import jalview.bin.Cache;
 import jalview.bin.Jalview;
 import jalview.commands.CommandI;
@@ -5638,7 +5638,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     ColourMenuHelper.setColourSelected(colourMenu, schemeName);
   }
 
-  public void newTreePanel(String treeType, DistanceModelI sm)
+  public void newTreePanel(String treeType, ScoreModelI sm)
   {
     String scoreModelName = sm.getName();
     final String ttl = TreePanel.getPanelTitle(treeType, scoreModelName);
index d053468..3f0c37f 100644 (file)
  */
 package jalview.gui;
 
-import jalview.analysis.scoremodels.PairwiseDistanceModel;
 import jalview.analysis.scoremodels.ScoreModels;
-import jalview.api.analysis.DistanceModelI;
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.ViewBasedAnalysisI;
+import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
@@ -153,38 +154,42 @@ public class PCAPanel extends GPCAPanel implements Runnable,
     pcaModel = null;
   }
 
+  /**
+   * Repopulate the options and actions under the score model menu when it is
+   * selected. Options will depend on whether 'nucleotide' or 'peptide'
+   * modelling is selected (and also possibly on whether any additional score
+   * models have been added).
+   */
   @Override
-  protected void scoreMatrix_menuSelected()
+  protected void scoreModel_menuSelected()
   {
-    scoreMatrixMenu.removeAll();
-    for (DistanceModelI sm : ScoreModels.getInstance().getModels())
-    {
-      if (sm instanceof PairwiseDistanceModel)
+    scoreModelMenu.removeAll();
+    for (final ScoreModelI sm : ScoreModels.getInstance().getModels())
+    {
+      final String name = sm.getName();
+      // create an entry for this score matrix for use in PCA
+      JCheckBoxMenuItem jm = new JCheckBoxMenuItem();
+      jm.setText(MessageManager.getStringOrReturn("label.score_model_",
+              name));
+      jm.setSelected(pcaModel.getScoreModelName().equals(name));
+      if ((pcaModel.isNucleotide() && sm.isDNA())
+              || (!pcaModel.isNucleotide() && sm.isProtein()))
       {
-        final String name = sm.getName();
-        // create an entry for this score matrix for use in PCA
-        JCheckBoxMenuItem jm = new JCheckBoxMenuItem();
-        jm.setText(MessageManager.getStringOrReturn("label.score_model_",
-                name));
-        jm.setSelected(pcaModel.getScore_matrix().equals(name));
-        if ((pcaModel.isNucleotide() && sm.isDNA())
-                || (!pcaModel.isNucleotide() && sm.isProtein()))
+        jm.addActionListener(new ActionListener()
         {
-          jm.addActionListener(new ActionListener()
+          @Override
+          public void actionPerformed(ActionEvent e)
           {
-            @Override
-            public void actionPerformed(ActionEvent e)
+            if (!pcaModel.getScoreModelName().equals(name))
             {
-              if (!pcaModel.getScore_matrix().equals(name))
-              {
-                pcaModel.setScore_matrix(name);
-                Thread worker = new Thread(PCAPanel.this);
-                worker.start();
-              }
+              ScoreModelI sm2 = configureScoreModel(sm);
+              pcaModel.setScoreModel(sm2);
+              Thread worker = new Thread(PCAPanel.this);
+              worker.start();
             }
-          });
-          scoreMatrixMenu.add(jm);
-        }
+          }
+        });
+        scoreModelMenu.add(jm);
       }
     }
   }
@@ -258,7 +263,8 @@ public class PCAPanel extends GPCAPanel implements Runnable,
     if (!pcaModel.isNucleotide())
     {
       pcaModel.setNucleotide(true);
-      pcaModel.setScore_matrix("DNA");
+      pcaModel.setScoreModel(ScoreModels.getInstance().getDefaultModel(
+              false));
       Thread worker = new Thread(this);
       worker.start();
     }
@@ -272,7 +278,8 @@ public class PCAPanel extends GPCAPanel implements Runnable,
     if (pcaModel.isNucleotide())
     {
       pcaModel.setNucleotide(false);
-      pcaModel.setScore_matrix("BLOSUM62");
+      pcaModel.setScoreModel(ScoreModels.getInstance()
+              .getDefaultModel(true));
       Thread worker = new Thread(this);
       worker.start();
     }
@@ -776,4 +783,28 @@ public class PCAPanel extends GPCAPanel implements Runnable,
     top = t;
     zCombobox.setSelectedIndex(2);
   }
+
+  /**
+   * If the score model is one that requires to get state data from the current
+   * view, allow it to do so
+   * 
+   * @param sm
+   * @return
+   */
+  protected ScoreModelI configureScoreModel(ScoreModelI sm)
+  {
+    if (sm instanceof ViewBasedAnalysisI)
+    {
+      try
+      {
+        sm = sm.getClass().newInstance();
+        ((ViewBasedAnalysisI) sm).configureFromAlignmentView(ap);
+      } catch (Exception q)
+      {
+        Cache.log.error("Couldn't create a scoremodel instance for "
+                + sm.getName());
+      }
+    }
+    return sm;
+  }
 }
index 54eed1a..eb4253f 100755 (executable)
@@ -207,7 +207,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
    *          DOCUMENT ME!
    * @param chunk
    *          DOCUMENT ME!
-   * @param scale
+   * @param wscale
    *          DOCUMENT ME!
    * @param width
    *          DOCUMENT ME!
@@ -217,7 +217,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
    *          DOCUMENT ME!
    */
   public void drawNode(Graphics g, SequenceNode node, float chunk,
-          float scale, int width, int offx, int offy)
+          double wscale, int width, int offx, int offy)
   {
     if (node == null)
     {
@@ -227,11 +227,11 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     if ((node.left() == null) && (node.right() == null))
     {
       // Drawing leaf node
-      float height = node.height;
-      float dist = node.dist;
+      double height = node.height;
+      double dist = node.dist;
 
-      int xstart = (int) ((height - dist) * scale) + offx;
-      int xend = (int) (height * scale) + offx;
+      int xstart = (int) ((height - dist) * wscale) + offx;
+      int xend = (int) (height * wscale) + offx;
 
       int ypos = (int) (node.ycount * chunk) + offy;
 
@@ -306,16 +306,16 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     }
     else
     {
-      drawNode(g, (SequenceNode) node.left(), chunk, scale, width, offx,
+      drawNode(g, (SequenceNode) node.left(), chunk, wscale, width, offx,
               offy);
-      drawNode(g, (SequenceNode) node.right(), chunk, scale, width, offx,
+      drawNode(g, (SequenceNode) node.right(), chunk, wscale, width, offx,
               offy);
 
-      float height = node.height;
-      float dist = node.dist;
+      double height = node.height;
+      double dist = node.dist;
 
-      int xstart = (int) ((height - dist) * scale) + offx;
-      int xend = (int) (height * scale) + offx;
+      int xstart = (int) ((height - dist) * wscale) + offx;
+      int xend = (int) (height * wscale) + offx;
       int ypos = (int) (node.ycount * chunk) + offy;
 
       g.setColor(node.color.darker());
@@ -339,8 +339,8 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
       Rectangle pos = new Rectangle(xend - 2, ypos - 2, 5, 5);
       nodeHash.put(node, pos);
 
-      g.drawLine((int) (height * scale) + offx, ystart,
-              (int) (height * scale) + offx, yend);
+      g.drawLine((int) (height * wscale) + offx, ystart,
+              (int) (height * wscale) + offx, yend);
 
       String nodeLabel = "";
 
@@ -422,7 +422,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 
     SequenceNode top = tree.getTopNode();
 
-    float wscale = (float) ((width * .8) - (offx * 2))
+    double wscale = ((width * .8) - (offx * 2))
             / tree.getMaxHeight();
 
     if (top.count == 0)
@@ -445,7 +445,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
    *          DOCUMENT ME!
    * @param chunk
    *          DOCUMENT ME!
-   * @param scale
+   * @param wscale
    *          DOCUMENT ME!
    * @param width
    *          DOCUMENT ME!
@@ -455,7 +455,7 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
    *          DOCUMENT ME!
    */
   public void pickNode(Rectangle pickBox, SequenceNode node, float chunk,
-          float scale, int width, int offx, int offy)
+          double wscale, int width, int offx, int offy)
   {
     if (node == null)
     {
@@ -464,11 +464,11 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 
     if ((node.left() == null) && (node.right() == null))
     {
-      float height = node.height;
-      float dist = node.dist;
+      double height = node.height;
+      double dist = node.dist;
 
-      int xstart = (int) ((height - dist) * scale) + offx;
-      int xend = (int) (height * scale) + offx;
+      int xstart = (int) ((height - dist) * wscale) + offx;
+      int xend = (int) (height * wscale) + offx;
 
       int ypos = (int) (node.ycount * chunk) + offy;
 
@@ -488,9 +488,9 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
     }
     else
     {
-      pickNode(pickBox, (SequenceNode) node.left(), chunk, scale, width,
+      pickNode(pickBox, (SequenceNode) node.left(), chunk, wscale, width,
               offx, offy);
-      pickNode(pickBox, (SequenceNode) node.right(), chunk, scale, width,
+      pickNode(pickBox, (SequenceNode) node.right(), chunk, wscale, width,
               offx, offy);
     }
   }
@@ -715,7 +715,8 @@ public class TreeCanvas extends JPanel implements MouseListener, Runnable,
 
     labelLength = fm.stringWidth(longestName) + 20; // 20 allows for scrollbar
 
-    float wscale = (width - labelLength - (offx * 2)) / tree.getMaxHeight();
+    double wscale = (width - labelLength - (offx * 2))
+            / tree.getMaxHeight();
 
     SequenceNode top = tree.getTopNode();
 
index 55e6650..8e2bff0 100644 (file)
@@ -22,7 +22,7 @@ package jalview.gui;
 
 import jalview.analysis.NJTree;
 import jalview.analysis.scoremodels.ScoreModels;
-import jalview.api.analysis.DistanceModelI;
+import jalview.api.analysis.ScoreModelI;
 import jalview.util.MessageManager;
 
 import java.awt.Color;
@@ -86,7 +86,7 @@ public class TreeChooser extends JPanel
 
     matrixNames = new JComboBox<String>();
     ScoreModels scoreModels = ScoreModels.getInstance();
-    for (DistanceModelI sm : scoreModels.getModels())
+    for (ScoreModelI sm : scoreModels.getModels())
     {
       boolean nucleotide = af.getViewport().getAlignment().isNucleotide();
       if (sm.isDNA() && nucleotide || sm.isProtein() && !nucleotide)
@@ -151,7 +151,7 @@ public class TreeChooser extends JPanel
       frame.setClosed(true);
       String treeType = neighbourJoining.isSelected() ? NJTree.NEIGHBOUR_JOINING
               : NJTree.AVERAGE_DISTANCE;
-      DistanceModelI sm = ScoreModels.getInstance().forName(
+      ScoreModelI sm = ScoreModels.getInstance().forName(
               matrixNames.getSelectedItem().toString());
       af.newTreePanel(treeType, sm);
     } catch (Exception ex)
index 13e2360..0a33ea8 100755 (executable)
@@ -23,7 +23,7 @@ package jalview.gui;
 import jalview.analysis.AlignmentSorter;
 import jalview.analysis.NJTree;
 import jalview.analysis.scoremodels.ScoreModels;
-import jalview.api.analysis.DistanceModelI;
+import jalview.api.analysis.ScoreModelI;
 import jalview.api.analysis.ViewBasedAnalysisI;
 import jalview.bin.Cache;
 import jalview.commands.CommandI;
@@ -300,26 +300,9 @@ public class TreePanel extends GTreePanel
           seqs = av.getSelectionGroup().getSequencesInOrder(
                   av.getAlignment());
         }
-        DistanceModelI sm = ScoreModels.getInstance().forName(pwtype);
-        if (sm instanceof ViewBasedAnalysisI)
-        {
-          try
-          {
-            sm = sm.getClass().newInstance();
-            ((ViewBasedAnalysisI) sm)
-                    .configureFromAlignmentView(treeCanvas.ap);
-          } catch (Exception q)
-          {
-            Cache.log.error("Couldn't create a scoremodel instance for "
-                    + sm.getName());
-          }
-          tree = new NJTree(seqs, seqStrings, type, pwtype, sm, start, end);
-        }
-        else
-        {
-          tree = new NJTree(seqs, seqStrings, type, pwtype, null, start,
-                  end);
-        }
+        ScoreModelI sm = ScoreModels.getInstance().forName(pwtype);
+        sm = configureScoreModel(sm);
+        tree = new NJTree(seqs, seqStrings, type, pwtype, sm, start, end);
         showDistances(true);
       }
 
@@ -898,4 +881,28 @@ public class TreePanel extends GTreePanel
             treecalcnm, smn);
     return ttl;
   }
+
+  /**
+   * If the score model is one that requires to get state data from the current
+   * view, allow it to do so
+   * 
+   * @param sm
+   * @return
+   */
+  protected ScoreModelI configureScoreModel(ScoreModelI sm)
+  {
+    if (sm instanceof ViewBasedAnalysisI)
+    {
+      try
+      {
+        sm = sm.getClass().newInstance();
+        ((ViewBasedAnalysisI) sm).configureFromAlignmentView(treeCanvas.ap);
+      } catch (Exception q)
+      {
+        Cache.log.error("Couldn't create a scoremodel instance for "
+                + sm.getName());
+      }
+    }
+    return sm;
+  }
 }
index 774641c..24961c0 100755 (executable)
@@ -52,7 +52,7 @@ public class GPCAPanel extends JInternalFrame
 
   protected JComboBox<String> zCombobox = new JComboBox<String>();
 
-  protected JMenu scoreMatrixMenu = new JMenu();
+  protected JMenu scoreModelMenu = new JMenu();
 
   protected JMenu viewMenu = new JMenu();
 
@@ -226,14 +226,14 @@ public class GPCAPanel extends JInternalFrame
       {
       }
     });
-    scoreMatrixMenu.setText(MessageManager
+    scoreModelMenu.setText(MessageManager
             .getString("label.select_score_model"));
-    scoreMatrixMenu.addMenuListener(new MenuListener()
+    scoreModelMenu.addMenuListener(new MenuListener()
     {
       @Override
       public void menuSelected(MenuEvent e)
       {
-        scoreMatrix_menuSelected();
+        scoreModel_menuSelected();
       }
 
       @Override
@@ -312,7 +312,7 @@ public class GPCAPanel extends JInternalFrame
     // calcSettings.add(jvVersionSetting); // todo remove? JAL-2416
     calcSettings.add(nuclSetting);
     calcSettings.add(protSetting);
-    calcSettings.add(scoreMatrixMenu);
+    calcSettings.add(scoreModelMenu);
     statusPanel.setLayout(new GridLayout());
     statusBar.setFont(VERDANA_12);
     // statusPanel.setBackground(Color.lightGray);
@@ -348,7 +348,7 @@ public class GPCAPanel extends JInternalFrame
     viewMenu.add(associateViewsMenu);
   }
 
-  protected void scoreMatrix_menuSelected()
+  protected void scoreModel_menuSelected()
   {
     // TODO Auto-generated method stub
 
index 8ac8731..70f4910 100755 (executable)
@@ -20,8 +20,8 @@
  */
 package jalview.schemes;
 
-import jalview.analysis.scoremodels.PairwiseScoreModelI;
 import jalview.analysis.scoremodels.ScoreModels;
+import jalview.api.analysis.PairwiseScoreModelI;
 import jalview.datamodel.AnnotatedCollectionI;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceI;
index 4ad6d48..fa4b747 100644 (file)
@@ -21,7 +21,9 @@
 package jalview.viewmodel;
 
 import jalview.analysis.PCA;
+import jalview.analysis.scoremodels.ScoreModels;
 import jalview.api.RotatableCanvasI;
+import jalview.api.analysis.ScoreModelI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.SequencePoint;
@@ -30,23 +32,6 @@ import java.util.Vector;
 
 public class PCAModel
 {
-  /*
-   * Jalview 2.10.1 treated gaps as X (peptide) or N (nucleotide)
-   * for pairwise scoring; 2.10.2 uses gap score (last column) in
-   * score matrix (JAL-2397)
-   * Set this flag to true (via Groovy) for 2.10.1 behaviour
-   */
-  private static boolean scoreGapAsAny = false;
-
-  public PCAModel(AlignmentView seqstrings2, SequenceI[] seqs2,
-          boolean nucleotide2)
-  {
-    seqstrings = seqstrings2;
-    seqs = seqs2;
-    nucleotide = nucleotide2;
-    score_matrix = nucleotide2 ? "DNA" : "BLOSUM62";
-  }
-
   private volatile PCA pca;
 
   int top;
@@ -55,20 +40,26 @@ public class PCAModel
 
   SequenceI[] seqs;
 
-  /**
-   * Score matrix used to calculate PC
+  /*
+   * Score model used to calculate PCA
    */
-  String score_matrix;
+  ScoreModelI scoreModel;
 
-  /**
-   * use the identity matrix for calculating similarity between sequences.
-   */
   private boolean nucleotide = false;
 
   private Vector<SequencePoint> points;
 
   private boolean jvCalcMode = true;
 
+  public PCAModel(AlignmentView seqstrings2, SequenceI[] seqs2,
+          boolean nucleotide2)
+  {
+    seqstrings = seqstrings2;
+    seqs = seqs2;
+    nucleotide = nucleotide2;
+    scoreModel = ScoreModels.getInstance().getDefaultModel(!nucleotide);
+  }
+
   public boolean isJvCalcMode()
   {
     return jvCalcMode;
@@ -76,10 +67,7 @@ public class PCAModel
 
   public void run()
   {
-    char gapChar = scoreGapAsAny ? (nucleotide ? 'N' : 'X') : ' ';
-    String[] sequenceStrings = seqstrings.getSequenceStrings(gapChar);
-    pca = new PCA(sequenceStrings, nucleotide,
-            score_matrix);
+    pca = new PCA(seqstrings, scoreModel);
     pca.setJvCalcMode(jvCalcMode);
     pca.run();
 
@@ -232,14 +220,14 @@ public class PCAModel
     jvCalcMode = state;
   }
 
-  public String getScore_matrix()
+  public String getScoreModelName()
   {
-    return score_matrix;
+    return scoreModel == null ? "" : scoreModel.getName();
   }
 
-  public void setScore_matrix(String score_matrix)
+  public void setScoreModel(ScoreModelI sm)
   {
-    this.score_matrix = score_matrix;
+    this.scoreModel = sm;
   }
 
 }
index 8b84829..cd6d7f5 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.analysis.scoremodels;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
 
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceFeature;
@@ -29,6 +30,7 @@ import jalview.gui.AlignFrame;
 import jalview.gui.JvOptionPane;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
+import jalview.math.MatrixI;
 
 import java.util.Arrays;
 
@@ -98,7 +100,7 @@ public class FeatureDistanceModelTest
     alf.getFeatureRenderer().findAllFeatures(true);
     Assert.assertEquals(alf.getFeatureRenderer().getDisplayedFeatureTypes()
             .size(), 3, "Number of feature types");
-    Assert.assertTrue(alf.getCurrentView().areFeaturesDisplayed());
+    assertTrue(alf.getCurrentView().areFeaturesDisplayed());
     return alf;
   }
 
@@ -107,15 +109,16 @@ public class FeatureDistanceModelTest
   {
     AlignFrame alf = getTestAlignmentFrame();
     FeatureDistanceModel fsm = new FeatureDistanceModel();
-    Assert.assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
+    assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
             .getAlignPanel()));
     alf.selectAllSequenceMenuItem_actionPerformed(null);
 
-    float[][] dm = fsm.findDistances(alf.getViewport().getAlignmentView(
+    MatrixI dm = fsm
+            .findDistances(alf.getViewport().getAlignmentView(
             true));
-    Assert.assertTrue(dm[0][2] == 0f,
+    assertEquals(dm.getValue(0, 2), 0d,
             "FER1_MESCR (0) should be identical with RAPSA (2)");
-    Assert.assertTrue(dm[0][1] > dm[0][2],
+    assertTrue(dm.getValue(0, 1) > dm.getValue(0, 2),
             "FER1_MESCR (0) should be further from SPIOL (1) than it is from RAPSA (2)");
   }
 
@@ -126,14 +129,15 @@ public class FeatureDistanceModelTest
     // hiding first two columns shouldn't affect the tree
     alf.getViewport().hideColumns(0, 1);
     FeatureDistanceModel fsm = new FeatureDistanceModel();
-    Assert.assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
+    assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
             .getAlignPanel()));
     alf.selectAllSequenceMenuItem_actionPerformed(null);
-    float[][] dm = fsm.findDistances(alf.getViewport().getAlignmentView(
+    MatrixI dm = fsm
+            .findDistances(alf.getViewport().getAlignmentView(
             true));
-    Assert.assertTrue(dm[0][2] == 0f,
+    assertEquals(dm.getValue(0, 2), 0d,
             "FER1_MESCR (0) should be identical with RAPSA (2)");
-    Assert.assertTrue(dm[0][1] > dm[0][2],
+    assertTrue(dm.getValue(0, 1) > dm.getValue(0, 2),
             "FER1_MESCR (0) should be further from SPIOL (1) than it is from RAPSA (2)");
   }
 
@@ -145,20 +149,23 @@ public class FeatureDistanceModelTest
     alf.getViewport().hideColumns(3, 4);
     alf.getViewport().hideColumns(0, 1);
     FeatureDistanceModel fsm = new FeatureDistanceModel();
-    Assert.assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
+    assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
             .getAlignPanel()));
     alf.selectAllSequenceMenuItem_actionPerformed(null);
-    float[][] dm = fsm.findDistances(alf.getViewport().getAlignmentView(
+    MatrixI dm = fsm
+            .findDistances(alf.getViewport().getAlignmentView(
             true));
-    Assert.assertTrue(
-            dm[0][2] == 0f,
+    assertEquals(
+            dm.getValue(0, 2),
+            0d,
             "After hiding last two columns FER1_MESCR (0) should still be identical with RAPSA (2)");
-    Assert.assertTrue(
-            dm[0][1] == 0f,
+    assertEquals(
+            dm.getValue(0, 1),
+            0d,
             "After hiding last two columns FER1_MESCR (0) should now also be identical with SPIOL (1)");
     for (int s = 0; s < 3; s++)
     {
-      Assert.assertTrue(dm[s][3] > 0f, "After hiding last two columns "
+      assertTrue(dm.getValue(s, 3) > 0d, "After hiding last two columns "
               + alf.getViewport().getAlignment().getSequenceAt(s).getName()
               + "(" + s + ") should still be distinct from FER1_MAIZE (3)");
     }
@@ -179,7 +186,7 @@ public class FeatureDistanceModelTest
     SequenceFeature sf = null;
     sf = new SequenceFeature("disulphide bond", "", 2, 5, Float.NaN, "");
     aseq.addSequenceFeature(sf);
-    Assert.assertTrue(sf.isContactFeature());
+    assertTrue(sf.isContactFeature());
     af.refreshFeatureUI(true);
     af.getFeatureRenderer().setAllVisible(Arrays.asList("disulphide bond"));
     Assert.assertEquals(af.getFeatureRenderer().getDisplayedFeatureTypes()
@@ -241,19 +248,20 @@ public class FeatureDistanceModelTest
     alf.getFeatureRenderer().findAllFeatures(true);
 
     FeatureDistanceModel fsm = new FeatureDistanceModel();
-    Assert.assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
+    assertTrue(fsm.configureFromAlignmentView(alf.getCurrentView()
             .getAlignPanel()));
     alf.selectAllSequenceMenuItem_actionPerformed(null);
 
-    float[][] distances = fsm.findDistances(alf.getViewport()
+    MatrixI distances = fsm.findDistances(alf.getViewport()
             .getAlignmentView(true));
-    assertEquals(distances.length, 2);
-    assertEquals(distances[0][0], 0f);
-    assertEquals(distances[1][1], 0f);
+    assertEquals(distances.width(), 2);
+    assertEquals(distances.height(), 2);
+    assertEquals(distances.getValue(0, 0), 0d);
+    assertEquals(distances.getValue(1, 1), 0d);
     // these left to fail pending resolution of
     // JAL-2424 (dividing score by 6, not 5)
-    assertEquals(distances[0][1], 1f);
-    assertEquals(distances[1][0], 1f);
+    assertEquals(distances.getValue(0, 1), 1f);
+    assertEquals(distances.getValue(1, 0), 1f);
   }
 
 }
index b234d48..01de741 100644 (file)
@@ -171,7 +171,7 @@ public class ScoreMatrixTest
     String[] seqs = new String[] { "FKL", "R D", "QIA", "GWC" };
     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
 
-    MatrixI pairwise = sm.computePairwiseScores(seqs);
+    MatrixI pairwise = sm.findSimilarities(seqs);
 
     /*
      * should be NxN where N = number of sequences
index 594adcd..c4c3edb 100644 (file)
@@ -4,7 +4,10 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
-import jalview.api.analysis.DistanceModelI;
+import jalview.api.analysis.DistanceScoreModelI;
+import jalview.api.analysis.PairwiseScoreModelI;
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.SimilarityScoreModelI;
 
 import java.util.Iterator;
 
@@ -19,45 +22,52 @@ public class ScoreModelsTest
   @Test
   public void testConstructor()
   {
-    Iterator<DistanceModelI> models = ScoreModels.getInstance().getModels()
+    Iterator<ScoreModelI> models = ScoreModels.getInstance().getModels()
             .iterator();
     assertTrue(models.hasNext());
 
     /*
      * models are served in order of addition
      */
-    DistanceModelI sm = models.next();
-    assertTrue(sm instanceof PairwiseDistanceModel);
+    ScoreModelI sm = models.next();
+    assertTrue(sm instanceof SimilarityScoreModelI);
+    assertTrue(sm instanceof PairwiseScoreModelI);
+    assertFalse(sm instanceof DistanceScoreModelI);
     assertEquals(sm.getName(), "BLOSUM62");
-    assertEquals(((PairwiseDistanceModel) sm).getScoreModel()
-            .getPairwiseScore('I', 'R'), -3f);
+    assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('I', 'R'), -3f);
 
     sm = models.next();
-    assertTrue(sm instanceof PairwiseDistanceModel);
+    assertTrue(sm instanceof SimilarityScoreModelI);
+    assertTrue(sm instanceof PairwiseScoreModelI);
+    assertFalse(sm instanceof DistanceScoreModelI);
     assertEquals(sm.getName(), "PAM250");
-    assertEquals(((PairwiseDistanceModel) sm).getScoreModel()
-            .getPairwiseScore('R', 'C'), -4f);
+    assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('R', 'C'), -4f);
 
     sm = models.next();
-    assertTrue(sm instanceof PairwiseDistanceModel);
+    assertTrue(sm instanceof SimilarityScoreModelI);
+    assertTrue(sm instanceof PairwiseScoreModelI);
+    assertFalse(sm instanceof DistanceScoreModelI);
     assertEquals(sm.getName(), "Identity (SeqSpace)");
-    assertEquals(((PairwiseDistanceModel) sm).getScoreModel()
-            .getPairwiseScore('R', 'C'), 0f);
-    assertEquals(((PairwiseDistanceModel) sm).getScoreModel()
-            .getPairwiseScore('R', 'r'), 1f);
+    assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('R', 'C'), 0f);
+    assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('R', 'r'), 1f);
 
     sm = models.next();
-    assertTrue(sm instanceof PairwiseDistanceModel);
+    assertTrue(sm instanceof SimilarityScoreModelI);
+    assertTrue(sm instanceof PairwiseScoreModelI);
+    assertFalse(sm instanceof DistanceScoreModelI);
     assertEquals(sm.getName(), "DNA");
-    assertEquals(((PairwiseDistanceModel) sm).getScoreModel()
-            .getPairwiseScore('c', 'x'), 1f);
+    assertEquals(((PairwiseScoreModelI) sm).getPairwiseScore('c', 'x'), 1f);
 
     sm = models.next();
-    assertFalse(sm instanceof PairwiseDistanceModel);
+    assertFalse(sm instanceof SimilarityScoreModelI);
+    assertFalse(sm instanceof PairwiseScoreModelI);
+    assertTrue(sm instanceof DistanceScoreModelI);
     assertEquals(sm.getName(), "Sequence Feature Similarity");
 
     sm = models.next();
-    assertFalse(sm instanceof PairwiseDistanceModel);
+    assertFalse(sm instanceof SimilarityScoreModelI);
+    assertFalse(sm instanceof PairwiseScoreModelI);
+    assertTrue(sm instanceof DistanceScoreModelI);
     assertEquals(sm.getName(), "PID");
   }
 
@@ -92,17 +102,11 @@ public class ScoreModelsTest
    */
   protected void printAllMatrices(boolean asHtml)
   {
-    for (DistanceModelI dm : ScoreModels.getInstance().getModels())
+    for (ScoreModelI sm : ScoreModels.getInstance().getModels())
     {
-      if (dm instanceof PairwiseDistanceModel)
+      if (sm instanceof ScoreMatrix)
       {
-        PairwiseScoreModelI psm = ((PairwiseDistanceModel) dm)
-                .getScoreModel();
-        if (psm instanceof ScoreMatrix)
-        {
-          ScoreMatrix sm = (ScoreMatrix) psm;
-          System.out.println(sm.outputMatrix(asHtml));
-        }
+        System.out.println(((ScoreMatrix) sm).outputMatrix(asHtml));
       }
     }
   }
index f955879..ec1779b 100644 (file)
@@ -129,12 +129,14 @@ public class ComparisonTest
     int length = seq1.length();
 
     // match gap-residue, match gap-gap: 9/10 identical
+    // TODO should gap-gap be included in a PID score? JAL-791
     assertEquals(90f, Comparison.PID(seq1, seq2, 0, length, true, false),
             0.001f);
     // overloaded version of the method signature above:
     assertEquals(90f, Comparison.PID(seq1, seq2), 0.001f);
 
     // don't match gap-residue, match gap-gap: 7/10 identical
+    // TODO should gap-gap be included in a PID score?
     assertEquals(70f, Comparison.PID(seq1, seq2, 0, length, false, false),
             0.001f);
   }