b234d480d6043e1813ef3c5b793f4a958c512486
[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.assertNotNull;
5 import static org.testng.Assert.assertNotSame;
6 import static org.testng.Assert.assertTrue;
7 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
8
9 import jalview.io.DataSourceType;
10 import jalview.io.FileParse;
11 import jalview.io.ScoreMatrixFile;
12 import jalview.math.MatrixI;
13
14 import java.io.IOException;
15 import java.net.MalformedURLException;
16 import java.util.Arrays;
17
18 import org.testng.annotations.Test;
19
20 public class ScoreMatrixTest
21 {
22   @Test(groups = "Functional")
23   public void testConstructor()
24   {
25     // note score matrix does not have to be symmetric (though it should be!)
26     float[][] scores = new float[3][];
27     scores[0] = new float[] { 1f, 2f, 3f };
28     scores[1] = new float[] { 4f, 5f, 6f };
29     scores[2] = new float[] { 7f, 8f, 9f };
30     ScoreMatrix sm = new ScoreMatrix("Test", "ABC".toCharArray(), scores);
31     assertEquals(sm.getSize(), 3);
32     assertArrayEquals(scores, sm.getMatrix());
33     assertEquals(sm.getPairwiseScore('A', 'a'), 1f);
34     assertEquals(sm.getPairwiseScore('b', 'c'), 6f);
35     assertEquals(sm.getPairwiseScore('c', 'b'), 8f);
36     assertEquals(sm.getPairwiseScore('A', 'D'), 0f);
37     assertEquals(sm.getMatrixIndex('c'), 2);
38     assertEquals(sm.getMatrixIndex(' '), -1);
39   }
40
41   @Test(
42     groups = "Functional",
43     expectedExceptions = { IllegalArgumentException.class })
44   public void testConstructor_matrixTooSmall()
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", "ABC".toCharArray(), scores);
50   }
51
52   @Test(
53     groups = "Functional",
54     expectedExceptions = { IllegalArgumentException.class })
55   public void testConstructor_matrixTooBig()
56   {
57     float[][] scores = new float[2][];
58     scores[0] = new float[] { 1f, 2f };
59     scores[1] = new float[] { 3f, 4f };
60     new ScoreMatrix("Test", "A".toCharArray(), scores);
61   }
62
63   @Test(
64     groups = "Functional",
65     expectedExceptions = { IllegalArgumentException.class })
66   public void testConstructor_matrixNotSquare()
67   {
68     float[][] scores = new float[2][];
69     scores[0] = new float[] { 1f, 2f };
70     scores[1] = new float[] { 3f };
71     new ScoreMatrix("Test", "AB".toCharArray(), scores);
72   }
73
74   @Test(groups = "Functional")
75   public void testBuildSymbolIndex()
76   {
77     short[] index = ScoreMatrix.buildSymbolIndex("AX-. yxYp".toCharArray());
78
79     assertEquals(index.length, 128); // ASCII character set size
80
81     assertEquals(index['A'], 0);
82     assertEquals(index['a'], 0); // lower-case mapping added
83     assertEquals(index['X'], 1);
84     assertEquals(index['-'], 2);
85     assertEquals(index['.'], 3);
86     assertEquals(index[' '], 4);
87     assertEquals(index['y'], 5); // lower-case override
88     assertEquals(index['x'], 6); // lower-case override
89     assertEquals(index['Y'], 7);
90     assertEquals(index['p'], 8);
91     assertEquals(index['P'], -1); // lower-case doesn't map upper-case
92
93     /*
94      * check all unmapped symbols have index for unmapped
95      */
96     for (int c = 0; c < index.length; c++)
97     {
98       if (!"AaXx-. Yyp".contains(String.valueOf((char) c)))
99       {
100         assertEquals(index[c], -1);
101       }
102     }
103   }
104
105   /**
106    * check that characters not in the basic ASCII set are simply ignored
107    */
108   @Test(groups = "Functional")
109   public void testBuildSymbolIndex_nonAscii()
110   {
111     char[] weird = new char[] { 128, 245, 'P' };
112     short[] index = ScoreMatrix.buildSymbolIndex(weird);
113     assertEquals(index.length, 128);
114     assertEquals(index['P'], 2);
115     assertEquals(index['p'], 2);
116     for (int c = 0; c < index.length; c++)
117     {
118       if (c != 'P' && c != 'p')
119       {
120         assertEquals(index[c], -1);
121       }
122     }
123   }
124
125   @Test(groups = "Functional")
126   public void testGetMatrix()
127   {
128     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
129     float[][] m = sm.getMatrix();
130     assertEquals(m.length, sm.getSize());
131     assertEquals(m[2][4], -3f);
132     // verify a defensive copy is returned
133     float[][] m2 = sm.getMatrix();
134     assertNotSame(m, m2);
135     assertTrue(Arrays.deepEquals(m, m2));
136   }
137
138   @Test(groups = "Functional")
139   public void testGetMatrixIndex()
140   {
141     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
142     assertEquals(sm.getMatrixIndex('A'), 0);
143     assertEquals(sm.getMatrixIndex('R'), 1);
144     assertEquals(sm.getMatrixIndex('r'), 1);
145     assertEquals(sm.getMatrixIndex('N'), 2);
146     assertEquals(sm.getMatrixIndex('D'), 3);
147     assertEquals(sm.getMatrixIndex('X'), 22);
148     assertEquals(sm.getMatrixIndex('x'), 22);
149     assertEquals(sm.getMatrixIndex(' '), 23);
150     assertEquals(sm.getMatrixIndex('*'), 24);
151     assertEquals(sm.getMatrixIndex('.'), -1);
152     assertEquals(sm.getMatrixIndex('-'), -1);
153     assertEquals(sm.getMatrixIndex('?'), -1);
154     assertEquals(sm.getMatrixIndex((char) 128), -1);
155   }
156
157   @Test(groups = "Functional")
158   public void testGetSize()
159   {
160     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
161     assertEquals(sm.getMatrix().length, sm.getSize());
162   }
163
164   @Test(groups = "Functional")
165   public void testComputePairwiseScores()
166   {
167     /*
168      * NB score matrix assumes space for gap - Jalview converts
169      * space to gap before computing PCA or Tree
170      */
171     String[] seqs = new String[] { "FKL", "R D", "QIA", "GWC" };
172     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
173
174     MatrixI pairwise = sm.computePairwiseScores(seqs);
175
176     /*
177      * should be NxN where N = number of sequences
178      */
179     assertEquals(pairwise.height(), 4);
180     assertEquals(pairwise.width(), 4);
181
182     /*
183      * should be symmetrical (because BLOSUM62 is)
184      */
185     for (int i = 0; i < pairwise.height(); i++)
186     {
187       for (int j = i + 1; j < pairwise.width(); j++)
188       {
189         assertEquals(pairwise.getValue(i, j), pairwise.getValue(j, i),
190                 String.format("Not symmetric at [%d, %d]", i, j));
191       }
192     }
193     /*
194      * verify expected BLOSUM dot product scores
195      */
196     // F.F + K.K + L.L = 6 + 5 + 4 = 15
197     assertEquals(pairwise.getValue(0, 0), 15d);
198     // R.R + -.- + D.D = 5 + 1 + 6 = 12
199     assertEquals(pairwise.getValue(1, 1), 12d);
200     // Q.Q + I.I + A.A = 5 + 4 + 4 = 13
201     assertEquals(pairwise.getValue(2, 2), 13d);
202     // G.G + W.W + C.C = 6 + 11 + 9 = 26
203     assertEquals(pairwise.getValue(3, 3), 26d);
204     // F.R + K.- + L.D = -3 + -4 + -4 = -11
205     assertEquals(pairwise.getValue(0, 1), -11d);
206     // F.Q + K.I + L.A = -3 + -3 + -1 = -7
207     assertEquals(pairwise.getValue(0, 2), -7d);
208     // F.G + K.W + L.C = -3 + -3 + -1 = -7
209     assertEquals(pairwise.getValue(0, 3), -7d);
210     // R.Q + -.I + D.A = 1 + -4 + -2 = -5
211     assertEquals(pairwise.getValue(1, 2), -5d);
212     // R.G + -.W + D.C = -2 + -4 + -3 = -9
213     assertEquals(pairwise.getValue(1, 3), -9d);
214     // Q.G + I.W + A.C = -2 + -3 + 0 = -5
215     assertEquals(pairwise.getValue(2, 3), -5d);
216   }
217
218   /**
219    * Test that the result of outputMatrix can be reparsed to give an identical
220    * ScoreMatrix
221    * 
222    * @throws IOException
223    * @throws MalformedURLException
224    */
225   @Test(groups = "Functional")
226   public void testOutputMatrix_roundTrip() throws MalformedURLException,
227           IOException
228   {
229     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
230     String output = sm.outputMatrix(false);
231     FileParse fp = new FileParse(output, DataSourceType.PASTE);
232     ScoreMatrixFile parser = new ScoreMatrixFile(fp);
233     ScoreMatrix sm2 = parser.parseMatrix();
234     assertNotNull(sm2);
235     assertTrue(sm2.equals(sm));
236   }
237
238   @Test(groups = "Functional")
239   public void testEqualsAndHashCode()
240   {
241     ScoreMatrix sm = ScoreModels.getInstance().getBlosum62();
242     ScoreMatrix sm2 = new ScoreMatrix(sm.getName(), sm.getSymbols()
243             .toCharArray(), sm.getMatrix());
244     assertTrue(sm.equals(sm2));
245     assertEquals(sm.hashCode(), sm2.hashCode());
246   }
247 }