    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    }