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