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 }