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