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