001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.math.linear;
018
019 import java.io.Serializable;
020
021 import org.apache.commons.math.MathRuntimeException;
022 import org.apache.commons.math.exception.util.LocalizedFormats;
023 import org.apache.commons.math.util.OpenIntToDoubleHashMap;
024 import org.apache.commons.math.util.OpenIntToDoubleHashMap.Iterator;
025 import org.apache.commons.math.util.FastMath;
026
027 /**
028 * This class implements the {@link RealVector} interface with a {@link OpenIntToDoubleHashMap} backing store.
029 * @version $Revision: 1073262 $ $Date: 2011-02-22 10:02:25 +0100 (mar. 22 f??vr. 2011) $
030 * @since 2.0
031 */
032 public class OpenMapRealVector extends AbstractRealVector implements SparseRealVector, Serializable {
033
034 /** Default Tolerance for having a value considered zero. */
035 public static final double DEFAULT_ZERO_TOLERANCE = 1.0e-12;
036
037 /** Serializable version identifier. */
038 private static final long serialVersionUID = 8772222695580707260L;
039
040 /** Entries of the vector. */
041 private final OpenIntToDoubleHashMap entries;
042
043 /** Dimension of the vector. */
044 private final int virtualSize;
045
046 /** Tolerance for having a value considered zero. */
047 private final double epsilon;
048
049 /**
050 * Build a 0-length vector.
051 * <p>Zero-length vectors may be used to initialized construction of vectors
052 * by data gathering. We start with zero-length and use either the {@link
053 * #OpenMapRealVector(OpenMapRealVector, int)} constructor
054 * or one of the <code>append</code> method ({@link #append(double)}, {@link
055 * #append(double[])}, {@link #append(RealVector)}) to gather data
056 * into this vector.</p>
057 */
058 public OpenMapRealVector() {
059 this(0, DEFAULT_ZERO_TOLERANCE);
060 }
061
062 /**
063 * Construct a (dimension)-length vector of zeros.
064 * @param dimension size of the vector
065 */
066 public OpenMapRealVector(int dimension) {
067 this(dimension, DEFAULT_ZERO_TOLERANCE);
068 }
069
070 /**
071 * Construct a (dimension)-length vector of zeros, specifying zero tolerance.
072 * @param dimension Size of the vector
073 * @param epsilon The tolerance for having a value considered zero
074 */
075 public OpenMapRealVector(int dimension, double epsilon) {
076 virtualSize = dimension;
077 entries = new OpenIntToDoubleHashMap(0.0);
078 this.epsilon = epsilon;
079 }
080
081 /**
082 * Build a resized vector, for use with append.
083 * @param v The original vector
084 * @param resize The amount to resize it
085 */
086 protected OpenMapRealVector(OpenMapRealVector v, int resize) {
087 virtualSize = v.getDimension() + resize;
088 entries = new OpenIntToDoubleHashMap(v.entries);
089 epsilon = v.epsilon;
090 }
091
092 /**
093 * Build a vector with known the sparseness (for advanced use only).
094 * @param dimension The size of the vector
095 * @param expectedSize The expected number of non-zero entries
096 */
097 public OpenMapRealVector(int dimension, int expectedSize) {
098 this(dimension, expectedSize, DEFAULT_ZERO_TOLERANCE);
099 }
100
101 /**
102 * Build a vector with known the sparseness and zero tolerance setting (for advanced use only).
103 * @param dimension The size of the vector
104 * @param expectedSize The expected number of non-zero entries
105 * @param epsilon The tolerance for having a value considered zero
106 */
107 public OpenMapRealVector(int dimension, int expectedSize, double epsilon) {
108 virtualSize = dimension;
109 entries = new OpenIntToDoubleHashMap(expectedSize, 0.0);
110 this.epsilon = epsilon;
111 }
112
113 /**
114 * Create from a double array.
115 * Only non-zero entries will be stored
116 * @param values The set of values to create from
117 */
118 public OpenMapRealVector(double[] values) {
119 this(values, DEFAULT_ZERO_TOLERANCE);
120 }
121
122 /**
123 * Create from a double array, specifying zero tolerance.
124 * Only non-zero entries will be stored
125 * @param values The set of values to create from
126 * @param epsilon The tolerance for having a value considered zero
127 */
128 public OpenMapRealVector(double[] values, double epsilon) {
129 virtualSize = values.length;
130 entries = new OpenIntToDoubleHashMap(0.0);
131 this.epsilon = epsilon;
132 for (int key = 0; key < values.length; key++) {
133 double value = values[key];
134 if (!isDefaultValue(value)) {
135 entries.put(key, value);
136 }
137 }
138 }
139
140 /**
141 * Create from a Double array.
142 * Only non-zero entries will be stored
143 * @param values The set of values to create from
144 */
145 public OpenMapRealVector(Double[] values) {
146 this(values, DEFAULT_ZERO_TOLERANCE);
147 }
148
149 /**
150 * Create from a Double array.
151 * Only non-zero entries will be stored
152 * @param values The set of values to create from
153 * @param epsilon The tolerance for having a value considered zero
154 */
155 public OpenMapRealVector(Double[] values, double epsilon) {
156 virtualSize = values.length;
157 entries = new OpenIntToDoubleHashMap(0.0);
158 this.epsilon = epsilon;
159 for (int key = 0; key < values.length; key++) {
160 double value = values[key].doubleValue();
161 if (!isDefaultValue(value)) {
162 entries.put(key, value);
163 }
164 }
165 }
166
167 /**
168 * Copy constructor.
169 * @param v The instance to copy from
170 */
171 public OpenMapRealVector(OpenMapRealVector v) {
172 virtualSize = v.getDimension();
173 entries = new OpenIntToDoubleHashMap(v.getEntries());
174 epsilon = v.epsilon;
175 }
176
177 /**
178 * Generic copy constructor.
179 * @param v The instance to copy from
180 */
181 public OpenMapRealVector(RealVector v) {
182 virtualSize = v.getDimension();
183 entries = new OpenIntToDoubleHashMap(0.0);
184 epsilon = DEFAULT_ZERO_TOLERANCE;
185 for (int key = 0; key < virtualSize; key++) {
186 double value = v.getEntry(key);
187 if (!isDefaultValue(value)) {
188 entries.put(key, value);
189 }
190 }
191 }
192
193 /**
194 * Get the entries of this instance.
195 * @return entries of this instance
196 */
197 private OpenIntToDoubleHashMap getEntries() {
198 return entries;
199 }
200
201 /**
202 * Determine if this value is within epsilon of zero.
203 * @param value The value to test
204 * @return <code>true</code> if this value is within epsilon to zero, <code>false</code> otherwise
205 * @since 2.1
206 */
207 protected boolean isDefaultValue(double value) {
208 return FastMath.abs(value) < epsilon;
209 }
210
211 /** {@inheritDoc} */
212 @Override
213 public RealVector add(RealVector v) throws IllegalArgumentException {
214 checkVectorDimensions(v.getDimension());
215 if (v instanceof OpenMapRealVector) {
216 return add((OpenMapRealVector) v);
217 } else {
218 return super.add(v);
219 }
220 }
221
222 /**
223 * Optimized method to add two OpenMapRealVectors. Copies the larger vector, iterates over the smaller.
224 * @param v Vector to add with
225 * @return The sum of <code>this</code> with <code>v</code>
226 * @throws IllegalArgumentException If the dimensions don't match
227 */
228 public OpenMapRealVector add(OpenMapRealVector v) throws IllegalArgumentException{
229 checkVectorDimensions(v.getDimension());
230 boolean copyThis = entries.size() > v.entries.size();
231 OpenMapRealVector res = copyThis ? this.copy() : v.copy();
232 Iterator iter = copyThis ? v.entries.iterator() : entries.iterator();
233 OpenIntToDoubleHashMap randomAccess = copyThis ? entries : v.entries;
234 while (iter.hasNext()) {
235 iter.advance();
236 int key = iter.key();
237 if (randomAccess.containsKey(key)) {
238 res.setEntry(key, randomAccess.get(key) + iter.value());
239 } else {
240 res.setEntry(key, iter.value());
241 }
242 }
243 return res;
244 }
245
246 /**
247 * Optimized method to append a OpenMapRealVector.
248 * @param v vector to append
249 * @return The result of appending <code>v</code> to self
250 */
251 public OpenMapRealVector append(OpenMapRealVector v) {
252 OpenMapRealVector res = new OpenMapRealVector(this, v.getDimension());
253 Iterator iter = v.entries.iterator();
254 while (iter.hasNext()) {
255 iter.advance();
256 res.setEntry(iter.key() + virtualSize, iter.value());
257 }
258 return res;
259 }
260
261 /** {@inheritDoc} */
262 public OpenMapRealVector append(RealVector v) {
263 if (v instanceof OpenMapRealVector) {
264 return append((OpenMapRealVector) v);
265 }
266 return append(v.getData());
267 }
268
269 /** {@inheritDoc} */
270 public OpenMapRealVector append(double d) {
271 OpenMapRealVector res = new OpenMapRealVector(this, 1);
272 res.setEntry(virtualSize, d);
273 return res;
274 }
275
276 /** {@inheritDoc} */
277 public OpenMapRealVector append(double[] a) {
278 OpenMapRealVector res = new OpenMapRealVector(this, a.length);
279 for (int i = 0; i < a.length; i++) {
280 res.setEntry(i + virtualSize, a[i]);
281 }
282 return res;
283 }
284
285 /**
286 * {@inheritDoc}
287 * @since 2.1
288 */
289 @Override
290 public OpenMapRealVector copy() {
291 return new OpenMapRealVector(this);
292 }
293
294 /**
295 * Optimized method to compute the dot product with an OpenMapRealVector.
296 * Iterates over the smaller of the two.
297 * @param v The vector to compute the dot product with
298 * @return The dot product of <code>this</code> and <code>v</code>
299 * @throws IllegalArgumentException If the dimensions don't match
300 */
301 public double dotProduct(OpenMapRealVector v) throws IllegalArgumentException {
302 checkVectorDimensions(v.getDimension());
303 boolean thisIsSmaller = entries.size() < v.entries.size();
304 Iterator iter = thisIsSmaller ? entries.iterator() : v.entries.iterator();
305 OpenIntToDoubleHashMap larger = thisIsSmaller ? v.entries : entries;
306 double d = 0;
307 while(iter.hasNext()) {
308 iter.advance();
309 d += iter.value() * larger.get(iter.key());
310 }
311 return d;
312 }
313
314 /** {@inheritDoc} */
315 @Override
316 public double dotProduct(RealVector v) throws IllegalArgumentException {
317 if(v instanceof OpenMapRealVector) {
318 return dotProduct((OpenMapRealVector)v);
319 } else {
320 return super.dotProduct(v);
321 }
322 }
323
324 /** {@inheritDoc} */
325 public OpenMapRealVector ebeDivide(RealVector v) throws IllegalArgumentException {
326 checkVectorDimensions(v.getDimension());
327 OpenMapRealVector res = new OpenMapRealVector(this);
328 Iterator iter = res.entries.iterator();
329 while (iter.hasNext()) {
330 iter.advance();
331 res.setEntry(iter.key(), iter.value() / v.getEntry(iter.key()));
332 }
333 return res;
334 }
335
336 /** {@inheritDoc} */
337 @Override
338 public OpenMapRealVector ebeDivide(double[] v) throws IllegalArgumentException {
339 checkVectorDimensions(v.length);
340 OpenMapRealVector res = new OpenMapRealVector(this);
341 Iterator iter = res.entries.iterator();
342 while (iter.hasNext()) {
343 iter.advance();
344 res.setEntry(iter.key(), iter.value() / v[iter.key()]);
345 }
346 return res;
347 }
348
349 /** {@inheritDoc} */
350 public OpenMapRealVector ebeMultiply(RealVector v) throws IllegalArgumentException {
351 checkVectorDimensions(v.getDimension());
352 OpenMapRealVector res = new OpenMapRealVector(this);
353 Iterator iter = res.entries.iterator();
354 while (iter.hasNext()) {
355 iter.advance();
356 res.setEntry(iter.key(), iter.value() * v.getEntry(iter.key()));
357 }
358 return res;
359 }
360
361 /** {@inheritDoc} */
362 @Override
363 public OpenMapRealVector ebeMultiply(double[] v) throws IllegalArgumentException {
364 checkVectorDimensions(v.length);
365 OpenMapRealVector res = new OpenMapRealVector(this);
366 Iterator iter = res.entries.iterator();
367 while (iter.hasNext()) {
368 iter.advance();
369 res.setEntry(iter.key(), iter.value() * v[iter.key()]);
370 }
371 return res;
372 }
373
374 /** {@inheritDoc} */
375 public OpenMapRealVector getSubVector(int index, int n) throws MatrixIndexException {
376 checkIndex(index);
377 checkIndex(index + n - 1);
378 OpenMapRealVector res = new OpenMapRealVector(n);
379 int end = index + n;
380 Iterator iter = entries.iterator();
381 while (iter.hasNext()) {
382 iter.advance();
383 int key = iter.key();
384 if (key >= index && key < end) {
385 res.setEntry(key - index, iter.value());
386 }
387 }
388 return res;
389 }
390
391 /** {@inheritDoc} */
392 @Override
393 public double[] getData() {
394 double[] res = new double[virtualSize];
395 Iterator iter = entries.iterator();
396 while (iter.hasNext()) {
397 iter.advance();
398 res[iter.key()] = iter.value();
399 }
400 return res;
401 }
402
403 /** {@inheritDoc} */
404 public int getDimension() {
405 return virtualSize;
406 }
407
408 /**
409 * Optimized method to compute distance.
410 * @param v The vector to compute distance to
411 * @return The distance from <code>this</code> and <code>v</code>
412 * @throws IllegalArgumentException If the dimensions don't match
413 */
414 public double getDistance(OpenMapRealVector v) throws IllegalArgumentException {
415 Iterator iter = entries.iterator();
416 double res = 0;
417 while (iter.hasNext()) {
418 iter.advance();
419 int key = iter.key();
420 double delta;
421 delta = iter.value() - v.getEntry(key);
422 res += delta * delta;
423 }
424 iter = v.getEntries().iterator();
425 while (iter.hasNext()) {
426 iter.advance();
427 int key = iter.key();
428 if (!entries.containsKey(key)) {
429 final double value = iter.value();
430 res += value * value;
431 }
432 }
433 return FastMath.sqrt(res);
434 }
435
436 /** {@inheritDoc} */
437 @Override
438 public double getDistance(RealVector v) throws IllegalArgumentException {
439 checkVectorDimensions(v.getDimension());
440 if (v instanceof OpenMapRealVector) {
441 return getDistance((OpenMapRealVector) v);
442 }
443 return getDistance(v.getData());
444 }
445
446 /** {@inheritDoc} */
447 @Override
448 public double getDistance(double[] v) throws IllegalArgumentException {
449 checkVectorDimensions(v.length);
450 double res = 0;
451 for (int i = 0; i < v.length; i++) {
452 double delta = entries.get(i) - v[i];
453 res += delta * delta;
454 }
455 return FastMath.sqrt(res);
456 }
457
458 /** {@inheritDoc} */
459 public double getEntry(int index) throws MatrixIndexException {
460 checkIndex(index);
461 return entries.get(index);
462 }
463
464 /**
465 * Distance between two vectors.
466 * <p>This method computes the distance consistent with
467 * L<sub>1</sub> norm, i.e. the sum of the absolute values of
468 * elements differences.</p>
469 * @param v vector to which distance is requested
470 * @return distance between two vectors.
471 */
472 public double getL1Distance(OpenMapRealVector v) {
473 double max = 0;
474 Iterator iter = entries.iterator();
475 while (iter.hasNext()) {
476 iter.advance();
477 double delta = FastMath.abs(iter.value() - v.getEntry(iter.key()));
478 max += delta;
479 }
480 iter = v.getEntries().iterator();
481 while (iter.hasNext()) {
482 iter.advance();
483 int key = iter.key();
484 if (!entries.containsKey(key)) {
485 double delta = FastMath.abs(iter.value());
486 max += FastMath.abs(delta);
487 }
488 }
489 return max;
490 }
491
492 /** {@inheritDoc} */
493 @Override
494 public double getL1Distance(RealVector v) throws IllegalArgumentException {
495 checkVectorDimensions(v.getDimension());
496 if (v instanceof OpenMapRealVector) {
497 return getL1Distance((OpenMapRealVector) v);
498 }
499 return getL1Distance(v.getData());
500 }
501
502 /** {@inheritDoc} */
503 @Override
504 public double getL1Distance(double[] v) throws IllegalArgumentException {
505 checkVectorDimensions(v.length);
506 double max = 0;
507 for (int i = 0; i < v.length; i++) {
508 double delta = FastMath.abs(getEntry(i) - v[i]);
509 max += delta;
510 }
511 return max;
512 }
513
514 /**
515 * Optimized method to compute LInfDistance.
516 * @param v The vector to compute from
517 * @return the LInfDistance
518 */
519 private double getLInfDistance(OpenMapRealVector v) {
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) throws IllegalArgumentException {
545 checkVectorDimensions(v.getDimension());
546 if (v instanceof OpenMapRealVector) {
547 return getLInfDistance((OpenMapRealVector) v);
548 }
549 return getLInfDistance(v.getData());
550 }
551
552 /** {@inheritDoc} */
553 @Override
554 public double getLInfDistance(double[] v) throws IllegalArgumentException {
555 checkVectorDimensions(v.length);
556 double max = 0;
557 for (int i = 0; i < v.length; i++) {
558 double delta = FastMath.abs(getEntry(i) - v[i]);
559 if (delta > max) {
560 max = delta;
561 }
562 }
563 return max;
564 }
565
566 /** {@inheritDoc} */
567 public boolean isInfinite() {
568 boolean infiniteFound = false;
569 Iterator iter = entries.iterator();
570 while (iter.hasNext()) {
571 iter.advance();
572 final double value = iter.value();
573 if (Double.isNaN(value)) {
574 return false;
575 }
576 if (Double.isInfinite(value)) {
577 infiniteFound = true;
578 }
579 }
580 return infiniteFound;
581 }
582
583 /** {@inheritDoc} */
584 public boolean isNaN() {
585 Iterator iter = entries.iterator();
586 while (iter.hasNext()) {
587 iter.advance();
588 if (Double.isNaN(iter.value())) {
589 return true;
590 }
591 }
592 return false;
593 }
594
595 /** {@inheritDoc} */
596 @Override
597 public OpenMapRealVector mapAdd(double d) {
598 return copy().mapAddToSelf(d);
599 }
600
601 /** {@inheritDoc} */
602 @Override
603 public OpenMapRealVector mapAddToSelf(double d) {
604 for (int i = 0; i < virtualSize; i++) {
605 setEntry(i, getEntry(i) + d);
606 }
607 return this;
608 }
609
610 /** {@inheritDoc} */
611 @Override
612 public RealMatrix outerProduct(double[] v) throws IllegalArgumentException {
613 checkVectorDimensions(v.length);
614 RealMatrix res = new OpenMapRealMatrix(virtualSize, virtualSize);
615 Iterator iter = entries.iterator();
616 while (iter.hasNext()) {
617 iter.advance();
618 int row = iter.key();
619 double value = iter.value();
620 for (int col = 0; col < virtualSize; col++) {
621 res.setEntry(row, col, value * v[col]);
622 }
623 }
624 return res;
625 }
626
627 /** {@inheritDoc} */
628 public RealVector projection(RealVector v) throws IllegalArgumentException {
629 checkVectorDimensions(v.getDimension());
630 return v.mapMultiply(dotProduct(v) / v.dotProduct(v));
631 }
632
633 /** {@inheritDoc} */
634 @Override
635 public OpenMapRealVector projection(double[] v) throws IllegalArgumentException {
636 checkVectorDimensions(v.length);
637 return (OpenMapRealVector) projection(new OpenMapRealVector(v));
638 }
639
640 /** {@inheritDoc} */
641 public void setEntry(int index, double value) throws MatrixIndexException {
642 checkIndex(index);
643 if (!isDefaultValue(value)) {
644 entries.put(index, value);
645 } else if (entries.containsKey(index)) {
646 entries.remove(index);
647 }
648 }
649
650 /** {@inheritDoc} */
651 @Override
652 public void setSubVector(int index, RealVector v) throws MatrixIndexException {
653 checkIndex(index);
654 checkIndex(index + v.getDimension() - 1);
655 setSubVector(index, v.getData());
656 }
657
658 /** {@inheritDoc} */
659 @Override
660 public void setSubVector(int index, double[] v) throws MatrixIndexException {
661 checkIndex(index);
662 checkIndex(index + v.length - 1);
663 for (int i = 0; i < v.length; i++) {
664 setEntry(i + index, v[i]);
665 }
666 }
667
668 /** {@inheritDoc} */
669 @Override
670 public void set(double value) {
671 for (int i = 0; i < virtualSize; i++) {
672 setEntry(i, value);
673 }
674 }
675
676 /**
677 * Optimized method to subtract OpenMapRealVectors.
678 * @param v The vector to subtract from <code>this</code>
679 * @return The difference of <code>this</code> and <code>v</code>
680 * @throws IllegalArgumentException If the dimensions don't match
681 */
682 public OpenMapRealVector subtract(OpenMapRealVector v) throws IllegalArgumentException{
683 checkVectorDimensions(v.getDimension());
684 OpenMapRealVector res = copy();
685 Iterator iter = v.getEntries().iterator();
686 while (iter.hasNext()) {
687 iter.advance();
688 int key = iter.key();
689 if (entries.containsKey(key)) {
690 res.setEntry(key, entries.get(key) - iter.value());
691 } else {
692 res.setEntry(key, -iter.value());
693 }
694 }
695 return res;
696 }
697
698 /** {@inheritDoc} */
699 @Override
700 public OpenMapRealVector subtract(RealVector v) throws IllegalArgumentException {
701 checkVectorDimensions(v.getDimension());
702 if (v instanceof OpenMapRealVector) {
703 return subtract((OpenMapRealVector) v);
704 }
705 return subtract(v.getData());
706 }
707
708 /** {@inheritDoc} */
709 @Override
710 public OpenMapRealVector subtract(double[] v) throws IllegalArgumentException {
711 checkVectorDimensions(v.length);
712 OpenMapRealVector res = new OpenMapRealVector(this);
713 for (int i = 0; i < v.length; i++) {
714 if (entries.containsKey(i)) {
715 res.setEntry(i, entries.get(i) - v[i]);
716 } else {
717 res.setEntry(i, -v[i]);
718 }
719 }
720 return res;
721 }
722
723
724 /** {@inheritDoc} */
725 @Override
726 public OpenMapRealVector unitVector() {
727 OpenMapRealVector res = copy();
728 res.unitize();
729 return res;
730 }
731
732 /** {@inheritDoc} */
733 @Override
734 public void unitize() {
735 double norm = getNorm();
736 if (isDefaultValue(norm)) {
737 throw MathRuntimeException.createArithmeticException(LocalizedFormats.CANNOT_NORMALIZE_A_ZERO_NORM_VECTOR);
738 }
739 Iterator iter = entries.iterator();
740 while (iter.hasNext()) {
741 iter.advance();
742 entries.put(iter.key(), iter.value() / norm);
743 }
744
745 }
746
747
748 /** {@inheritDoc} */
749 @Override
750 public double[] toArray() {
751 return getData();
752 }
753
754 /** {@inheritDoc}
755 * <p> Implementation Note: This works on exact values, and as a result
756 * it is possible for {@code a.subtract(b)} to be the zero vector, while
757 * {@code a.hashCode() != b.hashCode()}.</p>
758 */
759 @Override
760 public int hashCode() {
761 final int prime = 31;
762 int result = 1;
763 long temp;
764 temp = Double.doubleToLongBits(epsilon);
765 result = prime * result + (int) (temp ^ (temp >>> 32));
766 result = prime * result + virtualSize;
767 Iterator iter = entries.iterator();
768 while (iter.hasNext()) {
769 iter.advance();
770 temp = Double.doubleToLongBits(iter.value());
771 result = prime * result + (int) (temp ^ (temp >>32));
772 }
773 return result;
774 }
775
776 /**
777 * <p> Implementation Note: This performs an exact comparison, and as a result
778 * it is possible for {@code a.subtract(b}} to be the zero vector, while
779 * {@code a.equals(b) == false}.</p>
780 * {@inheritDoc}
781 */
782 @Override
783 public boolean equals(Object obj) {
784 if (this == obj) {
785 return true;
786 }
787 if (!(obj instanceof OpenMapRealVector)) {
788 return false;
789 }
790 OpenMapRealVector other = (OpenMapRealVector) obj;
791 if (virtualSize != other.virtualSize) {
792 return false;
793 }
794 if (Double.doubleToLongBits(epsilon) !=
795 Double.doubleToLongBits(other.epsilon)) {
796 return false;
797 }
798 Iterator iter = entries.iterator();
799 while (iter.hasNext()) {
800 iter.advance();
801 double test = other.getEntry(iter.key());
802 if (Double.doubleToLongBits(test) != Double.doubleToLongBits(iter.value())) {
803 return false;
804 }
805 }
806 iter = other.getEntries().iterator();
807 while (iter.hasNext()) {
808 iter.advance();
809 double test = iter.value();
810 if (Double.doubleToLongBits(test) != Double.doubleToLongBits(getEntry(iter.key()))) {
811 return false;
812 }
813 }
814 return true;
815 }
816
817 /**
818 *
819 * @return the percentage of none zero elements as a decimal percent.
820 * @deprecated as of 2.2 replaced by the correctly spelled {@link #getSparsity()}
821 */
822 @Deprecated
823 public double getSparcity() {
824 return getSparsity();
825 }
826
827 /**
828 *
829 * @return the percentage of none zero elements as a decimal percent.
830 * @since 2.2
831 */
832 public double getSparsity() {
833 return (double)entries.size()/(double)getDimension();
834 }
835
836 /** {@inheritDoc} */
837 @Override
838 public java.util.Iterator<Entry> sparseIterator() {
839 return new OpenMapSparseIterator();
840 }
841
842 /**
843 * Implementation of <code>Entry</code> optimized for OpenMap.
844 * <p>This implementation does not allow arbitrary calls to <code>setIndex</code>
845 * since the order that entries are returned is undefined.
846 */
847 protected class OpenMapEntry extends Entry {
848
849 /** Iterator pointing to the entry. */
850 private final Iterator iter;
851
852 /** Build an entry from an iterator point to an element.
853 * @param iter iterator pointing to the entry
854 */
855 protected OpenMapEntry(Iterator iter) {
856 this.iter = iter;
857 }
858
859 /** {@inheritDoc} */
860 @Override
861 public double getValue() {
862 return iter.value();
863 }
864
865 /** {@inheritDoc} */
866 @Override
867 public void setValue(double value) {
868 entries.put(iter.key(), value);
869 }
870
871 /** {@inheritDoc} */
872 @Override
873 public int getIndex() {
874 return iter.key();
875 }
876
877 }
878
879 /**
880 * Iterator class to do iteration over just the non-zero elements.
881 * <p>This implementation is fail-fast, so cannot be used to modify any zero element.
882 *
883 */
884 protected class OpenMapSparseIterator implements java.util.Iterator<Entry> {
885
886 /** Underlying iterator. */
887 private final Iterator iter;
888
889 /** Current entry. */
890 private final Entry current;
891
892 /** Simple constructor. */
893 protected OpenMapSparseIterator() {
894 iter = entries.iterator();
895 current = new OpenMapEntry(iter);
896 }
897
898 /** {@inheritDoc} */
899 public boolean hasNext() {
900 return iter.hasNext();
901 }
902
903 /** {@inheritDoc} */
904 public Entry next() {
905 iter.advance();
906 return current;
907 }
908
909 /** {@inheritDoc} */
910 public void remove() {
911 throw new UnsupportedOperationException("Not supported");
912 }
913
914 }
915 }