001package ch.akuhn.matrix;
002
003import java.io.StringWriter;
004import java.util.Arrays;
005import java.util.Iterator;
006import java.util.NoSuchElementException;
007
008/**
009 * An ordered list of floating point numbers.
010 * 
011 * @author Adrian Kuhn
012 */
013public abstract class Vector {
014
015        /**
016         * Add the given value to the value at the given index
017         * 
018         * @param index
019         * @param value
020         * @return the new value
021         */
022        public double add(int index, double value) {
023                return put(index, get(index) + value);
024        }
025
026        /**
027         * @return the density
028         */
029        public double density() {
030                return ((double) used()) / size();
031        }
032
033        /**
034         * Iterates over all entries. Some vectors omit zero-valued entries.
035         * 
036         * @return value and index of each entry.
037         */
038        public Iterable<Entry> entries() {
039                return new Iterable<Entry>() {
040                        @Override
041                        public Iterator<Entry> iterator() {
042                                return new Iterator<Entry>() {
043
044                                        private int index = 0;
045
046                                        @Override
047                                        public boolean hasNext() {
048                                                return index < size();
049                                        }
050
051                                        @Override
052                                        public Entry next() {
053                                                if (!hasNext())
054                                                        throw new NoSuchElementException();
055                                                return new Entry(index, get(index++));
056                                        }
057
058                                        @Override
059                                        public void remove() {
060                                                throw new UnsupportedOperationException();
061                                        }
062
063                                };
064                        }
065                };
066        }
067
068        /**
069         * Get the value at the given index
070         * 
071         * @param index
072         * @return the value
073         */
074        public abstract double get(int index);
075
076        /**
077         * Compute the L2 norm
078         * 
079         * @return the L2 norm
080         */
081        public double norm() {
082                double sum = 0;
083                for (final Entry each : entries())
084                        sum += each.value * each.value;
085                return Math.sqrt(sum);
086        }
087
088        /**
089         * Set the value at an index
090         * 
091         * @param index
092         * @param value
093         * @return the new value
094         */
095        public abstract double put(int index, double value);
096
097        /**
098         * @return the length of the vector
099         */
100        public abstract int size();
101
102        /**
103         * @return the sum of values
104         */
105        public double sum() {
106                double sum = 0;
107                for (final Entry each : entries())
108                        sum += each.value;
109                return sum;
110        }
111
112        /**
113         * Returns number of non-zero-valued entries.
114         * 
115         * @return a positive integer.
116         */
117        public int used() {
118                int count = 0;
119                for (final Entry each : entries())
120                        if (each.value != 0)
121                                count++;
122                return count;
123        }
124
125        /**
126         * An entry in a sparse vector
127         */
128        public final class Entry {
129                /**
130                 * The index
131                 */
132                public final int index;
133                /**
134                 * The value
135                 */
136                public final double value;
137
138                /**
139                 * Construct
140                 * 
141                 * @param index
142                 * @param value
143                 */
144                public Entry(int index, double value) {
145                        this.index = index;
146                        this.value = value;
147                }
148        }
149
150        /**
151         * Construct a Vector from an array of values
152         * 
153         * @param values
154         * @return the vector
155         */
156        public static Vector from(double... values) {
157                return new DenseVector(values.clone());
158        }
159
160        /**
161         * Copy a range from an array into a vector.
162         * 
163         * @param values
164         * @param start
165         * @param length
166         * @return the vector
167         */
168        public static Vector copy(double[] values, int start, int length) {
169                return new DenseVector(Arrays.copyOfRange(values, start, start + length));
170        }
171
172        /**
173         * Wrap an array in a vector
174         * 
175         * @param values
176         * @return the vector
177         */
178        public static Vector wrap(double... values) {
179                return new DenseVector(values);
180        }
181
182        /**
183         * Create an empty dense vector
184         * 
185         * @param size
186         * @return the vector
187         */
188        public static Vector dense(int size) {
189                return new DenseVector(size);
190        }
191
192        /**
193         * Create an empty sparse vector
194         * 
195         * @param size
196         * @return the vector
197         */
198        public static Vector sparse(int size) {
199                return new SparseVector(size);
200        }
201
202        /**
203         * Returns the dot/scalar product.
204         * 
205         * @param x
206         * @return the dot product
207         * 
208         */
209        public double dot(Vector x) {
210                double product = 0;
211                for (final Entry each : entries())
212                        product += each.value * x.get(each.index);
213                return product;
214        }
215
216        /**
217         * y = y + a*<code>this</code>.
218         * 
219         * @param a
220         * @param y
221         * 
222         */
223        public void scaleAndAddTo(double a, Vector y) {
224                for (final Entry each : entries())
225                        y.add(each.index, a * each.value);
226        }
227
228        /**
229         * I/O
230         * 
231         * @param array
232         * @param start
233         */
234        public void storeOn(double[] array, int start) {
235                assert start + size() <= array.length;
236                Arrays.fill(array, start, start + size(), 0);
237                for (final Entry each : entries())
238                        array[start + each.index] = each.value;
239        }
240
241        @Override
242        public String toString() {
243                final StringWriter out = new StringWriter();
244                out.append("(");
245                for (final Entry each : entries())
246                        out.append(each.value + ", ");
247                out.append(")");
248                return out.toString();
249        }
250
251        /**
252         * Multiply by a constant, creating a new vector
253         * 
254         * @param scalar
255         * @return the vector
256         */
257        public abstract Vector times(double scalar);
258
259        /**
260         * Multiply by a constant in-place
261         * 
262         * @param scalar
263         * @return this
264         */
265        public abstract Vector timesEquals(double scalar);
266
267        /**
268         * Test for equality
269         * 
270         * @param v
271         * @param epsilon
272         * @return true if the same; false otherwise
273         */
274        public abstract boolean equals(Vector v, double epsilon);
275
276        /**
277         * @return an array
278         */
279        public double[] unwrap() {
280                throw new Error("cannot unwrap instance of " + getClass());
281        }
282
283        /**
284         * mean-center the vector
285         */
286        public void applyCentering() {
287                final double[] values = unwrap();
288                final double mean = Util.sum(values) / values.length;
289                for (int i = 0; i < values.length; i++)
290                        values[i] -= mean;
291        }
292
293        /**
294         * @return the mean of the values
295         */
296        public double mean() {
297                final double[] values = unwrap();
298                return Util.sum(values) / values.length;
299        }
300}