summaryrefslogtreecommitdiff
path: root/src/de/lmu/ifi/dbs/elki/math/linearalgebra/Vector.java
diff options
context:
space:
mode:
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.java258
1 files changed, 220 insertions, 38 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 eca1dbea..36ab94dc 100644
--- a/src/de/lmu/ifi/dbs/elki/math/linearalgebra/Vector.java
+++ b/src/de/lmu/ifi/dbs/elki/math/linearalgebra/Vector.java
@@ -4,7 +4,7 @@ package de.lmu.ifi.dbs.elki.math.linearalgebra;
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
- Copyright (C) 2013
+ Copyright (C) 2014
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
@@ -23,19 +23,46 @@ package de.lmu.ifi.dbs.elki.math.linearalgebra;
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+import java.io.IOException;
+import java.nio.ByteBuffer;
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.ArrayLikeUtil;
+import de.lmu.ifi.dbs.elki.utilities.datastructures.arraylike.NumberArrayAdapter;
+import de.lmu.ifi.dbs.elki.utilities.io.ByteArrayUtil;
+import de.lmu.ifi.dbs.elki.utilities.io.ByteBufferSerializer;
/**
- * Provides a vector object that encapsulates an m x 1 - matrix object.
+ * A mathematical vector object, along with mathematical operations.
*
* @author Elke Achtert
*
* @apiviz.landmark
*/
-public class Vector implements NumberVector<Double> {
+public class Vector implements NumberVector {
+ /**
+ * Static vector factory.
+ */
+ public static final Factory FACTORY = new Factory();
+
+ /**
+ * Serializer for up to 127 dimensions.
+ */
+ public static final ByteBufferSerializer<Vector> BYTE_SERIALIZER = new SmallSerializer();
+
+ /**
+ * Serializer for up to 2^15-1 dimensions.
+ */
+ public static final ByteBufferSerializer<Vector> SHORT_SERIALIZER = new ShortSerializer();
+
+ /**
+ * Serializer using varint encoding.
+ */
+ public static final ByteBufferSerializer<Vector> VARIABLE_SERIALIZER = new VariableSerializer();
+
/**
* Array for internal storage of elements.
*
@@ -68,7 +95,7 @@ public class Vector implements NumberVector<Double> {
}
/**
- * Provides an m x 1 vector.
+ * Constructor
*
* @param m the number of rows
*/
@@ -85,13 +112,13 @@ public class Vector implements NumberVector<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;
@@ -185,7 +212,7 @@ public class Vector implements NumberVector<Double> {
public final Vector plus(final Vector v) {
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;
@@ -202,7 +229,7 @@ public class Vector implements NumberVector<Double> {
public final Vector plusTimes(final Vector v, final double s) {
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;
@@ -216,7 +243,7 @@ public class Vector implements NumberVector<Double> {
*/
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++) {
+ for(int i = 0; i < elements.length; i++) {
elements[i] += b.elements[i];
}
return this;
@@ -231,7 +258,7 @@ public class Vector implements NumberVector<Double> {
*/
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++) {
+ for(int i = 0; i < elements.length; i++) {
elements[i] += s * b.elements[i];
}
return this;
@@ -244,7 +271,7 @@ public class Vector implements NumberVector<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;
@@ -258,7 +285,7 @@ public class Vector implements NumberVector<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;
@@ -273,7 +300,7 @@ public class Vector implements NumberVector<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;
@@ -287,7 +314,7 @@ public class Vector implements NumberVector<Double> {
*/
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++) {
+ for(int i = 0; i < elements.length; i++) {
elements[i] -= b.elements[i];
}
return this;
@@ -302,7 +329,7 @@ public class Vector implements NumberVector<Double> {
*/
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++) {
+ for(int i = 0; i < elements.length; i++) {
elements[i] -= s * b.elements[i];
}
return this;
@@ -315,7 +342,7 @@ public class Vector implements NumberVector<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;
@@ -330,7 +357,7 @@ public class Vector implements NumberVector<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;
@@ -343,7 +370,7 @@ public class Vector implements NumberVector<Double> {
* @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;
@@ -358,8 +385,8 @@ public class Vector implements NumberVector<Double> {
public final Matrix times(final Matrix B) {
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];
}
}
@@ -375,10 +402,10 @@ public class Vector implements NumberVector<Double> {
public final Matrix transposeTimes(final Matrix B) {
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;
@@ -396,10 +423,10 @@ public class Vector implements NumberVector<Double> {
public final double transposeTimesTimes(final Matrix B, final Vector c) {
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];
@@ -416,7 +443,7 @@ public class Vector implements NumberVector<Double> {
public final double transposeTimes(final Vector B) {
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;
@@ -431,8 +458,8 @@ public class Vector implements NumberVector<Double> {
public final Matrix timesTranspose(final Matrix B) {
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];
}
}
@@ -447,8 +474,8 @@ public class Vector implements NumberVector<Double> {
*/
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];
}
}
@@ -462,7 +489,7 @@ public class Vector implements NumberVector<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;
}
@@ -476,8 +503,8 @@ public class Vector implements NumberVector<Double> {
*/
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;
}
}
@@ -494,7 +521,7 @@ public class Vector implements NumberVector<Double> {
public final Vector projection(final Matrix v) {
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));
@@ -509,17 +536,17 @@ public class Vector implements NumberVector<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);
@@ -632,4 +659,159 @@ public class Vector implements NumberVector<Double> {
public Vector getColumnVector() {
return copy();
}
+
+ /**
+ * Vector factory for Vectors.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ private static class Factory implements NumberVector.Factory<Vector> {
+ @Override
+ public <A> Vector newFeatureVector(A array, ArrayAdapter<? extends Number, A> adapter) {
+ if(adapter instanceof NumberArrayAdapter) {
+ return new Vector(ArrayLikeUtil.toPrimitiveDoubleArray(array, (NumberArrayAdapter<?, ? super A>) adapter));
+ }
+ double[] data = new double[adapter.size(array)];
+ for(int i = 0; i < data.length; i++) {
+ data[i] = adapter.get(array, i).doubleValue();
+ }
+ return new Vector(data);
+ }
+
+ @Override
+ public ByteBufferSerializer<Vector> getDefaultSerializer() {
+ return VARIABLE_SERIALIZER;
+ }
+
+ @Override
+ public Class<? super Vector> getRestrictionClass() {
+ return Vector.class;
+ }
+
+ @Override
+ public Vector newNumberVector(double[] values) {
+ return new Vector(values.clone());
+ }
+
+ @Override
+ public <A> Vector newNumberVector(A array, NumberArrayAdapter<?, ? super A> adapter) {
+ return new Vector(ArrayLikeUtil.toPrimitiveDoubleArray(array, adapter));
+ }
+
+ @Override
+ public Vector newNumberVector(NumberVector values) {
+ return new Vector(ArrayLikeUtil.toPrimitiveDoubleArray(values));
+ }
+ }
+
+ /**
+ * Serialization class for dense double vectors with up to 127 dimensions, by
+ * using a byte for storing the dimensionality.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public static class SmallSerializer implements ByteBufferSerializer<Vector> {
+ @Override
+ public Vector fromByteBuffer(ByteBuffer buffer) throws IOException {
+ final byte dimensionality = buffer.get();
+ assert (buffer.remaining() >= ByteArrayUtil.SIZE_DOUBLE * dimensionality);
+ final double[] values = new double[dimensionality];
+ for(int i = 0; i < dimensionality; i++) {
+ values[i] = buffer.getDouble();
+ }
+ return new Vector(values);
+ }
+
+ @Override
+ public void toByteBuffer(ByteBuffer buffer, Vector vec) throws IOException {
+ assert (vec.elements.length < Byte.MAX_VALUE) : "This serializer only supports a maximum dimensionality of " + Byte.MAX_VALUE + "!";
+ assert (buffer.remaining() >= ByteArrayUtil.SIZE_DOUBLE * vec.elements.length);
+ buffer.put((byte) vec.elements.length);
+ for(int i = 0; i < vec.elements.length; i++) {
+ buffer.putDouble(vec.elements[i]);
+ }
+ }
+
+ @Override
+ public int getByteSize(Vector vec) {
+ assert (vec.elements.length < Byte.MAX_VALUE) : "This serializer only supports a maximum dimensionality of " + Byte.MAX_VALUE + "!";
+ return ByteArrayUtil.SIZE_BYTE + ByteArrayUtil.SIZE_DOUBLE * vec.getDimensionality();
+ }
+ }
+
+ /**
+ * Serialization class for dense double vectors with up to
+ * {@link Short#MAX_VALUE} dimensions, by using a short for storing the
+ * dimensionality.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public static class ShortSerializer implements ByteBufferSerializer<Vector> {
+ @Override
+ public Vector fromByteBuffer(ByteBuffer buffer) throws IOException {
+ final short dimensionality = buffer.getShort();
+ assert (buffer.remaining() >= ByteArrayUtil.SIZE_DOUBLE * dimensionality);
+ final double[] values = new double[dimensionality];
+ for(int i = 0; i < dimensionality; i++) {
+ values[i] = buffer.getDouble();
+ }
+ return new Vector(values);
+ }
+
+ @Override
+ public void toByteBuffer(ByteBuffer buffer, Vector vec) throws IOException {
+ assert (vec.elements.length < Short.MAX_VALUE) : "This serializer only supports a maximum dimensionality of " + Short.MAX_VALUE + "!";
+ assert (buffer.remaining() >= ByteArrayUtil.SIZE_DOUBLE * vec.elements.length);
+ buffer.putShort((short) vec.elements.length);
+ for(int i = 0; i < vec.elements.length; i++) {
+ buffer.putDouble(vec.elements[i]);
+ }
+ }
+
+ @Override
+ public int getByteSize(Vector vec) {
+ assert (vec.elements.length < Short.MAX_VALUE) : "This serializer only supports a maximum dimensionality of " + Short.MAX_VALUE + "!";
+ return ByteArrayUtil.SIZE_SHORT + ByteArrayUtil.SIZE_DOUBLE * vec.getDimensionality();
+ }
+ }
+
+ /**
+ * Serialization class for variable dimensionality by using VarInt encoding.
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ protected static class VariableSerializer implements ByteBufferSerializer<Vector> {
+ @Override
+ public Vector fromByteBuffer(ByteBuffer buffer) throws IOException {
+ final int dimensionality = ByteArrayUtil.readUnsignedVarint(buffer);
+ assert (buffer.remaining() >= ByteArrayUtil.SIZE_DOUBLE * dimensionality);
+ final double[] values = new double[dimensionality];
+ for(int i = 0; i < dimensionality; i++) {
+ values[i] = buffer.getDouble();
+ }
+ return new Vector(values);
+ }
+
+ @Override
+ public void toByteBuffer(ByteBuffer buffer, Vector vec) throws IOException {
+ assert (buffer.remaining() >= ByteArrayUtil.SIZE_DOUBLE * vec.elements.length);
+ ByteArrayUtil.writeUnsignedVarint(buffer, vec.elements.length);
+ for(int i = 0; i < vec.elements.length; i++) {
+ buffer.putDouble(vec.elements[i]);
+ }
+ }
+
+ @Override
+ public int getByteSize(Vector vec) {
+ return ByteArrayUtil.getUnsignedVarintSize(vec.elements.length) + ByteArrayUtil.SIZE_DOUBLE * vec.elements.length;
+ }
+ }
}