View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.math.linear;
18  
19  import java.io.Serializable;
20  
21  import org.apache.commons.math.MathRuntimeException;
22  import org.apache.commons.math.util.OpenIntToDoubleHashMap;
23  import org.apache.commons.math.util.OpenIntToDoubleHashMap.Iterator;
24  
25  /**
26   * This class implements the {@link RealVector} interface with a {@link OpenIntToDoubleHashMap} backing store.
27   * @version $Revision: 800111 $ $Date: 2009-08-02 13:23:05 -0400 (Sun, 02 Aug 2009) $
28   * @since 2.0
29  */
30  public class OpenMapRealVector implements SparseRealVector, Serializable {
31  
32      /** Serializable version identifier. */
33      private static final long serialVersionUID = 8772222695580707260L;
34  
35      /** Default Tolerance for having a value considered zero. */
36      public static final double DEFAULT_ZERO_TOLERANCE = 1.0e-12;
37  
38      /** Entries of the vector. */
39      private final OpenIntToDoubleHashMap entries;
40  
41      /** Dimension of the vector. */
42      private final int virtualSize;
43  
44      /** Tolerance for having a value considered zero. */
45      private double epsilon;
46  
47      /**
48       * Build a 0-length vector.
49       * <p>Zero-length vectors may be used to initialized construction of vectors
50       * by data gathering. We start with zero-length and use either the {@link
51       * #OpenMapRealVector(OpenMapRealVector, int)} constructor
52       * or one of the <code>append</code> method ({@link #append(double)}, {@link
53       * #append(double[])}, {@link #append(RealVector)}) to gather data
54       * into this vector.</p>
55       */
56      public OpenMapRealVector() {
57          this(0, DEFAULT_ZERO_TOLERANCE);
58      }
59  
60      /**
61       * Construct a (dimension)-length vector of zeros.
62       * @param dimension size of the vector
63       */
64      public OpenMapRealVector(int dimension) {
65          this(dimension, DEFAULT_ZERO_TOLERANCE);
66      }
67  
68      /**
69       * Construct a (dimension)-length vector of zeros, specifying zero tolerance.
70       * @param dimension Size of the vector
71       * @param epsilon The tolerance for having a value considered zero
72       */
73      public OpenMapRealVector(int dimension, double epsilon) {
74          virtualSize = dimension;
75          entries = new OpenIntToDoubleHashMap(0.0);
76          this.epsilon = epsilon;
77      }
78  
79      /**
80       * Build a resized vector, for use with append.
81       * @param v The original vector
82       * @param resize The amount to resize it
83       */
84      protected OpenMapRealVector(OpenMapRealVector v, int resize) {
85          virtualSize = v.getDimension() + resize;
86          entries = new OpenIntToDoubleHashMap(v.entries);
87          epsilon = v.getEpsilon();
88      }
89  
90      /**
91       * Build a vector with known the sparseness (for advanced use only).
92       * @param dimension The size of the vector
93       * @param expectedSize The expected number of non-zero entries
94       */
95      public OpenMapRealVector(int dimension, int expectedSize) {
96          this(dimension, expectedSize, DEFAULT_ZERO_TOLERANCE);
97      }
98  
99      /**
100      * Build a vector with known the sparseness and zero tolerance setting (for advanced use only).
101      * @param dimension The size of the vector
102      * @param expectedSize The expected number of non-zero entries
103      * @param epsilon The tolerance for having a value considered zero
104      */
105     public OpenMapRealVector(int dimension, int expectedSize, double epsilon) {
106         virtualSize = dimension;
107         entries = new OpenIntToDoubleHashMap(expectedSize, 0.0);
108         this.epsilon = epsilon;
109     }
110 
111     /**
112      * Create from a double array.
113      * Only non-zero entries will be stored
114      * @param values The set of values to create from
115      */
116     public OpenMapRealVector(double[] values) {
117         this(values, DEFAULT_ZERO_TOLERANCE);
118     }
119 
120     /**
121      * Create from a double array, specifying zero tolerance.
122      * Only non-zero entries will be stored
123      * @param values The set of values to create from
124      * @param epsilon The tolerance for having a value considered zero
125      */
126     public OpenMapRealVector(double[] values, double epsilon) {
127         virtualSize = values.length;
128         entries = new OpenIntToDoubleHashMap(0.0);
129         this.epsilon = epsilon;
130         for (int key = 0; key < values.length; key++) {
131             double value = values[key];
132             if (!isZero(value)) {
133                 entries.put(key, value);
134             }
135         }
136     }
137 
138     /**
139      * Create from a Double array.
140      * Only non-zero entries will be stored
141      * @param values The set of values to create from
142      */
143     public OpenMapRealVector(Double[] values) {
144         this(values, DEFAULT_ZERO_TOLERANCE);
145     }
146 
147     /**
148      * Create from a Double array.
149      * Only non-zero entries will be stored
150      * @param values The set of values to create from
151      * @param epsilon The tolerance for having a value considered zero
152      */
153     public OpenMapRealVector(Double[] values, double epsilon) {
154         virtualSize = values.length;
155         entries = new OpenIntToDoubleHashMap(0.0);
156         this.epsilon = epsilon;
157         for (int key = 0; key < values.length; key++) {
158             double value = values[key].doubleValue();
159             if (!isZero(value)) {
160                 entries.put(key, value);
161             }
162         }
163     }
164 
165     /**
166      * Copy constructor.
167      * @param v The instance to copy from
168      */
169     public OpenMapRealVector(OpenMapRealVector v) {
170         virtualSize = v.getDimension();
171         entries = new OpenIntToDoubleHashMap(v.getEntries());
172         epsilon = v.getEpsilon();
173     }
174 
175     /**
176      * Generic copy constructor.
177      * @param v The instance to copy from
178      */
179     public OpenMapRealVector(RealVector v) {
180         virtualSize = v.getDimension();
181         entries = new OpenIntToDoubleHashMap(0.0);
182         epsilon = DEFAULT_ZERO_TOLERANCE;
183         for (int key = 0; key < virtualSize; key++) {
184             double value = v.getEntry(key);
185             if (!isZero(value)) {
186                 entries.put(key, value);
187             }
188         }
189     }
190 
191     /**
192      * Get the entries of this instance.
193      * @return entries of this instance
194      */
195     private OpenIntToDoubleHashMap getEntries() {
196         return entries;
197     }
198 
199     /**
200      * Determine if this value is zero.
201      * @param value The value to test
202      * @return <code>true</code> if this value is zero, <code>false</code> otherwise
203      */
204     protected boolean isZero(double value) {
205         return value > -epsilon && value < epsilon;
206     }
207 
208     /**
209      * Get the tolerance for having a value considered zero.
210      * @return The test range for testing if a value is zero
211      */
212     public double getEpsilon() {
213         return epsilon;
214     }
215 
216     /**
217      * Set the tolerance for having a value considered zero.
218      * @param epsilon The test range for testing if a value is zero
219      */
220     public void setEpsilon(double epsilon) {
221         this.epsilon = epsilon;
222     }
223 
224     /** {@inheritDoc} */
225     public OpenMapRealVector add(RealVector v) throws IllegalArgumentException {
226         checkVectorDimensions(v.getDimension());
227         if (v instanceof OpenMapRealVector) {
228             return add((OpenMapRealVector) v);
229         }
230         return add(v.getData());
231     }
232 
233     /**
234      * Optimized method to add two OpenMapRealVectors.
235      * @param v Vector to add with
236      * @return The sum of <code>this</code> with <code>v</code>
237      * @throws IllegalArgumentException If the dimensions don't match
238      */
239     public OpenMapRealVector add(OpenMapRealVector v) throws IllegalArgumentException{
240         checkVectorDimensions(v.getDimension());
241         OpenMapRealVector res = copy();
242         Iterator iter = v.getEntries().iterator();
243         while (iter.hasNext()) {
244             iter.advance();
245             int key = iter.key();
246             if (entries.containsKey(key)) {
247                 res.setEntry(key, entries.get(key) + iter.value());
248             } else {
249                 res.setEntry(key, iter.value());
250             }
251         }
252         return res;
253     }
254 
255     /** {@inheritDoc} */
256     public OpenMapRealVector add(double[] v) throws IllegalArgumentException {
257         checkVectorDimensions(v.length);
258         OpenMapRealVector res = new OpenMapRealVector(getDimension());
259         for (int i = 0; i < v.length; i++) {
260             res.setEntry(i, v[i] + getEntry(i));
261         }
262         return res;
263     }
264 
265     /**
266      * Optimized method to append a OpenMapRealVector.
267      * @param v vector to append
268      * @return The result of appending <code>v</code> to self
269      */
270     public OpenMapRealVector append(OpenMapRealVector v) {
271         OpenMapRealVector res = new OpenMapRealVector(this, v.getDimension());
272         Iterator iter = v.entries.iterator();
273         while (iter.hasNext()) {
274             iter.advance();
275             res.setEntry(iter.key() + virtualSize, iter.value());
276         }
277         return res;
278     }
279 
280     /** {@inheritDoc} */
281     public OpenMapRealVector append(RealVector v) {
282         if (v instanceof OpenMapRealVector) {
283             return append((OpenMapRealVector) v);
284         }
285         return append(v.getData());
286     }
287 
288     /** {@inheritDoc} */
289     public OpenMapRealVector append(double d) {
290         OpenMapRealVector res = new OpenMapRealVector(this, 1);
291         res.setEntry(virtualSize, d);
292         return res;
293     }
294 
295     /** {@inheritDoc} */
296     public OpenMapRealVector append(double[] a) {
297         OpenMapRealVector res = new OpenMapRealVector(this, a.length);
298         for (int i = 0; i < a.length; i++) {
299             res.setEntry(i + virtualSize, a[i]);
300         }
301         return res;
302     }
303 
304     /** {@inheritDoc} */
305     public OpenMapRealVector copy() {
306         return new OpenMapRealVector(this);
307     }
308 
309     /** {@inheritDoc} */
310     public double dotProduct(RealVector v) throws IllegalArgumentException {
311         checkVectorDimensions(v.getDimension());
312         double res = 0;
313         Iterator iter = entries.iterator();
314         while (iter.hasNext()) {
315             iter.advance();
316             res += v.getEntry(iter.key()) * iter.value();
317         }
318         return res;
319     }
320 
321     /** {@inheritDoc} */
322     public double dotProduct(double[] v) throws IllegalArgumentException {
323         checkVectorDimensions(v.length);
324         double res = 0;
325         Iterator iter = entries.iterator();
326         while (iter.hasNext()) {
327             int idx = iter.key();
328             double value = 0;
329             if (idx < v.length) {
330                 value = v[idx];
331             }
332             res += value * iter.value();
333         }
334         return res;
335     }
336 
337     /** {@inheritDoc} */
338     public OpenMapRealVector ebeDivide(RealVector v) throws IllegalArgumentException {
339         checkVectorDimensions(v.getDimension());
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.getEntry(iter.key()));
345         }
346         return res;
347     }
348 
349     /** {@inheritDoc} */
350     public OpenMapRealVector ebeDivide(double[] v) throws IllegalArgumentException {
351         checkVectorDimensions(v.length);
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[iter.key()]);
357         }
358         return res;
359     }
360 
361     /** {@inheritDoc} */
362     public OpenMapRealVector ebeMultiply(RealVector v) throws IllegalArgumentException {
363         checkVectorDimensions(v.getDimension());
364         OpenMapRealVector res = new OpenMapRealVector(this);
365         Iterator iter = res.entries.iterator();
366         while (iter.hasNext()) {
367             iter.advance();
368             res.setEntry(iter.key(), iter.value() * v.getEntry(iter.key()));
369         }
370         return res;
371     }
372 
373     /** {@inheritDoc} */
374     public OpenMapRealVector ebeMultiply(double[] v) throws IllegalArgumentException {
375         checkVectorDimensions(v.length);
376         OpenMapRealVector res = new OpenMapRealVector(this);
377         Iterator iter = res.entries.iterator();
378         while (iter.hasNext()) {
379             iter.advance();
380             res.setEntry(iter.key(), iter.value() * v[iter.key()]);
381         }
382         return res;
383     }
384 
385     /** {@inheritDoc} */
386     public OpenMapRealVector getSubVector(int index, int n) throws MatrixIndexException {
387         checkIndex(index);
388         checkIndex(index + n - 1);
389         OpenMapRealVector res = new OpenMapRealVector(n);
390         int end = index + n;
391         Iterator iter = entries.iterator();
392         while (iter.hasNext()) {
393             iter.advance();
394             int key = iter.key();
395             if (key >= index && key < end) {
396                 res.setEntry(key - index, iter.value());
397             }
398         }
399         return res;
400     }
401 
402     /** {@inheritDoc} */
403     public double[] getData() {
404         double[] res = new double[virtualSize];
405         Iterator iter = entries.iterator();
406         while (iter.hasNext()) {
407             iter.advance();
408             res[iter.key()] = iter.value();
409         }
410         return res;
411     }
412 
413     /** {@inheritDoc} */
414     public int getDimension() {
415         return virtualSize;
416     }
417 
418     /**
419      * Optimized method to compute distance.
420      * @param v The vector to compute distance to
421      * @return The distance from <code>this</code> and <code>v</code>
422      * @throws IllegalArgumentException If the dimensions don't match
423      */
424     public double getDistance(OpenMapRealVector v) throws IllegalArgumentException {
425         Iterator iter = entries.iterator();
426         double res = 0;
427         while (iter.hasNext()) {
428             iter.advance();
429             int key = iter.key();
430             double delta;
431             delta = iter.value() - v.getEntry(key);
432             res += delta * delta;
433         }
434         iter = v.getEntries().iterator();
435         while (iter.hasNext()) {
436             iter.advance();
437             int key = iter.key();
438             if (!entries.containsKey(key)) {
439                 final double value = iter.value();
440                 res += value * value;
441             }
442         }
443         return Math.sqrt(res);
444     }
445 
446     /** {@inheritDoc} */
447     public double getDistance(RealVector v) throws IllegalArgumentException {
448         checkVectorDimensions(v.getDimension());
449         if (v instanceof OpenMapRealVector) {
450             return getDistance((OpenMapRealVector) v);
451         }
452         return getDistance(v.getData());
453     }
454 
455     /** {@inheritDoc} */
456     public double getDistance(double[] v) throws IllegalArgumentException {
457         checkVectorDimensions(v.length);
458         double res = 0;
459         for (int i = 0; i < v.length; i++) {
460             double delta = entries.get(i) - v[i];
461             res += delta * delta;
462         }
463         return Math.sqrt(res);
464     }
465 
466     /** {@inheritDoc} */
467     public double getEntry(int index) throws MatrixIndexException {
468         checkIndex(index);
469         return entries.get(index);
470     }
471 
472     /**
473      * Distance between two vectors.
474      * <p>This method computes the distance consistent with
475      * L<sub>1</sub> norm, i.e. the sum of the absolute values of
476      * elements differences.</p>
477      * @param v vector to which distance is requested
478      * @return distance between two vectors.
479      */
480     public double getL1Distance(OpenMapRealVector v) {
481         double max = 0;
482         Iterator iter = entries.iterator();
483         while (iter.hasNext()) {
484             iter.advance();
485             double delta = Math.abs(iter.value() - v.getEntry(iter.key()));
486             max += delta;
487         }
488         iter = v.getEntries().iterator();
489         while (iter.hasNext()) {
490             iter.advance();
491             int key = iter.key();
492             if (!entries.containsKey(key)) {
493                 double delta = Math.abs(iter.value());
494                 max +=  Math.abs(delta);
495             }
496         }
497         return max;
498     }
499 
500     /** {@inheritDoc} */
501     public double getL1Distance(RealVector v) throws IllegalArgumentException {
502         checkVectorDimensions(v.getDimension());
503         if (v instanceof OpenMapRealVector) {
504             return getL1Distance((OpenMapRealVector) v);
505         }
506         return getL1Distance(v.getData());
507     }
508 
509     /** {@inheritDoc} */
510     public double getL1Distance(double[] v) throws IllegalArgumentException {
511         checkVectorDimensions(v.length);
512         double max = 0;
513         for (int i = 0; i < v.length; i++) {
514             double delta = Math.abs(getEntry(i) - v[i]);
515             max += delta;
516         }
517         return max;
518     }
519 
520     /** {@inheritDoc} */
521     public double getL1Norm() {
522         double res = 0;
523         Iterator iter = entries.iterator();
524         while (iter.hasNext()) {
525             iter.advance();
526             res += Math.abs(iter.value());
527         }
528         return res;
529     }
530 
531     /**
532      * Optimized method to compute LInfDistance.
533      * @param v The vector to compute from
534      * @return the LInfDistance
535      */
536     private double getLInfDistance(OpenMapRealVector v) {
537         double max = 0;
538         Iterator iter = entries.iterator();
539         while (iter.hasNext()) {
540             iter.advance();
541             double delta = Math.abs(iter.value() - v.getEntry(iter.key()));
542             if (delta > max) {
543                 max = delta;
544             }
545         }
546         iter = v.getEntries().iterator();
547         while (iter.hasNext()) {
548             iter.advance();
549             int key = iter.key();
550             if (!entries.containsKey(key)) {
551                 if (iter.value() > max) {
552                     max = iter.value();
553                 }
554             }
555         }
556         return max;
557     }
558 
559     /** {@inheritDoc} */
560     public double getLInfDistance(RealVector v) throws IllegalArgumentException {
561         checkVectorDimensions(v.getDimension());
562         if (v instanceof OpenMapRealVector) {
563             return getLInfDistance((OpenMapRealVector) v);
564         }
565         return getLInfDistance(v.getData());
566     }
567 
568     /** {@inheritDoc} */
569     public double getLInfDistance(double[] v) throws IllegalArgumentException {
570         checkVectorDimensions(v.length);
571         double max = 0;
572         for (int i = 0; i < v.length; i++) {
573             double delta = Math.abs(getEntry(i) - v[i]);
574             if (delta > max) {
575                 max = delta;
576             }
577         }
578         return max;
579     }
580 
581     /** {@inheritDoc} */
582     public double getLInfNorm() {
583         double max = 0;
584         Iterator iter = entries.iterator();
585         while (iter.hasNext()) {
586             iter.advance();
587             max += iter.value();
588         }
589         return max;
590     }
591 
592     /** {@inheritDoc} */
593     public double getNorm() {
594         double res = 0;
595         Iterator iter = entries.iterator();
596         while (iter.hasNext()) {
597             iter.advance();
598             res += iter.value() * iter.value();
599         }
600         return Math.sqrt(res);
601     }
602 
603     /** {@inheritDoc} */
604     public boolean isInfinite() {
605         boolean infiniteFound = false;
606         Iterator iter = entries.iterator();
607         while (iter.hasNext()) {
608             iter.advance();
609             final double value = iter.value();
610             if (Double.isNaN(value)) {
611                 return false;
612             }
613             if (Double.isInfinite(value)) {
614                 infiniteFound = true;
615             }
616         }
617         return infiniteFound;
618     }
619 
620     /** {@inheritDoc} */
621     public boolean isNaN() {
622         Iterator iter = entries.iterator();
623         while (iter.hasNext()) {
624             iter.advance();
625             if (Double.isNaN(iter.value())) {
626                 return true;
627             }
628         }
629         return false;
630     }
631 
632     /** {@inheritDoc} */
633     public OpenMapRealVector mapAbs() {
634         return copy().mapAbsToSelf();
635     }
636 
637     /** {@inheritDoc} */
638     public OpenMapRealVector mapAbsToSelf() {
639         Iterator iter = entries.iterator();
640         while (iter.hasNext()) {
641             iter.advance();
642             entries.put(iter.key(), Math.abs(iter.value()));
643         }
644         return this;
645     }
646 
647     /** {@inheritDoc} */
648     public OpenMapRealVector mapAcos() {
649         return copy().mapAcosToSelf();
650     }
651 
652     /** {@inheritDoc} */
653     public OpenMapRealVector mapAcosToSelf() {
654         for (int i = 0; i < virtualSize; i++) {
655             setEntry(i, Math.acos(getEntry(i)));
656         }
657         return this;
658     }
659 
660     /** {@inheritDoc} */
661     public OpenMapRealVector mapAdd(double d) {
662         return copy().mapAddToSelf(d);
663     }
664 
665     /** {@inheritDoc} */
666     public OpenMapRealVector mapAddToSelf(double d) {
667         for (int i = 0; i < virtualSize; i++) {
668             setEntry(i, getEntry(i) + d);
669         }
670         return this;
671     }
672 
673     /** {@inheritDoc} */
674     public OpenMapRealVector mapAsin() {
675         return copy().mapAsinToSelf();
676     }
677 
678     /** {@inheritDoc} */
679     public OpenMapRealVector mapAsinToSelf() {
680         Iterator iter = entries.iterator();
681         while (iter.hasNext()) {
682             iter.advance();
683             entries.put(iter.key(), Math.asin(iter.value()));
684         }
685         return this;
686     }
687 
688     /** {@inheritDoc} */
689     public OpenMapRealVector mapAtan() {
690         return copy().mapAtanToSelf();
691     }
692 
693     /** {@inheritDoc} */
694     public OpenMapRealVector mapAtanToSelf() {
695         Iterator iter = entries.iterator();
696         while (iter.hasNext()) {
697             iter.advance();
698             entries.put(iter.key(), Math.atan(iter.value()));
699         }
700         return this;
701     }
702 
703     /** {@inheritDoc} */
704     public OpenMapRealVector mapCbrt() {
705         return copy().mapCbrtToSelf();
706     }
707 
708     /** {@inheritDoc} */
709     public OpenMapRealVector mapCbrtToSelf() {
710         Iterator iter = entries.iterator();
711         while (iter.hasNext()) {
712             iter.advance();
713             entries.put(iter.key(), Math.cbrt(iter.value()));
714         }
715         return this;
716     }
717 
718     /** {@inheritDoc} */
719     public OpenMapRealVector mapCeil() {
720         return copy().mapCeilToSelf();
721     }
722 
723     /** {@inheritDoc} */
724     public OpenMapRealVector mapCeilToSelf() {
725         Iterator iter = entries.iterator();
726         while (iter.hasNext()) {
727             iter.advance();
728             entries.put(iter.key(), Math.ceil(iter.value()));
729         }
730         return this;
731     }
732 
733     /** {@inheritDoc} */
734     public OpenMapRealVector mapCos() {
735         return copy().mapCosToSelf();
736     }
737 
738     /** {@inheritDoc} */
739     public OpenMapRealVector mapCosToSelf() {
740         for (int i = 0; i < virtualSize; i++) {
741             setEntry(i, Math.cos(getEntry(i)));
742         }
743         return this;
744     }
745 
746     /** {@inheritDoc} */
747     public OpenMapRealVector mapCosh() {
748         return copy().mapCoshToSelf();
749     }
750 
751     /** {@inheritDoc} */
752     public OpenMapRealVector mapCoshToSelf() {
753         for (int i = 0; i < virtualSize; i++) {
754             setEntry(i, Math.cosh(getEntry(i)));
755         }
756         return this;
757     }
758 
759     /** {@inheritDoc} */
760     public OpenMapRealVector mapDivide(double d) {
761         return copy().mapDivideToSelf(d);
762     }
763 
764     /** {@inheritDoc} */
765     public OpenMapRealVector mapDivideToSelf(double d) {
766         Iterator iter = entries.iterator();
767         while (iter.hasNext()) {
768             iter.advance();
769             entries.put(iter.key(), iter.value() / d);
770         }
771         return this;
772     }
773 
774     /** {@inheritDoc} */
775     public OpenMapRealVector mapExp() {
776         return copy().mapExpToSelf();
777     }
778 
779     /** {@inheritDoc} */
780     public OpenMapRealVector mapExpToSelf() {
781         for (int i = 0; i < virtualSize; i++) {
782             entries.put(i, Math.exp(entries.get(i)));
783         }
784         return this;
785     }
786 
787     /** {@inheritDoc} */
788     public OpenMapRealVector mapExpm1() {
789         return copy().mapExpm1ToSelf();
790     }
791 
792     /** {@inheritDoc} */
793     public OpenMapRealVector mapExpm1ToSelf() {
794         Iterator iter = entries.iterator();
795         while (iter.hasNext()) {
796             iter.advance();
797             entries.put(iter.key(), Math.expm1(iter.value()));
798         }
799         return this;
800     }
801 
802     /** {@inheritDoc} */
803     public OpenMapRealVector mapFloor() {
804         return copy().mapFloorToSelf();
805     }
806 
807     /** {@inheritDoc} */
808     public OpenMapRealVector mapFloorToSelf() {
809         Iterator iter = entries.iterator();
810         while (iter.hasNext()) {
811             iter.advance();
812             entries.put(iter.key(), Math.floor(iter.value()));
813         }
814         return this;
815     }
816 
817     /** {@inheritDoc} */
818     public OpenMapRealVector mapInv() {
819         return copy().mapInvToSelf();
820     }
821 
822     /** {@inheritDoc} */
823     public OpenMapRealVector mapInvToSelf() {
824         for (int i = 0; i < virtualSize; i++) {
825             setEntry(i, 1.0/getEntry(i));
826         }
827         return this;
828     }
829 
830     /** {@inheritDoc} */
831     public OpenMapRealVector mapLog() {
832         return copy().mapLogToSelf();
833     }
834 
835     /** {@inheritDoc} */
836     public OpenMapRealVector mapLog10() {
837         return copy().mapLog10ToSelf();
838     }
839 
840     /** {@inheritDoc} */
841     public OpenMapRealVector mapLog10ToSelf() {
842         for (int i = 0; i < virtualSize; i++) {
843             setEntry(i, Math.log10(getEntry(i)));
844         }
845         return this;
846     }
847 
848     /** {@inheritDoc} */
849     public OpenMapRealVector mapLog1p() {
850         return copy().mapLog1pToSelf();
851     }
852 
853     /** {@inheritDoc} */
854     public OpenMapRealVector mapLog1pToSelf() {
855         Iterator iter = entries.iterator();
856         while (iter.hasNext()) {
857             iter.advance();
858             entries.put(iter.key(), Math.log1p(iter.value()));
859         }
860         return this;
861     }
862 
863     /** {@inheritDoc} */
864     public OpenMapRealVector mapLogToSelf() {
865         for (int i = 0; i < virtualSize; i++) {
866             setEntry(i, Math.log(getEntry(i)));
867         }
868        return this;
869     }
870 
871     /** {@inheritDoc} */
872     public OpenMapRealVector mapMultiply(double d) {
873         return copy().mapMultiplyToSelf(d);
874     }
875 
876     /** {@inheritDoc} */
877     public OpenMapRealVector mapMultiplyToSelf(double d) {
878         Iterator iter = entries.iterator();
879         while (iter.hasNext()) {
880             iter.advance();
881             entries.put(iter.key(), iter.value() * d);
882         }
883         return this;
884     }
885     /** {@inheritDoc} */
886     public OpenMapRealVector mapPow(double d) {
887         return copy().mapPowToSelf(d);
888     }
889 
890     /** {@inheritDoc} */
891     public OpenMapRealVector mapPowToSelf(double d) {
892         Iterator iter = entries.iterator();
893         while (iter.hasNext()) {
894             iter.advance();
895             entries.put(iter.key(), Math.pow(iter.value(), d));
896         }
897         return this;
898     }
899 
900     /** {@inheritDoc} */
901     public OpenMapRealVector mapRint() {
902         return copy().mapRintToSelf();
903     }
904 
905     /** {@inheritDoc} */
906     public OpenMapRealVector mapRintToSelf() {
907         Iterator iter = entries.iterator();
908         while (iter.hasNext()) {
909             iter.advance();
910             entries.put(iter.key(), Math.rint(iter.value()));
911         }
912         return this;
913     }
914 
915     /** {@inheritDoc} */
916     public OpenMapRealVector mapSignum() {
917         return copy().mapSignumToSelf();
918     }
919 
920     /** {@inheritDoc} */
921     public OpenMapRealVector mapSignumToSelf() {
922         Iterator iter = entries.iterator();
923         while (iter.hasNext()) {
924             iter.advance();
925             entries.put(iter.key(), Math.signum(iter.value()));
926         }
927         return this;
928     }
929 
930     /** {@inheritDoc} */
931     public OpenMapRealVector mapSin() {
932         return copy().mapSinToSelf();
933     }
934 
935     /** {@inheritDoc} */
936     public OpenMapRealVector mapSinToSelf() {
937         Iterator iter = entries.iterator();
938         while (iter.hasNext()) {
939             iter.advance();
940             entries.put(iter.key(), Math.sin(iter.value()));
941         }
942         return this;
943     }
944 
945     /** {@inheritDoc} */
946     public OpenMapRealVector mapSinh() {
947         return copy().mapSinhToSelf();
948     }
949 
950     /** {@inheritDoc} */
951     public OpenMapRealVector mapSinhToSelf() {
952 
953         Iterator iter = entries.iterator();
954         while (iter.hasNext()) {
955             iter.advance();
956             entries.put(iter.key(), Math.sinh(iter.value()));
957         }
958         return this;
959     }
960 
961     /** {@inheritDoc} */
962     public OpenMapRealVector mapSqrt() {
963         return copy().mapSqrtToSelf();
964     }
965 
966     /** {@inheritDoc} */
967     public OpenMapRealVector mapSqrtToSelf() {
968         Iterator iter = entries.iterator();
969         while (iter.hasNext()) {
970             iter.advance();
971             entries.put(iter.key(), Math.sqrt(iter.value()));
972         }
973         return this;
974     }
975 
976     /** {@inheritDoc} */
977     public OpenMapRealVector mapSubtract(double d) {
978         return copy().mapSubtractToSelf(d);
979     }
980 
981     /** {@inheritDoc} */
982     public OpenMapRealVector mapSubtractToSelf(double d) {
983         return mapAddToSelf(-d);
984     }
985 
986     /** {@inheritDoc} */
987     public OpenMapRealVector mapTan() {
988         return copy().mapTanToSelf();
989     }
990 
991     /** {@inheritDoc} */
992     public OpenMapRealVector mapTanToSelf() {
993         Iterator iter = entries.iterator();
994         while (iter.hasNext()) {
995             iter.advance();
996             entries.put(iter.key(), Math.tan(iter.value()));
997         }
998         return this;
999     }
1000 
1001     /** {@inheritDoc} */
1002     public OpenMapRealVector mapTanh() {
1003         return copy().mapTanhToSelf();
1004     }
1005 
1006     /** {@inheritDoc} */
1007     public OpenMapRealVector mapTanhToSelf() {
1008         Iterator iter = entries.iterator();
1009         while (iter.hasNext()) {
1010             iter.advance();
1011             entries.put(iter.key(), Math.tanh(iter.value()));
1012         }
1013         return this;
1014     }
1015 
1016     /** {@inheritDoc} */
1017     public OpenMapRealVector mapUlp() {
1018         return copy().mapUlpToSelf();
1019     }
1020 
1021     /** {@inheritDoc} */
1022     public OpenMapRealVector mapUlpToSelf() {
1023         Iterator iter = entries.iterator();
1024         while (iter.hasNext()) {
1025             iter.advance();
1026             entries.put(iter.key(), Math.ulp(iter.value()));
1027         }
1028         return this;
1029     }
1030 
1031     /**
1032      * Optimized method to compute the outer product.
1033      * @param v The vector to comput the outer product on
1034      * @return The outer product of <code>this</code> and <code>v</code>
1035      * @throws IllegalArgumentException If the dimensions don't match
1036      */
1037     public OpenMapRealMatrix outerproduct(OpenMapRealVector v) throws IllegalArgumentException{
1038         checkVectorDimensions(v.getDimension());
1039         OpenMapRealMatrix res = new OpenMapRealMatrix(virtualSize, virtualSize);
1040         Iterator iter = entries.iterator();
1041         while (iter.hasNext()) {
1042             iter.advance();
1043             Iterator iter2 = v.getEntries().iterator();
1044             while (iter2.hasNext()) {
1045                 iter2.advance();
1046                 res.setEntry(iter.key(), iter2.key(), iter.value()*iter2.value());
1047             }
1048         }
1049         return res;
1050     }
1051 
1052     /** {@inheritDoc} */
1053     public RealMatrix outerProduct(RealVector v)
1054             throws IllegalArgumentException {
1055         checkVectorDimensions(v.getDimension());
1056         if (v instanceof OpenMapRealVector) {
1057             return outerproduct((OpenMapRealVector)v);
1058         }
1059         RealMatrix res = new OpenMapRealMatrix(virtualSize, virtualSize);
1060         Iterator iter = entries.iterator();
1061         while (iter.hasNext()) {
1062             iter.advance();
1063             int row = iter.key();
1064             for (int col = 0; col < virtualSize; col++) {
1065                 res.setEntry(row, col, iter.value()*v.getEntry(col));
1066             }
1067         }
1068         return res;
1069     }
1070 
1071     /** {@inheritDoc} */
1072     public RealMatrix outerProduct(double[] v) throws IllegalArgumentException {
1073         checkVectorDimensions(v.length);
1074         RealMatrix res = new OpenMapRealMatrix(virtualSize, virtualSize);
1075         Iterator iter = entries.iterator();
1076         while (iter.hasNext()) {
1077             iter.advance();
1078             int row = iter.key();
1079             double value = iter.value();
1080             for (int col = 0; col < virtualSize; col++) {
1081                 res.setEntry(row, col, value * v[col]);
1082             }
1083         }
1084         return res;
1085     }
1086 
1087     /** {@inheritDoc} */
1088     public RealVector projection(RealVector v) throws IllegalArgumentException {
1089         checkVectorDimensions(v.getDimension());
1090         return v.mapMultiply(dotProduct(v) / v.dotProduct(v));
1091     }
1092 
1093     /** {@inheritDoc} */
1094     public OpenMapRealVector projection(double[] v) throws IllegalArgumentException {
1095         checkVectorDimensions(v.length);
1096         return (OpenMapRealVector) projection(new OpenMapRealVector(v));
1097     }
1098 
1099     /** {@inheritDoc} */
1100     public void setEntry(int index, double value) throws MatrixIndexException {
1101         checkIndex(index);
1102         if (!isZero(value)) {
1103             entries.put(index, value);
1104         } else if (entries.containsKey(index)) {
1105             entries.remove(index);
1106         }
1107     }
1108 
1109     /** {@inheritDoc} */
1110     public void setSubVector(int index, RealVector v) throws MatrixIndexException {
1111         checkIndex(index);
1112         checkIndex(index + v.getDimension() - 1);
1113         setSubVector(index, v.getData());
1114     }
1115 
1116     /** {@inheritDoc} */
1117     public void setSubVector(int index, double[] v) throws MatrixIndexException {
1118         checkIndex(index);
1119         checkIndex(index + v.length - 1);
1120         for (int i = 0; i < v.length; i++) {
1121             setEntry(i + index, v[i]);
1122         }
1123     }
1124 
1125     /** {@inheritDoc} */
1126     public void set(double value) {
1127         for (int i = 0; i < virtualSize; i++) {
1128             setEntry(i, value);
1129         }
1130     }
1131 
1132     /**
1133      * Optimized method to subtract OpenMapRealVectors.
1134      * @param v The vector to subtract from <code>this</code>
1135      * @return The difference of <code>this</code> and <code>v</code>
1136      * @throws IllegalArgumentException If the dimensions don't match
1137      */
1138     public OpenMapRealVector subtract(OpenMapRealVector v) throws IllegalArgumentException{
1139         checkVectorDimensions(v.getDimension());
1140         OpenMapRealVector res = copy();
1141         Iterator iter = v.getEntries().iterator();
1142         while (iter.hasNext()) {
1143             iter.advance();
1144             int key = iter.key();
1145             if (entries.containsKey(key)) {
1146                 res.setEntry(key, entries.get(key) - iter.value());
1147             } else {
1148                 res.setEntry(key, -iter.value());
1149             }
1150         }
1151         return res;
1152     }
1153 
1154     /** {@inheritDoc} */
1155     public OpenMapRealVector subtract(RealVector v) throws IllegalArgumentException {
1156         checkVectorDimensions(v.getDimension());
1157         if (v instanceof OpenMapRealVector) {
1158             return subtract((OpenMapRealVector) v);
1159         }
1160         return subtract(v.getData());
1161     }
1162 
1163     /** {@inheritDoc} */
1164     public OpenMapRealVector subtract(double[] v) throws IllegalArgumentException {
1165         checkVectorDimensions(v.length);
1166         OpenMapRealVector res = new OpenMapRealVector(this);
1167         for (int i = 0; i < v.length; i++) {
1168             if (entries.containsKey(i)) {
1169                 res.setEntry(i, entries.get(i) - v[i]);
1170             } else {
1171                 res.setEntry(i, -v[i]);
1172             }
1173         }
1174         return res;
1175     }
1176 
1177 
1178     /** {@inheritDoc} */
1179     public OpenMapRealVector unitVector() {
1180         OpenMapRealVector res = copy();
1181         res.unitize();
1182         return res;
1183     }
1184 
1185     /** {@inheritDoc} */
1186     public void unitize() {
1187         double norm = getNorm();
1188         if (isZero(norm)) {
1189             throw  MathRuntimeException.createArithmeticException("cannot normalize a zero norm vector");
1190         }
1191         Iterator iter = entries.iterator();
1192         while (iter.hasNext()) {
1193             iter.advance();
1194             entries.put(iter.key(), iter.value() / norm);
1195         }
1196 
1197     }
1198 
1199     /**
1200      * Check if an index is valid.
1201      *
1202      * @param index
1203      *            index to check
1204      * @exception MatrixIndexException
1205      *                if index is not valid
1206      */
1207     private void checkIndex(final int index) throws MatrixIndexException {
1208         if (index < 0 || index >= getDimension()) {
1209             throw new MatrixIndexException(
1210                     "index {0} out of allowed range [{1}, {2}]",
1211                     index, 0, getDimension() - 1);
1212         }
1213     }
1214 
1215     /**
1216      * Check if instance dimension is equal to some expected value.
1217      *
1218      * @param n
1219      *            expected dimension.
1220      * @exception IllegalArgumentException
1221      *                if the dimension is inconsistent with vector size
1222      */
1223     protected void checkVectorDimensions(int n) throws IllegalArgumentException {
1224         if (getDimension() != n) {
1225             throw MathRuntimeException.createIllegalArgumentException(
1226                     "vector length mismatch: got {0} but expected {1}",
1227                     getDimension(), n);
1228         }
1229     }
1230 
1231     /** {@inheritDoc} */
1232     public double[] toArray() {
1233         return getData();
1234     }
1235 
1236     /** {@inheritDoc} 
1237      * <p> Implementation Note: This works on exact values, and as a result
1238      * it is possible for {@code a.subtract(b)} to be the zero vector, while
1239      * {@code a.hashCode() != b.hashCode()}.</p>
1240      */
1241     @Override
1242     public int hashCode() {
1243         final int prime = 31;
1244         int result = 1;
1245         long temp;
1246         temp = Double.doubleToLongBits(epsilon);
1247         result = prime * result + (int) (temp ^ (temp >>> 32));
1248         result = prime * result + virtualSize;
1249         Iterator iter = entries.iterator();
1250         while (iter.hasNext()) {
1251             iter.advance();
1252             temp = Double.doubleToLongBits(iter.value());
1253             result = prime * result + (int) (temp ^ (temp >>32));
1254         }
1255         return result;
1256     }
1257 
1258     /**  
1259      * <p> Implementation Note: This performs an exact comparison, and as a result
1260      * it is possible for {@code a.subtract(b}} to be the zero vector, while 
1261      * {@code  a.equals(b) == false}.</p>
1262      * {@inheritDoc}
1263      */
1264     @Override
1265     public boolean equals(Object obj) {
1266         if (this == obj) {
1267             return true;
1268         }
1269         if (obj == null) {
1270             return false;
1271         }
1272         if (!(obj instanceof OpenMapRealVector)) {
1273             return false;
1274         }
1275         OpenMapRealVector other = (OpenMapRealVector) obj;
1276         if (virtualSize != other.virtualSize) {
1277             return false;
1278         }
1279         if (Double.doubleToLongBits(epsilon) !=
1280             Double.doubleToLongBits(other.epsilon)) {
1281             return false;
1282         }
1283         Iterator iter = entries.iterator();
1284         while (iter.hasNext()) {
1285             iter.advance();
1286             double test = other.getEntry(iter.key());
1287             if (Double.doubleToLongBits(test) != Double.doubleToLongBits(iter.value())) {
1288                 return false;
1289             }
1290         }
1291         iter = other.getEntries().iterator();
1292         while (iter.hasNext()) {
1293             iter.advance();
1294             double test = iter.value();
1295             if (Double.doubleToLongBits(test) != Double.doubleToLongBits(getEntry(iter.key()))) {
1296                 return false;
1297             }
1298         }
1299         return true;
1300     }
1301 
1302     /**
1303      * 
1304      * @return the percentage of none zero elements as a decimal percent.
1305      */
1306     public double getSparcity() {
1307         return (double)entries.size()/(double)getDimension();
1308     }
1309 
1310 }