2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.analysis.scoremodels;
23 import static org.testng.Assert.assertEquals;
24 import static org.testng.Assert.assertFalse;
25 import static org.testng.Assert.assertNotEquals;
26 import static org.testng.Assert.assertNotNull;
27 import static org.testng.Assert.assertNotSame;
28 import static org.testng.Assert.assertNull;
29 import static org.testng.Assert.assertTrue;
30 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
32 import jalview.api.analysis.SimilarityParamsI;
33 import jalview.io.DataSourceType;
34 import jalview.io.FileParse;
35 import jalview.io.ScoreMatrixFile;
36 import jalview.math.Matrix;
37 import jalview.math.MatrixI;
38 import jalview.schemes.ResidueProperties;
40 import java.io.IOException;
41 import java.net.MalformedURLException;
42 import java.util.Arrays;
44 import org.testng.annotations.Test;
46 import junit.extensions.PA;
48 public class ScoreMatrixTest
50 @Test(groups = "Functional")
51 public void testConstructor()
53 // note score matrix does not have to be symmetric (though it should be!)
54 float[][] scores = new float[3][];
55 scores[0] = new float[] { 1f, 2f, 3f };
56 scores[1] = new float[] { -4f, 5f, 6f };
57 scores[2] = new float[] { 7f, 8f, 9f };
58 ScoreMatrix sm = new ScoreMatrix("Test", "ABC".toCharArray(), scores);
59 assertFalse(sm.isSymmetric());
60 assertEquals(sm.getSize(), 3);
61 assertArrayEquals(scores, sm.getMatrix());
62 assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
63 assertEquals(sm.getPairwiseScore('b', 'c'), 6f);
64 assertEquals(sm.getPairwiseScore('c', 'b'), 8f);
65 assertEquals(sm.getMatrixIndex('c'), 2);
66 assertEquals(sm.getMatrixIndex(' '), -1);
68 // substitution to or from unknown symbol gets minimum score
69 assertEquals(sm.getPairwiseScore('A', 'D'), -4f);
70 assertEquals(sm.getPairwiseScore('D', 'A'), -4f);
71 // unknown-to-self gets a score of 1
72 assertEquals(sm.getPairwiseScore('D', 'D'), 1f);
76 groups = "Functional",
78 { IllegalArgumentException.class })
79 public void testConstructor_matrixTooSmall()
81 float[][] scores = new float[2][];
82 scores[0] = new float[] { 1f, 2f };
83 scores[1] = new float[] { 3f, 4f };
84 new ScoreMatrix("Test", "ABC".toCharArray(), scores);
88 groups = "Functional",
90 { IllegalArgumentException.class })
91 public void testConstructor_matrixTooBig()
93 float[][] scores = new float[2][];
94 scores[0] = new float[] { 1f, 2f };
95 scores[1] = new float[] { 3f, 4f };
96 new ScoreMatrix("Test", "A".toCharArray(), scores);
100 groups = "Functional",
102 { IllegalArgumentException.class })
103 public void testConstructor_matrixNotSquare()
105 float[][] scores = new float[2][];
106 scores[0] = new float[] { 1f, 2f };
107 scores[1] = new float[] { 3f };
108 new ScoreMatrix("Test", "AB".toCharArray(), scores);
111 @Test(groups = "Functional")
112 public void testBuildSymbolIndex()
114 float[][] scores = new float[2][];
115 scores[0] = new float[] { 1f, 2f };
116 scores[1] = new float[] { 3f, 4f };
117 ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '.' },
119 short[] index = sm.buildSymbolIndex("AX-yxYp".toCharArray());
121 assertEquals(index.length, 128); // ASCII character set size
123 assertEquals(index['A'], 0);
124 assertEquals(index['a'], 0); // lower-case mapping added
125 assertEquals(index['X'], 1);
126 assertEquals(index['-'], 2);
127 assertEquals(index['y'], 3); // lower-case override
128 assertEquals(index['x'], 4); // lower-case override
129 assertEquals(index['Y'], 5);
130 assertEquals(index['p'], 6);
131 assertEquals(index['P'], -1); // lower-case doesn't map upper-case
134 * check all unmapped symbols have index for unmapped
136 for (int c = 0; c < index.length; c++)
138 if (!"AaXx-. Yyp".contains(String.valueOf((char) c)))
140 assertEquals(index[c], -1);
146 * check that characters not in the basic ASCII set are simply ignored
148 @Test(groups = "Functional")
149 public void testBuildSymbolIndex_nonAscii()
151 float[][] scores = new float[2][];
152 scores[0] = new float[] { 1f, 2f };
153 scores[1] = new float[] { 3f, 4f };
154 ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '.' },
156 char[] weird = new char[] { 128, 245, 'P' };
157 short[] index = sm.buildSymbolIndex(weird);
158 assertEquals(index.length, 128);
159 assertEquals(index['P'], 2);
160 assertEquals(index['p'], 2);
161 for (int c = 0; c < index.length; c++)
163 if (c != 'P' && c != 'p')
165 assertEquals(index[c], -1);
170 @Test(groups = "Functional")
171 public void testGetMatrix()
173 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
174 float[][] m = sm.getMatrix();
175 assertEquals(m.length, sm.getSize());
176 assertEquals(m[2][4], -3f);
177 // verify a defensive copy is returned
178 float[][] m2 = sm.getMatrix();
179 assertNotSame(m, m2);
180 assertTrue(Arrays.deepEquals(m, m2));
183 @Test(groups = "Functional")
184 public void testGetMatrixIndex()
186 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
187 assertEquals(sm.getMatrixIndex('A'), 0);
188 assertEquals(sm.getMatrixIndex('R'), 1);
189 assertEquals(sm.getMatrixIndex('r'), 1);
190 assertEquals(sm.getMatrixIndex('N'), 2);
191 assertEquals(sm.getMatrixIndex('D'), 3);
192 assertEquals(sm.getMatrixIndex('X'), 22);
193 assertEquals(sm.getMatrixIndex('x'), 22);
194 assertEquals(sm.getMatrixIndex('-'), -1);
195 assertEquals(sm.getMatrixIndex('*'), 23);
196 assertEquals(sm.getMatrixIndex('.'), -1);
197 assertEquals(sm.getMatrixIndex(' '), -1);
198 assertEquals(sm.getMatrixIndex('?'), -1);
199 assertEquals(sm.getMatrixIndex((char) 128), -1);
202 @Test(groups = "Functional")
203 public void testGetSize()
205 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
206 assertEquals(sm.getMatrix().length, sm.getSize());
209 @Test(groups = "Functional")
210 public void testComputePairwiseScores()
213 * NB score matrix expects '-' for gap
215 String[] seqs = new String[] { "FKL", "R-D", "QIA", "GWC" };
216 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
218 MatrixI pairwise = sm.findSimilarities(seqs, SimilarityParams.Jalview);
221 * should be NxN where N = number of sequences
223 assertEquals(pairwise.height(), 4);
224 assertEquals(pairwise.width(), 4);
227 * should be symmetrical (because BLOSUM62 is)
229 for (int i = 0; i < pairwise.height(); i++)
231 for (int j = i + 1; j < pairwise.width(); j++)
233 assertEquals(pairwise.getValue(i, j), pairwise.getValue(j, i),
234 String.format("Not symmetric at [%d, %d]", i, j));
238 * verify expected BLOSUM dot product scores
240 // F.F + K.K + L.L = 6 + 5 + 4 = 15
241 assertEquals(pairwise.getValue(0, 0), 15d);
242 // R.R + -.- + D.D = 5 + 1 + 6 = 12
243 assertEquals(pairwise.getValue(1, 1), 12d);
244 // Q.Q + I.I + A.A = 5 + 4 + 4 = 13
245 assertEquals(pairwise.getValue(2, 2), 13d);
246 // G.G + W.W + C.C = 6 + 11 + 9 = 26
247 assertEquals(pairwise.getValue(3, 3), 26d);
248 // F.R + K.- + L.D = -3 + -4 + -4 = -11
249 assertEquals(pairwise.getValue(0, 1), -11d);
250 // F.Q + K.I + L.A = -3 + -3 + -1 = -7
251 assertEquals(pairwise.getValue(0, 2), -7d);
252 // F.G + K.W + L.C = -3 + -3 + -1 = -7
253 assertEquals(pairwise.getValue(0, 3), -7d);
254 // R.Q + -.I + D.A = 1 + -4 + -2 = -5
255 assertEquals(pairwise.getValue(1, 2), -5d);
256 // R.G + -.W + D.C = -2 + -4 + -3 = -9
257 assertEquals(pairwise.getValue(1, 3), -9d);
258 // Q.G + I.W + A.C = -2 + -3 + 0 = -5
259 assertEquals(pairwise.getValue(2, 3), -5d);
263 * Test that the result of outputMatrix can be reparsed to give an identical
266 * @throws IOException
267 * @throws MalformedURLException
269 @Test(groups = "Functional")
270 public void testOutputMatrix_roundTrip()
271 throws MalformedURLException, IOException
273 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
274 String output = sm.outputMatrix(false);
275 FileParse fp = new FileParse(output, DataSourceType.PASTE);
276 ScoreMatrixFile parser = new ScoreMatrixFile(fp);
277 ScoreMatrix sm2 = parser.parseMatrix();
279 assertTrue(sm2.equals(sm));
282 @Test(groups = "Functional")
283 public void testEqualsAndHashCode()
285 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
286 ScoreMatrix sm2 = new ScoreMatrix(sm.getName(),
287 sm.getSymbols().toCharArray(), sm.getMatrix());
288 assertTrue(sm.equals(sm2));
289 assertEquals(sm.hashCode(), sm2.hashCode());
291 sm2 = ScoreModels.getInstance().getPam250();
292 assertFalse(sm.equals(sm2));
293 assertNotEquals(sm.hashCode(), sm2.hashCode());
295 assertFalse(sm.equals("hello"));
299 * Tests for scoring options where the longer length of two sequences is used
301 @Test(groups = "Functional")
302 public void testcomputeSimilarity_matchLongestSequence()
305 * ScoreMatrix expects '-' for gaps
307 String s1 = "FR-K-S";
309 ScoreMatrix blosum = ScoreModels.getInstance().getBlosum62();
312 * score gap-gap and gap-char
313 * shorter sequence treated as if with trailing gaps
314 * score = F^F + R^S + -^- + K^- + -^L + S^-
315 * = 6 + -1 + 1 + -4 + -4 + -4 = -6
317 SimilarityParamsI params = new SimilarityParams(true, true, true,
319 assertEquals(blosum.computeSimilarity(s1, s2, params), -6d);
320 // matchGap (arg2) is ignored:
321 params = new SimilarityParams(true, false, true, false);
322 assertEquals(blosum.computeSimilarity(s1, s2, params), -6d);
325 * score gap-char but not gap-gap
326 * score = F^F + R^S + 0 + K^- + -^L + S^-
327 * = 6 + -1 + 0 + -4 + -4 + -4 = -7
329 params = new SimilarityParams(false, true, true, false);
330 assertEquals(blosum.computeSimilarity(s1, s2, params), -7d);
331 // matchGap (arg2) is ignored:
332 params = new SimilarityParams(false, false, true, false);
333 assertEquals(blosum.computeSimilarity(s1, s2, params), -7d);
336 * score gap-gap but not gap-char
337 * score = F^F + R^S + -^- + 0 + 0 + 0
340 params = new SimilarityParams(true, false, false, false);
341 assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
342 // matchGap (arg2) is ignored:
343 params = new SimilarityParams(true, true, false, false);
344 assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
347 * score neither gap-gap nor gap-char
348 * score = F^F + R^S + 0 + 0 + 0 + 0
351 params = new SimilarityParams(false, false, false, false);
352 assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
353 // matchGap (arg2) is ignored:
354 params = new SimilarityParams(false, true, false, false);
355 assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
359 * Tests for scoring options where only the shorter length of two sequences is
362 @Test(groups = "Functional")
363 public void testcomputeSimilarity_matchShortestSequence()
366 * ScoreMatrix expects '-' for gaps
368 String s1 = "FR-K-S";
370 ScoreMatrix blosum = ScoreModels.getInstance().getBlosum62();
373 * score gap-gap and gap-char
374 * match shorter sequence only
375 * score = F^F + R^S + -^- + K^- + -^L
376 * = 6 + -1 + 1 + -4 + -4 = -2
378 SimilarityParamsI params = new SimilarityParams(true, true, true, true);
379 assertEquals(blosum.computeSimilarity(s1, s2, params), -2d);
380 // matchGap (arg2) is ignored:
381 params = new SimilarityParams(true, false, true, true);
382 assertEquals(blosum.computeSimilarity(s1, s2, params), -2d);
385 * score gap-char but not gap-gap
386 * score = F^F + R^S + 0 + K^- + -^L
387 * = 6 + -1 + 0 + -4 + -4 = -3
389 params = new SimilarityParams(false, true, true, true);
390 assertEquals(blosum.computeSimilarity(s1, s2, params), -3d);
391 // matchGap (arg2) is ignored:
392 params = new SimilarityParams(false, false, true, true);
393 assertEquals(blosum.computeSimilarity(s1, s2, params), -3d);
396 * score gap-gap but not gap-char
397 * score = F^F + R^S + -^- + 0 + 0
400 params = new SimilarityParams(true, false, false, true);
401 assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
402 // matchGap (arg2) is ignored:
403 params = new SimilarityParams(true, true, false, true);
404 assertEquals(blosum.computeSimilarity(s1, s2, params), 6d);
407 * score neither gap-gap nor gap-char
408 * score = F^F + R^S + 0 + 0 + 0
411 params = new SimilarityParams(false, false, false, true);
412 assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
413 // matchGap (arg2) is ignored:
414 params = new SimilarityParams(false, true, false, true);
415 assertEquals(blosum.computeSimilarity(s1, s2, params), 5d);
418 @Test(groups = "Functional")
419 public void testSymmetric()
421 verifySymmetric(ScoreModels.getInstance().getBlosum62());
422 verifySymmetric(ScoreModels.getInstance().getPam250());
423 verifySymmetric(ScoreModels.getInstance().getDefaultModel(false)); // dna
427 * A helper method that inspects a loaded matrix and reports any asymmetry as
432 private void verifySymmetric(ScoreMatrix sm)
434 float[][] m = sm.getMatrix();
436 for (int row = 0; row < rows; row++)
438 assertEquals(m[row].length, rows);
439 for (int col = 0; col < rows; col++)
441 assertEquals(m[row][col], m[col][row],
442 String.format("%s [%s, %s]", sm.getName(),
443 ResidueProperties.aa[row],
444 ResidueProperties.aa[col]));
450 * A test that just asserts the expected values in the Blosum62 score matrix
452 @Test(groups = "Functional")
453 public void testBlosum62_values()
455 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
457 assertTrue(sm.isProtein());
458 assertFalse(sm.isDNA());
459 assertNull(sm.getDescription());
462 * verify expected scores against ARNDCQEGHILKMFPSTWYVBZX
463 * scraped from https://www.ncbi.nlm.nih.gov/Class/FieldGuide/BLOSUM62.txt
465 verifyValues(sm, 'A',
467 { 4, -1, -2, -2, 0, -1, -1, 0, -2, -1, -1, -1, -1, -2, -1, 1, 0,
468 -3, -2, 0, -2, -1, 0 });
469 verifyValues(sm, 'R',
471 { -1, 5, 0, -2, -3, 1, 0, -2, 0, -3, -2, 2, -1, -3, -2, -1, -1,
472 -3, -2, -3, -1, 0, -1 });
473 verifyValues(sm, 'N',
475 { -2, 0, 6, 1, -3, 0, 0, 0, 1, -3, -3, 0, -2, -3, -2, 1, 0, -4,
477 verifyValues(sm, 'D',
479 { -2, -2, 1, 6, -3, 0, 2, -1, -1, -3, -4, -1, -3, -3, -1, 0, -1,
480 -4, -3, -3, 4, 1, -1 });
481 verifyValues(sm, 'C',
483 { 0, -3, -3, -3, 9, -3, -4, -3, -3, -1, -1, -3, -1, -2, -3, -1,
484 -1, -2, -2, -1, -3, -3, -2 });
485 verifyValues(sm, 'Q',
487 { -1, 1, 0, 0, -3, 5, 2, -2, 0, -3, -2, 1, 0, -3, -1, 0, -1, -2,
489 verifyValues(sm, 'E',
491 { -1, 0, 0, 2, -4, 2, 5, -2, 0, -3, -3, 1, -2, -3, -1, 0, -1,
492 -3, -2, -2, 1, 4, -1 });
493 verifyValues(sm, 'G',
495 { 0, -2, 0, -1, -3, -2, -2, 6, -2, -4, -4, -2, -3, -3, -2, 0,
496 -2, -2, -3, -3, -1, -2, -1 });
497 verifyValues(sm, 'H',
499 { -2, 0, 1, -1, -3, 0, 0, -2, 8, -3, -3, -1, -2, -1, -2, -1, -2,
500 -2, 2, -3, 0, 0, -1 });
501 verifyValues(sm, 'I',
503 { -1, -3, -3, -3, -1, -3, -3, -4, -3, 4, 2, -3, 1, 0, -3, -2,
504 -1, -3, -1, 3, -3, -3, -1 });
505 verifyValues(sm, 'L',
507 { -1, -2, -3, -4, -1, -2, -3, -4, -3, 2, 4, -2, 2, 0, -3, -2,
508 -1, -2, -1, 1, -4, -3, -1 });
509 verifyValues(sm, 'K',
511 { -1, 2, 0, -1, -3, 1, 1, -2, -1, -3, -2, 5, -1, -3, -1, 0, -1,
512 -3, -2, -2, 0, 1, -1 });
513 verifyValues(sm, 'M',
515 { -1, -1, -2, -3, -1, 0, -2, -3, -2, 1, 2, -1, 5, 0, -2, -1, -1,
516 -1, -1, 1, -3, -1, -1 });
517 verifyValues(sm, 'F',
519 { -2, -3, -3, -3, -2, -3, -3, -3, -1, 0, 0, -3, 0, 6, -4, -2,
520 -2, 1, 3, -1, -3, -3, -1 });
521 verifyValues(sm, 'P',
523 { -1, -2, -2, -1, -3, -1, -1, -2, -2, -3, -3, -1, -2, -4, 7, -1,
524 -1, -4, -3, -2, -2, -1, -2 });
525 verifyValues(sm, 'S',
527 { 1, -1, 1, 0, -1, 0, 0, 0, -1, -2, -2, 0, -1, -2, -1, 4, 1, -3,
529 verifyValues(sm, 'T',
531 { 0, -1, 0, -1, -1, -1, -1, -2, -2, -1, -1, -1, -1, -2, -1, 1,
532 5, -2, -2, 0, -1, -1, 0 });
533 verifyValues(sm, 'W',
535 { -3, -3, -4, -4, -2, -2, -3, -2, -2, -3, -2, -3, -1, 1, -4, -3,
536 -2, 11, 2, -3, -4, -3, -2 });
537 verifyValues(sm, 'Y',
539 { -2, -2, -2, -3, -2, -1, -2, -3, 2, -1, -1, -2, -1, 3, -3, -2,
540 -2, 2, 7, -1, -3, -2, -1 });
541 verifyValues(sm, 'V',
543 { 0, -3, -3, -3, -1, -2, -2, -3, -3, 3, 1, -2, 1, -1, -2, -2, 0,
544 -3, -1, 4, -3, -2, -1 });
545 verifyValues(sm, 'B',
547 { -2, -1, 3, 4, -3, 0, 1, -1, 0, -3, -4, 0, -3, -3, -2, 0, -1,
548 -4, -3, -3, 4, 1, -1 });
549 verifyValues(sm, 'Z',
551 { -1, 0, 0, 1, -3, 3, 4, -2, 0, -3, -3, 1, -1, -3, -1, 0, -1,
552 -3, -2, -2, 1, 4, -1 });
553 verifyValues(sm, 'X',
555 { 0, -1, -1, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, 0,
556 0, -2, -1, -1, -1, -1, -1 });
560 * Helper method to check pairwise scores for one residue
565 * score values against 'res', in ResidueProperties.aaIndex order
567 private void verifyValues(ScoreMatrix sm, char res, float[] expected)
569 for (int j = 0; j < expected.length; j++)
571 char c2 = ResidueProperties.aa[j].charAt(0);
572 assertEquals(sm.getPairwiseScore(res, c2), expected[j],
573 String.format("%s->%s", res, c2));
577 @Test(groups = "Functional")
578 public void testConstructor_gapDash()
580 float[][] scores = new float[2][];
581 scores[0] = new float[] { 1f, 2f };
582 scores[1] = new float[] { 4f, 5f };
583 ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', '-' },
585 assertEquals(sm.getSize(), 2);
586 assertArrayEquals(scores, sm.getMatrix());
587 assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
588 assertEquals(sm.getPairwiseScore('A', 'A'), 1f);
589 assertEquals(sm.getPairwiseScore('a', '-'), 2f);
590 assertEquals(sm.getPairwiseScore('-', 'A'), 4f);
591 assertEquals(sm.getMatrixIndex('a'), 0);
592 assertEquals(sm.getMatrixIndex('A'), 0);
593 assertEquals(sm.getMatrixIndex('-'), 1);
594 assertEquals(sm.getMatrixIndex(' '), -1);
595 assertEquals(sm.getMatrixIndex('.'), -1);
598 @Test(groups = "Functional")
599 public void testGetPairwiseScore()
601 float[][] scores = new float[2][];
602 scores[0] = new float[] { 1f, 2f };
603 scores[1] = new float[] { -4f, 5f };
604 ScoreMatrix sm = new ScoreMatrix("Test", new char[] { 'A', 'B' },
606 assertEquals(sm.getPairwiseScore('A', 'A'), 1f);
607 assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
608 assertEquals(sm.getPairwiseScore('A', 'B'), 2f);
609 assertEquals(sm.getPairwiseScore('b', 'a'), -4f);
610 assertEquals(sm.getPairwiseScore('B', 'b'), 5f);
613 * unknown symbols currently score minimum score
614 * or 1 for identity with self
616 assertEquals(sm.getPairwiseScore('A', '-'), -4f);
617 assertEquals(sm.getPairwiseScore('-', 'A'), -4f);
618 assertEquals(sm.getPairwiseScore('-', '-'), 1f);
619 assertEquals(sm.getPairwiseScore('Q', 'W'), -4f);
620 assertEquals(sm.getPairwiseScore('Q', 'Q'), 1f);
623 * symbols not in basic ASCII set score zero
626 assertEquals(sm.getPairwiseScore('Q', c), 0f);
627 assertEquals(sm.getPairwiseScore(c, 'Q'), 0f);
630 @Test(groups = "Functional")
631 public void testGetMinimumScore()
633 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
634 assertEquals(sm.getMinimumScore(), -4f);
637 @Test(groups = "Functional")
638 public void testGetMaximumScore()
640 ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
641 assertEquals(sm.getMaximumScore(), 11f);
644 @Test(groups = "Functional")
645 public void testOutputMatrix_html()
647 float[][] scores = new float[2][];
648 scores[0] = new float[] { 1f, 2f };
649 scores[1] = new float[] { 4f, -5.3E-10f };
650 ScoreMatrix sm = new ScoreMatrix("Test", "AB".toCharArray(), scores);
651 String html = sm.outputMatrix(true);
652 String expected = "<table border=\"1\"><tr><th></th><th> A </th><th> B </th></tr>\n"
653 + "<tr><td>A</td><td>1.0</td><td>2.0</td></tr>\n"
654 + "<tr><td>B</td><td>4.0</td><td>-5.3E-10</td></tr>\n"
656 assertEquals(html, expected);
659 @Test(groups = "Functional")
660 public void testIsSymmetric()
662 double delta = 0.0001d;
663 float[][] scores = new float[][] { { 1f, -2f }, { -2f, 3f } };
664 ScoreMatrix sm = new ScoreMatrix("Test", "AB".toCharArray(), scores);
665 assertTrue(sm.isSymmetric());
668 * verify that with a symmetric score matrix,
669 * pairwise similarity matrix is also symmetric
670 * seq1.seq1 = 5*A.A + 3*B.B = 5+9 = 14
671 * seq1.seq2 = 3*A.A + 2*A.B + B.A + 2*B.B = 3 + -4 + -2 + 6 = 3
672 * seq2.seq1 = 3*A.A + A.B + 2*B.A + 2*B.B = 3 + -2 + -4 + 6 = 3
673 * seq2.seq2 = 4*A.A + 4*B.B = 4 + 12 = 16
675 SimilarityParamsI params = new SimilarityParams(true, true, true,
677 String seq1 = "AAABBBAA";
678 String seq2 = "AABBABBA";
679 String[] seqs1 = new String[] { seq1, seq2 };
680 MatrixI res1 = sm.findSimilarities(seqs1, params);
682 res1.equals(new Matrix(new double[][]
683 { { 14d, 3d }, { 3d, 16d } }), delta));
686 * order of sequences affects diagonal, but not off-diagonal values
687 * [0, 0] is now seq2.seq2, [1, 1] is seq1.seq1
688 * [0, 1] is now seq2.seq1 = seq1.seq2 by symmetry
690 String[] seqs2 = new String[] { seq2, seq1 };
691 MatrixI res2 = sm.findSimilarities(seqs2, params);
692 assertFalse(res1.equals(res2));
694 res2.equals(new Matrix(new double[][]
695 { { 16d, 3d }, { 3d, 14d } }), delta));
698 * now make the score matrix asymmetric
699 * seq1.seq1 = 5*A.A + 3*B.B = 5+9 = 14
700 * seq1.seq2 = 3*A.A + 2*A.B + B.A + 2*B.B = 3 + -4 + 2 + 6 = 7
701 * seq2.seq1 = 3*A.A + A.B + 2*B.A + 2*B.B = 3 + -2 + 4 + 6 = 11
702 * seq2.seq2 = 4*A.A + 4*B.B = 4 + 12 = 16
704 scores = new float[][] { { 1f, -2f }, { 2f, 3f } };
705 sm = new ScoreMatrix("Test", "AB".toCharArray(), scores);
706 assertFalse(sm.isSymmetric()); // [0, 1] != [1, 0]
707 res1 = sm.findSimilarities(seqs1, params);
709 res1.equals(new Matrix(new double[][]
710 { { 14d, 7d }, { 11d, 16d } }), delta));
713 * reverse order of sequences
714 * - reverses order of main diagonal
715 * - reflects off-diagonal values
717 res2 = sm.findSimilarities(seqs2, params);
718 assertFalse(res1.equals(res2));
720 res2.equals(new Matrix(new double[][]
721 { { 16d, 11d }, { 7d, 14d } }), delta));
724 * verify that forcing an asymmetric matrix to use
725 * symmetric calculation gives a different (wrong) result
727 PA.setValue(sm, "symmetric", true);
728 assertTrue(sm.isSymmetric()); // it's not true!
729 res2 = sm.findSimilarities(seqs1, params);
730 assertFalse(res1.equals(res2, delta));