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 import de.lmu.ifi.dbs.elki.math.MathUtil;
30 
31 /**
32  * Class testing the methods of the {@link VMath} class, which provide
33  * mathematical operations and have
34  * one dimensional double arrays as input.
35  *
36  * One dimensional double arrays are interpreted column vectors.
37  *
38  * @author Merlin Dietrich
39  */
40 public final class VMathVectorTest {
41   /**
42    * A vector of length 5 as test-data.
43    */
44   protected static final double[] TESTVEC = { 2, 3, 5, 7, 9 };
45 
46   /**
47    * Testing the vector times scalar method of VMath class.
48    */
49   @Test
testTimes()50   public void testTimes() {
51     final double[] v1 = { 1, 3, 9, 7 };
52     final double s_case1 = 5;
53     final double s_case2 = 1. / 3;
54     final double s_case3 = 0.100000000000006100004;
55 
56     final double[] res_case1 = { v1[0] * s_case1, v1[1] * s_case1, v1[2] * s_case1, v1[3] * s_case1 };
57     final double[] res_case2 = { v1[0] * s_case2, v1[1] * s_case2, v1[2] * s_case2, v1[3] * s_case2 };
58     final double[] res_case3 = { v1[0] * s_case3, v1[1] * s_case3, v1[2] * s_case3, v1[3] * s_case3 };
59 
60     // test the three cases
61     assertArrayEquals(res_case1, times(v1, s_case1), 0.);
62     assertArrayEquals(res_case2, times(v1, s_case2), 0.);
63     assertArrayEquals(res_case3, times(v1, s_case3), 0.);
64   }
65 
66   /**
67    * Testing VMath methods, which operate as addition on vectors.
68    * <p>
69    * The following VMath methods are tested:<br>
70    * plus,plusEquals; timesPlus, timesPlusEquals;
71    * plusTimes, plusTimesEquals, timesPlus, timesPlusEquals;
72    * timesPlustimes, timesPlustimesEquals
73    */
74   @Test
testPlus()75   public void testPlus() {
76     /*
77      * test-data I:
78      * Four dimensional test vectors, Near 0 numerical loss of precision in ResultData res* and
79      * mixed positive and negative numbers.
80      */
81     final double[] v1_I = { -14, 1, 2, 0.100000000000006100004 };
82     final double[] v2_I = { 7, 6, 2, -0.1000000000000069 };
83     final double s_I = 13, s1_I = 2, s2_I = -3;
84 
85     final double[] res_plus_I = { v1_I[0] + v2_I[0], v1_I[1] + v2_I[1], v1_I[2] + v2_I[2], v1_I[3] + v2_I[3] };
86     final double[] res_plus_scal_I = { v1_I[0] + s_I, v1_I[1] + s_I, v1_I[2] + s_I, v1_I[3] + s_I };
87     final double[] res_timesPlus_I = { s1_I * v1_I[0] + v2_I[0], s1_I * v1_I[1] + v2_I[1], s1_I * v1_I[2] + v2_I[2], s1_I * v1_I[3] + v2_I[3] };
88     final double[] res_plusTimes_I = { v1_I[0] + s2_I * v2_I[0], v1_I[1] + s2_I * v2_I[1], v1_I[2] + s2_I * v2_I[2], v1_I[3] + s2_I * v2_I[3] };
89     final double[] res_timesPlustimes_I = { s1_I * v1_I[0] + s2_I * v2_I[0], s1_I * v1_I[1] + s2_I * v2_I[1], s1_I * v1_I[2] + s2_I * v2_I[2], s1_I * v1_I[3] + s2_I * v2_I[3] };
90 
91     // testing plus and plusEquals
92     assertArrayEquals(res_plus_I, plus(v1_I, v2_I), 0.);
93     assertArrayEquals(res_plus_I, plusEquals(copy(v1_I), v2_I), 0.);
94 
95     // testing plus and plusEquals
96     assertArrayEquals(res_plus_scal_I, plus(v1_I, s_I), 0.);
97     assertArrayEquals(res_plus_scal_I, plusEquals(copy(v1_I), s_I), 0.);
98 
99     // testing timesPlus and timesPlusEquals
100     assertArrayEquals(res_timesPlus_I, timesPlus(v1_I, s1_I, v2_I), 0.);
101     assertArrayEquals(res_timesPlus_I, timesPlusEquals(copy(v1_I), s1_I, v2_I), 0.);
102 
103     // testing plusTimes and plusTimesEquals
104     assertArrayEquals(res_plusTimes_I, plusTimes(v1_I, v2_I, s2_I), 0.);
105     assertArrayEquals(res_plusTimes_I, plusTimesEquals(copy(v1_I), v2_I, s2_I), 0.);
106 
107     // testing timesPlustimes and timesPlustimesEquals
108     assertArrayEquals(res_timesPlustimes_I, timesPlusTimes(v1_I, s1_I, v2_I, s2_I), 0.);
109     assertArrayEquals(res_timesPlustimes_I, timesPlusTimesEquals(copy(v1_I), s1_I, v2_I, s2_I), 0);
110 
111     /*
112      * test-data II:
113      * Three dimensional test vectors of type double with 5 decimal places as
114      * mantissa. Numbers are strictly positive.
115      */
116     final double delta = 1E-10;
117     final double[] v1_II = { 0.17825, 32.546, 2958.3 };
118     final double[] v2_II = { 0.82175, 67.454, 7041.7 };
119 
120     final double s_II = 0.92175, s1_II = 1.5, s2_II = 0.5;
121 
122     final double[] res_plus_II = { v1_II[0] + v2_II[0], v1_II[1] + v2_II[1], v1_II[2] + v2_II[2] };
123     final double[] res_plus_scal_II = { v1_II[0] + s_II, v1_II[1] + s_II, v1_II[2] + s_II };
124     final double[] res_timesPlus_II = { s1_II * v1_II[0] + v2_II[0], s1_II * v1_II[1] + v2_II[1], s1_II * v1_II[2] + v2_II[2] };
125     final double[] res_plusTimes_II = { v1_II[0] + s2_II * v2_II[0], v1_II[1] + s2_II * v2_II[1], v1_II[2] + s2_II * v2_II[2] };
126     final double[] res_timesPlustimes_II = { s1_II * v1_II[0] + s2_II * v2_II[0], s1_II * v1_II[1] + s2_II * v2_II[1], s1_II * v1_II[2] + s2_II * v2_II[2] };
127 
128     // testing plus and plusEquals (Vector + Vector)
129     assertArrayEquals(res_plus_II, plus(v1_II, v2_II), delta);
130     assertArrayEquals(res_plus_II, plusEquals(copy(v1_II), v2_II), delta);
131 
132     // testingplus() and plusEquals (Vector + Skalar)
133     assertArrayEquals(res_plus_scal_II, plus(v1_II, s_II), delta);
134     assertArrayEquals(res_plus_scal_II, plusEquals(copy(v1_II), s_II), delta);
135 
136     // testing timesPlus() and timesPlusEquals()
137     assertArrayEquals(res_timesPlus_II, timesPlus(v1_II, s1_II, v2_II), delta);
138     assertArrayEquals(res_timesPlus_II, timesPlusEquals(copy(v1_II), s1_II, v2_II), delta);
139 
140     // testing plusTimes() and plusTimesEquals()
141     assertArrayEquals(res_plusTimes_II, plusTimes(v1_II, v2_II, s2_II), delta);
142     assertArrayEquals(res_plusTimes_II, plusTimesEquals(copy(v1_II), v2_II, s2_II), delta);
143 
144     // testing timesPlustimes() and timesPlustimesEquals()
145     assertArrayEquals(res_timesPlustimes_II, timesPlusTimes(v1_II, s1_II, v2_II, s2_II), delta);
146     assertArrayEquals(res_timesPlustimes_II, timesPlusTimesEquals(copy(v1_II), s1_II, v2_II, s2_II), delta);
147 
148     /*
149      * general testing
150      */
151     final double[] v5 = { 1, 2, 3 }, v6 = { 4, 5, 6 };
152     final double s5 = 2, s6 = 3;
153 
154     // consistency check to minus method
155     assertArrayEquals(minus(v5, times(v6, -1)), plus(v5, v6), 0.);
156     // consistency check within the plus methods
157     assertArrayEquals(plus(v5, times(v6, s6)), plusTimes(v5, v6, s6), 0.);
158     assertArrayEquals(plus(times(v5, s5), v6), timesPlus(v5, s5, v6), 0.);
159     assertArrayEquals(plus(times(v5, s5), times(v6, s6)), timesPlusTimes(v5, s5, v6, s6), 0.);
160   }
161 
162   /**
163    * Testing VMath methods, which operate as subtraction on vectors.
164    * <p>
165    * The following VMath methods are tested:<br>
166    * minus, minusEquals, timesMinus, timesMinusEquals;
167    * minusTimes, minusTimesEquals, timesMinus, timesMinusEquals;
168    * timesMinustimes, timesMinustimesEquals
169    */
170   @Test
testMinus()171   public void testMinus() {
172     // test case I
173     final double[] v1 = { -14, 1, 2, 0.100000000000006100004 };
174     final double[] v2 = { 7, 6, 2, -0.1000000000000069 };
175 
176     final double s0 = 13, s1 = 2, s2 = -3;
177     final double[] res_minus_I = { v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2], v1[3] - v2[3] };
178     final double[] res_minus_scal_I = { v1[0] - s0, v1[1] - s0, v1[2] - s0, v1[3] - s0 };
179     final double[] res_timesMinus_I = { s1 * v1[0] - v2[0], s1 * v1[1] - v2[1], s1 * v1[2] - v2[2], s1 * v1[3] - v2[3] };
180     final double[] res_minusTimes_I = { v1[0] - s2 * v2[0], v1[1] - s2 * v2[1], v1[2] - s2 * v2[2], v1[3] - s2 * v2[3] };
181     final double[] res_timesMinustimes_I = { s1 * v1[0] - s2 * v2[0], s1 * v1[1] - s2 * v2[1], s1 * v1[2] - s2 * v2[2], s1 * v1[3] - s2 * v2[3] };
182 
183     // minus and minusEquals
184     assertArrayEquals(res_minus_I, minus(v1, v2), 0.);
185     assertArrayEquals(res_minus_I, minusEquals(copy(v1), v2), 0.);
186 
187     // minus and minusEquals
188     assertArrayEquals(res_minus_scal_I, minus(v1, s0), 0.);
189     assertArrayEquals(res_minus_scal_I, minusEquals(copy(v1), s0), 0.);
190 
191     // timesMinus and timesMinusEquals
192     assertArrayEquals(res_timesMinus_I, timesMinus(v1, s1, v2), 0.);
193     assertArrayEquals(res_timesMinus_I, timesMinusEquals(copy(v1), s1, v2), 0.);
194 
195     // minusTimes and minusTimesEquals
196     assertArrayEquals(res_minusTimes_I, minusTimes(v1, v2, s2), 0.);
197     assertArrayEquals(res_minusTimes_I, minusTimesEquals(copy(v1), v2, s2), 0.);
198 
199     // timesMinustimes and timesMinustimesEquals
200     assertArrayEquals(res_timesMinustimes_I, timesMinusTimes(v1, s1, v2, s2), 0.);
201     assertArrayEquals(res_timesMinustimes_I, timesMinusTimesEquals(copy(v1), s1, v2, s2), 0);
202 
203     // test case II
204     final double delta = 1E-10;
205     final double[] v3 = { 0.17825, 32.546, 2958.3 };
206     final double[] v4 = { 0.82175, 67.454, 7041.7 };
207 
208     final double s00 = 0.92175, s3 = 1.5, s4 = 0.5;
209 
210     final double[] res_minus_II = { v3[0] - v4[0], v3[1] - v4[1], v3[2] - v4[2] };
211     final double[] res_minus_scal_II = { v3[0] - s00, v3[1] - s00, v3[2] - s00 };
212     final double[] res_timesMinus_II = { s3 * v3[0] - v4[0], s3 * v3[1] - v4[1], s3 * v3[2] - v4[2] };
213     final double[] res_minusTimes_II = { v3[0] - s4 * v4[0], v3[1] - s4 * v4[1], v3[2] - s4 * v4[2] };
214     final double[] res_timesMinustimes_II = { s3 * v3[0] - s4 * v4[0], s3 * v3[1] - s4 * v4[1], s3 * v3[2] - s4 * v4[2] };
215 
216     // minus and minusEquals
217     assertArrayEquals(res_minus_II, minus(v3, v4), delta);
218     assertArrayEquals(res_minus_II, minusEquals(copy(v3), v4), delta);
219 
220     // minus and minusEquals
221     assertArrayEquals(res_minus_scal_II, minus(v3, s00), delta);
222     assertArrayEquals(res_minus_scal_II, minusEquals(copy(v3), s00), delta);
223 
224     // timesMinus and timesMinusEquals
225     assertArrayEquals(res_timesMinus_II, timesMinus(v3, s3, v4), delta);
226     assertArrayEquals(res_timesMinus_II, timesMinusEquals(copy(v3), s3, v4), delta);
227 
228     // minusTimes and minusTimesEquals
229     assertArrayEquals(res_minusTimes_II, minusTimes(v3, v4, s4), delta);
230     assertArrayEquals(res_minusTimes_II, minusTimesEquals(copy(v3), v4, s4), delta);
231 
232     // timesMinustimes and timesMinustimesEquals
233     assertArrayEquals(res_timesMinustimes_II, timesMinusTimes(v3, s3, v4, s4), delta);
234     assertArrayEquals(res_timesMinustimes_II, timesMinusTimesEquals(copy(v3), s3, v4, s4), delta);
235 
236     // general testing
237     final double[] v5 = { 1, 2, 3 };
238     final double[] v6 = { 4, 5, 6 };
239     final double s5 = 2, s6 = 3;
240 
241     // checking that vector - same_vector is zero
242     assertArrayEquals(new double[] { 0, 0, 0, }, minus(v5, v5), 0.);
243     // consistency check to plus methods
244     assertArrayEquals(plus(v5, times(v6, -1)), minus(v5, v6), 0.);
245     // consistency check within the minus methods
246     assertArrayEquals(minus(v5, times(v6, s6)), minusTimes(v5, v6, s6), 0.);
247     assertArrayEquals(minus(times(v5, s5), v6), timesMinus(v5, s5, v6), 0.);
248     assertArrayEquals(minus(times(v5, s5), times(v6, s6)), timesMinusTimes(v5, s5, v6, s6), 0.);
249   }
250 
251   /**
252    * Testing scalarProduct and transposeTimes methods of the VMath class.
253    */
254   @Test
testScalarProduct()255   public void testScalarProduct() {
256     // testing scalarProduct and transposeTimes return the same result
257     final double[] v1 = { 1.21, 3, 7, -2 };
258     final double[] v2 = { 3.5, -1, 4, -7 };
259     final double res = v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] + v1[3] * v2[3];
260 
261     assertEquals(transposeTimes(v1, v2), scalarProduct(v1, v2), 0.);
262     assertEquals(res, scalarProduct(v1, v2), 0.);
263 
264     // testing scalarProduct and transposeTimes via squareSum
265     assertEquals(squareSum(v1), scalarProduct(v1, v1), 0.);
266     assertEquals(transposeTimes(v1, v1), scalarProduct(v1, v1), 0.);
267 
268     assertEquals(squareSum(v2), transposeTimes(v2, v2), 0.);
269     assertEquals(transposeTimes(v2, v2), scalarProduct(v2, v2), 0.);
270   }
271 
272   /**
273    * Testing the timesTranspose(vector, vector) method of {@link VMath} class.
274    */
275   @Test
testTimesTranspose()276   public void testTimesTranspose() {
277     final double[] v1 = { 1.21, 3, 7, -2 }, v2 = { 3.5, -1, 4, -7 };
278     final double[][] res = { //
279         { v1[0] * v2[0], v1[0] * v2[1], v1[0] * v2[2], v1[0] * v2[3] }, //
280         { v1[1] * v2[0], v1[1] * v2[1], v1[1] * v2[2], v1[1] * v2[3] }, //
281         { v1[2] * v2[0], v1[2] * v2[1], v1[2] * v2[2], v1[2] * v2[3] }, //
282         { v1[3] * v2[0], v1[3] * v2[1], v1[3] * v2[2], v1[3] * v2[3] } };
283     assertTrue(VMath.equals(timesTranspose(v1, v2), res));
284 
285     // testing timesTranspose(vector, vector) via times(matrix, matrix)
286     // because times(vector) returns a matrix. This is at the same time a test
287     // for transpose if timesTranspose is correct.
288     final double[][] m1 = transpose(transpose(TESTVEC));
289     final double[][] m2 = transpose(TESTVEC);
290     assertTrue(VMath.equals(timesTranspose(TESTVEC, TESTVEC), times(m1, m2)));
291   }
292 
293   /**
294    * Testing the normalizeVector) and normalizeEquals(Vector) methods of the
295    * {@link VMath} class.
296    */
297   @Test
testNormalize()298   public void testNormalize() {
299     final double[] v1 = copy(TESTVEC), v1_copy = copy(v1);
300     final double[] v1_normal = normalize(v1);
301 
302     // Test that both methods return a vector with length 1.
303     // That more methods ensure the result we use squareSum instead of
304     // euclideanLength here
305     assertEquals(1, squareSum(v1_normal), 0.);
306     assertEquals(1, squareSum(normalizeEquals(v1)), 0.);
307 
308     // Check that both methods return the same Vector
309     assertArrayEquals(v1_normal, v1, 0.);
310 
311     // Check that the normalize Vector times the euclidean length of the
312     // original Vector equals the original vector
313     assertArrayEquals(v1_copy, times(v1_normal, euclideanLength(v1_copy)), 1e-15);
314   }
315 
316   /**
317    * Testing the cosine angle(Vector, Vector) methods of the VMath class.
318    */
319   @Test
testAngle()320   public void testAngle() {
321     // test case I
322     final double[] v1_I = { 1, 0 }, v2_I = { 1, 1 }, v3_I = { 2, 0, 0 };
323     assertEquals(MathUtil.SQRTHALF, angle(v2_I, v1_I), 0.);
324     assertEquals(MathUtil.SQRTHALF, angle(v1_I, v2_I), 0.);
325     assertEquals(1., angle(v3_I, v1_I), 0.);
326     assertEquals(1., angle(v1_I, v3_I), 0.);
327 
328     // set the origin, no change of data needed
329     final double[] origin_I = { 0, 1 };
330     assertEquals(MathUtil.SQRTHALF, angle(v2_I, v1_I, origin_I), 0.);
331     assertEquals(MathUtil.SQRTHALF, angle(v1_I, v2_I, origin_I), 0.);
332     assertEquals(Math.sqrt(0.8), angle(v3_I, v2_I, origin_I), 0.);
333     assertEquals(Math.sqrt(0.8), angle(v2_I, v3_I, origin_I), 0.);
334 
335     // test case II
336     final double[] v1_II = { 1, 0 }, v2_II = { 1, Math.tan(Math.PI / 3) };
337     assertEquals(Math.sqrt(.25), angle(v2_II, v1_II), 1e-15);
338     assertEquals(Math.sqrt(.25), angle(v1_II, v2_II), 1e-15);
339 
340     // change the origin
341     final double[] v3_II = { 2, 3 }, v4_II = { 2, 3 + Math.tan(Math.PI / 3) };
342     final double[] origin_II = { 1, 3 };
343     assertEquals(Math.sqrt(.25), angle(v3_II, v4_II, origin_II), 1e-15);
344     assertEquals(Math.sqrt(.25), angle(v4_II, v3_II, origin_II), 1e-15);
345   }
346 
347   /**
348    * Testing the summation methods and the euclidienLength method of VMath
349    * class.
350    */
351   @Test
testSummation()352   public void testSummation() {
353     // testing sum
354     final double[] v = { 1.21, -3, 2, 3.2, -5, 1 };
355     final double res_vsum = v[0] + v[1] + v[2] + v[3] + v[4] + v[5];
356     assertEquals(res_vsum, sum(v), 0.);
357 
358     assertEquals(1, sum(unitVector(3, 1)), 0.);
359 
360     final double[] v1 = { 0.1234512345123456, -0.123451234512345 };
361     assertEquals(0, sum(v1), 1e-15);
362 
363     // testing squareSum
364     final double res_vsumsqare = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3] + v[4] * v[4] + v[5] * v[5];
365     assertEquals(res_vsumsqare, squareSum(v), 0.);
366     assertEquals(1, squareSum(unitVector(20, 10)), 0.);
367     // via transposeTimes and scalarProduct
368     assertEquals(transposeTimes(v, v), squareSum(v), 0.);
369 
370     // testing euclideanLength
371     final double res_veuclid = Math.sqrt(res_vsumsqare);
372     assertEquals(res_veuclid, euclideanLength(v), 0.);
373     assertEquals(1, euclideanLength(unitVector(3, 1)), 0.);
374   }
375 
376   /**
377    * Testing the transpose(vector) method of VMath class.
378    */
379   @Test
testTransposed()380   public void testTransposed() {
381     final double[] v1 = TESTVEC;
382     final double[][] v1_t = { v1 };
383     assertTrue(VMath.equals(transpose(v1), v1_t));
384 
385     final double[] v2 = { 4, 5, 6, 0, 2, 1 };
386     final double[][] v2_t = { v2 };
387     assertTrue(VMath.equals(transpose(v2), v2_t));
388   }
389 
390   /**
391    * Testing the rotate90Equals(vector) method of VMath class.
392    */
393   @Test
testRotate90Equals()394   public void testRotate90Equals() {
395     // simple test case
396     final double[] v1 = { 1, 0 };
397     final double[] res = { 0, -1 };
398     assertArrayEquals(res, rotate90Equals(v1), 0);
399 
400     // more complex test case
401     final double[] v2 = { 1.21, -2.4 };
402     final double[] v2_copy = copy(v2);
403     // first rotation -> angle of 90° while cos(90°) = 0
404     assertEquals(0.0, angle(v2_copy, rotate90Equals(v2)), 0.);
405     final double[] v2_copy1rotate = copy(v2);
406     // second rotation -> additive inverse
407     assertArrayEquals(times(v2_copy, -1), rotate90Equals(v2), 0.);
408     // third rotation -> additive inverse to first rotation
409     assertArrayEquals(times(v2_copy1rotate, -1), rotate90Equals(v2), 0.);
410     // forth rotation -> identity
411     assertArrayEquals(v2_copy, rotate90Equals(v2), 0.);
412   }
413 
414   /**
415    * Testing that the *Equals methods tested in this class work in place and
416    * that the other
417    * methods tested create a new instance.
418    *
419    * Tests of methods where the class of the instance returned differs form the
420    * class of input are reasonably omitted,
421    * when testing reference.
422    */
423   @Test
testReference()424   public void testReference() {
425     final double[] v1 = { 0 }, v2 = { 0 };
426     final double s1 = 0, s2 = 0;
427 
428     // testing methods as in testMinus
429     assertNotSame(v1, minus(v1, s1));
430     assertSame(v1, minusEquals(v1, s1));
431 
432     assertNotSame(v1, minus(v1, v2));
433     assertSame(v1, minusEquals(v1, v2));
434 
435     assertNotSame(v1, timesMinus(v1, s1, v2));
436     assertSame(v1, timesMinusEquals(v1, s1, v2));
437 
438     assertNotSame(v1, minusTimes(v1, v2, s2));
439     assertSame(v1, minusTimesEquals(v1, v2, s2));
440 
441     assertNotSame(v1, timesMinusTimes(v1, s1, v2, s2));
442     assertSame(v1, timesMinusTimesEquals(v1, s1, v2, s2));
443 
444     // testing methods as in testNormalize
445     final double[] v3 = { 2 };
446     assertNotSame(v3, normalize(v3));
447     assertSame(v3, normalizeEquals(v3));
448 
449     // testing methods as in testPlus
450     assertNotSame(v1, plus(v1, s1));
451     assertSame(v1, plusEquals(v1, s1));
452 
453     assertNotSame(v1, plus(v1, v2));
454     assertSame(v1, plusEquals(v1, v2));
455 
456     assertNotSame(v1, timesPlus(v1, s1, v2));
457     assertSame(v1, timesPlusEquals(v1, s1, v2));
458 
459     assertNotSame(v1, plusTimes(v1, v2, s2));
460     assertSame(v1, plusTimesEquals(v1, v2, s2));
461 
462     assertNotSame(v1, timesPlusTimes(v1, s1, v2, s2));
463     assertSame(v1, timesPlusTimesEquals(v1, s1, v2, s2));
464 
465     // testing methods as in testTimes
466     assertNotSame(v1, times(v1, s1));
467     assertSame(v1, timesEquals(v1, s1));
468 
469     // testing methods as in testRotate90Equals
470     final double[] v4 = { 1, 0 };
471     assertSame(v4, rotate90Equals(v4));
472   }
473 
474   /**
475    * Testing that correct Error is raised when dimension of the input data
476    * mismatch the needs of the method.
477    * Methods where no error is to be raised are omitted.
478    *
479    * See {@link VMathOperationsTest#assertDimensionMismatch} for details.
480    */
481   @Test
testDimensionMismatch()482   public void testDimensionMismatch() {
483     final double[] v_len1 = { 1 }, v_len2 = { 1, 1 }, v_len3 = { 1, 1, 1 };
484     double s1 = 1, s2 = 1;
485 
486     // methods as in testPlus
487     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> plus(v_len1, v_len2));
488     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> plusEquals(v_len1, v_len2));
489 
490     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> timesPlus(v_len1, s1, v_len2));
491     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> timesPlusEquals(v_len1, s1, v_len2));
492 
493     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> plusTimes(v_len1, v_len2, s2));
494     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> plusTimesEquals(v_len1, v_len2, s2));
495 
496     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> timesPlusTimes(v_len1, s1, v_len2, s2));
497     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> timesPlusTimesEquals(v_len1, s1, v_len2, s2));
498 
499     // methods as in testMinus
500     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> minus(v_len1, v_len2));
501     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> minusEquals(v_len1, v_len2));
502 
503     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> timesMinus(v_len1, s1, v_len2));
504     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> timesMinusEquals(v_len1, s1, v_len2));
505 
506     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> minusTimes(v_len1, v_len2, s2));
507     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> minusTimesEquals(v_len1, v_len2, s2));
508 
509     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> timesMinusTimes(v_len1, s1, v_len2, s2));
510     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> timesMinusTimesEquals(v_len1, s1, v_len2, s2));
511 
512     // methods as in testScalarProduct
513     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> scalarProduct(v_len1, v_len2));
514     assertDimensionMismatch(ERR_VEC_DIMENSIONS, () -> transposeTimes(v_len1, v_len2));
515 
516     // test rotate90
517     assertDimensionMismatch("rotate90Equals is only valid for 2d vectors.", () -> rotate90Equals(v_len1));
518     assertDimensionMismatch("rotate90Equals is only valid for 2d vectors.", () -> rotate90Equals(v_len3));
519   }
520 }
521