Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
MatrixTest | 36 | 227 | 42 |
1 | /* | |
2 | * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) | |
3 | * Copyright (C) $$Year-Rel$$ The Jalview Authors | |
4 | * | |
5 | * This file is part of Jalview. | |
6 | * | |
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. | |
11 | * | |
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. | |
16 | * | |
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. | |
20 | */ | |
21 | package jalview.math; | |
22 | ||
23 | import static org.testng.Assert.assertEquals; | |
24 | import static org.testng.Assert.assertFalse; | |
25 | import static org.testng.Assert.assertNotSame; | |
26 | import static org.testng.Assert.assertNull; | |
27 | import static org.testng.Assert.assertTrue; | |
28 | import static org.testng.Assert.fail; | |
29 | ||
30 | import java.util.Arrays; | |
31 | import java.util.Random; | |
32 | ||
33 | import org.testng.annotations.Test; | |
34 | import org.testng.internal.junit.ArrayAsserts; | |
35 | ||
36 | public class MatrixTest | |
37 | { | |
38 | final static double DELTA = 0.000001d; | |
39 | ||
40 | 0 | @Test(groups = "Timing") |
41 | public void testPreMultiply_timing() | |
42 | { | |
43 | 0 | int rows = 50; // increase to stress test timing |
44 | 0 | int cols = 100; |
45 | 0 | double[][] d1 = new double[rows][cols]; |
46 | 0 | double[][] d2 = new double[cols][rows]; |
47 | 0 | Matrix m1 = new Matrix(d1); |
48 | 0 | Matrix m2 = new Matrix(d2); |
49 | 0 | long start = System.currentTimeMillis(); |
50 | 0 | m1.preMultiply(m2); |
51 | 0 | long elapsed = System.currentTimeMillis() - start; |
52 | 0 | System.out.println(rows + "x" + cols |
53 | + " multiplications of double took " + elapsed + "ms"); | |
54 | } | |
55 | ||
56 | 1 | @Test(groups = "Functional") |
57 | public void testPreMultiply() | |
58 | { | |
59 | 1 | Matrix m1 = new Matrix(new double[][] { { 2, 3, 4 } }); // 1x3 |
60 | 1 | Matrix m2 = new Matrix(new double[][] { { 5 }, { 6 }, { 7 } }); // 3x1 |
61 | ||
62 | /* | |
63 | * 1x3 times 3x1 is 1x1 | |
64 | * 2x5 + 3x6 + 4*7 = 56 | |
65 | */ | |
66 | 1 | MatrixI m3 = m2.preMultiply(m1); |
67 | 1 | assertEquals(m3.height(), 1); |
68 | 1 | assertEquals(m3.width(), 1); |
69 | 1 | assertEquals(m3.getValue(0, 0), 56d); |
70 | ||
71 | /* | |
72 | * 3x1 times 1x3 is 3x3 | |
73 | */ | |
74 | 1 | m3 = m1.preMultiply(m2); |
75 | 1 | assertEquals(m3.height(), 3); |
76 | 1 | assertEquals(m3.width(), 3); |
77 | 1 | assertEquals(Arrays.toString(m3.getRow(0)), "[10.0, 15.0, 20.0]"); |
78 | 1 | assertEquals(Arrays.toString(m3.getRow(1)), "[12.0, 18.0, 24.0]"); |
79 | 1 | assertEquals(Arrays.toString(m3.getRow(2)), "[14.0, 21.0, 28.0]"); |
80 | } | |
81 | ||
82 | 1 | @Test( |
83 | groups = "Functional", | |
84 | expectedExceptions = | |
85 | { IllegalArgumentException.class }) | |
86 | public void testPreMultiply_tooManyColumns() | |
87 | { | |
88 | 1 | Matrix m1 = new Matrix(new double[][] { { 2, 3, 4 }, { 3, 4, 5 } }); // 2x3 |
89 | ||
90 | /* | |
91 | * 2x3 times 2x3 invalid operation - | |
92 | * multiplier has more columns than multiplicand has rows | |
93 | */ | |
94 | 1 | m1.preMultiply(m1); |
95 | 0 | fail("Expected exception"); |
96 | } | |
97 | ||
98 | 1 | @Test( |
99 | groups = "Functional", | |
100 | expectedExceptions = | |
101 | { IllegalArgumentException.class }) | |
102 | public void testPreMultiply_tooFewColumns() | |
103 | { | |
104 | 1 | Matrix m1 = new Matrix(new double[][] { { 2, 3, 4 }, { 3, 4, 5 } }); // 2x3 |
105 | ||
106 | /* | |
107 | * 3x2 times 3x2 invalid operation - | |
108 | * multiplier has more columns than multiplicand has row | |
109 | */ | |
110 | 1 | m1.preMultiply(m1); |
111 | 0 | fail("Expected exception"); |
112 | } | |
113 | ||
114 | 1 | private boolean matrixEquals(Matrix m1, Matrix m2) |
115 | { | |
116 | 1 | if (m1.width() != m2.width() || m1.height() != m2.height()) |
117 | { | |
118 | 0 | return false; |
119 | } | |
120 | 6 | for (int i = 0; i < m1.height(); i++) |
121 | { | |
122 | 5 | if (!Arrays.equals(m1.getRow(i), m2.getRow(i))) |
123 | { | |
124 | 0 | return false; |
125 | } | |
126 | } | |
127 | 1 | return true; |
128 | } | |
129 | ||
130 | 1 | @Test(groups = "Functional") |
131 | public void testPostMultiply() | |
132 | { | |
133 | /* | |
134 | * Square matrices | |
135 | * (2 3) . (10 100) | |
136 | * (4 5) (1000 10000) | |
137 | * = | |
138 | * (3020 30200) | |
139 | * (5040 50400) | |
140 | */ | |
141 | 1 | MatrixI m1 = new Matrix(new double[][] { { 2, 3 }, { 4, 5 } }); |
142 | 1 | MatrixI m2 = new Matrix( |
143 | new double[][] | |
144 | { { 10, 100 }, { 1000, 10000 } }); | |
145 | 1 | MatrixI m3 = m1.postMultiply(m2); |
146 | 1 | assertEquals(Arrays.toString(m3.getRow(0)), "[3020.0, 30200.0]"); |
147 | 1 | assertEquals(Arrays.toString(m3.getRow(1)), "[5040.0, 50400.0]"); |
148 | ||
149 | /* | |
150 | * also check m2.preMultiply(m1) - should be same as m1.postMultiply(m2) | |
151 | */ | |
152 | 1 | m3 = m2.preMultiply(m1); |
153 | 1 | assertEquals(Arrays.toString(m3.getRow(0)), "[3020.0, 30200.0]"); |
154 | 1 | assertEquals(Arrays.toString(m3.getRow(1)), "[5040.0, 50400.0]"); |
155 | ||
156 | /* | |
157 | * m1 has more rows than columns | |
158 | * (2).(10 100 1000) = (20 200 2000) | |
159 | * (3) (30 300 3000) | |
160 | */ | |
161 | 1 | m1 = new Matrix(new double[][] { { 2 }, { 3 } }); |
162 | 1 | m2 = new Matrix(new double[][] { { 10, 100, 1000 } }); |
163 | 1 | m3 = m1.postMultiply(m2); |
164 | 1 | assertEquals(m3.height(), 2); |
165 | 1 | assertEquals(m3.width(), 3); |
166 | 1 | assertEquals(Arrays.toString(m3.getRow(0)), "[20.0, 200.0, 2000.0]"); |
167 | 1 | assertEquals(Arrays.toString(m3.getRow(1)), "[30.0, 300.0, 3000.0]"); |
168 | 1 | m3 = m2.preMultiply(m1); |
169 | 1 | assertEquals(m3.height(), 2); |
170 | 1 | assertEquals(m3.width(), 3); |
171 | 1 | assertEquals(Arrays.toString(m3.getRow(0)), "[20.0, 200.0, 2000.0]"); |
172 | 1 | assertEquals(Arrays.toString(m3.getRow(1)), "[30.0, 300.0, 3000.0]"); |
173 | ||
174 | /* | |
175 | * m1 has more columns than rows | |
176 | * (2 3 4) . (5 4) = (56 25) | |
177 | * (6 3) | |
178 | * (7 2) | |
179 | * [0, 0] = 2*5 + 3*6 + 4*7 = 56 | |
180 | * [0, 1] = 2*4 + 3*3 + 4*2 = 25 | |
181 | */ | |
182 | 1 | m1 = new Matrix(new double[][] { { 2, 3, 4 } }); |
183 | 1 | m2 = new Matrix(new double[][] { { 5, 4 }, { 6, 3 }, { 7, 2 } }); |
184 | 1 | m3 = m1.postMultiply(m2); |
185 | 1 | assertEquals(m3.height(), 1); |
186 | 1 | assertEquals(m3.width(), 2); |
187 | 1 | assertEquals(m3.getRow(0)[0], 56d); |
188 | 1 | assertEquals(m3.getRow(0)[1], 25d); |
189 | ||
190 | /* | |
191 | * and check premultiply equivalent | |
192 | */ | |
193 | 1 | m3 = m2.preMultiply(m1); |
194 | 1 | assertEquals(m3.height(), 1); |
195 | 1 | assertEquals(m3.width(), 2); |
196 | 1 | assertEquals(m3.getRow(0)[0], 56d); |
197 | 1 | assertEquals(m3.getRow(0)[1], 25d); |
198 | } | |
199 | ||
200 | 1 | @Test(groups = "Functional") |
201 | public void testCopy() | |
202 | { | |
203 | 1 | Random r = new Random(); |
204 | 1 | int rows = 5; |
205 | 1 | int cols = 11; |
206 | 1 | double[][] in = new double[rows][cols]; |
207 | ||
208 | 6 | for (int i = 0; i < rows; i++) |
209 | { | |
210 | 60 | for (int j = 0; j < cols; j++) |
211 | { | |
212 | 55 | in[i][j] = r.nextDouble(); |
213 | } | |
214 | } | |
215 | 1 | Matrix m1 = new Matrix(in); |
216 | ||
217 | 1 | Matrix m2 = (Matrix) m1.copy(); |
218 | 1 | assertNotSame(m1, m2); |
219 | 1 | assertTrue(matrixEquals(m1, m2)); |
220 | 1 | assertNull(m2.d); |
221 | 1 | assertNull(m2.e); |
222 | ||
223 | /* | |
224 | * now add d and e vectors and recopy | |
225 | */ | |
226 | 1 | m1.d = Arrays.copyOf(in[2], in[2].length); |
227 | 1 | m1.e = Arrays.copyOf(in[4], in[4].length); |
228 | 1 | m2 = (Matrix) m1.copy(); |
229 | 1 | assertNotSame(m2.d, m1.d); |
230 | 1 | assertNotSame(m2.e, m1.e); |
231 | 1 | assertEquals(m2.d, m1.d); |
232 | 1 | assertEquals(m2.e, m1.e); |
233 | } | |
234 | ||
235 | /** | |
236 | * main method extracted from Matrix | |
237 | * | |
238 | * @param args | |
239 | */ | |
240 | 0 | public static void main(String[] args) throws Exception |
241 | { | |
242 | 0 | int n = Integer.parseInt(args[0]); |
243 | 0 | double[][] in = new double[n][n]; |
244 | ||
245 | 0 | for (int i = 0; i < n; i++) |
246 | { | |
247 | 0 | for (int j = 0; j < n; j++) |
248 | { | |
249 | 0 | in[i][j] = Math.random(); |
250 | } | |
251 | } | |
252 | ||
253 | 0 | Matrix origmat = new Matrix(in); |
254 | ||
255 | // System.out.println(" --- Original matrix ---- "); | |
256 | // / origmat.print(System.out); | |
257 | // System.out.println(); | |
258 | // System.out.println(" --- transpose matrix ---- "); | |
259 | 0 | MatrixI trans = origmat.transpose(); |
260 | ||
261 | // trans.print(System.out); | |
262 | // System.out.println(); | |
263 | // System.out.println(" --- OrigT * Orig ---- "); | |
264 | 0 | MatrixI symm = trans.postMultiply(origmat); |
265 | ||
266 | // symm.print(System.out); | |
267 | // System.out.println(); | |
268 | // Copy the symmetric matrix for later | |
269 | // Matrix origsymm = symm.copy(); | |
270 | ||
271 | // This produces the tridiagonal transformation matrix | |
272 | // long tstart = System.currentTimeMillis(); | |
273 | 0 | symm.tred(); |
274 | ||
275 | // long tend = System.currentTimeMillis(); | |
276 | ||
277 | // System.out.println("Time take for tred = " + (tend-tstart) + "ms"); | |
278 | // System.out.println(" ---Tridiag transform matrix ---"); | |
279 | // symm.print(System.out); | |
280 | // System.out.println(); | |
281 | // System.out.println(" --- D vector ---"); | |
282 | // symm.printD(System.out); | |
283 | // System.out.println(); | |
284 | // System.out.println(" --- E vector ---"); | |
285 | // symm.printE(System.out); | |
286 | // System.out.println(); | |
287 | // Now produce the diagonalization matrix | |
288 | // tstart = System.currentTimeMillis(); | |
289 | 0 | symm.tqli(); |
290 | // tend = System.currentTimeMillis(); | |
291 | ||
292 | // System.out.println("Time take for tqli = " + (tend-tstart) + " ms"); | |
293 | // System.out.println(" --- New diagonalization matrix ---"); | |
294 | // symm.print(System.out); | |
295 | // System.out.println(); | |
296 | // System.out.println(" --- D vector ---"); | |
297 | // symm.printD(System.out); | |
298 | // System.out.println(); | |
299 | // System.out.println(" --- E vector ---"); | |
300 | // symm.printE(System.out); | |
301 | // System.out.println(); | |
302 | // System.out.println(" --- First eigenvector --- "); | |
303 | // double[] eigenv = symm.getColumn(0); | |
304 | // for (int i=0; i < eigenv.length;i++) { | |
305 | // Format.print(System.out,"%15.4f",eigenv[i]); | |
306 | // } | |
307 | // System.out.println(); | |
308 | // double[] neigenv = origsymm.vectorPostMultiply(eigenv); | |
309 | // for (int i=0; i < neigenv.length;i++) { | |
310 | // Format.print(System.out,"%15.4f",neigenv[i]/symm.d[0]); | |
311 | // } | |
312 | // System.out.println(); | |
313 | } | |
314 | ||
315 | 0 | @Test(groups = "Timing") |
316 | public void testSign() | |
317 | { | |
318 | 0 | assertEquals(Matrix.sign(-1, -2), -1d); |
319 | 0 | assertEquals(Matrix.sign(-1, 2), 1d); |
320 | 0 | assertEquals(Matrix.sign(-1, 0), 1d); |
321 | 0 | assertEquals(Matrix.sign(1, -2), -1d); |
322 | 0 | assertEquals(Matrix.sign(1, 2), 1d); |
323 | 0 | assertEquals(Matrix.sign(1, 0), 1d); |
324 | } | |
325 | ||
326 | /** | |
327 | * Helper method to make values for a sparse, pseudo-random symmetric matrix | |
328 | * | |
329 | * @param rows | |
330 | * @param cols | |
331 | * @param occupancy | |
332 | * one in 'occupancy' entries will be non-zero | |
333 | * @return | |
334 | */ | |
335 | 1 | public double[][] getSparseValues(int rows, int cols, int occupancy) |
336 | { | |
337 | 1 | Random r = new Random(1729); |
338 | ||
339 | /* | |
340 | * generate whole number values between -12 and +12 | |
341 | * (to mimic score matrices used in Jalview) | |
342 | */ | |
343 | 1 | double[][] d = new double[rows][cols]; |
344 | 1 | int m = 0; |
345 | 11 | for (int i = 0; i < rows; i++) |
346 | { | |
347 | 10 | if (++m % occupancy == 0) |
348 | { | |
349 | 0 | d[i][i] = r.nextInt() % 13; // diagonal |
350 | } | |
351 | 55 | for (int j = 0; j < i; j++) |
352 | { | |
353 | 45 | if (++m % occupancy == 0) |
354 | { | |
355 | 18 | d[i][j] = r.nextInt() % 13; |
356 | 18 | d[j][i] = d[i][j]; |
357 | } | |
358 | } | |
359 | } | |
360 | 1 | return d; |
361 | ||
362 | } | |
363 | ||
364 | /** | |
365 | * Verify that the results of method tred() are the same if the calculation is | |
366 | * redone | |
367 | */ | |
368 | 1 | @Test(groups = "Functional") |
369 | public void testTred_reproducible() | |
370 | { | |
371 | /* | |
372 | * make a pseudo-random symmetric matrix as required for tred/tqli | |
373 | */ | |
374 | 1 | int rows = 10; |
375 | 1 | int cols = rows; |
376 | 1 | double[][] d = getSparseValues(rows, cols, 3); |
377 | ||
378 | /* | |
379 | * make a copy of the values so m1, m2 are not | |
380 | * sharing arrays! | |
381 | */ | |
382 | 1 | double[][] d1 = new double[rows][cols]; |
383 | 11 | for (int row = 0; row < rows; row++) |
384 | { | |
385 | 110 | for (int col = 0; col < cols; col++) |
386 | { | |
387 | 100 | d1[row][col] = d[row][col]; |
388 | } | |
389 | } | |
390 | 1 | Matrix m1 = new Matrix(d); |
391 | 1 | Matrix m2 = new Matrix(d1); |
392 | 1 | assertMatricesMatch(m1, m2); // sanity check |
393 | 1 | m1.tred(); |
394 | 1 | m2.tred(); |
395 | 1 | assertMatricesMatch(m1, m2); |
396 | } | |
397 | ||
398 | 2 | public static void assertMatricesMatch(MatrixI m1, MatrixI m2) |
399 | { | |
400 | 2 | if (m1.height() != m2.height()) |
401 | { | |
402 | 0 | fail("height mismatch"); |
403 | } | |
404 | 2 | if (m1.width() != m2.width()) |
405 | { | |
406 | 0 | fail("width mismatch"); |
407 | } | |
408 | 22 | for (int row = 0; row < m1.height(); row++) |
409 | { | |
410 | 220 | for (int col = 0; col < m1.width(); col++) |
411 | { | |
412 | 200 | double v2 = m2.getValue(row, col); |
413 | 200 | double v1 = m1.getValue(row, col); |
414 | 200 | if (Math.abs(v1 - v2) > DELTA) |
415 | { | |
416 | 0 | fail(String.format("At [%d, %d] %f != %f", row, col, v1, v2)); |
417 | } | |
418 | } | |
419 | } | |
420 | 2 | ArrayAsserts.assertArrayEquals("D vector", m1.getD(), m2.getD(), |
421 | 0.00001d); | |
422 | 2 | ArrayAsserts.assertArrayEquals("E vector", m1.getE(), m2.getE(), |
423 | 0.00001d); | |
424 | } | |
425 | ||
426 | 1 | @Test(groups = "Functional") |
427 | public void testFindMinMax() | |
428 | { | |
429 | /* | |
430 | * empty matrix case | |
431 | */ | |
432 | 1 | Matrix m = new Matrix(new double[][] { {} }); |
433 | 1 | assertNull(m.findMinMax()); |
434 | ||
435 | /* | |
436 | * normal case | |
437 | */ | |
438 | 1 | double[][] vals = new double[2][]; |
439 | 1 | vals[0] = new double[] { 7d, 1d, -2.3d }; |
440 | 1 | vals[1] = new double[] { -12d, 94.3d, -102.34d }; |
441 | 1 | m = new Matrix(vals); |
442 | 1 | double[] minMax = m.findMinMax(); |
443 | 1 | assertEquals(minMax[0], -102.34d); |
444 | 1 | assertEquals(minMax[1], 94.3d); |
445 | } | |
446 | ||
447 | 1 | @Test(groups = { "Functional", "Timing" }) |
448 | public void testFindMinMax_timing() | |
449 | { | |
450 | 1 | Random r = new Random(); |
451 | 1 | int size = 1000; // increase to stress test timing |
452 | 1 | double[][] vals = new double[size][size]; |
453 | 1 | double max = -Double.MAX_VALUE; |
454 | 1 | double min = Double.MAX_VALUE; |
455 | 1001 | for (int i = 0; i < size; i++) |
456 | { | |
457 | 1000 | vals[i] = new double[size]; |
458 | 1001000 | for (int j = 0; j < size; j++) |
459 | { | |
460 | // use nextLong rather than nextDouble to include negative values | |
461 | 1000000 | double d = r.nextLong(); |
462 | 1000000 | if (d > max) |
463 | { | |
464 | 13 | max = d; |
465 | } | |
466 | 1000000 | if (d < min) |
467 | { | |
468 | 12 | min = d; |
469 | } | |
470 | 1000000 | vals[i][j] = d; |
471 | } | |
472 | } | |
473 | 1 | Matrix m = new Matrix(vals); |
474 | 1 | long now = System.currentTimeMillis(); |
475 | 1 | double[] minMax = m.findMinMax(); |
476 | 1 | System.out.println(String.format("findMinMax for %d x %d took %dms", |
477 | size, size, (System.currentTimeMillis() - now))); | |
478 | 1 | assertEquals(minMax[0], min); |
479 | 1 | assertEquals(minMax[1], max); |
480 | } | |
481 | ||
482 | /** | |
483 | * Test range reversal with maximum value becoming zero | |
484 | */ | |
485 | 1 | @Test(groups = "Functional") |
486 | public void testReverseRange_maxToZero() | |
487 | { | |
488 | 1 | Matrix m1 = new Matrix( |
489 | new double[][] | |
490 | { { 2, 3.5, 4 }, { -3.4, 4, 15 } }); | |
491 | ||
492 | /* | |
493 | * subtract all from max: range -3.4 to 15 becomes 18.4 to 0 | |
494 | */ | |
495 | 1 | m1.reverseRange(true); |
496 | 1 | assertEquals(m1.getValue(0, 0), 13d, DELTA); |
497 | 1 | assertEquals(m1.getValue(0, 1), 11.5d, DELTA); |
498 | 1 | assertEquals(m1.getValue(0, 2), 11d, DELTA); |
499 | 1 | assertEquals(m1.getValue(1, 0), 18.4d, DELTA); |
500 | 1 | assertEquals(m1.getValue(1, 1), 11d, DELTA); |
501 | 1 | assertEquals(m1.getValue(1, 2), 0d, DELTA); |
502 | ||
503 | /* | |
504 | * repeat operation - range is now 0 to 18.4 | |
505 | */ | |
506 | 1 | m1.reverseRange(true); |
507 | 1 | assertEquals(m1.getValue(0, 0), 5.4d, DELTA); |
508 | 1 | assertEquals(m1.getValue(0, 1), 6.9d, DELTA); |
509 | 1 | assertEquals(m1.getValue(0, 2), 7.4d, DELTA); |
510 | 1 | assertEquals(m1.getValue(1, 0), 0d, DELTA); |
511 | 1 | assertEquals(m1.getValue(1, 1), 7.4d, DELTA); |
512 | 1 | assertEquals(m1.getValue(1, 2), 18.4d, DELTA); |
513 | } | |
514 | ||
515 | /** | |
516 | * Test range reversal with minimum and maximum values swapped | |
517 | */ | |
518 | 1 | @Test(groups = "Functional") |
519 | public void testReverseRange_swapMinMax() | |
520 | { | |
521 | 1 | Matrix m1 = new Matrix( |
522 | new double[][] | |
523 | { { 2, 3.5, 4 }, { -3.4, 4, 15 } }); | |
524 | ||
525 | /* | |
526 | * swap all values in min-max range | |
527 | * = subtract from (min + max = 11.6) | |
528 | * range -3.4 to 15 becomes 18.4 to -3.4 | |
529 | */ | |
530 | 1 | m1.reverseRange(false); |
531 | 1 | assertEquals(m1.getValue(0, 0), 9.6d, DELTA); |
532 | 1 | assertEquals(m1.getValue(0, 1), 8.1d, DELTA); |
533 | 1 | assertEquals(m1.getValue(0, 2), 7.6d, DELTA); |
534 | 1 | assertEquals(m1.getValue(1, 0), 15d, DELTA); |
535 | 1 | assertEquals(m1.getValue(1, 1), 7.6d, DELTA); |
536 | 1 | assertEquals(m1.getValue(1, 2), -3.4d, DELTA); |
537 | ||
538 | /* | |
539 | * repeat operation - original values restored | |
540 | */ | |
541 | 1 | m1.reverseRange(false); |
542 | 1 | assertEquals(m1.getValue(0, 0), 2d, DELTA); |
543 | 1 | assertEquals(m1.getValue(0, 1), 3.5d, DELTA); |
544 | 1 | assertEquals(m1.getValue(0, 2), 4d, DELTA); |
545 | 1 | assertEquals(m1.getValue(1, 0), -3.4d, DELTA); |
546 | 1 | assertEquals(m1.getValue(1, 1), 4d, DELTA); |
547 | 1 | assertEquals(m1.getValue(1, 2), 15d, DELTA); |
548 | } | |
549 | ||
550 | 1 | @Test(groups = "Functional") |
551 | public void testMultiply() | |
552 | { | |
553 | 1 | Matrix m = new Matrix( |
554 | new double[][] | |
555 | { { 2, 3.5, 4 }, { -3.4, 4, 15 } }); | |
556 | 1 | m.multiply(2d); |
557 | 1 | assertEquals(m.getValue(0, 0), 4d, DELTA); |
558 | 1 | assertEquals(m.getValue(0, 1), 7d, DELTA); |
559 | 1 | assertEquals(m.getValue(0, 2), 8d, DELTA); |
560 | 1 | assertEquals(m.getValue(1, 0), -6.8d, DELTA); |
561 | 1 | assertEquals(m.getValue(1, 1), 8d, DELTA); |
562 | 1 | assertEquals(m.getValue(1, 2), 30d, DELTA); |
563 | } | |
564 | ||
565 | 1 | @Test(groups = "Functional") |
566 | public void testConstructor() | |
567 | { | |
568 | 1 | double[][] values = new double[][] { { 1, 2, 3 }, { 4, 5, 6 } }; |
569 | 1 | Matrix m = new Matrix(values); |
570 | 1 | assertEquals(m.getValue(0, 0), 1d, DELTA); |
571 | ||
572 | /* | |
573 | * verify the matrix has a copy of the original array | |
574 | */ | |
575 | 1 | assertNotSame(values[0], m.getRow(0)); |
576 | 1 | values[0][0] = -1d; |
577 | 1 | assertEquals(m.getValue(0, 0), 1d, DELTA); // unchanged |
578 | } | |
579 | ||
580 | 1 | @Test(groups = "Functional") |
581 | public void testEquals() | |
582 | { | |
583 | 1 | double[][] values = new double[][] { { 1, 2, 3 }, { 4, 5, 6 } }; |
584 | 1 | Matrix m1 = new Matrix(values); |
585 | 1 | double[][] values2 = new double[][] { { 1, 2, 3 }, { 4, 5, 6 } }; |
586 | 1 | Matrix m2 = new Matrix(values2); |
587 | ||
588 | 1 | double delta = 0.0001d; |
589 | 1 | assertTrue(m1.equals(m1, delta)); |
590 | 1 | assertTrue(m1.equals(m2, delta)); |
591 | 1 | assertTrue(m2.equals(m1, delta)); |
592 | ||
593 | 1 | double[][] values3 = new double[][] { { 1, 2, 3 }, { 4, 5, 7 } }; |
594 | 1 | m2 = new Matrix(values3); |
595 | 1 | assertFalse(m1.equals(m2, delta)); |
596 | 1 | assertFalse(m2.equals(m1, delta)); |
597 | ||
598 | // must be same shape | |
599 | 1 | values2 = new double[][] { { 1, 2, 3 } }; |
600 | 1 | m2 = new Matrix(values2); |
601 | 1 | assertFalse(m2.equals(m1, delta)); |
602 | ||
603 | 1 | assertFalse(m1.equals(null, delta)); |
604 | } | |
605 | } |