You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mahout.apache.org by gs...@apache.org on 2009/12/18 00:22:41 UTC
svn commit: r891983 [41/47] - in /lucene/mahout/trunk: ./ core/
core/src/main/java/org/apache/mahout/cf/taste/hadoop/item/
core/src/main/java/org/apache/mahout/clustering/
core/src/main/java/org/apache/mahout/clustering/canopy/
core/src/main/java/org/a...
Added: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/TridiagonalDoubleMatrix2D.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/TridiagonalDoubleMatrix2D.java?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/TridiagonalDoubleMatrix2D.java (added)
+++ lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/TridiagonalDoubleMatrix2D.java Thu Dec 17 23:22:16 2009
@@ -0,0 +1,532 @@
+/*
+Copyright � 1999 CERN - European Organization for Nuclear Research.
+Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose
+is hereby granted without fee, provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear in supporting documentation.
+CERN makes no representations about the suitability of this software for any purpose.
+It is provided "as is" without expressed or implied warranty.
+*/
+package org.apache.mahout.math.matrix.impl;
+
+import org.apache.mahout.math.function.DoubleDoubleFunction;
+import org.apache.mahout.math.function.IntIntDoubleFunction;
+import org.apache.mahout.math.jet.math.Functions;
+import org.apache.mahout.math.jet.math.Mult;
+import org.apache.mahout.math.jet.math.PlusMult;
+import org.apache.mahout.math.matrix.DoubleMatrix1D;
+import org.apache.mahout.math.matrix.DoubleMatrix2D;
+
+/**
+ * Tridiagonal 2-d matrix holding <tt>double</tt> elements. First see the <a href="package-summary.html">package
+ * summary</a> and javadoc <a href="package-tree.html">tree view</a> to get the broad picture. <p>
+ * <b>Implementation:</b> TODO.
+ *
+ * @author wolfgang.hoschek@cern.ch
+ * @version 0.9, 04/14/2000
+ */
+class TridiagonalDoubleMatrix2D extends WrapperDoubleMatrix2D {
+ /*
+ * The non zero elements of the matrix: {lower, diagonal, upper}.
+ */
+ private final double[] values;
+
+ /*
+ * The startIndexes and number of non zeros: {lowerStart, diagonalStart, upperStart, values.length, lowerNonZeros, diagonalNonZeros, upperNonZeros}.
+ * lowerStart = 0
+ * diagonalStart = lowerStart + lower.length
+ * upperStart = diagonalStart + diagonal.length
+ */
+ private final int[] dims;
+
+ private static final int NONZERO = 4;
+
+ //protected double diagonal[];
+ //protected double lower[];
+ //protected double upper[];
+
+ //protected int diagonalNonZeros;
+ //protected int lowerNonZeros;
+ //protected int upperNonZeros;
+ //protected int N;
+
+ /**
+ * Constructs a matrix with a copy of the given values. <tt>values</tt> is required to have the form
+ * <tt>values[row][column]</tt> and have exactly the same number of columns in every row. <p> The values are copied.
+ * So subsequent changes in <tt>values</tt> are not reflected in the matrix, and vice-versa.
+ *
+ * @param values The values to be filled into the new matrix.
+ * @throws IllegalArgumentException if <tt>for any 1 <= row < values.length: values[row].length !=
+ * values[row-1].length</tt>.
+ */
+ TridiagonalDoubleMatrix2D(double[][] values) {
+ this(values.length, values.length == 0 ? 0 : values[0].length);
+ assign(values);
+ }
+
+ /**
+ * Constructs a matrix with a given number of rows and columns. All entries are initially <tt>0</tt>.
+ *
+ * @param rows the number of rows the matrix shall have.
+ * @param columns the number of columns the matrix shall have.
+ * @throws IllegalArgumentException if <tt>rows<0 || columns<0 || (double)columns*rows > Integer.MAX_VALUE</tt>.
+ */
+ TridiagonalDoubleMatrix2D(int rows, int columns) {
+ super(null);
+ setUp(rows, columns);
+
+ int d = Math.min(rows, columns);
+ int u = d - 1;
+ int l = d - 1;
+ if (rows > columns) {
+ l++;
+ }
+ if (rows < columns) {
+ u++;
+ }
+
+ values = new double[l + d + u]; // {lower, diagonal, upper}
+ int[] dimensions = {0, l, l + d, l + d + u, 0, 0,
+ 0}; // {lowerStart, diagonalStart, upperStart, values.length, lowerNonZeros, diagonalNonZeros, upperNonZeros}
+ dims = dimensions;
+ }
+
+ /**
+ * Sets all cells to the state specified by <tt>value</tt>.
+ *
+ * @param value the value to be filled into the cells.
+ * @return <tt>this</tt> (for convenience only).
+ */
+ @Override
+ public DoubleMatrix2D assign(double value) {
+ // overriden for performance only
+ if (value == 0) {
+ for (int i = values.length; --i >= 0;) {
+ values[i] = 0;
+ }
+ for (int i = dims.length; --i >= NONZERO;) {
+ dims[i] = 0;
+ }
+
+ } else {
+ super.assign(value);
+ }
+ return this;
+ }
+
+ @Override
+ public DoubleMatrix2D assign(final org.apache.mahout.math.function.DoubleFunction function) {
+ if (function instanceof Mult) { // x[i] = mult*x[i]
+ double alpha = ((Mult) function).getMultiplicator();
+ if (alpha == 1) {
+ return this;
+ }
+ if (alpha == 0) {
+ return assign(0);
+ }
+ if (alpha != alpha) {
+ return assign(alpha);
+ } // the funny definition of isNaN(). This should better not happen.
+
+ forEachNonZero(
+ new IntIntDoubleFunction() {
+ @Override
+ public double apply(int i, int j, double value) {
+ return function.apply(value);
+ }
+ }
+ );
+ } else {
+ super.assign(function);
+ }
+ return this;
+ }
+
+ /**
+ * Replaces all cell values of the receiver with the values of another matrix. Both matrices must have the same number
+ * of rows and columns. If both matrices share the same cells (as is the case if they are views derived from the same
+ * matrix) and intersect in an ambiguous way, then replaces <i>as if</i> using an intermediate auxiliary deep copy of
+ * <tt>other</tt>.
+ *
+ * @param source the source matrix to copy from (may be identical to the receiver).
+ * @return <tt>this</tt> (for convenience only).
+ * @throws IllegalArgumentException if <tt>columns() != source.columns() || rows() != source.rows()</tt>
+ */
+ @Override
+ public DoubleMatrix2D assign(DoubleMatrix2D source) {
+ // overriden for performance only
+ if (source == this) {
+ return this;
+ } // nothing to do
+ checkShape(source);
+
+ if (source instanceof TridiagonalDoubleMatrix2D) {
+ // quickest
+ TridiagonalDoubleMatrix2D other = (TridiagonalDoubleMatrix2D) source;
+
+ System.arraycopy(other.values, 0, this.values, 0, this.values.length);
+ System.arraycopy(other.dims, 0, this.dims, 0, this.dims.length);
+ return this;
+ }
+
+ if (source instanceof RCDoubleMatrix2D || source instanceof SparseDoubleMatrix2D) {
+ assign(0);
+ source.forEachNonZero(
+ new IntIntDoubleFunction() {
+ @Override
+ public double apply(int i, int j, double value) {
+ setQuick(i, j, value);
+ return value;
+ }
+ }
+ );
+ return this;
+ }
+
+ return super.assign(source);
+ }
+
+ @Override
+ public DoubleMatrix2D assign(final DoubleMatrix2D y,
+ DoubleDoubleFunction function) {
+ checkShape(y);
+
+ if (function instanceof PlusMult) { // x[i] = x[i] + alpha*y[i]
+ final double alpha = ((PlusMult) function).getMultiplicator();
+ if (alpha == 0) {
+ return this;
+ } // nothing to do
+ y.forEachNonZero(
+ new IntIntDoubleFunction() {
+ @Override
+ public double apply(int i, int j, double value) {
+ setQuick(i, j, getQuick(i, j) + alpha * value);
+ return value;
+ }
+ }
+ );
+ return this;
+ }
+
+ if (function == org.apache.mahout.math.jet.math.Functions.mult) { // x[i] = x[i] * y[i]
+ forEachNonZero(
+ new IntIntDoubleFunction() {
+ @Override
+ public double apply(int i, int j, double value) {
+ setQuick(i, j, getQuick(i, j) * y.getQuick(i, j));
+ return value;
+ }
+ }
+ );
+ return this;
+ }
+
+ if (function == org.apache.mahout.math.jet.math.Functions.div) { // x[i] = x[i] / y[i]
+ forEachNonZero(
+ new IntIntDoubleFunction() {
+ @Override
+ public double apply(int i, int j, double value) {
+ setQuick(i, j, getQuick(i, j) / y.getQuick(i, j));
+ return value;
+ }
+ }
+ );
+ return this;
+ }
+
+ return super.assign(y, function);
+ }
+
+ @Override
+ public DoubleMatrix2D forEachNonZero(IntIntDoubleFunction function) {
+ for (int kind = 0; kind <= 2; kind++) {
+ int i = 0, j = 0;
+ switch (kind) {
+ case 0: {
+ i = 1;
+ } // lower
+ // case 1: { } // diagonal
+ case 2: {
+ j = 1;
+ } // upper
+ }
+ int low = dims[kind];
+ int high = dims[kind + 1];
+
+ for (int k = low; k < high; k++, i++, j++) {
+ double value = values[k];
+ if (value != 0) {
+ double r = function.apply(i, j, value);
+ if (r != value) {
+ if (r == 0) {
+ dims[kind + NONZERO]++;
+ } // one non zero more
+ values[k] = r;
+ }
+ }
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Returns the content of this matrix if it is a wrapper; or <tt>this</tt> otherwise. Override this method in
+ * wrappers.
+ */
+ @Override
+ protected DoubleMatrix2D getContent() {
+ return this;
+ }
+
+ /**
+ * Returns the matrix cell value at coordinate <tt>[row,column]</tt>.
+ *
+ * <p>Provided with invalid parameters this method may return invalid objects without throwing any exception. <b>You
+ * should only use this method when you are absolutely sure that the coordinate is within bounds.</b> Precondition
+ * (unchecked): <tt>0 <= column < columns() && 0 <= row < rows()</tt>.
+ *
+ * @param row the index of the row-coordinate.
+ * @param column the index of the column-coordinate.
+ * @return the value at the specified coordinate.
+ */
+ @Override
+ public double getQuick(int row, int column) {
+ int i = row;
+ int j = column;
+
+ int k = j - i + 1;
+ int q = i;
+ if (k == 0) {
+ q = j;
+ } // lower diagonal
+
+ if (k >= 0 && k <= 2) {
+ return values[dims[k] + q];
+ }
+ return 0;
+
+
+ //int k = -1;
+ //int q = 0;
+
+ //if (i==j) { k=0; q=i; }
+ //if (i==j+1) { k=1; q=j; }
+ //if (i==j-1) { k=2; q=i; }
+
+ //if (k<0) return 0;
+ //return values[dims[k]+q];
+
+
+ //if (i==j) return diagonal[i];
+ //if (i==j+1) return lower[j];
+ //if (i==j-1) return upper[i];
+
+ //return 0;
+ }
+
+ /**
+ * Construct and returns a new empty matrix <i>of the same dynamic type</i> as the receiver, having the specified
+ * number of rows and columns. For example, if the receiver is an instance of type <tt>DenseDoubleMatrix2D</tt> the
+ * new matrix must also be of type <tt>DenseDoubleMatrix2D</tt>, if the receiver is an instance of type
+ * <tt>SparseDoubleMatrix2D</tt> the new matrix must also be of type <tt>SparseDoubleMatrix2D</tt>, etc. In general,
+ * the new matrix should have internal parametrization as similar as possible.
+ *
+ * @param rows the number of rows the matrix shall have.
+ * @param columns the number of columns the matrix shall have.
+ * @return a new empty matrix of the same dynamic type.
+ */
+ @Override
+ public DoubleMatrix2D like(int rows, int columns) {
+ return new TridiagonalDoubleMatrix2D(rows, columns);
+ }
+
+ /**
+ * Construct and returns a new 1-d matrix <i>of the corresponding dynamic type</i>, entirelly independent of the
+ * receiver. For example, if the receiver is an instance of type <tt>DenseDoubleMatrix2D</tt> the new matrix must be
+ * of type <tt>DenseDoubleMatrix1D</tt>, if the receiver is an instance of type <tt>SparseDoubleMatrix2D</tt> the new
+ * matrix must be of type <tt>SparseDoubleMatrix1D</tt>, etc.
+ *
+ * @param size the number of cells the matrix shall have.
+ * @return a new matrix of the corresponding dynamic type.
+ */
+ @Override
+ public DoubleMatrix1D like1D(int size) {
+ return new SparseDoubleMatrix1D(size);
+ }
+
+ /**
+ * Sets the matrix cell at coordinate <tt>[row,column]</tt> to the specified value.
+ *
+ * <p>Provided with invalid parameters this method may access illegal indexes without throwing any exception. <b>You
+ * should only use this method when you are absolutely sure that the coordinate is within bounds.</b> Precondition
+ * (unchecked): <tt>0 <= column < columns() && 0 <= row < rows()</tt>.
+ *
+ * @param row the index of the row-coordinate.
+ * @param column the index of the column-coordinate.
+ * @param value the value to be filled into the specified cell.
+ */
+ @Override
+ public void setQuick(int row, int column, double value) {
+ int i = row;
+ int j = column;
+
+ boolean isZero = (value == 0);
+
+ int k = j - i + 1;
+ int q = i;
+ if (k == 0) {
+ q = j;
+ } // lower diagonal
+
+ if (k >= 0 && k <= 2) {
+ int index = dims[k] + q;
+ if (values[index] != 0) {
+ if (isZero) {
+ dims[k + NONZERO]--;
+ } // one nonZero less
+ } else {
+ if (!isZero) {
+ dims[k + NONZERO]++;
+ } // one nonZero more
+ }
+ values[index] = value;
+ return;
+ }
+
+ if (!isZero) {
+ throw new IllegalArgumentException(
+ "Can't store non-zero value to non-tridiagonal coordinate: row=" + row + ", column=" + column + ", value=" +
+ value);
+ }
+
+ }
+
+ @Override
+ public DoubleMatrix1D zMult(DoubleMatrix1D y, DoubleMatrix1D z, double alpha, double beta, final boolean transposeA) {
+ int m = rows;
+ int n = columns;
+ if (transposeA) {
+ m = columns;
+ n = rows;
+ }
+
+ boolean ignore = (z == null);
+ if (z == null) {
+ z = new DenseDoubleMatrix1D(m);
+ }
+
+ if (!(this.isNoView && y instanceof DenseDoubleMatrix1D && z instanceof DenseDoubleMatrix1D)) {
+ return super.zMult(y, z, alpha, beta, transposeA);
+ }
+
+ if (n != y.size() || m > z.size()) {
+ throw new IllegalArgumentException(
+ "Incompatible args: " + ((transposeA ? viewDice() : this).toStringShort()) + ", " + y.toStringShort() + ", " +
+ z.toStringShort());
+ }
+
+ if (!ignore) {
+ z.assign(Functions.mult(beta / alpha));
+ }
+
+ DenseDoubleMatrix1D zz = (DenseDoubleMatrix1D) z;
+ final double[] zElements = zz.elements;
+ final int zStride = zz.stride;
+ final int zi = z.index(0);
+
+ DenseDoubleMatrix1D yy = (DenseDoubleMatrix1D) y;
+ final double[] yElements = yy.elements;
+ final int yStride = yy.stride;
+ final int yi = y.index(0);
+
+ if (yElements == null || zElements == null) {
+ throw new InternalError();
+ }
+
+ forEachNonZero(
+ new IntIntDoubleFunction() {
+ @Override
+ public double apply(int i, int j, double value) {
+ if (transposeA) {
+ int tmp = i;
+ i = j;
+ j = tmp;
+ }
+ zElements[zi + zStride * i] += value * yElements[yi + yStride * j];
+ //z.setQuick(row,z.getQuick(row) + value * y.getQuick(column));
+ //log.info("["+i+","+j+"]-->"+value);
+ return value;
+ }
+ }
+ );
+
+ if (alpha != 1) {
+ z.assign(Functions.mult(alpha));
+ }
+ return z;
+ }
+
+ @Override
+ public DoubleMatrix2D zMult(DoubleMatrix2D B, DoubleMatrix2D C, final double alpha, double beta,
+ final boolean transposeA, boolean transposeB) {
+ if (transposeB) {
+ B = B.viewDice();
+ }
+ int m = rows;
+ int n = columns;
+ if (transposeA) {
+ m = columns;
+ n = rows;
+ }
+ int p = B.columns;
+ boolean ignore = (C == null);
+ if (C == null) {
+ C = new DenseDoubleMatrix2D(m, p);
+ }
+
+ if (B.rows != n) {
+ throw new IllegalArgumentException("Matrix2D inner dimensions must agree:" + toStringShort() + ", " +
+ (transposeB ? B.viewDice() : B).toStringShort());
+ }
+ if (C.rows != m || C.columns != p) {
+ throw new IllegalArgumentException(
+ "Incompatibel result matrix: " + toStringShort() + ", " + (transposeB ? B.viewDice() : B).toStringShort() +
+ ", " + C.toStringShort());
+ }
+ if (this == C || B == C) {
+ throw new IllegalArgumentException("Matrices must not be identical");
+ }
+
+ if (!ignore) {
+ C.assign(Functions.mult(beta));
+ }
+
+ // cache views
+ final DoubleMatrix1D[] Brows = new DoubleMatrix1D[n];
+ for (int i = n; --i >= 0;) {
+ Brows[i] = B.viewRow(i);
+ }
+ final DoubleMatrix1D[] Crows = new DoubleMatrix1D[m];
+ for (int i = m; --i >= 0;) {
+ Crows[i] = C.viewRow(i);
+ }
+
+ final org.apache.mahout.math.jet.math.PlusMult fun = org.apache.mahout.math.jet.math.PlusMult.plusMult(0);
+
+ forEachNonZero(
+ new IntIntDoubleFunction() {
+ @Override
+ public double apply(int i, int j, double value) {
+ fun.setMultiplicator(value * alpha);
+ if (!transposeA) {
+ Crows[i].assign(Brows[j], fun);
+ } else {
+ Crows[j].assign(Brows[i], fun);
+ }
+ return value;
+ }
+ }
+ );
+
+ return C;
+ }
+}
Propchange: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/TridiagonalDoubleMatrix2D.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/WrapperDoubleMatrix1D.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/WrapperDoubleMatrix1D.java?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/WrapperDoubleMatrix1D.java (added)
+++ lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/WrapperDoubleMatrix1D.java Thu Dec 17 23:22:16 2009
@@ -0,0 +1,248 @@
+/*
+Copyright � 1999 CERN - European Organization for Nuclear Research.
+Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose
+is hereby granted without fee, provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear in supporting documentation.
+CERN makes no representations about the suitability of this software for any purpose.
+It is provided "as is" without expressed or implied warranty.
+*/
+package org.apache.mahout.math.matrix.impl;
+
+import org.apache.mahout.math.matrix.DoubleMatrix1D;
+import org.apache.mahout.math.matrix.DoubleMatrix2D;
+
+/**
+ * 1-d matrix holding <tt>double</tt> elements; either a view wrapping another matrix or a matrix whose views are
+ * wrappers.
+ *
+ * @author wolfgang.hoschek@cern.ch
+ * @version 1.0, 09/24/99
+ */
+class WrapperDoubleMatrix1D extends DoubleMatrix1D {
+ /*
+ * The elements of the matrix.
+ */
+ protected final DoubleMatrix1D content;
+
+ WrapperDoubleMatrix1D(DoubleMatrix1D newContent) {
+ if (newContent != null) {
+ setUp(newContent.size());
+ }
+ this.content = newContent;
+ }
+
+ /**
+ * Returns the content of this matrix if it is a wrapper; or <tt>this</tt> otherwise. Override this method in
+ * wrappers.
+ */
+ @Override
+ protected DoubleMatrix1D getContent() {
+ return this.content;
+ }
+
+ /**
+ * Returns the matrix cell value at coordinate <tt>index</tt>.
+ *
+ * <p>Provided with invalid parameters this method may return invalid objects without throwing any exception. <b>You
+ * should only use this method when you are absolutely sure that the coordinate is within bounds.</b> Precondition
+ * (unchecked): <tt>index<0 || index>=size()</tt>.
+ *
+ * @param index the index of the cell.
+ * @return the value of the specified cell.
+ */
+ @Override
+ public double getQuick(int index) {
+ return content.getQuick(index);
+ }
+
+ /**
+ * Construct and returns a new empty matrix <i>of the same dynamic type</i> as the receiver, having the specified
+ * size. For example, if the receiver is an instance of type <tt>DenseDoubleMatrix1D</tt> the new matrix must also be
+ * of type <tt>DenseDoubleMatrix1D</tt>, if the receiver is an instance of type <tt>SparseDoubleMatrix1D</tt> the new
+ * matrix must also be of type <tt>SparseDoubleMatrix1D</tt>, etc. In general, the new matrix should have internal
+ * parametrization as similar as possible.
+ *
+ * @param size the number of cell the matrix shall have.
+ * @return a new empty matrix of the same dynamic type.
+ */
+ @Override
+ public DoubleMatrix1D like(int size) {
+ return content.like(size);
+ }
+
+ /**
+ * Construct and returns a new 2-d matrix <i>of the corresponding dynamic type</i>, entirelly independent of the
+ * receiver. For example, if the receiver is an instance of type <tt>DenseDoubleMatrix1D</tt> the new matrix must be
+ * of type <tt>DenseDoubleMatrix2D</tt>, if the receiver is an instance of type <tt>SparseDoubleMatrix1D</tt> the new
+ * matrix must be of type <tt>SparseDoubleMatrix2D</tt>, etc.
+ *
+ * @param rows the number of rows the matrix shall have.
+ * @param columns the number of columns the matrix shall have.
+ * @return a new matrix of the corresponding dynamic type.
+ */
+ @Override
+ public DoubleMatrix2D like2D(int rows, int columns) {
+ return content.like2D(rows, columns);
+ }
+
+ /**
+ * Sets the matrix cell at coordinate <tt>index</tt> to the specified value.
+ *
+ * <p>Provided with invalid parameters this method may access illegal indexes without throwing any exception. <b>You
+ * should only use this method when you are absolutely sure that the coordinate is within bounds.</b> Precondition
+ * (unchecked): <tt>index<0 || index>=size()</tt>.
+ *
+ * @param index the index of the cell.
+ * @param value the value to be filled into the specified cell.
+ */
+ @Override
+ public void setQuick(int index, double value) {
+ content.setQuick(index, value);
+ }
+
+ /**
+ * Constructs and returns a new <i>flip view</i>. What used to be index <tt>0</tt> is now index <tt>size()-1</tt>,
+ * ..., what used to be index <tt>size()-1</tt> is now index <tt>0</tt>. The returned view is backed by this matrix,
+ * so changes in the returned view are reflected in this matrix, and vice-versa.
+ *
+ * @return a new flip view.
+ */
+ @Override
+ public DoubleMatrix1D viewFlip() {
+ DoubleMatrix1D view = new WrapperDoubleMatrix1D(this) {
+ @Override
+ public double getQuick(int index) {
+ return content.get(size - 1 - index);
+ }
+
+ @Override
+ public void setQuick(int index, double value) {
+ content.set(size - 1 - index, value);
+ }
+ };
+ return view;
+ }
+
+ /**
+ * Constructs and returns a new <i>sub-range view</i> that is a <tt>width</tt> sub matrix starting at <tt>index</tt>.
+ *
+ * Operations on the returned view can only be applied to the restricted range. Any attempt to access coordinates not
+ * contained in the view will throw an <tt>IndexOutOfBoundsException</tt>. <p> <b>Note that the view is really just a
+ * range restriction:</b> The returned matrix is backed by this matrix, so changes in the returned matrix are
+ * reflected in this matrix, and vice-versa. <p> The view contains the cells from <tt>index..index+width-1</tt>. and
+ * has <tt>view.size() == width</tt>. A view's legal coordinates are again zero based, as usual. In other words, legal
+ * coordinates of the view are <tt>0 .. view.size()-1==width-1</tt>. As usual, any attempt to access a cell at other
+ * coordinates will throw an <tt>IndexOutOfBoundsException</tt>.
+ *
+ * @param index The index of the first cell.
+ * @param width The width of the range.
+ * @return the new view.
+ * @throws IndexOutOfBoundsException if <tt>index<0 || width<0 || index+width>size()</tt>.
+ */
+ @Override
+ public DoubleMatrix1D viewPart(final int index, int width) {
+ checkRange(index, width);
+ DoubleMatrix1D view = new WrapperDoubleMatrix1D(this) {
+ @Override
+ public double getQuick(int i) {
+ return content.get(index + i);
+ }
+
+ @Override
+ public void setQuick(int i, double value) {
+ content.set(index + i, value);
+ }
+ };
+ view.size = width;
+ return view;
+ }
+
+ /**
+ * Constructs and returns a new <i>selection view</i> that is a matrix holding the indicated cells. There holds
+ * <tt>view.size() == indexes.length</tt> and <tt>view.get(i) == this.get(indexes[i])</tt>. Indexes can occur multiple
+ * times and can be in arbitrary order. <p> <b>Example:</b> <br>
+ * <pre>
+ * this = (0,0,8,0,7)
+ * indexes = (0,2,4,2)
+ * -->
+ * view = (0,8,7,8)
+ * </pre>
+ * Note that modifying <tt>indexes</tt> after this call has returned has no effect on the view. The returned view is
+ * backed by this matrix, so changes in the returned view are reflected in this matrix, and vice-versa.
+ *
+ * @param indexes The indexes of the cells that shall be visible in the new view. To indicate that <i>all</i> cells
+ * shall be visible, simply set this parameter to <tt>null</tt>.
+ * @return the new view.
+ * @throws IndexOutOfBoundsException if <tt>!(0 <= indexes[i] < size())</tt> for any <tt>i=0..indexes.length()-1</tt>.
+ */
+ @Override
+ public DoubleMatrix1D viewSelection(int[] indexes) {
+ // check for "all"
+ if (indexes == null) {
+ indexes = new int[size];
+ for (int i = size; --i >= 0;) {
+ indexes[i] = i;
+ }
+ }
+
+ checkIndexes(indexes);
+ final int[] idx = indexes;
+
+ DoubleMatrix1D view = new WrapperDoubleMatrix1D(this) {
+ @Override
+ public double getQuick(int i) {
+ return content.get(idx[i]);
+ }
+
+ @Override
+ public void setQuick(int i, double value) {
+ content.set(idx[i], value);
+ }
+ };
+ view.size = indexes.length;
+ return view;
+ }
+
+ /**
+ * Construct and returns a new selection view.
+ *
+ * @param offsets the offsets of the visible elements.
+ * @return a new view.
+ */
+ @Override
+ protected DoubleMatrix1D viewSelectionLike(int[] offsets) {
+ throw new InternalError(); // should never get called
+ }
+
+ /**
+ * Constructs and returns a new <i>stride view</i> which is a sub matrix consisting of every i-th cell. More
+ * specifically, the view has size <tt>this.size()/stride</tt> holding cells <tt>this.get(i*stride)</tt> for all <tt>i
+ * = 0..size()/stride - 1</tt>.
+ *
+ * @param theStride the step factor.
+ * @return the new view.
+ * @throws IndexOutOfBoundsException if <tt>stride <= 0</tt>.
+ */
+ @Override
+ public DoubleMatrix1D viewStrides(final int theStride) {
+ if (stride <= 0) {
+ throw new IndexOutOfBoundsException("illegal stride: " + stride);
+ }
+ DoubleMatrix1D view = new WrapperDoubleMatrix1D(this) {
+ @Override
+ public double getQuick(int index) {
+ return content.get(index * theStride);
+ }
+
+ @Override
+ public void setQuick(int index, double value) {
+ content.set(index * theStride, value);
+ }
+ };
+ view.size = size;
+ if (size != 0) {
+ view.size = (size - 1) / theStride + 1;
+ }
+ return view;
+ }
+}
Propchange: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/WrapperDoubleMatrix1D.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/WrapperDoubleMatrix2D.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/WrapperDoubleMatrix2D.java?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/WrapperDoubleMatrix2D.java (added)
+++ lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/WrapperDoubleMatrix2D.java Thu Dec 17 23:22:16 2009
@@ -0,0 +1,414 @@
+/*
+Copyright � 1999 CERN - European Organization for Nuclear Research.
+Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose
+is hereby granted without fee, provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear in supporting documentation.
+CERN makes no representations about the suitability of this software for any purpose.
+It is provided "as is" without expressed or implied warranty.
+*/
+package org.apache.mahout.math.matrix.impl;
+
+import org.apache.mahout.math.matrix.DoubleMatrix1D;
+import org.apache.mahout.math.matrix.DoubleMatrix2D;
+
+/**
+ * 2-d matrix holding <tt>double</tt> elements; either a view wrapping another matrix or a matrix whose views are
+ * wrappers.
+ *
+ * @author wolfgang.hoschek@cern.ch
+ * @version 1.0, 04/14/2000
+ */
+class WrapperDoubleMatrix2D extends DoubleMatrix2D {
+ /*
+ * The elements of the matrix.
+ */
+ protected final DoubleMatrix2D content;
+
+ /**
+ * Constructs a matrix with a copy of the given values. <tt>values</tt> is required to have the form
+ * <tt>values[row][column]</tt> and have exactly the same number of columns in every row. <p> The values are copied.
+ * So subsequent changes in <tt>values</tt> are not reflected in the matrix, and vice-versa.
+ *
+ * @param newContent The values to be filled into the new matrix.
+ * @throws IllegalArgumentException if <tt>for any 1 <= row < values.length: values[row].length !=
+ * values[row-1].length</tt>.
+ */
+ WrapperDoubleMatrix2D(DoubleMatrix2D newContent) {
+ if (newContent != null) {
+ setUp(newContent.rows(), newContent.columns());
+ }
+ this.content = newContent;
+ }
+
+ /**
+ * Returns the content of this matrix if it is a wrapper; or <tt>this</tt> otherwise. Override this method in
+ * wrappers.
+ */
+ @Override
+ protected DoubleMatrix2D getContent() {
+ return content;
+ }
+
+ /**
+ * Returns the matrix cell value at coordinate <tt>[row,column]</tt>.
+ *
+ * <p>Provided with invalid parameters this method may return invalid objects without throwing any exception. <b>You
+ * should only use this method when you are absolutely sure that the coordinate is within bounds.</b> Precondition
+ * (unchecked): <tt>0 <= column < columns() && 0 <= row < rows()</tt>.
+ *
+ * @param row the index of the row-coordinate.
+ * @param column the index of the column-coordinate.
+ * @return the value at the specified coordinate.
+ */
+ @Override
+ public double getQuick(int row, int column) {
+ return content.getQuick(row, column);
+ }
+
+ /**
+ * Construct and returns a new empty matrix <i>of the same dynamic type</i> as the receiver, having the specified
+ * number of rows and columns. For example, if the receiver is an instance of type <tt>DenseDoubleMatrix2D</tt> the
+ * new matrix must also be of type <tt>DenseDoubleMatrix2D</tt>, if the receiver is an instance of type
+ * <tt>SparseDoubleMatrix2D</tt> the new matrix must also be of type <tt>SparseDoubleMatrix2D</tt>, etc. In general,
+ * the new matrix should have internal parametrization as similar as possible.
+ *
+ * @param rows the number of rows the matrix shall have.
+ * @param columns the number of columns the matrix shall have.
+ * @return a new empty matrix of the same dynamic type.
+ */
+ @Override
+ public DoubleMatrix2D like(int rows, int columns) {
+ return content.like(rows, columns);
+ }
+
+ /**
+ * Construct and returns a new 1-d matrix <i>of the corresponding dynamic type</i>, entirelly independent of the
+ * receiver. For example, if the receiver is an instance of type <tt>DenseDoubleMatrix2D</tt> the new matrix must be
+ * of type <tt>DenseDoubleMatrix1D</tt>, if the receiver is an instance of type <tt>SparseDoubleMatrix2D</tt> the new
+ * matrix must be of type <tt>SparseDoubleMatrix1D</tt>, etc.
+ *
+ * @param size the number of cells the matrix shall have.
+ * @return a new matrix of the corresponding dynamic type.
+ */
+ @Override
+ public DoubleMatrix1D like1D(int size) {
+ return content.like1D(size);
+ }
+
+ /**
+ * Construct and returns a new 1-d matrix <i>of the corresponding dynamic type</i>, sharing the same cells. For
+ * example, if the receiver is an instance of type <tt>DenseDoubleMatrix2D</tt> the new matrix must be of type
+ * <tt>DenseDoubleMatrix1D</tt>, if the receiver is an instance of type <tt>SparseDoubleMatrix2D</tt> the new matrix
+ * must be of type <tt>SparseDoubleMatrix1D</tt>, etc.
+ *
+ * @param size the number of cells the matrix shall have.
+ * @param offset the index of the first element.
+ * @param stride the number of indexes between any two elements, i.e. <tt>index(i+1)-index(i)</tt>.
+ * @return a new matrix of the corresponding dynamic type.
+ */
+ @Override
+ protected DoubleMatrix1D like1D(int size, int offset, int stride) {
+ throw new InternalError(); // should never get called
+ }
+
+ /**
+ * Sets the matrix cell at coordinate <tt>[row,column]</tt> to the specified value.
+ *
+ * <p>Provided with invalid parameters this method may access illegal indexes without throwing any exception. <b>You
+ * should only use this method when you are absolutely sure that the coordinate is within bounds.</b> Precondition
+ * (unchecked): <tt>0 <= column < columns() && 0 <= row < rows()</tt>.
+ *
+ * @param row the index of the row-coordinate.
+ * @param column the index of the column-coordinate.
+ * @param value the value to be filled into the specified cell.
+ */
+ @Override
+ public void setQuick(int row, int column, double value) {
+ content.setQuick(row, column, value);
+ }
+
+ /**
+ * Constructs and returns a new <i>slice view</i> representing the rows of the given column. The returned view is
+ * backed by this matrix, so changes in the returned view are reflected in this matrix, and vice-versa. To obtain a
+ * slice view on subranges, construct a sub-ranging view (<tt>viewPart(...)</tt>), then apply this method to the
+ * sub-range view. <p> <b>Example:</b> <table border="0"> <tr nowrap> <td valign="top">2 x 3 matrix: <br> 1, 2, 3<br>
+ * 4, 5, 6 </td> <td>viewColumn(0) ==></td> <td valign="top">Matrix1D of size 2:<br> 1, 4</td> </tr> </table>
+ *
+ * @param column the column to fix.
+ * @return a new slice view.
+ * @throws IndexOutOfBoundsException if <tt>column < 0 || column >= columns()</tt>.
+ * @see #viewRow(int)
+ */
+ @Override
+ public DoubleMatrix1D viewColumn(int column) {
+ return viewDice().viewRow(column);
+ }
+
+ /**
+ * Constructs and returns a new <i>flip view</i> along the column axis. What used to be column <tt>0</tt> is now
+ * column <tt>columns()-1</tt>, ..., what used to be column <tt>columns()-1</tt> is now column <tt>0</tt>. The
+ * returned view is backed by this matrix, so changes in the returned view are reflected in this matrix, and
+ * vice-versa. <p> <b>Example:</b> <table border="0"> <tr nowrap> <td valign="top">2 x 3 matrix: <br> 1, 2, 3<br> 4,
+ * 5, 6 </td> <td>columnFlip ==></td> <td valign="top">2 x 3 matrix:<br> 3, 2, 1 <br> 6, 5, 4</td> <td>columnFlip
+ * ==></td> <td valign="top">2 x 3 matrix: <br> 1, 2, 3<br> 4, 5, 6 </td> </tr> </table>
+ *
+ * @return a new flip view.
+ * @see #viewRowFlip()
+ */
+ @Override
+ public DoubleMatrix2D viewColumnFlip() {
+ if (columns == 0) {
+ return this;
+ }
+ DoubleMatrix2D view = new WrapperDoubleMatrix2D(this) {
+ @Override
+ public double getQuick(int row, int column) {
+ return content.get(row, columns - 1 - column);
+ }
+
+ @Override
+ public void setQuick(int row, int column, double value) {
+ content.set(row, columns - 1 - column, value);
+ }
+ };
+ return view;
+ }
+
+ /**
+ * Constructs and returns a new <i>dice (transposition) view</i>; Swaps axes; example: 3 x 4 matrix --> 4 x 3 matrix.
+ * The view has both dimensions exchanged; what used to be columns become rows, what used to be rows become columns.
+ * In other words: <tt>view.get(row,column)==this.get(column,row)</tt>. This is a zero-copy transposition, taking
+ * O(1), i.e. constant time. The returned view is backed by this matrix, so changes in the returned view are reflected
+ * in this matrix, and vice-versa. Use idioms like <tt>result = viewDice(A).copy()</tt> to generate an independent
+ * transposed matrix. <p> <b>Example:</b> <table border="0"> <tr nowrap> <td valign="top">2 x 3 matrix: <br> 1, 2,
+ * 3<br> 4, 5, 6 </td> <td>transpose ==></td> <td valign="top">3 x 2 matrix:<br> 1, 4 <br> 2, 5 <br> 3, 6</td>
+ * <td>transpose ==></td> <td valign="top">2 x 3 matrix: <br> 1, 2, 3<br> 4, 5, 6 </td> </tr> </table>
+ *
+ * @return a new dice view.
+ */
+ @Override
+ public DoubleMatrix2D viewDice() {
+ DoubleMatrix2D view = new WrapperDoubleMatrix2D(this) {
+ @Override
+ public double getQuick(int row, int column) {
+ return content.get(column, row);
+ }
+
+ @Override
+ public void setQuick(int row, int column, double value) {
+ content.set(column, row, value);
+ }
+ };
+ view.rows = columns;
+ view.columns = rows;
+ return view;
+ }
+
+ /**
+ * Constructs and returns a new <i>sub-range view</i> that is a <tt>height x width</tt> sub matrix starting at
+ * <tt>[row,column]</tt>.
+ *
+ * Operations on the returned view can only be applied to the restricted range. Any attempt to access coordinates not
+ * contained in the view will throw an <tt>IndexOutOfBoundsException</tt>. <p> <b>Note that the view is really just a
+ * range restriction:</b> The returned matrix is backed by this matrix, so changes in the returned matrix are
+ * reflected in this matrix, and vice-versa. <p> The view contains the cells from <tt>[row,column]</tt> to
+ * <tt>[row+height-1,column+width-1]</tt>, all inclusive. and has <tt>view.rows() == height; view.columns() ==
+ * width;</tt>. A view's legal coordinates are again zero based, as usual. In other words, legal coordinates of the
+ * view range from <tt>[0,0]</tt> to <tt>[view.rows()-1==height-1,view.columns()-1==width-1]</tt>. As usual, any
+ * attempt to access a cell at a coordinate <tt>column<0 || column>=view.columns() || row<0 ||
+ * row>=view.rows()</tt> will throw an <tt>IndexOutOfBoundsException</tt>.
+ *
+ * @param row The index of the row-coordinate.
+ * @param column The index of the column-coordinate.
+ * @param height The height of the box.
+ * @param width The width of the box.
+ * @return the new view.
+ * @throws IndexOutOfBoundsException if <tt>column<0 || width<0 || column+width>columns() || row<0 || height<0 ||
+ * row+height>rows()</tt>
+ */
+ @Override
+ public DoubleMatrix2D viewPart(final int row, final int column, int height, int width) {
+ checkBox(row, column, height, width);
+ DoubleMatrix2D view = new WrapperDoubleMatrix2D(this) {
+ @Override
+ public double getQuick(int i, int j) {
+ return content.get(row + i, column + j);
+ }
+
+ @Override
+ public void setQuick(int i, int j, double value) {
+ content.set(row + i, column + j, value);
+ }
+ };
+ view.rows = height;
+ view.columns = width;
+
+ return view;
+ }
+
+ /**
+ * Constructs and returns a new <i>slice view</i> representing the columns of the given row. The returned view is
+ * backed by this matrix, so changes in the returned view are reflected in this matrix, and vice-versa. To obtain a
+ * slice view on subranges, construct a sub-ranging view (<tt>viewPart(...)</tt>), then apply this method to the
+ * sub-range view. <p> <b>Example:</b> <table border="0"> <tr nowrap> <td valign="top">2 x 3 matrix: <br> 1, 2, 3<br>
+ * 4, 5, 6 </td> <td>viewRow(0) ==></td> <td valign="top">Matrix1D of size 3:<br> 1, 2, 3</td> </tr> </table>
+ *
+ * @param row the row to fix.
+ * @return a new slice view.
+ * @throws IndexOutOfBoundsException if <tt>row < 0 || row >= rows()</tt>.
+ * @see #viewColumn(int)
+ */
+ @Override
+ public DoubleMatrix1D viewRow(int row) {
+ checkRow(row);
+ return new DelegateDoubleMatrix1D(this, row);
+ }
+
+ /**
+ * Constructs and returns a new <i>flip view</i> along the row axis. What used to be row <tt>0</tt> is now row
+ * <tt>rows()-1</tt>, ..., what used to be row <tt>rows()-1</tt> is now row <tt>0</tt>. The returned view is backed by
+ * this matrix, so changes in the returned view are reflected in this matrix, and vice-versa. <p> <b>Example:</b>
+ * <table border="0"> <tr nowrap> <td valign="top">2 x 3 matrix: <br> 1, 2, 3<br> 4, 5, 6 </td> <td>rowFlip ==></td>
+ * <td valign="top">2 x 3 matrix:<br> 4, 5, 6 <br> 1, 2, 3</td> <td>rowFlip ==></td> <td valign="top">2 x 3 matrix:
+ * <br> 1, 2, 3<br> 4, 5, 6 </td> </tr> </table>
+ *
+ * @return a new flip view.
+ * @see #viewColumnFlip()
+ */
+ @Override
+ public DoubleMatrix2D viewRowFlip() {
+ if (rows == 0) {
+ return this;
+ }
+ DoubleMatrix2D view = new WrapperDoubleMatrix2D(this) {
+ @Override
+ public double getQuick(int row, int column) {
+ return content.get(rows - 1 - row, column);
+ }
+
+ @Override
+ public void setQuick(int row, int column, double value) {
+ content.set(rows - 1 - row, column, value);
+ }
+ };
+ return view;
+ }
+
+ /**
+ * Constructs and returns a new <i>selection view</i> that is a matrix holding the indicated cells. There holds
+ * <tt>view.rows() == rowIndexes.length, view.columns() == columnIndexes.length</tt> and <tt>view.get(i,j) ==
+ * this.get(rowIndexes[i],columnIndexes[j])</tt>. Indexes can occur multiple times and can be in arbitrary order. <p>
+ * <b>Example:</b>
+ * <pre>
+ * this = 2 x 3 matrix:
+ * 1, 2, 3
+ * 4, 5, 6
+ * rowIndexes = (0,1)
+ * columnIndexes = (1,0,1,0)
+ * -->
+ * view = 2 x 4 matrix:
+ * 2, 1, 2, 1
+ * 5, 4, 5, 4
+ * </pre>
+ * Note that modifying the index arguments after this call has returned has no effect on the view. The returned view
+ * is backed by this matrix, so changes in the returned view are reflected in this matrix, and vice-versa. <p> To
+ * indicate "all" rows or "all columns", simply set the respective parameter
+ *
+ * @param rowIndexes The rows of the cells that shall be visible in the new view. To indicate that <i>all</i> rows
+ * shall be visible, simply set this parameter to <tt>null</tt>.
+ * @param columnIndexes The columns of the cells that shall be visible in the new view. To indicate that <i>all</i>
+ * columns shall be visible, simply set this parameter to <tt>null</tt>.
+ * @return the new view.
+ * @throws IndexOutOfBoundsException if <tt>!(0 <= rowIndexes[i] < rows())</tt> for any <tt>i=0..rowIndexes.length()-1</tt>.
+ * @throws IndexOutOfBoundsException if <tt>!(0 <= columnIndexes[i] < columns())</tt> for any
+ * <tt>i=0..columnIndexes.length()-1</tt>.
+ */
+ @Override
+ public DoubleMatrix2D viewSelection(int[] rowIndexes, int[] columnIndexes) {
+ // check for "all"
+ if (rowIndexes == null) {
+ rowIndexes = new int[rows];
+ for (int i = rows; --i >= 0;) {
+ rowIndexes[i] = i;
+ }
+ }
+ if (columnIndexes == null) {
+ columnIndexes = new int[columns];
+ for (int i = columns; --i >= 0;) {
+ columnIndexes[i] = i;
+ }
+ }
+
+ checkRowIndexes(rowIndexes);
+ checkColumnIndexes(columnIndexes);
+ final int[] rix = rowIndexes;
+ final int[] cix = columnIndexes;
+
+ DoubleMatrix2D view = new WrapperDoubleMatrix2D(this) {
+ @Override
+ public double getQuick(int i, int j) {
+ return content.get(rix[i], cix[j]);
+ }
+
+ @Override
+ public void setQuick(int i, int j, double value) {
+ content.set(rix[i], cix[j], value);
+ }
+ };
+ view.rows = rowIndexes.length;
+ view.columns = columnIndexes.length;
+
+ return view;
+ }
+
+ /**
+ * Construct and returns a new selection view.
+ *
+ * @param rowOffsets the offsets of the visible elements.
+ * @param columnOffsets the offsets of the visible elements.
+ * @return a new view.
+ */
+ @Override
+ protected DoubleMatrix2D viewSelectionLike(int[] rowOffsets, int[] columnOffsets) {
+ throw new InternalError(); // should never be called
+ }
+
+ /**
+ * Constructs and returns a new <i>stride view</i> which is a sub matrix consisting of every i-th cell. More
+ * specifically, the view has <tt>this.rows()/rowStride</tt> rows and <tt>this.columns()/columnStride</tt> columns
+ * holding cells <tt>this.get(i*rowStride,j*columnStride)</tt> for all <tt>i = 0..rows()/rowStride - 1, j =
+ * 0..columns()/columnStride - 1</tt>. The returned view is backed by this matrix, so changes in the returned view are
+ * reflected in this matrix, and vice-versa.
+ *
+ * @param theRowStride the row step factor.
+ * @param theColumnStride the column step factor.
+ * @return a new view.
+ * @throws IndexOutOfBoundsException if <tt>rowStride<=0 || columnStride<=0</tt>.
+ */
+ @Override
+ public DoubleMatrix2D viewStrides(final int theRowStride, final int theColumnStride) {
+ if (theRowStride <= 0 || theColumnStride <= 0) {
+ throw new IndexOutOfBoundsException("illegal stride");
+ }
+ DoubleMatrix2D view = new WrapperDoubleMatrix2D(this) {
+ @Override
+ public double getQuick(int row, int column) {
+ return content.get(theRowStride * row, theColumnStride * column);
+ }
+
+ @Override
+ public void setQuick(int row, int column, double value) {
+ content.set(theRowStride * row, theColumnStride * column, value);
+ }
+ };
+ view.rows = rows;
+ view.columns = columns;
+ if (rows != 0) {
+ view.rows = (rows - 1) / theRowStride + 1;
+ }
+ if (columns != 0) {
+ view.columns = (columns - 1) / theColumnStride + 1;
+ }
+ return view;
+ }
+}
Propchange: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/WrapperDoubleMatrix2D.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/package.html
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/package.html?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/package.html (added)
+++ lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/package.html Thu Dec 17 23:22:16 2009
@@ -0,0 +1,6 @@
+<HTML>
+<BODY>
+Matrix <i>implementations</i>; You normally need not look at this package, because all concrete classes implement the
+abstract interfaces of {@link org.apache.mahout.math.matrix}, <i>without subsetting or supersetting</i>.
+</BODY>
+</HTML>
\ No newline at end of file
Propchange: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/impl/package.html
------------------------------------------------------------------------------
svn:eol-style = native
Added: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/linalg/Algebra.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/linalg/Algebra.java?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/linalg/Algebra.java (added)
+++ lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/linalg/Algebra.java Thu Dec 17 23:22:16 2009
@@ -0,0 +1,1032 @@
+/*
+Copyright � 1999 CERN - European Organization for Nuclear Research.
+Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose
+is hereby granted without fee, provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear in supporting documentation.
+CERN makes no representations about the suitability of this software for any purpose.
+It is provided "as is" without expressed or implied warranty.
+*/
+package org.apache.mahout.math.matrix.linalg;
+
+import org.apache.mahout.math.GenericPermuting;
+import org.apache.mahout.math.GenericSorting;
+import org.apache.mahout.math.PersistentObject;
+import org.apache.mahout.math.Swapper;
+import org.apache.mahout.math.bitvector.QuickBitVector;
+import org.apache.mahout.math.function.DoubleDoubleFunction;
+import org.apache.mahout.math.function.IntComparator;
+import org.apache.mahout.math.jet.math.Functions;
+import org.apache.mahout.math.list.ObjectArrayList;
+import org.apache.mahout.math.matrix.DoubleFactory2D;
+import org.apache.mahout.math.matrix.DoubleMatrix1D;
+import org.apache.mahout.math.matrix.DoubleMatrix2D;
+
+/** @deprecated until unit tests are in place. Until this time, this class/interface is unsupported. */
+@Deprecated
+public class Algebra extends PersistentObject {
+
+ /**
+ * A default Algebra object; has {@link Property#DEFAULT} attached for tolerance. Allows ommiting to construct an
+ * Algebra object time and again.
+ *
+ * Note that this Algebra object is immutable. Any attempt to assign a new Property object to it (via method
+ * <tt>setProperty</tt>), or to alter the tolerance of its property object (via <tt>property().setTolerance(...)</tt>)
+ * will throw an exception.
+ */
+ public static final Algebra DEFAULT;
+
+ /**
+ * A default Algebra object; has {@link Property#ZERO} attached for tolerance. Allows ommiting to construct an Algebra
+ * object time and again.
+ *
+ * Note that this Algebra object is immutable. Any attempt to assign a new Property object to it (via method
+ * <tt>setProperty</tt>), or to alter the tolerance of its property object (via <tt>property().setTolerance(...)</tt>)
+ * will throw an exception.
+ */
+ private static final Algebra ZERO;
+
+ /** The property object attached to this instance. */
+ private Property property;
+
+ static {
+ // don't use new Algebra(Property.DEFAULT.tolerance()), because then property object would be mutable.
+ DEFAULT = new Algebra();
+ DEFAULT.property = Property.DEFAULT; // immutable property object
+
+ ZERO = new Algebra();
+ ZERO.property = Property.ZERO; // immutable property object
+ }
+
+ /** Constructs a new instance with an equality tolerance given by <tt>Property.DEFAULT.tolerance()</tt>. */
+ public Algebra() {
+ this(Property.DEFAULT.tolerance());
+ }
+
+ /**
+ * Constructs a new instance with the given equality tolerance.
+ *
+ * @param tolerance the tolerance to be used for equality operations.
+ */
+ public Algebra(double tolerance) {
+ setProperty(new Property(tolerance));
+ }
+
+ /** Constructs and returns the cholesky-decomposition of the given matrix. */
+ private static CholeskyDecomposition chol(DoubleMatrix2D matrix) {
+ return new CholeskyDecomposition(matrix);
+ }
+
+ /**
+ * Returns a copy of the receiver. The attached property object is also copied. Hence, the property object of the copy
+ * is mutable.
+ *
+ * @return a copy of the receiver.
+ */
+ @Override
+ public Object clone() {
+ return new Algebra(property.tolerance());
+ }
+
+ /** Returns the condition of matrix <tt>A</tt>, which is the ratio of largest to smallest singular value. */
+ public double cond(DoubleMatrix2D A) {
+ return svd(A).cond();
+ }
+
+ /**
+ * Returns the determinant of matrix <tt>A</tt>.
+ *
+ * @return the determinant.
+ */
+ public double det(DoubleMatrix2D A) {
+ return lu(A).det();
+ }
+
+ /** Constructs and returns the Eigenvalue-decomposition of the given matrix. */
+ private static EigenvalueDecomposition eig(DoubleMatrix2D matrix) {
+ return new EigenvalueDecomposition(matrix);
+ }
+
+ /** Returns sqrt(a^2 + b^2) without under/overflow. */
+ protected static double hypot(double a, double b) {
+ double r;
+ if (Math.abs(a) > Math.abs(b)) {
+ r = b / a;
+ r = Math.abs(a) * Math.sqrt(1 + r * r);
+ } else if (b != 0) {
+ r = a / b;
+ r = Math.abs(b) * Math.sqrt(1 + r * r);
+ } else {
+ r = 0.0;
+ }
+ return r;
+ }
+
+ /** Returns sqrt(a^2 + b^2) without under/overflow. */
+ private static org.apache.mahout.math.function.DoubleDoubleFunction hypotFunction() {
+ return new DoubleDoubleFunction() {
+ @Override
+ public double apply(double a, double b) {
+ return hypot(a, b);
+ }
+ };
+ }
+
+ /**
+ * Returns the inverse or pseudo-inverse of matrix <tt>A</tt>.
+ *
+ * @return a new independent matrix; inverse(matrix) if the matrix is square, pseudoinverse otherwise.
+ */
+ public DoubleMatrix2D inverse(DoubleMatrix2D A) {
+ if (property.isSquare(A) && property.isDiagonal(A)) {
+ DoubleMatrix2D inv = A.copy();
+ boolean isNonSingular = Diagonal.inverse(inv);
+ if (!isNonSingular) {
+ throw new IllegalArgumentException("A is singular.");
+ }
+ return inv;
+ }
+ return solve(A, DoubleFactory2D.dense.identity(A.rows()));
+ }
+
+ /** Constructs and returns the LU-decomposition of the given matrix. */
+ private static LUDecomposition lu(DoubleMatrix2D matrix) {
+ return new LUDecomposition(matrix);
+ }
+
+ /**
+ * Inner product of two vectors; <tt>Sum(x[i] * y[i])</tt>. Also known as dot product. <br> Equivalent to
+ * <tt>x.zDotProduct(y)</tt>.
+ *
+ * @param x the first source vector.
+ * @param y the second source matrix.
+ * @return the inner product.
+ * @throws IllegalArgumentException if <tt>x.size() != y.size()</tt>.
+ */
+ public double mult(DoubleMatrix1D x, DoubleMatrix1D y) {
+ return x.zDotProduct(y);
+ }
+
+ /**
+ * Linear algebraic matrix-vector multiplication; <tt>z = A * y</tt>. <tt>z[i] = Sum(A[i,j] * y[j]), i=0..A.rows()-1,
+ * j=0..y.size()-1</tt>.
+ *
+ * @param A the source matrix.
+ * @param y the source vector.
+ * @return <tt>z</tt>; a new vector with <tt>z.size()==A.rows()</tt>.
+ * @throws IllegalArgumentException if <tt>A.columns() != y.size()</tt>.
+ */
+ public DoubleMatrix1D mult(DoubleMatrix2D A, DoubleMatrix1D y) {
+ return A.zMult(y, null);
+ }
+
+ /**
+ * Linear algebraic matrix-matrix multiplication; <tt>C = A x B</tt>. <tt>C[i,j] = Sum(A[i,k] * B[k,j]),
+ * k=0..n-1</tt>. <br> Matrix shapes: <tt>A(m x n), B(n x p), C(m x p)</tt>.
+ *
+ * @param A the first source matrix.
+ * @param B the second source matrix.
+ * @return <tt>C</tt>; a new matrix holding the results, with <tt>C.rows()=A.rows(), C.columns()==B.columns()</tt>.
+ * @throws IllegalArgumentException if <tt>B.rows() != A.columns()</tt>.
+ */
+ public DoubleMatrix2D mult(DoubleMatrix2D A, DoubleMatrix2D B) {
+ return A.zMult(B, null);
+ }
+
+ /**
+ * Outer product of two vectors; Sets <tt>A[i,j] = x[i] * y[j]</tt>.
+ *
+ * @param x the first source vector.
+ * @param y the second source vector.
+ * @param A the matrix to hold the results. Set this parameter to <tt>null</tt> to indicate that a new result matrix
+ * shall be constructed.
+ * @return A (for convenience only).
+ * @throws IllegalArgumentException if <tt>A.rows() != x.size() || A.columns() != y.size()</tt>.
+ */
+ public DoubleMatrix2D multOuter(DoubleMatrix1D x, DoubleMatrix1D y, DoubleMatrix2D A) {
+ int rows = x.size();
+ int columns = y.size();
+ if (A == null) {
+ A = x.like2D(rows, columns);
+ }
+ if (A.rows() != rows || A.columns() != columns) {
+ throw new IllegalArgumentException();
+ }
+
+ for (int row = rows; --row >= 0;) {
+ A.viewRow(row).assign(y);
+ }
+
+ for (int column = columns; --column >= 0;) {
+ A.viewColumn(column).assign(x, org.apache.mahout.math.jet.math.Functions.mult);
+ }
+ return A;
+ }
+
+ /** Returns the one-norm of vector <tt>x</tt>, which is <tt>Sum(abs(x[i]))</tt>. */
+ public double norm1(DoubleMatrix1D x) {
+ if (x.size() == 0) {
+ return 0;
+ }
+ return x.aggregate(Functions.plus, org.apache.mahout.math.jet.math.Functions.abs);
+ }
+
+ /** Returns the one-norm of matrix <tt>A</tt>, which is the maximum absolute column sum. */
+ public double norm1(DoubleMatrix2D A) {
+ double max = 0;
+ for (int column = A.columns(); --column >= 0;) {
+ max = Math.max(max, norm1(A.viewColumn(column)));
+ }
+ return max;
+ }
+
+ /** Returns the two-norm (aka <i>euclidean norm</i>) of vector <tt>x</tt>; equivalent to <tt>mult(x,x)</tt>. */
+ public double norm2(DoubleMatrix1D x) {
+ return mult(x, x);
+ }
+
+ /** Returns the two-norm of matrix <tt>A</tt>, which is the maximum singular value; obtained from SVD. */
+ public double norm2(DoubleMatrix2D A) {
+ return svd(A).norm2();
+ }
+
+ /** Returns the Frobenius norm of matrix <tt>A</tt>, which is <tt>Sqrt(Sum(A[i,j]<sup>2</sup>))</tt>. */
+ public double normF(DoubleMatrix2D A) {
+ if (A.size() == 0) {
+ return 0;
+ }
+ return A.aggregate(hypotFunction(), org.apache.mahout.math.jet.math.Functions.identity);
+ }
+
+ /** Returns the infinity norm of vector <tt>x</tt>, which is <tt>Max(abs(x[i]))</tt>. */
+ public double normInfinity(DoubleMatrix1D x) {
+ // fix for bug reported by T.J.Hunt@open.ac.uk
+ if (x.size() == 0) {
+ return 0;
+ }
+ return x.aggregate(Functions.max, org.apache.mahout.math.jet.math.Functions.abs);
+// if (x.size()==0) return 0;
+// return x.aggregate(Functions.plus,org.apache.mahout.math.jet.math.Functions.abs);
+// double max = 0;
+// for (int i = x.size(); --i >= 0; ) {
+// max = Math.max(max, x.getQuick(i));
+// }
+// return max;
+ }
+
+ /** Returns the infinity norm of matrix <tt>A</tt>, which is the maximum absolute row sum. */
+ public double normInfinity(DoubleMatrix2D A) {
+ double max = 0;
+ for (int row = A.rows(); --row >= 0;) {
+ //max = Math.max(max, normInfinity(A.viewRow(row)));
+ max = Math.max(max, norm1(A.viewRow(row)));
+ }
+ return max;
+ }
+
+ /**
+ * Modifies the given vector <tt>A</tt> such that it is permuted as specified; Useful for pivoting. Cell <tt>A[i]</tt>
+ * will go into cell <tt>A[indexes[i]]</tt>. <p> <b>Example:</b>
+ * <pre>
+ * Reordering
+ * [A,B,C,D,E] with indexes [0,4,2,3,1] yields
+ * [A,E,C,D,B]
+ * In other words A[0]<--A[0], A[1]<--A[4], A[2]<--A[2], A[3]<--A[3], A[4]<--A[1].
+ *
+ * Reordering
+ * [A,B,C,D,E] with indexes [0,4,1,2,3] yields
+ * [A,E,B,C,D]
+ * In other words A[0]<--A[0], A[1]<--A[4], A[2]<--A[1], A[3]<--A[2], A[4]<--A[3].
+ * </pre>
+ *
+ * @param A the vector to permute.
+ * @param indexes the permutation indexes, must satisfy <tt>indexes.length==A.size() && indexes[i] >= 0 && indexes[i]
+ * < A.size()</tt>;
+ * @param work the working storage, must satisfy <tt>work.length >= A.size()</tt>; set <tt>work==null</tt> if you
+ * don't care about performance.
+ * @return the modified <tt>A</tt> (for convenience only).
+ * @throws IndexOutOfBoundsException if <tt>indexes.length != A.size()</tt>.
+ */
+ public DoubleMatrix1D permute(DoubleMatrix1D A, int[] indexes, double[] work) {
+ // check validity
+ int size = A.size();
+ if (indexes.length != size) {
+ throw new IndexOutOfBoundsException("invalid permutation");
+ }
+
+ /*
+ int i=size;
+ int a;
+ while (--i >= 0 && (a=indexes[i])==i) if (a < 0 || a >= size) throw new IndexOutOfBoundsException("invalid permutation");
+ if (i<0) return; // nothing to permute
+ */
+
+ if (work == null || size > work.length) {
+ work = A.toArray();
+ } else {
+ A.toArray(work);
+ }
+ for (int i = size; --i >= 0;) {
+ A.setQuick(i, work[indexes[i]]);
+ }
+ return A;
+ }
+
+ /**
+ * Constructs and returns a new row and column permuted <i>selection view</i> of matrix <tt>A</tt>; equivalent to
+ * {@link DoubleMatrix2D#viewSelection(int[],int[])}. The returned matrix is backed by this matrix, so changes in the
+ * returned matrix are reflected in this matrix, and vice-versa. Use idioms like <tt>result = permute(...).copy()</tt>
+ * to generate an independent sub matrix.
+ *
+ * @return the new permuted selection view.
+ */
+ public DoubleMatrix2D permute(DoubleMatrix2D A, int[] rowIndexes, int[] columnIndexes) {
+ return A.viewSelection(rowIndexes, columnIndexes);
+ }
+
+ /**
+ * Modifies the given matrix <tt>A</tt> such that it's columns are permuted as specified; Useful for pivoting. Column
+ * <tt>A[i]</tt> will go into column <tt>A[indexes[i]]</tt>. Equivalent to <tt>permuteRows(transpose(A), indexes,
+ * work)</tt>.
+ *
+ * @param A the matrix to permute.
+ * @param indexes the permutation indexes, must satisfy <tt>indexes.length==A.columns() && indexes[i] >= 0 &&
+ * indexes[i] < A.columns()</tt>;
+ * @param work the working storage, must satisfy <tt>work.length >= A.columns()</tt>; set <tt>work==null</tt> if
+ * you don't care about performance.
+ * @return the modified <tt>A</tt> (for convenience only).
+ * @throws IndexOutOfBoundsException if <tt>indexes.length != A.columns()</tt>.
+ */
+ public DoubleMatrix2D permuteColumns(DoubleMatrix2D A, int[] indexes, int[] work) {
+ return permuteRows(A.viewDice(), indexes, work);
+ }
+
+ /**
+ * Modifies the given matrix <tt>A</tt> such that it's rows are permuted as specified; Useful for pivoting. Row
+ * <tt>A[i]</tt> will go into row <tt>A[indexes[i]]</tt>. <p> <b>Example:</b>
+ * <pre>
+ * Reordering
+ * [A,B,C,D,E] with indexes [0,4,2,3,1] yields
+ * [A,E,C,D,B]
+ * In other words A[0]<--A[0], A[1]<--A[4], A[2]<--A[2], A[3]<--A[3], A[4]<--A[1].
+ *
+ * Reordering
+ * [A,B,C,D,E] with indexes [0,4,1,2,3] yields
+ * [A,E,B,C,D]
+ * In other words A[0]<--A[0], A[1]<--A[4], A[2]<--A[1], A[3]<--A[2], A[4]<--A[3].
+ * </pre>
+ *
+ * @param A the matrix to permute.
+ * @param indexes the permutation indexes, must satisfy <tt>indexes.length==A.rows() && indexes[i] >= 0 && indexes[i]
+ * < A.rows()</tt>;
+ * @param work the working storage, must satisfy <tt>work.length >= A.rows()</tt>; set <tt>work==null</tt> if you
+ * don't care about performance.
+ * @return the modified <tt>A</tt> (for convenience only).
+ * @throws IndexOutOfBoundsException if <tt>indexes.length != A.rows()</tt>.
+ */
+ public DoubleMatrix2D permuteRows(final DoubleMatrix2D A, int[] indexes, int[] work) {
+ // check validity
+ int size = A.rows();
+ if (indexes.length != size) {
+ throw new IndexOutOfBoundsException("invalid permutation");
+ }
+
+ /*
+ int i=size;
+ int a;
+ while (--i >= 0 && (a=indexes[i])==i) if (a < 0 || a >= size) throw new IndexOutOfBoundsException("invalid permutation");
+ if (i<0) return; // nothing to permute
+ */
+
+ int columns = A.columns();
+ if (columns < size / 10) { // quicker
+ double[] doubleWork = new double[size];
+ for (int j = A.columns(); --j >= 0;) {
+ permute(A.viewColumn(j), indexes, doubleWork);
+ }
+ return A;
+ }
+
+ Swapper swapper = new Swapper() {
+ @Override
+ public void swap(int a, int b) {
+ A.viewRow(a).swap(A.viewRow(b));
+ }
+ };
+
+ GenericPermuting.permute(indexes, swapper, work, null);
+ return A;
+ }
+
+ /**
+ * Linear algebraic matrix power; <tt>B = A<sup>k</sup> <==> B = A*A*...*A</tt>. <ul> <li><tt>p >= 1: B =
+ * A*A*...*A</tt>.</li> <li><tt>p == 0: B = identity matrix</tt>.</li> <li><tt>p < 0: B =
+ * pow(inverse(A),-p)</tt>.</li> </ul> Implementation: Based on logarithms of 2, memory usage minimized.
+ *
+ * @param A the source matrix; must be square; stays unaffected by this operation.
+ * @param p the exponent, can be any number.
+ * @return <tt>B</tt>, a newly constructed result matrix; storage-independent of <tt>A</tt>.
+ * @throws IllegalArgumentException if <tt>!property().isSquare(A)</tt>.
+ */
+ public DoubleMatrix2D pow(DoubleMatrix2D A, int p) {
+ // matrix multiplication based on log2 method: A*A*....*A is slow, ((A * A)^2)^2 * ... is faster
+ // allocates two auxiliary matrices as work space
+
+ Blas blas = SmpBlas.getSmpBlas(); // for parallel matrix mult; if not initialized defaults to sequential blas
+ Property.DEFAULT.checkSquare(A);
+ if (p < 0) {
+ A = inverse(A);
+ p = -p;
+ }
+ if (p == 0) {
+ return DoubleFactory2D.dense.identity(A.rows());
+ }
+ DoubleMatrix2D T = A.like(); // temporary
+ if (p == 1) {
+ return T.assign(A);
+ } // safes one auxiliary matrix allocation
+ if (p == 2) {
+ blas.dgemm(false, false, 1, A, A, 0, T); // mult(A,A); // safes one auxiliary matrix allocation
+ return T;
+ }
+
+ int k = QuickBitVector.mostSignificantBit(p); // index of highest bit in state "true"
+
+ /*
+ this is the naive version:
+ DoubleMatrix2D B = A.copy();
+ for (int i=0; i<p-1; i++) {
+ B = mult(B,A);
+ }
+ return B;
+ */
+
+ // here comes the optimized version:
+ //org.apache.mahout.math.Timer timer = new Timer().start();
+
+ int i = 0;
+ while (i <= k && (p & (1 << i)) == 0) { // while (bit i of p == false)
+ // A = mult(A,A); would allocate a lot of temporary memory
+ blas.dgemm(false, false, 1, A, A, 0, T); // A.zMult(A,T);
+ DoubleMatrix2D swap = A;
+ A = T;
+ T = swap; // swap A with T
+ i++;
+ }
+
+ DoubleMatrix2D B = A.copy();
+ i++;
+ for (; i <= k; i++) {
+ // A = mult(A,A); would allocate a lot of temporary memory
+ blas.dgemm(false, false, 1, A, A, 0, T); // A.zMult(A,T);
+ DoubleMatrix2D swap = A;
+ A = T;
+ T = swap; // swap A with T
+
+ if ((p & (1 << i)) != 0) { // if (bit i of p == true)
+ // B = mult(B,A); would allocate a lot of temporary memory
+ blas.dgemm(false, false, 1, B, A, 0, T); // B.zMult(A,T);
+ swap = B;
+ B = T;
+ T = swap; // swap B with T
+ }
+ }
+ //timer.stop().display();
+ return B;
+ }
+
+ /**
+ * Returns the property object attached to this Algebra, defining tolerance.
+ *
+ * @return the Property object.
+ * @see #setProperty(Property)
+ */
+ public Property property() {
+ return property;
+ }
+
+ /** Constructs and returns the QR-decomposition of the given matrix. */
+ private static QRDecomposition qr(DoubleMatrix2D matrix) {
+ return new QRDecomposition(matrix);
+ }
+
+ /** Returns the effective numerical rank of matrix <tt>A</tt>, obtained from Singular Value Decomposition. */
+ public int rank(DoubleMatrix2D A) {
+ return svd(A).rank();
+ }
+
+ /**
+ * Attaches the given property object to this Algebra, defining tolerance.
+ *
+ * @param property the Property object to be attached.
+ * @throws UnsupportedOperationException if <tt>this==DEFAULT && property!=this.property()</tt> - The DEFAULT Algebra
+ * object is immutable.
+ * @throws UnsupportedOperationException if <tt>this==ZERO && property!=this.property()</tt> - The ZERO Algebra object
+ * is immutable.
+ * @see #property
+ */
+ public void setProperty(Property property) {
+ if (this == DEFAULT && property != this.property) {
+ throw new IllegalArgumentException("Attempted to modify immutable object.");
+ }
+ if (this == ZERO && property != this.property) {
+ throw new IllegalArgumentException("Attempted to modify immutable object.");
+ }
+ this.property = property;
+ }
+
+ /**
+ * Solves A*X = B.
+ *
+ * @return X; a new independent matrix; solution if A is square, least squares solution otherwise.
+ */
+ public DoubleMatrix2D solve(DoubleMatrix2D A, DoubleMatrix2D B) {
+ return (A.rows() == A.columns() ? (lu(A).solve(B)) : (qr(A).solve(B)));
+ }
+
+ /**
+ * Solves X*A = B, which is also A'*X' = B'.
+ *
+ * @return X; a new independent matrix; solution if A is square, least squares solution otherwise.
+ */
+ public DoubleMatrix2D solveTranspose(DoubleMatrix2D A, DoubleMatrix2D B) {
+ return solve(transpose(A), transpose(B));
+ }
+
+ /**
+ * Copies the columns of the indicated rows into a new sub matrix. <tt>sub[0..rowIndexes.length-1,0..columnTo-columnFrom]
+ * = A[rowIndexes(:),columnFrom..columnTo]</tt>; The returned matrix is <i>not backed</i> by this matrix, so changes
+ * in the returned matrix are <i>not reflected</i> in this matrix, and vice-versa.
+ *
+ * @param A the source matrix to copy from.
+ * @param rowIndexes the indexes of the rows to copy. May be unsorted.
+ * @param columnFrom the index of the first column to copy (inclusive).
+ * @param columnTo the index of the last column to copy (inclusive).
+ * @return a new sub matrix; with <tt>sub.rows()==rowIndexes.length; sub.columns()==columnTo-columnFrom+1</tt>.
+ * @throws IndexOutOfBoundsException if <tt>columnFrom<0 || columnTo-columnFrom+1<0 || columnTo+1>matrix.columns() ||
+ * for any row=rowIndexes[i]: row < 0 || row >= matrix.rows()</tt>.
+ */
+ private static DoubleMatrix2D subMatrix(DoubleMatrix2D A, int[] rowIndexes, int columnFrom, int columnTo) {
+ int width = columnTo - columnFrom + 1;
+ int rows = A.rows();
+ A = A.viewPart(0, columnFrom, rows, width);
+ DoubleMatrix2D sub = A.like(rowIndexes.length, width);
+
+ for (int r = rowIndexes.length; --r >= 0;) {
+ int row = rowIndexes[r];
+ if (row < 0 || row >= rows) {
+ throw new IndexOutOfBoundsException("Illegal Index");
+ }
+ sub.viewRow(r).assign(A.viewRow(row));
+ }
+ return sub;
+ }
+
+ /**
+ * Copies the rows of the indicated columns into a new sub matrix. <tt>sub[0..rowTo-rowFrom,0..columnIndexes.length-1]
+ * = A[rowFrom..rowTo,columnIndexes(:)]</tt>; The returned matrix is <i>not backed</i> by this matrix, so changes in
+ * the returned matrix are <i>not reflected</i> in this matrix, and vice-versa.
+ *
+ * @param A the source matrix to copy from.
+ * @param rowFrom the index of the first row to copy (inclusive).
+ * @param rowTo the index of the last row to copy (inclusive).
+ * @param columnIndexes the indexes of the columns to copy. May be unsorted.
+ * @return a new sub matrix; with <tt>sub.rows()==rowTo-rowFrom+1; sub.columns()==columnIndexes.length</tt>.
+ * @throws IndexOutOfBoundsException if <tt>rowFrom<0 || rowTo-rowFrom+1<0 || rowTo+1>matrix.rows() || for any
+ * col=columnIndexes[i]: col < 0 || col >= matrix.columns()</tt>.
+ */
+ private static DoubleMatrix2D subMatrix(DoubleMatrix2D A, int rowFrom, int rowTo, int[] columnIndexes) {
+ if (rowTo - rowFrom >= A.rows()) {
+ throw new IndexOutOfBoundsException("Too many rows");
+ }
+ int height = rowTo - rowFrom + 1;
+ int columns = A.columns();
+ A = A.viewPart(rowFrom, 0, height, columns);
+ DoubleMatrix2D sub = A.like(height, columnIndexes.length);
+
+ for (int c = columnIndexes.length; --c >= 0;) {
+ int column = columnIndexes[c];
+ if (column < 0 || column >= columns) {
+ throw new IndexOutOfBoundsException("Illegal Index");
+ }
+ sub.viewColumn(c).assign(A.viewColumn(column));
+ }
+ return sub;
+ }
+
+ /**
+ * Constructs and returns a new <i>sub-range view</i> which is the sub matrix <tt>A[fromRow..toRow,fromColumn..toColumn]</tt>.
+ * The returned matrix is backed by this matrix, so changes in the returned matrix are reflected in this matrix, and
+ * vice-versa. Use idioms like <tt>result = subMatrix(...).copy()</tt> to generate an independent sub matrix.
+ *
+ * @param A the source matrix.
+ * @param fromRow The index of the first row (inclusive).
+ * @param toRow The index of the last row (inclusive).
+ * @param fromColumn The index of the first column (inclusive).
+ * @param toColumn The index of the last column (inclusive).
+ * @return a new sub-range view.
+ * @throws IndexOutOfBoundsException if <tt>fromColumn<0 || toColumn-fromColumn+1<0 || toColumn>=A.columns() ||
+ * fromRow<0 || toRow-fromRow+1<0 || toRow>=A.rows()</tt>
+ */
+ public DoubleMatrix2D subMatrix(DoubleMatrix2D A, int fromRow, int toRow, int fromColumn, int toColumn) {
+ return A.viewPart(fromRow, fromColumn, toRow - fromRow + 1, toColumn - fromColumn + 1);
+ }
+
+ /** Constructs and returns the SingularValue-decomposition of the given matrix. */
+ private static SingularValueDecomposition svd(DoubleMatrix2D matrix) {
+ return new SingularValueDecomposition(matrix);
+ }
+
+ /**
+ * Returns a String with (propertyName, propertyValue) pairs. Useful for debugging or to quickly get the rough
+ * picture. For example,
+ * <pre>
+ * cond : 14.073264490042144
+ * det : Illegal operation or error: Matrix must be square.
+ * norm1 : 0.9620244354009628
+ * norm2 : 3.0
+ * normF : 1.304841791648992
+ * normInfinity : 1.5406551198102534
+ * rank : 3
+ * trace : 0
+ * </pre>
+ */
+ public String toString(DoubleMatrix2D matrix) {
+ final org.apache.mahout.math.list.ObjectArrayList names = new ObjectArrayList();
+ final org.apache.mahout.math.list.ObjectArrayList values = new ObjectArrayList();
+
+ // determine properties
+ names.add("cond");
+ String unknown = "Illegal operation or error: ";
+ try {
+ values.add(String.valueOf(cond(matrix)));
+ }
+ catch (IllegalArgumentException exc) {
+ values.add(unknown + exc.getMessage());
+ }
+
+ names.add("det");
+ try {
+ values.add(String.valueOf(det(matrix)));
+ }
+ catch (IllegalArgumentException exc) {
+ values.add(unknown + exc.getMessage());
+ }
+
+ names.add("norm1");
+ try {
+ values.add(String.valueOf(norm1(matrix)));
+ }
+ catch (IllegalArgumentException exc) {
+ values.add(unknown + exc.getMessage());
+ }
+
+ names.add("norm2");
+ try {
+ values.add(String.valueOf(norm2(matrix)));
+ }
+ catch (IllegalArgumentException exc) {
+ values.add(unknown + exc.getMessage());
+ }
+
+ names.add("normF");
+ try {
+ values.add(String.valueOf(normF(matrix)));
+ }
+ catch (IllegalArgumentException exc) {
+ values.add(unknown + exc.getMessage());
+ }
+
+ names.add("normInfinity");
+ try {
+ values.add(String.valueOf(normInfinity(matrix)));
+ }
+ catch (IllegalArgumentException exc) {
+ values.add(unknown + exc.getMessage());
+ }
+
+ names.add("rank");
+ try {
+ values.add(String.valueOf(rank(matrix)));
+ }
+ catch (IllegalArgumentException exc) {
+ values.add(unknown + exc.getMessage());
+ }
+
+ names.add("trace");
+ try {
+ values.add(String.valueOf(trace(matrix)));
+ }
+ catch (IllegalArgumentException exc) {
+ values.add(unknown + exc.getMessage());
+ }
+
+
+ // sort ascending by property name
+ IntComparator comp = new IntComparator() {
+ @Override
+ public int compare(int a, int b) {
+ return Property.get(names, a).compareTo(Property.get(names, b));
+ }
+ };
+ Swapper swapper = new Swapper() {
+ @Override
+ public void swap(int a, int b) {
+ Object tmp = names.get(a);
+ names.set(a, names.get(b));
+ names.set(b, tmp);
+ tmp = values.get(a);
+ values.set(a, values.get(b));
+ values.set(b, tmp);
+ }
+ };
+ GenericSorting.quickSort(0, names.size(), comp, swapper);
+
+ // determine padding for nice formatting
+ int maxLength = 0;
+ for (int i = 0; i < names.size(); i++) {
+ int length = ((String) names.get(i)).length();
+ maxLength = Math.max(length, maxLength);
+ }
+
+ // finally, format properties
+ StringBuilder buf = new StringBuilder();
+ for (int i = 0; i < names.size(); i++) {
+ String name = ((String) names.get(i));
+ buf.append(name);
+ buf.append(Property.blanks(maxLength - name.length()));
+ buf.append(" : ");
+ buf.append(values.get(i));
+ if (i < names.size() - 1) {
+ buf.append('\n');
+ }
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * Returns the results of <tt>toString(A)</tt> and additionally the results of all sorts of decompositions applied to
+ * the given matrix. Useful for debugging or to quickly get the rough picture. For example,
+ * <pre>
+ * A = 3 x 3 matrix
+ * 249 66 68
+ * 104 214 108
+ * 144 146 293
+ *
+ * cond : 3.931600417472078
+ * det : 9638870.0
+ * norm1 : 497.0
+ * norm2 : 473.34508217011404
+ * normF : 516.873292016525
+ * normInfinity : 583.0
+ * rank : 3
+ * trace : 756.0
+ *
+ * density : 1.0
+ * isDiagonal : false
+ * isDiagonallyDominantByColumn : true
+ * isDiagonallyDominantByRow : true
+ * isIdentity : false
+ * isLowerBidiagonal : false
+ * isLowerTriangular : false
+ * isNonNegative : true
+ * isOrthogonal : false
+ * isPositive : true
+ * isSingular : false
+ * isSkewSymmetric : false
+ * isSquare : true
+ * isStrictlyLowerTriangular : false
+ * isStrictlyTriangular : false
+ * isStrictlyUpperTriangular : false
+ * isSymmetric : false
+ * isTriangular : false
+ * isTridiagonal : false
+ * isUnitTriangular : false
+ * isUpperBidiagonal : false
+ * isUpperTriangular : false
+ * isZero : false
+ * lowerBandwidth : 2
+ * semiBandwidth : 3
+ * upperBandwidth : 2
+ *
+ * -----------------------------------------------------------------------------
+ * LUDecompositionQuick(A) --> isNonSingular(A), det(A), pivot, L, U, inverse(A)
+ * -----------------------------------------------------------------------------
+ * isNonSingular = true
+ * det = 9638870.0
+ * pivot = [0, 1, 2]
+ *
+ * L = 3 x 3 matrix
+ * 1 0 0
+ * 0.417671 1 0
+ * 0.578313 0.57839 1
+ *
+ * U = 3 x 3 matrix
+ * 249 66 68
+ * 0 186.433735 79.598394
+ * 0 0 207.635819
+ *
+ * inverse(A) = 3 x 3 matrix
+ * 0.004869 -0.000976 -0.00077
+ * -0.001548 0.006553 -0.002056
+ * -0.001622 -0.002786 0.004816
+ *
+ * -----------------------------------------------------------------
+ * QRDecomposition(A) --> hasFullRank(A), H, Q, R, pseudo inverse(A)
+ * -----------------------------------------------------------------
+ * hasFullRank = true
+ *
+ * H = 3 x 3 matrix
+ * 1.814086 0 0
+ * 0.34002 1.903675 0
+ * 0.470797 0.428218 2
+ *
+ * Q = 3 x 3 matrix
+ * -0.814086 0.508871 0.279845
+ * -0.34002 -0.808296 0.48067
+ * -0.470797 -0.296154 -0.831049
+ *
+ * R = 3 x 3 matrix
+ * -305.864349 -195.230337 -230.023539
+ * 0 -182.628353 467.703164
+ * 0 0 -309.13388
+ *
+ * pseudo inverse(A) = 3 x 3 matrix
+ * 0.006601 0.001998 -0.005912
+ * -0.005105 0.000444 0.008506
+ * -0.000905 -0.001555 0.002688
+ *
+ * --------------------------------------------------------------------------
+ * CholeskyDecomposition(A) --> isSymmetricPositiveDefinite(A), L, inverse(A)
+ * --------------------------------------------------------------------------
+ * isSymmetricPositiveDefinite = false
+ *
+ * L = 3 x 3 matrix
+ * 15.779734 0 0
+ * 6.590732 13.059948 0
+ * 9.125629 6.573948 12.903724
+ *
+ * inverse(A) = Illegal operation or error: Matrix is not symmetric positive definite.
+ *
+ * ---------------------------------------------------------------------
+ * EigenvalueDecomposition(A) --> D, V, realEigenvalues, imagEigenvalues
+ * ---------------------------------------------------------------------
+ * realEigenvalues = 1 x 3 matrix
+ * 462.796507 172.382058 120.821435
+ * imagEigenvalues = 1 x 3 matrix
+ * 0 0 0
+ *
+ * D = 3 x 3 matrix
+ * 462.796507 0 0
+ * 0 172.382058 0
+ * 0 0 120.821435
+ *
+ * V = 3 x 3 matrix
+ * -0.398877 -0.778282 0.094294
+ * -0.500327 0.217793 -0.806319
+ * -0.768485 0.66553 0.604862
+ *
+ * ---------------------------------------------------------------------
+ * SingularValueDecomposition(A) --> cond(A), rank(A), norm2(A), U, S, V
+ * ---------------------------------------------------------------------
+ * cond = 3.931600417472078
+ * rank = 3
+ * norm2 = 473.34508217011404
+ *
+ * U = 3 x 3 matrix
+ * 0.46657 -0.877519 0.110777
+ * 0.50486 0.161382 -0.847982
+ * 0.726243 0.45157 0.51832
+ *
+ * S = 3 x 3 matrix
+ * 473.345082 0 0
+ * 0 169.137441 0
+ * 0 0 120.395013
+ *
+ * V = 3 x 3 matrix
+ * 0.577296 -0.808174 0.116546
+ * 0.517308 0.251562 -0.817991
+ * 0.631761 0.532513 0.563301
+ * </pre>
+ */
+ public String toVerboseString(DoubleMatrix2D matrix) {
+/*
+ StringBuffer buf = new StringBuffer();
+ String unknown = "Illegal operation or error: ";
+ String constructionException = "Illegal operation or error upon construction: ";
+
+ buf.append("------------------------------------------------------------------\n");
+ buf.append("LUDecomposition(A) --> isNonSingular, det, pivot, L, U, inverse(A)\n");
+ buf.append("------------------------------------------------------------------\n");
+*/
+
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("A = ");
+ buf.append(matrix);
+
+ buf.append("\n\n").append(toString(matrix));
+ buf.append("\n\n").append(Property.DEFAULT.toString(matrix));
+
+ LUDecomposition lu = null;
+ String constructionException = "Illegal operation or error upon construction of ";
+ try {
+ lu = new LUDecomposition(matrix);
+ }
+ catch (IllegalArgumentException exc) {
+ buf.append("\n\n").append(constructionException).append(" LUDecomposition: ").append(exc.getMessage());
+ }
+ if (lu != null) {
+ buf.append("\n\n").append(lu.toString());
+ }
+
+ QRDecomposition qr = null;
+ try {
+ qr = new QRDecomposition(matrix);
+ }
+ catch (IllegalArgumentException exc) {
+ buf.append("\n\n").append(constructionException).append(" QRDecomposition: ").append(exc.getMessage());
+ }
+ if (qr != null) {
+ buf.append("\n\n").append(qr.toString());
+ }
+
+ CholeskyDecomposition chol = null;
+ try {
+ chol = new CholeskyDecomposition(matrix);
+ }
+ catch (IllegalArgumentException exc) {
+ buf.append("\n\n").append(constructionException).append(" CholeskyDecomposition: ").append(exc.getMessage());
+ }
+ if (chol != null) {
+ buf.append("\n\n").append(chol.toString());
+ }
+
+ EigenvalueDecomposition eig = null;
+ try {
+ eig = new EigenvalueDecomposition(matrix);
+ }
+ catch (IllegalArgumentException exc) {
+ buf.append("\n\n").append(constructionException).append(" EigenvalueDecomposition: ").append(exc.getMessage());
+ }
+ if (eig != null) {
+ buf.append("\n\n").append(eig.toString());
+ }
+
+ SingularValueDecomposition svd = null;
+ try {
+ svd = new SingularValueDecomposition(matrix);
+ }
+ catch (IllegalArgumentException exc) {
+ buf.append("\n\n").append(constructionException).append(" SingularValueDecomposition: ").append(exc.getMessage());
+ }
+ if (svd != null) {
+ buf.append("\n\n").append(svd.toString());
+ }
+
+ return buf.toString();
+ }
+
+ /** Returns the sum of the diagonal elements of matrix <tt>A</tt>; <tt>Sum(A[i,i])</tt>. */
+ public double trace(DoubleMatrix2D A) {
+ double sum = 0;
+ for (int i = Math.min(A.rows(), A.columns()); --i >= 0;) {
+ sum += A.getQuick(i, i);
+ }
+ return sum;
+ }
+
+ /**
+ * Constructs and returns a new view which is the transposition of the given matrix <tt>A</tt>. Equivalent to {@link
+ * DoubleMatrix2D#viewDice A.viewDice()}. This is a zero-copy transposition, taking O(1), i.e. constant time. The
+ * returned view is backed by this matrix, so changes in the returned view are reflected in this matrix, and
+ * vice-versa. Use idioms like <tt>result = transpose(A).copy()</tt> to generate an independent matrix. <p>
+ * <b>Example:</b> <table border="0"> <tr nowrap> <td valign="top">2 x 3 matrix: <br> 1, 2, 3<br> 4, 5, 6 </td>
+ * <td>transpose ==></td> <td valign="top">3 x 2 matrix:<br> 1, 4 <br> 2, 5 <br> 3, 6</td> <td>transpose ==></td> <td
+ * valign="top">2 x 3 matrix: <br> 1, 2, 3<br> 4, 5, 6 </td> </tr> </table>
+ *
+ * @return a new transposed view.
+ */
+ public DoubleMatrix2D transpose(DoubleMatrix2D A) {
+ return A.viewDice();
+ }
+
+ /**
+ * Modifies the matrix to be a lower trapezoidal matrix.
+ *
+ * @return <tt>A</tt> (for convenience only).
+ */
+ protected DoubleMatrix2D trapezoidalLower(DoubleMatrix2D A) {
+ int rows = A.rows();
+ int columns = A.columns();
+ for (int r = rows; --r >= 0;) {
+ for (int c = columns; --c >= 0;) {
+ if (r < c) {
+ A.setQuick(r, c, 0);
+ }
+ }
+ }
+ return A;
+ }
+
+}
Propchange: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/linalg/Algebra.java
------------------------------------------------------------------------------
svn:eol-style = native