Merge branch 'develop' into features/JAL-2393customMatrices
[jalview.git] / test / jalview / analysis / scoremodels / ScoreMatrixTest.java
1 package jalview.analysis.scoremodels;
2 import static org.testng.Assert.assertEquals;
3 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
4
5 import jalview.math.MatrixI;
6
7 import org.testng.annotations.Test;
8
9 public class ScoreMatrixTest
10 {
11   @Test(groups = "Functional")
12   public void testConstructor()
13   {
14     // note score matrix does not have to be symmetric (though it should be!)
15     float[][] scores = new float[3][];
16     scores[0] = new float[] { 1f, 2f, 3f };
17     scores[1] = new float[] { 4f, 5f, 6f };
18     scores[2] = new float[] { 7f, 8f, 9f };
19     ScoreMatrix sm = new ScoreMatrix("Test", "ABC".toCharArray(), scores);
20     assertEquals(sm.getSize(), 3);
21     assertArrayEquals(scores, sm.getMatrix());
22     assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
23     assertEquals(sm.getPairwiseScore('b', 'c'), 6f);
24     assertEquals(sm.getPairwiseScore('c', 'b'), 8f);
25     assertEquals(sm.getPairwiseScore('A', 'D'), 0f);
26     assertEquals(sm.getMatrixIndex('c'), 2);
27     assertEquals(sm.getMatrixIndex(' '), -1);
28   }
29
30   @Test(
31     groups = "Functional",
32     expectedExceptions = { IllegalArgumentException.class })
33   public void testConstructor_matrixTooSmall()
34   {
35     float[][] scores = new float[2][];
36     scores[0] = new float[] { 1f, 2f };
37     scores[1] = new float[] { 3f, 4f };
38     new ScoreMatrix("Test", "ABC".toCharArray(), scores);
39   }
40
41   @Test(
42     groups = "Functional",
43     expectedExceptions = { IllegalArgumentException.class })
44   public void testConstructor_matrixTooBig()
45   {
46     float[][] scores = new float[2][];
47     scores[0] = new float[] { 1f, 2f };
48     scores[1] = new float[] { 3f, 4f };
49     new ScoreMatrix("Test", "A".toCharArray(), scores);
50   }
51
52   @Test(
53     groups = "Functional",
54     expectedExceptions = { IllegalArgumentException.class })
55   public void testConstructor_matrixNotSquare()
56   {
57     float[][] scores = new float[2][];
58     scores[0] = new float[] { 1f, 2f };
59     scores[1] = new float[] { 3f };
60     new ScoreMatrix("Test", "AB".toCharArray(), scores);
61   }
62
63   @Test(groups = "Functional")
64   public void testBuildSymbolIndex()
65   {
66     short[] index = ScoreMatrix.buildSymbolIndex("AX-. yxYp".toCharArray());
67
68     assertEquals(index.length, 128); // ASCII character set size
69
70     assertEquals(index['A'], 0);
71     assertEquals(index['a'], 0); // lower-case mapping added
72     assertEquals(index['X'], 1);
73     assertEquals(index['-'], 2);
74     assertEquals(index['.'], 3);
75     assertEquals(index[' '], 4);
76     assertEquals(index['y'], 5); // lower-case override
77     assertEquals(index['x'], 6); // lower-case override
78     assertEquals(index['Y'], 7);
79     assertEquals(index['p'], 8);
80     assertEquals(index['P'], -1); // lower-case doesn't map upper-case
81
82     /*
83      * check all unmapped symbols have index for unmapped
84      */
85     for (int c = 0; c < index.length; c++)
86     {
87       if (!"AaXx-. Yyp".contains(String.valueOf((char) c)))
88       {
89         assertEquals(index[c], -1);
90       }
91     }
92   }
93
94   /**
95    * check that characters not in the basic ASCII set are simply ignored
96    */
97   @Test(groups = "Functional")
98   public void testBuildSymbolIndex_nonAscii()
99   {
100     char[] weird = new char[] { 128, 245, 'P' };
101     short[] index = ScoreMatrix.buildSymbolIndex(weird);
102     assertEquals(index.length, 128);
103     assertEquals(index['P'], 2);
104     assertEquals(index['p'], 2);
105     for (int c = 0; c < index.length; c++)
106     {
107       if (c != 'P' && c != 'p')
108       {
109         assertEquals(index[c], -1);
110       }
111     }
112   }
113
114   @Test(groups = "Functional")
115   public void testGetMatrixIndex()
116   {
117     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
118     assertEquals(sm.getMatrixIndex('A'), 0);
119     assertEquals(sm.getMatrixIndex('R'), 1);
120     assertEquals(sm.getMatrixIndex('r'), 1);
121     assertEquals(sm.getMatrixIndex('N'), 2);
122     assertEquals(sm.getMatrixIndex('D'), 3);
123     assertEquals(sm.getMatrixIndex('X'), 22);
124     assertEquals(sm.getMatrixIndex('x'), 22);
125     assertEquals(sm.getMatrixIndex(' '), 23);
126     assertEquals(sm.getMatrixIndex('*'), 24);
127     assertEquals(sm.getMatrixIndex('.'), -1);
128     assertEquals(sm.getMatrixIndex('-'), -1);
129     assertEquals(sm.getMatrixIndex('?'), -1);
130     assertEquals(sm.getMatrixIndex((char) 128), -1);
131   }
132
133   @Test(groups = "Functional")
134   public void testGetSize()
135   {
136     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
137     assertEquals(sm.getMatrix().length, sm.getSize());
138   }
139
140   @Test(groups = "Functional")
141   public void testComputePairwiseScores()
142   {
143     /*
144      * NB score matrix assumes space for gap - Jalview converts
145      * space to gap before computing PCA or Tree
146      */
147     String[] seqs = new String[] { "FKL", "R D", "QIA", "GWC" };
148     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
149
150     MatrixI pairwise = sm.computePairwiseScores(seqs);
151
152     /*
153      * should be NxN where N = number of sequences
154      */
155     assertEquals(pairwise.height(), 4);
156     assertEquals(pairwise.width(), 4);
157
158     /*
159      * should be symmetrical (because BLOSUM62 is)
160      */
161     for (int i = 0; i < pairwise.height(); i++)
162     {
163       for (int j = i + 1; j < pairwise.width(); j++)
164       {
165         assertEquals(pairwise.getValue(i, j), pairwise.getValue(j, i),
166                 String.format("Not symmetric at [%d, %d]", i, j));
167       }
168     }
169     /*
170      * verify expected BLOSUM dot product scores
171      */
172     // F.F + K.K + L.L = 6 + 5 + 4 = 15
173     assertEquals(pairwise.getValue(0, 0), 15d);
174     // R.R + -.- + D.D = 5 + 1 + 6 = 12
175     assertEquals(pairwise.getValue(1, 1), 12d);
176     // Q.Q + I.I + A.A = 5 + 4 + 4 = 13
177     assertEquals(pairwise.getValue(2, 2), 13d);
178     // G.G + W.W + C.C = 6 + 11 + 9 = 26
179     assertEquals(pairwise.getValue(3, 3), 26d);
180     // F.R + K.- + L.D = -3 + -4 + -4 = -11
181     assertEquals(pairwise.getValue(0, 1), -11d);
182     // F.Q + K.I + L.A = -3 + -3 + -1 = -7
183     assertEquals(pairwise.getValue(0, 2), -7d);
184     // F.G + K.W + L.C = -3 + -3 + -1 = -7
185     assertEquals(pairwise.getValue(0, 3), -7d);
186     // R.Q + -.I + D.A = 1 + -4 + -2 = -5
187     assertEquals(pairwise.getValue(1, 2), -5d);
188     // R.G + -.W + D.C = -2 + -4 + -3 = -9
189     assertEquals(pairwise.getValue(1, 3), -9d);
190     // Q.G + I.W + A.C = -2 + -3 + 0 = -5
191     assertEquals(pairwise.getValue(2, 3), -5d);
192   }
193 }