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",
58 { IllegalArgumentException.class })
59 public void testConstructor_matrixTooSmall()
61 float[][] scores = new float[2][];
62 scores[0] = new float[] { 1f, 2f };
63 scores[1] = new float[] { 3f, 4f };
64 new ScoreMatrix("Test", "ABC".toCharArray(), scores);
68 groups = "Functional",
70 { IllegalArgumentException.class })
71 public void testConstructor_matrixTooBig()
73 float[][] scores = new float[2][];
74 scores[0] = new float[] { 1f, 2f };
75 scores[1] = new float[] { 3f, 4f };
76 new ScoreMatrix("Test", "A".toCharArray(), scores);
80 groups = "Functional",
82 { IllegalArgumentException.class })
83 public void testConstructor_matrixNotSquare()
85 float[][] scores = new float[2][];
86 scores[0] = new float[] { 1f, 2f };
87 scores[1] = new float[] { 3f };
88 new ScoreMatrix("Test", "AB".toCharArray(), scores);
91 @Test(groups = "Functional")
92 public void testBuildSymbolIndex()
94 float[][] scores = new float[2][];
95 scores[0] = new float[] { 1f, 2f };
96 scores[1] = new float[] { 3f, 4f };
97 ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '.' },
99 short[] index = sm.buildSymbolIndex("AX-yxYp".toCharArray());
101 assertEquals(index.length, 128); // ASCII character set size
103 assertEquals(index['A'], 0);
104 assertEquals(index['a'], 0); // lower-case mapping added
105 assertEquals(index['X'], 1);
106 assertEquals(index['-'], 2);
107 assertEquals(index['y'], 3); // lower-case override
108 assertEquals(index['x'], 4); // lower-case override
109 assertEquals(index['Y'], 5);
110 assertEquals(index['p'], 6);
111 assertEquals(index['P'], -1); // lower-case doesn't map upper-case
114 * check all unmapped symbols have index for unmapped
116 for (int c = 0; c < index.length; c++)
118 if (!"AaXx-. Yyp".contains(String.valueOf((char) c)))
120 assertEquals(index[c], -1);
126 * check that characters not in the basic ASCII set are simply ignored
128 @Test(groups = "Functional")
129 public void testBuildSymbolIndex_nonAscii()
131 float[][] scores = new float[2][];
132 scores[0] = new float[] { 1f, 2f };
133 scores[1] = new float[] { 3f, 4f };
134 ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '.' },
136 char[] weird = new char[] { 128, 245, 'P' };
137 short[] index = sm.buildSymbolIndex(weird);
138 assertEquals(index.length, 128);
139 assertEquals(index['P'], 2);
140 assertEquals(index['p'], 2);
141 for (int c = 0; c < index.length; c++)
143 if (c != 'P' && c != 'p')
145 assertEquals(index[c], -1);
150 @Test(groups = "Functional")
151 public void testGetMatrix()
153 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
154 float[][] m = sm.getMatrix();
155 assertEquals(m.length, sm.getSize());
156 assertEquals(m[2][4], -3f);
157 // verify a defensive copy is returned
158 float[][] m2 = sm.getMatrix();
159 assertNotSame(m, m2);
160 assertTrue(Arrays.deepEquals(m, m2));
163 @Test(groups = "Functional")
164 public void testGetMatrixIndex()
166 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
167 assertEquals(sm.getMatrixIndex('A'), 0);
168 assertEquals(sm.getMatrixIndex('R'), 1);
169 assertEquals(sm.getMatrixIndex('r'), 1);
170 assertEquals(sm.getMatrixIndex('N'), 2);
171 assertEquals(sm.getMatrixIndex('D'), 3);
172 assertEquals(sm.getMatrixIndex('X'), 22);
173 assertEquals(sm.getMatrixIndex('x'), 22);
174 assertEquals(sm.getMatrixIndex('-'), -1);
175 assertEquals(sm.getMatrixIndex('*'), 23);
176 assertEquals(sm.getMatrixIndex('.'), -1);
177 assertEquals(sm.getMatrixIndex(' '), -1);
178 assertEquals(sm.getMatrixIndex('?'), -1);
179 assertEquals(sm.getMatrixIndex((char) 128), -1);
182 @Test(groups = "Functional")
183 public void testGetSize()
185 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
186 assertEquals(sm.getMatrix().length, sm.getSize());
189 @Test(groups = "Functional")
190 public void testComputePairwiseScores()
193 * NB score matrix expects '-' for gap
195 String[] seqs = new String[] { "FKL", "R-D", "QIA", "GWC" };
196 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
198 MatrixI pairwise = sm.findSimilarities(seqs, SimilarityParams.Jalview);
201 * should be NxN where N = number of sequences
203 assertEquals(pairwise.height(), 4);
204 assertEquals(pairwise.width(), 4);
207 * should be symmetrical (because BLOSUM62 is)
209 for (int i = 0; i < pairwise.height(); i++)
211 for (int j = i + 1; j < pairwise.width(); j++)
213 assertEquals(pairwise.getValue(i, j), pairwise.getValue(j, i),
214 String.format("Not symmetric at [%d, %d]", i, j));
218 * verify expected BLOSUM dot product scores
220 // F.F + K.K + L.L = 6 + 5 + 4 = 15
221 assertEquals(pairwise.getValue(0, 0), 15d);
222 // R.R + -.- + D.D = 5 + 1 + 6 = 12
223 assertEquals(pairwise.getValue(1, 1), 12d);
224 // Q.Q + I.I + A.A = 5 + 4 + 4 = 13
225 assertEquals(pairwise.getValue(2, 2), 13d);
226 // G.G + W.W + C.C = 6 + 11 + 9 = 26
227 assertEquals(pairwise.getValue(3, 3), 26d);
228 // F.R + K.- + L.D = -3 + -4 + -4 = -11
229 assertEquals(pairwise.getValue(0, 1), -11d);
230 // F.Q + K.I + L.A = -3 + -3 + -1 = -7
231 assertEquals(pairwise.getValue(0, 2), -7d);
232 // F.G + K.W + L.C = -3 + -3 + -1 = -7
233 assertEquals(pairwise.getValue(0, 3), -7d);
234 // R.Q + -.I + D.A = 1 + -4 + -2 = -5
235 assertEquals(pairwise.getValue(1, 2), -5d);
236 // R.G + -.W + D.C = -2 + -4 + -3 = -9
237 assertEquals(pairwise.getValue(1, 3), -9d);
238 // Q.G + I.W + A.C = -2 + -3 + 0 = -5
239 assertEquals(pairwise.getValue(2, 3), -5d);
243 * Test that the result of outputMatrix can be reparsed to give an identical
246 * @throws IOException
247 * @throws MalformedURLException
249 @Test(groups = "Functional")
250 public void testOutputMatrix_roundTrip()
251 throws MalformedURLException, IOException
253 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
254 String output = sm.outputMatrix(false);
255 FileParse fp = new FileParse(output, DataSourceType.PASTE);
256 ScoreMatrixFile parser = new ScoreMatrixFile(fp);
257 ScoreMatrix sm2 = parser.parseMatrix();
259 assertTrue(sm2.equals(sm));
262 @Test(groups = "Functional")
263 public void testEqualsAndHashCode()
265 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
266 ScoreMatrix sm2 = new ScoreMatrix(sm.getName(),
267 sm.getSymbols().toCharArray(), sm.getMatrix());
268 assertTrue(sm.equals(sm2));
269 assertEquals(sm.hashCode(), sm2.hashCode());
271 sm2 = ScoreModels.getInstance().getPam250();
272 assertFalse(sm.equals(sm2));
273 assertNotEquals(sm.hashCode(), sm2.hashCode());
275 assertFalse(sm.equals("hello"));
279 * Tests for scoring options where the longer length of two sequences is used
281 @Test(groups = "Functional")
282 public void testcomputeSimilarity_matchLongestSequence()
285 * ScoreMatrix expects '-' for gaps
287 String s1 = "FR-K-S";
289 ScoreMatrix blosum = ScoreModels.getInstance().getBlosum62();
292 * score gap-gap and gap-char
293 * shorter sequence treated as if with trailing gaps
294 * score = F^F + R^S + -^- + K^- + -^L + S^-
295 * = 6 + -1 + 1 + -4 + -4 + -4 = -6
297 SimilarityParamsI params = new SimilarityParams(true, true, true,
299 assertEquals(blosum.computeSimilarity(s1, s2, params), -6d);
300 // matchGap (arg2) is ignored:
301 params = new SimilarityParams(true, false, true, false);
302 assertEquals(blosum.computeSimilarity(s1, s2, params), -6d);
305 * score gap-char but not gap-gap
306 * score = F^F + R^S + 0 + K^- + -^L + S^-
307 * = 6 + -1 + 0 + -4 + -4 + -4 = -7
309 params = new SimilarityParams(false, true, true, false);
310 assertEquals(blosum.computeSimilarity(s1, s2, params), -7d);
311 // matchGap (arg2) is ignored:
312 params = new SimilarityParams(false, false, true, false);
313 assertEquals(blosum.computeSimilarity(s1, s2, params), -7d);
316 * score gap-gap but not gap-char
317 * score = F^F + R^S + -^- + 0 + 0 + 0
320 params = new SimilarityParams(true, false, false, false);
321 assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
322 // matchGap (arg2) is ignored:
323 params = new SimilarityParams(true, true, false, false);
324 assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
327 * score neither gap-gap nor gap-char
328 * score = F^F + R^S + 0 + 0 + 0 + 0
331 params = new SimilarityParams(false, false, false, false);
332 assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
333 // matchGap (arg2) is ignored:
334 params = new SimilarityParams(false, true, false, false);
335 assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
339 * Tests for scoring options where only the shorter length of two sequences is
342 @Test(groups = "Functional")
343 public void testcomputeSimilarity_matchShortestSequence()
346 * ScoreMatrix expects '-' for gaps
348 String s1 = "FR-K-S";
350 ScoreMatrix blosum = ScoreModels.getInstance().getBlosum62();
353 * score gap-gap and gap-char
354 * match shorter sequence only
355 * score = F^F + R^S + -^- + K^- + -^L
356 * = 6 + -1 + 1 + -4 + -4 = -2
358 SimilarityParamsI params = new SimilarityParams(true, true, true, true);
359 assertEquals(blosum.computeSimilarity(s1, s2, params), -2d);
360 // matchGap (arg2) is ignored:
361 params = new SimilarityParams(true, false, true, true);
362 assertEquals(blosum.computeSimilarity(s1, s2, params), -2d);
365 * score gap-char but not gap-gap
366 * score = F^F + R^S + 0 + K^- + -^L
367 * = 6 + -1 + 0 + -4 + -4 = -3
369 params = new SimilarityParams(false, true, true, true);
370 assertEquals(blosum.computeSimilarity(s1, s2, params), -3d);
371 // matchGap (arg2) is ignored:
372 params = new SimilarityParams(false, false, true, true);
373 assertEquals(blosum.computeSimilarity(s1, s2, params), -3d);
376 * score gap-gap but not gap-char
377 * score = F^F + R^S + -^- + 0 + 0
380 params = new SimilarityParams(true, false, false, true);
381 assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
382 // matchGap (arg2) is ignored:
383 params = new SimilarityParams(true, true, false, true);
384 assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
387 * score neither gap-gap nor gap-char
388 * score = F^F + R^S + 0 + 0 + 0
391 params = new SimilarityParams(false, false, false, true);
392 assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
393 // matchGap (arg2) is ignored:
394 params = new SimilarityParams(false, true, false, true);
395 assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
398 @Test(groups = "Functional")
399 public void testSymmetric()
401 verifySymmetric(ScoreModels.getInstance().getBlosum62());
402 verifySymmetric(ScoreModels.getInstance().getPam250());
403 verifySymmetric(ScoreModels.getInstance().getDefaultModel(false)); // dna
407 * A helper method that inspects a loaded matrix and reports any asymmetry as
412 private void verifySymmetric(ScoreMatrix sm)
414 float[][] m = sm.getMatrix();
416 for (int row = 0; row < rows; row++)
418 assertEquals(m[row].length, rows);
419 for (int col = 0; col < rows; col++)
421 assertEquals(m[row][col], m[col][row],
422 String.format("%s [%s, %s]", sm.getName(),
423 ResidueProperties.aa[row],
424 ResidueProperties.aa[col]));
430 * A test that just asserts the expected values in the Blosum62 score matrix
432 @Test(groups = "Functional")
433 public void testBlosum62_values()
435 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
437 assertTrue(sm.isProtein());
438 assertFalse(sm.isDNA());
439 assertNull(sm.getDescription());
442 * verify expected scores against ARNDCQEGHILKMFPSTWYVBZX
443 * scraped from https://www.ncbi.nlm.nih.gov/Class/FieldGuide/BLOSUM62.txt
445 verifyValues(sm, 'A',
447 { 4, -1, -2, -2, 0, -1, -1, 0, -2, -1, -1, -1, -1, -2, -1, 1, 0,
448 -3, -2, 0, -2, -1, 0 });
449 verifyValues(sm, 'R',
451 { -1, 5, 0, -2, -3, 1, 0, -2, 0, -3, -2, 2, -1, -3, -2, -1, -1,
452 -3, -2, -3, -1, 0, -1 });
453 verifyValues(sm, 'N',
455 { -2, 0, 6, 1, -3, 0, 0, 0, 1, -3, -3, 0, -2, -3, -2, 1, 0, -4,
457 verifyValues(sm, 'D',
459 { -2, -2, 1, 6, -3, 0, 2, -1, -1, -3, -4, -1, -3, -3, -1, 0, -1,
460 -4, -3, -3, 4, 1, -1 });
461 verifyValues(sm, 'C',
463 { 0, -3, -3, -3, 9, -3, -4, -3, -3, -1, -1, -3, -1, -2, -3, -1,
464 -1, -2, -2, -1, -3, -3, -2 });
465 verifyValues(sm, 'Q',
467 { -1, 1, 0, 0, -3, 5, 2, -2, 0, -3, -2, 1, 0, -3, -1, 0, -1, -2,
469 verifyValues(sm, 'E',
471 { -1, 0, 0, 2, -4, 2, 5, -2, 0, -3, -3, 1, -2, -3, -1, 0, -1,
472 -3, -2, -2, 1, 4, -1 });
473 verifyValues(sm, 'G',
475 { 0, -2, 0, -1, -3, -2, -2, 6, -2, -4, -4, -2, -3, -3, -2, 0,
476 -2, -2, -3, -3, -1, -2, -1 });
477 verifyValues(sm, 'H',
479 { -2, 0, 1, -1, -3, 0, 0, -2, 8, -3, -3, -1, -2, -1, -2, -1, -2,
480 -2, 2, -3, 0, 0, -1 });
481 verifyValues(sm, 'I',
483 { -1, -3, -3, -3, -1, -3, -3, -4, -3, 4, 2, -3, 1, 0, -3, -2,
484 -1, -3, -1, 3, -3, -3, -1 });
485 verifyValues(sm, 'L',
487 { -1, -2, -3, -4, -1, -2, -3, -4, -3, 2, 4, -2, 2, 0, -3, -2,
488 -1, -2, -1, 1, -4, -3, -1 });
489 verifyValues(sm, 'K',
491 { -1, 2, 0, -1, -3, 1, 1, -2, -1, -3, -2, 5, -1, -3, -1, 0, -1,
492 -3, -2, -2, 0, 1, -1 });
493 verifyValues(sm, 'M',
495 { -1, -1, -2, -3, -1, 0, -2, -3, -2, 1, 2, -1, 5, 0, -2, -1, -1,
496 -1, -1, 1, -3, -1, -1 });
497 verifyValues(sm, 'F',
499 { -2, -3, -3, -3, -2, -3, -3, -3, -1, 0, 0, -3, 0, 6, -4, -2,
500 -2, 1, 3, -1, -3, -3, -1 });
501 verifyValues(sm, 'P',
503 { -1, -2, -2, -1, -3, -1, -1, -2, -2, -3, -3, -1, -2, -4, 7, -1,
504 -1, -4, -3, -2, -2, -1, -2 });
505 verifyValues(sm, 'S',
507 { 1, -1, 1, 0, -1, 0, 0, 0, -1, -2, -2, 0, -1, -2, -1, 4, 1, -3,
509 verifyValues(sm, 'T',
511 { 0, -1, 0, -1, -1, -1, -1, -2, -2, -1, -1, -1, -1, -2, -1, 1,
512 5, -2, -2, 0, -1, -1, 0 });
513 verifyValues(sm, 'W',
515 { -3, -3, -4, -4, -2, -2, -3, -2, -2, -3, -2, -3, -1, 1, -4, -3,
516 -2, 11, 2, -3, -4, -3, -2 });
517 verifyValues(sm, 'Y',
519 { -2, -2, -2, -3, -2, -1, -2, -3, 2, -1, -1, -2, -1, 3, -3, -2,
520 -2, 2, 7, -1, -3, -2, -1 });
521 verifyValues(sm, 'V',
523 { 0, -3, -3, -3, -1, -2, -2, -3, -3, 3, 1, -2, 1, -1, -2, -2, 0,
524 -3, -1, 4, -3, -2, -1 });
525 verifyValues(sm, 'B',
527 { -2, -1, 3, 4, -3, 0, 1, -1, 0, -3, -4, 0, -3, -3, -2, 0, -1,
528 -4, -3, -3, 4, 1, -1 });
529 verifyValues(sm, 'Z',
531 { -1, 0, 0, 1, -3, 3, 4, -2, 0, -3, -3, 1, -1, -3, -1, 0, -1,
532 -3, -2, -2, 1, 4, -1 });
533 verifyValues(sm, 'X',
535 { 0, -1, -1, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, 0,
536 0, -2, -1, -1, -1, -1, -1 });
540 * Helper method to check pairwise scores for one residue
545 * score values against 'res', in ResidueProperties.aaIndex order
547 private void verifyValues(ScoreMatrix sm, char res, float[] expected)
549 for (int j = 0; j < expected.length; j++)
551 char c2 = ResidueProperties.aa[j].charAt(0);
552 assertEquals(sm.getPairwiseScore(res, c2), expected[j],
553 String.format("%s->%s", res, c2));
557 @Test(groups = "Functional")
558 public void testConstructor_gapDash()
560 float[][] scores = new float[2][];
561 scores[0] = new float[] { 1f, 2f };
562 scores[1] = new float[] { 4f, 5f };
563 ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '-' },
565 assertEquals(sm.getSize(), 2);
566 assertArrayEquals(scores, sm.getMatrix());
567 assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
568 assertEquals(sm.getPairwiseScore('A', 'A'), 1f);
569 assertEquals(sm.getPairwiseScore('a', '-'), 2f);
570 assertEquals(sm.getPairwiseScore('-', 'A'), 4f);
571 assertEquals(sm.getMatrixIndex('a'), 0);
572 assertEquals(sm.getMatrixIndex('A'), 0);
573 assertEquals(sm.getMatrixIndex('-'), 1);
574 assertEquals(sm.getMatrixIndex(' '), -1);
575 assertEquals(sm.getMatrixIndex('.'), -1);
578 @Test(groups = "Functional")
579 public void testGetPairwiseScore()
581 float[][] scores = new float[2][];
582 scores[0] = new float[] { 1f, 2f };
583 scores[1] = new float[] { -4f, 5f };
584 ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', 'B' },
586 assertEquals(sm.getPairwiseScore('A', 'A'), 1f);
587 assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
588 assertEquals(sm.getPairwiseScore('A', 'B'), 2f);
589 assertEquals(sm.getPairwiseScore('b', 'a'), -4f);
590 assertEquals(sm.getPairwiseScore('B', 'b'), 5f);
593 * unknown symbols currently score minimum score
594 * or 1 for identity with self
596 assertEquals(sm.getPairwiseScore('A', '-'), -4f);
597 assertEquals(sm.getPairwiseScore('-', 'A'), -4f);
598 assertEquals(sm.getPairwiseScore('-', '-'), 1f);
599 assertEquals(sm.getPairwiseScore('Q', 'W'), -4f);
600 assertEquals(sm.getPairwiseScore('Q', 'Q'), 1f);
603 * symbols not in basic ASCII set score zero
606 assertEquals(sm.getPairwiseScore('Q', c), 0f);
607 assertEquals(sm.getPairwiseScore(c, 'Q'), 0f);
610 @Test(groups = "Functional")
611 public void testGetMinimumScore()
613 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
614 assertEquals(sm.getMinimumScore(), -4f);
617 @Test(groups = "Functional")
618 public void testGetMaximumScore()
620 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
621 assertEquals(sm.getMaximumScore(), 11f);
624 @Test(groups = "Functional")
625 public void testOutputMatrix_html()
627 float[][] scores = new float[2][];
628 scores[0] = new float[] { 1f, 2f };
629 scores[1] = new float[] { 4f, -5.3E-10f };
630 ScoreMatrix sm = new ScoreMatrix("Test", "AB".toCharArray(), scores);
631 String html = sm.outputMatrix(true);
632 String expected = "<table border=\"1\"><tr><th></th><th> A </th><th> B </th></tr>\n"
633 + "<tr><td>A</td><td>1.0</td><td>2.0</td></tr>\n"
634 + "<tr><td>B</td><td>4.0</td><td>-5.3E-10</td></tr>\n"
636 assertEquals(html, expected);
639 @Test(groups = "Functional")
640 public void testIsSymmetric()
642 double delta = 0.0001d;
643 float[][] scores = new float[][] { { 1f, -2f }, { -2f, 3f } };
644 ScoreMatrix sm = new ScoreMatrix("Test", "AB".toCharArray(), scores);
645 assertTrue(sm.isSymmetric());
648 * verify that with a symmetric score matrix,
649 * pairwise similarity matrix is also symmetric
650 * seq1.seq1 = 5*A.A + 3*B.B = 5+9 = 14
651 * seq1.seq2 = 3*A.A + 2*A.B + B.A + 2*B.B = 3 + -4 + -2 + 6 = 3
652 * seq2.seq1 = 3*A.A + A.B + 2*B.A + 2*B.B = 3 + -2 + -4 + 6 = 3
653 * seq2.seq2 = 4*A.A + 4*B.B = 4 + 12 = 16
655 SimilarityParamsI params = new SimilarityParams(true, true, true,
657 String seq1 = "AAABBBAA";
658 String seq2 = "AABBABBA";
659 String[] seqs1 = new String[] { seq1, seq2 };
660 MatrixI res1 = sm.findSimilarities(seqs1, params);
662 res1.equals(new Matrix(new double[][]
663 { { 14d, 3d }, { 3d, 16d } }), delta));
666 * order of sequences affects diagonal, but not off-diagonal values
667 * [0, 0] is now seq2.seq2, [1, 1] is seq1.seq1
668 * [0, 1] is now seq2.seq1 = seq1.seq2 by symmetry
670 String[] seqs2 = new String[] { seq2, seq1 };
671 MatrixI res2 = sm.findSimilarities(seqs2, params);
672 assertFalse(res1.equals(res2));
673 assertTrue(res2.equals(new Matrix(new double[][]
674 { { 16d, 3d }, { 3d, 14d } }), delta));
677 * now make the score matrix asymmetric
678 * seq1.seq1 = 5*A.A + 3*B.B = 5+9 = 14
679 * seq1.seq2 = 3*A.A + 2*A.B + B.A + 2*B.B = 3 + -4 + 2 + 6 = 7
680 * seq2.seq1 = 3*A.A + A.B + 2*B.A + 2*B.B = 3 + -2 + 4 + 6 = 11
681 * seq2.seq2 = 4*A.A + 4*B.B = 4 + 12 = 16
683 scores = new float[][] { { 1f, -2f }, { 2f, 3f } };
684 sm = new ScoreMatrix("Test", "AB".toCharArray(), scores);
685 assertFalse(sm.isSymmetric()); // [0, 1] != [1, 0]
686 res1 = sm.findSimilarities(seqs1, params);
687 assertTrue(res1.equals(new Matrix(new double[][]
688 { { 14d, 7d }, { 11d, 16d } }), delta));
691 * reverse order of sequences
692 * - reverses order of main diagonal
693 * - reflects off-diagonal values
695 res2 = sm.findSimilarities(seqs2, params);
696 assertFalse(res1.equals(res2));
698 res2.equals(new Matrix(new double[][]
699 { { 16d, 11d }, { 7d, 14d } }), delta));
702 * verify that forcing an asymmetric matrix to use
703 * symmetric calculation gives a different (wrong) result
705 PA.setValue(sm, "symmetric", true);
706 assertTrue(sm.isSymmetric()); // it's not true!
707 res2 = sm.findSimilarities(seqs1, params);
708 assertFalse(res1.equals(res2, delta));