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 &lt;= row &lt; 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 &lt;= column &lt; columns() && 0 &lt;= row &lt; 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 &lt;= column &lt; columns() && 0 &lt;= row &lt; 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&lt;0 || index&gt;=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&lt;0 || index&gt;=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 &lt;= row &lt; 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 &lt;= column &lt; columns() && 0 &lt;= row &lt; 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 &lt;= column &lt; columns() && 0 &lt;= row &lt; 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&lt;0 || column&gt;=view.columns() || row&lt;0 ||
+   * row&gt;=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 &gt;= 1: B =
+   * A*A*...*A</tt>.</li> <li><tt>p == 0: B = identity matrix</tt>.</li> <li><tt>p &lt;  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