JAL-2416 score matrix gap symbol (if any) dynamically determined
[jalview.git] / src / jalview / analysis / scoremodels / ScoreMatrix.java
index 41d7383..b904432 100644 (file)
@@ -30,10 +30,20 @@ import jalview.util.Comparison;
 
 import java.util.Arrays;
 
+/**
+ * A class that models a substitution score matrix for any given alphabet of
+ * symbols
+ */
 public class ScoreMatrix implements SimilarityScoreModelI,
         PairwiseScoreModelI
 {
   /*
+   * this fields records which gap character (if any) is used in the alphabet;
+   * space, dash or dot are recognised as gap symbols
+   */
+  private char gapCharacter = '0';
+
+  /*
    * 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)
@@ -49,10 +59,16 @@ public class ScoreMatrix implements SimilarityScoreModelI,
 
   /*
    * the name of the model as shown in menus
+   * each score model in use should have a unique name
    */
   private String name;
 
   /*
+   * a description for the model as shown in tooltips
+   */
+  private String description;
+
+  /*
    * the characters that the model provides scores for
    */
   private char[] symbols;
@@ -79,21 +95,21 @@ public class ScoreMatrix implements SimilarityScoreModelI,
    * of symbols. The matrix should be square and of the same size as the
    * alphabet, for example 20x20 for a 20 symbol alphabet.
    * 
-   * @param name
+   * @param theName
    *          Unique, human readable name for the matrix
    * @param alphabet
    *          the symbols to which scores apply
-   * @param matrix
+   * @param values
    *          Pairwise scores indexed according to the symbol alphabet
    */
-  public ScoreMatrix(String name, char[] alphabet, float[][] matrix)
+  public ScoreMatrix(String theName, char[] alphabet, float[][] values)
   {
-    if (alphabet.length != matrix.length)
+    if (alphabet.length != values.length)
     {
       throw new IllegalArgumentException(
               "score matrix size must match alphabet size");
     }
-    for (float[] row : matrix)
+    for (float[] row : values)
     {
       if (row.length != alphabet.length)
       {
@@ -102,8 +118,8 @@ public class ScoreMatrix implements SimilarityScoreModelI,
       }
     }
 
-    this.matrix = matrix;
-    this.name = name;
+    this.matrix = values;
+    this.name = theName;
     this.symbols = alphabet;
 
     symbolIndex = buildSymbolIndex(alphabet);
@@ -124,17 +140,25 @@ public class ScoreMatrix implements SimilarityScoreModelI,
    * Mappings are added automatically for lower case symbols (for non case
    * sensitive scoring), unless they are explicitly present in the alphabet (are
    * scored separately in the score matrix).
+   * <p>
+   * the gap character (space, dash or dot) included in the alphabet (if any) is
+   * recorded in a field
    * 
    * @param alphabet
    * @return
    */
-  static short[] buildSymbolIndex(char[] alphabet)
+  short[] buildSymbolIndex(char[] alphabet)
   {
     short[] index = new short[MAX_ASCII + 1];
     Arrays.fill(index, UNMAPPED);
     short pos = 0;
     for (char c : alphabet)
     {
+      if (Comparison.isGap(c))
+      {
+        gapCharacter = c;
+      }
+
       if (c <= MAX_ASCII)
       {
         index[c] = pos;
@@ -163,6 +187,12 @@ public class ScoreMatrix implements SimilarityScoreModelI,
   }
 
   @Override
+  public String getDescription()
+  {
+    return description;
+  }
+
+  @Override
   public boolean isDNA()
   {
     return !peptide;
@@ -215,6 +245,19 @@ public class ScoreMatrix implements SimilarityScoreModelI,
   }
 
   /**
+   * Answers the matrix index for the gap character, or -1 if unmapped in the
+   * matrix. Use this method only if using <code>getMatrix</code> in order to
+   * compute scores directly (without symbol lookup) for efficiency.
+   * 
+   * @return
+   * @see #getMatrix()
+   */
+  public int getGapIndex()
+  {
+    return getMatrixIndex(gapCharacter);
+  }
+
+  /**
    * Returns the pairwise score for substituting c with d, or zero if c or d is
    * an unscored or unexpected character
    */
@@ -350,7 +393,8 @@ public class ScoreMatrix implements SimilarityScoreModelI,
   public MatrixI findSimilarities(AlignmentView seqstrings,
           SimilarityParamsI options)
   {
-    char gapChar = scoreGapAsAny ? (seqstrings.isNa() ? 'N' : 'X') : ' ';
+    char gapChar = scoreGapAsAny ? (seqstrings.isNa() ? 'N' : 'X')
+            : Comparison.GAP_DASH;
     String[] seqs = seqstrings.getSequenceStrings(gapChar);
     return findSimilarities(seqs, options);
   }
@@ -408,9 +452,9 @@ public class ScoreMatrix implements SimilarityScoreModelI,
           break;
         }
       }
-      // Change GAP_SPACE to GAP_DASH if we adopt - for gap in matrices
-      char c1 = i >= len1 ? Comparison.GAP_SPACE : seq1.charAt(i);
-      char c2 = i >= len2 ? Comparison.GAP_SPACE : seq2.charAt(i);
+
+      char c1 = i >= len1 ? gapCharacter : seq1.charAt(i);
+      char c2 = i >= len2 ? gapCharacter : seq2.charAt(i);
       boolean gap1 = Comparison.isGap(c1);
       boolean gap2 = Comparison.isGap(c2);
 
@@ -429,7 +473,7 @@ public class ScoreMatrix implements SimilarityScoreModelI,
         /*
          * gap-residue: score if options say so
          */
-        if (!params.includesGaps())
+        if (!params.includeGaps())
         {
           continue;
         }
@@ -484,4 +528,9 @@ public class ScoreMatrix implements SimilarityScoreModelI,
   {
     return new String(symbols);
   }
+
+  public void setDescription(String desc)
+  {
+    description = desc;
+  }
 }