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