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.util.OpenIntToDoubleHashMap;
023    import org.apache.commons.math.util.OpenIntToDoubleHashMap.Iterator;
024    
025    /**
026     * This class implements the {@link RealVector} interface with a {@link OpenIntToDoubleHashMap} backing store.
027     * @version $Revision: 800111 $ $Date: 2009-08-02 13:23:05 -0400 (Sun, 02 Aug 2009) $
028     * @since 2.0
029    */
030    public class OpenMapRealVector implements SparseRealVector, Serializable {
031    
032        /** Serializable version identifier. */
033        private static final long serialVersionUID = 8772222695580707260L;
034    
035        /** Default Tolerance for having a value considered zero. */
036        public static final double DEFAULT_ZERO_TOLERANCE = 1.0e-12;
037    
038        /** Entries of the vector. */
039        private final OpenIntToDoubleHashMap entries;
040    
041        /** Dimension of the vector. */
042        private final int virtualSize;
043    
044        /** Tolerance for having a value considered zero. */
045        private double epsilon;
046    
047        /**
048         * Build a 0-length vector.
049         * <p>Zero-length vectors may be used to initialized construction of vectors
050         * by data gathering. We start with zero-length and use either the {@link
051         * #OpenMapRealVector(OpenMapRealVector, int)} constructor
052         * or one of the <code>append</code> method ({@link #append(double)}, {@link
053         * #append(double[])}, {@link #append(RealVector)}) to gather data
054         * into this vector.</p>
055         */
056        public OpenMapRealVector() {
057            this(0, DEFAULT_ZERO_TOLERANCE);
058        }
059    
060        /**
061         * Construct a (dimension)-length vector of zeros.
062         * @param dimension size of the vector
063         */
064        public OpenMapRealVector(int dimension) {
065            this(dimension, DEFAULT_ZERO_TOLERANCE);
066        }
067    
068        /**
069         * Construct a (dimension)-length vector of zeros, specifying zero tolerance.
070         * @param dimension Size of the vector
071         * @param epsilon The tolerance for having a value considered zero
072         */
073        public OpenMapRealVector(int dimension, double epsilon) {
074            virtualSize = dimension;
075            entries = new OpenIntToDoubleHashMap(0.0);
076            this.epsilon = epsilon;
077        }
078    
079        /**
080         * Build a resized vector, for use with append.
081         * @param v The original vector
082         * @param resize The amount to resize it
083         */
084        protected OpenMapRealVector(OpenMapRealVector v, int resize) {
085            virtualSize = v.getDimension() + resize;
086            entries = new OpenIntToDoubleHashMap(v.entries);
087            epsilon = v.getEpsilon();
088        }
089    
090        /**
091         * Build a vector with known the sparseness (for advanced use only).
092         * @param dimension The size of the vector
093         * @param expectedSize The expected number of non-zero entries
094         */
095        public OpenMapRealVector(int dimension, int expectedSize) {
096            this(dimension, expectedSize, DEFAULT_ZERO_TOLERANCE);
097        }
098    
099        /**
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    }