diff options
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/math/linearalgebra/Vector.java')
-rw-r--r-- | src/de/lmu/ifi/dbs/elki/math/linearalgebra/Vector.java | 238 |
1 files changed, 120 insertions, 118 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/math/linearalgebra/Vector.java b/src/de/lmu/ifi/dbs/elki/math/linearalgebra/Vector.java index 0a674d87..b0e1c78e 100644 --- a/src/de/lmu/ifi/dbs/elki/math/linearalgebra/Vector.java +++ b/src/de/lmu/ifi/dbs/elki/math/linearalgebra/Vector.java @@ -27,8 +27,6 @@ import java.util.Arrays; import de.lmu.ifi.dbs.elki.data.NumberVector; import de.lmu.ifi.dbs.elki.utilities.FormatUtil; -import de.lmu.ifi.dbs.elki.utilities.datastructures.arraylike.ArrayAdapter; -import de.lmu.ifi.dbs.elki.utilities.datastructures.arraylike.NumberArrayAdapter; /** * Provides a vector object that encapsulates an m x 1 - matrix object. @@ -37,7 +35,7 @@ import de.lmu.ifi.dbs.elki.utilities.datastructures.arraylike.NumberArrayAdapter * * @apiviz.landmark */ -public class Vector implements NumberVector<Vector, Double> { +public class Vector implements NumberVector<Double> { /** * Array for internal storage of elements. * @@ -46,6 +44,21 @@ public class Vector implements NumberVector<Vector, Double> { protected final double[] elements; /** + * Error message (in assertions!) when vector dimensionalities do not agree. + */ + public static final String ERR_VEC_DIMENSIONS = "Vector dimensions do not agree."; + + /** + * Error message (in assertions!) when matrix dimensionalities do not agree. + */ + public static final String ERR_MATRIX_INNERDIM = "Matrix inner dimensions do not agree."; + + /** + * Error message (in assertions!) when dimensionalities do not agree. + */ + private static final String ERR_DIMENSIONS = "Dimensionalities do not agree."; + + /** * Construct a vector from a given array. * * @param values array of doubles @@ -64,7 +77,7 @@ public class Vector implements NumberVector<Vector, Double> { } /** - * Returns a randomly created vector of length 1.0 + * Returns a randomly created vector of length 1.0. * * @param dimensionality dimensionality * @return the dimensionality of the vector @@ -72,13 +85,13 @@ public class Vector implements NumberVector<Vector, Double> { public static final Vector randomNormalizedVector(final int dimensionality) { final Vector v = new Vector(dimensionality); double norm = 0; - while(norm <= 0) { - for(int i = 0; i < dimensionality; i++) { + while (norm <= 0) { + for (int i = 0; i < dimensionality; i++) { v.elements[i] = Math.random(); } norm = v.euclideanLength(); } - for(int row = 0; row < dimensionality; row++) { + for (int row = 0; row < dimensionality; row++) { v.elements[row] /= norm; } return v; @@ -106,9 +119,6 @@ public class Vector implements NumberVector<Vector, Double> { return new Vector(elements.clone()); } - /** - * Clone the Vector object. - */ @Override public Vector clone() { return this.copy(); @@ -173,9 +183,9 @@ public class Vector implements NumberVector<Vector, Double> { * @return the resulting vector */ public final Vector plus(final Vector v) { - assert (this.elements.length == v.elements.length) : "Vector dimensions must agree."; + assert (this.elements.length == v.elements.length) : ERR_VEC_DIMENSIONS; final Vector result = new Vector(elements.length); - for(int i = 0; i < elements.length; i++) { + for (int i = 0; i < elements.length; i++) { result.elements[i] = elements[i] + v.elements[i]; } return result; @@ -190,39 +200,39 @@ public class Vector implements NumberVector<Vector, Double> { * @return the resulting vector */ public final Vector plusTimes(final Vector v, final double s) { - assert (this.elements.length == v.elements.length) : "Vector dimensions must agree."; + assert (this.elements.length == v.elements.length) : ERR_VEC_DIMENSIONS; final Vector result = new Vector(elements.length); - for(int i = 0; i < elements.length; i++) { + for (int i = 0; i < elements.length; i++) { result.elements[i] = elements[i] + v.elements[i] * s; } return result; } /** - * A = A + B + * a = a + b. * - * @param B another matrix - * @return A + B in this Matrix + * @param b another vector + * @return a + b in this vector */ - public final Vector plusEquals(final Vector B) { - assert (this.elements.length == B.elements.length) : "Vector dimensions must agree."; - for(int i = 0; i < elements.length; i++) { - elements[i] += B.elements[i]; + public final Vector plusEquals(final Vector b) { + assert (this.elements.length == b.elements.length) : ERR_VEC_DIMENSIONS; + for (int i = 0; i < elements.length; i++) { + elements[i] += b.elements[i]; } return this; } /** - * A = A + s * B + * a = a + s * b. * - * @param B another matrix + * @param b another vector * @param s Scalar - * @return A + s * B in this Matrix + * @return a + s * b in this vector */ - public final Vector plusTimesEquals(final Vector B, final double s) { - assert (this.elements.length == B.elements.length) : "Vector dimensions must agree."; - for(int i = 0; i < elements.length; i++) { - elements[i] += s * B.elements[i]; + public final Vector plusTimesEquals(final Vector b, final double s) { + assert (this.elements.length == b.elements.length) : ERR_VEC_DIMENSIONS; + for (int i = 0; i < elements.length; i++) { + elements[i] += s * b.elements[i]; } return this; } @@ -234,7 +244,7 @@ public class Vector implements NumberVector<Vector, Double> { * @return Modified vector */ public final Vector plusEquals(final double d) { - for(int i = 0; i < elements.length; i++) { + for (int i = 0; i < elements.length; i++) { elements[i] += d; } return this; @@ -248,7 +258,7 @@ public class Vector implements NumberVector<Vector, Double> { */ public final Vector minus(final Vector v) { final Vector sub = new Vector(elements.length); - for(int i = 0; i < elements.length; i++) { + for (int i = 0; i < elements.length; i++) { sub.elements[i] = elements[i] - v.elements[i]; } return sub; @@ -263,37 +273,37 @@ public class Vector implements NumberVector<Vector, Double> { */ public final Vector minusTimes(final Vector v, final double s) { final Vector sub = new Vector(elements.length); - for(int i = 0; i < elements.length; i++) { + for (int i = 0; i < elements.length; i++) { sub.elements[i] = elements[i] - v.elements[i] * s; } return sub; } /** - * A = A - B + * a = a - b. * - * @param B another matrix - * @return A - B in this Matrix + * @param b another vector + * @return a - b in this vector */ - public final Vector minusEquals(final Vector B) { - assert (this.elements.length == B.elements.length) : "Vector dimensions must agree."; - for(int i = 0; i < elements.length; i++) { - elements[i] -= B.elements[i]; + public final Vector minusEquals(final Vector b) { + assert (this.elements.length == b.elements.length) : ERR_VEC_DIMENSIONS; + for (int i = 0; i < elements.length; i++) { + elements[i] -= b.elements[i]; } return this; } /** - * A = A - s * B + * a = a - s * b. * - * @param B another matrix + * @param b another vector * @param s Scalar - * @return A - s * B in this Matrix + * @return a - s * b in this vector */ - public final Vector minusTimesEquals(final Vector B, final double s) { - assert (this.elements.length == B.elements.length) : "Vector dimensions must agree."; - for(int i = 0; i < elements.length; i++) { - elements[i] -= s * B.elements[i]; + public final Vector minusTimesEquals(final Vector b, final double s) { + assert (this.elements.length == b.elements.length) : ERR_VEC_DIMENSIONS; + for (int i = 0; i < elements.length; i++) { + elements[i] -= s * b.elements[i]; } return this; } @@ -305,7 +315,7 @@ public class Vector implements NumberVector<Vector, Double> { * @return Modified vector */ public final Vector minusEquals(final double d) { - for(int i = 0; i < elements.length; i++) { + for (int i = 0; i < elements.length; i++) { elements[i] -= d; } return this; @@ -320,36 +330,36 @@ public class Vector implements NumberVector<Vector, Double> { */ public final Vector times(final double s) { final Vector v = new Vector(elements.length); - for(int i = 0; i < elements.length; i++) { + for (int i = 0; i < elements.length; i++) { v.elements[i] = elements[i] * s; } return v; } /** - * Multiply a matrix by a scalar in place, A = s*A + * Multiply a matrix by a scalar in place, A = s*A. * * @param s scalar * @return replace A by s*A */ public final Vector timesEquals(final double s) { - for(int i = 0; i < elements.length; i++) { + for (int i = 0; i < elements.length; i++) { elements[i] *= s; } return this; } /** - * Linear algebraic matrix multiplication, A * B + * Linear algebraic matrix multiplication, A * B. * * @param B another matrix * @return Matrix product, A * B */ public final Matrix times(final Matrix B) { - assert (B.elements.length == 1) : "Matrix inner dimensions must agree."; + assert (B.elements.length == 1) : ERR_MATRIX_INNERDIM; final Matrix X = new Matrix(this.elements.length, B.columndimension); - for(int j = 0; j < B.columndimension; j++) { - for(int i = 0; i < this.elements.length; i++) { + for (int j = 0; j < B.columndimension; j++) { + for (int i = 0; i < this.elements.length; i++) { X.elements[i][j] = elements[i] * B.elements[0][j]; } } @@ -357,18 +367,18 @@ public class Vector implements NumberVector<Vector, Double> { } /** - * Linear algebraic matrix multiplication, A<sup>T</sup> * B + * Linear algebraic matrix multiplication, A<sup>T</sup> * B. * * @param B another matrix * @return Matrix product, A<sup>T</sup> * B */ public final Matrix transposeTimes(final Matrix B) { - assert (B.elements.length == this.elements.length) : "Matrix inner dimensions must agree."; + assert (B.elements.length == this.elements.length) : ERR_MATRIX_INNERDIM; final Matrix X = new Matrix(1, B.columndimension); - for(int j = 0; j < B.columndimension; j++) { + for (int j = 0; j < B.columndimension; j++) { // multiply it with each row from A double s = 0; - for(int k = 0; k < this.elements.length; k++) { + for (int k = 0; k < this.elements.length; k++) { s += this.elements[k] * B.elements[k][j]; } X.elements[0][j] = s; @@ -377,19 +387,19 @@ public class Vector implements NumberVector<Vector, Double> { } /** - * Linear algebraic matrix multiplication, a<sup>T</sup> * B * c + * Linear algebraic matrix multiplication, a<sup>T</sup> * B * c. * * @param B matrix * @param c vector on the right - * @return Matrix product, a<sup>T</sup> * B + * @return Matrix product, a<sup>T</sup> * B * c */ public final double transposeTimesTimes(final Matrix B, final Vector c) { - assert (B.elements.length == this.elements.length) : "Matrix inner dimensions must agree."; + assert (B.elements.length == this.elements.length) : ERR_MATRIX_INNERDIM; double sum = 0.0; - for(int j = 0; j < B.columndimension; j++) { + for (int j = 0; j < B.columndimension; j++) { // multiply it with each row from A double s = 0; - for(int k = 0; k < this.elements.length; k++) { + for (int k = 0; k < this.elements.length; k++) { s += this.elements[k] * B.elements[k][j]; } sum += s * c.elements[j]; @@ -398,31 +408,31 @@ public class Vector implements NumberVector<Vector, Double> { } /** - * Linear algebraic matrix multiplication, A<sup>T</sup> * B + * Linear algebraic matrix multiplication, A<sup>T</sup> * B. * * @param B another vector * @return Matrix product, A<sup>T</sup> * B */ public final double transposeTimes(final Vector B) { - assert (B.elements.length == this.elements.length) : "Matrix inner dimensions must agree."; + assert (B.elements.length == this.elements.length) : ERR_MATRIX_INNERDIM; double s = 0; - for(int k = 0; k < this.elements.length; k++) { + for (int k = 0; k < this.elements.length; k++) { s += this.elements[k] * B.elements[k]; } return s; } /** - * Linear algebraic matrix multiplication, A * B^T + * Linear algebraic matrix multiplication, A * B^T. * * @param B another matrix * @return Matrix product, A * B^T */ public final Matrix timesTranspose(final Matrix B) { - assert (B.columndimension == 1) : "Matrix inner dimensions must agree."; + assert (B.columndimension == 1) : ERR_MATRIX_INNERDIM; final Matrix X = new Matrix(this.elements.length, B.elements.length); - for(int j = 0; j < B.elements.length; j++) { - for(int i = 0; i < this.elements.length; i++) { + for (int j = 0; j < B.elements.length; j++) { + for (int i = 0; i < this.elements.length; i++) { X.elements[i][j] = elements[i] * B.elements[j][0]; } } @@ -430,15 +440,15 @@ public class Vector implements NumberVector<Vector, Double> { } /** - * Linear algebraic matrix multiplication, A * B^T + * Linear algebraic matrix multiplication, A * B^T. * * @param B another matrix * @return Matrix product, A * B^T */ public final Matrix timesTranspose(final Vector B) { final Matrix X = new Matrix(this.elements.length, B.elements.length); - for(int j = 0; j < B.elements.length; j++) { - for(int i = 0; i < this.elements.length; i++) { + for (int j = 0; j < B.elements.length; j++) { + for (int i = 0; i < this.elements.length; i++) { X.elements[i][j] = elements[i] * B.elements[j]; } } @@ -452,7 +462,7 @@ public class Vector implements NumberVector<Vector, Double> { */ public final double euclideanLength() { double acc = 0.0; - for(int row = 0; row < elements.length; row++) { + for (int row = 0; row < elements.length; row++) { final double v = elements[row]; acc += v * v; } @@ -461,11 +471,13 @@ public class Vector implements NumberVector<Vector, Double> { /** * Normalizes this vector to the length of 1.0. + * + * @return this vector */ public final Vector normalize() { double norm = euclideanLength(); - if(norm != 0) { - for(int row = 0; row < elements.length; row++) { + if (norm != 0) { + for (int row = 0; row < elements.length; row++) { elements[row] /= norm; } } @@ -480,9 +492,9 @@ public class Vector implements NumberVector<Vector, Double> { * @return the projection of p into the subspace formed by v */ public final Vector projection(final Matrix v) { - assert (elements.length == v.elements.length) : "p and v differ in row dimensionality!"; + assert (elements.length == v.elements.length) : ERR_DIMENSIONS; Vector sum = new Vector(elements.length); - for(int i = 0; i < v.columndimension; i++) { + for (int i = 0; i < v.columndimension; i++) { // TODO: optimize - copy less? Vector v_i = v.getCol(i); sum.plusTimesEquals(v_i, this.transposeTimes(v_i)); @@ -497,17 +509,17 @@ public class Vector implements NumberVector<Vector, Double> { @Override public boolean equals(Object obj) { - if(this == obj) { + if (this == obj) { return true; } - if(obj == null) { + if (obj == null) { return false; } - if(getClass() != obj.getClass()) { + if (getClass() != obj.getClass()) { return false; } final Vector other = (Vector) obj; - if(this.elements.length != other.elements.length) { + if (this.elements.length != other.elements.length) { return false; } return Arrays.equals(this.elements, other.elements); @@ -525,7 +537,7 @@ public class Vector implements NumberVector<Vector, Double> { /** * Returns a string representation of this vector without adding extra - * whitespace + * whitespace. * * @return a string representation of this vector. */ @@ -553,81 +565,71 @@ public class Vector implements NumberVector<Vector, Double> { return this; } + /** + * Cross product for 3d vectors, i.e. <code>this x other</code> + * + * @param other Other vector + * @return Cross product of this vector and the other vector + */ + public Vector cross3D(Vector other) { + assert (elements.length == 3 && other.elements.length == 3); + Vector out = new Vector(3); + out.elements[0] = (elements[1] * other.elements[2]) - (elements[2] * other.elements[1]); + out.elements[1] = (elements[2] * other.elements[0]) - (elements[0] * other.elements[2]); + out.elements[2] = (elements[0] * other.elements[1]) - (elements[1] * other.elements[0]); + return out; + } + // ////// NumberVector API. A bit hackish. :-( @Override public double getMin(int dimension) { - return elements[dimension - 1]; + return elements[dimension]; } @Override public double getMax(int dimension) { - return elements[dimension - 1]; + return elements[dimension]; } @Override + @Deprecated public Double getValue(int dimension) { - return elements[dimension - 1]; + return Double.valueOf(elements[dimension]); } @Override public double doubleValue(int dimension) { - return elements[dimension - 1]; + return elements[dimension]; } @Override public float floatValue(int dimension) { - return (float) elements[dimension - 1]; + return (float) elements[dimension]; } @Override public int intValue(int dimension) { - return (int) elements[dimension - 1]; + return (int) elements[dimension]; } @Override public long longValue(int dimension) { - return (long) elements[dimension - 1]; + return (long) elements[dimension]; } @Override public short shortValue(int dimension) { - return (short) elements[dimension - 1]; + return (short) elements[dimension]; } @Override public byte byteValue(int dimension) { - return (byte) elements[dimension - 1]; + return (byte) elements[dimension]; } @Override public Vector getColumnVector() { return copy(); } - - @Override - public Vector newNumberVector(double[] values) { - return new Vector(values); - } - - @Override - public <A> Vector newNumberVector(A array, NumberArrayAdapter<?, A> adapter) { - double[] raw = new double[adapter.size(array)]; - for(int i = 0; i < raw.length; i++) { - raw[i] = adapter.getDouble(array, i); - } - return new Vector(raw); - } - - @Override - public <A> Vector newFeatureVector(A array, ArrayAdapter<Double, A> adapter) { - if(adapter instanceof NumberArrayAdapter) { - return newNumberVector(array, (NumberArrayAdapter<?, A>) adapter); - } - double[] raw = new double[adapter.size(array)]; - for(int i = 0; i < raw.length; i++) { - raw[i] = adapter.get(array, i); - } - return new Vector(raw); - } -}
\ No newline at end of file +} |