package ch.akuhn.matrix;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* An ordered list of floating point numbers.
*
* @author Adrian Kuhn
*
*/
public abstract class Vector {
public double add(int index, double value) {
return put(index, get(index) + value);
}
public double density() {
return ((double) used()) / size();
}
/**
* Iterates over all entries. Some vectors omit zero-valued entries.
*
* @return value and index of each entry.
*/
public Iterable<Entry> entries() {
return new Iterable<Entry>() {
@Override
public Iterator<Entry> iterator() {
return new Iterator<Entry>() {
private int index = 0;
@Override
public boolean hasNext() {
return index < size();
}
@Override
public Entry next() {
if (!hasNext()) throw new NoSuchElementException();
return new Entry(index, get(index++));
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
public abstract double get(int index);
public double norm() {
double sum = 0;
for (Entry each: entries())
sum += each.value * each.value;
return Math.sqrt(sum);
}
public abstract double put(int index, double value);
public abstract int size();
public double sum() {
double sum = 0;
for (Entry each: entries())
sum += each.value;
return sum;
}
/**
* Returns number of non-zero-valued entries.
*
* @return a positive integer.
*/
public int used() {
int count = 0;
for (Entry each: entries())
if (each.value != 0) count++;
return count;
}
public final class Entry {
public final int index;
public final double value;
public Entry(int index, double value) {
this.index = index;
this.value = value;
}
}
public static Vector from(double... values) {
return new DenseVector(values.clone());
}
public static Vector copy(double[] values, int start, int length) {
return new DenseVector(Arrays.copyOfRange(values, start, start + length));
}
public static Vector wrap(double... values) {
return new DenseVector(values);
}
public static Vector dense(int size) {
return new DenseVector(size);
}
public static Vector sparse(int size) {
return new SparseVector(size);
}
/**
* Returns the dot/scalar product.
*
*/
public double dot(Vector x) {
double product = 0;
for (Entry each: entries())
product += each.value * x.get(each.index);
return product;
}
/**
* y = y + a*<code>this</code>.
*
*/
public void scaleAndAddTo(double a, Vector y) {
for (Entry each: entries())
y.add(each.index, a * each.value);
}
public void storeOn(double[] array, int start) {
assert start + size() <= array.length;
Arrays.fill(array, start, start + size(), 0);
for (Entry each: entries())
array[start + each.index] = each.value;
}
public abstract Vector times(double scalar);
public abstract boolean equals(Vector v, double epsilon);
public void apply(Function f) {
f.apply(unwrap());
}
public double[] unwrap() {
throw new Error("cannot unwrap instance of " + getClass());
}
public void applyCentering() {
double[] values = unwrap();
double mean = Util.sum(values) / values.length;
for (int i = 0; i < values.length; i++)
values[i] -= mean;
}
public double mean() {
double[] values = unwrap();
return Util.sum(values) / values.length;
}
}