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.math.linear;
018    
019    import java.io.Serializable;
020    import java.lang.reflect.Array;
021    import java.util.Arrays;
022    
023    import org.apache.commons.math.Field;
024    import org.apache.commons.math.FieldElement;
025    import org.apache.commons.math.MathRuntimeException;
026    
027    /**
028     * This class implements the {@link FieldVector} interface with a {@link FieldElement} array.
029     * @param <T> the type of the field elements
030     * @version $Revision: 903046 $ $Date: 2010-01-25 21:07:26 -0500 (Mon, 25 Jan 2010) $
031     * @since 2.0
032     */
033    public class ArrayFieldVector<T extends FieldElement<T>> implements FieldVector<T>, Serializable {
034    
035        /** Serializable version identifier. */
036        private static final long serialVersionUID = 7648186910365927050L;
037    
038        /** Entries of the vector. */
039        protected T[] data;
040    
041        /** Field to which the elements belong. */
042        private final Field<T> field;
043    
044        /**
045         * Build a 0-length vector.
046         * <p>Zero-length vectors may be used to initialized construction of vectors
047         * by data gathering. We start with zero-length and use either the {@link
048         * #ArrayFieldVector(ArrayFieldVector, ArrayFieldVector)} constructor
049         * or one of the <code>append</code> methods ({@link #append(FieldElement[])},
050         * {@link #add(FieldVector)}, {@link #append(ArrayFieldVector)}) to gather data
051         * into this vector.</p>
052         * @param field field to which the elements belong
053         */
054        public ArrayFieldVector(final Field<T> field) {
055            this(field, 0);
056        }
057    
058        /**
059         * Construct a (size)-length vector of zeros.
060         * @param field field to which the elements belong
061         * @param size size of the vector
062         */
063        public ArrayFieldVector(Field<T> field, int size) {
064            this.field = field;
065            data = buildArray(size);
066            Arrays.fill(data, field.getZero());
067        }
068    
069        /**
070         * Construct an (size)-length vector with preset values.
071         * @param size size of the vector
072         * @param preset fill the vector with this scalar value
073         */
074        public ArrayFieldVector(int size, T preset) {
075            this(preset.getField(), size);
076            Arrays.fill(data, preset);
077        }
078    
079        /**
080         * Construct a vector from an array, copying the input array.
081         * @param d array of Ts.
082         * @throws IllegalArgumentException if <code>d</code> is empty
083         */
084        public ArrayFieldVector(T[] d)
085            throws IllegalArgumentException {
086            try {
087                field = d[0].getField();
088                data = d.clone();
089            } catch (ArrayIndexOutOfBoundsException e) {
090                throw MathRuntimeException.createIllegalArgumentException(
091                          "vector must have at least one element");
092            }
093        }
094    
095        /**
096         * Create a new ArrayFieldVector using the input array as the underlying
097         * data array.
098         * <p>If an array is built specially in order to be embedded in a
099         * ArrayFieldVector and not used directly, the <code>copyArray</code> may be
100         * set to <code>false</code. This will prevent the copying and improve
101         * performance as no new array will be built and no data will be copied.</p>
102         * @param d data for new vector
103         * @param copyArray if true, the input array will be copied, otherwise
104         * it will be referenced
105         * @throws IllegalArgumentException if <code>d</code> is empty
106         * @throws NullPointerException if <code>d</code> is null
107         * @see #ArrayFieldVector(FieldElement[])
108         */
109        public ArrayFieldVector(T[] d, boolean copyArray)
110            throws NullPointerException, IllegalArgumentException {
111            try {
112                field = d[0].getField();
113                data = copyArray ? d.clone() :  d;
114            } catch (ArrayIndexOutOfBoundsException e) {
115                throw MathRuntimeException.createIllegalArgumentException(
116                          "vector must have at least one element");
117            }
118        }
119    
120        /**
121         * Construct a vector from part of a array.
122         * @param d array of Ts.
123         * @param pos position of first entry
124         * @param size number of entries to copy
125         */
126        public ArrayFieldVector(T[] d, int pos, int size) {
127            if (d.length < pos + size) {
128                throw MathRuntimeException.createIllegalArgumentException(
129                        "position {0} and size {1} don't fit to the size of the input array {2}",
130                        pos, size, d.length);
131            }
132            field = d[0].getField();
133            data = buildArray(size);
134            System.arraycopy(d, pos, data, 0, size);
135        }
136    
137        /**
138         * Construct a vector from another vector, using a deep copy.
139         * @param v vector to copy
140         */
141        public ArrayFieldVector(FieldVector<T> v) {
142            field = v.getField();
143            data = buildArray(v.getDimension());
144            for (int i = 0; i < data.length; ++i) {
145                data[i] = v.getEntry(i);
146            }
147        }
148    
149        /**
150         * Construct a vector from another vector, using a deep copy.
151         * @param v vector to copy
152         */
153        public ArrayFieldVector(ArrayFieldVector<T> v) {
154            field = v.getField();
155            data = v.data.clone();
156        }
157    
158        /**
159         * Construct a vector from another vector.
160         * @param v vector to copy
161         * @param deep if true perform a deep copy otherwise perform a shallow copy
162         */
163        public ArrayFieldVector(ArrayFieldVector<T> v, boolean deep) {
164            field = v.getField();
165            data = deep ? v.data.clone() : v.data;
166        }
167    
168        /**
169         * Construct a vector by appending one vector to another vector.
170         * @param v1 first vector (will be put in front of the new vector)
171         * @param v2 second vector (will be put at back of the new vector)
172         */
173        public ArrayFieldVector(ArrayFieldVector<T> v1, ArrayFieldVector<T> v2) {
174            field = v1.getField();
175            data = buildArray(v1.data.length + v2.data.length);
176            System.arraycopy(v1.data, 0, data, 0, v1.data.length);
177            System.arraycopy(v2.data, 0, data, v1.data.length, v2.data.length);
178        }
179    
180        /**
181         * Construct a vector by appending one vector to another vector.
182         * @param v1 first vector (will be put in front of the new vector)
183         * @param v2 second vector (will be put at back of the new vector)
184         */
185        public ArrayFieldVector(ArrayFieldVector<T> v1, T[] v2) {
186            field = v1.getField();
187            data = buildArray(v1.data.length + v2.length);
188            System.arraycopy(v1.data, 0, data, 0, v1.data.length);
189            System.arraycopy(v2, 0, data, v1.data.length, v2.length);
190        }
191    
192        /**
193         * Construct a vector by appending one vector to another vector.
194         * @param v1 first vector (will be put in front of the new vector)
195         * @param v2 second vector (will be put at back of the new vector)
196         */
197        public ArrayFieldVector(T[] v1, ArrayFieldVector<T> v2) {
198            field = v2.getField();
199            data = buildArray(v1.length + v2.data.length);
200            System.arraycopy(v1, 0, data, 0, v1.length);
201            System.arraycopy(v2.data, 0, data, v1.length, v2.data.length);
202        }
203    
204        /**
205         * Construct a vector by appending one vector to another vector.
206         * @param v1 first vector (will be put in front of the new vector)
207         * @param v2 second vector (will be put at back of the new vector)
208         * @exception IllegalArgumentException if both vectors are empty
209         */
210        public ArrayFieldVector(T[] v1, T[] v2) {
211            try {
212                data = buildArray(v1.length + v2.length);
213                System.arraycopy(v1, 0, data, 0, v1.length);
214                System.arraycopy(v2, 0, data, v1.length, v2.length);
215                field = data[0].getField();
216            } catch (ArrayIndexOutOfBoundsException e) {
217                throw MathRuntimeException.createIllegalArgumentException(
218                          "vector must have at least one element");
219            }
220        }
221    
222        /** Build an array of elements.
223         * @param length size of the array to build
224         * @return a new array
225         */
226        @SuppressWarnings("unchecked") // field is of type T
227        private T[] buildArray(final int length) {
228            return (T[]) Array.newInstance(field.getZero().getClass(), length);
229        }
230    
231        /** {@inheritDoc} */
232        public Field<T> getField() {
233            return field;
234        }
235    
236        /** {@inheritDoc} */
237        public FieldVector<T> copy() {
238            return new ArrayFieldVector<T>(this, true);
239        }
240    
241        /** {@inheritDoc} */
242        public FieldVector<T> add(FieldVector<T> v) throws IllegalArgumentException {
243            try {
244                return add((ArrayFieldVector<T>) v);
245            } catch (ClassCastException cce) {
246                checkVectorDimensions(v);
247                T[] out = buildArray(data.length);
248                for (int i = 0; i < data.length; i++) {
249                    out[i] = data[i].add(v.getEntry(i));
250                }
251                return new ArrayFieldVector<T>(out);
252            }
253        }
254    
255        /** {@inheritDoc} */
256        public FieldVector<T> add(T[] v) throws IllegalArgumentException {
257            checkVectorDimensions(v.length);
258            T[] out = buildArray(data.length);
259            for (int i = 0; i < data.length; i++) {
260                out[i] = data[i].add(v[i]);
261            }
262            return new ArrayFieldVector<T>(out);
263        }
264    
265        /**
266         * Compute the sum of this and v.
267         * @param v vector to be added
268         * @return this + v
269         * @throws IllegalArgumentException if v is not the same size as this
270         */
271        public ArrayFieldVector<T> add(ArrayFieldVector<T> v)
272            throws IllegalArgumentException {
273            return (ArrayFieldVector<T>) add(v.data);
274        }
275    
276        /** {@inheritDoc} */
277        public FieldVector<T> subtract(FieldVector<T> v) throws IllegalArgumentException {
278            try {
279                return subtract((ArrayFieldVector<T>) v);
280            } catch (ClassCastException cce) {
281                checkVectorDimensions(v);
282                T[] out = buildArray(data.length);
283                for (int i = 0; i < data.length; i++) {
284                    out[i] = data[i].subtract(v.getEntry(i));
285                }
286                return new ArrayFieldVector<T>(out);
287            }
288        }
289    
290        /** {@inheritDoc} */
291        public FieldVector<T> subtract(T[] v) throws IllegalArgumentException {
292            checkVectorDimensions(v.length);
293            T[] out = buildArray(data.length);
294            for (int i = 0; i < data.length; i++) {
295                out[i] = data[i].subtract(v[i]);
296            }
297            return new ArrayFieldVector<T>(out);
298        }
299    
300        /**
301         * Compute this minus v.
302         * @param v vector to be subtracted
303         * @return this + v
304         * @throws IllegalArgumentException if v is not the same size as this
305         */
306        public ArrayFieldVector<T> subtract(ArrayFieldVector<T> v)
307            throws IllegalArgumentException {
308            return (ArrayFieldVector<T>) subtract(v.data);
309        }
310    
311        /** {@inheritDoc} */
312        public FieldVector<T> mapAdd(T d) {
313            T[] out = buildArray(data.length);
314            for (int i = 0; i < data.length; i++) {
315                out[i] = data[i].add(d);
316            }
317            return new ArrayFieldVector<T>(out);
318        }
319    
320        /** {@inheritDoc} */
321        public FieldVector<T> mapAddToSelf(T d) {
322            for (int i = 0; i < data.length; i++) {
323                data[i] = data[i].add(d);
324            }
325            return this;
326        }
327    
328        /** {@inheritDoc} */
329        public FieldVector<T> mapSubtract(T d) {
330            T[] out = buildArray(data.length);
331            for (int i = 0; i < data.length; i++) {
332                out[i] = data[i].subtract(d);
333            }
334            return new ArrayFieldVector<T>(out);
335        }
336    
337        /** {@inheritDoc} */
338        public FieldVector<T> mapSubtractToSelf(T d) {
339            for (int i = 0; i < data.length; i++) {
340                data[i] = data[i].subtract(d);
341            }
342            return this;
343        }
344    
345        /** {@inheritDoc} */
346        public FieldVector<T> mapMultiply(T d) {
347            T[] out = buildArray(data.length);
348            for (int i = 0; i < data.length; i++) {
349                out[i] = data[i].multiply(d);
350            }
351            return new ArrayFieldVector<T>(out);
352        }
353    
354        /** {@inheritDoc} */
355        public FieldVector<T> mapMultiplyToSelf(T d) {
356            for (int i = 0; i < data.length; i++) {
357                data[i] = data[i].multiply(d);
358            }
359            return this;
360        }
361    
362        /** {@inheritDoc} */
363        public FieldVector<T> mapDivide(T d) {
364            T[] out = buildArray(data.length);
365            for (int i = 0; i < data.length; i++) {
366                out[i] = data[i].divide(d);
367            }
368            return new ArrayFieldVector<T>(out);
369        }
370    
371        /** {@inheritDoc} */
372        public FieldVector<T> mapDivideToSelf(T d) {
373            for (int i = 0; i < data.length; i++) {
374                data[i] = data[i].divide(d);
375            }
376            return this;
377        }
378    
379        /** {@inheritDoc} */
380        public FieldVector<T> mapInv() {
381            T[] out = buildArray(data.length);
382            final T one = field.getOne();
383            for (int i = 0; i < data.length; i++) {
384                out[i] = one.divide(data[i]);
385            }
386            return new ArrayFieldVector<T>(out);
387        }
388    
389        /** {@inheritDoc} */
390        public FieldVector<T> mapInvToSelf() {
391            final T one = field.getOne();
392            for (int i = 0; i < data.length; i++) {
393                data[i] = one.divide(data[i]);
394            }
395            return this;
396        }
397    
398        /** {@inheritDoc} */
399        public FieldVector<T> ebeMultiply(FieldVector<T> v)
400            throws IllegalArgumentException {
401            try {
402                return ebeMultiply((ArrayFieldVector<T>) v);
403            } catch (ClassCastException cce) {
404                checkVectorDimensions(v);
405                T[] out = buildArray(data.length);
406                for (int i = 0; i < data.length; i++) {
407                    out[i] = data[i].multiply(v.getEntry(i));
408                }
409                return new ArrayFieldVector<T>(out);
410            }
411        }
412    
413        /** {@inheritDoc} */
414        public FieldVector<T> ebeMultiply(T[] v)
415            throws IllegalArgumentException {
416            checkVectorDimensions(v.length);
417            T[] out = buildArray(data.length);
418            for (int i = 0; i < data.length; i++) {
419                out[i] = data[i].multiply(v[i]);
420            }
421            return new ArrayFieldVector<T>(out);
422        }
423    
424        /**
425         * Element-by-element multiplication.
426         * @param v vector by which instance elements must be multiplied
427         * @return a vector containing this[i] * v[i] for all i
428         * @exception IllegalArgumentException if v is not the same size as this
429         */
430        public ArrayFieldVector<T> ebeMultiply(ArrayFieldVector<T> v)
431            throws IllegalArgumentException {
432            return (ArrayFieldVector<T>) ebeMultiply(v.data);
433        }
434    
435        /** {@inheritDoc} */
436        public FieldVector<T> ebeDivide(FieldVector<T> v)
437            throws IllegalArgumentException {
438            try {
439                return ebeDivide((ArrayFieldVector<T>) v);
440            } catch (ClassCastException cce) {
441                checkVectorDimensions(v);
442                T[] out = buildArray(data.length);
443                for (int i = 0; i < data.length; i++) {
444                    out[i] = data[i].divide(v.getEntry(i));
445                }
446                return new ArrayFieldVector<T>(out);
447            }
448        }
449    
450        /** {@inheritDoc} */
451        public FieldVector<T> ebeDivide(T[] v)
452            throws IllegalArgumentException {
453            checkVectorDimensions(v.length);
454            T[] out = buildArray(data.length);
455            for (int i = 0; i < data.length; i++) {
456                    out[i] = data[i].divide(v[i]);
457            }
458            return new ArrayFieldVector<T>(out);
459        }
460    
461        /**
462         * Element-by-element division.
463         * @param v vector by which instance elements must be divided
464         * @return a vector containing this[i] / v[i] for all i
465         * @throws IllegalArgumentException if v is not the same size as this
466         */
467        public ArrayFieldVector<T> ebeDivide(ArrayFieldVector<T> v)
468            throws IllegalArgumentException {
469            return (ArrayFieldVector<T>) ebeDivide(v.data);
470        }
471    
472        /** {@inheritDoc} */
473        public T[] getData() {
474            return data.clone();
475        }
476    
477        /**
478         * Returns a reference to the underlying data array.
479         * <p>Does not make a fresh copy of the underlying data.</p>
480         * @return array of entries
481         */
482        public T[] getDataRef() {
483            return data;
484        }
485    
486        /** {@inheritDoc} */
487        public T dotProduct(FieldVector<T> v)
488            throws IllegalArgumentException {
489            try {
490                return dotProduct((ArrayFieldVector<T>) v);
491            } catch (ClassCastException cce) {
492                checkVectorDimensions(v);
493                T dot = field.getZero();
494                for (int i = 0; i < data.length; i++) {
495                    dot = dot.add(data[i].multiply(v.getEntry(i)));
496                }
497                return dot;
498            }
499        }
500    
501        /** {@inheritDoc} */
502        public T dotProduct(T[] v)
503            throws IllegalArgumentException {
504            checkVectorDimensions(v.length);
505            T dot = field.getZero();
506            for (int i = 0; i < data.length; i++) {
507                dot = dot.add(data[i].multiply(v[i]));
508            }
509            return dot;
510        }
511    
512        /**
513         * Compute the dot product.
514         * @param v vector with which dot product should be computed
515         * @return the scalar dot product between instance and v
516         * @exception IllegalArgumentException if v is not the same size as this
517         */
518        public T dotProduct(ArrayFieldVector<T> v)
519            throws IllegalArgumentException {
520            return dotProduct(v.data);
521        }
522    
523        /** {@inheritDoc} */
524        public FieldVector<T> projection(FieldVector<T> v) {
525            return v.mapMultiply(dotProduct(v).divide(v.dotProduct(v)));
526        }
527    
528        /** {@inheritDoc} */
529        public FieldVector<T> projection(T[] v) {
530            return projection(new ArrayFieldVector<T>(v, false));
531        }
532    
533       /** Find the orthogonal projection of this vector onto another vector.
534         * @param v vector onto which instance must be projected
535         * @return projection of the instance onto v
536         * @throws IllegalArgumentException if v is not the same size as this
537         */
538        public ArrayFieldVector<T> projection(ArrayFieldVector<T> v) {
539            return (ArrayFieldVector<T>) v.mapMultiply(dotProduct(v).divide(v.dotProduct(v)));
540        }
541    
542        /** {@inheritDoc} */
543        public FieldMatrix<T> outerProduct(FieldVector<T> v)
544            throws IllegalArgumentException {
545            try {
546                return outerProduct((ArrayFieldVector<T>) v);
547            } catch (ClassCastException cce) {
548                checkVectorDimensions(v);
549                final int m = data.length;
550                final FieldMatrix<T> out = new Array2DRowFieldMatrix<T>(field, m, m);
551                for (int i = 0; i < data.length; i++) {
552                    for (int j = 0; j < data.length; j++) {
553                        out.setEntry(i, j, data[i].multiply(v.getEntry(j)));
554                    }
555                }
556                return out;
557            }
558        }
559    
560        /**
561         * Compute the outer product.
562         * @param v vector with which outer product should be computed
563         * @return the square matrix outer product between instance and v
564         * @exception IllegalArgumentException if v is not the same size as this
565         */
566        public FieldMatrix<T> outerProduct(ArrayFieldVector<T> v)
567            throws IllegalArgumentException {
568            return outerProduct(v.data);
569        }
570    
571        /** {@inheritDoc} */
572        public FieldMatrix<T> outerProduct(T[] v)
573            throws IllegalArgumentException {
574            checkVectorDimensions(v.length);
575            final int m = data.length;
576            final FieldMatrix<T> out = new Array2DRowFieldMatrix<T>(field, m, m);
577            for (int i = 0; i < data.length; i++) {
578                for (int j = 0; j < data.length; j++) {
579                    out.setEntry(i, j, data[i].multiply(v[j]));
580                }
581            }
582            return out;
583        }
584    
585        /** {@inheritDoc} */
586        public T getEntry(int index) throws MatrixIndexException {
587            return data[index];
588        }
589    
590        /** {@inheritDoc} */
591        public int getDimension() {
592            return data.length;
593        }
594    
595        /** {@inheritDoc} */
596        public FieldVector<T> append(FieldVector<T> v) {
597            try {
598                return append((ArrayFieldVector<T>) v);
599            } catch (ClassCastException cce) {
600                return new ArrayFieldVector<T>(this,new ArrayFieldVector<T>(v));
601            }
602        }
603    
604        /**
605         * Construct a vector by appending a vector to this vector.
606         * @param v vector to append to this one.
607         * @return a new vector
608         */
609        public ArrayFieldVector<T> append(ArrayFieldVector<T> v) {
610            return new ArrayFieldVector<T>(this, v);
611        }
612    
613        /** {@inheritDoc} */
614        public FieldVector<T> append(T in) {
615            final T[] out = buildArray(data.length + 1);
616            System.arraycopy(data, 0, out, 0, data.length);
617            out[data.length] = in;
618            return new ArrayFieldVector<T>(out);
619        }
620    
621        /** {@inheritDoc} */
622        public FieldVector<T> append(T[] in) {
623            return new ArrayFieldVector<T>(this, in);
624        }
625    
626        /** {@inheritDoc} */
627        public FieldVector<T> getSubVector(int index, int n) {
628            ArrayFieldVector<T> out = new ArrayFieldVector<T>(field, n);
629            try {
630                System.arraycopy(data, index, out.data, 0, n);
631            } catch (IndexOutOfBoundsException e) {
632                checkIndex(index);
633                checkIndex(index + n - 1);
634            }
635            return out;
636        }
637    
638        /** {@inheritDoc} */
639        public void setEntry(int index, T value) {
640            try {
641                data[index] = value;
642            } catch (IndexOutOfBoundsException e) {
643                checkIndex(index);
644            }
645        }
646    
647        /** {@inheritDoc} */
648        public void setSubVector(int index, FieldVector<T> v) {
649            try {
650                try {
651                    set(index, (ArrayFieldVector<T>) v);
652                } catch (ClassCastException cce) {
653                    for (int i = index; i < index + v.getDimension(); ++i) {
654                        data[i] = v.getEntry(i-index);
655                    }
656                }
657            } catch (IndexOutOfBoundsException e) {
658                checkIndex(index);
659                checkIndex(index + v.getDimension() - 1);
660            }
661        }
662    
663        /** {@inheritDoc} */
664        public void setSubVector(int index, T[] v) {
665            try {
666                System.arraycopy(v, 0, data, index, v.length);
667            } catch (IndexOutOfBoundsException e) {
668                checkIndex(index);
669                checkIndex(index + v.length - 1);
670            }
671        }
672    
673        /**
674         * Set a set of consecutive elements.
675         *
676         * @param index index of first element to be set.
677         * @param v vector containing the values to set.
678         * @exception MatrixIndexException if the index is
679         * inconsistent with vector size
680         */
681        public void set(int index, ArrayFieldVector<T> v)
682            throws MatrixIndexException {
683            setSubVector(index, v.data);
684        }
685    
686        /** {@inheritDoc} */
687        public void set(T value) {
688            Arrays.fill(data, value);
689        }
690    
691        /** {@inheritDoc} */
692        public T[] toArray(){
693            return data.clone();
694        }
695    
696        /**
697         * Check if instance and specified vectors have the same dimension.
698         * @param v vector to compare instance with
699         * @exception IllegalArgumentException if the vectors do not
700         * have the same dimension
701         */
702        protected void checkVectorDimensions(FieldVector<T> v)
703            throws IllegalArgumentException {
704            checkVectorDimensions(v.getDimension());
705        }
706    
707        /**
708         * Check if instance dimension is equal to some expected value.
709         *
710         * @param n expected dimension.
711         * @exception IllegalArgumentException if the dimension is
712         * inconsistent with vector size
713         */
714        protected void checkVectorDimensions(int n)
715            throws IllegalArgumentException {
716            if (data.length != n) {
717                throw MathRuntimeException.createIllegalArgumentException(
718                        "vector length mismatch: got {0} but expected {1}",
719                        data.length, n);
720            }
721        }
722    
723        /**
724         * Test for the equality of two real vectors.
725         * <p>
726         * If all coordinates of two real vectors are exactly the same, and none are
727         * <code>Double.NaN</code>, the two real vectors are considered to be equal.
728         * </p>
729         * <p>
730         * <code>NaN</code> coordinates are considered to affect globally the vector
731         * and be equals to each other - i.e, if either (or all) coordinates of the
732         * real vector are equal to <code>Double.NaN</code>, the real vector is equal to
733         * a vector with all <code>Double.NaN</code> coordinates.
734         * </p>
735         *
736         * @param other Object to test for equality to this
737         * @return true if two 3D vector objects are equal, false if
738         *         object is null, not an instance of Vector3D, or
739         *         not equal to this Vector3D instance
740         *
741         */
742        @Override
743        public boolean equals(Object other) {
744    
745          if (this == other) {
746            return true;
747          }
748    
749          if (other == null) {
750            return false;
751          }
752    
753          try {
754              @SuppressWarnings("unchecked") // May fail, but we ignore ClassCastException
755              FieldVector<T> rhs = (FieldVector<T>) other;
756              if (data.length != rhs.getDimension()) {
757                  return false;
758              }
759    
760              for (int i = 0; i < data.length; ++i) {
761                  if (!data[i].equals(rhs.getEntry(i))) {
762                      return false;
763                  }
764              }
765              return true;
766    
767          } catch (ClassCastException ex) {
768              // ignore exception
769              return false;
770          }
771    
772        }
773    
774        /**
775         * Get a hashCode for the real vector.
776         * <p>All NaN values have the same hash code.</p>
777         * @return a hash code value for this object
778         */
779        @Override
780        public int hashCode() {
781            int h = 3542;
782            for (final T a : data) {
783                h = h ^ a.hashCode();
784            }
785            return h;
786        }
787    
788        /**
789         * Check if an index is valid.
790         * @param index index to check
791         * @exception MatrixIndexException if index is not valid
792         */
793        private void checkIndex(final int index)
794            throws MatrixIndexException {
795            if (index < 0 || index >= getDimension()) {
796                throw new MatrixIndexException(
797                        "index {0} out of allowed range [{1}, {2}]",
798                        index, 0, getDimension() - 1);
799            }
800        }
801    
802    }