1 /*
2  * This file is part of ELKI:
3  * Environment for Developing KDD-Applications Supported by Index-Structures
4  *
5  * Copyright (C) 2018
6  * ELKI Development Team
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Affero General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Affero General Public License for more details.
17  *
18  * You should have received a copy of the GNU Affero General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 package de.lmu.ifi.dbs.elki.math.linearalgebra;
22 
23 import static de.lmu.ifi.dbs.elki.math.linearalgebra.VMath.*;
24 import static de.lmu.ifi.dbs.elki.math.linearalgebra.VMathOperationsTest.assertDimensionMismatch;
25 import static org.junit.Assert.*;
26 
27 import org.junit.Test;
28 
29 /**
30  * Class testing the methods of the {@link VMath} class,
31  * which provide mathematical operations and have two dimensional double arrays
32  * as input.
33  * <p>
34  * Two dimensional double arrays are interpreted as rows x columns matrixes.
35  *
36  * @author Merlin Dietrich
37  */
38 @SuppressWarnings("deprecation")
39 public class VMathMatrixTest {
40   /**
41    * A non symmetric 4 x 5 (rows x columns) matrix as test-data.
42    */
43   protected static final double[][] TESTMATRIX = { //
44       { 1, 2, 3, 4, 5 }, //
45       { 2, 3, 4, 5, 1 }, //
46       { 3, 4, 5, 1, 2 }, //
47       { 4, 5, 1, 2, 3 } };
48 
49   /**
50    * Testing the transposed method of VMath class.
51    */
52   @Test
testTransposed()53   public void testTransposed() {
54     final double[][] m1 = TESTMATRIX;
55     final double[][] res_case1 = { //
56         { m1[0][0], m1[1][0], m1[2][0], m1[3][0] }, //
57         { m1[0][1], m1[1][1], m1[2][1], m1[3][1] }, //
58         { m1[0][2], m1[1][2], m1[2][2], m1[3][2] }, //
59         { m1[0][3], m1[1][3], m1[2][3], m1[3][3] }, //
60         { m1[0][4], m1[1][4], m1[2][4], m1[3][4] } };
61     assertTrue(almostEquals(transpose(m1), res_case1));
62   }
63 
64   /**
65    * Testing the plus, plusEquals methods of VMath class.
66    */
67   @Test
testPlus()68   public void testPlus() {
69     final double[][] m1 = { //
70         { -14, -1, 0.01, 0.100000000000006100004 }, //
71         { 1.21, 0, 2, 0.500000000000006100004 }, //
72         { -14, 1, -3.42, 1.100000000000006100007 } };
73     final double[][] m2 = { //
74         { 7, 6, 0, -0.1000000000000069 }, //
75         { -1.21, -9, 2, 0.4000000000000069 }, //
76         { -3, 26, 1, 0 } };
77     final double s = 13;
78     final double[][] res_plus = { //
79         { m1[0][0] + m2[0][0], m1[0][1] + m2[0][1], m1[0][2] + m2[0][2], m1[0][3] + m2[0][3] }, //
80         { m1[1][0] + m2[1][0], m1[1][1] + m2[1][1], m1[1][2] + m2[1][2], m1[1][3] + m2[1][3] }, //
81         { m1[2][0] + m2[2][0], m1[2][1] + m2[2][1], m1[2][2] + m2[2][2], m1[2][3] + m2[2][3] } };
82     final double[][] res_plusTimes = { { m1[0][0] + s * m2[0][0], m1[0][1] + s * m2[0][1], m1[0][2] + s * m2[0][2], m1[0][3] + s * m2[0][3] }, //
83         { m1[1][0] + s * m2[1][0], m1[1][1] + s * m2[1][1], m1[1][2] + s * m2[1][2], m1[1][3] + s * m2[1][3] }, //
84         { m1[2][0] + s * m2[2][0], m1[2][1] + s * m2[2][1], m1[2][2] + s * m2[2][2], m1[2][3] + s * m2[2][3] } };
85 
86     // testing plus and plusEquals
87     assertTrue(almostEquals(res_plus, plus(m1, m2), 0.));
88     assertTrue(almostEquals(res_plus, plusEquals(copy(m1), m2), 0.));
89     // via minusTimes
90     assertTrue(almostEquals(res_plus, plusTimes(m1, m2, 1), 0.));
91 
92     // testing plusTimes and plusTimesEquals
93     assertTrue(almostEquals(res_plusTimes, plusTimes(m1, m2, s), 0.));
94     assertTrue(almostEquals(res_plusTimes, plusTimesEquals(copy(m1), m2, s), 0.));
95   }
96 
97   /**
98    * Testing the matrix minus, minusEquals methods of VMath class.
99    */
100   @Test
testMinus()101   public void testMinus() {
102     final double[][] m1 = { //
103         { 13, 0, 5 }, //
104         { -3, 1, 3 }, //
105         { 1, 2, -4.7 }, //
106         { -7, -2.21, 72 }, //
107         { -27, 12, 0 } };
108     final double[][] m2 = { //
109         { -13, 0.1, 0.0000000000000006 }, //
110         { 5, 42, 2 }, //
111         { 7, 3, 4.7 }, //
112         { -7, 4, 2 }, //
113         { 7, 6, -6 } };
114     final double s = 13;
115     final double[][] res_minus = { //
116         { m1[0][0] - m2[0][0], m1[0][1] - m2[0][1], m1[0][2] - m2[0][2] }, //
117         { m1[1][0] - m2[1][0], m1[1][1] - m2[1][1], m1[1][2] - m2[1][2] }, //
118         { m1[2][0] - m2[2][0], m1[2][1] - m2[2][1], m1[2][2] - m2[2][2] }, //
119         { m1[3][0] - m2[3][0], m1[3][1] - m2[3][1], m1[3][2] - m2[3][2] }, //
120         { m1[4][0] - m2[4][0], m1[4][1] - m2[4][1], m1[4][2] - m2[4][2] } };
121     final double[][] res_minusTimes = { //
122         { m1[0][0] - s * m2[0][0], m1[0][1] - s * m2[0][1], m1[0][2] - s * m2[0][2] }, //
123         { m1[1][0] - s * m2[1][0], m1[1][1] - s * m2[1][1], m1[1][2] - s * m2[1][2] }, //
124         { m1[2][0] - s * m2[2][0], m1[2][1] - s * m2[2][1], m1[2][2] - s * m2[2][2] }, //
125         { m1[3][0] - s * m2[3][0], m1[3][1] - s * m2[3][1], m1[3][2] - s * m2[3][2] }, //
126         { m1[4][0] - s * m2[4][0], m1[4][1] - s * m2[4][1], m1[4][2] - s * m2[4][2] } };
127 
128     // testing minus and minusEquals (Matrix - Matrix)
129     assertTrue(almostEquals(res_minus, minus(m1, m2), 0.));
130     assertTrue(almostEquals(res_minus, minusEquals(copy(m1), m2), 0.));
131     // via minusTimes
132     assertTrue(almostEquals(res_minus, minusTimes(m1, m2, 1), 0.));
133 
134     // testing minusTimes and minusTimesEquals
135     assertTrue(almostEquals(res_minusTimes, minusTimes(m1, m2, s), 0.));
136     assertTrue(almostEquals(res_minusTimes, minusTimesEquals(copy(m1), m2, s), 0.));
137     // via plusTimes (this is a test for plusTimes as well)
138     assertTrue(almostEquals(plusTimes(m1, m2, -s), minusTimes(m1, m2, s), 0.));
139   }
140 
141   /**
142    * Testing the matrix times scalar multiplication methods times, timesEquals
143    * of VMath class.
144    */
145   @Test
testMatrixScalarMultiplication()146   public void testMatrixScalarMultiplication() {
147     final double[][] m1 = TESTMATRIX;
148     final double s1 = 1. / 3;
149     final double[][] m1_times_one_third = { //
150         { s1 * m1[0][0], s1 * m1[0][1], s1 * m1[0][2], s1 * m1[0][3], s1 * m1[0][4] }, //
151         { s1 * m1[1][0], s1 * m1[1][1], s1 * m1[1][2], s1 * m1[1][3], s1 * m1[1][4] }, //
152         { s1 * m1[2][0], s1 * m1[2][1], s1 * m1[2][2], s1 * m1[2][3], s1 * m1[2][4] }, //
153         { s1 * m1[3][0], s1 * m1[3][1], s1 * m1[3][2], s1 * m1[3][3], s1 * m1[3][4] } };
154 
155     assertTrue(almostEquals(m1_times_one_third, times(m1, s1), 0.));
156     assertTrue(almostEquals(m1_times_one_third, timesEquals(m1, s1), 0.));
157 
158     // check if 0 works a clear
159     final double[][] m1_times_zero = new double[m1.length][m1[0].length];
160 
161     assertTrue(almostEquals(times(m1, 0), m1_times_zero));
162     assertTrue(almostEquals(timesEquals(m1, 0), m1_times_zero));
163 
164     // check if 1 works a identity
165     assertTrue(almostEquals(times(m1, 1), m1));
166     assertTrue(almostEquals(timesEquals(m1, 1), m1));
167   }
168 
169   /**
170    * Testing the matrix times matrix multiplications methods of VMath class.
171    *
172    * The following VMath methods are tested:<br>
173    * times, transposeTimesTranspose, timesTranspose, transposeTimes
174    */
175   @Test
testMatrixMatrixMultiplication()176   public void testMatrixMatrixMultiplication() {
177     // testing times and transposedTimestranspose
178     final double[][] m1 = { //
179         { 1.21, 2000 }, //
180         { 0, -1 }, //
181         { 7, 0 } };
182     final double[][] m2 = { //
183         { -1.21, 2000, 2 }, //
184         { -700, -2368, 4.3 } };
185     final double[][] res_times = { //
186         { m1[0][0] * m2[0][0] + m1[0][1] * m2[1][0], m1[0][0] * m2[0][1] + m1[0][1] * m2[1][1], m1[0][0] * m2[0][2] + m1[0][1] * m2[1][2] }, //
187         { m1[1][0] * m2[0][0] + m1[1][1] * m2[1][0], m1[1][0] * m2[0][1] + m1[1][1] * m2[1][1], m1[1][0] * m2[0][2] + m1[1][1] * m2[1][2] }, //
188         { m1[2][0] * m2[0][0] + m1[2][1] * m2[1][0], m1[2][0] * m2[0][1] + m1[2][1] * m2[1][1], m1[2][0] * m2[0][2] + m1[2][1] * m2[1][2] } };
189     final double[][] res_transTimesTrans = { //
190         { m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2], m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] }, //
191         { m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2], m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] } };
192 
193     assertTrue(almostEquals(times(m1, m2), res_times));
194     assertTrue(almostEquals(transposeTimesTranspose(m2, m1), transpose(res_times)));
195 
196     assertTrue(almostEquals(transposeTimesTranspose(m1, m2), res_transTimesTrans));
197     assertTrue(almostEquals(times(m2, m1), transpose(res_transTimesTrans)));
198 
199     // general testing and testing transposeTimes and timesTranspose
200     final double[][] m3 = TESTMATRIX;
201     final double[][] m4 = { //
202         { 5, 0, 4, 3, 1 }, //
203         { 9, -3, 2, 8, 8 }, //
204         { -4, -1, 4, 9, -9 }, //
205         { 1, 1, 7, 5, 7 } };
206     final double[][] m3_t = transpose(m3), m4_t = transpose(m4);
207 
208     // check times(Matrix, id) = Matrix = times(id, Matrix)
209     assertTrue(almostEquals(times(m3, unitMatrix(5)), m3));
210     assertTrue(almostEquals(times(unitMatrix(4), m3), m3));
211 
212     // check transposeTimesTranspose(Matrix, id) = transpose(Matrix) =
213     // transposeTimesTranspose(id, Matrix)
214     assertTrue(almostEquals(transposeTimesTranspose(m3, unitMatrix(4)), m3_t));
215     assertTrue(almostEquals(transposeTimesTranspose(unitMatrix(5), m3), m3_t));
216 
217     final double[][] m3_times_m4transposed = { //
218         { transposeTimes(m3[0], m4[0]), transposeTimes(m3[0], m4[1]), transposeTimes(m3[0], m4[2]), transposeTimes(m3[0], m4[3]) }, //
219         { transposeTimes(m3[1], m4[0]), transposeTimes(m3[1], m4[1]), transposeTimes(m3[1], m4[2]), transposeTimes(m3[1], m4[3]) }, //
220         { transposeTimes(m3[2], m4[0]), transposeTimes(m3[2], m4[1]), transposeTimes(m3[2], m4[2]), transposeTimes(m3[2], m4[3]) }, //
221         { transposeTimes(m3[3], m4[0]), transposeTimes(m3[3], m4[1]), transposeTimes(m3[3], m4[2]), transposeTimes(m3[3], m4[3]) } };
222 
223     // testing timesTranspose without not using a matrix methods times
224     assertTrue(almostEquals(timesTranspose(m3, m4), m3_times_m4transposed));
225 
226     // testing timesTranspose without not using a vector method transposeTimes
227     // this is at the same time a test for the times method assuming the test
228     // before succeeded.
229     assertTrue(almostEquals(timesTranspose(m3, m4), times(m3, m4_t)));
230     // and the following analog a test for the transposeTimesTranspose method
231     assertTrue(almostEquals(timesTranspose(m3, m4), transposeTimesTranspose(m3_t, m4)));
232 
233     final double[][] m3transposed_times_m4 = { //
234         { transposeTimes(m3_t[0], m4_t[0]), transposeTimes(m3_t[0], m4_t[1]), transposeTimes(m3_t[0], m4_t[2]), transposeTimes(m3_t[0], m4_t[3]), transposeTimes(m3_t[0], m4_t[4]) }, //
235         { transposeTimes(m3_t[1], m4_t[0]), transposeTimes(m3_t[1], m4_t[1]), transposeTimes(m3_t[1], m4_t[2]), transposeTimes(m3_t[1], m4_t[3]), transposeTimes(m3_t[1], m4_t[4]) }, //
236         { transposeTimes(m3_t[2], m4_t[0]), transposeTimes(m3_t[2], m4_t[1]), transposeTimes(m3_t[2], m4_t[2]), transposeTimes(m3_t[2], m4_t[3]), transposeTimes(m3_t[2], m4_t[4]) }, //
237         { transposeTimes(m3_t[3], m4_t[0]), transposeTimes(m3_t[3], m4_t[1]), transposeTimes(m3_t[3], m4_t[2]), transposeTimes(m3_t[3], m4_t[3]), transposeTimes(m3_t[3], m4_t[4]) }, //
238         { transposeTimes(m3_t[4], m4_t[0]), transposeTimes(m3_t[4], m4_t[1]), transposeTimes(m3_t[4], m4_t[2]), transposeTimes(m3_t[4], m4_t[3]), transposeTimes(m3_t[4], m4_t[4]) } };
239 
240     // testing transposeTimes without not using a matrix methods times
241     // without transpose and times
242     assertTrue(almostEquals(transposeTimes(m3, m4), m3transposed_times_m4));
243 
244     // testing transposeTimes without using a vector method timesTransposed
245     // this is as well a test for the times method assuming the test before
246     // succeeded.
247     assertTrue(almostEquals(transposeTimes(m3, m4), times(m3_t, m4)));
248     // and the following analog a test for the transposeTimesTranspose method
249     assertTrue(almostEquals(transposeTimes(m3, m4), transposeTimesTranspose(m3, m4_t)));
250   }
251 
252   /**
253    * Testing the Matrix times Vector multiplications methods of VMath class.
254    *
255    * The following VMath methods are tested:<br>
256    * times(matrix, vector), times(vector, matrix), transposeTimes(matrix,
257    * vector), transposeTimes(vector, matrix),
258    * timesTranspose(vector, matrix), transposeTimesTimes(vector, matrix, vector)
259    */
260   @Test
testMatrixVectorMultiplication()261   public void testMatrixVectorMultiplication() {
262     final double[] v1 = { 1.21, 2 }, v2 = { 3, 0.5, -3 };
263     final double[][] m1 = { //
264         { 1.21, 2000 }, //
265         { 0, -1 }, //
266         { 7, 0 } };
267     final double[] res_times = { m1[0][0] * v1[0] + m1[0][1] * v1[1], m1[1][0] * v1[0] + m1[1][1] * v1[1], m1[2][0] * v1[0] + m1[2][1] * v1[1], };
268     final double[] res_transposeTimes = { m1[0][0] * v2[0] + m1[1][0] * v2[1] + m1[2][0] * v2[2], m1[0][1] * v2[0] + m1[1][1] * v2[1] + m1[2][1] * v2[2] };
269     final double res_transposeTimesTimes = (m1[0][0] * v2[0] + m1[1][0] * v2[1] + m1[2][0] * v2[2]) * v1[0] + (m1[0][1] * v2[0] + m1[1][1] * v2[1] + m1[2][1] * v2[2]) * v1[1];
270 
271     // testing times(m1, v2)
272     assertArrayEquals(res_times, times(m1, v1), 0.);
273     assertArrayEquals(transpose(m1)[0], times(m1, unitVector(2, 0)), 0.);
274     assertArrayEquals(transpose(m1)[1], times(m1, unitVector(2, 1)), 0.);
275 
276     // testing transposeTimes(m1, v2);
277     assertArrayEquals(res_transposeTimes, transposeTimes(m1, v2), 0.);
278     assertArrayEquals(m1[0], transposeTimes(m1, unitVector(3, 0)), 0.);
279     assertArrayEquals(m1[1], transposeTimes(m1, unitVector(3, 1)), 0.);
280     assertArrayEquals(m1[2], transposeTimes(m1, unitVector(3, 2)), 0.);
281 
282     // testing transposeTimesTimes(a, B, c);
283     assertEquals(res_transposeTimesTimes, transposeTimesTimes(v2, m1, v1), 0.);
284     assertEquals(transposeTimes(v2, times(m1, v1)), transposeTimesTimes(v2, m1, v1), 0.);
285     assertEquals(times(transposeTimes(v2, m1), v1)[0], transposeTimesTimes(v2, m1, v1), 0.);
286 
287     // testing transposedTimes(vector, Matrix) via
288     // transpose(transposeTimes(matrix, vector))
289     assertTrue(VMath.equals(transposeTimes(unitVector(3, 0), m1), transpose(transposeTimes(m1, unitVector(3, 0)))));
290     assertTrue(VMath.equals(transposeTimes(unitVector(3, 1), m1), transpose(transposeTimes(m1, unitVector(3, 1)))));
291     assertTrue(VMath.equals(transposeTimes(unitVector(3, 2), m1), transpose(transposeTimes(m1, unitVector(3, 2)))));
292   }
293 
294   /**
295    * Testing the timesTranspose(vector, matrix), times(vector, matrix)
296    * multiplication methods of VMath class,
297    * where the matrix as two dimensional double array actually need to be a
298    * vector.
299    */
300   @Test
testVectorVectorMultiplication()301   public void testVectorVectorMultiplication() {
302     final double[] v3 = { 1, 2, -7 };
303     final double[] v4 = { -5, 1, 3, -4 };
304     final double[][] m2 = { v4 };
305     final double[][] m2_t = { { v4[0] }, { v4[1] }, { v4[2] }, { v4[3] } };
306     final double[][] res = { //
307         { v3[0] * v4[0], v3[0] * v4[1], v3[0] * v4[2], v3[0] * v4[3] }, //
308         { v3[1] * v4[0], v3[1] * v4[1], v3[1] * v4[2], v3[1] * v4[3] }, //
309         { v3[2] * v4[0], v3[2] * v4[1], v3[2] * v4[2], v3[2] * v4[3] } };
310 
311     // testing times(vector, matrix)
312     assertTrue(almostEquals(times(v3, m2), res));
313     // via timesTranspose(vector,vector)
314     assertTrue(almostEquals(times(v3, m2), timesTranspose(v3, v4)));
315 
316     // testing timesTranspose(vector, matrix)
317     assertTrue(almostEquals(timesTranspose(v3, m2_t), res));
318     // via timesTranspose(vector,vector)
319     assertTrue(almostEquals(timesTranspose(v3, m2_t), timesTranspose(v3, v4)));
320   }
321 
322   /**
323    * Testing the unitMatrix and the identity method of VMath class.
324    */
325   @Test
testUnitMatrix()326   public void testUnitMatrix() {
327     // test unitMatrix(dim) and unitMatrix(dim) equals identity(dim, dim)
328     final double[][] m_unit = { { 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0 }, { 0, 0, 1, 0, 0 }, { 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 1 } };
329     assertTrue(VMath.equals(unitMatrix(5), m_unit));
330     assertTrue(VMath.equals(identity(5, 5), m_unit));
331 
332     // test identity with dimensions 3x5 and 5x3
333     final double[][] m_identity3x5 = { { 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0 }, { 0, 0, 1, 0, 0 } };
334     assertTrue(VMath.equals(identity(3, 5), m_identity3x5));
335     assertTrue(VMath.equals(identity(5, 3), transpose(m_identity3x5)));
336   }
337 
338   @Test
testFrobenius()339   public void testFrobenius() {
340     final double[][] m = identity(4, 6);
341     assertEquals(2, normF(m), 0.);
342     m[0][5] = 5;
343     assertEquals(Math.sqrt(29), normF(m), 0.);
344   }
345 
346   /**
347    * Testing that the *Equals methods tested in this class
348    * class work in place and that other methods tested
349    * create a new instance.
350    *
351    * Methods where the class of the instance
352    * returned differs form class of the input are reasonably omitted
353    * when testing reference.
354    */
355   @Test
testReference()356   public void testReference() {
357     final double[][] m1 = { { 42 } };
358     final double[] inner = { 42 };
359     final double[][] m2 = { inner };
360 
361     // Ensure the compiler did not optimize away this test.
362     assertNotSame(m1[0], m2[0]);
363 
364     // testing the methods as in testInverse
365     assertNotSame(m1, inverse(m1));
366 
367     // testing the methods as in testMatrixMatrixMultiplication
368     assertNotSame(m1, times(m1, m1));
369 
370     assertNotSame(m1, transposeTimesTranspose(m1, m1));
371 
372     assertNotSame(m1, timesTranspose(m1, m1));
373 
374     assertNotSame(m1, transposeTimes(m1, m1));
375 
376     // testing the methods as in testMatrixScalarMultiplication
377     final double s1 = 3.14;
378     assertNotSame(m1, times(m1, s1));
379     assertSame(m1, timesEquals(m1, s1));
380 
381     // testing the methods as in testTranspose
382     assertNotSame(m1, transpose(m1));
383 
384     // testing the methods as in testMatrixVectorMultiplication
385     final double[] v1 = { 3.14 };
386     assertNotSame(m1, times(v1, m1));
387     assertNotSame(m1, times(m1, v1));
388 
389     assertNotSame(m1, transposeTimes(m1, v1));
390     assertNotSame(m1, transposeTimes(v1, m1));
391 
392     assertNotSame(m1, timesTranspose(v1, m1));
393 
394     // testing the methods as in testMinus
395     assertNotSame(m1, minus(m1, m2));
396     assertSame(m1, minusEquals(m1, m2));
397 
398     assertNotSame(m1, minusTimes(m1, m1, s1));
399     assertSame(m1, minusTimesEquals(m1, m1, s1));
400 
401     // testing the methods as in testPlus
402     assertNotSame(m1, plus(m1, m2));
403     assertSame(m1, plusEquals(m1, m2));
404 
405     assertNotSame(m1, plusTimes(m1, m1, s1));
406     assertSame(m1, plusTimesEquals(m1, m1, s1));
407 
408     // testing the methods as in testTraspose
409     assertNotSame(m1, transpose(m1));
410   }
411 
412   /**
413    * Testing that correct error is raised when dimension of the input data
414    * mismatch the needs of the method.
415    * Methods where no error is to be raised are omitted.
416    * <p>
417    * See {@link VMathOperationsTest#assertDimensionMismatch} for details.
418    */
419   @Test
testDimensionMismatch()420   public void testDimensionMismatch() {
421     // testing the appendColums method
422     assertDimensionMismatch("m.getRowDimension() != column.getRowDimension()", () -> appendColumns(identity(3, 2), identity(2, 2)));
423 
424     // testing the methods as in testMatrixMatrixMultiplication
425     assertDimensionMismatch(ERR_MATRIX_INNERDIM, () -> times(unitMatrix(3), identity(2, 3)));
426     assertDimensionMismatch(ERR_MATRIX_INNERDIM, () -> transposeTimesTranspose(unitMatrix(3), identity(3, 2)));
427     assertDimensionMismatch(ERR_MATRIX_INNERDIM, () -> timesTranspose(unitMatrix(3), identity(3, 2)));
428     assertDimensionMismatch(ERR_MATRIX_INNERDIM, () -> transposeTimes(unitMatrix(3), identity(2, 3)));
429 
430     // testing the methods as in testMatrixVectorMultiplication
431     // vector length and number of rows in matrix differ
432     assertDimensionMismatch(ERR_MATRIX_INNERDIM, () -> times(identity(2, 3), unitVector(2, 0)));
433 
434     // vector length and number of columns in matrix differ
435     assertDimensionMismatch(ERR_MATRIX_INNERDIM, () -> transposeTimes(identity(2, 3), unitVector(3, 0)));
436 
437     // first vector has wrong length
438     assertDimensionMismatch(ERR_MATRIX_INNERDIM, () -> transposeTimesTimes(unitVector(3, 0), identity(2, 3), unitVector(3, 0)));
439     // second vector has wrong length
440     assertDimensionMismatch(ERR_MATRIX_INNERDIM, () -> transposeTimesTimes(unitVector(2, 0), identity(2, 3), unitVector(2, 0)));
441 
442     // matrix has more than one row
443     assertDimensionMismatch(ERR_MATRIX_INNERDIM, () -> times(unitVector(3, 0), identity(2, 3)));
444 
445     // matrix has more than one column
446     assertDimensionMismatch(ERR_MATRIX_INNERDIM, () -> timesTranspose(unitVector(3, 0), identity(3, 2)));
447 
448     // vector length and number of rows in matrix differ
449     assertDimensionMismatch(ERR_MATRIX_INNERDIM, () -> transposeTimes(unitVector(3, 0), identity(2, 3)));
450 
451     // testing the methods as in testMinus
452     assertDimensionMismatch(ERR_MATRIX_DIMENSIONS, () -> minus(identity(3, 3), identity(2, 3)));
453     assertDimensionMismatch(ERR_MATRIX_DIMENSIONS, () -> minusEquals(identity(2, 2), identity(2, 3)));
454 
455     assertDimensionMismatch(ERR_MATRIX_DIMENSIONS, () -> minusTimes(identity(3, 3), identity(2, 3), 1));
456     assertDimensionMismatch(ERR_MATRIX_DIMENSIONS, () -> minusTimesEquals(identity(2, 2), identity(2, 3), 1));
457 
458     // testing the methods as in testPlus
459     assertDimensionMismatch(ERR_MATRIX_DIMENSIONS, () -> plus(identity(3, 3), identity(2, 3)));
460     assertDimensionMismatch(ERR_MATRIX_DIMENSIONS, () -> plusEquals(identity(2, 2), identity(2, 3)));
461 
462     assertDimensionMismatch(ERR_MATRIX_DIMENSIONS, () -> plusTimes(identity(3, 3), identity(2, 3), 1));
463     assertDimensionMismatch(ERR_MATRIX_DIMENSIONS, () -> plusTimesEquals(identity(2, 2), identity(2, 3), 1));
464 
465     // testSolve, testTraspose, testUnitMatrix are tested in separate classes
466   }
467 }
468