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: 783702 $ $Date: 2009-06-11 04:54:02 -0400 (Thu, 11 Jun 2009) $
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 /** Field to which the elements belong. */
039 private final Field<T> field;
040
041 /** Entries of the vector. */
042 protected T[] data;
043
044 /** Build an array of elements.
045 * @param length size of the array to build
046 * @return a new array
047 */
048 @SuppressWarnings("unchecked")
049 private T[] buildArray(final int length) {
050 return (T[]) Array.newInstance(field.getZero().getClass(), length);
051 }
052
053 /**
054 * Build a 0-length vector.
055 * <p>Zero-length vectors may be used to initialized construction of vectors
056 * by data gathering. We start with zero-length and use either the {@link
057 * #ArrayFieldVector(ArrayFieldVector, ArrayFieldVector)} constructor
058 * or one of the <code>append</code> methods ({@link #append(FieldElement[])},
059 * {@link #add(FieldVector)}, {@link #append(ArrayFieldVector)}) to gather data
060 * into this vector.</p>
061 * @param field field to which the elements belong
062 */
063 public ArrayFieldVector(final Field<T> field) {
064 this(field, 0);
065 }
066
067 /**
068 * Construct a (size)-length vector of zeros.
069 * @param field field to which the elements belong
070 * @param size size of the vector
071 */
072 public ArrayFieldVector(Field<T> field, int size) {
073 this.field = field;
074 data = buildArray(size);
075 Arrays.fill(data, field.getZero());
076 }
077
078 /**
079 * Construct an (size)-length vector with preset values.
080 * @param size size of the vector
081 * @param preset fill the vector with this scalar value
082 */
083 public ArrayFieldVector(int size, T preset) {
084 this(preset.getField(), size);
085 Arrays.fill(data, preset);
086 }
087
088 /**
089 * Construct a vector from an array, copying the input array.
090 * @param d array of Ts.
091 * @throws IllegalArgumentException if <code>d</code> is empty
092 */
093 public ArrayFieldVector(T[] d)
094 throws IllegalArgumentException {
095 try {
096 field = d[0].getField();
097 data = d.clone();
098 } catch (ArrayIndexOutOfBoundsException e) {
099 throw MathRuntimeException.createIllegalArgumentException(
100 "vector must have at least one element");
101 }
102 }
103
104 /**
105 * Create a new ArrayFieldVector using the input array as the underlying
106 * data array.
107 * <p>If an array is built specially in order to be embedded in a
108 * ArrayFieldVector and not used directly, the <code>copyArray</code> may be
109 * set to <code>false</code. This will prevent the copying and improve
110 * performance as no new array will be built and no data will be copied.</p>
111 * @param d data for new vector
112 * @param copyArray if true, the input array will be copied, otherwise
113 * it will be referenced
114 * @throws IllegalArgumentException if <code>d</code> is empty
115 * @throws NullPointerException if <code>d</code> is null
116 * @see #ArrayFieldVector(FieldElement[])
117 */
118 public ArrayFieldVector(T[] d, boolean copyArray)
119 throws NullPointerException, IllegalArgumentException {
120 try {
121 field = d[0].getField();
122 data = copyArray ? d.clone() : d;
123 } catch (ArrayIndexOutOfBoundsException e) {
124 throw MathRuntimeException.createIllegalArgumentException(
125 "vector must have at least one element");
126 }
127 }
128
129 /**
130 * Construct a vector from part of a array.
131 * @param d array of Ts.
132 * @param pos position of first entry
133 * @param size number of entries to copy
134 */
135 public ArrayFieldVector(T[] d, int pos, int size) {
136 if (d.length < pos + size) {
137 throw MathRuntimeException.createIllegalArgumentException(
138 "position {0} and size {1} don't fit to the size of the input array {2}",
139 pos, size, d.length);
140 }
141 field = d[0].getField();
142 data = buildArray(size);
143 System.arraycopy(d, pos, data, 0, size);
144 }
145
146 /**
147 * Construct a vector from another vector, using a deep copy.
148 * @param v vector to copy
149 */
150 public ArrayFieldVector(FieldVector<T> v) {
151 field = v.getField();
152 data = buildArray(v.getDimension());
153 for (int i = 0; i < data.length; ++i) {
154 data[i] = v.getEntry(i);
155 }
156 }
157
158 /**
159 * Construct a vector from another vector, using a deep copy.
160 * @param v vector to copy
161 */
162 public ArrayFieldVector(ArrayFieldVector<T> v) {
163 field = v.getField();
164 data = v.data.clone();
165 }
166
167 /**
168 * Construct a vector from another vector.
169 * @param v vector to copy
170 * @param deep if true perform a deep copy otherwise perform a shallow copy
171 */
172 public ArrayFieldVector(ArrayFieldVector<T> v, boolean deep) {
173 field = v.getField();
174 data = deep ? v.data.clone() : v.data;
175 }
176
177 /**
178 * Construct a vector by appending one vector to another vector.
179 * @param v1 first vector (will be put in front of the new vector)
180 * @param v2 second vector (will be put at back of the new vector)
181 */
182 public ArrayFieldVector(ArrayFieldVector<T> v1, ArrayFieldVector<T> v2) {
183 field = v1.getField();
184 data = buildArray(v1.data.length + v2.data.length);
185 System.arraycopy(v1.data, 0, data, 0, v1.data.length);
186 System.arraycopy(v2.data, 0, data, v1.data.length, v2.data.length);
187 }
188
189 /**
190 * Construct a vector by appending one vector to another vector.
191 * @param v1 first vector (will be put in front of the new vector)
192 * @param v2 second vector (will be put at back of the new vector)
193 */
194 public ArrayFieldVector(ArrayFieldVector<T> v1, T[] v2) {
195 field = v1.getField();
196 data = buildArray(v1.data.length + v2.length);
197 System.arraycopy(v1.data, 0, data, 0, v1.data.length);
198 System.arraycopy(v2, 0, data, v1.data.length, v2.length);
199 }
200
201 /**
202 * Construct a vector by appending one vector to another vector.
203 * @param v1 first vector (will be put in front of the new vector)
204 * @param v2 second vector (will be put at back of the new vector)
205 */
206 public ArrayFieldVector(T[] v1, ArrayFieldVector<T> v2) {
207 field = v2.getField();
208 data = buildArray(v1.length + v2.data.length);
209 System.arraycopy(v1, 0, data, 0, v1.length);
210 System.arraycopy(v2.data, 0, data, v1.length, v2.data.length);
211 }
212
213 /**
214 * Construct a vector by appending one vector to another vector.
215 * @param v1 first vector (will be put in front of the new vector)
216 * @param v2 second vector (will be put at back of the new vector)
217 * @exception IllegalArgumentException if both vectors are empty
218 */
219 public ArrayFieldVector(T[] v1, T[] v2) {
220 try {
221 data = buildArray(v1.length + v2.length);
222 System.arraycopy(v1, 0, data, 0, v1.length);
223 System.arraycopy(v2, 0, data, v1.length, v2.length);
224 field = data[0].getField();
225 } catch (ArrayIndexOutOfBoundsException e) {
226 throw MathRuntimeException.createIllegalArgumentException(
227 "vector must have at least one element");
228 }
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 @SuppressWarnings("unchecked")
743 @Override
744 public boolean equals(Object other) {
745
746 if (this == other) {
747 return true;
748 }
749
750 if (other == null) {
751 return false;
752 }
753
754 try {
755
756 FieldVector<T> rhs = (FieldVector<T>) other;
757 if (data.length != rhs.getDimension()) {
758 return false;
759 }
760
761 for (int i = 0; i < data.length; ++i) {
762 if (!data[i].equals(rhs.getEntry(i))) {
763 return false;
764 }
765 }
766 return true;
767
768 } catch (ClassCastException ex) {
769 // ignore exception
770 return false;
771 }
772
773 }
774
775 /**
776 * Get a hashCode for the real vector.
777 * <p>All NaN values have the same hash code.</p>
778 * @return a hash code value for this object
779 */
780 @Override
781 public int hashCode() {
782 int h = 3542;
783 for (final T a : data) {
784 h = h ^ a.hashCode();
785 }
786 return h;
787 }
788
789 /**
790 * Check if an index is valid.
791 * @param index index to check
792 * @exception MatrixIndexException if index is not valid
793 */
794 private void checkIndex(final int index)
795 throws MatrixIndexException {
796 if (index < 0 || index >= getDimension()) {
797 throw new MatrixIndexException(
798 "index {0} out of allowed range [{1}, {2}]",
799 index, 0, getDimension() - 1);
800 }
801 }
802
803 }