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  
23  import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
24  import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
25  import org.apache.commons.math4.legacy.exception.NotPositiveException;
26  import org.apache.commons.math4.legacy.exception.NullArgumentException;
27  import org.apache.commons.math4.legacy.exception.NumberIsTooLargeException;
28  import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
29  import org.apache.commons.math4.legacy.exception.OutOfRangeException;
30  import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
31  import org.apache.commons.math4.core.jdkmath.JdkMath;
32  
33  /**
34   * This class implements the {@link RealVector} interface with a double array.
35   * @since 2.0
36   */
37  public class ArrayRealVector extends RealVector implements Serializable {
38      /** Serializable version identifier. */
39      private static final long serialVersionUID = -1097961340710804027L;
40      /** Default format. */
41      private static final RealVectorFormat DEFAULT_FORMAT = RealVectorFormat.getInstance();
42  
43      /** Entries of the vector. */
44      private double[] data;
45  
46      /**
47       * Build a 0-length vector.
48       * Zero-length vectors may be used to initialized construction of vectors
49       * by data gathering. We start with zero-length and use either the {@link
50       * #ArrayRealVector(ArrayRealVector, ArrayRealVector)} constructor
51       * or one of the {@code append} method ({@link #append(double)},
52       * {@link #append(ArrayRealVector)}) to gather data into this vector.
53       */
54      public ArrayRealVector() {
55          data = new double[0];
56      }
57  
58      /**
59       * Construct a vector of zeroes.
60       *
61       * @param size Size of the vector.
62       */
63      public ArrayRealVector(int size) {
64          data = new double[size];
65      }
66  
67      /**
68       * Construct a vector with preset values.
69       *
70       * @param size Size of the vector
71       * @param preset All entries will be set with this value.
72       */
73      public ArrayRealVector(int size, double preset) {
74          data = new double[size];
75          Arrays.fill(data, preset);
76      }
77  
78      /**
79       * Construct a vector from an array, copying the input array.
80       *
81       * @param d Array.
82       */
83      public ArrayRealVector(double[] d) {
84          data = d.clone();
85      }
86  
87      /**
88       * Create a new ArrayRealVector using the input array as the underlying
89       * data array.
90       * If an array is built specially in order to be embedded in a
91       * ArrayRealVector and not used directly, the {@code copyArray} may be
92       * set to {@code false}. This will prevent the copying and improve
93       * performance as no new array will be built and no data will be copied.
94       *
95       * @param d Data for the new vector.
96       * @param copyArray if {@code true}, the input array will be copied,
97       * otherwise it will be referenced.
98       * @throws NullArgumentException if {@code d} is {@code null}.
99       * @see #ArrayRealVector(double[])
100      */
101     public ArrayRealVector(double[] d, boolean copyArray)
102         throws NullArgumentException {
103         if (d == null) {
104             throw new NullArgumentException();
105         }
106         data = copyArray ? d.clone() :  d;
107     }
108 
109     /**
110      * Construct a vector from part of a array.
111      *
112      * @param d Array.
113      * @param pos Position of first entry.
114      * @param size Number of entries to copy.
115      * @throws NullArgumentException if {@code d} is {@code null}.
116      * @throws NumberIsTooLargeException if the size of {@code d} is less
117      * than {@code pos + size}.
118      */
119     public ArrayRealVector(double[] d, int pos, int size)
120         throws NullArgumentException, NumberIsTooLargeException {
121         if (d == null) {
122             throw new NullArgumentException();
123         }
124         if (d.length < pos + size) {
125             throw new NumberIsTooLargeException(pos + size, d.length, true);
126         }
127         data = new double[size];
128         System.arraycopy(d, pos, data, 0, size);
129     }
130 
131     /**
132      * Construct a vector from an array.
133      *
134      * @param d Array of {@code Double}s.
135      */
136     public ArrayRealVector(Double[] d) {
137         data = new double[d.length];
138         for (int i = 0; i < d.length; i++) {
139             data[i] = d[i].doubleValue();
140         }
141     }
142 
143     /**
144      * Construct a vector from part of an array.
145      *
146      * @param d Array.
147      * @param pos Position of first entry.
148      * @param size Number of entries to copy.
149      * @throws NullArgumentException if {@code d} is {@code null}.
150      * @throws NumberIsTooLargeException if the size of {@code d} is less
151      * than {@code pos + size}.
152      */
153     public ArrayRealVector(Double[] d, int pos, int size)
154         throws NullArgumentException, NumberIsTooLargeException {
155         if (d == null) {
156             throw new NullArgumentException();
157         }
158         if (d.length < pos + size) {
159             throw new NumberIsTooLargeException(pos + size, d.length, true);
160         }
161         data = new double[size];
162         for (int i = pos; i < pos + size; i++) {
163             data[i - pos] = d[i].doubleValue();
164         }
165     }
166 
167     /**
168      * Construct a vector from another vector, using a deep copy.
169      *
170      * @param v vector to copy.
171      * @throws NullArgumentException if {@code v} is {@code null}.
172      */
173     public ArrayRealVector(RealVector v) throws NullArgumentException {
174         if (v == null) {
175             throw new NullArgumentException();
176         }
177         data = new double[v.getDimension()];
178         for (int i = 0; i < data.length; ++i) {
179             data[i] = v.getEntry(i);
180         }
181     }
182 
183     /**
184      * Construct a vector from another vector, using a deep copy.
185      *
186      * @param v Vector to copy.
187      * @throws NullArgumentException if {@code v} is {@code null}.
188      */
189     public ArrayRealVector(ArrayRealVector v) throws NullArgumentException {
190         this(v, true);
191     }
192 
193     /**
194      * Construct a vector from another vector.
195      *
196      * @param v Vector to copy.
197      * @param deep If {@code true} perform a deep copy, otherwise perform a
198      * shallow copy.
199      */
200     public ArrayRealVector(ArrayRealVector v, boolean deep) {
201         data = deep ? v.data.clone() : v.data;
202     }
203 
204     /**
205      * Construct a vector by appending one vector to another vector.
206      * @param v1 First vector (will be put in front of the new vector).
207      * @param v2 Second vector (will be put at back of the new vector).
208      */
209     public ArrayRealVector(ArrayRealVector v1, ArrayRealVector v2) {
210         data = new double[v1.data.length + v2.data.length];
211         System.arraycopy(v1.data, 0, data, 0, v1.data.length);
212         System.arraycopy(v2.data, 0, data, v1.data.length, v2.data.length);
213     }
214 
215     /**
216      * Construct a vector by appending one vector to another vector.
217      * @param v1 First vector (will be put in front of the new vector).
218      * @param v2 Second vector (will be put at back of the new vector).
219      */
220     public ArrayRealVector(ArrayRealVector v1, RealVector v2) {
221         final int l1 = v1.data.length;
222         final int l2 = v2.getDimension();
223         data = new double[l1 + l2];
224         System.arraycopy(v1.data, 0, data, 0, l1);
225         for (int i = 0; i < l2; ++i) {
226             data[l1 + i] = v2.getEntry(i);
227         }
228     }
229 
230     /**
231      * Construct a vector by appending one vector to another vector.
232      * @param v1 First vector (will be put in front of the new vector).
233      * @param v2 Second vector (will be put at back of the new vector).
234      */
235     public ArrayRealVector(RealVector v1, ArrayRealVector v2) {
236         final int l1 = v1.getDimension();
237         final int l2 = v2.data.length;
238         data = new double[l1 + l2];
239         for (int i = 0; i < l1; ++i) {
240             data[i] = v1.getEntry(i);
241         }
242         System.arraycopy(v2.data, 0, data, l1, l2);
243     }
244 
245     /**
246      * Construct a vector by appending one vector to another vector.
247      * @param v1 First vector (will be put in front of the new vector).
248      * @param v2 Second vector (will be put at back of the new vector).
249      */
250     public ArrayRealVector(ArrayRealVector v1, double[] v2) {
251         final int l1 = v1.getDimension();
252         final int l2 = v2.length;
253         data = new double[l1 + l2];
254         System.arraycopy(v1.data, 0, data, 0, l1);
255         System.arraycopy(v2, 0, data, l1, l2);
256     }
257 
258     /**
259      * Construct a vector by appending one vector to another vector.
260      * @param v1 First vector (will be put in front of the new vector).
261      * @param v2 Second vector (will be put at back of the new vector).
262      */
263     public ArrayRealVector(double[] v1, ArrayRealVector v2) {
264         final int l1 = v1.length;
265         final int l2 = v2.getDimension();
266         data = new double[l1 + l2];
267         System.arraycopy(v1, 0, data, 0, l1);
268         System.arraycopy(v2.data, 0, data, l1, l2);
269     }
270 
271     /**
272      * Construct a vector by appending one vector to another vector.
273      * @param v1 first vector (will be put in front of the new vector)
274      * @param v2 second vector (will be put at back of the new vector)
275      */
276     public ArrayRealVector(double[] v1, double[] v2) {
277         final int l1 = v1.length;
278         final int l2 = v2.length;
279         data = new double[l1 + l2];
280         System.arraycopy(v1, 0, data, 0, l1);
281         System.arraycopy(v2, 0, data, l1, l2);
282     }
283 
284     /** {@inheritDoc} */
285     @Override
286     public ArrayRealVector copy() {
287         return new ArrayRealVector(this, true);
288     }
289 
290     /** {@inheritDoc} */
291     @Override
292     public ArrayRealVector add(RealVector v)
293         throws DimensionMismatchException {
294         if (v instanceof ArrayRealVector) {
295             final double[] vData = ((ArrayRealVector) v).data;
296             final int dim = vData.length;
297             checkVectorDimensions(dim);
298             ArrayRealVector result = new ArrayRealVector(dim);
299             double[] resultData = result.data;
300             for (int i = 0; i < dim; i++) {
301                 resultData[i] = data[i] + vData[i];
302             }
303             return result;
304         } else {
305             checkVectorDimensions(v);
306             double[] out = data.clone();
307             Iterator<Entry> it = v.iterator();
308             while (it.hasNext()) {
309                 final Entry e = it.next();
310                 out[e.getIndex()] += e.getValue();
311             }
312             return new ArrayRealVector(out, false);
313         }
314     }
315 
316     /** {@inheritDoc} */
317     @Override
318     public ArrayRealVector subtract(RealVector v)
319         throws DimensionMismatchException {
320         if (v instanceof ArrayRealVector) {
321             final double[] vData = ((ArrayRealVector) v).data;
322             final int dim = vData.length;
323             checkVectorDimensions(dim);
324             ArrayRealVector result = new ArrayRealVector(dim);
325             double[] resultData = result.data;
326             for (int i = 0; i < dim; i++) {
327                 resultData[i] = data[i] - vData[i];
328             }
329             return result;
330         } else {
331             checkVectorDimensions(v);
332             double[] out = data.clone();
333             Iterator<Entry> it = v.iterator();
334             while (it.hasNext()) {
335                 final Entry e = it.next();
336                 out[e.getIndex()] -= e.getValue();
337             }
338             return new ArrayRealVector(out, false);
339         }
340     }
341 
342     /** {@inheritDoc} */
343     @Override
344     public ArrayRealVector map(UnivariateFunction function) {
345         return copy().mapToSelf(function);
346     }
347 
348     /** {@inheritDoc} */
349     @Override
350     public ArrayRealVector mapToSelf(UnivariateFunction function) {
351         for (int i = 0; i < data.length; i++) {
352             data[i] = function.value(data[i]);
353         }
354         return this;
355     }
356 
357     /** {@inheritDoc} */
358     @Override
359     public RealVector mapAddToSelf(double d) {
360         for (int i = 0; i < data.length; i++) {
361             data[i] += d;
362         }
363         return this;
364     }
365 
366     /** {@inheritDoc} */
367     @Override
368     public RealVector mapSubtractToSelf(double d) {
369         for (int i = 0; i < data.length; i++) {
370             data[i] -= d;
371         }
372         return this;
373     }
374 
375     /** {@inheritDoc} */
376     @Override
377     public RealVector mapMultiplyToSelf(double d) {
378         for (int i = 0; i < data.length; i++) {
379             data[i] *= d;
380         }
381         return this;
382     }
383 
384     /** {@inheritDoc} */
385     @Override
386     public RealVector mapDivideToSelf(double d) {
387         for (int i = 0; i < data.length; i++) {
388             data[i] /= d;
389         }
390         return this;
391     }
392 
393     /** {@inheritDoc} */
394     @Override
395     public ArrayRealVector ebeMultiply(RealVector v)
396         throws DimensionMismatchException {
397         if (v instanceof ArrayRealVector) {
398             final double[] vData = ((ArrayRealVector) v).data;
399             final int dim = vData.length;
400             checkVectorDimensions(dim);
401             ArrayRealVector result = new ArrayRealVector(dim);
402             double[] resultData = result.data;
403             for (int i = 0; i < dim; i++) {
404                 resultData[i] = data[i] * vData[i];
405             }
406             return result;
407         } else {
408             checkVectorDimensions(v);
409             double[] out = data.clone();
410             for (int i = 0; i < data.length; i++) {
411                 out[i] *= v.getEntry(i);
412             }
413             return new ArrayRealVector(out, false);
414         }
415     }
416 
417     /** {@inheritDoc} */
418     @Override
419     public ArrayRealVector ebeDivide(RealVector v)
420         throws DimensionMismatchException {
421         if (v instanceof ArrayRealVector) {
422             final double[] vData = ((ArrayRealVector) v).data;
423             final int dim = vData.length;
424             checkVectorDimensions(dim);
425             ArrayRealVector result = new ArrayRealVector(dim);
426             double[] resultData = result.data;
427             for (int i = 0; i < dim; i++) {
428                 resultData[i] = data[i] / vData[i];
429             }
430             return result;
431         } else {
432             checkVectorDimensions(v);
433             double[] out = data.clone();
434             for (int i = 0; i < data.length; i++) {
435                 out[i] /= v.getEntry(i);
436             }
437             return new ArrayRealVector(out, false);
438         }
439     }
440 
441     /**
442      * Get a reference to the underlying data array.
443      * This method does not make a fresh copy of the underlying data.
444      *
445      * @return the array of entries.
446      */
447     public double[] getDataRef() {
448         return data;
449     }
450 
451     /** {@inheritDoc} */
452     @Override
453     public double dotProduct(RealVector v) throws DimensionMismatchException {
454         if (v instanceof ArrayRealVector) {
455             final double[] vData = ((ArrayRealVector) v).data;
456             checkVectorDimensions(vData.length);
457             double dot = 0;
458             for (int i = 0; i < data.length; i++) {
459                 dot += data[i] * vData[i];
460             }
461             return dot;
462         }
463         return super.dotProduct(v);
464     }
465 
466     /** {@inheritDoc} */
467     @Override
468     public double getNorm() {
469         double sum = 0;
470         for (double a : data) {
471             sum += a * a;
472         }
473         return JdkMath.sqrt(sum);
474     }
475 
476     /** {@inheritDoc} */
477     @Override
478     public double getL1Norm() {
479         double sum = 0;
480         for (double a : data) {
481             sum += JdkMath.abs(a);
482         }
483         return sum;
484     }
485 
486     /** {@inheritDoc} */
487     @Override
488     public double getLInfNorm() {
489         double max = 0;
490         for (double a : data) {
491             max = JdkMath.max(max, JdkMath.abs(a));
492         }
493         return max;
494     }
495 
496     /** {@inheritDoc} */
497     @Override
498     public double getDistance(RealVector v) throws DimensionMismatchException {
499         if (v instanceof ArrayRealVector) {
500             final double[] vData = ((ArrayRealVector) v).data;
501             checkVectorDimensions(vData.length);
502             double sum = 0;
503             for (int i = 0; i < data.length; ++i) {
504                 final double delta = data[i] - vData[i];
505                 sum += delta * delta;
506             }
507             return JdkMath.sqrt(sum);
508         } else {
509             checkVectorDimensions(v);
510             double sum = 0;
511             for (int i = 0; i < data.length; ++i) {
512                 final double delta = data[i] - v.getEntry(i);
513                 sum += delta * delta;
514             }
515             return JdkMath.sqrt(sum);
516         }
517     }
518 
519     /** {@inheritDoc} */
520     @Override
521     public double getL1Distance(RealVector v)
522         throws DimensionMismatchException {
523         if (v instanceof ArrayRealVector) {
524             final double[] vData = ((ArrayRealVector) v).data;
525             checkVectorDimensions(vData.length);
526             double sum = 0;
527             for (int i = 0; i < data.length; ++i) {
528                 final double delta = data[i] - vData[i];
529                 sum += JdkMath.abs(delta);
530             }
531             return sum;
532         } else {
533             checkVectorDimensions(v);
534             double sum = 0;
535             for (int i = 0; i < data.length; ++i) {
536                 final double delta = data[i] - v.getEntry(i);
537                 sum += JdkMath.abs(delta);
538             }
539             return sum;
540         }
541     }
542 
543     /** {@inheritDoc} */
544     @Override
545     public double getLInfDistance(RealVector v)
546         throws DimensionMismatchException {
547         if (v instanceof ArrayRealVector) {
548             final double[] vData = ((ArrayRealVector) v).data;
549             checkVectorDimensions(vData.length);
550             double max = 0;
551             for (int i = 0; i < data.length; ++i) {
552                 final double delta = data[i] - vData[i];
553                 max = JdkMath.max(max, JdkMath.abs(delta));
554             }
555             return max;
556         } else {
557             checkVectorDimensions(v);
558             double max = 0;
559             for (int i = 0; i < data.length; ++i) {
560                 final double delta = data[i] - v.getEntry(i);
561                 max = JdkMath.max(max, JdkMath.abs(delta));
562             }
563             return max;
564         }
565     }
566 
567     /** {@inheritDoc} */
568     @Override
569     public RealMatrix outerProduct(RealVector v) {
570         if (v instanceof ArrayRealVector) {
571             final double[] vData = ((ArrayRealVector) v).data;
572             final int m = data.length;
573             final int n = vData.length;
574             final RealMatrix out = MatrixUtils.createRealMatrix(m, n);
575             for (int i = 0; i < m; i++) {
576                 for (int j = 0; j < n; j++) {
577                     out.setEntry(i, j, data[i] * vData[j]);
578                 }
579             }
580             return out;
581         } else {
582             final int m = data.length;
583             final int n = v.getDimension();
584             final RealMatrix out = MatrixUtils.createRealMatrix(m, n);
585             for (int i = 0; i < m; i++) {
586                 for (int j = 0; j < n; j++) {
587                     out.setEntry(i, j, data[i] * v.getEntry(j));
588                 }
589             }
590             return out;
591         }
592     }
593 
594     /** {@inheritDoc} */
595     @Override
596     public double getEntry(int index) throws OutOfRangeException {
597         try {
598             return data[index];
599         } catch (IndexOutOfBoundsException e) {
600             throw new OutOfRangeException(LocalizedFormats.INDEX, index, 0,
601                 getDimension() - 1);
602         }
603     }
604 
605     /** {@inheritDoc} */
606     @Override
607     public int getDimension() {
608         return data.length;
609     }
610 
611     /** {@inheritDoc} */
612     @Override
613     public RealVector append(RealVector v) {
614         if (v instanceof ArrayRealVector) {
615             return new ArrayRealVector(this, (ArrayRealVector) v);
616         }
617         return new ArrayRealVector(this, v);
618     }
619 
620     /**
621      * Construct a vector by appending a vector to this vector.
622      *
623      * @param v Vector to append to this one.
624      * @return a new vector.
625      */
626     public ArrayRealVector append(ArrayRealVector v) {
627         return new ArrayRealVector(this, v);
628     }
629 
630     /** {@inheritDoc} */
631     @Override
632     public RealVector append(double in) {
633         final double[] out = new double[data.length + 1];
634         System.arraycopy(data, 0, out, 0, data.length);
635         out[data.length] = in;
636         return new ArrayRealVector(out, false);
637     }
638 
639     /** {@inheritDoc} */
640     @Override
641     public RealVector getSubVector(int index, int n)
642         throws OutOfRangeException, NotPositiveException {
643         if (n < 0) {
644             throw new NotPositiveException(LocalizedFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, n);
645         }
646         ArrayRealVector out = new ArrayRealVector(n);
647         try {
648             System.arraycopy(data, index, out.data, 0, n);
649         } catch (IndexOutOfBoundsException e) {
650             checkIndex(index);
651             checkIndex(index + n - 1);
652         }
653         return out;
654     }
655 
656     /** {@inheritDoc} */
657     @Override
658     public void setEntry(int index, double value) throws OutOfRangeException {
659         try {
660             data[index] = value;
661         } catch (IndexOutOfBoundsException e) {
662             checkIndex(index);
663         }
664     }
665 
666     /** {@inheritDoc} */
667     @Override
668     public void addToEntry(int index, double increment)
669         throws OutOfRangeException {
670         try {
671         data[index] += increment;
672         } catch(IndexOutOfBoundsException e){
673             throw new OutOfRangeException(LocalizedFormats.INDEX,
674                                           index, 0, data.length - 1);
675         }
676     }
677 
678     /** {@inheritDoc} */
679     @Override
680     public void setSubVector(int index, RealVector v)
681         throws OutOfRangeException {
682         if (v instanceof ArrayRealVector) {
683             setSubVector(index, ((ArrayRealVector) v).data);
684         } else {
685             try {
686                 for (int i = index; i < index + v.getDimension(); ++i) {
687                     data[i] = v.getEntry(i - index);
688                 }
689             } catch (IndexOutOfBoundsException e) {
690                 checkIndex(index);
691                 checkIndex(index + v.getDimension() - 1);
692             }
693         }
694     }
695 
696     /**
697      * Set a set of consecutive elements.
698      *
699      * @param index Index of first element to be set.
700      * @param v Vector containing the values to set.
701      * @throws OutOfRangeException if the index is inconsistent with the vector
702      * size.
703      */
704     public void setSubVector(int index, double[] v)
705         throws OutOfRangeException {
706         try {
707             System.arraycopy(v, 0, data, index, v.length);
708         } catch (IndexOutOfBoundsException e) {
709             checkIndex(index);
710             checkIndex(index + v.length - 1);
711         }
712     }
713 
714     /** {@inheritDoc} */
715     @Override
716     public void set(double value) {
717         Arrays.fill(data, value);
718     }
719 
720     /** {@inheritDoc} */
721     @Override
722     public double[] toArray(){
723         return data.clone();
724     }
725 
726     /** {@inheritDoc} */
727     @Override
728     public String toString(){
729         return DEFAULT_FORMAT.format(this);
730     }
731 
732     /**
733      * Check if instance and specified vectors have the same dimension.
734      *
735      * @param v Vector to compare instance with.
736      * @throws DimensionMismatchException if the vectors do not
737      * have the same dimension.
738      */
739     @Override
740     protected void checkVectorDimensions(RealVector v)
741         throws DimensionMismatchException {
742         checkVectorDimensions(v.getDimension());
743     }
744 
745     /**
746      * Check if instance dimension is equal to some expected value.
747      *
748      * @param n Expected dimension.
749      * @throws DimensionMismatchException if the dimension is
750      * inconsistent with vector size.
751      */
752     @Override
753     protected void checkVectorDimensions(int n)
754         throws DimensionMismatchException {
755         if (data.length != n) {
756             throw new DimensionMismatchException(data.length, n);
757         }
758     }
759 
760     /**
761      * Check if any coordinate of this vector is {@code NaN}.
762      *
763      * @return {@code true} if any coordinate of this vector is {@code NaN},
764      * {@code false} otherwise.
765      */
766     @Override
767     public boolean isNaN() {
768         for (double v : data) {
769             if (Double.isNaN(v)) {
770                 return true;
771             }
772         }
773         return false;
774     }
775 
776     /**
777      * Check whether any coordinate of this vector is infinite and none
778      * are {@code NaN}.
779      *
780      * @return {@code true} if any coordinate of this vector is infinite and
781      * none are {@code NaN}, {@code false} otherwise.
782      */
783     @Override
784     public boolean isInfinite() {
785         if (isNaN()) {
786             return false;
787         }
788 
789         for (double v : data) {
790             if (Double.isInfinite(v)) {
791                 return true;
792             }
793         }
794 
795         return false;
796     }
797 
798     /** {@inheritDoc} */
799     @Override
800     public boolean equals(Object other) {
801         if (this == other) {
802             return true;
803         }
804 
805         if (!(other instanceof RealVector)) {
806             return false;
807         }
808 
809         RealVector rhs = (RealVector) other;
810         if (data.length != rhs.getDimension()) {
811             return false;
812         }
813 
814         if (rhs.isNaN()) {
815             return this.isNaN();
816         }
817 
818         for (int i = 0; i < data.length; ++i) {
819             if (data[i] != rhs.getEntry(i)) {
820                 return false;
821             }
822         }
823         return true;
824     }
825 
826     /**
827      * {@inheritDoc} All {@code NaN} values have the same hash code.
828      */
829     @Override
830     public int hashCode() {
831         if (isNaN()) {
832             return 9;
833         }
834         return Arrays.hashCode(data);
835     }
836 
837     /** {@inheritDoc} */
838     @Override
839     public ArrayRealVector combine(double a, double b, RealVector y)
840         throws DimensionMismatchException {
841         return copy().combineToSelf(a, b, y);
842     }
843 
844     /** {@inheritDoc} */
845     @Override
846     public ArrayRealVector combineToSelf(double a, double b, RealVector y)
847         throws DimensionMismatchException {
848         if (y instanceof ArrayRealVector) {
849             final double[] yData = ((ArrayRealVector) y).data;
850             checkVectorDimensions(yData.length);
851             for (int i = 0; i < this.data.length; i++) {
852                 data[i] = a * data[i] + b * yData[i];
853             }
854         } else {
855             checkVectorDimensions(y);
856             for (int i = 0; i < this.data.length; i++) {
857                 data[i] = a * data[i] + b * y.getEntry(i);
858             }
859         }
860         return this;
861     }
862 
863     /** {@inheritDoc} */
864     @Override
865     public double walkInDefaultOrder(final RealVectorPreservingVisitor visitor) {
866         visitor.start(data.length, 0, data.length - 1);
867         for (int i = 0; i < data.length; i++) {
868             visitor.visit(i, data[i]);
869         }
870         return visitor.end();
871     }
872 
873     /** {@inheritDoc} */
874     @Override
875     public double walkInDefaultOrder(final RealVectorPreservingVisitor visitor,
876         final int start, final int end) throws NumberIsTooSmallException,
877         OutOfRangeException {
878         checkIndices(start, end);
879         visitor.start(data.length, start, end);
880         for (int i = start; i <= end; i++) {
881             visitor.visit(i, data[i]);
882         }
883         return visitor.end();
884     }
885 
886     /**
887      * {@inheritDoc}
888      *
889      * In this implementation, the optimized order is the default order.
890      */
891     @Override
892     public double walkInOptimizedOrder(final RealVectorPreservingVisitor visitor) {
893         return walkInDefaultOrder(visitor);
894     }
895 
896     /**
897      * {@inheritDoc}
898      *
899      * In this implementation, the optimized order is the default order.
900      */
901     @Override
902     public double walkInOptimizedOrder(final RealVectorPreservingVisitor visitor,
903         final int start, final int end) throws NumberIsTooSmallException,
904         OutOfRangeException {
905         return walkInDefaultOrder(visitor, start, end);
906     }
907 
908     /** {@inheritDoc} */
909     @Override
910     public double walkInDefaultOrder(final RealVectorChangingVisitor visitor) {
911         visitor.start(data.length, 0, data.length - 1);
912         for (int i = 0; i < data.length; i++) {
913             data[i] = visitor.visit(i, data[i]);
914         }
915         return visitor.end();
916     }
917 
918     /** {@inheritDoc} */
919     @Override
920     public double walkInDefaultOrder(final RealVectorChangingVisitor visitor,
921         final int start, final int end) throws NumberIsTooSmallException,
922         OutOfRangeException {
923         checkIndices(start, end);
924         visitor.start(data.length, start, end);
925         for (int i = start; i <= end; i++) {
926             data[i] = visitor.visit(i, data[i]);
927         }
928         return visitor.end();
929     }
930 
931     /**
932      * {@inheritDoc}
933      *
934      * In this implementation, the optimized order is the default order.
935      */
936     @Override
937     public double walkInOptimizedOrder(final RealVectorChangingVisitor visitor) {
938         return walkInDefaultOrder(visitor);
939     }
940 
941     /**
942      * {@inheritDoc}
943      *
944      * In this implementation, the optimized order is the default order.
945      */
946     @Override
947     public double walkInOptimizedOrder(final RealVectorChangingVisitor visitor,
948         final int start, final int end) throws NumberIsTooSmallException,
949         OutOfRangeException {
950         return walkInDefaultOrder(visitor, start, end);
951     }
952 }