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