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    import java.lang.reflect.Array;
021    
022    import org.apache.commons.math.Field;
023    import org.apache.commons.math.FieldElement;
024    import org.apache.commons.math.MathRuntimeException;
025    import org.apache.commons.math.exception.util.LocalizedFormats;
026    import org.apache.commons.math.util.OpenIntToFieldHashMap;
027    
028    /**
029     * This class implements the {@link FieldVector} interface with a {@link OpenIntToFieldHashMap} backing store.
030     * @param <T> the type of the field elements
031     * @version $Revision: 983921 $ $Date: 2010-08-10 12:46:06 +0200 (mar. 10 ao??t 2010) $
032     * @since 2.0
033     */
034    public class SparseFieldVector<T extends FieldElement<T>> implements FieldVector<T>, Serializable {
035    
036        /**
037         *  Serial version id
038         */
039        private static final long serialVersionUID = 7841233292190413362L;
040        /** Field to which the elements belong. */
041        private final Field<T> field;
042        /** Entries of the vector. */
043        private final OpenIntToFieldHashMap<T> entries;
044        /** Dimension of the vector. */
045        private final int virtualSize;
046    
047        /**
048         * Build a 0-length vector.
049         * <p>Zero-length vectors may be used to initialize construction of vectors
050         * by data gathering. We start with zero-length and use either the {@link
051         * #SparseFieldVector(SparseFieldVector, int)} constructor
052         * or one of the <code>append</code> method ({@link #append(FieldElement)},
053         * {@link #append(FieldElement[])}, {@link #append(FieldVector)},
054         * {@link #append(SparseFieldVector)}) to gather data into this vector.</p>
055         * @param field field to which the elements belong
056         */
057        public SparseFieldVector(Field<T> field) {
058            this(field, 0);
059        }
060    
061    
062        /**
063         * Construct a (dimension)-length vector of zeros.
064         * @param field field to which the elements belong
065         * @param dimension Size of the vector
066         */
067        public SparseFieldVector(Field<T> field, int dimension) {
068            this.field = field;
069            virtualSize = dimension;
070            entries = new OpenIntToFieldHashMap<T>(field);
071        }
072    
073        /**
074         * Build a resized vector, for use with append.
075         * @param v The original vector
076         * @param resize The amount to resize it
077         */
078        protected SparseFieldVector(SparseFieldVector<T> v, int resize) {
079            field = v.field;
080            virtualSize = v.getDimension() + resize;
081            entries = new OpenIntToFieldHashMap<T>(v.entries);
082        }
083    
084    
085        /**
086         * Build a vector with known the sparseness (for advanced use only).
087         * @param field field to which the elements belong
088         * @param dimension The size of the vector
089         * @param expectedSize The expected number of non-zero entries
090         */
091        public SparseFieldVector(Field<T> field, int dimension, int expectedSize) {
092            this.field = field;
093            virtualSize = dimension;
094            entries = new OpenIntToFieldHashMap<T>(field,expectedSize);
095        }
096    
097        /**
098         * Create from a Field array.
099         * Only non-zero entries will be stored
100         * @param field field to which the elements belong
101         * @param values The set of values to create from
102         */
103        public SparseFieldVector(Field<T> field, T[] values) {
104            this.field = field;
105            virtualSize = values.length;
106            entries = new OpenIntToFieldHashMap<T>(field);
107            for (int key = 0; key < values.length; key++) {
108                T value = values[key];
109                entries.put(key, value);
110            }
111        }
112    
113    
114    
115        /**
116         * Copy constructor.
117         * @param v The instance to copy from
118         */
119        public SparseFieldVector(SparseFieldVector<T> v) {
120            field = v.field;
121            virtualSize = v.getDimension();
122            entries = new OpenIntToFieldHashMap<T>(v.getEntries());
123        }
124    
125        /**
126         * Get the entries of this instance.
127         * @return entries of this instance
128         */
129        private OpenIntToFieldHashMap<T> getEntries() {
130            return entries;
131        }
132    
133        /**
134         * Optimized method to add sparse vectors.
135         * @param v vector to add
136         * @return The sum of <code>this</code> and <code>v</code>
137         * @throws IllegalArgumentException If the dimensions don't match
138         */
139        public FieldVector<T> add(SparseFieldVector<T> v) throws IllegalArgumentException {
140            checkVectorDimensions(v.getDimension());
141            SparseFieldVector<T> res = (SparseFieldVector<T>)copy();
142            OpenIntToFieldHashMap<T>.Iterator iter = v.getEntries().iterator();
143            while (iter.hasNext()) {
144                iter.advance();
145                int key = iter.key();
146                T value = iter.value();
147                if (entries.containsKey(key)) {
148                    res.setEntry(key, entries.get(key).add(value));
149                } else {
150                    res.setEntry(key, value);
151                }
152            }
153            return res;
154    
155        }
156    
157    
158        /** {@inheritDoc} */
159        public FieldVector<T> add(T[] v) throws IllegalArgumentException {
160            checkVectorDimensions(v.length);
161            SparseFieldVector<T> res = new SparseFieldVector<T>(field,getDimension());
162            for (int i = 0; i < v.length; i++) {
163                res.setEntry(i, v[i].add(getEntry(i)));
164            }
165            return res;
166        }
167    
168        /**
169         * Construct a vector by appending a vector to this vector.
170         * @param v vector to append to this one.
171         * @return a new vector
172         */
173        public FieldVector<T> append(SparseFieldVector<T> v) {
174            SparseFieldVector<T> res = new SparseFieldVector<T>(this, v.getDimension());
175            OpenIntToFieldHashMap<T>.Iterator iter = v.entries.iterator();
176            while (iter.hasNext()) {
177                iter.advance();
178                res.setEntry(iter.key() + virtualSize, iter.value());
179            }
180            return res;
181        }
182    
183        /** {@inheritDoc} */
184        public FieldVector<T> append(FieldVector<T> v) {
185            if (v instanceof SparseFieldVector<?>) {
186                return append((SparseFieldVector<T>) v);
187            } else {
188                return append(v.toArray());
189            }
190        }
191    
192        /** {@inheritDoc} */
193        public FieldVector<T> append(T d) {
194            FieldVector<T> res = new SparseFieldVector<T>(this, 1);
195            res.setEntry(virtualSize, d);
196            return res;
197         }
198    
199        /** {@inheritDoc} */
200        public FieldVector<T> append(T[] a) {
201            FieldVector<T> res = new SparseFieldVector<T>(this, a.length);
202            for (int i = 0; i < a.length; i++) {
203                res.setEntry(i + virtualSize, a[i]);
204            }
205            return res;
206         }
207    
208        /** {@inheritDoc} */
209        public FieldVector<T> copy() {
210            return new SparseFieldVector<T>(this);
211       }
212    
213        /** {@inheritDoc} */
214        public T dotProduct(FieldVector<T> v) throws IllegalArgumentException {
215            checkVectorDimensions(v.getDimension());
216            T res = field.getZero();
217            OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
218            while (iter.hasNext()) {
219                iter.advance();
220                res = res.add(v.getEntry(iter.key()).multiply(iter.value()));
221            }
222            return res;
223        }
224    
225        /** {@inheritDoc} */
226        public T dotProduct(T[] v) throws IllegalArgumentException {
227            checkVectorDimensions(v.length);
228            T res = field.getZero();
229            OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
230            while (iter.hasNext()) {
231                int idx = iter.key();
232                T value = field.getZero();
233                if (idx < v.length) {
234                    value = v[idx];
235                }
236                res = res.add(value.multiply(iter.value()));
237            }
238            return res;
239         }
240    
241        /** {@inheritDoc} */
242        public FieldVector<T> ebeDivide(FieldVector<T> v)
243            throws IllegalArgumentException {
244            checkVectorDimensions(v.getDimension());
245            SparseFieldVector<T> res = new SparseFieldVector<T>(this);
246            OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator();
247            while (iter.hasNext()) {
248                iter.advance();
249                res.setEntry(iter.key(), iter.value().divide(v.getEntry(iter.key())));
250            }
251            return res;
252        }
253    
254        /** {@inheritDoc} */
255        public FieldVector<T> ebeDivide(T[] v) throws IllegalArgumentException {
256            checkVectorDimensions(v.length);
257            SparseFieldVector<T> res = new SparseFieldVector<T>(this);
258            OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator();
259            while (iter.hasNext()) {
260                iter.advance();
261                res.setEntry(iter.key(), iter.value().divide(v[iter.key()]));
262            }
263            return res;
264        }
265    
266        /** {@inheritDoc} */
267        public FieldVector<T> ebeMultiply(FieldVector<T> v)throws IllegalArgumentException {
268            checkVectorDimensions(v.getDimension());
269            SparseFieldVector<T> res = new SparseFieldVector<T>(this);
270            OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator();
271            while (iter.hasNext()) {
272                iter.advance();
273                res.setEntry(iter.key(), iter.value().multiply(v.getEntry(iter.key())));
274            }
275            return res;
276        }
277    
278        /** {@inheritDoc} */
279         public FieldVector<T> ebeMultiply(T[] v) throws IllegalArgumentException {
280            checkVectorDimensions(v.length);
281            SparseFieldVector<T> res = new SparseFieldVector<T>(this);
282            OpenIntToFieldHashMap<T>.Iterator iter = res.entries.iterator();
283            while (iter.hasNext()) {
284                iter.advance();
285                res.setEntry(iter.key(), iter.value().multiply(v[iter.key()]));
286            }
287            return res;
288        }
289    
290         /** {@inheritDoc} */
291         public T[] getData() {
292            T[] res = buildArray(virtualSize);
293            OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
294            while (iter.hasNext()) {
295                iter.advance();
296                res[iter.key()] = iter.value();
297            }
298            return res;
299         }
300    
301         /** {@inheritDoc} */
302         public int getDimension() {
303            return virtualSize;
304        }
305    
306         /** {@inheritDoc} */
307         public T getEntry(int index) throws MatrixIndexException {
308            checkIndex(index);
309            return entries.get(index);
310       }
311    
312         /** {@inheritDoc} */
313         public Field<T> getField() {
314            return field;
315        }
316    
317         /** {@inheritDoc} */
318         public FieldVector<T> getSubVector(int index, int n)
319                throws MatrixIndexException {
320            checkIndex(index);
321            checkIndex(index + n - 1);
322            SparseFieldVector<T> res = new SparseFieldVector<T>(field,n);
323            int end = index + n;
324            OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
325            while (iter.hasNext()) {
326                iter.advance();
327                int key = iter.key();
328                if (key >= index && key < end) {
329                    res.setEntry(key - index, iter.value());
330                }
331            }
332            return res;
333        }
334    
335         /** {@inheritDoc} */
336         public FieldVector<T> mapAdd(T d) {
337            return copy().mapAddToSelf(d);
338       }
339    
340         /** {@inheritDoc} */
341         public FieldVector<T> mapAddToSelf(T d) {
342            for (int i = 0; i < virtualSize; i++) {
343                setEntry(i, getEntry(i).add(d));
344            }
345            return this;
346        }
347    
348         /** {@inheritDoc} */
349         public FieldVector<T> mapDivide(T d) {
350            return copy().mapDivideToSelf(d);
351        }
352    
353         /** {@inheritDoc} */
354         public FieldVector<T> mapDivideToSelf(T d) {
355            OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
356            while (iter.hasNext()) {
357                iter.advance();
358                entries.put(iter.key(), iter.value().divide(d));
359            }
360            return this;
361       }
362    
363         /** {@inheritDoc} */
364         public FieldVector<T> mapInv() {
365            return copy().mapInvToSelf();
366       }
367    
368         /** {@inheritDoc} */
369         public FieldVector<T> mapInvToSelf() {
370            for (int i = 0; i < virtualSize; i++) {
371                setEntry(i, field.getOne().divide(getEntry(i)));
372            }
373            return this;
374       }
375    
376         /** {@inheritDoc} */
377         public FieldVector<T> mapMultiply(T d) {
378            return copy().mapMultiplyToSelf(d);
379        }
380    
381         /** {@inheritDoc} */
382         public FieldVector<T> mapMultiplyToSelf(T d) {
383            OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
384            while (iter.hasNext()) {
385                iter.advance();
386                entries.put(iter.key(), iter.value().multiply(d));
387            }
388            return this;
389       }
390    
391         /** {@inheritDoc} */
392         public FieldVector<T> mapSubtract(T d) {
393            return copy().mapSubtractToSelf(d);
394        }
395    
396         /** {@inheritDoc} */
397         public FieldVector<T> mapSubtractToSelf(T d) {
398            return mapAddToSelf(field.getZero().subtract(d));
399        }
400    
401         /**
402          * Optimized method to compute outer product when both vectors are sparse.
403          * @param v vector with which outer product should be computed
404          * @return the square matrix outer product between instance and v
405          * @throws IllegalArgumentException if v is not the same size as {@code this}
406          */
407        public FieldMatrix<T> outerProduct(SparseFieldVector<T> v)
408                throws IllegalArgumentException {
409            checkVectorDimensions(v.getDimension());
410            SparseFieldMatrix<T> res = new SparseFieldMatrix<T>(field, virtualSize, virtualSize);
411            OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
412            while (iter.hasNext()) {
413                iter.advance();
414                OpenIntToFieldHashMap<T>.Iterator iter2 = v.entries.iterator();
415                while (iter2.hasNext()) {
416                    iter2.advance();
417                    res.setEntry(iter.key(), iter2.key(), iter.value().multiply(iter2.value()));
418                }
419            }
420            return res;
421        }
422    
423        /** {@inheritDoc} */
424        public FieldMatrix<T> outerProduct(T[] v) throws IllegalArgumentException {
425            checkVectorDimensions(v.length);
426            FieldMatrix<T> res = new SparseFieldMatrix<T>(field, virtualSize, virtualSize);
427            OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
428            while (iter.hasNext()) {
429                iter.advance();
430                int row = iter.key();
431                FieldElement<T>value = iter.value();
432                for (int col = 0; col < virtualSize; col++) {
433                    res.setEntry(row, col, value.multiply(v[col]));
434                }
435            }
436            return res;
437         }
438    
439        /** {@inheritDoc} */
440        public FieldMatrix<T> outerProduct(FieldVector<T> v)
441        throws IllegalArgumentException {
442            if(v instanceof SparseFieldVector<?>)
443                return outerProduct((SparseFieldVector<T>)v);
444            else
445                return outerProduct(v.toArray());
446        }
447    
448        /** {@inheritDoc} */
449        public FieldVector<T> projection(FieldVector<T> v)
450        throws IllegalArgumentException {
451            checkVectorDimensions(v.getDimension());
452            return v.mapMultiply(dotProduct(v).divide(v.dotProduct(v)));
453        }
454    
455        /** {@inheritDoc} */
456        public FieldVector<T> projection(T[] v) throws IllegalArgumentException {
457            checkVectorDimensions(v.length);
458            return projection(new SparseFieldVector<T>(field,v));
459        }
460    
461        /** {@inheritDoc} */
462        public void set(T value) {
463            for (int i = 0; i < virtualSize; i++) {
464                setEntry(i, value);
465            }
466        }
467    
468        /** {@inheritDoc} */
469        public void setEntry(int index, T value) throws MatrixIndexException {
470            checkIndex(index);
471            entries.put(index, value);
472       }
473    
474        /** {@inheritDoc} */
475        public void setSubVector(int index, FieldVector<T> v)
476                throws MatrixIndexException {
477            checkIndex(index);
478            checkIndex(index + v.getDimension() - 1);
479            setSubVector(index, v.getData());
480        }
481    
482        /** {@inheritDoc} */
483        public void setSubVector(int index, T[] v) throws MatrixIndexException {
484            checkIndex(index);
485            checkIndex(index + v.length - 1);
486            for (int i = 0; i < v.length; i++) {
487                setEntry(i + index, v[i]);
488            }
489    
490        }
491    
492        /**
493         * Optimized method to subtract SparseRealVectors.
494         * @param v The vector to subtract from <code>this</code>
495         * @return The difference of <code>this</code> and <code>v</code>
496         * @throws IllegalArgumentException If the dimensions don't match
497         */
498        public SparseFieldVector<T> subtract(SparseFieldVector<T> v) throws IllegalArgumentException{
499            checkVectorDimensions(v.getDimension());
500            SparseFieldVector<T> res = (SparseFieldVector<T>)copy();
501            OpenIntToFieldHashMap<T>.Iterator iter = v.getEntries().iterator();
502            while (iter.hasNext()) {
503                iter.advance();
504                int key = iter.key();
505                if (entries.containsKey(key)) {
506                    res.setEntry(key, entries.get(key).subtract(iter.value()));
507                } else {
508                    res.setEntry(key, field.getZero().subtract(iter.value()));
509                }
510            }
511            return res;
512        }
513    
514        /** {@inheritDoc} */
515        public FieldVector<T> subtract(FieldVector<T> v)
516               throws IllegalArgumentException {
517            if(v instanceof SparseFieldVector<?>)
518                return subtract((SparseFieldVector<T>)v);
519            else
520                return subtract(v.toArray());
521        }
522    
523        /** {@inheritDoc} */
524        public FieldVector<T> subtract(T[] v) throws IllegalArgumentException {
525            checkVectorDimensions(v.length);
526            SparseFieldVector<T> res = new SparseFieldVector<T>(this);
527            for (int i = 0; i < v.length; i++) {
528                if (entries.containsKey(i)) {
529                    res.setEntry(i, entries.get(i).subtract(v[i]));
530                } else {
531                    res.setEntry(i, field.getZero().subtract(v[i]));
532                }
533            }
534            return res;
535        }
536    
537        /** {@inheritDoc} */
538        public T[] toArray() {
539            return getData();
540        }
541    
542        /**
543         * Check if an index is valid.
544         *
545         * @param index
546         *            index to check
547         * @exception MatrixIndexException
548         *                if index is not valid
549         */
550        private void checkIndex(final int index) throws MatrixIndexException {
551            if (index < 0 || index >= getDimension()) {
552                throw new MatrixIndexException(LocalizedFormats.INDEX_OUT_OF_RANGE,
553                                               index, 0, getDimension() - 1);
554            }
555        }
556    
557        /**
558         * Check if instance dimension is equal to some expected value.
559         *
560         * @param n
561         *            expected dimension.
562         * @exception IllegalArgumentException
563         *                if the dimension is inconsistent with vector size
564         */
565        protected void checkVectorDimensions(int n) throws IllegalArgumentException {
566            if (getDimension() != n) {
567                throw MathRuntimeException.createIllegalArgumentException(
568                        LocalizedFormats.VECTOR_LENGTH_MISMATCH,
569                        getDimension(), n);
570            }
571        }
572    
573    
574        /** {@inheritDoc} */
575        public FieldVector<T> add(FieldVector<T> v) throws IllegalArgumentException {
576            if (v instanceof SparseFieldVector<?>) {
577                return add((SparseFieldVector<T>)v);
578            } else {
579                return add(v.toArray());
580            }
581        }
582    
583        /** Build an array of elements.
584         * @param length size of the array to build
585         * @return a new array
586         */
587        @SuppressWarnings("unchecked") // field is type T
588        private T[] buildArray(final int length) {
589            return (T[]) Array.newInstance(field.getZero().getClass(), length);
590        }
591    
592    
593        /** {@inheritDoc} */
594        @Override
595        public int hashCode() {
596            final int prime = 31;
597            int result = 1;
598            result = prime * result + ((field == null) ? 0 : field.hashCode());
599            result = prime * result + virtualSize;
600            OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
601            while (iter.hasNext()) {
602                iter.advance();
603                int temp = iter.value().hashCode();
604                result = prime * result + temp;
605            }
606            return result;
607        }
608    
609    
610        /** {@inheritDoc} */
611        @Override
612        public boolean equals(Object obj) {
613    
614            if (this == obj) {
615                return true;
616            }
617    
618            if (!(obj instanceof SparseFieldVector<?>)) {
619                return false;
620            }
621    
622            @SuppressWarnings("unchecked") // OK, because "else if" check below ensures that
623                                           // other must be the same type as this
624            SparseFieldVector<T> other = (SparseFieldVector<T>) obj;
625            if (field == null) {
626                if (other.field != null) {
627                    return false;
628                }
629            } else if (!field.equals(other.field)) {
630                return false;
631            }
632            if (virtualSize != other.virtualSize) {
633                return false;
634            }
635    
636            OpenIntToFieldHashMap<T>.Iterator iter = entries.iterator();
637            while (iter.hasNext()) {
638                iter.advance();
639                T test = other.getEntry(iter.key());
640                if (!test.equals(iter.value())) {
641                    return false;
642                }
643            }
644            iter = other.getEntries().iterator();
645            while (iter.hasNext()) {
646                iter.advance();
647                T test = iter.value();
648                if (!test.equals(getEntry(iter.key()))) {
649                    return false;
650                }
651            }
652            return true;
653        }
654    
655    
656    
657    }