You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mahout.apache.org by td...@apache.org on 2011/09/01 13:28:14 UTC
svn commit: r1164010 - in /mahout/trunk/math/src:
main/java/org/apache/mahout/math/ test/java/org/apache/mahout/math/
Author: tdunning
Date: Thu Sep 1 11:28:14 2011
New Revision: 1164010
URL: http://svn.apache.org/viewvc?rev=1164010&view=rev
Log:
MAHOUT-790 - Add some vector and matrix types to simplify certain manipulations.
Added:
mahout/trunk/math/src/main/java/org/apache/mahout/math/ConstantVector.java
mahout/trunk/math/src/main/java/org/apache/mahout/math/DiagonalMatrix.java
mahout/trunk/math/src/main/java/org/apache/mahout/math/PermutedVectorView.java
mahout/trunk/math/src/main/java/org/apache/mahout/math/PivotedMatrix.java
mahout/trunk/math/src/test/java/org/apache/mahout/math/PermutedVectorViewTest.java
mahout/trunk/math/src/test/java/org/apache/mahout/math/PivotedMatrixTest.java
Added: mahout/trunk/math/src/main/java/org/apache/mahout/math/ConstantVector.java
URL: http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/ConstantVector.java?rev=1164010&view=auto
==============================================================================
--- mahout/trunk/math/src/main/java/org/apache/mahout/math/ConstantVector.java (added)
+++ mahout/trunk/math/src/main/java/org/apache/mahout/math/ConstantVector.java Thu Sep 1 11:28:14 2011
@@ -0,0 +1,125 @@
+package org.apache.mahout.math;
+
+import com.google.common.collect.AbstractIterator;
+
+import java.util.Iterator;
+
+/**
+ * Implements a vector with all the same values.
+ */
+public class ConstantVector extends AbstractVector {
+ private double value;
+
+ public ConstantVector(double value, int size) {
+ super(size);
+ this.value = value;
+ }
+
+ /**
+ * Subclasses must override to return an appropriately sparse or dense result
+ *
+ * @param rows the row cardinality
+ * @param columns the column cardinality
+ * @return a Matrix
+ */
+ @Override
+ protected Matrix matrixLike(int rows, int columns) {
+ return new DenseMatrix(rows, columns);
+ }
+
+ /**
+ * @return true iff this implementation should be considered dense -- that it explicitly represents
+ * every value
+ */
+ @Override
+ public boolean isDense() {
+ return true;
+ }
+
+ /**
+ * @return true iff this implementation should be considered to be iterable in index order in an
+ * efficient way. In particular this implies that {@link #iterator()} and {@link
+ * #iterateNonZero()} return elements in ascending order by index.
+ */
+ @Override
+ public boolean isSequentialAccess() {
+ return true;
+ }
+
+ /**
+ * Iterates over all elements <p/> * NOTE: Implementations may choose to reuse the Element returned
+ * for performance reasons, so if you need a copy of it, you should call {@link #getElement(int)}
+ * for the given index
+ *
+ * @return An {@link java.util.Iterator} over all elements
+ */
+ @Override
+ public Iterator<Element> iterator() {
+ return new AbstractIterator<Element>() {
+ int i = 0;
+ int n = size();
+ @Override
+ protected Element computeNext() {
+ if (i < n) {
+ return new LocalElement(i++);
+ } else {
+ return endOfData();
+ }
+ }
+ };
+ }
+
+ /**
+ * Iterates over all non-zero elements. <p/> NOTE: Implementations may choose to reuse the Element
+ * returned for performance reasons, so if you need a copy of it, you should call {@link
+ * #getElement(int)} for the given index
+ *
+ * @return An {@link java.util.Iterator} over all non-zero elements
+ */
+ @Override
+ public Iterator<Element> iterateNonZero() {
+ return iterator();
+ }
+
+ /**
+ * Return the value at the given index, without checking bounds
+ *
+ * @param index an int index
+ * @return the double at the index
+ */
+ @Override
+ public double getQuick(int index) {
+ return value;
+ }
+
+ /**
+ * Return an empty vector of the same underlying class as the receiver
+ *
+ * @return a Vector
+ */
+ @Override
+ public Vector like() {
+ return new DenseVector(size());
+ }
+
+ /**
+ * Set the value at the given index, without checking bounds
+ *
+ * @param index an int index into the receiver
+ * @param value a double value to set
+ */
+ @Override
+ public void setQuick(int index, double value) {
+ throw new UnsupportedOperationException("Can't set a value in a constant matrix");
+ }
+
+ /**
+ * Return the number of values in the recipient
+ *
+ * @return an int
+ */
+ @Override
+ public int getNumNondefaultElements() {
+ return size();
+ }
+}
Added: mahout/trunk/math/src/main/java/org/apache/mahout/math/DiagonalMatrix.java
URL: http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/DiagonalMatrix.java?rev=1164010&view=auto
==============================================================================
--- mahout/trunk/math/src/main/java/org/apache/mahout/math/DiagonalMatrix.java (added)
+++ mahout/trunk/math/src/main/java/org/apache/mahout/math/DiagonalMatrix.java Thu Sep 1 11:28:14 2011
@@ -0,0 +1,153 @@
+package org.apache.mahout.math;
+
+/**
+ * Created by IntelliJ IDEA. User: tdunning Date: 8/9/11 Time: 10:36 PM To change this template use
+ * File | Settings | File Templates.
+ */
+public class DiagonalMatrix extends AbstractMatrix {
+ private Vector diagonal;
+
+ public DiagonalMatrix(Vector values) {
+ this.diagonal = values;
+ super.cardinality[0] = values.size();
+ super.cardinality[1] = values.size();
+ }
+
+ public DiagonalMatrix(Matrix values) {
+ this(values.viewDiagonal());
+ }
+
+ public DiagonalMatrix(double value, int size) {
+ this(new ConstantVector(value, size));
+ }
+
+ public DiagonalMatrix(double[] values) {
+ this.diagonal = new DenseVector(values);
+ }
+
+ public static DiagonalMatrix identity(int size) {
+ return new DiagonalMatrix(1, size);
+ }
+
+ @Override
+ public Matrix assignColumn(int column, Vector other) {
+ throw new UnsupportedOperationException("Can't assign a column to a diagonal matrix");
+ }
+
+ /**
+ * Assign the other vector values to the row of the receiver
+ *
+ * @param row the int row to assign
+ * @param other a Vector
+ * @return the modified receiver
+ * @throws CardinalityException if the cardinalities differ
+ */
+ @Override
+ public Matrix assignRow(int row, Vector other) {
+ throw new UnsupportedOperationException("Can't assign a row to a diagonal matrix");
+ }
+
+ /**
+ * Return the column at the given index
+ *
+ * @param column an int column index
+ * @return a Vector at the index
+ * @throws IndexException if the index is out of bounds
+ */
+ @Override
+ public Vector getColumn(int column) {
+ return new MatrixVectorView(this, 0, column, 1, 0);
+ }
+
+ /**
+ * Return the row at the given index
+ *
+ * @param row an int row index
+ * @return a Vector at the index
+ * @throws IndexException if the index is out of bounds
+ */
+ @Override
+ public Vector getRow(int row) {
+ return new MatrixVectorView(this, row, 0, 0, 1);
+ }
+
+ /**
+ * Provides a view of the diagonal of a matrix.
+ */
+ @Override
+ public Vector viewDiagonal() {
+ return this.diagonal;
+ }
+
+ /**
+ * Return the value at the given location, without checking bounds
+ *
+ * @param row an int row index
+ * @param column an int column index
+ * @return the double at the index
+ */
+ @Override
+ public double getQuick(int row, int column) {
+ if (row == column) {
+ return diagonal.get(row);
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Return an empty matrix of the same underlying class as the receiver
+ *
+ * @return a Matrix
+ */
+ @Override
+ public Matrix like() {
+ return new SparseRowMatrix(size());
+ }
+
+ /**
+ * Returns an empty matrix of the same underlying class as the receiver and of the specified
+ * size.
+ *
+ * @param rows the int number of rows
+ * @param columns the int number of columns
+ */
+ @Override
+ public Matrix like(int rows, int columns) {
+ return new SparseRowMatrix(new int[]{rows, columns});
+ }
+
+ @Override
+ public void setQuick(int row, int column, double value) {
+ if (row == column) {
+ diagonal.set(row, value);
+ } else {
+ throw new UnsupportedOperationException("Can't set off-diagonal element");
+ }
+ }
+
+ /**
+ * Return the number of values in the recipient
+ *
+ * @return an int[2] containing [row, column] count
+ */
+ @Override
+ public int[] getNumNondefaultElements() {
+ throw new UnsupportedOperationException("Don't understand how to implement this");
+ }
+
+ /**
+ * Return a new matrix containing the subset of the recipient
+ *
+ * @param offset an int[2] offset into the receiver
+ * @param size the int[2] size of the desired result
+ * @return a new Matrix that is a view of the original
+ * @throws CardinalityException if the length is greater than the cardinality of the receiver
+ * @throws IndexException if the offset is negative or the offset+length is outside of the
+ * receiver
+ */
+ @Override
+ public Matrix viewPart(int[] offset, int[] size) {
+ return new MatrixView(this, offset, size);
+ }
+}
Added: mahout/trunk/math/src/main/java/org/apache/mahout/math/PermutedVectorView.java
URL: http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/PermutedVectorView.java?rev=1164010&view=auto
==============================================================================
--- mahout/trunk/math/src/main/java/org/apache/mahout/math/PermutedVectorView.java (added)
+++ mahout/trunk/math/src/main/java/org/apache/mahout/math/PermutedVectorView.java Thu Sep 1 11:28:14 2011
@@ -0,0 +1,192 @@
+package org.apache.mahout.math;
+
+import com.google.common.collect.AbstractIterator;
+
+import java.util.Iterator;
+
+/**
+ * Provides a permuted view of a vector.
+ */
+public class PermutedVectorView extends AbstractVector {
+ private Vector vector; // the vector containing the data
+ private int[] pivot; // convert from external index to internal
+ private int[] unpivot; // convert from internal index to external
+
+ public PermutedVectorView(Vector vector, int[] pivot, int[] unpivot) {
+ super(vector.size());
+ this.vector = vector;
+ this.pivot = pivot;
+ this.unpivot = unpivot;
+ }
+
+ public PermutedVectorView(Vector vector, int[] pivot) {
+ this(vector, pivot, reversePivotPermutation(pivot));
+ }
+
+ private static int[] reversePivotPermutation(int[] pivot) {
+ int[] unpivot1 = new int[pivot.length];
+ for (int i = 0; i < pivot.length; i++) {
+ unpivot1[pivot[i]] = i;
+ }
+ return unpivot1;
+ }
+
+ /**
+ * Subclasses must override to return an appropriately sparse or dense result
+ *
+ * @param rows the row cardinality
+ * @param columns the column cardinality
+ * @return a Matrix
+ */
+ @Override
+ protected Matrix matrixLike(int rows, int columns) {
+ if (vector.isDense()) {
+ return new DenseMatrix(rows, columns);
+ } else {
+ return new SparseRowMatrix(new int[] {rows, columns});
+ }
+ }
+
+ /**
+ * @return true iff this implementation should be considered dense -- that it explicitly
+ * represents every value
+ */
+ @Override
+ public boolean isDense() {
+ return vector.isDense();
+ }
+
+ /**
+ * @return true iff this implementation should be considered to be iterable in index order in an
+ * efficient way. In particular this implies that {@link #iterator()} and {@link
+ * #iterateNonZero()} return elements in ascending order by index.
+ */
+ @Override
+ public boolean isSequentialAccess() {
+ return vector.isSequentialAccess();
+ }
+
+ /**
+ * Iterates over all elements <p/> * NOTE: Implementations may choose to reuse the Element
+ * returned for performance reasons, so if you need a copy of it, you should call {@link
+ * #getElement(int)} for the given index
+ *
+ * @return An {@link java.util.Iterator} over all elements
+ */
+ @Override
+ public Iterator<Element> iterator() {
+ return new AbstractIterator<Element>() {
+ Iterator<Element> i = vector.iterator();
+
+ @Override
+ protected Vector.Element computeNext() {
+ if (i.hasNext()) {
+ final Element x = i.next();
+ return new Element() {
+ int index = unpivot[x.index()];
+
+ @Override
+ public double get() {
+ return x.get();
+ }
+
+ @Override
+ public int index() {
+ return index;
+ }
+
+ @Override
+ public void set(double value) {
+ x.set(value);
+ }
+ };
+ } else {
+ return endOfData();
+ }
+ }
+ };
+ }
+
+ /**
+ * Iterates over all non-zero elements. <p/> NOTE: Implementations may choose to reuse the Element
+ * returned for performance reasons, so if you need a copy of it, you should call {@link
+ * #getElement(int)} for the given index
+ *
+ * @return An {@link java.util.Iterator} over all non-zero elements
+ */
+ @Override
+ public Iterator<Element> iterateNonZero() {
+ return new AbstractIterator<Element>() {
+ Iterator<Element> i = vector.iterateNonZero();
+
+ @Override
+ protected Vector.Element computeNext() {
+ if (i.hasNext()) {
+ final Element x = i.next();
+ return new Element() {
+ int index = unpivot[x.index()];
+
+ @Override
+ public double get() {
+ return x.get();
+ }
+
+ @Override
+ public int index() {
+ return index;
+ }
+
+ @Override
+ public void set(double value) {
+ x.set(value);
+ }
+ };
+ } else {
+ return endOfData();
+ }
+ }
+ };
+ }
+
+ /**
+ * Return the value at the given index, without checking bounds
+ *
+ * @param index an int index
+ * @return the double at the index
+ */
+ @Override
+ public double getQuick(int index) {
+ return vector.getQuick(pivot[index]);
+ }
+
+ /**
+ * Return an empty vector of the same underlying class as the receiver
+ *
+ * @return a Vector
+ */
+ @Override
+ public Vector like() {
+ return vector.like();
+ }
+
+ /**
+ * Set the value at the given index, without checking bounds
+ *
+ * @param index an int index into the receiver
+ * @param value a double value to set
+ */
+ @Override
+ public void setQuick(int index, double value) {
+ vector.setQuick(pivot[index], value);
+ }
+
+ /**
+ * Return the number of values in the recipient
+ *
+ * @return an int
+ */
+ @Override
+ public int getNumNondefaultElements() {
+ return vector.getNumNondefaultElements();
+ }
+}
Added: mahout/trunk/math/src/main/java/org/apache/mahout/math/PivotedMatrix.java
URL: http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/PivotedMatrix.java?rev=1164010&view=auto
==============================================================================
--- mahout/trunk/math/src/main/java/org/apache/mahout/math/PivotedMatrix.java (added)
+++ mahout/trunk/math/src/main/java/org/apache/mahout/math/PivotedMatrix.java Thu Sep 1 11:28:14 2011
@@ -0,0 +1,257 @@
+package org.apache.mahout.math;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Matrix that allows transparent row and column permutation.
+ */
+public class PivotedMatrix extends AbstractMatrix {
+ private Matrix base;
+ private int[] rowPivot;
+ private int[] rowUnpivot;
+
+ private int[] columnPivot;
+ private int[] columnUnpivot;
+
+ public PivotedMatrix(Matrix base, int[] pivot) {
+ this(base, pivot, java.util.Arrays.copyOf(pivot, pivot.length));
+ }
+ public PivotedMatrix(Matrix base, int[] rowPivot, int[] columnPivot) {
+ cardinality[ROW] = base.rowSize();
+ cardinality[COL] = base.columnSize();
+
+ this.base = base;
+ this.rowPivot = rowPivot;
+ rowUnpivot = invert(rowPivot);
+
+ this.columnPivot = columnPivot;
+ columnUnpivot = invert(columnPivot);
+ }
+
+ public PivotedMatrix(Matrix base) {
+ this(base, identityPivot(base.rowSize()),identityPivot(base.columnSize()));
+ }
+
+ /**
+ * Swaps indexes i and j. This does both row and column permutation.
+ *
+ * @param i First index to swap.
+ * @param j Second index to swap.
+ */
+ public void swap(int i, int j) {
+ swapRows(i, j);
+ swapColumns(i, j);
+ }
+
+ /**
+ * Swaps indexes i and j. This does just row permutation.
+ *
+ * @param i First index to swap.
+ * @param j Second index to swap.
+ */
+ public void swapRows(int i, int j) {
+ swap(rowPivot, rowUnpivot, i, j);
+ }
+
+
+ /**
+ * Swaps indexes i and j. This does just row permutation.
+ *
+ * @param i First index to swap.
+ * @param j Second index to swap.
+ */
+ public void swapColumns(int i, int j) {
+ swap(columnPivot, columnUnpivot, i, j);
+ }
+
+ private void swap(int[] pivot, int[] unpivot, int i, int j) {
+ Preconditions.checkPositionIndex(i, pivot.length);
+ Preconditions.checkPositionIndex(j, pivot.length);
+ if (i != j) {
+ int tmp = pivot[i];
+ pivot[i] = pivot[j];
+ pivot[j] = tmp;
+
+ unpivot[pivot[i]] = i;
+ unpivot[pivot[j]] = j;
+ }
+ }
+
+ /**
+ * Assign the other vector values to the column of the receiver
+ *
+ * @param column the int row to assign
+ * @param other a Vector
+ * @return the modified receiver
+ * @throws org.apache.mahout.math.CardinalityException
+ * if the cardinalities differ
+ */
+ @Override
+ public Matrix assignColumn(int column, Vector other) {
+ // note the reversed pivoting for other
+ return base.assignColumn(columnPivot[column], new PermutedVectorView(other, rowUnpivot, rowPivot));
+ }
+
+ /**
+ * Assign the other vector values to the row of the receiver
+ *
+ * @param row the int row to assign
+ * @param other a Vector
+ * @return the modified receiver
+ * @throws org.apache.mahout.math.CardinalityException
+ * if the cardinalities differ
+ */
+ @Override
+ public Matrix assignRow(int row, Vector other) {
+ // note the reversed pivoting for other
+ return base.assignRow(rowPivot[row], new PermutedVectorView(other, columnUnpivot, columnPivot));
+ }
+
+ /**
+ * Return the column at the given index
+ *
+ * @param column an int column index
+ * @return a Vector at the index
+ * @throws org.apache.mahout.math.IndexException
+ * if the index is out of bounds
+ */
+ @Override
+ public Vector getColumn(int column) {
+ if (column < 0 || column >= columnSize()) {
+ throw new IndexException(column, columnSize());
+ }
+ return new PermutedVectorView(base.getColumn(columnPivot[column]), rowPivot, rowUnpivot);
+ }
+
+ /**
+ * Return the row at the given index
+ *
+ * @param row an int row index
+ * @return a Vector at the index
+ * @throws org.apache.mahout.math.IndexException
+ * if the index is out of bounds
+ */
+ @Override
+ public Vector getRow(int row) {
+ if (row < 0 || row >= rowSize()) {
+ throw new IndexException(row, rowSize());
+ }
+ return new PermutedVectorView(base.getRow(rowPivot[row]), columnPivot, columnUnpivot);
+ }
+
+ /**
+ * Return the value at the given indexes, without checking bounds
+ *
+ * @param row an int row index
+ * @param column an int column index
+ * @return the double at the index
+ */
+ @Override
+ public double getQuick(int row, int column) {
+ return base.getQuick(rowPivot[row], columnPivot[column]);
+ }
+
+ /**
+ * Return an empty matrix of the same underlying class as the receiver
+ *
+ * @return a Matrix
+ */
+ @Override
+ public Matrix like() {
+ return new PivotedMatrix(base.like());
+ }
+
+ /**
+ * Returns an empty matrix of the same underlying class as the receiver and of the specified
+ * size.
+ *
+ * @param rows the int number of rows
+ * @param columns the int number of columns
+ */
+ @Override
+ public Matrix like(int rows, int columns) {
+ return new PivotedMatrix(base.like(rows, columns));
+ }
+
+ /**
+ * Set the value at the given index, without checking bounds
+ *
+ * @param row an int row index into the receiver
+ * @param column an int column index into the receiver
+ * @param value a double value to set
+ */
+ @Override
+ public void setQuick(int row, int column, double value) {
+ base.setQuick(rowPivot[row], columnPivot[column], value);
+ }
+
+ /**
+ * Return the number of values in the recipient
+ *
+ * @return an int[2] containing [row, column] count
+ */
+ @Override
+ public int[] getNumNondefaultElements() {
+ return base.getNumNondefaultElements();
+ }
+
+ /**
+ * Return a new matrix containing the subset of the recipient
+ *
+ * @param offset an int[2] offset into the receiver
+ * @param size the int[2] size of the desired result
+ * @return a new Matrix that is a view of the original
+ * @throws org.apache.mahout.math.CardinalityException
+ * if the length is greater than the cardinality of the receiver
+ * @throws org.apache.mahout.math.IndexException
+ * if the offset is negative or the offset+length is outside of the receiver
+ */
+ @Override
+ public Matrix viewPart(int[] offset, int[] size) {
+ return new MatrixView(this, offset, size);
+ }
+
+ public int rowUnpivot(int k) {
+ return rowUnpivot[k];
+ }
+
+ public int columnUnpivot(int k) {
+ return columnUnpivot[k];
+ }
+
+ public int[] getRowPivot() {
+ return rowPivot;
+ }
+
+ public int[] getInverseRowPivot() {
+ return rowUnpivot;
+ }
+
+ public int[] getColumnPivot() {
+ return columnPivot;
+ }
+
+ public int[] getInverseColumnPivot() {
+ return columnUnpivot;
+ }
+
+ public Matrix getBase() {
+ return base;
+ }
+
+ private static int[] identityPivot(int n) {
+ int[] pivot = new int[n];
+ for (int i = 0; i < n; i++) {
+ pivot[i] = i;
+ }
+ return pivot;
+ }
+
+ private int[] invert(int[] pivot) {
+ int[] x = new int[pivot.length];
+ for (int i = 0; i < pivot.length; i++) {
+ x[pivot[i]] = i;
+ }
+ return x;
+ }
+}
Added: mahout/trunk/math/src/test/java/org/apache/mahout/math/PermutedVectorViewTest.java
URL: http://svn.apache.org/viewvc/mahout/trunk/math/src/test/java/org/apache/mahout/math/PermutedVectorViewTest.java?rev=1164010&view=auto
==============================================================================
--- mahout/trunk/math/src/test/java/org/apache/mahout/math/PermutedVectorViewTest.java (added)
+++ mahout/trunk/math/src/test/java/org/apache/mahout/math/PermutedVectorViewTest.java Thu Sep 1 11:28:14 2011
@@ -0,0 +1,88 @@
+package org.apache.mahout.math;
+
+import org.apache.mahout.common.RandomUtils;
+import org.apache.mahout.math.function.DoubleFunction;
+import org.junit.Test;
+
+import java.util.Iterator;
+import java.util.Random;
+
+public class PermutedVectorViewTest extends MahoutTestCase {
+ @Test
+ public void testViewBasics() {
+ Vector v = randomVector();
+
+ int[] pivot = pivot();
+
+ PermutedVectorView pvv = new PermutedVectorView(v, pivot);
+
+ // verify the view has the same contents
+ for (int i = 0; i < 20; i++) {
+ assertEquals("Element " + i, v.get(pivot[i]), pvv.get(i), 0);
+ }
+
+ // change a view element or two on each side
+ pvv.set(6, 321);
+ v.set(9, 512);
+
+ // verify again
+ for (int i = 0; i < 20; i++) {
+ assertEquals("Element " + i, v.get(pivot[i]), pvv.get(i), 0);
+ }
+ }
+
+ @Test
+ public void testIterators() {
+ int[] pivot = pivot();
+ int[] unpivot = unpivot();
+
+ Vector v = randomVector();
+ PermutedVectorView pvv = new PermutedVectorView(v, pivot);
+
+ // check a simple operation and thus an iterator
+ assertEquals(v.zSum(), pvv.zSum(), 0);
+
+ assertEquals(v.getNumNondefaultElements(), pvv.getNumNondefaultElements());
+ v.set(11, 0);
+ assertEquals(v.getNumNondefaultElements(), pvv.getNumNondefaultElements());
+
+ Iterator<Vector.Element> vi = pvv.iterator();
+ int i = 0;
+ while (vi.hasNext()) {
+ Vector.Element e = vi.next();
+ assertEquals("Index " + i, i, pivot[e.index()]);
+ assertEquals("Reverse Index " + i, unpivot[i], e.index());
+ assertEquals("Self-value " + i, e.get(), pvv.get(e.index()), 0);
+ // note that we iterate in the original vector order
+ assertEquals("Value " + i, v.get(i), e.get(), 0);
+ i++;
+ }
+ }
+
+ private int[] pivot() {
+ return new int[]{11, 7, 10, 9, 8, 3, 17, 0, 19, 13, 12, 1, 5, 6, 16, 2, 4, 14, 18, 15};
+ }
+
+ private int[] unpivot() {
+ int[] pivot = pivot();
+ int[] unpivot = new int[20];
+
+ for (int i = 0; i < 20; i++) {
+ unpivot[pivot[i]] = i;
+ }
+ return unpivot;
+ }
+
+ private Vector randomVector() {
+ Vector v = new DenseVector(20);
+ v.assign(new DoubleFunction() {
+ Random gen = RandomUtils.getRandom();
+
+ @Override
+ public double apply(double arg1) {
+ return gen.nextDouble();
+ }
+ });
+ return v;
+ }
+}
Added: mahout/trunk/math/src/test/java/org/apache/mahout/math/PivotedMatrixTest.java
URL: http://svn.apache.org/viewvc/mahout/trunk/math/src/test/java/org/apache/mahout/math/PivotedMatrixTest.java?rev=1164010&view=auto
==============================================================================
--- mahout/trunk/math/src/test/java/org/apache/mahout/math/PivotedMatrixTest.java (added)
+++ mahout/trunk/math/src/test/java/org/apache/mahout/math/PivotedMatrixTest.java Thu Sep 1 11:28:14 2011
@@ -0,0 +1,48 @@
+package org.apache.mahout.math;
+
+import org.apache.mahout.common.RandomUtils;
+import org.junit.Test;
+
+import java.util.Random;
+
+public class PivotedMatrixTest extends MatrixTest {
+ @Override
+ public Matrix matrixFactory(double[][] values) {
+ Random gen = RandomUtils.getRandom();
+
+ Matrix base = new DenseMatrix(values);
+
+ // for general tests, we just make a scrambled matrix and fill it
+ // with the standard data. Then we can test the details of the
+ // row and/or column swapping separately.
+ PivotedMatrix pm = new PivotedMatrix(base.like());
+
+ pm.swap(0, 1);
+ pm.swapRows(1, 2);
+ pm.assign(base);
+ return pm;
+ }
+
+ @Test
+ public void testSwap() {
+ Matrix m = new DenseMatrix(10, 10);
+ for (int i = 0; i < 10; i++) {
+ for (int j = 0; j < 10; j++) {
+ m.set(i, j, 10 * i + j);
+ }
+ }
+
+ PivotedMatrix pm = new PivotedMatrix(m);
+
+ pm.swap(3, 5);
+
+ assertEquals(0, pm.viewDiagonal().minus(new DenseVector(new double[]{0, 11, 22, 55, 44, 33, 66, 77, 88, 99})).norm(1), 1e-10);
+
+ pm.swap(2, 7);
+ assertEquals(0, pm.viewDiagonal().minus(new DenseVector(new double[]{0, 11, 77, 55, 44, 33, 66, 22, 88, 99})).norm(1), 1e-10);
+
+ pm.swap(5, 8);
+ assertEquals(0, pm.viewColumn(4).minus(new DenseVector(new double[]{4.0,14.0,74.0,54.0,44.0,84.0,64.0,24.0,34.0,94.0})).norm(1), 1e-10);
+ assertEquals(0, pm.viewDiagonal().minus(new DenseVector(new double[]{0, 11, 77, 55, 44, 88, 66, 22, 33, 99})).norm(1), 1e-10);
+ }
+}