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.exception.DimensionMismatchException; 022import org.apache.commons.math3.exception.MathArithmeticException; 023import org.apache.commons.math3.exception.NotPositiveException; 024import org.apache.commons.math3.exception.OutOfRangeException; 025import org.apache.commons.math3.exception.util.LocalizedFormats; 026import org.apache.commons.math3.util.FastMath; 027import org.apache.commons.math3.util.OpenIntToDoubleHashMap; 028import org.apache.commons.math3.util.OpenIntToDoubleHashMap.Iterator; 029 030/** 031 * This class implements the {@link RealVector} interface with a 032 * {@link OpenIntToDoubleHashMap} backing store. 033 * <p> 034 * Caveat: This implementation assumes that, for any {@code x}, 035 * the equality {@code x * 0d == 0d} holds. But it is is not true for 036 * {@code NaN}. Moreover, zero entries will lose their sign. 037 * Some operations (that involve {@code NaN} and/or infinities) may 038 * thus give incorrect results, like multiplications, divisions or 039 * functions mapping. 040 * </p> 041 * @since 2.0 042 */ 043public class OpenMapRealVector extends SparseRealVector 044 implements Serializable { 045 /** Default Tolerance for having a value considered zero. */ 046 public static final double DEFAULT_ZERO_TOLERANCE = 1.0e-12; 047 /** Serializable version identifier. */ 048 private static final long serialVersionUID = 8772222695580707260L; 049 /** Entries of the vector. */ 050 private final OpenIntToDoubleHashMap entries; 051 /** Dimension of the vector. */ 052 private final int virtualSize; 053 /** Tolerance for having a value considered zero. */ 054 private final double epsilon; 055 056 /** 057 * Build a 0-length vector. 058 * Zero-length vectors may be used to initialized construction of vectors 059 * by data gathering. We start with zero-length and use either the {@link 060 * #OpenMapRealVector(OpenMapRealVector, int)} constructor 061 * or one of the {@code append} method ({@link #append(double)}, 062 * {@link #append(RealVector)}) to gather data into this vector. 063 */ 064 public OpenMapRealVector() { 065 this(0, DEFAULT_ZERO_TOLERANCE); 066 } 067 068 /** 069 * Construct a vector of zeroes. 070 * 071 * @param dimension Size of the vector. 072 */ 073 public OpenMapRealVector(int dimension) { 074 this(dimension, DEFAULT_ZERO_TOLERANCE); 075 } 076 077 /** 078 * Construct a vector of zeroes, specifying zero tolerance. 079 * 080 * @param dimension Size of the vector. 081 * @param epsilon Tolerance below which a value considered zero. 082 */ 083 public OpenMapRealVector(int dimension, double epsilon) { 084 virtualSize = dimension; 085 entries = new OpenIntToDoubleHashMap(0.0); 086 this.epsilon = epsilon; 087 } 088 089 /** 090 * Build a resized vector, for use with append. 091 * 092 * @param v Original vector. 093 * @param resize Amount to add. 094 */ 095 protected OpenMapRealVector(OpenMapRealVector v, int resize) { 096 virtualSize = v.getDimension() + resize; 097 entries = new OpenIntToDoubleHashMap(v.entries); 098 epsilon = v.epsilon; 099 } 100 101 /** 102 * Build a vector with known the sparseness (for advanced use only). 103 * 104 * @param dimension Size of the vector. 105 * @param expectedSize The expected number of non-zero entries. 106 */ 107 public OpenMapRealVector(int dimension, int expectedSize) { 108 this(dimension, expectedSize, DEFAULT_ZERO_TOLERANCE); 109 } 110 111 /** 112 * Build a vector with known the sparseness and zero tolerance 113 * setting (for advanced use only). 114 * 115 * @param dimension Size of the vector. 116 * @param expectedSize Expected number of non-zero entries. 117 * @param epsilon Tolerance below which a value is considered zero. 118 */ 119 public OpenMapRealVector(int dimension, int expectedSize, double epsilon) { 120 virtualSize = dimension; 121 entries = new OpenIntToDoubleHashMap(expectedSize, 0.0); 122 this.epsilon = epsilon; 123 } 124 125 /** 126 * Create from an array. 127 * Only non-zero entries will be stored. 128 * 129 * @param values Set of values to create from. 130 */ 131 public OpenMapRealVector(double[] values) { 132 this(values, DEFAULT_ZERO_TOLERANCE); 133 } 134 135 /** 136 * Create from an array, specifying zero tolerance. 137 * Only non-zero entries will be stored. 138 * 139 * @param values Set of values to create from. 140 * @param epsilon Tolerance below which a value is considered zero. 141 */ 142 public OpenMapRealVector(double[] values, double epsilon) { 143 virtualSize = values.length; 144 entries = new OpenIntToDoubleHashMap(0.0); 145 this.epsilon = epsilon; 146 for (int key = 0; key < values.length; key++) { 147 double value = values[key]; 148 if (!isDefaultValue(value)) { 149 entries.put(key, value); 150 } 151 } 152 } 153 154 /** 155 * Create from an array. 156 * Only non-zero entries will be stored. 157 * 158 * @param values The set of values to create from 159 */ 160 public OpenMapRealVector(Double[] values) { 161 this(values, DEFAULT_ZERO_TOLERANCE); 162 } 163 164 /** 165 * Create from an array. 166 * Only non-zero entries will be stored. 167 * 168 * @param values Set of values to create from. 169 * @param epsilon Tolerance below which a value is considered zero. 170 */ 171 public OpenMapRealVector(Double[] values, double epsilon) { 172 virtualSize = values.length; 173 entries = new OpenIntToDoubleHashMap(0.0); 174 this.epsilon = epsilon; 175 for (int key = 0; key < values.length; key++) { 176 double value = values[key].doubleValue(); 177 if (!isDefaultValue(value)) { 178 entries.put(key, value); 179 } 180 } 181 } 182 183 /** 184 * Copy constructor. 185 * 186 * @param v Instance to copy from. 187 */ 188 public OpenMapRealVector(OpenMapRealVector v) { 189 virtualSize = v.getDimension(); 190 entries = new OpenIntToDoubleHashMap(v.getEntries()); 191 epsilon = v.epsilon; 192 } 193 194 /** 195 * Generic copy constructor. 196 * 197 * @param v Instance to copy from. 198 */ 199 public OpenMapRealVector(RealVector v) { 200 virtualSize = v.getDimension(); 201 entries = new OpenIntToDoubleHashMap(0.0); 202 epsilon = DEFAULT_ZERO_TOLERANCE; 203 for (int key = 0; key < virtualSize; key++) { 204 double value = v.getEntry(key); 205 if (!isDefaultValue(value)) { 206 entries.put(key, value); 207 } 208 } 209 } 210 211 /** 212 * Get the entries of this instance. 213 * 214 * @return the entries of this instance. 215 */ 216 private OpenIntToDoubleHashMap getEntries() { 217 return entries; 218 } 219 220 /** 221 * Determine if this value is within epsilon of zero. 222 * 223 * @param value Value to test 224 * @return {@code true} if this value is within epsilon to zero, 225 * {@code false} otherwise. 226 * @since 2.1 227 */ 228 protected boolean isDefaultValue(double value) { 229 return FastMath.abs(value) < epsilon; 230 } 231 232 /** {@inheritDoc} */ 233 @Override 234 public RealVector add(RealVector v) 235 throws DimensionMismatchException { 236 checkVectorDimensions(v.getDimension()); 237 if (v instanceof OpenMapRealVector) { 238 return add((OpenMapRealVector) v); 239 } else { 240 return super.add(v); 241 } 242 } 243 244 /** 245 * Optimized method to add two OpenMapRealVectors. 246 * It copies the larger vector, then iterates over the smaller. 247 * 248 * @param v Vector to add. 249 * @return the sum of {@code this} and {@code v}. 250 * @throws DimensionMismatchException if the dimensions do not match. 251 */ 252 public OpenMapRealVector add(OpenMapRealVector v) 253 throws DimensionMismatchException { 254 checkVectorDimensions(v.getDimension()); 255 boolean copyThis = entries.size() > v.entries.size(); 256 OpenMapRealVector res = copyThis ? this.copy() : v.copy(); 257 Iterator iter = copyThis ? v.entries.iterator() : entries.iterator(); 258 OpenIntToDoubleHashMap randomAccess = copyThis ? entries : v.entries; 259 while (iter.hasNext()) { 260 iter.advance(); 261 int key = iter.key(); 262 if (randomAccess.containsKey(key)) { 263 res.setEntry(key, randomAccess.get(key) + iter.value()); 264 } else { 265 res.setEntry(key, iter.value()); 266 } 267 } 268 return res; 269 } 270 271 /** 272 * Optimized method to append a OpenMapRealVector. 273 * @param v vector to append 274 * @return The result of appending {@code v} to self 275 */ 276 public OpenMapRealVector append(OpenMapRealVector v) { 277 OpenMapRealVector res = new OpenMapRealVector(this, v.getDimension()); 278 Iterator iter = v.entries.iterator(); 279 while (iter.hasNext()) { 280 iter.advance(); 281 res.setEntry(iter.key() + virtualSize, iter.value()); 282 } 283 return res; 284 } 285 286 /** {@inheritDoc} */ 287 @Override 288 public OpenMapRealVector append(RealVector v) { 289 if (v instanceof OpenMapRealVector) { 290 return append((OpenMapRealVector) v); 291 } else { 292 final OpenMapRealVector res = new OpenMapRealVector(this, v.getDimension()); 293 for (int i = 0; i < v.getDimension(); i++) { 294 res.setEntry(i + virtualSize, v.getEntry(i)); 295 } 296 return res; 297 } 298 } 299 300 /** {@inheritDoc} */ 301 @Override 302 public OpenMapRealVector append(double d) { 303 OpenMapRealVector res = new OpenMapRealVector(this, 1); 304 res.setEntry(virtualSize, d); 305 return res; 306 } 307 308 /** 309 * {@inheritDoc} 310 * @since 2.1 311 */ 312 @Override 313 public OpenMapRealVector copy() { 314 return new OpenMapRealVector(this); 315 } 316 317 /** 318 * Computes the dot product. 319 * Note that the computation is now performed in the parent class: no 320 * performance improvement is to be expected from this overloaded 321 * method. 322 * The previous implementation was buggy and cannot be easily fixed 323 * (see MATH-795). 324 * 325 * @param v Vector. 326 * @return the dot product of this vector with {@code v}. 327 * @throws DimensionMismatchException if {@code v} is not the same size as 328 * {@code this} vector. 329 * 330 * @deprecated as of 3.1 (to be removed in 4.0). The computation is 331 * performed by the parent class. The method must be kept to maintain 332 * backwards compatibility. 333 */ 334 @Deprecated 335 public double dotProduct(OpenMapRealVector v) 336 throws DimensionMismatchException { 337 return dotProduct((RealVector) v); 338 } 339 340 /** {@inheritDoc} */ 341 @Override 342 public OpenMapRealVector ebeDivide(RealVector v) 343 throws DimensionMismatchException { 344 checkVectorDimensions(v.getDimension()); 345 OpenMapRealVector res = new OpenMapRealVector(this); 346 /* 347 * MATH-803: it is not sufficient to loop through non zero entries of 348 * this only. Indeed, if this[i] = 0d and v[i] = 0d, then 349 * this[i] / v[i] = NaN, and not 0d. 350 */ 351 final int n = getDimension(); 352 for (int i = 0; i < n; i++) { 353 res.setEntry(i, this.getEntry(i) / v.getEntry(i)); 354 } 355 return res; 356 } 357 358 /** {@inheritDoc} */ 359 @Override 360 public OpenMapRealVector ebeMultiply(RealVector v) 361 throws DimensionMismatchException { 362 checkVectorDimensions(v.getDimension()); 363 OpenMapRealVector res = new OpenMapRealVector(this); 364 Iterator iter = entries.iterator(); 365 while (iter.hasNext()) { 366 iter.advance(); 367 res.setEntry(iter.key(), iter.value() * v.getEntry(iter.key())); 368 } 369 return res; 370 } 371 372 /** {@inheritDoc} */ 373 @Override 374 public OpenMapRealVector getSubVector(int index, int n) 375 throws NotPositiveException, OutOfRangeException { 376 checkIndex(index); 377 if (n < 0) { 378 throw new NotPositiveException(LocalizedFormats.NUMBER_OF_ELEMENTS_SHOULD_BE_POSITIVE, n); 379 } 380 checkIndex(index + n - 1); 381 OpenMapRealVector res = new OpenMapRealVector(n); 382 int end = index + n; 383 Iterator iter = entries.iterator(); 384 while (iter.hasNext()) { 385 iter.advance(); 386 int key = iter.key(); 387 if (key >= index && key < end) { 388 res.setEntry(key - index, iter.value()); 389 } 390 } 391 return res; 392 } 393 394 /** {@inheritDoc} */ 395 @Override 396 public int getDimension() { 397 return virtualSize; 398 } 399 400 /** 401 * Optimized method to compute distance. 402 * 403 * @param v Vector to compute distance to. 404 * @return the distance from {@code this} and {@code v}. 405 * @throws DimensionMismatchException if the dimensions do not match. 406 */ 407 public double getDistance(OpenMapRealVector v) 408 throws DimensionMismatchException { 409 checkVectorDimensions(v.getDimension()); 410 Iterator iter = entries.iterator(); 411 double res = 0; 412 while (iter.hasNext()) { 413 iter.advance(); 414 int key = iter.key(); 415 double delta; 416 delta = iter.value() - v.getEntry(key); 417 res += delta * delta; 418 } 419 iter = v.getEntries().iterator(); 420 while (iter.hasNext()) { 421 iter.advance(); 422 int key = iter.key(); 423 if (!entries.containsKey(key)) { 424 final double value = iter.value(); 425 res += value * value; 426 } 427 } 428 return FastMath.sqrt(res); 429 } 430 431 /** {@inheritDoc} */ 432 @Override 433 public double getDistance(RealVector v) throws DimensionMismatchException { 434 checkVectorDimensions(v.getDimension()); 435 if (v instanceof OpenMapRealVector) { 436 return getDistance((OpenMapRealVector) v); 437 } else { 438 return super.getDistance(v); 439 } 440 } 441 442 /** {@inheritDoc} */ 443 @Override 444 public double getEntry(int index) throws OutOfRangeException { 445 checkIndex(index); 446 return entries.get(index); 447 } 448 449 /** 450 * Distance between two vectors. 451 * This method computes the distance consistent with 452 * L<sub>1</sub> norm, i.e. the sum of the absolute values of 453 * elements differences. 454 * 455 * @param v Vector to which distance is requested. 456 * @return distance between this vector and {@code v}. 457 * @throws DimensionMismatchException if the dimensions do not match. 458 */ 459 public double getL1Distance(OpenMapRealVector v) 460 throws DimensionMismatchException { 461 checkVectorDimensions(v.getDimension()); 462 double max = 0; 463 Iterator iter = entries.iterator(); 464 while (iter.hasNext()) { 465 iter.advance(); 466 double delta = FastMath.abs(iter.value() - v.getEntry(iter.key())); 467 max += delta; 468 } 469 iter = v.getEntries().iterator(); 470 while (iter.hasNext()) { 471 iter.advance(); 472 int key = iter.key(); 473 if (!entries.containsKey(key)) { 474 double delta = FastMath.abs(iter.value()); 475 max += FastMath.abs(delta); 476 } 477 } 478 return max; 479 } 480 481 /** {@inheritDoc} */ 482 @Override 483 public double getL1Distance(RealVector v) 484 throws DimensionMismatchException { 485 checkVectorDimensions(v.getDimension()); 486 if (v instanceof OpenMapRealVector) { 487 return getL1Distance((OpenMapRealVector) v); 488 } else { 489 return super.getL1Distance(v); 490 } 491 } 492 493 /** 494 * Optimized method to compute LInfDistance. 495 * 496 * @param v Vector to compute distance from. 497 * @return the LInfDistance. 498 * @throws DimensionMismatchException if the dimensions do not match. 499 */ 500 private double getLInfDistance(OpenMapRealVector v) 501 throws DimensionMismatchException { 502 checkVectorDimensions(v.getDimension()); 503 double max = 0; 504 Iterator iter = entries.iterator(); 505 while (iter.hasNext()) { 506 iter.advance(); 507 double delta = FastMath.abs(iter.value() - v.getEntry(iter.key())); 508 if (delta > max) { 509 max = delta; 510 } 511 } 512 iter = v.getEntries().iterator(); 513 while (iter.hasNext()) { 514 iter.advance(); 515 int key = iter.key(); 516 if (!entries.containsKey(key) && iter.value() > max) { 517 max = iter.value(); 518 } 519 } 520 return max; 521 } 522 523 /** {@inheritDoc} */ 524 @Override 525 public double getLInfDistance(RealVector v) 526 throws DimensionMismatchException { 527 checkVectorDimensions(v.getDimension()); 528 if (v instanceof OpenMapRealVector) { 529 return getLInfDistance((OpenMapRealVector) v); 530 } else { 531 return super.getLInfDistance(v); 532 } 533 } 534 535 /** {@inheritDoc} */ 536 @Override 537 public boolean isInfinite() { 538 boolean infiniteFound = false; 539 Iterator iter = entries.iterator(); 540 while (iter.hasNext()) { 541 iter.advance(); 542 final double value = iter.value(); 543 if (Double.isNaN(value)) { 544 return false; 545 } 546 if (Double.isInfinite(value)) { 547 infiniteFound = true; 548 } 549 } 550 return infiniteFound; 551 } 552 553 /** {@inheritDoc} */ 554 @Override 555 public boolean isNaN() { 556 Iterator iter = entries.iterator(); 557 while (iter.hasNext()) { 558 iter.advance(); 559 if (Double.isNaN(iter.value())) { 560 return true; 561 } 562 } 563 return false; 564 } 565 566 /** {@inheritDoc} */ 567 @Override 568 public OpenMapRealVector mapAdd(double d) { 569 return copy().mapAddToSelf(d); 570 } 571 572 /** {@inheritDoc} */ 573 @Override 574 public OpenMapRealVector mapAddToSelf(double d) { 575 for (int i = 0; i < virtualSize; i++) { 576 setEntry(i, getEntry(i) + d); 577 } 578 return this; 579 } 580 581 /** {@inheritDoc} */ 582 @Override 583 public void setEntry(int index, double value) 584 throws OutOfRangeException { 585 checkIndex(index); 586 if (!isDefaultValue(value)) { 587 entries.put(index, value); 588 } else if (entries.containsKey(index)) { 589 entries.remove(index); 590 } 591 } 592 593 /** {@inheritDoc} */ 594 @Override 595 public void setSubVector(int index, RealVector v) 596 throws OutOfRangeException { 597 checkIndex(index); 598 checkIndex(index + v.getDimension() - 1); 599 for (int i = 0; i < v.getDimension(); i++) { 600 setEntry(i + index, v.getEntry(i)); 601 } 602 } 603 604 /** {@inheritDoc} */ 605 @Override 606 public void set(double value) { 607 for (int i = 0; i < virtualSize; i++) { 608 setEntry(i, value); 609 } 610 } 611 612 /** 613 * Optimized method to subtract OpenMapRealVectors. 614 * 615 * @param v Vector to subtract from {@code this}. 616 * @return the difference of {@code this} and {@code v}. 617 * @throws DimensionMismatchException if the dimensions do not match. 618 */ 619 public OpenMapRealVector subtract(OpenMapRealVector v) 620 throws DimensionMismatchException { 621 checkVectorDimensions(v.getDimension()); 622 OpenMapRealVector res = copy(); 623 Iterator iter = v.getEntries().iterator(); 624 while (iter.hasNext()) { 625 iter.advance(); 626 int key = iter.key(); 627 if (entries.containsKey(key)) { 628 res.setEntry(key, entries.get(key) - iter.value()); 629 } else { 630 res.setEntry(key, -iter.value()); 631 } 632 } 633 return res; 634 } 635 636 /** {@inheritDoc} */ 637 @Override 638 public RealVector subtract(RealVector v) 639 throws DimensionMismatchException { 640 checkVectorDimensions(v.getDimension()); 641 if (v instanceof OpenMapRealVector) { 642 return subtract((OpenMapRealVector) v); 643 } else { 644 return super.subtract(v); 645 } 646 } 647 648 /** {@inheritDoc} */ 649 @Override 650 public OpenMapRealVector unitVector() throws MathArithmeticException { 651 OpenMapRealVector res = copy(); 652 res.unitize(); 653 return res; 654 } 655 656 /** {@inheritDoc} */ 657 @Override 658 public void unitize() throws MathArithmeticException { 659 double norm = getNorm(); 660 if (isDefaultValue(norm)) { 661 throw new MathArithmeticException(LocalizedFormats.ZERO_NORM); 662 } 663 Iterator iter = entries.iterator(); 664 while (iter.hasNext()) { 665 iter.advance(); 666 entries.put(iter.key(), iter.value() / norm); 667 } 668 } 669 670 /** {@inheritDoc} */ 671 @Override 672 public double[] toArray() { 673 double[] res = new double[virtualSize]; 674 Iterator iter = entries.iterator(); 675 while (iter.hasNext()) { 676 iter.advance(); 677 res[iter.key()] = iter.value(); 678 } 679 return res; 680 } 681 682 /** 683 * {@inheritDoc} 684 * Implementation Note: This works on exact values, and as a result 685 * it is possible for {@code a.subtract(b)} to be the zero vector, while 686 * {@code a.hashCode() != b.hashCode()}. 687 */ 688 @Override 689 public int hashCode() { 690 final int prime = 31; 691 int result = 1; 692 long temp; 693 temp = Double.doubleToLongBits(epsilon); 694 result = prime * result + (int) (temp ^ (temp >>> 32)); 695 result = prime * result + virtualSize; 696 Iterator iter = entries.iterator(); 697 while (iter.hasNext()) { 698 iter.advance(); 699 temp = Double.doubleToLongBits(iter.value()); 700 result = prime * result + (int) (temp ^ (temp >>32)); 701 } 702 return result; 703 } 704 705 /** 706 * {@inheritDoc} 707 * Implementation Note: This performs an exact comparison, and as a result 708 * it is possible for {@code a.subtract(b}} to be the zero vector, while 709 * {@code a.equals(b) == false}. 710 */ 711 @Override 712 public boolean equals(Object obj) { 713 if (this == obj) { 714 return true; 715 } 716 if (!(obj instanceof OpenMapRealVector)) { 717 return false; 718 } 719 OpenMapRealVector other = (OpenMapRealVector) obj; 720 if (virtualSize != other.virtualSize) { 721 return false; 722 } 723 if (Double.doubleToLongBits(epsilon) != 724 Double.doubleToLongBits(other.epsilon)) { 725 return false; 726 } 727 Iterator iter = entries.iterator(); 728 while (iter.hasNext()) { 729 iter.advance(); 730 double test = other.getEntry(iter.key()); 731 if (Double.doubleToLongBits(test) != Double.doubleToLongBits(iter.value())) { 732 return false; 733 } 734 } 735 iter = other.getEntries().iterator(); 736 while (iter.hasNext()) { 737 iter.advance(); 738 double test = iter.value(); 739 if (Double.doubleToLongBits(test) != Double.doubleToLongBits(getEntry(iter.key()))) { 740 return false; 741 } 742 } 743 return true; 744 } 745 746 /** 747 * 748 * @return the percentage of none zero elements as a decimal percent. 749 * @since 2.2 750 */ 751 public double getSparsity() { 752 return (double)entries.size()/(double)getDimension(); 753 } 754 755 /** {@inheritDoc} */ 756 @Override 757 public java.util.Iterator<Entry> sparseIterator() { 758 return new OpenMapSparseIterator(); 759 } 760 761 /** 762 * Implementation of {@code Entry} optimized for OpenMap. 763 * This implementation does not allow arbitrary calls to {@code setIndex} 764 * since the order in which entries are returned is undefined. 765 */ 766 protected class OpenMapEntry extends Entry { 767 /** Iterator pointing to the entry. */ 768 private final Iterator iter; 769 770 /** 771 * Build an entry from an iterator point to an element. 772 * 773 * @param iter Iterator pointing to the entry. 774 */ 775 protected OpenMapEntry(Iterator iter) { 776 this.iter = iter; 777 } 778 779 /** {@inheritDoc} */ 780 @Override 781 public double getValue() { 782 return iter.value(); 783 } 784 785 /** {@inheritDoc} */ 786 @Override 787 public void setValue(double value) { 788 entries.put(iter.key(), value); 789 } 790 791 /** {@inheritDoc} */ 792 @Override 793 public int getIndex() { 794 return iter.key(); 795 } 796 797 } 798 799 /** 800 * Iterator class to do iteration over just the non-zero elements. 801 * This implementation is fail-fast, so cannot be used to modify 802 * any zero element. 803 */ 804 protected class OpenMapSparseIterator implements java.util.Iterator<Entry> { 805 /** Underlying iterator. */ 806 private final Iterator iter; 807 /** Current entry. */ 808 private final Entry current; 809 810 /** Simple constructor. */ 811 protected OpenMapSparseIterator() { 812 iter = entries.iterator(); 813 current = new OpenMapEntry(iter); 814 } 815 816 /** {@inheritDoc} */ 817 public boolean hasNext() { 818 return iter.hasNext(); 819 } 820 821 /** {@inheritDoc} */ 822 public Entry next() { 823 iter.advance(); 824 return current; 825 } 826 827 /** {@inheritDoc} */ 828 public void remove() { 829 throw new UnsupportedOperationException("Not supported"); 830 } 831 } 832}