1 package jalview.analysis.scoremodels;
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;
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.Matrix;
17 import jalview.math.MatrixI;
18 import jalview.schemes.ResidueProperties;
20 import java.io.IOException;
21 import java.net.MalformedURLException;
22 import java.util.Arrays;
24 import org.testng.annotations.Test;
26 import junit.extensions.PA;
28 public class ScoreMatrixTest
30 @Test(groups = "Functional")
31 public void testConstructor()
33 // note score matrix does not have to be symmetric (though it should be!)
34 float[][] scores = new float[3][];
35 scores[0] = new float[] { 1f, 2f, 3f };
36 scores[1] = new float[] { -4f, 5f, 6f };
37 scores[2] = new float[] { 7f, 8f, 9f };
38 ScoreMatrix sm = new ScoreMatrix("Test", "ABC".toCharArray(), scores);
39 assertFalse(sm.isSymmetric());
40 assertEquals(sm.getSize(), 3);
41 assertArrayEquals(scores, sm.getMatrix());
42 assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
43 assertEquals(sm.getPairwiseScore('b', 'c'), 6f);
44 assertEquals(sm.getPairwiseScore('c', 'b'), 8f);
45 assertEquals(sm.getMatrixIndex('c'), 2);
46 assertEquals(sm.getMatrixIndex(' '), -1);
48 // substitution to or from unknown symbol gets minimum score
49 assertEquals(sm.getPairwiseScore('A', 'D'), -4f);
50 assertEquals(sm.getPairwiseScore('D', 'A'), -4f);
51 // unknown-to-self gets a score of 1
52 assertEquals(sm.getPairwiseScore('D', 'D'), 1f);
56 groups = "Functional",
57 expectedExceptions = { IllegalArgumentException.class })
58 public void testConstructor_matrixTooSmall()
60 float[][] scores = new float[2][];
61 scores[0] = new float[] { 1f, 2f };
62 scores[1] = new float[] { 3f, 4f };
63 new ScoreMatrix("Test", "ABC".toCharArray(), scores);
67 groups = "Functional",
68 expectedExceptions = { IllegalArgumentException.class })
69 public void testConstructor_matrixTooBig()
71 float[][] scores = new float[2][];
72 scores[0] = new float[] { 1f, 2f };
73 scores[1] = new float[] { 3f, 4f };
74 new ScoreMatrix("Test", "A".toCharArray(), scores);
78 groups = "Functional",
79 expectedExceptions = { IllegalArgumentException.class })
80 public void testConstructor_matrixNotSquare()
82 float[][] scores = new float[2][];
83 scores[0] = new float[] { 1f, 2f };
84 scores[1] = new float[] { 3f };
85 new ScoreMatrix("Test", "AB".toCharArray(), scores);
88 @Test(groups = "Functional")
89 public void testBuildSymbolIndex()
91 float[][] scores = new float[2][];
92 scores[0] = new float[] { 1f, 2f };
93 scores[1] = new float[] { 3f, 4f };
94 ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '.' },
96 short[] index = sm.buildSymbolIndex("AX-yxYp".toCharArray());
98 assertEquals(index.length, 128); // ASCII character set size
100 assertEquals(index['A'], 0);
101 assertEquals(index['a'], 0); // lower-case mapping added
102 assertEquals(index['X'], 1);
103 assertEquals(index['-'], 2);
104 assertEquals(index['y'], 3); // lower-case override
105 assertEquals(index['x'], 4); // lower-case override
106 assertEquals(index['Y'], 5);
107 assertEquals(index['p'], 6);
108 assertEquals(index['P'], -1); // lower-case doesn't map upper-case
111 * check all unmapped symbols have index for unmapped
113 for (int c = 0; c < index.length; c++)
115 if (!"AaXx-. Yyp".contains(String.valueOf((char) c)))
117 assertEquals(index[c], -1);
123 * check that characters not in the basic ASCII set are simply ignored
125 @Test(groups = "Functional")
126 public void testBuildSymbolIndex_nonAscii()
128 float[][] scores = new float[2][];
129 scores[0] = new float[] { 1f, 2f };
130 scores[1] = new float[] { 3f, 4f };
131 ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '.' },
133 char[] weird = new char[] { 128, 245, 'P' };
134 short[] index = sm.buildSymbolIndex(weird);
135 assertEquals(index.length, 128);
136 assertEquals(index['P'], 2);
137 assertEquals(index['p'], 2);
138 for (int c = 0; c < index.length; c++)
140 if (c != 'P' && c != 'p')
142 assertEquals(index[c], -1);
147 @Test(groups = "Functional")
148 public void testGetMatrix()
150 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
151 float[][] m = sm.getMatrix();
152 assertEquals(m.length, sm.getSize());
153 assertEquals(m[2][4], -3f);
154 // verify a defensive copy is returned
155 float[][] m2 = sm.getMatrix();
156 assertNotSame(m, m2);
157 assertTrue(Arrays.deepEquals(m, m2));
160 @Test(groups = "Functional")
161 public void testGetMatrixIndex()
163 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
164 assertEquals(sm.getMatrixIndex('A'), 0);
165 assertEquals(sm.getMatrixIndex('R'), 1);
166 assertEquals(sm.getMatrixIndex('r'), 1);
167 assertEquals(sm.getMatrixIndex('N'), 2);
168 assertEquals(sm.getMatrixIndex('D'), 3);
169 assertEquals(sm.getMatrixIndex('X'), 22);
170 assertEquals(sm.getMatrixIndex('x'), 22);
171 assertEquals(sm.getMatrixIndex('-'), -1);
172 assertEquals(sm.getMatrixIndex('*'), 23);
173 assertEquals(sm.getMatrixIndex('.'), -1);
174 assertEquals(sm.getMatrixIndex(' '), -1);
175 assertEquals(sm.getMatrixIndex('?'), -1);
176 assertEquals(sm.getMatrixIndex((char) 128), -1);
179 @Test(groups = "Functional")
180 public void testGetSize()
182 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
183 assertEquals(sm.getMatrix().length, sm.getSize());
186 @Test(groups = "Functional")
187 public void testComputePairwiseScores()
190 * NB score matrix expects '-' for gap
192 String[] seqs = new String[] { "FKL", "R-D", "QIA", "GWC" };
193 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
195 MatrixI pairwise = sm.findSimilarities(seqs, SimilarityParams.Jalview);
198 * should be NxN where N = number of sequences
200 assertEquals(pairwise.height(), 4);
201 assertEquals(pairwise.width(), 4);
204 * should be symmetrical (because BLOSUM62 is)
206 for (int i = 0; i < pairwise.height(); i++)
208 for (int j = i + 1; j < pairwise.width(); j++)
210 assertEquals(pairwise.getValue(i, j), pairwise.getValue(j, i),
211 String.format("Not symmetric at [%d, %d]", i, j));
215 * verify expected BLOSUM dot product scores
217 // F.F + K.K + L.L = 6 + 5 + 4 = 15
218 assertEquals(pairwise.getValue(0, 0), 15d);
219 // R.R + -.- + D.D = 5 + 1 + 6 = 12
220 assertEquals(pairwise.getValue(1, 1), 12d);
221 // Q.Q + I.I + A.A = 5 + 4 + 4 = 13
222 assertEquals(pairwise.getValue(2, 2), 13d);
223 // G.G + W.W + C.C = 6 + 11 + 9 = 26
224 assertEquals(pairwise.getValue(3, 3), 26d);
225 // F.R + K.- + L.D = -3 + -4 + -4 = -11
226 assertEquals(pairwise.getValue(0, 1), -11d);
227 // F.Q + K.I + L.A = -3 + -3 + -1 = -7
228 assertEquals(pairwise.getValue(0, 2), -7d);
229 // F.G + K.W + L.C = -3 + -3 + -1 = -7
230 assertEquals(pairwise.getValue(0, 3), -7d);
231 // R.Q + -.I + D.A = 1 + -4 + -2 = -5
232 assertEquals(pairwise.getValue(1, 2), -5d);
233 // R.G + -.W + D.C = -2 + -4 + -3 = -9
234 assertEquals(pairwise.getValue(1, 3), -9d);
235 // Q.G + I.W + A.C = -2 + -3 + 0 = -5
236 assertEquals(pairwise.getValue(2, 3), -5d);
240 * Test that the result of outputMatrix can be reparsed to give an identical
243 * @throws IOException
244 * @throws MalformedURLException
246 @Test(groups = "Functional")
247 public void testOutputMatrix_roundTrip() throws MalformedURLException,
250 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
251 String output = sm.outputMatrix(false);
252 FileParse fp = new FileParse(output, DataSourceType.PASTE);
253 ScoreMatrixFile parser = new ScoreMatrixFile(fp);
254 ScoreMatrix sm2 = parser.parseMatrix();
256 assertTrue(sm2.equals(sm));
259 @Test(groups = "Functional")
260 public void testEqualsAndHashCode()
262 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
263 ScoreMatrix sm2 = new ScoreMatrix(sm.getName(), sm.getSymbols()
264 .toCharArray(), sm.getMatrix());
265 assertTrue(sm.equals(sm2));
266 assertEquals(sm.hashCode(), sm2.hashCode());
268 sm2 = ScoreModels.getInstance().getPam250();
269 assertFalse(sm.equals(sm2));
270 assertNotEquals(sm.hashCode(), sm2.hashCode());
272 assertFalse(sm.equals("hello"));
276 * Tests for scoring options where the longer length of two sequences is used
278 @Test(groups = "Functional")
279 public void testcomputeSimilarity_matchLongestSequence()
282 * ScoreMatrix expects '-' for gaps
284 String s1 = "FR-K-S";
286 ScoreMatrix blosum = ScoreModels.getInstance().getBlosum62();
289 * score gap-gap and gap-char
290 * shorter sequence treated as if with trailing gaps
291 * score = F^F + R^S + -^- + K^- + -^L + S^-
292 * = 6 + -1 + 1 + -4 + -4 + -4 = -6
294 SimilarityParamsI params = new SimilarityParams(true, true, true, false);
295 assertEquals(blosum.computeSimilarity(s1, s2, params), -6d);
296 // matchGap (arg2) is ignored:
297 params = new SimilarityParams(true, false, true, false);
298 assertEquals(blosum.computeSimilarity(s1, s2, params), -6d);
301 * score gap-char but not gap-gap
302 * score = F^F + R^S + 0 + K^- + -^L + S^-
303 * = 6 + -1 + 0 + -4 + -4 + -4 = -7
305 params = new SimilarityParams(false, true, true, false);
306 assertEquals(blosum.computeSimilarity(s1, s2, params), -7d);
307 // matchGap (arg2) is ignored:
308 params = new SimilarityParams(false, false, true, false);
309 assertEquals(blosum.computeSimilarity(s1, s2, params), -7d);
312 * score gap-gap but not gap-char
313 * score = F^F + R^S + -^- + 0 + 0 + 0
316 params = new SimilarityParams(true, false, false, false);
317 assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
318 // matchGap (arg2) is ignored:
319 params = new SimilarityParams(true, true, false, false);
320 assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
323 * score neither gap-gap nor gap-char
324 * score = F^F + R^S + 0 + 0 + 0 + 0
327 params = new SimilarityParams(false, false, false, false);
328 assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
329 // matchGap (arg2) is ignored:
330 params = new SimilarityParams(false, true, false, false);
331 assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
335 * Tests for scoring options where only the shorter length of two sequences is
338 @Test(groups = "Functional")
339 public void testcomputeSimilarity_matchShortestSequence()
342 * ScoreMatrix expects '-' for gaps
344 String s1 = "FR-K-S";
346 ScoreMatrix blosum = ScoreModels.getInstance().getBlosum62();
349 * score gap-gap and gap-char
350 * match shorter sequence only
351 * score = F^F + R^S + -^- + K^- + -^L
352 * = 6 + -1 + 1 + -4 + -4 = -2
354 SimilarityParamsI params = new SimilarityParams(true, true, true, true);
355 assertEquals(blosum.computeSimilarity(s1, s2, params), -2d);
356 // matchGap (arg2) is ignored:
357 params = new SimilarityParams(true, false, true, true);
358 assertEquals(blosum.computeSimilarity(s1, s2, params), -2d);
361 * score gap-char but not gap-gap
362 * score = F^F + R^S + 0 + K^- + -^L
363 * = 6 + -1 + 0 + -4 + -4 = -3
365 params = new SimilarityParams(false, true, true, true);
366 assertEquals(blosum.computeSimilarity(s1, s2, params), -3d);
367 // matchGap (arg2) is ignored:
368 params = new SimilarityParams(false, false, true, true);
369 assertEquals(blosum.computeSimilarity(s1, s2, params), -3d);
372 * score gap-gap but not gap-char
373 * score = F^F + R^S + -^- + 0 + 0
376 params = new SimilarityParams(true, false, false, true);
377 assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
378 // matchGap (arg2) is ignored:
379 params = new SimilarityParams(true, true, false, true);
380 assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
383 * score neither gap-gap nor gap-char
384 * score = F^F + R^S + 0 + 0 + 0
387 params = new SimilarityParams(false, false, false, true);
388 assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
389 // matchGap (arg2) is ignored:
390 params = new SimilarityParams(false, true, false, true);
391 assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
394 @Test(groups = "Functional")
395 public void testSymmetric()
397 verifySymmetric(ScoreModels.getInstance().getBlosum62());
398 verifySymmetric(ScoreModels.getInstance().getPam250());
399 verifySymmetric(ScoreModels.getInstance().getDefaultModel(false)); // dna
403 * A helper method that inspects a loaded matrix and reports any asymmetry as
408 private void verifySymmetric(ScoreMatrix sm)
410 float[][] m = sm.getMatrix();
412 for (int row = 0; row < rows; row++)
414 assertEquals(m[row].length, rows);
415 for (int col = 0; col < rows; col++)
417 assertEquals(m[row][col], m[col][row], String.format("%s [%s, %s]",
418 sm.getName(), ResidueProperties.aa[row],
419 ResidueProperties.aa[col]));
425 * A test that just asserts the expected values in the Blosum62 score matrix
427 @Test(groups = "Functional")
428 public void testBlosum62_values()
430 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
432 assertTrue(sm.isProtein());
433 assertFalse(sm.isDNA());
434 assertNull(sm.getDescription());
437 * verify expected scores against ARNDCQEGHILKMFPSTWYVBZX
438 * scraped from https://www.ncbi.nlm.nih.gov/Class/FieldGuide/BLOSUM62.txt
440 verifyValues(sm, 'A', new float[] { 4, -1, -2, -2, 0, -1, -1, 0, -2,
442 -1, -1, -1, -2, -1, 1, 0, -3, -2, 0, -2, -1, 0 });
443 verifyValues(sm, 'R', new float[] { -1, 5, 0, -2, -3, 1, 0, -2, 0, -3,
444 -2, 2, -1, -3, -2, -1, -1, -3, -2, -3, -1, 0, -1 });
445 verifyValues(sm, 'N', new float[] { -2, 0, 6, 1, -3, 0, 0, 0, 1, -3,
447 0, -2, -3, -2, 1, 0, -4, -2, -3, 3, 0, -1 });
448 verifyValues(sm, 'D', new float[] { -2, -2, 1, 6, -3, 0, 2, -1, -1, -3,
449 -4, -1, -3, -3, -1, 0, -1, -4, -3, -3, 4, 1, -1 });
450 verifyValues(sm, 'C', new float[] { 0, -3, -3, -3, 9, -3, -4, -3, -3,
452 -1, -3, -1, -2, -3, -1, -1, -2, -2, -1, -3, -3, -2 });
453 verifyValues(sm, 'Q', new float[] { -1, 1, 0, 0, -3, 5, 2, -2, 0, -3,
455 1, 0, -3, -1, 0, -1, -2, -1, -2, 0, 3, -1 });
456 verifyValues(sm, 'E', new float[] { -1, 0, 0, 2, -4, 2, 5, -2, 0, -3,
458 1, -2, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1 });
459 verifyValues(sm, 'G', new float[] { 0, -2, 0, -1, -3, -2, -2, 6, -2,
461 -4, -2, -3, -3, -2, 0, -2, -2, -3, -3, -1, -2, -1 });
462 verifyValues(sm, 'H', new float[] { -2, 0, 1, -1, -3, 0, 0, -2, 8, -3,
463 -3, -1, -2, -1, -2, -1, -2, -2, 2, -3, 0, 0, -1 });
464 verifyValues(sm, 'I', new float[] { -1, -3, -3, -3, -1, -3, -3, -4, -3,
465 4, 2, -3, 1, 0, -3, -2, -1, -3, -1, 3, -3, -3, -1 });
466 verifyValues(sm, 'L', new float[] { -1, -2, -3, -4, -1, -2, -3, -4, -3,
467 2, 4, -2, 2, 0, -3, -2, -1, -2, -1, 1, -4, -3, -1 });
468 verifyValues(sm, 'K', new float[] { -1, 2, 0, -1, -3, 1, 1, -2, -1, -3,
469 -2, 5, -1, -3, -1, 0, -1, -3, -2, -2, 0, 1, -1 });
470 verifyValues(sm, 'M', new float[] { -1, -1, -2, -3, -1, 0, -2, -3, -2,
472 2, -1, 5, 0, -2, -1, -1, -1, -1, 1, -3, -1, -1 });
473 verifyValues(sm, 'F', new float[] { -2, -3, -3, -3, -2, -3, -3, -3, -1,
474 0, 0, -3, 0, 6, -4, -2, -2, 1, 3, -1, -3, -3, -1 });
475 verifyValues(sm, 'P', new float[] { -1, -2, -2, -1, -3, -1, -1, -2, -2,
476 -3, -3, -1, -2, -4, 7, -1, -1, -4, -3, -2, -2, -1, -2 });
477 verifyValues(sm, 'S', new float[] { 1, -1, 1, 0, -1, 0, 0, 0, -1, -2,
479 0, -1, -2, -1, 4, 1, -3, -2, -2, 0, 0, 0 });
480 verifyValues(sm, 'T', new float[] { 0, -1, 0, -1, -1, -1, -1, -2, -2,
482 -1, -1, -1, -2, -1, 1, 5, -2, -2, 0, -1, -1, 0 });
483 verifyValues(sm, 'W', new float[] { -3, -3, -4, -4, -2, -2, -3, -2, -2,
484 -3, -2, -3, -1, 1, -4, -3, -2, 11, 2, -3, -4, -3, -2 });
485 verifyValues(sm, 'Y', new float[] { -2, -2, -2, -3, -2, -1, -2, -3, 2,
486 -1, -1, -2, -1, 3, -3, -2, -2, 2, 7, -1, -3, -2, -1 });
487 verifyValues(sm, 'V', new float[] { 0, -3, -3, -3, -1, -2, -2, -3, -3,
489 1, -2, 1, -1, -2, -2, 0, -3, -1, 4, -3, -2, -1 });
490 verifyValues(sm, 'B', new float[] { -2, -1, 3, 4, -3, 0, 1, -1, 0, -3,
491 -4, 0, -3, -3, -2, 0, -1, -4, -3, -3, 4, 1, -1 });
492 verifyValues(sm, 'Z', new float[] { -1, 0, 0, 1, -3, 3, 4, -2, 0, -3,
494 1, -1, -3, -1, 0, -1, -3, -2, -2, 1, 4, -1 });
495 verifyValues(sm, 'X', new float[] { 0, -1, -1, -1, -2, -1, -1, -1, -1,
496 -1, -1, -1, -1, -1, -2, 0, 0, -2, -1, -1, -1, -1, -1 });
500 * Helper method to check pairwise scores for one residue
505 * score values against 'res', in ResidueProperties.aaIndex order
507 private void verifyValues(ScoreMatrix sm, char res, float[] expected)
509 for (int j = 0; j < expected.length; j++)
511 char c2 = ResidueProperties.aa[j].charAt(0);
512 assertEquals(sm.getPairwiseScore(res, c2), expected[j],
513 String.format("%s->%s", res, c2));
517 @Test(groups = "Functional")
518 public void testConstructor_gapDash()
520 float[][] scores = new float[2][];
521 scores[0] = new float[] { 1f, 2f };
522 scores[1] = new float[] { 4f, 5f };
523 ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '-' },
525 assertEquals(sm.getSize(), 2);
526 assertArrayEquals(scores, sm.getMatrix());
527 assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
528 assertEquals(sm.getPairwiseScore('A', 'A'), 1f);
529 assertEquals(sm.getPairwiseScore('a', '-'), 2f);
530 assertEquals(sm.getPairwiseScore('-', 'A'), 4f);
531 assertEquals(sm.getMatrixIndex('a'), 0);
532 assertEquals(sm.getMatrixIndex('A'), 0);
533 assertEquals(sm.getMatrixIndex('-'), 1);
534 assertEquals(sm.getMatrixIndex(' '), -1);
535 assertEquals(sm.getMatrixIndex('.'), -1);
538 @Test(groups = "Functional")
539 public void testGetPairwiseScore()
541 float[][] scores = new float[2][];
542 scores[0] = new float[] { 1f, 2f };
543 scores[1] = new float[] { -4f, 5f };
544 ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', 'B' },
546 assertEquals(sm.getPairwiseScore('A', 'A'), 1f);
547 assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
548 assertEquals(sm.getPairwiseScore('A', 'B'), 2f);
549 assertEquals(sm.getPairwiseScore('b', 'a'), -4f);
550 assertEquals(sm.getPairwiseScore('B', 'b'), 5f);
553 * unknown symbols currently score minimum score
554 * or 1 for identity with self
556 assertEquals(sm.getPairwiseScore('A', '-'), -4f);
557 assertEquals(sm.getPairwiseScore('-', 'A'), -4f);
558 assertEquals(sm.getPairwiseScore('-', '-'), 1f);
559 assertEquals(sm.getPairwiseScore('Q', 'W'), -4f);
560 assertEquals(sm.getPairwiseScore('Q', 'Q'), 1f);
563 * symbols not in basic ASCII set score zero
566 assertEquals(sm.getPairwiseScore('Q', c), 0f);
567 assertEquals(sm.getPairwiseScore(c, 'Q'), 0f);
570 @Test(groups = "Functional")
571 public void testGetMinimumScore()
573 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
574 assertEquals(sm.getMinimumScore(), -4f);
577 @Test(groups = "Functional")
578 public void testGetMaximumScore()
580 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
581 assertEquals(sm.getMaximumScore(), 11f);
584 @Test(groups = "Functional")
585 public void testOutputMatrix_html()
587 float[][] scores = new float[2][];
588 scores[0] = new float[] { 1f, 2f };
589 scores[1] = new float[] { 4f, -5.3E-10f };
590 ScoreMatrix sm = new ScoreMatrix("Test", "AB".toCharArray(), scores);
591 String html = sm.outputMatrix(true);
592 String expected = "<table border=\"1\"><tr><th></th><th> A </th><th> B </th></tr>\n"
593 + "<tr><td>A</td><td>1.0</td><td>2.0</td></tr>\n"
594 + "<tr><td>B</td><td>4.0</td><td>-5.3E-10</td></tr>\n"
596 assertEquals(html, expected);
599 @Test(groups = "Functional")
600 public void testIsSymmetric()
602 float[][] scores = new float[][] { { 1f, -2f }, { -2f, 3f } };
603 ScoreMatrix sm = new ScoreMatrix("Test", "AB".toCharArray(), scores);
604 assertTrue(sm.isSymmetric());
607 * verify that with a symmetric score matrix,
608 * pairwise similarity matrix is also symmetric
609 * seq1.seq1 = 5*A.A + 3*B.B = 5+9 = 14
610 * seq1.seq2 = 3*A.A + 2*A.B + B.A + 2*B.B = 3 + -4 + -2 + 6 = 3
611 * seq2.seq1 = 3*A.A + A.B + 2*B.A + 2*B.B = 3 + -2 + -4 + 6 = 3
612 * seq2.seq2 = 4*A.A + 4*B.B = 4 + 12 = 16
614 SimilarityParamsI params = new SimilarityParams(true, true, true,
616 String seq1 = "AAABBBAA";
617 String seq2 = "AABBABBA";
618 String[] seqs1 = new String[] { seq1, seq2 };
619 MatrixI res1 = sm.findSimilarities(seqs1, params);
621 new Matrix(new double[][]
622 { { 14d, 3d }, { 3d, 16d } }));
625 * order of sequences affects diagonal, but not off-diagonal values
626 * [0, 0] is now seq2.seq2, [1, 1] is seq1.seq1
627 * [0, 1] is now seq2.seq1 = seq1.seq2 by symmetry
629 String[] seqs2 = new String[] { seq2, seq1 };
630 MatrixI res2 = sm.findSimilarities(seqs2, params);
631 assertFalse(res1.equals(res2));
633 new Matrix(new double[][]
634 { { 16d, 3d }, { 3d, 14d } }));
637 * now make the score matrix asymmetric
638 * seq1.seq1 = 5*A.A + 3*B.B = 5+9 = 14
639 * seq1.seq2 = 3*A.A + 2*A.B + B.A + 2*B.B = 3 + -4 + 2 + 6 = 7
640 * seq2.seq1 = 3*A.A + A.B + 2*B.A + 2*B.B = 3 + -2 + 4 + 6 = 11
641 * seq2.seq2 = 4*A.A + 4*B.B = 4 + 12 = 16
643 scores = new float[][] { { 1f, -2f }, { 2f, 3f } };
644 sm = new ScoreMatrix("Test", "AB".toCharArray(), scores);
645 assertFalse(sm.isSymmetric()); // [0, 1] != [1, 0]
646 res1 = sm.findSimilarities(seqs1, params);
648 new Matrix(new double[][]
649 { { 14d, 7d }, { 11d, 16d } }));
652 * reverse order of sequences
653 * - reverses order of main diagonal
654 * - reflects off-diagonal values
656 res2 = sm.findSimilarities(seqs2, params);
657 assertFalse(res1.equals(res2));
659 new Matrix(new double[][]
660 { { 16d, 11d }, { 7d, 14d } }));
663 * verify that forcing an asymmetric matrix to use
664 * symmetric calculation gives a different (wrong) result
666 PA.setValue(sm, "symmetric", true);
667 assertTrue(sm.isSymmetric()); // it's not true!
668 res2 = sm.findSimilarities(seqs1, params);
669 assertFalse(res1.equals(res2));