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}