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.math3.linear;
018
019import java.io.Serializable;
020import java.util.Arrays;
021import java.util.Iterator;
022
023import org.apache.commons.math3.analysis.UnivariateFunction;
024import org.apache.commons.math3.exception.NotPositiveException;
025import org.apache.commons.math3.exception.NullArgumentException;
026import org.apache.commons.math3.exception.DimensionMismatchException;
027import org.apache.commons.math3.exception.NumberIsTooLargeException;
028import org.apache.commons.math3.exception.NumberIsTooSmallException;
029import org.apache.commons.math3.exception.OutOfRangeException;
030import org.apache.commons.math3.exception.util.LocalizedFormats;
031import org.apache.commons.math3.util.MathUtils;
032import org.apache.commons.math3.util.FastMath;
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        try {
616            return new ArrayRealVector(this, (ArrayRealVector) v);
617        } catch (ClassCastException cce) {
618            return new ArrayRealVector(this, v);
619        }
620    }
621
622    /**
623     * Construct a vector by appending a vector to this vector.
624     *
625     * @param v Vector to append to this one.
626     * @return a new vector.
627     */
628    public ArrayRealVector append(ArrayRealVector v) {
629        return new ArrayRealVector(this, v);
630    }
631
632    /** {@inheritDoc} */
633    @Override
634    public RealVector append(double in) {
635        final double[] out = new double[data.length + 1];
636        System.arraycopy(data, 0, out, 0, data.length);
637        out[data.length] = in;
638        return new ArrayRealVector(out, false);
639    }
640
641    /** {@inheritDoc} */
642    @Override
643    public RealVector getSubVector(int index, int n)
644        throws OutOfRangeException, NotPositiveException {
645        if (n < 0) {
646            throw new NotPositiveException(LocalizedFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, n);
647        }
648        ArrayRealVector out = new ArrayRealVector(n);
649        try {
650            System.arraycopy(data, index, out.data, 0, n);
651        } catch (IndexOutOfBoundsException e) {
652            checkIndex(index);
653            checkIndex(index + n - 1);
654        }
655        return out;
656    }
657
658    /** {@inheritDoc} */
659    @Override
660    public void setEntry(int index, double value) throws OutOfRangeException {
661        try {
662            data[index] = value;
663        } catch (IndexOutOfBoundsException e) {
664            checkIndex(index);
665        }
666    }
667
668    /** {@inheritDoc} */
669    @Override
670    public void addToEntry(int index, double increment)
671        throws OutOfRangeException {
672        try {
673        data[index] += increment;
674        } catch(IndexOutOfBoundsException e){
675            throw new OutOfRangeException(LocalizedFormats.INDEX,
676                                          index, 0, data.length - 1);
677        }
678    }
679
680    /** {@inheritDoc} */
681    @Override
682    public void setSubVector(int index, RealVector v)
683        throws OutOfRangeException {
684        if (v instanceof ArrayRealVector) {
685            setSubVector(index, ((ArrayRealVector) v).data);
686        } else {
687            try {
688                for (int i = index; i < index + v.getDimension(); ++i) {
689                    data[i] = v.getEntry(i - index);
690                }
691            } catch (IndexOutOfBoundsException e) {
692                checkIndex(index);
693                checkIndex(index + v.getDimension() - 1);
694            }
695        }
696    }
697
698    /**
699     * Set a set of consecutive elements.
700     *
701     * @param index Index of first element to be set.
702     * @param v Vector containing the values to set.
703     * @throws OutOfRangeException if the index is inconsistent with the vector
704     * size.
705     */
706    public void setSubVector(int index, double[] v)
707        throws OutOfRangeException {
708        try {
709            System.arraycopy(v, 0, data, index, v.length);
710        } catch (IndexOutOfBoundsException e) {
711            checkIndex(index);
712            checkIndex(index + v.length - 1);
713        }
714    }
715
716    /** {@inheritDoc} */
717    @Override
718    public void set(double value) {
719        Arrays.fill(data, value);
720    }
721
722    /** {@inheritDoc} */
723    @Override
724    public double[] toArray(){
725        return data.clone();
726    }
727
728    /** {@inheritDoc} */
729    @Override
730    public String toString(){
731        return DEFAULT_FORMAT.format(this);
732    }
733
734    /**
735     * Check if instance and specified vectors have the same dimension.
736     *
737     * @param v Vector to compare instance with.
738     * @throws DimensionMismatchException if the vectors do not
739     * have the same dimension.
740     */
741    @Override
742    protected void checkVectorDimensions(RealVector v)
743        throws DimensionMismatchException {
744        checkVectorDimensions(v.getDimension());
745    }
746
747    /**
748     * Check if instance dimension is equal to some expected value.
749     *
750     * @param n Expected dimension.
751     * @throws DimensionMismatchException if the dimension is
752     * inconsistent with vector size.
753     */
754    @Override
755    protected void checkVectorDimensions(int n)
756        throws DimensionMismatchException {
757        if (data.length != n) {
758            throw new DimensionMismatchException(data.length, n);
759        }
760    }
761
762    /**
763     * Check if any coordinate of this vector is {@code NaN}.
764     *
765     * @return {@code true} if any coordinate of this vector is {@code NaN},
766     * {@code false} otherwise.
767     */
768    @Override
769    public boolean isNaN() {
770        for (double v : data) {
771            if (Double.isNaN(v)) {
772                return true;
773            }
774        }
775        return false;
776    }
777
778    /**
779     * Check whether any coordinate of this vector is infinite and none
780     * are {@code NaN}.
781     *
782     * @return {@code true} if any coordinate of this vector is infinite and
783     * none are {@code NaN}, {@code false} otherwise.
784     */
785    @Override
786    public boolean isInfinite() {
787        if (isNaN()) {
788            return false;
789        }
790
791        for (double v : data) {
792            if (Double.isInfinite(v)) {
793                return true;
794            }
795        }
796
797        return false;
798    }
799
800    /** {@inheritDoc} */
801    @Override
802    public boolean equals(Object other) {
803        if (this == other) {
804            return true;
805        }
806
807        if (!(other instanceof RealVector)) {
808            return false;
809        }
810
811        RealVector rhs = (RealVector) other;
812        if (data.length != rhs.getDimension()) {
813            return false;
814        }
815
816        if (rhs.isNaN()) {
817            return this.isNaN();
818        }
819
820        for (int i = 0; i < data.length; ++i) {
821            if (data[i] != rhs.getEntry(i)) {
822                return false;
823            }
824        }
825        return true;
826    }
827
828    /**
829     * {@inheritDoc} All {@code NaN} values have the same hash code.
830     */
831    @Override
832    public int hashCode() {
833        if (isNaN()) {
834            return 9;
835        }
836        return MathUtils.hash(data);
837    }
838
839    /** {@inheritDoc} */
840    @Override
841    public ArrayRealVector combine(double a, double b, RealVector y)
842        throws DimensionMismatchException {
843        return copy().combineToSelf(a, b, y);
844    }
845
846    /** {@inheritDoc} */
847    @Override
848    public ArrayRealVector combineToSelf(double a, double b, RealVector y)
849        throws DimensionMismatchException {
850        if (y instanceof ArrayRealVector) {
851            final double[] yData = ((ArrayRealVector) y).data;
852            checkVectorDimensions(yData.length);
853            for (int i = 0; i < this.data.length; i++) {
854                data[i] = a * data[i] + b * yData[i];
855            }
856        } else {
857            checkVectorDimensions(y);
858            for (int i = 0; i < this.data.length; i++) {
859                data[i] = a * data[i] + b * y.getEntry(i);
860            }
861        }
862        return this;
863    }
864
865    /** {@inheritDoc} */
866    @Override
867    public double walkInDefaultOrder(final RealVectorPreservingVisitor visitor) {
868        visitor.start(data.length, 0, data.length - 1);
869        for (int i = 0; i < data.length; i++) {
870            visitor.visit(i, data[i]);
871        }
872        return visitor.end();
873    }
874
875    /** {@inheritDoc} */
876    @Override
877    public double walkInDefaultOrder(final RealVectorPreservingVisitor visitor,
878        final int start, final int end) throws NumberIsTooSmallException,
879        OutOfRangeException {
880        checkIndices(start, end);
881        visitor.start(data.length, start, end);
882        for (int i = start; i <= end; i++) {
883            visitor.visit(i, data[i]);
884        }
885        return visitor.end();
886    }
887
888    /**
889     * {@inheritDoc}
890     *
891     * In this implementation, the optimized order is the default order.
892     */
893    @Override
894    public double walkInOptimizedOrder(final RealVectorPreservingVisitor visitor) {
895        return walkInDefaultOrder(visitor);
896    }
897
898    /**
899     * {@inheritDoc}
900     *
901     * In this implementation, the optimized order is the default order.
902     */
903    @Override
904    public double walkInOptimizedOrder(final RealVectorPreservingVisitor visitor,
905        final int start, final int end) throws NumberIsTooSmallException,
906        OutOfRangeException {
907        return walkInDefaultOrder(visitor, start, end);
908    }
909
910    /** {@inheritDoc} */
911    @Override
912    public double walkInDefaultOrder(final RealVectorChangingVisitor visitor) {
913        visitor.start(data.length, 0, data.length - 1);
914        for (int i = 0; i < data.length; i++) {
915            data[i] = visitor.visit(i, data[i]);
916        }
917        return visitor.end();
918    }
919
920    /** {@inheritDoc} */
921    @Override
922    public double walkInDefaultOrder(final RealVectorChangingVisitor visitor,
923        final int start, final int end) throws NumberIsTooSmallException,
924        OutOfRangeException {
925        checkIndices(start, end);
926        visitor.start(data.length, start, end);
927        for (int i = start; i <= end; i++) {
928            data[i] = visitor.visit(i, data[i]);
929        }
930        return visitor.end();
931    }
932
933    /**
934     * {@inheritDoc}
935     *
936     * In this implementation, the optimized order is the default order.
937     */
938    @Override
939    public double walkInOptimizedOrder(final RealVectorChangingVisitor visitor) {
940        return walkInDefaultOrder(visitor);
941    }
942
943    /**
944     * {@inheritDoc}
945     *
946     * In this implementation, the optimized order is the default order.
947     */
948    @Override
949    public double walkInOptimizedOrder(final RealVectorChangingVisitor visitor,
950        final int start, final int end) throws NumberIsTooSmallException,
951        OutOfRangeException {
952        return walkInDefaultOrder(visitor, start, end);
953    }
954}