16d95049639a2deb9f9ef515f9f069e3b72d064e
[jalview.git] / test / jalview / analysis / scoremodels / ScoreMatrixTest.java
1 package jalview.analysis.scoremodels;
2
3 import static org.testng.Assert.assertEquals;
4 import static org.testng.Assert.assertFalse;
5 import static org.testng.Assert.assertNotEquals;
6 import static org.testng.Assert.assertNotNull;
7 import static org.testng.Assert.assertNotSame;
8 import static org.testng.Assert.assertNull;
9 import static org.testng.Assert.assertTrue;
10 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
11
12 import jalview.api.analysis.SimilarityParamsI;
13 import jalview.io.DataSourceType;
14 import jalview.io.FileParse;
15 import jalview.io.ScoreMatrixFile;
16 import jalview.math.MatrixI;
17 import jalview.schemes.ResidueProperties;
18
19 import java.io.IOException;
20 import java.net.MalformedURLException;
21 import java.util.Arrays;
22
23 import org.testng.annotations.Test;
24
25 public class ScoreMatrixTest
26 {
27   @Test(groups = "Functional")
28   public void testConstructor()
29   {
30     // note score matrix does not have to be symmetric (though it should be!)
31     float[][] scores = new float[3][];
32     scores[0] = new float[] { 1f, 2f, 3f };
33     scores[1] = new float[] { -4f, 5f, 6f };
34     scores[2] = new float[] { 7f, 8f, 9f };
35     ScoreMatrix sm = new ScoreMatrix("Test", "ABC".toCharArray(), scores);
36     assertEquals(sm.getSize(), 3);
37     assertArrayEquals(scores, sm.getMatrix());
38     assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
39     assertEquals(sm.getPairwiseScore('b', 'c'), 6f);
40     assertEquals(sm.getPairwiseScore('c', 'b'), 8f);
41     assertEquals(sm.getMatrixIndex('c'), 2);
42     assertEquals(sm.getMatrixIndex(' '), -1);
43
44     // substitution to or from unknown symbol gets minimum score
45     assertEquals(sm.getPairwiseScore('A', 'D'), -4f);
46     assertEquals(sm.getPairwiseScore('D', 'A'), -4f);
47     // unknown-to-self gets a score of 1
48     assertEquals(sm.getPairwiseScore('D', 'D'), 1f);
49
50     assertEquals(sm.getGapIndex(), -1); // no gap symbol
51   }
52
53   @Test(
54     groups = "Functional",
55     expectedExceptions = { IllegalArgumentException.class })
56   public void testConstructor_matrixTooSmall()
57   {
58     float[][] scores = new float[2][];
59     scores[0] = new float[] { 1f, 2f };
60     scores[1] = new float[] { 3f, 4f };
61     new ScoreMatrix("Test", "ABC".toCharArray(), scores);
62   }
63
64   @Test(
65     groups = "Functional",
66     expectedExceptions = { IllegalArgumentException.class })
67   public void testConstructor_matrixTooBig()
68   {
69     float[][] scores = new float[2][];
70     scores[0] = new float[] { 1f, 2f };
71     scores[1] = new float[] { 3f, 4f };
72     new ScoreMatrix("Test", "A".toCharArray(), scores);
73   }
74
75   @Test(
76     groups = "Functional",
77     expectedExceptions = { IllegalArgumentException.class })
78   public void testConstructor_matrixNotSquare()
79   {
80     float[][] scores = new float[2][];
81     scores[0] = new float[] { 1f, 2f };
82     scores[1] = new float[] { 3f };
83     new ScoreMatrix("Test", "AB".toCharArray(), scores);
84   }
85
86   @Test(groups = "Functional")
87   public void testBuildSymbolIndex()
88   {
89     float[][] scores = new float[2][];
90     scores[0] = new float[] { 1f, 2f };
91     scores[1] = new float[] { 3f, 4f };
92     ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '.' },
93             scores);
94     short[] index = sm.buildSymbolIndex("AX-yxYp".toCharArray());
95
96     assertEquals(index.length, 128); // ASCII character set size
97
98     assertEquals(index['A'], 0);
99     assertEquals(index['a'], 0); // lower-case mapping added
100     assertEquals(index['X'], 1);
101     assertEquals(index['-'], 2);
102     assertEquals(index['y'], 3); // lower-case override
103     assertEquals(index['x'], 4); // lower-case override
104     assertEquals(index['Y'], 5);
105     assertEquals(index['p'], 6);
106     assertEquals(index['P'], -1); // lower-case doesn't map upper-case
107
108     /*
109      * check all unmapped symbols have index for unmapped
110      */
111     for (int c = 0; c < index.length; c++)
112     {
113       if (!"AaXx-. Yyp".contains(String.valueOf((char) c)))
114       {
115         assertEquals(index[c], -1);
116       }
117     }
118   }
119
120   /**
121    * check that characters not in the basic ASCII set are simply ignored
122    */
123   @Test(groups = "Functional")
124   public void testBuildSymbolIndex_nonAscii()
125   {
126     float[][] scores = new float[2][];
127     scores[0] = new float[] { 1f, 2f };
128     scores[1] = new float[] { 3f, 4f };
129     ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '.' },
130             scores);
131     char[] weird = new char[] { 128, 245, 'P' };
132     short[] index = sm.buildSymbolIndex(weird);
133     assertEquals(index.length, 128);
134     assertEquals(index['P'], 2);
135     assertEquals(index['p'], 2);
136     for (int c = 0; c < index.length; c++)
137     {
138       if (c != 'P' && c != 'p')
139       {
140         assertEquals(index[c], -1);
141       }
142     }
143   }
144
145   @Test(groups = "Functional")
146   public void testGetMatrix()
147   {
148     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
149     float[][] m = sm.getMatrix();
150     assertEquals(m.length, sm.getSize());
151     assertEquals(m[2][4], -3f);
152     // verify a defensive copy is returned
153     float[][] m2 = sm.getMatrix();
154     assertNotSame(m, m2);
155     assertTrue(Arrays.deepEquals(m, m2));
156   }
157
158   @Test(groups = "Functional")
159   public void testGetMatrixIndex()
160   {
161     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
162     assertEquals(sm.getMatrixIndex('A'), 0);
163     assertEquals(sm.getMatrixIndex('R'), 1);
164     assertEquals(sm.getMatrixIndex('r'), 1);
165     assertEquals(sm.getMatrixIndex('N'), 2);
166     assertEquals(sm.getMatrixIndex('D'), 3);
167     assertEquals(sm.getMatrixIndex('X'), 22);
168     assertEquals(sm.getMatrixIndex('x'), 22);
169     assertEquals(sm.getMatrixIndex('-'), 23);
170     assertEquals(sm.getMatrixIndex('*'), -1);
171     assertEquals(sm.getMatrixIndex('.'), -1);
172     assertEquals(sm.getMatrixIndex(' '), -1);
173     assertEquals(sm.getMatrixIndex('?'), -1);
174     assertEquals(sm.getMatrixIndex((char) 128), -1);
175   }
176
177   @Test(groups = "Functional")
178   public void testGetGapIndex()
179   {
180     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
181     assertEquals(sm.getGapIndex(), 23);
182   }
183
184   @Test(groups = "Functional")
185   public void testGetSize()
186   {
187     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
188     assertEquals(sm.getMatrix().length, sm.getSize());
189   }
190
191   @Test(groups = "Functional")
192   public void testComputePairwiseScores()
193   {
194     /*
195      * NB score matrix expects '-' for gap
196      */
197     String[] seqs = new String[] { "FKL", "R-D", "QIA", "GWC" };
198     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
199
200     MatrixI pairwise = sm.findSimilarities(seqs, SimilarityParams.Jalview);
201
202     /*
203      * should be NxN where N = number of sequences
204      */
205     assertEquals(pairwise.height(), 4);
206     assertEquals(pairwise.width(), 4);
207
208     /*
209      * should be symmetrical (because BLOSUM62 is)
210      */
211     for (int i = 0; i < pairwise.height(); i++)
212     {
213       for (int j = i + 1; j < pairwise.width(); j++)
214       {
215         assertEquals(pairwise.getValue(i, j), pairwise.getValue(j, i),
216                 String.format("Not symmetric at [%d, %d]", i, j));
217       }
218     }
219     /*
220      * verify expected BLOSUM dot product scores
221      */
222     // F.F + K.K + L.L = 6 + 5 + 4 = 15
223     assertEquals(pairwise.getValue(0, 0), 15d);
224     // R.R + -.- + D.D = 5 + 1 + 6 = 12
225     assertEquals(pairwise.getValue(1, 1), 12d);
226     // Q.Q + I.I + A.A = 5 + 4 + 4 = 13
227     assertEquals(pairwise.getValue(2, 2), 13d);
228     // G.G + W.W + C.C = 6 + 11 + 9 = 26
229     assertEquals(pairwise.getValue(3, 3), 26d);
230     // F.R + K.- + L.D = -3 + -4 + -4 = -11
231     assertEquals(pairwise.getValue(0, 1), -11d);
232     // F.Q + K.I + L.A = -3 + -3 + -1 = -7
233     assertEquals(pairwise.getValue(0, 2), -7d);
234     // F.G + K.W + L.C = -3 + -3 + -1 = -7
235     assertEquals(pairwise.getValue(0, 3), -7d);
236     // R.Q + -.I + D.A = 1 + -4 + -2 = -5
237     assertEquals(pairwise.getValue(1, 2), -5d);
238     // R.G + -.W + D.C = -2 + -4 + -3 = -9
239     assertEquals(pairwise.getValue(1, 3), -9d);
240     // Q.G + I.W + A.C = -2 + -3 + 0 = -5
241     assertEquals(pairwise.getValue(2, 3), -5d);
242   }
243
244   /**
245    * Test that the result of outputMatrix can be reparsed to give an identical
246    * ScoreMatrix
247    * 
248    * @throws IOException
249    * @throws MalformedURLException
250    */
251   @Test(groups = "Functional")
252   public void testOutputMatrix_roundTrip() throws MalformedURLException,
253           IOException
254   {
255     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
256     String output = sm.outputMatrix(false);
257     FileParse fp = new FileParse(output, DataSourceType.PASTE);
258     ScoreMatrixFile parser = new ScoreMatrixFile(fp);
259     ScoreMatrix sm2 = parser.parseMatrix();
260     assertNotNull(sm2);
261     assertTrue(sm2.equals(sm));
262   }
263
264   @Test(groups = "Functional")
265   public void testEqualsAndHashCode()
266   {
267     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
268     ScoreMatrix sm2 = new ScoreMatrix(sm.getName(), sm.getSymbols()
269             .toCharArray(), sm.getMatrix());
270     assertTrue(sm.equals(sm2));
271     assertEquals(sm.hashCode(), sm2.hashCode());
272
273     sm2 = ScoreModels.getInstance().getPam250();
274     assertFalse(sm.equals(sm2));
275     assertNotEquals(sm.hashCode(), sm2.hashCode());
276
277     assertFalse(sm.equals("hello"));
278   }
279
280   /**
281    * Tests for scoring options where the longer length of two sequences is used
282    */
283   @Test(groups = "Functional")
284   public void testcomputeSimilarity_matchLongestSequence()
285   {
286     /*
287      * ScoreMatrix expects '-' for gaps
288      */
289     String s1 = "FR-K-S";
290     String s2 = "FS--L";
291     ScoreMatrix blosum = ScoreModels.getInstance().getBlosum62();
292   
293     /*
294      * score gap-gap and gap-char
295      * shorter sequence treated as if with trailing gaps
296      * score = F^F + R^S + -^- + K^- + -^L + S^-
297      * = 6 + -1 + 1 + -4 + -4 + -4 = -6
298      */
299     SimilarityParamsI params = new SimilarityParams(true, true, true, false);
300     assertEquals(blosum.computeSimilarity(s1, s2, params), -6d);
301     // matchGap (arg2) is ignored:
302     params = new SimilarityParams(true, false, true, false);
303     assertEquals(blosum.computeSimilarity(s1, s2, params), -6d);
304   
305     /*
306      * score gap-char but not gap-gap
307      * score = F^F + R^S + 0 + K^- + -^L + S^-
308      * = 6 + -1 + 0 + -4 + -4 + -4 = -7
309      */
310     params = new SimilarityParams(false, true, true, false);
311     assertEquals(blosum.computeSimilarity(s1, s2, params), -7d);
312     // matchGap (arg2) is ignored:
313     params = new SimilarityParams(false, false, true, false);
314     assertEquals(blosum.computeSimilarity(s1, s2, params), -7d);
315   
316     /*
317      * score gap-gap but not gap-char
318      * score = F^F + R^S + -^- + 0 + 0 + 0
319      * = 6 + -1 + 1 = 6
320      */
321     params = new SimilarityParams(true, false, false, false);
322     assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
323     // matchGap (arg2) is ignored:
324     params = new SimilarityParams(true, true, false, false);
325     assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
326   
327     /*
328      * score neither gap-gap nor gap-char
329      * score = F^F + R^S + 0 + 0 + 0 + 0
330      * = 6 + -1  = 5
331      */
332     params = new SimilarityParams(false, false, false, false);
333     assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
334     // matchGap (arg2) is ignored:
335     params = new SimilarityParams(false, true, false, false);
336     assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
337   }
338
339   /**
340    * Tests for scoring options where only the shorter length of two sequences is
341    * used
342    */
343   @Test(groups = "Functional")
344   public void testcomputeSimilarity_matchShortestSequence()
345   {
346     /*
347      * ScoreMatrix expects '-' for gaps
348      */
349     String s1 = "FR-K-S";
350     String s2 = "FS--L";
351     ScoreMatrix blosum = ScoreModels.getInstance().getBlosum62();
352
353     /*
354      * score gap-gap and gap-char
355      * match shorter sequence only
356      * score = F^F + R^S + -^- + K^- + -^L
357      * = 6 + -1 + 1 + -4 + -4 = -2
358      */
359     SimilarityParamsI params = new SimilarityParams(true, true, true, true);
360     assertEquals(blosum.computeSimilarity(s1, s2, params), -2d);
361     // matchGap (arg2) is ignored:
362     params = new SimilarityParams(true, false, true, true);
363     assertEquals(blosum.computeSimilarity(s1, s2, params), -2d);
364   
365     /*
366      * score gap-char but not gap-gap
367      * score = F^F + R^S + 0 + K^- + -^L
368      * = 6 + -1 + 0 + -4 + -4 = -3
369      */
370     params = new SimilarityParams(false, true, true, true);
371     assertEquals(blosum.computeSimilarity(s1, s2, params), -3d);
372     // matchGap (arg2) is ignored:
373     params = new SimilarityParams(false, false, true, true);
374     assertEquals(blosum.computeSimilarity(s1, s2, params), -3d);
375   
376     /*
377      * score gap-gap but not gap-char
378      * score = F^F + R^S + -^- + 0 + 0
379      * = 6 + -1 + 1 = 6
380      */
381     params = new SimilarityParams(true, false, false, true);
382     assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
383     // matchGap (arg2) is ignored:
384     params = new SimilarityParams(true, true, false, true);
385     assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
386   
387     /*
388      * score neither gap-gap nor gap-char
389      * score = F^F + R^S + 0 + 0 + 0
390      * = 6 + -1  = 5
391      */
392     params = new SimilarityParams(false, false, false, true);
393     assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
394     // matchGap (arg2) is ignored:
395     params = new SimilarityParams(false, true, false, true);
396     assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
397   }
398
399   @Test(groups = "Functional")
400   public void testSymmetric()
401   {
402     verifySymmetric(ScoreModels.getInstance().getBlosum62());
403     verifySymmetric(ScoreModels.getInstance().getPam250());
404     verifySymmetric(ScoreModels.getInstance().getDefaultModel(false)); // dna
405   }
406
407   private void verifySymmetric(ScoreMatrix sm)
408   {
409     float[][] m = sm.getMatrix();
410     int rows = m.length;
411     for (int row = 0; row < rows; row++)
412     {
413       assertEquals(m[row].length, rows);
414       for (int col = 0; col < rows; col++)
415       {
416         assertEquals(m[row][col], m[col][row], String.format("%s [%s, %s]",
417                 sm.getName(), ResidueProperties.aa[row],
418                 ResidueProperties.aa[col]));
419       }
420     }
421   }
422
423   /**
424    * A test that just asserts the expected values in the Blosum62 score matrix
425    */
426   @Test(groups = "Functional")
427   public void testBlosum62_values()
428   {
429     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
430
431     assertTrue(sm.isProtein());
432     assertFalse(sm.isDNA());
433     assertNull(sm.getDescription());
434     sm.setDescription("BLOSUM62");
435     assertEquals(sm.getDescription(), "BLOSUM62");
436
437     /*
438      * verify expected scores against ARNDCQEGHILKMFPSTWYVBZX
439      * scraped from https://www.ncbi.nlm.nih.gov/Class/FieldGuide/BLOSUM62.txt
440      */
441     verifyValues(sm, 'A', new float[] { 4, -1, -2, -2, 0, -1, -1, 0, -2,
442         -1,
443         -1, -1, -1, -2, -1, 1, 0, -3, -2, 0, -2, -1, 0 });
444     verifyValues(sm, 'R', new float[] { -1, 5, 0, -2, -3, 1, 0, -2, 0, -3,
445         -2, 2, -1, -3, -2, -1, -1, -3, -2, -3, -1, 0, -1 });
446     verifyValues(sm, 'N', new float[] { -2, 0, 6, 1, -3, 0, 0, 0, 1, -3,
447         -3,
448         0, -2, -3, -2, 1, 0, -4, -2, -3, 3, 0, -1 });
449     verifyValues(sm, 'D', new float[] { -2, -2, 1, 6, -3, 0, 2, -1, -1, -3,
450         -4, -1, -3, -3, -1, 0, -1, -4, -3, -3, 4, 1, -1 });
451     verifyValues(sm, 'C', new float[] { 0, -3, -3, -3, 9, -3, -4, -3, -3,
452         -1,
453         -1, -3, -1, -2, -3, -1, -1, -2, -2, -1, -3, -3, -2 });
454     verifyValues(sm, 'Q', new float[] { -1, 1, 0, 0, -3, 5, 2, -2, 0, -3,
455         -2,
456         1, 0, -3, -1, 0, -1, -2, -1, -2, 0, 3, -1 });
457     verifyValues(sm, 'E', new float[] { -1, 0, 0, 2, -4, 2, 5, -2, 0, -3,
458         -3,
459         1, -2, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1 });
460     verifyValues(sm, 'G', new float[] { 0, -2, 0, -1, -3, -2, -2, 6, -2,
461         -4,
462         -4, -2, -3, -3, -2, 0, -2, -2, -3, -3, -1, -2, -1 });
463     verifyValues(sm, 'H', new float[] { -2, 0, 1, -1, -3, 0, 0, -2, 8, -3,
464         -3, -1, -2, -1, -2, -1, -2, -2, 2, -3, 0, 0, -1 });
465     verifyValues(sm, 'I', new float[] { -1, -3, -3, -3, -1, -3, -3, -4, -3,
466         4, 2, -3, 1, 0, -3, -2, -1, -3, -1, 3, -3, -3, -1 });
467     verifyValues(sm, 'L', new float[] { -1, -2, -3, -4, -1, -2, -3, -4, -3,
468         2, 4, -2, 2, 0, -3, -2, -1, -2, -1, 1, -4, -3, -1 });
469     verifyValues(sm, 'K', new float[] { -1, 2, 0, -1, -3, 1, 1, -2, -1, -3,
470         -2, 5, -1, -3, -1, 0, -1, -3, -2, -2, 0, 1, -1 });
471     verifyValues(sm, 'M', new float[] { -1, -1, -2, -3, -1, 0, -2, -3, -2,
472         1,
473         2, -1, 5, 0, -2, -1, -1, -1, -1, 1, -3, -1, -1 });
474     verifyValues(sm, 'F', new float[] { -2, -3, -3, -3, -2, -3, -3, -3, -1,
475         0, 0, -3, 0, 6, -4, -2, -2, 1, 3, -1, -3, -3, -1 });
476     verifyValues(sm, 'P', new float[] { -1, -2, -2, -1, -3, -1, -1, -2, -2,
477         -3, -3, -1, -2, -4, 7, -1, -1, -4, -3, -2, -2, -1, -2 });
478     verifyValues(sm, 'S', new float[] { 1, -1, 1, 0, -1, 0, 0, 0, -1, -2,
479         -2,
480         0, -1, -2, -1, 4, 1, -3, -2, -2, 0, 0, 0 });
481     verifyValues(sm, 'T', new float[] { 0, -1, 0, -1, -1, -1, -1, -2, -2,
482         -1,
483         -1, -1, -1, -2, -1, 1, 5, -2, -2, 0, -1, -1, 0 });
484     verifyValues(sm, 'W', new float[] { -3, -3, -4, -4, -2, -2, -3, -2, -2,
485         -3, -2, -3, -1, 1, -4, -3, -2, 11, 2, -3, -4, -3, -2 });
486     verifyValues(sm, 'Y', new float[] { -2, -2, -2, -3, -2, -1, -2, -3, 2,
487         -1, -1, -2, -1, 3, -3, -2, -2, 2, 7, -1, -3, -2, -1 });
488     verifyValues(sm, 'V', new float[] { 0, -3, -3, -3, -1, -2, -2, -3, -3,
489         3,
490         1, -2, 1, -1, -2, -2, 0, -3, -1, 4, -3, -2, -1 });
491     verifyValues(sm, 'B', new float[] { -2, -1, 3, 4, -3, 0, 1, -1, 0, -3,
492         -4, 0, -3, -3, -2, 0, -1, -4, -3, -3, 4, 1, -1 });
493     verifyValues(sm, 'Z', new float[] { -1, 0, 0, 1, -3, 3, 4, -2, 0, -3,
494         -3,
495         1, -1, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1 });
496     verifyValues(sm, 'X', new float[] { 0, -1, -1, -1, -2, -1, -1, -1, -1,
497         -1, -1, -1, -1, -1, -2, 0, 0, -2, -1, -1, -1, -1, -1 });
498   }
499
500   /**
501    * Helper method to check pairwise scores for one residue
502    * 
503    * @param sm
504    * @param res
505    * @param expected
506    *          score values against 'res', in ResidueProperties.aaIndex order
507    */
508   private void verifyValues(ScoreMatrix sm, char res, float[] expected)
509   {
510     for (int j = 0; j < expected.length; j++)
511     {
512       char c2 = ResidueProperties.aa[j].charAt(0);
513       assertEquals(sm.getPairwiseScore(res, c2), expected[j],
514               String.format("%s->%s", res, c2));
515     }
516   }
517
518   @Test(groups = "Functional")
519   public void testConstructor_gapDash()
520   {
521     float[][] scores = new float[2][];
522     scores[0] = new float[] { 1f, 2f };
523     scores[1] = new float[] { 4f, 5f };
524     ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '-' },
525             scores);
526     assertEquals(sm.getSize(), 2);
527     assertArrayEquals(scores, sm.getMatrix());
528     assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
529     assertEquals(sm.getPairwiseScore('A', 'A'), 1f);
530     assertEquals(sm.getPairwiseScore('a', '-'), 2f);
531     assertEquals(sm.getPairwiseScore('-', 'A'), 4f);
532     assertEquals(sm.getMatrixIndex('a'), 0);
533     assertEquals(sm.getMatrixIndex('A'), 0);
534     assertEquals(sm.getMatrixIndex('-'), 1);
535     assertEquals(sm.getMatrixIndex(' '), -1);
536     assertEquals(sm.getMatrixIndex('.'), -1);
537   
538     assertEquals(sm.getGapIndex(), 1);
539   }
540
541   @Test(groups = "Functional")
542   public void testGetPairwiseScore()
543   {
544     float[][] scores = new float[2][];
545     scores[0] = new float[] { 1f, 2f };
546     scores[1] = new float[] { -4f, 5f };
547     ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', 'B' },
548             scores);
549     assertEquals(sm.getPairwiseScore('A', 'A'), 1f);
550     assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
551     assertEquals(sm.getPairwiseScore('A', 'B'), 2f);
552     assertEquals(sm.getPairwiseScore('b', 'a'), -4f);
553     assertEquals(sm.getPairwiseScore('B', 'b'), 5f);
554
555     /*
556      * unknown symbols currently score minimum score
557      * or 1 for identity with self
558      */
559     assertEquals(sm.getPairwiseScore('A', '-'), -4f);
560     assertEquals(sm.getPairwiseScore('-', 'A'), -4f);
561     assertEquals(sm.getPairwiseScore('-', '-'), 1f);
562     assertEquals(sm.getPairwiseScore('Q', 'W'), -4f);
563     assertEquals(sm.getPairwiseScore('Q', 'Q'), 1f);
564
565     /*
566      * symbols not in basic ASCII set score zero
567      */
568     char c = (char) 200;
569     assertEquals(sm.getPairwiseScore('Q', c), 0f);
570     assertEquals(sm.getPairwiseScore(c, 'Q'), 0f);
571   }
572
573   @Test(groups = "Functional")
574   public void testGetMinimumScore()
575   {
576     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
577     assertEquals(sm.getMinimumScore(), -4f);
578   }
579
580   @Test(groups = "Functional")
581   public void testGetMaximumScore()
582   {
583     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
584     assertEquals(sm.getMaximumScore(), 11f);
585   }
586
587   @Test(groups = "Functional")
588   public void testOutputMatrix_html()
589   {
590     float[][] scores = new float[2][];
591     scores[0] = new float[] { 1f, 2f };
592     scores[1] = new float[] { 4f, -5.3E-10f };
593     ScoreMatrix sm = new ScoreMatrix("Test", "AB".toCharArray(), scores);
594     String html = sm.outputMatrix(true);
595     String expected = "<table border=\"1\"><tr><th></th><th>&nbsp;A&nbsp;</th><th>&nbsp;B&nbsp;</th></tr>\n"
596             + "<tr><td>A</td><td>1.0</td><td>2.0</td></tr>\n"
597             + "<tr><td>B</td><td>4.0</td><td>-5.3E-10</td></tr>\n"
598             + "</table>";
599     assertEquals(html, expected);
600   }
601 }