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 }