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