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 */ 017package org.apache.commons.math3.linear; 018 019import java.io.Serializable; 020 021import org.apache.commons.math3.Field; 022import org.apache.commons.math3.FieldElement; 023import org.apache.commons.math3.exception.DimensionMismatchException; 024import org.apache.commons.math3.exception.MathArithmeticException; 025import org.apache.commons.math3.exception.NotPositiveException; 026import org.apache.commons.math3.exception.NullArgumentException; 027import org.apache.commons.math3.exception.NumberIsTooSmallException; 028import org.apache.commons.math3.exception.OutOfRangeException; 029import org.apache.commons.math3.exception.util.LocalizedFormats; 030import org.apache.commons.math3.util.MathArrays; 031import org.apache.commons.math3.util.MathUtils; 032import org.apache.commons.math3.util.OpenIntToFieldHashMap; 033 034/** 035 * This class implements the {@link FieldVector} interface with a {@link OpenIntToFieldHashMap} backing store. 036 * <p> 037 * Caveat: This implementation assumes that, for any {@code x}, 038 * the equality {@code x * 0d == 0d} holds. But it is is not true for 039 * {@code NaN}. Moreover, zero entries will lose their sign. 040 * Some operations (that involve {@code NaN} and/or infinities) may 041 * thus give incorrect results. 042 * </p> 043 * @param <T> the type of the field elements 044 * @since 2.0 045 */ 046public class SparseFieldVector<T extends FieldElement<T>> implements FieldVector<T>, Serializable { 047 /** Serialization identifier. */ 048 private static final long serialVersionUID = 7841233292190413362L; 049 /** Field to which the elements belong. */ 050 private final Field<T> field; 051 /** Entries of the vector. */ 052 private final OpenIntToFieldHashMap<T> entries; 053 /** Dimension of the vector. */ 054 private final int virtualSize; 055 056 /** 057 * Build a 0-length vector. 058 * Zero-length vectors may be used to initialize construction of vectors 059 * by data gathering. We start with zero-length and use either the {@link 060 * #SparseFieldVector(SparseFieldVector, int)} constructor 061 * or one of the {@code append} method ({@link #append(FieldVector)} or 062 * {@link #append(SparseFieldVector)}) to gather data into this vector. 063 * 064 * @param field Field to which the elements belong. 065 */ 066 public SparseFieldVector(Field<T> field) { 067 this(field, 0); 068 } 069 070 071 /** 072 * Construct a vector of zeroes. 073 * 074 * @param field Field to which the elements belong. 075 * @param dimension Size of the vector. 076 */ 077 public SparseFieldVector(Field<T> field, int dimension) { 078 this.field = field; 079 virtualSize = dimension; 080 entries = new OpenIntToFieldHashMap<T>(field); 081 } 082 083 /** 084 * Build a resized vector, for use with append. 085 * 086 * @param v Original vector 087 * @param resize Amount to add. 088 */ 089 protected SparseFieldVector(SparseFieldVector<T> v, int resize) { 090 field = v.field; 091 virtualSize = v.getDimension() + resize; 092 entries = new OpenIntToFieldHashMap<T>(v.entries); 093 } 094 095 096 /** 097 * Build a vector with known the sparseness (for advanced use only). 098 * 099 * @param field Field to which the elements belong. 100 * @param dimension Size of the vector. 101 * @param expectedSize Expected number of non-zero entries. 102 */ 103 public SparseFieldVector(Field<T> field, int dimension, int expectedSize) { 104 this.field = field; 105 virtualSize = dimension; 106 entries = new OpenIntToFieldHashMap<T>(field,expectedSize); 107 } 108 109 /** 110 * Create from a Field array. 111 * Only non-zero entries will be stored. 112 * 113 * @param field Field to which the elements belong. 114 * @param values Set of values to create from. 115 * @exception NullArgumentException if values is null 116 */ 117 public SparseFieldVector(Field<T> field, T[] values) throws NullArgumentException { 118 MathUtils.checkNotNull(values); 119 this.field = field; 120 virtualSize = values.length; 121 entries = new OpenIntToFieldHashMap<T>(field); 122 for (int key = 0; key < values.length; key++) { 123 T value = values[key]; 124 entries.put(key, value); 125 } 126 } 127 128 /** 129 * Copy constructor. 130 * 131 * @param v Instance to copy. 132 */ 133 public SparseFieldVector(SparseFieldVector<T> v) { 134 field = v.field; 135 virtualSize = v.getDimension(); 136 entries = new OpenIntToFieldHashMap<T>(v.getEntries()); 137 } 138 139 /** 140 * Get the entries of this instance. 141 * 142 * @return the entries of this instance 143 */ 144 private OpenIntToFieldHashMap<T> getEntries() { 145 return entries; 146 } 147 148 /** 149 * Optimized method to add sparse vectors. 150 * 151 * @param v Vector to add. 152 * @return {@code this + v}. 153 * @throws DimensionMismatchException if {@code v} is not the same size as 154 * {@code this}. 155 */ 156 public FieldVector<T> add(SparseFieldVector<T> v) 157 throws DimensionMismatchException { 158 checkVectorDimensions(v.getDimension()); 159 SparseFieldVector<T> res = (SparseFieldVector<T>)copy(); 160 OpenIntToFieldHashMap<T>.Iterator iter = v.getEntries().iterator(); 161 while (iter.hasNext()) { 162 iter.advance(); 163 int key = iter.key(); 164 T value = iter.value(); 165 if (entries.containsKey(key)) { 166 res.setEntry(key, entries.get(key).add(value)); 167 } else { 168 res.setEntry(key, value); 169 } 170 } 171 return res; 172 173 } 174 175 /** 176 * Construct a vector by appending a vector to this vector. 177 * 178 * @param v Vector to append to this one. 179 * @return a new vector. 180 */ 181 public FieldVector<T> append(SparseFieldVector<T> v) { 182 SparseFieldVector<T> res = new SparseFieldVector<T>(this, v.getDimension()); 183 OpenIntToFieldHashMap<T>.Iterator iter = v.entries.iterator(); 184 while (iter.hasNext()) { 185 iter.advance(); 186 res.setEntry(iter.key() + virtualSize, iter.value()); 187 } 188 return res; 189 } 190 191 /** {@inheritDoc} */ 192 public FieldVector<T> append(FieldVector<T> v) { 193 if (v instanceof SparseFieldVector<?>) { 194 return append((SparseFieldVector<T>) v); 195 } else { 196 final int n = v.getDimension(); 197 FieldVector<T> res = new SparseFieldVector<T>(this, n); 198 for (int i = 0; i < n; i++) { 199 res.setEntry(i + virtualSize, v.getEntry(i)); 200 } 201 return res; 202 } 203 } 204 205 /** {@inheritDoc} 206 * @exception NullArgumentException if d is null 207 */ 208 public FieldVector<T> append(T d) throws NullArgumentException { 209 MathUtils.checkNotNull(d); 210 FieldVector<T> res = new SparseFieldVector<T>(this, 1); 211 res.setEntry(virtualSize, d); 212 return res; 213 } 214 215 /** {@inheritDoc} */ 216 public FieldVector<T> copy() { 217 return new SparseFieldVector<T>(this); 218 } 219 220 /** {@inheritDoc} */ 221 public T dotProduct(FieldVector<T> v) throws DimensionMismatchException { 222 checkVectorDimensions(v.getDimension()); 223 T res = field.getZero(); 224 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 225 while (iter.hasNext()) { 226 iter.advance(); 227 res = res.add(v.getEntry(iter.key()).multiply(iter.value())); 228 } 229 return res; 230 } 231 232 /** {@inheritDoc} */ 233 public FieldVector<T> ebeDivide(FieldVector<T> v) 234 throws DimensionMismatchException, MathArithmeticException { 235 checkVectorDimensions(v.getDimension()); 236 SparseFieldVector<T> res = new SparseFieldVector<T>(this); 237 OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator(); 238 while (iter.hasNext()) { 239 iter.advance(); 240 res.setEntry(iter.key(), iter.value().divide(v.getEntry(iter.key()))); 241 } 242 return res; 243 } 244 245 /** {@inheritDoc} */ 246 public FieldVector<T> ebeMultiply(FieldVector<T> v) 247 throws DimensionMismatchException { 248 checkVectorDimensions(v.getDimension()); 249 SparseFieldVector<T> res = new SparseFieldVector<T>(this); 250 OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator(); 251 while (iter.hasNext()) { 252 iter.advance(); 253 res.setEntry(iter.key(), iter.value().multiply(v.getEntry(iter.key()))); 254 } 255 return res; 256 } 257 258 /** 259 * {@inheritDoc} 260 * 261 * @deprecated as of 3.1, to be removed in 4.0. Please use the {@link #toArray()} method instead. 262 */ 263 @Deprecated 264 public T[] getData() { 265 return toArray(); 266 } 267 268 /** {@inheritDoc} */ 269 public int getDimension() { 270 return virtualSize; 271 } 272 273 /** {@inheritDoc} */ 274 public T getEntry(int index) throws OutOfRangeException { 275 checkIndex(index); 276 return entries.get(index); 277 } 278 279 /** {@inheritDoc} */ 280 public Field<T> getField() { 281 return field; 282 } 283 284 /** {@inheritDoc} */ 285 public FieldVector<T> getSubVector(int index, int n) 286 throws OutOfRangeException, NotPositiveException { 287 if (n < 0) { 288 throw new NotPositiveException(LocalizedFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, n); 289 } 290 checkIndex(index); 291 checkIndex(index + n - 1); 292 SparseFieldVector<T> res = new SparseFieldVector<T>(field,n); 293 int end = index + n; 294 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 295 while (iter.hasNext()) { 296 iter.advance(); 297 int key = iter.key(); 298 if (key >= index && key < end) { 299 res.setEntry(key - index, iter.value()); 300 } 301 } 302 return res; 303 } 304 305 /** {@inheritDoc} */ 306 public FieldVector<T> mapAdd(T d) throws NullArgumentException { 307 return copy().mapAddToSelf(d); 308 } 309 310 /** {@inheritDoc} */ 311 public FieldVector<T> mapAddToSelf(T d) throws NullArgumentException { 312 for (int i = 0; i < virtualSize; i++) { 313 setEntry(i, getEntry(i).add(d)); 314 } 315 return this; 316 } 317 318 /** {@inheritDoc} */ 319 public FieldVector<T> mapDivide(T d) 320 throws NullArgumentException, MathArithmeticException { 321 return copy().mapDivideToSelf(d); 322 } 323 324 /** {@inheritDoc} */ 325 public FieldVector<T> mapDivideToSelf(T d) 326 throws NullArgumentException, MathArithmeticException { 327 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 328 while (iter.hasNext()) { 329 iter.advance(); 330 entries.put(iter.key(), iter.value().divide(d)); 331 } 332 return this; 333 } 334 335 /** {@inheritDoc} */ 336 public FieldVector<T> mapInv() throws MathArithmeticException { 337 return copy().mapInvToSelf(); 338 } 339 340 /** {@inheritDoc} */ 341 public FieldVector<T> mapInvToSelf() throws MathArithmeticException { 342 for (int i = 0; i < virtualSize; i++) { 343 setEntry(i, field.getOne().divide(getEntry(i))); 344 } 345 return this; 346 } 347 348 /** {@inheritDoc} */ 349 public FieldVector<T> mapMultiply(T d) throws NullArgumentException { 350 return copy().mapMultiplyToSelf(d); 351 } 352 353 /** {@inheritDoc} */ 354 public FieldVector<T> mapMultiplyToSelf(T d) throws NullArgumentException { 355 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 356 while (iter.hasNext()) { 357 iter.advance(); 358 entries.put(iter.key(), iter.value().multiply(d)); 359 } 360 return this; 361 } 362 363 /** {@inheritDoc} */ 364 public FieldVector<T> mapSubtract(T d) throws NullArgumentException { 365 return copy().mapSubtractToSelf(d); 366 } 367 368 /** {@inheritDoc} */ 369 public FieldVector<T> mapSubtractToSelf(T d) throws NullArgumentException { 370 return mapAddToSelf(field.getZero().subtract(d)); 371 } 372 373 /** 374 * Optimized method to compute outer product when both vectors are sparse. 375 * @param v vector with which outer product should be computed 376 * @return the matrix outer product between instance and v 377 */ 378 public FieldMatrix<T> outerProduct(SparseFieldVector<T> v) { 379 final int n = v.getDimension(); 380 SparseFieldMatrix<T> res = new SparseFieldMatrix<T>(field, virtualSize, n); 381 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 382 while (iter.hasNext()) { 383 iter.advance(); 384 OpenIntToFieldHashMap<T>.Iterator iter2 = v.entries.iterator(); 385 while (iter2.hasNext()) { 386 iter2.advance(); 387 res.setEntry(iter.key(), iter2.key(), iter.value().multiply(iter2.value())); 388 } 389 } 390 return res; 391 } 392 393 /** {@inheritDoc} */ 394 public FieldMatrix<T> outerProduct(FieldVector<T> v) { 395 if (v instanceof SparseFieldVector<?>) { 396 return outerProduct((SparseFieldVector<T>)v); 397 } else { 398 final int n = v.getDimension(); 399 FieldMatrix<T> res = new SparseFieldMatrix<T>(field, virtualSize, n); 400 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 401 while (iter.hasNext()) { 402 iter.advance(); 403 int row = iter.key(); 404 FieldElement<T>value = iter.value(); 405 for (int col = 0; col < n; col++) { 406 res.setEntry(row, col, value.multiply(v.getEntry(col))); 407 } 408 } 409 return res; 410 } 411 } 412 413 /** {@inheritDoc} */ 414 public FieldVector<T> projection(FieldVector<T> v) 415 throws DimensionMismatchException, MathArithmeticException { 416 checkVectorDimensions(v.getDimension()); 417 return v.mapMultiply(dotProduct(v).divide(v.dotProduct(v))); 418 } 419 420 /** {@inheritDoc} 421 * @exception NullArgumentException if value is null 422 */ 423 public void set(T value) { 424 MathUtils.checkNotNull(value); 425 for (int i = 0; i < virtualSize; i++) { 426 setEntry(i, value); 427 } 428 } 429 430 /** {@inheritDoc} 431 * @exception NullArgumentException if value is null 432 */ 433 public void setEntry(int index, T value) throws NullArgumentException, OutOfRangeException { 434 MathUtils.checkNotNull(value); 435 checkIndex(index); 436 entries.put(index, value); 437 } 438 439 /** {@inheritDoc} */ 440 public void setSubVector(int index, FieldVector<T> v) 441 throws OutOfRangeException { 442 checkIndex(index); 443 checkIndex(index + v.getDimension() - 1); 444 final int n = v.getDimension(); 445 for (int i = 0; i < n; i++) { 446 setEntry(i + index, v.getEntry(i)); 447 } 448 } 449 450 /** 451 * Optimized method to compute {@code this} minus {@code v}. 452 * @param v vector to be subtracted 453 * @return {@code this - v} 454 * @throws DimensionMismatchException if {@code v} is not the same size as 455 * {@code this}. 456 */ 457 public SparseFieldVector<T> subtract(SparseFieldVector<T> v) 458 throws DimensionMismatchException { 459 checkVectorDimensions(v.getDimension()); 460 SparseFieldVector<T> res = (SparseFieldVector<T>)copy(); 461 OpenIntToFieldHashMap<T>.Iterator iter = v.getEntries().iterator(); 462 while (iter.hasNext()) { 463 iter.advance(); 464 int key = iter.key(); 465 if (entries.containsKey(key)) { 466 res.setEntry(key, entries.get(key).subtract(iter.value())); 467 } else { 468 res.setEntry(key, field.getZero().subtract(iter.value())); 469 } 470 } 471 return res; 472 } 473 474 /** {@inheritDoc} */ 475 public FieldVector<T> subtract(FieldVector<T> v) 476 throws DimensionMismatchException { 477 if (v instanceof SparseFieldVector<?>) { 478 return subtract((SparseFieldVector<T>)v); 479 } else { 480 final int n = v.getDimension(); 481 checkVectorDimensions(n); 482 SparseFieldVector<T> res = new SparseFieldVector<T>(this); 483 for (int i = 0; i < n; i++) { 484 if (entries.containsKey(i)) { 485 res.setEntry(i, entries.get(i).subtract(v.getEntry(i))); 486 } else { 487 res.setEntry(i, field.getZero().subtract(v.getEntry(i))); 488 } 489 } 490 return res; 491 } 492 } 493 494 /** {@inheritDoc} */ 495 public T[] toArray() { 496 T[] res = MathArrays.buildArray(field, virtualSize); 497 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 498 while (iter.hasNext()) { 499 iter.advance(); 500 res[iter.key()] = iter.value(); 501 } 502 return res; 503 } 504 505 /** 506 * Check whether an index is valid. 507 * 508 * @param index Index to check. 509 * @throws OutOfRangeException if the index is not valid. 510 */ 511 private void checkIndex(final int index) throws OutOfRangeException { 512 if (index < 0 || index >= getDimension()) { 513 throw new OutOfRangeException(index, 0, getDimension() - 1); 514 } 515 } 516 517 /** 518 * Checks that the indices of a subvector are valid. 519 * 520 * @param start the index of the first entry of the subvector 521 * @param end the index of the last entry of the subvector (inclusive) 522 * @throws OutOfRangeException if {@code start} of {@code end} are not valid 523 * @throws NumberIsTooSmallException if {@code end < start} 524 * @since 3.3 525 */ 526 private void checkIndices(final int start, final int end) 527 throws NumberIsTooSmallException, OutOfRangeException { 528 final int dim = getDimension(); 529 if ((start < 0) || (start >= dim)) { 530 throw new OutOfRangeException(LocalizedFormats.INDEX, start, 0, 531 dim - 1); 532 } 533 if ((end < 0) || (end >= dim)) { 534 throw new OutOfRangeException(LocalizedFormats.INDEX, end, 0, 535 dim - 1); 536 } 537 if (end < start) { 538 throw new NumberIsTooSmallException(LocalizedFormats.INITIAL_ROW_AFTER_FINAL_ROW, 539 end, start, false); 540 } 541 } 542 543 /** 544 * Check if instance dimension is equal to some expected value. 545 * 546 * @param n Expected dimension. 547 * @throws DimensionMismatchException if the dimensions do not match. 548 */ 549 protected void checkVectorDimensions(int n) 550 throws DimensionMismatchException { 551 if (getDimension() != n) { 552 throw new DimensionMismatchException(getDimension(), n); 553 } 554 } 555 556 /** {@inheritDoc} */ 557 public FieldVector<T> add(FieldVector<T> v) throws DimensionMismatchException { 558 if (v instanceof SparseFieldVector<?>) { 559 return add((SparseFieldVector<T>) v); 560 } else { 561 final int n = v.getDimension(); 562 checkVectorDimensions(n); 563 SparseFieldVector<T> res = new SparseFieldVector<T>(field, 564 getDimension()); 565 for (int i = 0; i < n; i++) { 566 res.setEntry(i, v.getEntry(i).add(getEntry(i))); 567 } 568 return res; 569 } 570 } 571 572 /** 573 * Visits (but does not alter) all entries of this vector in default order 574 * (increasing index). 575 * 576 * @param visitor the visitor to be used to process the entries of this 577 * vector 578 * @return the value returned by {@link FieldVectorPreservingVisitor#end()} 579 * at the end of the walk 580 * @since 3.3 581 */ 582 public T walkInDefaultOrder(final FieldVectorPreservingVisitor<T> visitor) { 583 final int dim = getDimension(); 584 visitor.start(dim, 0, dim - 1); 585 for (int i = 0; i < dim; i++) { 586 visitor.visit(i, getEntry(i)); 587 } 588 return visitor.end(); 589 } 590 591 /** 592 * Visits (but does not alter) some entries of this vector in default order 593 * (increasing index). 594 * 595 * @param visitor visitor to be used to process the entries of this vector 596 * @param start the index of the first entry to be visited 597 * @param end the index of the last entry to be visited (inclusive) 598 * @return the value returned by {@link FieldVectorPreservingVisitor#end()} 599 * at the end of the walk 600 * @throws NumberIsTooSmallException if {@code end < start}. 601 * @throws OutOfRangeException if the indices are not valid. 602 * @since 3.3 603 */ 604 public T walkInDefaultOrder(final FieldVectorPreservingVisitor<T> visitor, 605 final int start, final int end) 606 throws NumberIsTooSmallException, OutOfRangeException { 607 checkIndices(start, end); 608 visitor.start(getDimension(), start, end); 609 for (int i = start; i <= end; i++) { 610 visitor.visit(i, getEntry(i)); 611 } 612 return visitor.end(); 613 } 614 615 /** 616 * Visits (but does not alter) all entries of this vector in optimized 617 * order. The order in which the entries are visited is selected so as to 618 * lead to the most efficient implementation; it might depend on the 619 * concrete implementation of this abstract class. 620 * 621 * @param visitor the visitor to be used to process the entries of this 622 * vector 623 * @return the value returned by {@link FieldVectorPreservingVisitor#end()} 624 * at the end of the walk 625 * @since 3.3 626 */ 627 public T walkInOptimizedOrder(final FieldVectorPreservingVisitor<T> visitor) { 628 return walkInDefaultOrder(visitor); 629 } 630 631 /** 632 * Visits (but does not alter) some entries of this vector in optimized 633 * order. The order in which the entries are visited is selected so as to 634 * lead to the most efficient implementation; it might depend on the 635 * concrete implementation of this abstract class. 636 * 637 * @param visitor visitor to be used to process the entries of this vector 638 * @param start the index of the first entry to be visited 639 * @param end the index of the last entry to be visited (inclusive) 640 * @return the value returned by {@link FieldVectorPreservingVisitor#end()} 641 * at the end of the walk 642 * @throws NumberIsTooSmallException if {@code end < start}. 643 * @throws OutOfRangeException if the indices are not valid. 644 * @since 3.3 645 */ 646 public T walkInOptimizedOrder(final FieldVectorPreservingVisitor<T> visitor, 647 final int start, final int end) 648 throws NumberIsTooSmallException, OutOfRangeException { 649 return walkInDefaultOrder(visitor, start, end); 650 } 651 652 /** 653 * Visits (and possibly alters) all entries of this vector in default order 654 * (increasing index). 655 * 656 * @param visitor the visitor to be used to process and modify the entries 657 * of this vector 658 * @return the value returned by {@link FieldVectorChangingVisitor#end()} 659 * at the end of the walk 660 * @since 3.3 661 */ 662 public T walkInDefaultOrder(final FieldVectorChangingVisitor<T> visitor) { 663 final int dim = getDimension(); 664 visitor.start(dim, 0, dim - 1); 665 for (int i = 0; i < dim; i++) { 666 setEntry(i, visitor.visit(i, getEntry(i))); 667 } 668 return visitor.end(); 669 } 670 671 /** 672 * Visits (and possibly alters) some entries of this vector in default order 673 * (increasing index). 674 * 675 * @param visitor visitor to be used to process the entries of this vector 676 * @param start the index of the first entry to be visited 677 * @param end the index of the last entry to be visited (inclusive) 678 * @return the value returned by {@link FieldVectorChangingVisitor#end()} 679 * at the end of the walk 680 * @throws NumberIsTooSmallException if {@code end < start}. 681 * @throws OutOfRangeException if the indices are not valid. 682 * @since 3.3 683 */ 684 public T walkInDefaultOrder(final FieldVectorChangingVisitor<T> visitor, 685 final int start, final int end) 686 throws NumberIsTooSmallException, OutOfRangeException { 687 checkIndices(start, end); 688 visitor.start(getDimension(), start, end); 689 for (int i = start; i <= end; i++) { 690 setEntry(i, visitor.visit(i, getEntry(i))); 691 } 692 return visitor.end(); 693 } 694 695 /** 696 * Visits (and possibly alters) all entries of this vector in optimized 697 * order. The order in which the entries are visited is selected so as to 698 * lead to the most efficient implementation; it might depend on the 699 * concrete implementation of this abstract class. 700 * 701 * @param visitor the visitor to be used to process the entries of this 702 * vector 703 * @return the value returned by {@link FieldVectorChangingVisitor#end()} 704 * at the end of the walk 705 * @since 3.3 706 */ 707 public T walkInOptimizedOrder(final FieldVectorChangingVisitor<T> visitor) { 708 return walkInDefaultOrder(visitor); 709 } 710 711 /** 712 * Visits (and possibly change) some entries of this vector in optimized 713 * order. The order in which the entries are visited is selected so as to 714 * lead to the most efficient implementation; it might depend on the 715 * concrete implementation of this abstract class. 716 * 717 * @param visitor visitor to be used to process the entries of this vector 718 * @param start the index of the first entry to be visited 719 * @param end the index of the last entry to be visited (inclusive) 720 * @return the value returned by {@link FieldVectorChangingVisitor#end()} 721 * at the end of the walk 722 * @throws NumberIsTooSmallException if {@code end < start}. 723 * @throws OutOfRangeException if the indices are not valid. 724 * @since 3.3 725 */ 726 public T walkInOptimizedOrder(final FieldVectorChangingVisitor<T> visitor, 727 final int start, final int end) 728 throws NumberIsTooSmallException, OutOfRangeException { 729 return walkInDefaultOrder(visitor, start, end); 730 } 731 732 /** {@inheritDoc} */ 733 @Override 734 public int hashCode() { 735 final int prime = 31; 736 int result = 1; 737 result = prime * result + ((field == null) ? 0 : field.hashCode()); 738 result = prime * result + virtualSize; 739 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 740 while (iter.hasNext()) { 741 iter.advance(); 742 int temp = iter.value().hashCode(); 743 result = prime * result + temp; 744 } 745 return result; 746 } 747 748 749 /** {@inheritDoc} */ 750 @Override 751 public boolean equals(Object obj) { 752 753 if (this == obj) { 754 return true; 755 } 756 757 if (!(obj instanceof SparseFieldVector<?>)) { 758 return false; 759 } 760 761 @SuppressWarnings("unchecked") // OK, because "else if" check below ensures that 762 // other must be the same type as this 763 SparseFieldVector<T> other = (SparseFieldVector<T>) obj; 764 if (field == null) { 765 if (other.field != null) { 766 return false; 767 } 768 } else if (!field.equals(other.field)) { 769 return false; 770 } 771 if (virtualSize != other.virtualSize) { 772 return false; 773 } 774 775 OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator(); 776 while (iter.hasNext()) { 777 iter.advance(); 778 T test = other.getEntry(iter.key()); 779 if (!test.equals(iter.value())) { 780 return false; 781 } 782 } 783 iter = other.getEntries().iterator(); 784 while (iter.hasNext()) { 785 iter.advance(); 786 T test = iter.value(); 787 if (!test.equals(getEntry(iter.key()))) { 788 return false; 789 } 790 } 791 return true; 792 } 793}