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    }