View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.math4.legacy.linear;
18  
19  import java.io.Serializable;
20  import java.util.Arrays;
21  import java.util.Iterator;
22  import java.util.NoSuchElementException;
23  
24  import org.apache.commons.math4.legacy.TestUtils;
25  import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
26  import org.apache.commons.math4.legacy.analysis.function.Abs;
27  import org.apache.commons.math4.legacy.analysis.function.Acos;
28  import org.apache.commons.math4.legacy.analysis.function.Asin;
29  import org.apache.commons.math4.legacy.analysis.function.Atan;
30  import org.apache.commons.math4.legacy.analysis.function.Cbrt;
31  import org.apache.commons.math4.legacy.analysis.function.Ceil;
32  import org.apache.commons.math4.legacy.analysis.function.Cos;
33  import org.apache.commons.math4.legacy.analysis.function.Cosh;
34  import org.apache.commons.math4.legacy.analysis.function.Exp;
35  import org.apache.commons.math4.legacy.analysis.function.Expm1;
36  import org.apache.commons.math4.legacy.analysis.function.Floor;
37  import org.apache.commons.math4.legacy.analysis.function.Inverse;
38  import org.apache.commons.math4.legacy.analysis.function.Log;
39  import org.apache.commons.math4.legacy.analysis.function.Log10;
40  import org.apache.commons.math4.legacy.analysis.function.Log1p;
41  import org.apache.commons.math4.legacy.analysis.function.Power;
42  import org.apache.commons.math4.legacy.analysis.function.Rint;
43  import org.apache.commons.math4.legacy.analysis.function.Signum;
44  import org.apache.commons.math4.legacy.analysis.function.Sin;
45  import org.apache.commons.math4.legacy.analysis.function.Sinh;
46  import org.apache.commons.math4.legacy.analysis.function.Sqrt;
47  import org.apache.commons.math4.legacy.analysis.function.Tan;
48  import org.apache.commons.math4.legacy.analysis.function.Tanh;
49  import org.apache.commons.math4.legacy.analysis.function.Ulp;
50  import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
51  import org.apache.commons.math4.legacy.exception.MathArithmeticException;
52  import org.apache.commons.math4.legacy.exception.MathUnsupportedOperationException;
53  import org.apache.commons.math4.legacy.exception.NotPositiveException;
54  import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
55  import org.apache.commons.math4.legacy.exception.OutOfRangeException;
56  import org.apache.commons.math4.core.jdkmath.JdkMath;
57  import org.junit.Assert;
58  import org.junit.Test;
59  
60  
61  public abstract class RealVectorAbstractTest {
62  
63      protected enum BinaryOperation {
64          ADD, SUB, MUL, DIV
65      }
66  
67      /**
68       * <p>
69       * This is an attempt at covering most particular cases of combining two
70       * values. Here {@code x} is the value returned by
71       * {@link #getPreferredEntryValue()}, while {@code y} and {@code z} are two
72       * "normal" values.
73       * </p>
74       * <ol>
75       *   <li>
76       *     Addition: the following cases should be covered
77       *     <ul>
78       *       <li>{@code (2 * x) + (-x)}</li>
79       *       <li>{@code (-x) + 2 * x}</li>
80       *       <li>{@code x + y}</li>
81       *       <li>{@code y + x}</li>
82       *       <li>{@code y + z}</li>
83       *       <li>{@code y + (x - y)}</li>
84       *       <li>{@code (y - x) + x}</li>
85       *     </ul>
86       *     The values to be considered are:
87       *     {@code x, y, z, 2 * x, -x, x - y, y - x}.
88       *   </li>
89       *   <li>
90       *     Subtraction: the following cases should be covered
91       *     <ul>
92       *       <li>{@code (2 * x) - x}</li>
93       *       <li>{@code x - y}</li>
94       *       <li>{@code y - x}</li>
95       *       <li>{@code y - z}</li>
96       *       <li>{@code y - (y - x)}</li>
97       *       <li>{@code (y + x) - y}</li>
98       *     </ul>
99       *     The values to be considered are: {@code x, y, z, x + y, y - x}.
100      *   </li>
101      *   <li>
102      *     Multiplication
103      *     <ul>
104      *       <li>{@code (x * x) * (1 / x)}</li>
105      *       <li>{@code (1 / x) * (x * x)}</li>
106      *       <li>{@code x * y}</li>
107      *       <li>{@code y * x}</li>
108      *       <li>{@code y * z}</li>
109      *     </ul>
110      *     The values to be considered are: {@code x, y, z, 1 / x, x * x}.
111      *   </li>
112      *   <li>
113      *     Division
114      *     <ul>
115      *       <li>{@code (x * x) / x}</li>
116      *       <li>{@code x / y}</li>
117      *       <li>{@code y / x}</li>
118      *       <li>{@code y / z}</li>
119      *     </ul>
120      *     The values to be considered are: {@code x, y, z, x * x}.
121      *   </li>
122      * </ol>
123      * Also to be considered {@code NaN}, {@code POSITIVE_INFINITY},
124      * {@code NEGATIVE_INFINITY}, {@code +0.0}, {@code -0.0}.
125      */
126     private final double[] values;
127 
128     /**
129      * Creates a new instance of {@link RealVector}, with specified entries.
130      * The returned vector must be of the type currently tested. It should be
131      * noted that some tests assume that no references to the specified
132      * {@code double[]} are kept in the returned object: if necessary, defensive
133      * copy of this array should be made.
134      *
135      * @param data the entries of the vector to be created
136      * @return a new {@link RealVector} of the type to be tested
137      */
138     public abstract RealVector create(double[] data);
139 
140     /**
141      * Creates a new instance of {@link RealVector}, with specified entries.
142      * The type of the returned vector must be different from the type currently
143      * tested. It should be noted that some tests assume that no references to
144      * the specified {@code double[]} are kept in the returned object: if
145      * necessary, defensive copy of this array should be made.
146      *
147      * @param data the entries of the vector to be created
148      * @return a new {@link RealVector} of an alien type
149      */
150     public RealVector createAlien(double[] data){
151         return new RealVectorTestImpl(data);
152     }
153 
154     /**
155      * Returns a preferred value of the entries, to be tested specifically. Some
156      * implementations of {@link RealVector} (e.g. {@link OpenMapRealVector}) do
157      * not store specific values of entries. In order to ensure that all tests
158      * take into account this specific value, some entries of the vectors to be
159      * tested are deliberately set to the value returned by the present method.
160      * The default implementation returns {@code 0.0}.
161      *
162      * @return a value which <em>should</em> be present in all vectors to be
163      * tested
164      */
165     public double getPreferredEntryValue() {
166         return 0.0;
167     }
168 
169     public RealVectorAbstractTest() {
170         /*
171          * Make sure that x, y, z are three different values. Also, x is the
172          * preferred value (e.g. the value which is not stored in sparse
173          * implementations).
174          */
175         final double x = getPreferredEntryValue();
176         final double y = x + 1d;
177         final double z = y + 1d;
178 
179         values =
180             new double[] {
181                 Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY,
182                 0d, -0d, x, y, z, 2 * x, -x, 1 / x, x * x, x + y, x - y, y - x
183             };
184     }
185 
186     @Test
187     public void testGetDimension() {
188         final double x = getPreferredEntryValue();
189         final double[] data1 = {x, x, x, x};
190         Assert.assertEquals(data1.length, create(data1).getDimension());
191         final double y = x + 1;
192         final double[] data2 = {y, y, y, y};
193         Assert.assertEquals(data2.length, create(data2).getDimension());
194     }
195 
196     @Test
197     public void testGetEntry() {
198         final double x = getPreferredEntryValue();
199         final double[] data = {x, 1d, 2d, x, x};
200         final RealVector v = create(data);
201         for (int i = 0; i < data.length; i++) {
202             Assert.assertEquals("entry " + i, data[i], v.getEntry(i), 0d);
203         }
204     }
205 
206     @Test(expected=OutOfRangeException.class)
207     public void testGetEntryInvalidIndex1() {
208         create(new double[4]).getEntry(-1);
209     }
210 
211     @Test(expected=OutOfRangeException.class)
212     public void testGetEntryInvalidIndex2() {
213         create(new double[4]).getEntry(4);
214     }
215 
216     @Test
217     public void testSetEntry() {
218         final double x = getPreferredEntryValue();
219         final double[] data = {x, 1d, 2d, x, x};
220         final double[] expected = Arrays.copyOf(data, data.length);
221         final RealVector actual = create(data);
222 
223         /*
224          * Try setting to any value.
225          */
226         for (int i = 0; i < data.length; i++) {
227             final double oldValue = data[i];
228             final double newValue = oldValue + 1d;
229             expected[i] = newValue;
230             actual.setEntry(i, newValue);
231             TestUtils.assertEquals("while setting entry #" + i, expected,
232                 actual, 0d);
233             expected[i] = oldValue;
234             actual.setEntry(i, oldValue);
235         }
236 
237         /*
238          * Try setting to the preferred value.
239          */
240         for (int i = 0; i < data.length; i++) {
241             final double oldValue = data[i];
242             final double newValue = x;
243             expected[i] = newValue;
244             actual.setEntry(i, newValue);
245             TestUtils.assertEquals("while setting entry #" + i, expected,
246                 actual, 0d);
247             expected[i] = oldValue;
248             actual.setEntry(i, oldValue);
249         }
250     }
251 
252     @Test(expected=OutOfRangeException.class)
253     public void testSetEntryInvalidIndex1() {
254         create(new double[4]).setEntry(-1, getPreferredEntryValue());
255     }
256 
257     @Test(expected=OutOfRangeException.class)
258     public void testSetEntryInvalidIndex2() {
259         create(new double[4]).setEntry(4, getPreferredEntryValue());
260     }
261 
262     @Test
263     public void testAddToEntry() {
264         final double x = getPreferredEntryValue();
265         final double[] data1 = {x, 1d, 2d, x, x};
266 
267         final double[] expected = Arrays.copyOf(data1, data1.length);
268         final RealVector actual = create(data1);
269 
270         /*
271          * Try adding any value.
272          */
273         double increment = 1d;
274         for (int i = 0; i < data1.length; i++) {
275             final double oldValue = data1[i];
276             expected[i] += increment;
277             actual.addToEntry(i, increment);
278             TestUtils.assertEquals("while incrementing entry #" + i, expected,
279                 actual, 0d);
280             expected[i] = oldValue;
281             actual.setEntry(i, oldValue);
282         }
283 
284         /*
285          * Try incrementing so that result is equal to preferred value.
286          */
287         for (int i = 0; i < data1.length; i++) {
288             final double oldValue = data1[i];
289             increment = x - oldValue;
290             expected[i] = x;
291             actual.addToEntry(i, increment);
292             TestUtils.assertEquals("while incrementing entry #" + i, expected,
293                 actual, 0d);
294             expected[i] = oldValue;
295             actual.setEntry(i, oldValue);
296         }
297     }
298 
299     @Test(expected=OutOfRangeException.class)
300     public void testAddToEntryInvalidIndex1() {
301         create(new double[3]).addToEntry(-1, getPreferredEntryValue());
302     }
303 
304     @Test(expected=OutOfRangeException.class)
305     public void testAddToEntryInvalidIndex2() {
306         create(new double[3]).addToEntry(4, getPreferredEntryValue());
307     }
308 
309     private void doTestAppendVector(final String message, final RealVector v1,
310         final RealVector v2, final double delta) {
311 
312         final int n1 = v1.getDimension();
313         final int n2 = v2.getDimension();
314         final RealVector v = v1.append(v2);
315         Assert.assertEquals(message, n1 + n2, v.getDimension());
316         for (int i = 0; i < n1; i++) {
317             final String msg = message + ", entry #" + i;
318             Assert.assertEquals(msg, v1.getEntry(i), v.getEntry(i), delta);
319         }
320         for (int i = 0; i < n2; i++) {
321             final String msg = message + ", entry #" + (n1 + i);
322             Assert.assertEquals(msg, v2.getEntry(i), v.getEntry(n1 + i), delta);
323         }
324     }
325 
326     @Test
327     public void testAppendVector() {
328         final double x = getPreferredEntryValue();
329         final double[] data1 =  {x, 1d, 2d, x, x};
330         final double[] data2 =  {x, x, 3d, x, 4d, x};
331 
332         doTestAppendVector("same type", create(data1), create(data2), 0d);
333         doTestAppendVector("mixed types", create(data1), createAlien(data2), 0d);
334     }
335 
336     private void doTestAppendScalar(final String message, final RealVector v,
337         final double d, final double delta) {
338 
339         final int n = v.getDimension();
340         final RealVector w = v.append(d);
341         Assert.assertEquals(message, n + 1, w.getDimension());
342         for (int i = 0; i < n; i++) {
343             final String msg = message + ", entry #" + i;
344             Assert.assertEquals(msg, v.getEntry(i), w.getEntry(i), delta);
345         }
346         final String msg = message + ", entry #" + n;
347         Assert.assertEquals(msg, d, w.getEntry(n), delta);
348     }
349 
350     @Test
351     public void testAppendScalar() {
352         final double x = getPreferredEntryValue();
353         final double[] data = new double[] {x, 1d, 2d, x, x};
354 
355         doTestAppendScalar("", create(data), 1d, 0d);
356         doTestAppendScalar("", create(data), x, 0d);
357     }
358 
359     @Test
360     public void testGetSubVector() {
361         final double x = getPreferredEntryValue();
362         final double[] data = {x, x, x, 1d, x, 2d, x, x, 3d, x, x, x, 4d, x, x, x};
363         final int index = 1;
364         final int n = data.length - 5;
365         final RealVector actual = create(data).getSubVector(index, n);
366         final double[] expected = new double[n];
367         System.arraycopy(data, index, expected, 0, n);
368         TestUtils.assertEquals("", expected, actual, 0d);
369     }
370 
371     @Test(expected = OutOfRangeException.class)
372     public void testGetSubVectorInvalidIndex1() {
373         final int n = 10;
374         create(new double[n]).getSubVector(-1, 2);
375     }
376 
377     @Test(expected = OutOfRangeException.class)
378     public void testGetSubVectorInvalidIndex2() {
379         final int n = 10;
380         create(new double[n]).getSubVector(n, 2);
381     }
382 
383     @Test(expected = OutOfRangeException.class)
384     public void testGetSubVectorInvalidIndex3() {
385         final int n = 10;
386         create(new double[n]).getSubVector(0, n + 1);
387     }
388 
389     @Test(expected = NotPositiveException.class)
390     public void testGetSubVectorInvalidIndex4() {
391         final int n = 10;
392         create(new double[n]).getSubVector(3, -2);
393     }
394 
395     @Test
396     public void testSetSubVectorSameType() {
397         final double x = getPreferredEntryValue();
398         final double[] expected = {x, x, x, 1d, x, 2d, x, x, 3d, x, x, x, 4d, x, x, x};
399         final double[] sub = {5d, x, 6d, 7d, 8d};
400         final RealVector actual = create(expected);
401         final int index = 2;
402         actual.setSubVector(index, create(sub));
403 
404         for (int i = 0; i < sub.length; i++){
405             expected[index + i] = sub[i];
406         }
407         TestUtils.assertEquals("", expected, actual, 0d);
408     }
409 
410     @Test
411     public void testSetSubVectorMixedType() {
412         final double x = getPreferredEntryValue();
413         final double[] expected = {x, x, x, 1d, x, 2d, x, x, 3d, x, x, x, 4d, x, x, x};
414         final double[] sub = {5d, x, 6d, 7d, 8d};
415         final RealVector actual = create(expected);
416         final int index = 2;
417         actual.setSubVector(index, createAlien(sub));
418 
419         for (int i = 0; i < sub.length; i++){
420             expected[index + i] = sub[i];
421         }
422         TestUtils.assertEquals("", expected, actual, 0d);
423     }
424 
425     @Test(expected = OutOfRangeException.class)
426     public void testSetSubVectorInvalidIndex1() {
427         create(new double[10]).setSubVector(-1, create(new double[2]));
428     }
429 
430     @Test(expected = OutOfRangeException.class)
431     public void testSetSubVectorInvalidIndex2() {
432         create(new double[10]).setSubVector(10, create(new double[2]));
433     }
434 
435     @Test(expected = OutOfRangeException.class)
436     public void testSetSubVectorInvalidIndex3() {
437         create(new double[10]).setSubVector(9, create(new double[2]));
438     }
439 
440     @Test
441     public void testIsNaN() {
442         final RealVector v = create(new double[] {0, 1, 2});
443 
444         Assert.assertFalse(v.isNaN());
445         v.setEntry(1, Double.NaN);
446         Assert.assertTrue(v.isNaN());
447     }
448 
449     @Test
450     public void testIsInfinite() {
451         final RealVector v = create(new double[] { 0, 1, 2 });
452 
453         Assert.assertFalse(v.isInfinite());
454         v.setEntry(0, Double.POSITIVE_INFINITY);
455         Assert.assertTrue(v.isInfinite());
456         v.setEntry(1, Double.NaN);
457         Assert.assertFalse(v.isInfinite());
458     }
459 
460     protected void doTestEbeBinaryOperation(final BinaryOperation op, final boolean mixed, boolean ignoreSpecial) {
461         final double[] data1 = new double[values.length * values.length];
462         final double[] data2 = new double[values.length * values.length];
463         int k = 0;
464         for (int i = 0; i < values.length; i++) {
465             for (int j = 0; j < values.length; j++) {
466                 data1[k] = values[i];
467                 data2[k] = values[j];
468                 ++k;
469             }
470         }
471         final RealVector v1 = create(data1);
472         final RealVector v2 = mixed ? createAlien(data2) : create(data2);
473         final RealVector actual;
474         switch (op) {
475             case ADD:
476                 actual = v1.add(v2);
477                 break;
478             case SUB:
479                 actual = v1.subtract(v2);
480                 break;
481             case MUL:
482                 actual = v1.ebeMultiply(v2);
483                 break;
484             case DIV:
485                 actual = v1.ebeDivide(v2);
486                 break;
487             default:
488                 throw new AssertionError("unexpected value");
489         }
490         final double[] expected = new double[data1.length];
491         for (int i = 0; i < expected.length; i++) {
492             switch (op) {
493                 case ADD:
494                     expected[i] = data1[i] + data2[i];
495                     break;
496                 case SUB:
497                     expected[i] = data1[i] - data2[i];
498                     break;
499                 case MUL:
500                     expected[i] = data1[i] * data2[i];
501                     break;
502                 case DIV:
503                     expected[i] = data1[i] / data2[i];
504                     break;
505                 default:
506                     throw new AssertionError("unexpected value");
507             }
508         }
509         for (int i = 0; i < expected.length; i++) {
510             boolean isSpecial = Double.isNaN(expected[i]) || Double.isInfinite(expected[i]);
511             if (!(isSpecial && ignoreSpecial)) {
512                 final String msg = "entry #"+i+", left = "+data1[i]+", right = " + data2[i];
513                 Assert.assertEquals(msg, expected[i], actual.getEntry(i), 0.0);
514             }
515         }
516     }
517 
518     private void doTestEbeBinaryOperationDimensionMismatch(final BinaryOperation op) {
519         final int n = 10;
520         switch (op) {
521             case ADD:
522                 create(new double[n]).add(create(new double[n + 1]));
523                 break;
524             case SUB:
525                 create(new double[n]).subtract(create(new double[n + 1]));
526                 break;
527             case MUL:
528                 create(new double[n]).ebeMultiply(create(new double[n + 1]));
529                 break;
530             case DIV:
531                 create(new double[n]).ebeDivide(create(new double[n + 1]));
532                 break;
533             default:
534                 throw new AssertionError("unexpected value");
535         }
536     }
537 
538     @Test
539     public void testAddSameType() {
540         doTestEbeBinaryOperation(BinaryOperation.ADD, false, false);
541     }
542 
543     @Test
544     public void testAddMixedTypes() {
545         doTestEbeBinaryOperation(BinaryOperation.ADD, true, false);
546     }
547 
548     @Test(expected = DimensionMismatchException.class)
549     public void testAddDimensionMismatch() {
550         doTestEbeBinaryOperationDimensionMismatch(BinaryOperation.ADD);
551     }
552 
553     @Test
554     public void testSubtractSameType() {
555         doTestEbeBinaryOperation(BinaryOperation.SUB, false, false);
556     }
557 
558     @Test
559     public void testSubtractMixedTypes() {
560         doTestEbeBinaryOperation(BinaryOperation.SUB, true, false);
561     }
562 
563     @Test(expected = DimensionMismatchException.class)
564     public void testSubtractDimensionMismatch() {
565         doTestEbeBinaryOperationDimensionMismatch(BinaryOperation.SUB);
566     }
567 
568     @Test
569     public void testEbeMultiplySameType() {
570         doTestEbeBinaryOperation(BinaryOperation.MUL, false, false);
571     }
572 
573     @Test
574     public void testEbeMultiplyMixedTypes() {
575         doTestEbeBinaryOperation(BinaryOperation.MUL, true, false);
576     }
577 
578     @Test(expected = DimensionMismatchException.class)
579     public void testEbeMultiplyDimensionMismatch() {
580         doTestEbeBinaryOperationDimensionMismatch(BinaryOperation.MUL);
581     }
582 
583     @Test
584     public void testEbeDivideSameType() {
585         doTestEbeBinaryOperation(BinaryOperation.DIV, false, false);
586     }
587 
588    @Test
589     public void testEbeDivideMixedTypes() {
590         doTestEbeBinaryOperation(BinaryOperation.DIV, true, false);
591     }
592 
593     @Test(expected = DimensionMismatchException.class)
594     public void testEbeDivideDimensionMismatch() {
595         doTestEbeBinaryOperationDimensionMismatch(BinaryOperation.DIV);
596     }
597 
598     private void doTestGetDistance(final boolean mixed) {
599         final double x = getPreferredEntryValue();
600         final double[] data1 = new double[] { x, x, 1d, x, 2d, x, x, 3d, x };
601         final double[] data2 = new double[] { 4d, x, x, 5d, 6d, 7d, x, x, 8d };
602         final RealVector v1 = create(data1);
603         final RealVector v2;
604         if (mixed) {
605             v2 = createAlien(data2);
606         } else {
607             v2 = create(data2);
608         }
609         final double actual = v1.getDistance(v2);
610         double expected = 0d;
611         for (int i = 0; i < data1.length; i++) {
612             final double delta = data2[i] - data1[i];
613             expected += delta * delta;
614         }
615         expected = JdkMath.sqrt(expected);
616         Assert.assertEquals("", expected, actual, 0d);
617     }
618 
619     @Test
620     public void testGetDistanceSameType() {
621         doTestGetDistance(false);
622     }
623 
624     @Test
625     public void testGetDistanceMixedTypes() {
626         doTestGetDistance(true);
627     }
628 
629     @Test(expected = DimensionMismatchException.class)
630     public void testGetDistanceDimensionMismatch() {
631         create(new double[4]).getDistance(createAlien(new double[5]));
632     }
633 
634     @Test
635     public void testGetNorm() {
636         final double x = getPreferredEntryValue();
637         final double[] data = new double[] { x, x, 1d, x, 2d, x, x, 3d, x };
638         final RealVector v = create(data);
639         final double actual = v.getNorm();
640         double expected = 0d;
641         for (int i = 0; i < data.length; i++) {
642             expected += data[i] * data[i];
643         }
644         expected = JdkMath.sqrt(expected);
645         Assert.assertEquals("", expected, actual, 0d);
646     }
647 
648     private void doTestGetL1Distance(final boolean mixed) {
649         final double x = getPreferredEntryValue();
650         final double[] data1 = new double[] { x, x, 1d, x, 2d, x, x, 3d, x };
651         final double[] data2 = new double[] { 4d, x, x, 5d, 6d, 7d, x, x, 8d };
652         final RealVector v1 = create(data1);
653         final RealVector v2;
654         if (mixed) {
655             v2 = createAlien(data2);
656         } else {
657             v2 = create(data2);
658         }
659         final double actual = v1.getL1Distance(v2);
660         double expected = 0d;
661         for (int i = 0; i < data1.length; i++) {
662             final double delta = data2[i] - data1[i];
663             expected += JdkMath.abs(delta);
664         }
665         Assert.assertEquals("", expected, actual, 0d);
666     }
667 
668     @Test
669     public void testGetL1DistanceSameType() {
670         doTestGetL1Distance(false);
671     }
672 
673     @Test
674     public void testGetL1DistanceMixedTypes() {
675         doTestGetL1Distance(true);
676     }
677 
678     @Test(expected = DimensionMismatchException.class)
679     public void testGetL1DistanceDimensionMismatch() {
680         create(new double[4]).getL1Distance(createAlien(new double[5]));
681     }
682 
683     @Test
684     public void testGetL1Norm() {
685         final double x = getPreferredEntryValue();
686         final double[] data = new double[] { x, x, 1d, x, 2d, x, x, 3d, x };
687         final RealVector v = create(data);
688         final double actual = v.getL1Norm();
689         double expected = 0d;
690         for (int i = 0; i < data.length; i++) {
691             expected += JdkMath.abs(data[i]);
692         }
693         Assert.assertEquals("", expected, actual, 0d);
694     }
695 
696     private void doTestGetLInfDistance(final boolean mixed) {
697         final double x = getPreferredEntryValue();
698         final double[] data1 = new double[] { x, x, 1d, x, 2d, x, x, 3d, x };
699         final double[] data2 = new double[] { 4d, x, x, 5d, 6d, 7d, x, x, 8d };
700         final RealVector v1 = create(data1);
701         final RealVector v2;
702         if (mixed) {
703             v2 = createAlien(data2);
704         } else {
705             v2 = create(data2);
706         }
707         final double actual = v1.getLInfDistance(v2);
708         double expected = 0d;
709         for (int i = 0; i < data1.length; i++) {
710             final double delta = data2[i] - data1[i];
711             expected = JdkMath.max(expected, JdkMath.abs(delta));
712         }
713         Assert.assertEquals("", expected, actual, 0d);
714     }
715 
716     @Test
717     public void testGetLInfDistanceSameType() {
718         doTestGetLInfDistance(false);
719     }
720 
721     @Test
722     public void testGetLInfDistanceMixedTypes() {
723         doTestGetLInfDistance(true);
724     }
725 
726     @Test(expected = DimensionMismatchException.class)
727     public void testGetLInfDistanceDimensionMismatch() {
728         create(new double[4]).getLInfDistance(createAlien(new double[5]));
729     }
730 
731     @Test
732     public void testGetLInfNorm() {
733         final double x = getPreferredEntryValue();
734         final double[] data = new double[] { x, x, 1d, x, 2d, x, x, 3d, x };
735         final RealVector v = create(data);
736         final double actual = v.getLInfNorm();
737         double expected = 0d;
738         for (int i = 0; i < data.length; i++) {
739             expected = JdkMath.max(expected, JdkMath.abs(data[i]));
740         }
741         Assert.assertEquals("", expected, actual, 0d);
742     }
743 
744     private void doTestMapBinaryOperation(final BinaryOperation op, final boolean inPlace) {
745         final double[] expected = new double[values.length];
746         for (int i = 0; i < values.length; i++) {
747             final double d = values[i];
748             for (int j = 0; j < expected.length; j++) {
749                 switch (op) {
750                     case ADD:
751                         expected[j] = values[j] + d;
752                         break;
753                     case SUB:
754                         expected[j] = values[j] - d;
755                         break;
756                     case MUL:
757                         expected[j] = values[j] * d;
758                         break;
759                     case DIV:
760                         expected[j] = values[j] / d;
761                         break;
762                     default:
763                         throw new AssertionError("unexpected value");
764                 }
765             }
766             final RealVector v = create(values);
767             final RealVector actual;
768             if (inPlace) {
769                 switch (op) {
770                     case ADD:
771                         actual = v.mapAddToSelf(d);
772                         break;
773                     case SUB:
774                         actual = v.mapSubtractToSelf(d);
775                         break;
776                     case MUL:
777                         actual = v.mapMultiplyToSelf(d);
778                         break;
779                     case DIV:
780                         actual = v.mapDivideToSelf(d);
781                         break;
782                     default:
783                         throw new AssertionError("unexpected value");
784                 }
785             } else {
786                 switch (op) {
787                     case ADD:
788                         actual = v.mapAdd(d);
789                         break;
790                     case SUB:
791                         actual = v.mapSubtract(d);
792                         break;
793                     case MUL:
794                         actual = v.mapMultiply(d);
795                         break;
796                     case DIV:
797                         actual = v.mapDivide(d);
798                         break;
799                     default:
800                         throw new AssertionError("unexpected value");
801                 }
802             }
803             TestUtils.assertEquals(Double.toString(d), expected, actual, 0d);
804         }
805     }
806 
807     @Test
808     public void testMapAdd() {
809         doTestMapBinaryOperation(BinaryOperation.ADD, false);
810     }
811 
812     @Test
813     public void testMapAddToSelf() {
814         doTestMapBinaryOperation(BinaryOperation.ADD, true);
815     }
816 
817     @Test
818     public void testMapSubtract() {
819         doTestMapBinaryOperation(BinaryOperation.SUB, false);
820     }
821 
822     @Test
823     public void testMapSubtractToSelf() {
824         doTestMapBinaryOperation(BinaryOperation.SUB, true);
825     }
826 
827     @Test
828     public void testMapMultiply() {
829         doTestMapBinaryOperation(BinaryOperation.MUL, false);
830     }
831 
832     @Test
833     public void testMapMultiplyToSelf() {
834         doTestMapBinaryOperation(BinaryOperation.MUL, true);
835     }
836 
837     @Test
838     public void testMapDivide() {
839         doTestMapBinaryOperation(BinaryOperation.DIV, false);
840     }
841 
842     @Test
843     public void testMapDivideToSelf() {
844         doTestMapBinaryOperation(BinaryOperation.DIV, true);
845     }
846 
847     private void doTestMapFunction(final UnivariateFunction f,
848         final boolean inPlace) {
849         final double[] data = new double[values.length + 6];
850         System.arraycopy(values, 0, data, 0, values.length);
851         data[values.length + 0] = 0.5 * JdkMath.PI;
852         data[values.length + 1] = -0.5 * JdkMath.PI;
853         data[values.length + 2] = JdkMath.E;
854         data[values.length + 3] = -JdkMath.E;
855         data[values.length + 4] = 1.0;
856         data[values.length + 5] = -1.0;
857         final double[] expected = new double[data.length];
858         for (int i = 0; i < data.length; i++) {
859             expected[i] = f.value(data[i]);
860         }
861         final RealVector v = create(data);
862         final RealVector actual;
863         if (inPlace) {
864             actual = v.mapToSelf(f);
865             Assert.assertSame(v, actual);
866         } else {
867             actual = v.map(f);
868         }
869         TestUtils.assertEquals(f.getClass().getSimpleName(), expected, actual, 1E-16);
870     }
871 
872     protected UnivariateFunction[] createFunctions() {
873         return new UnivariateFunction[] {
874             new Power(2.0), new Exp(), new Expm1(), new Log(), new Log10(),
875             new Log1p(), new Cosh(), new Sinh(), new Tanh(), new Cos(),
876             new Sin(), new Tan(), new Acos(), new Asin(), new Atan(),
877             new Inverse(), new Abs(), new Sqrt(), new Cbrt(), new Ceil(),
878             new Floor(), new Rint(), new Signum(), new Ulp()
879         };
880     }
881 
882     @Test
883     public void testMap() {
884         final UnivariateFunction[] functions = createFunctions();
885         for (UnivariateFunction f : functions) {
886             doTestMapFunction(f, false);
887         }
888     }
889 
890     @Test
891     public void testMapToSelf() {
892         final UnivariateFunction[] functions = createFunctions();
893         for (UnivariateFunction f : functions) {
894             doTestMapFunction(f, true);
895         }
896     }
897 
898     private void doTestOuterProduct(final boolean mixed) {
899         final double[] dataU = values;
900         final RealVector u = create(dataU);
901         final double[] dataV = new double[values.length + 3];
902         System.arraycopy(values, 0, dataV, 0, values.length);
903         dataV[values.length] = 1d;
904         dataV[values.length] = -2d;
905         dataV[values.length] = 3d;
906         final RealVector v;
907         if (mixed) {
908             v = createAlien(dataV);
909         } else {
910             v = create(dataV);
911         }
912         final RealMatrix uv = u.outerProduct(v);
913         Assert.assertEquals("number of rows", dataU.length, uv
914             .getRowDimension());
915         Assert.assertEquals("number of columns", dataV.length, uv
916             .getColumnDimension());
917         for (int i = 0; i < dataU.length; i++) {
918             for (int j = 0; j < dataV.length; j++) {
919                 final double expected = dataU[i] * dataV[j];
920                 final double actual = uv.getEntry(i, j);
921                 Assert.assertEquals(dataU[i] + " * " + dataV[j], expected, actual, 0d);
922             }
923         }
924     }
925 
926     @Test
927     public void testOuterProductSameType() {
928         doTestOuterProduct(false);
929     }
930 
931     @Test
932     public void testOuterProductMixedTypes() {
933         doTestOuterProduct(true);
934     }
935 
936     private void doTestProjection(final boolean mixed) {
937         final double x = getPreferredEntryValue();
938         final double[] data1 = {
939             x, 1d, x, x, 2d, x, x, x, 3d, x, x, x, x
940         };
941         final double[] data2 = {
942             5d, -6d, 7d, x, x, -8d, -9d, 10d, 11d, x, 12d, 13d, -15d
943         };
944         double dotProduct = 0d;
945         double norm2 = 0d;
946         for (int i = 0; i < data1.length; i++){
947             dotProduct += data1[i] * data2[i];
948             norm2 += data2[i] * data2[i];
949         }
950         final double s = dotProduct / norm2;
951         final double[] expected = new double[data1.length];
952         for (int i = 0; i < data2.length; i++) {
953             expected[i] = s * data2[i];
954         }
955         final RealVector v1 = create(data1);
956         final RealVector v2;
957         if (mixed) {
958             v2 = createAlien(data2);
959         } else {
960             v2 = create(data2);
961         }
962         final RealVector actual = v1.projection(v2);
963         TestUtils.assertEquals("", expected, actual, 0d);
964     }
965 
966     @Test
967     public void testProjectionSameType() {
968         doTestProjection(false);
969     }
970 
971     @Test
972     public void testProjectionMixedTypes() {
973         doTestProjection(true);
974     }
975 
976     @Test(expected = MathArithmeticException.class)
977     public void testProjectionNullVector() {
978         create(new double[4]).projection(create(new double[4]));
979     }
980 
981     @Test(expected = DimensionMismatchException.class)
982     public void testProjectionDimensionMismatch() {
983         final RealVector v1 = create(new double[4]);
984         final RealVector v2 = create(new double[5]);
985         v2.set(1.0);
986         v1.projection(v2);
987     }
988 
989     @Test
990     public void testSet() {
991         for (int i = 0; i < values.length; i++) {
992             final double expected = values[i];
993             final RealVector v = create(values);
994             v.set(expected);
995             for (int j = 0; j < values.length; j++) {
996                 Assert.assertEquals("entry #" + j, expected, v.getEntry(j), 0);
997             }
998         }
999     }
1000 
1001     @Test
1002     public void testToArray() {
1003         final double[] data = create(values).toArray();
1004         Assert.assertNotSame(values, data);
1005         for (int i = 0; i < values.length; i++) {
1006             Assert.assertEquals("entry #" + i, values[i], data[i], 0);
1007         }
1008     }
1009 
1010     private void doTestUnitVector(final boolean inPlace) {
1011         final double x = getPreferredEntryValue();
1012         final double[] data = {
1013             x, 1d, x, x, 2d, x, x, x, 3d, x, x, x, x
1014         };
1015         double norm = 0d;
1016         for (int i = 0; i < data.length; i++) {
1017             norm += data[i] * data[i];
1018         }
1019         norm = JdkMath.sqrt(norm);
1020         final double[] expected = new double[data.length];
1021         for (int i = 0; i < expected.length; i++) {
1022             expected[i] = data[i] / norm;
1023         }
1024         final RealVector v = create(data);
1025         final RealVector actual;
1026         if (inPlace) {
1027             v.unitize();
1028             actual = v;
1029         } else {
1030             actual = v.unitVector();
1031             Assert.assertNotSame(v, actual);
1032         }
1033         TestUtils.assertEquals("", expected, actual, 0d);
1034     }
1035 
1036     @Test
1037     public void testUnitVector() {
1038         doTestUnitVector(false);
1039     }
1040 
1041     @Test
1042     public void testUnitize() {
1043         doTestUnitVector(true);
1044     }
1045 
1046     private void doTestUnitVectorNullVector(final boolean inPlace) {
1047         final double[] data = {
1048             0d, 0d, 0d, 0d, 0d
1049         };
1050         if (inPlace) {
1051             create(data).unitize();
1052         } else {
1053             create(data).unitVector();
1054         }
1055     }
1056 
1057     @Test(expected=MathArithmeticException.class)
1058     public void testUnitVectorNullVector() {
1059         doTestUnitVectorNullVector(false);
1060     }
1061 
1062     @Test(expected=MathArithmeticException.class)
1063     public void testUnitizeNullVector() {
1064         doTestUnitVectorNullVector(true);
1065     }
1066 
1067     @Test
1068     public void testIterator() {
1069         final RealVector v = create(values);
1070         final Iterator<RealVector.Entry> it = v.iterator();
1071         for (int i = 0; i < values.length; i++) {
1072             Assert.assertTrue("entry #" + i, it.hasNext());
1073             final RealVector.Entry e = it.next();
1074             Assert.assertEquals("", i, e.getIndex());
1075             Assert.assertEquals("", values[i], e.getValue(), 0d);
1076             try {
1077                 it.remove();
1078                 Assert.fail("MathUnsupportedOperationException should have been thrown");
1079             } catch (MathUnsupportedOperationException exc) {
1080                 // Expected behavior
1081             }
1082         }
1083         Assert.assertFalse(it.hasNext());
1084         try {
1085             it.next();
1086             Assert.fail("NoSuchElementException should have been thrown");
1087         } catch (NoSuchElementException e) {
1088             // Expected behavior
1089         }
1090     }
1091 
1092     private void doTestCombine(final boolean inPlace, final boolean mixed) {
1093         final int n = values.length * values.length;
1094         final double[] data1 = new double[n];
1095         final double[] data2 = new double[n];
1096         for (int i = 0; i < values.length; i++) {
1097             for (int j = 0; j < values.length; j++) {
1098                 final int index = values.length * i + j;
1099                 data1[index] = values[i];
1100                 data2[index] = values[j];
1101             }
1102         }
1103         final RealVector v1 = create(data1);
1104         final RealVector v2 = mixed ? createAlien(data2) : create(data2);
1105         final double[] expected = new double[n];
1106         for (int i = 0; i < values.length; i++) {
1107             final double a1 = values[i];
1108             for (int j = 0; j < values.length; j++) {
1109                 final double a2 = values[j];
1110                 for (int k = 0; k < n; k++) {
1111                     expected[k] = a1 * data1[k] + a2 * data2[k];
1112                 }
1113                 final RealVector actual;
1114                 if (inPlace) {
1115                     final RealVector v1bis = v1.copy();
1116                     actual = v1bis.combineToSelf(a1, a2, v2);
1117                     Assert.assertSame(v1bis, actual);
1118                 } else {
1119                     actual = v1.combine(a1, a2, v2);
1120                 }
1121                 TestUtils.assertEquals("a1 = " + a1 + ", a2 = " + a2, expected,
1122                     actual, 0.);
1123             }
1124         }
1125     }
1126 
1127     private void doTestCombineDimensionMismatch(final boolean inPlace, final boolean mixed) {
1128         final RealVector v1 = create(new double[10]);
1129         final RealVector v2;
1130         if (mixed) {
1131             v2 = createAlien(new double[15]);
1132         } else {
1133             v2 = create(new double[15]);
1134         }
1135         if (inPlace) {
1136             v1.combineToSelf(1.0, 1.0, v2);
1137         } else {
1138             v1.combine(1.0, 1.0, v2);
1139         }
1140     }
1141 
1142     @Test
1143     public void testCombineSameType() {
1144         doTestCombine(false, false);
1145     }
1146 
1147     @Test
1148     public void testCombineMixedTypes() {
1149         doTestCombine(false, true);
1150     }
1151 
1152     @Test(expected = DimensionMismatchException.class)
1153     public void testCombineDimensionMismatchSameType() {
1154         doTestCombineDimensionMismatch(false, false);
1155     }
1156 
1157     @Test(expected = DimensionMismatchException.class)
1158     public void testCombineDimensionMismatchMixedTypes() {
1159         doTestCombineDimensionMismatch(false, true);
1160     }
1161 
1162     @Test
1163     public void testCombineToSelfSameType() {
1164         doTestCombine(true, false);
1165     }
1166 
1167     @Test
1168     public void testCombineToSelfMixedTypes() {
1169         doTestCombine(true, true);
1170     }
1171 
1172     @Test(expected = DimensionMismatchException.class)
1173     public void testCombineToSelfDimensionMismatchSameType() {
1174         doTestCombineDimensionMismatch(true, false);
1175     }
1176 
1177     @Test(expected = DimensionMismatchException.class)
1178     public void testCombineToSelfDimensionMismatchMixedTypes() {
1179         doTestCombineDimensionMismatch(true, true);
1180     }
1181 
1182     @Test
1183     public void testCopy() {
1184         final RealVector v = create(values);
1185         final RealVector w = v.copy();
1186         Assert.assertNotSame(v, w);
1187         TestUtils.assertEquals("", values, w, 0d);
1188     }
1189 
1190     private void doTestDotProductRegularValues(final boolean mixed) {
1191         final double x = getPreferredEntryValue();
1192         final double[] data1 = {
1193             x, 1d, x, x, 2d, x, x, x, 3d, x, x, x, x
1194         };
1195         final double[] data2 = {
1196             5d, -6d, 7d, x, x, -8d, -9d, 10d, 11d, x, 12d, 13d, -15d
1197         };
1198         double expected = 0d;
1199         for (int i = 0; i < data1.length; i++){
1200             expected += data1[i] * data2[i];
1201         }
1202         final RealVector v1 = create(data1);
1203         final RealVector v2;
1204         if (mixed) {
1205             v2 = createAlien(data2);
1206         } else {
1207             v2 = create(data2);
1208         }
1209         final double actual = v1.dotProduct(v2);
1210         Assert.assertEquals("", expected, actual, 0d);
1211     }
1212 
1213     private void doTestDotProductSpecialValues(final boolean mixed) {
1214         for (int i = 0; i < values.length; i++) {
1215             final double[] data1 = {
1216                 values[i]
1217             };
1218             final RealVector v1 = create(data1);
1219             for (int j = 0; j < values.length; j++) {
1220                 final double[] data2 = {
1221                     values[j]
1222                 };
1223                 final RealVector v2;
1224                 if (mixed) {
1225                     v2 = createAlien(data2);
1226                 } else {
1227                     v2 = create(data2);
1228                 }
1229                 final double expected = data1[0] * data2[0];
1230                 final double actual = v1.dotProduct(v2);
1231                 Assert.assertEquals(data1[0] + " * " + data2[0], expected,
1232                     actual, 0d);
1233             }
1234         }
1235     }
1236 
1237     private void doTestDotProductDimensionMismatch(final boolean mixed) {
1238         final double[] data1 = new double[10];
1239         final double[] data2 = new double[data1.length + 1];
1240         final RealVector v1 = create(data1);
1241         final RealVector v2;
1242         if (mixed) {
1243             v2 = createAlien(data2);
1244         } else {
1245             v2 = create(data2);
1246         }
1247         v1.dotProduct(v2);
1248     }
1249 
1250     @Test
1251     public void testDotProductSameType() {
1252         doTestDotProductRegularValues(false);
1253         doTestDotProductSpecialValues(false);
1254     }
1255 
1256     @Test(expected=DimensionMismatchException.class)
1257     public void testDotProductDimensionMismatchSameType() {
1258         doTestDotProductDimensionMismatch(false);
1259     }
1260 
1261     @Test
1262     public void testDotProductMixedTypes() {
1263         doTestDotProductRegularValues(true);
1264         doTestDotProductSpecialValues(true);
1265     }
1266 
1267     @Test(expected=DimensionMismatchException.class)
1268     public void testDotProductDimensionMismatchMixedTypes() {
1269         doTestDotProductDimensionMismatch(true);
1270     }
1271 
1272     private void doTestCosine(final boolean mixed) {
1273         final double x = getPreferredEntryValue();
1274         final double[] data1 = {
1275             x, 1d, x, x, 2d, x, x, x, 3d, x, x, x, x
1276         };
1277         final double[] data2 = {
1278             5d, -6d, 7d, x, x, -8d, -9d, 10d, 11d, x, 12d, 13d, -15d
1279         };
1280         double norm1 = 0d;
1281         double norm2 = 0d;
1282         double dotProduct = 0d;
1283         for (int i = 0; i < data1.length; i++){
1284             norm1 += data1[i] * data1[i];
1285             norm2 += data2[i] * data2[i];
1286             dotProduct += data1[i] * data2[i];
1287         }
1288         norm1 = JdkMath.sqrt(norm1);
1289         norm2 = JdkMath.sqrt(norm2);
1290         final double expected = dotProduct / (norm1 * norm2);
1291         final RealVector v1 = create(data1);
1292         final RealVector v2;
1293         if (mixed) {
1294             v2 = createAlien(data2);
1295         } else {
1296             v2 = create(data2);
1297         }
1298         final double actual = v1.cosine(v2);
1299         Assert.assertEquals("", expected, actual, 0d);
1300     }
1301 
1302     @Test
1303     public void testCosineSameType() {
1304         doTestCosine(false);
1305     }
1306 
1307     @Test
1308     public void testCosineMixedTypes() {
1309         doTestCosine(true);
1310     }
1311 
1312     @Test(expected=MathArithmeticException.class)
1313     public void testCosineLeftNullVector() {
1314         final RealVector v = create(new double[] {0, 0, 0});
1315         final RealVector w = create(new double[] {1, 0, 0});
1316         v.cosine(w);
1317     }
1318 
1319     @Test(expected=MathArithmeticException.class)
1320     public void testCosineRightNullVector() {
1321         final RealVector v = create(new double[] {0, 0, 0});
1322         final RealVector w = create(new double[] {1, 0, 0});
1323         w.cosine(v);
1324     }
1325 
1326     @Test(expected=DimensionMismatchException.class)
1327     public void testCosineDimensionMismatch() {
1328         final RealVector v = create(new double[] {1, 2, 3});
1329         final RealVector w = create(new double[] {1, 2, 3, 4});
1330         v.cosine(w);
1331     }
1332 
1333     @Test
1334     public void testEquals() {
1335         final RealVector v = create(new double[] { 0, 1, 2 });
1336 
1337         Assert.assertEquals(v, v);
1338         Assert.assertEquals(v, v.copy());
1339         Assert.assertNotEquals(v, null);
1340         Assert.assertNotEquals(v, v.getSubVector(0, v.getDimension() - 1));
1341         Assert.assertEquals(v, v.getSubVector(0, v.getDimension()));
1342     }
1343 
1344     @Test
1345     public void testSerial()  {
1346         RealVector v = create(new double[] { 0, 1, 2 });
1347         Assert.assertEquals(v,TestUtils.serializeAndRecover(v));
1348     }
1349 
1350     @Test
1351     public void testMinMax() {
1352         final RealVector v1 = create(new double[] {0, -6, 4, 12, 7});
1353         Assert.assertEquals(1, v1.getMinIndex());
1354         Assert.assertEquals(-6, v1.getMinValue(), 1.0e-12);
1355         Assert.assertEquals(3, v1.getMaxIndex());
1356         Assert.assertEquals(12, v1.getMaxValue(), 1.0e-12);
1357         final RealVector v2 = create(new double[] {Double.NaN, 3, Double.NaN, -2});
1358         Assert.assertEquals(3, v2.getMinIndex());
1359         Assert.assertEquals(-2, v2.getMinValue(), 1.0e-12);
1360         Assert.assertEquals(1, v2.getMaxIndex());
1361         Assert.assertEquals(3, v2.getMaxValue(), 1.0e-12);
1362         final RealVector v3 = create(new double[] {Double.NaN, Double.NaN});
1363         Assert.assertEquals(-1, v3.getMinIndex());
1364         Assert.assertTrue(Double.isNaN(v3.getMinValue()));
1365         Assert.assertEquals(-1, v3.getMaxIndex());
1366         Assert.assertTrue(Double.isNaN(v3.getMaxValue()));
1367         final RealVector v4 = create(new double[0]);
1368         Assert.assertEquals(-1, v4.getMinIndex());
1369         Assert.assertTrue(Double.isNaN(v4.getMinValue()));
1370         Assert.assertEquals(-1, v4.getMaxIndex());
1371         Assert.assertTrue(Double.isNaN(v4.getMaxValue()));
1372     }
1373 
1374     /*
1375      * TESTS OF THE VISITOR PATTERN
1376      */
1377 
1378     /** The whole vector is visited. */
1379     @Test
1380     public void testWalkInDefaultOrderPreservingVisitor1() {
1381         final double[] data = new double[] {
1382             0d, 1d, 0d, 0d, 2d, 0d, 0d, 0d, 3d
1383         };
1384         final RealVector v = create(data);
1385         final RealVectorPreservingVisitor visitor;
1386         visitor = new RealVectorPreservingVisitor() {
1387 
1388             private int expectedIndex;
1389 
1390             @Override
1391             public void visit(final int actualIndex, final double actualValue) {
1392                 Assert.assertEquals(expectedIndex, actualIndex);
1393                 Assert.assertEquals(Integer.toString(actualIndex),
1394                                     data[actualIndex], actualValue, 0d);
1395                 ++expectedIndex;
1396             }
1397 
1398             @Override
1399             public void start(final int actualSize, final int actualStart,
1400                               final int actualEnd) {
1401                 Assert.assertEquals(data.length, actualSize);
1402                 Assert.assertEquals(0, actualStart);
1403                 Assert.assertEquals(data.length - 1, actualEnd);
1404                 expectedIndex = 0;
1405             }
1406 
1407             @Override
1408             public double end() {
1409                 return 0.0;
1410             }
1411         };
1412         v.walkInDefaultOrder(visitor);
1413     }
1414 
1415     /** Visiting an invalid subvector. */
1416     @Test
1417     public void testWalkInDefaultOrderPreservingVisitor2() {
1418         final RealVector v = create(new double[5]);
1419         final RealVectorPreservingVisitor visitor;
1420         visitor = new RealVectorPreservingVisitor() {
1421 
1422             @Override
1423             public void visit(int index, double value) {
1424                 // Do nothing
1425             }
1426 
1427             @Override
1428             public void start(int dimension, int start, int end) {
1429                 // Do nothing
1430             }
1431 
1432             @Override
1433             public double end() {
1434                 return 0.0;
1435             }
1436         };
1437         try {
1438             v.walkInDefaultOrder(visitor, -1, 4);
1439             Assert.fail();
1440         } catch (OutOfRangeException e) {
1441             // Expected behavior
1442         }
1443         try {
1444             v.walkInDefaultOrder(visitor, 5, 4);
1445             Assert.fail();
1446         } catch (OutOfRangeException e) {
1447             // Expected behavior
1448         }
1449         try {
1450             v.walkInDefaultOrder(visitor, 0, -1);
1451             Assert.fail();
1452         } catch (OutOfRangeException e) {
1453             // Expected behavior
1454         }
1455         try {
1456             v.walkInDefaultOrder(visitor, 0, 5);
1457             Assert.fail();
1458         } catch (OutOfRangeException e) {
1459             // Expected behavior
1460         }
1461         try {
1462             v.walkInDefaultOrder(visitor, 4, 0);
1463             Assert.fail();
1464         } catch (NumberIsTooSmallException e) {
1465             // Expected behavior
1466         }
1467     }
1468 
1469     /** Visiting a valid subvector. */
1470     @Test
1471     public void testWalkInDefaultOrderPreservingVisitor3() {
1472         final double[] data = new double[] {
1473             0d, 1d, 0d, 0d, 2d, 0d, 0d, 0d, 3d
1474         };
1475         final int expectedStart = 2;
1476         final int expectedEnd = 7;
1477         final RealVector v = create(data);
1478         final RealVectorPreservingVisitor visitor;
1479         visitor = new RealVectorPreservingVisitor() {
1480 
1481             private int expectedIndex;
1482 
1483             @Override
1484             public void visit(final int actualIndex, final double actualValue) {
1485                 Assert.assertEquals(expectedIndex, actualIndex);
1486                 Assert.assertEquals(Integer.toString(actualIndex),
1487                                     data[actualIndex], actualValue, 0d);
1488                 ++expectedIndex;
1489             }
1490 
1491             @Override
1492             public void start(final int actualSize, final int actualStart,
1493                               final int actualEnd) {
1494                 Assert.assertEquals(data.length, actualSize);
1495                 Assert.assertEquals(expectedStart, actualStart);
1496                 Assert.assertEquals(expectedEnd, actualEnd);
1497                 expectedIndex = expectedStart;
1498             }
1499 
1500             @Override
1501             public double end() {
1502                 return 0.0;
1503             }
1504         };
1505         v.walkInDefaultOrder(visitor, expectedStart, expectedEnd);
1506     }
1507 
1508     /** The whole vector is visited. */
1509     @Test
1510     public void testWalkInOptimizedOrderPreservingVisitor1() {
1511         final double[] data = new double[] {
1512             0d, 1d, 0d, 0d, 2d, 0d, 0d, 0d, 3d
1513         };
1514         final RealVector v = create(data);
1515         final RealVectorPreservingVisitor visitor;
1516         visitor = new RealVectorPreservingVisitor() {
1517             private final boolean[] visited = new boolean[data.length];
1518 
1519             @Override
1520             public void visit(final int actualIndex, final double actualValue) {
1521                 visited[actualIndex] = true;
1522                 Assert.assertEquals(Integer.toString(actualIndex),
1523                                     data[actualIndex], actualValue, 0d);
1524             }
1525 
1526             @Override
1527             public void start(final int actualSize, final int actualStart,
1528                               final int actualEnd) {
1529                 Assert.assertEquals(data.length, actualSize);
1530                 Assert.assertEquals(0, actualStart);
1531                 Assert.assertEquals(data.length - 1, actualEnd);
1532                 Arrays.fill(visited, false);
1533             }
1534 
1535             @Override
1536             public double end() {
1537                 for (int i = 0; i < data.length; i++) {
1538                     Assert.assertTrue("entry " + i + "has not been visited",
1539                                       visited[i]);
1540                 }
1541                 return 0.0;
1542             }
1543         };
1544         v.walkInOptimizedOrder(visitor);
1545     }
1546 
1547     /** Visiting an invalid subvector. */
1548     @Test
1549     public void testWalkInOptimizedOrderPreservingVisitor2() {
1550         final RealVector v = create(new double[5]);
1551         final RealVectorPreservingVisitor visitor;
1552         visitor = new RealVectorPreservingVisitor() {
1553 
1554             @Override
1555             public void visit(int index, double value) {
1556                 // Do nothing
1557             }
1558 
1559             @Override
1560             public void start(int dimension, int start, int end) {
1561                 // Do nothing
1562             }
1563 
1564             @Override
1565             public double end() {
1566                 return 0.0;
1567             }
1568         };
1569         try {
1570             v.walkInOptimizedOrder(visitor, -1, 4);
1571             Assert.fail();
1572         } catch (OutOfRangeException e) {
1573             // Expected behavior
1574         }
1575         try {
1576             v.walkInOptimizedOrder(visitor, 5, 4);
1577             Assert.fail();
1578         } catch (OutOfRangeException e) {
1579             // Expected behavior
1580         }
1581         try {
1582             v.walkInOptimizedOrder(visitor, 0, -1);
1583             Assert.fail();
1584         } catch (OutOfRangeException e) {
1585             // Expected behavior
1586         }
1587         try {
1588             v.walkInOptimizedOrder(visitor, 0, 5);
1589             Assert.fail();
1590         } catch (OutOfRangeException e) {
1591             // Expected behavior
1592         }
1593         try {
1594             v.walkInOptimizedOrder(visitor, 4, 0);
1595             Assert.fail();
1596         } catch (NumberIsTooSmallException e) {
1597             // Expected behavior
1598         }
1599     }
1600 
1601     /** Visiting a valid subvector. */
1602     @Test
1603     public void testWalkInOptimizedOrderPreservingVisitor3() {
1604         final double[] data = new double[] {
1605             0d, 1d, 0d, 0d, 2d, 0d, 0d, 0d, 3d
1606         };
1607         final int expectedStart = 2;
1608         final int expectedEnd = 7;
1609         final RealVector v = create(data);
1610         final RealVectorPreservingVisitor visitor;
1611         visitor = new RealVectorPreservingVisitor() {
1612             private final boolean[] visited = new boolean[data.length];
1613 
1614             @Override
1615             public void visit(final int actualIndex, final double actualValue) {
1616                 Assert.assertEquals(Integer.toString(actualIndex),
1617                                     data[actualIndex], actualValue, 0d);
1618                 visited[actualIndex] = true;
1619             }
1620 
1621             @Override
1622             public void start(final int actualSize, final int actualStart,
1623                               final int actualEnd) {
1624                 Assert.assertEquals(data.length, actualSize);
1625                 Assert.assertEquals(expectedStart, actualStart);
1626                 Assert.assertEquals(expectedEnd, actualEnd);
1627                 Arrays.fill(visited, true);
1628             }
1629 
1630             @Override
1631             public double end() {
1632                 for (int i = expectedStart; i <= expectedEnd; i++) {
1633                     Assert.assertTrue("entry " + i + "has not been visited",
1634                                       visited[i]);
1635                 }
1636                 return 0.0;
1637             }
1638         };
1639         v.walkInOptimizedOrder(visitor, expectedStart, expectedEnd);
1640     }
1641 
1642     /** The whole vector is visited. */
1643     @Test
1644     public void testWalkInDefaultOrderChangingVisitor1() {
1645         final double[] data = new double[] {
1646             0d, 1d, 0d, 0d, 2d, 0d, 0d, 0d, 3d
1647         };
1648         final RealVector v = create(data);
1649         final RealVectorChangingVisitor visitor;
1650         visitor = new RealVectorChangingVisitor() {
1651 
1652             private int expectedIndex;
1653 
1654             @Override
1655             public double visit(final int actualIndex, final double actualValue) {
1656                 Assert.assertEquals(expectedIndex, actualIndex);
1657                 Assert.assertEquals(Integer.toString(actualIndex),
1658                                     data[actualIndex], actualValue, 0d);
1659                 ++expectedIndex;
1660                 return actualIndex + actualValue;
1661             }
1662 
1663             @Override
1664             public void start(final int actualSize, final int actualStart,
1665                               final int actualEnd) {
1666                 Assert.assertEquals(data.length, actualSize);
1667                 Assert.assertEquals(0, actualStart);
1668                 Assert.assertEquals(data.length - 1, actualEnd);
1669                 expectedIndex = 0;
1670             }
1671 
1672             @Override
1673             public double end() {
1674                 return 0.0;
1675             }
1676         };
1677         v.walkInDefaultOrder(visitor);
1678         for (int i = 0; i < data.length; i++) {
1679             Assert.assertEquals("entry " + i, i + data[i], v.getEntry(i), 0.0);
1680         }
1681     }
1682 
1683     /** Visiting an invalid subvector. */
1684     @Test
1685     public void testWalkInDefaultOrderChangingVisitor2() {
1686         final RealVector v = create(new double[5]);
1687         final RealVectorChangingVisitor visitor;
1688         visitor = new RealVectorChangingVisitor() {
1689 
1690             @Override
1691             public double visit(int index, double value) {
1692                 return 0.0;
1693             }
1694 
1695             @Override
1696             public void start(int dimension, int start, int end) {
1697                 // Do nothing
1698             }
1699 
1700             @Override
1701             public double end() {
1702                 return 0.0;
1703             }
1704         };
1705         try {
1706             v.walkInDefaultOrder(visitor, -1, 4);
1707             Assert.fail();
1708         } catch (OutOfRangeException e) {
1709             // Expected behavior
1710         }
1711         try {
1712             v.walkInDefaultOrder(visitor, 5, 4);
1713             Assert.fail();
1714         } catch (OutOfRangeException e) {
1715             // Expected behavior
1716         }
1717         try {
1718             v.walkInDefaultOrder(visitor, 0, -1);
1719             Assert.fail();
1720         } catch (OutOfRangeException e) {
1721             // Expected behavior
1722         }
1723         try {
1724             v.walkInDefaultOrder(visitor, 0, 5);
1725             Assert.fail();
1726         } catch (OutOfRangeException e) {
1727             // Expected behavior
1728         }
1729         try {
1730             v.walkInDefaultOrder(visitor, 4, 0);
1731             Assert.fail();
1732         } catch (NumberIsTooSmallException e) {
1733             // Expected behavior
1734         }
1735     }
1736 
1737     /** Visiting a valid subvector. */
1738     @Test
1739     public void testWalkInDefaultOrderChangingVisitor3() {
1740         final double[] data = new double[] {
1741             0d, 1d, 0d, 0d, 2d, 0d, 0d, 0d, 3d
1742         };
1743         final int expectedStart = 2;
1744         final int expectedEnd = 7;
1745         final RealVector v = create(data);
1746         final RealVectorChangingVisitor visitor;
1747         visitor = new RealVectorChangingVisitor() {
1748 
1749             private int expectedIndex;
1750 
1751             @Override
1752             public double visit(final int actualIndex, final double actualValue) {
1753                 Assert.assertEquals(expectedIndex, actualIndex);
1754                 Assert.assertEquals(Integer.toString(actualIndex),
1755                                     data[actualIndex], actualValue, 0d);
1756                 ++expectedIndex;
1757                 return actualIndex + actualValue;
1758             }
1759 
1760             @Override
1761             public void start(final int actualSize, final int actualStart,
1762                               final int actualEnd) {
1763                 Assert.assertEquals(data.length, actualSize);
1764                 Assert.assertEquals(expectedStart, actualStart);
1765                 Assert.assertEquals(expectedEnd, actualEnd);
1766                 expectedIndex = expectedStart;
1767             }
1768 
1769             @Override
1770             public double end() {
1771                 return 0.0;
1772             }
1773         };
1774         v.walkInDefaultOrder(visitor, expectedStart, expectedEnd);
1775         for (int i = expectedStart; i <= expectedEnd; i++) {
1776             Assert.assertEquals("entry " + i, i + data[i], v.getEntry(i), 0.0);
1777         }
1778     }
1779 
1780     /** The whole vector is visited. */
1781     @Test
1782     public void testWalkInOptimizedOrderChangingVisitor1() {
1783         final double[] data = new double[] {
1784             0d, 1d, 0d, 0d, 2d, 0d, 0d, 0d, 3d
1785         };
1786         final RealVector v = create(data);
1787         final RealVectorChangingVisitor visitor;
1788         visitor = new RealVectorChangingVisitor() {
1789             private final boolean[] visited = new boolean[data.length];
1790 
1791             @Override
1792             public double visit(final int actualIndex, final double actualValue) {
1793                 visited[actualIndex] = true;
1794                 Assert.assertEquals(Integer.toString(actualIndex),
1795                                     data[actualIndex], actualValue, 0d);
1796                 return actualIndex + actualValue;
1797             }
1798 
1799             @Override
1800             public void start(final int actualSize, final int actualStart,
1801                               final int actualEnd) {
1802                 Assert.assertEquals(data.length, actualSize);
1803                 Assert.assertEquals(0, actualStart);
1804                 Assert.assertEquals(data.length - 1, actualEnd);
1805                 Arrays.fill(visited, false);
1806             }
1807 
1808             @Override
1809             public double end() {
1810                 for (int i = 0; i < data.length; i++) {
1811                     Assert.assertTrue("entry " + i + "has not been visited",
1812                                       visited[i]);
1813                 }
1814                 return 0.0;
1815             }
1816         };
1817         v.walkInOptimizedOrder(visitor);
1818         for (int i = 0; i < data.length; i++) {
1819             Assert.assertEquals("entry " + i, i + data[i], v.getEntry(i), 0.0);
1820         }
1821     }
1822 
1823     /** Visiting an invalid subvector. */
1824     @Test
1825     public void testWalkInOptimizedOrderChangingVisitor2() {
1826         final RealVector v = create(new double[5]);
1827         final RealVectorChangingVisitor visitor;
1828         visitor = new RealVectorChangingVisitor() {
1829 
1830             @Override
1831             public double visit(int index, double value) {
1832                 return 0.0;
1833             }
1834 
1835             @Override
1836             public void start(int dimension, int start, int end) {
1837                 // Do nothing
1838             }
1839 
1840             @Override
1841             public double end() {
1842                 return 0.0;
1843             }
1844         };
1845         try {
1846             v.walkInOptimizedOrder(visitor, -1, 4);
1847             Assert.fail();
1848         } catch (OutOfRangeException e) {
1849             // Expected behavior
1850         }
1851         try {
1852             v.walkInOptimizedOrder(visitor, 5, 4);
1853             Assert.fail();
1854         } catch (OutOfRangeException e) {
1855             // Expected behavior
1856         }
1857         try {
1858             v.walkInOptimizedOrder(visitor, 0, -1);
1859             Assert.fail();
1860         } catch (OutOfRangeException e) {
1861             // Expected behavior
1862         }
1863         try {
1864             v.walkInOptimizedOrder(visitor, 0, 5);
1865             Assert.fail();
1866         } catch (OutOfRangeException e) {
1867             // Expected behavior
1868         }
1869         try {
1870             v.walkInOptimizedOrder(visitor, 4, 0);
1871             Assert.fail();
1872         } catch (NumberIsTooSmallException e) {
1873             // Expected behavior
1874         }
1875     }
1876 
1877     /** Visiting a valid subvector. */
1878     @Test
1879     public void testWalkInOptimizedOrderChangingVisitor3() {
1880         final double[] data = new double[] {
1881             0d, 1d, 0d, 0d, 2d, 0d, 0d, 0d, 3d
1882         };
1883         final int expectedStart = 2;
1884         final int expectedEnd = 7;
1885         final RealVector v = create(data);
1886         final RealVectorChangingVisitor visitor;
1887         visitor = new RealVectorChangingVisitor() {
1888             private final boolean[] visited = new boolean[data.length];
1889 
1890             @Override
1891             public double visit(final int actualIndex, final double actualValue) {
1892                 Assert.assertEquals(Integer.toString(actualIndex),
1893                                     data[actualIndex], actualValue, 0d);
1894                 visited[actualIndex] = true;
1895                 return actualIndex + actualValue;
1896             }
1897 
1898             @Override
1899             public void start(final int actualSize, final int actualStart,
1900                               final int actualEnd) {
1901                 Assert.assertEquals(data.length, actualSize);
1902                 Assert.assertEquals(expectedStart, actualStart);
1903                 Assert.assertEquals(expectedEnd, actualEnd);
1904                 Arrays.fill(visited, true);
1905             }
1906 
1907             @Override
1908             public double end() {
1909                 for (int i = expectedStart; i <= expectedEnd; i++) {
1910                     Assert.assertTrue("entry " + i + "has not been visited",
1911                                       visited[i]);
1912                 }
1913                 return 0.0;
1914             }
1915         };
1916         v.walkInOptimizedOrder(visitor, expectedStart, expectedEnd);
1917         for (int i = expectedStart; i <= expectedEnd; i++) {
1918             Assert.assertEquals("entry " + i, i + data[i], v.getEntry(i), 0.0);
1919         }
1920     }
1921 
1922     /**
1923      * Minimal implementation of the {@link RealVector} abstract class, for
1924      * mixed types unit tests.
1925      */
1926     public static class RealVectorTestImpl extends RealVector
1927         implements Serializable {
1928 
1929         /** Serializable version identifier. */
1930         private static final long serialVersionUID = 20120706L;
1931 
1932         /** Entries of the vector. */
1933         protected double data[];
1934 
1935         public RealVectorTestImpl(double[] d) {
1936             data = d.clone();
1937         }
1938 
1939         private UnsupportedOperationException unsupported() {
1940             return new UnsupportedOperationException("Not supported, unneeded for test purposes");
1941         }
1942 
1943         @Override
1944         public RealVector copy() {
1945             return new RealVectorTestImpl(data);
1946         }
1947 
1948         @Override
1949         public RealVector ebeMultiply(RealVector v) {
1950             throw unsupported();
1951         }
1952 
1953         @Override
1954         public RealVector ebeDivide(RealVector v) {
1955             throw unsupported();
1956         }
1957 
1958         @Override
1959         public double getEntry(int index) {
1960             checkIndex(index);
1961             return data[index];
1962         }
1963 
1964         @Override
1965         public int getDimension() {
1966             return data.length;
1967         }
1968 
1969         @Override
1970         public RealVector append(RealVector v) {
1971             throw unsupported();
1972         }
1973 
1974         @Override
1975         public RealVector append(double d) {
1976             throw unsupported();
1977         }
1978 
1979         @Override
1980         public RealVector getSubVector(int index, int n) {
1981             throw unsupported();
1982         }
1983 
1984         @Override
1985         public void setEntry(int index, double value) {
1986             checkIndex(index);
1987             data[index] = value;
1988         }
1989 
1990         @Override
1991         public void setSubVector(int index, RealVector v) {
1992             throw unsupported();
1993         }
1994 
1995         @Override
1996         public boolean isNaN() {
1997             throw unsupported();
1998         }
1999 
2000         @Override
2001         public boolean isInfinite() {
2002             throw unsupported();
2003         }
2004     }
2005 }