You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mahout.apache.org by ra...@apache.org on 2018/09/08 23:35:17 UTC

[13/15] mahout git commit: NO-JIRA Trevors updates

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/DiagonalMatrix.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/DiagonalMatrix.java b/core/src/main/java/org/apache/mahout/math/DiagonalMatrix.java
new file mode 100644
index 0000000..070fad2
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/DiagonalMatrix.java
@@ -0,0 +1,378 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.math;
+
+import org.apache.mahout.math.flavor.MatrixFlavor;
+import org.apache.mahout.math.flavor.TraversingStructureEnum;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public class DiagonalMatrix extends AbstractMatrix implements MatrixTimesOps {
+  private final Vector diagonal;
+
+  public DiagonalMatrix(Vector values) {
+    super(values.size(), values.size());
+    this.diagonal = values;
+  }
+
+  public DiagonalMatrix(Matrix values) {
+    this(values.viewDiagonal());
+  }
+
+  public DiagonalMatrix(double value, int size) {
+    this(new ConstantVector(value, size));
+  }
+
+  public DiagonalMatrix(double[] values) {
+    super(values.length, values.length);
+    this.diagonal = new DenseVector(values);
+  }
+
+  public static DiagonalMatrix identity(int size) {
+    return new DiagonalMatrix(1, size);
+  }
+
+  @Override
+  public Matrix assignColumn(int column, Vector other) {
+    throw new UnsupportedOperationException("Can't assign a column to a diagonal matrix");
+  }
+
+  /**
+   * Assign the other vector values to the row of the receiver
+   *
+   * @param row   the int row to assign
+   * @param other a Vector
+   * @return the modified receiver
+   * @throws CardinalityException if the cardinalities differ
+   */
+  @Override
+  public Matrix assignRow(int row, Vector other) {
+    throw new UnsupportedOperationException("Can't assign a row to a diagonal matrix");
+  }
+
+  @Override
+  public Vector viewRow(int row) {
+    return new SingleElementVector(row);
+  }
+
+  @Override
+  public Vector viewColumn(int row) {
+    return new SingleElementVector(row);
+  }
+
+  /**
+   * Special class to implement views of rows and columns of a diagonal matrix.
+   */
+  public class SingleElementVector extends AbstractVector {
+    private int index;
+
+    public SingleElementVector(int index) {
+      super(diagonal.size());
+      this.index = index;
+    }
+
+    @Override
+    public double getQuick(int index) {
+      if (index == this.index) {
+        return diagonal.get(index);
+      } else {
+        return 0;
+      }
+    }
+
+    @Override
+    public void set(int index, double value) {
+      if (index == this.index) {
+        diagonal.set(index, value);
+      } else {
+        throw new IllegalArgumentException("Can't set off-diagonal element of diagonal matrix");
+      }
+    }
+
+    @Override
+    protected Iterator<Element> iterateNonZero() {
+      return new Iterator<Element>() {
+        boolean more = true;
+
+        @Override
+        public boolean hasNext() {
+          return more;
+        }
+
+        @Override
+        public Element next() {
+          if (more) {
+            more = false;
+            return new Element() {
+              @Override
+              public double get() {
+                return diagonal.get(index);
+              }
+
+              @Override
+              public int index() {
+                return index;
+              }
+
+              @Override
+              public void set(double value) {
+                diagonal.set(index, value);
+              }
+            };
+          } else {
+            throw new NoSuchElementException("Only one non-zero element in a row or column of a diagonal matrix");
+          }
+        }
+
+        @Override
+        public void remove() {
+          throw new UnsupportedOperationException("Can't remove from vector view");
+        }
+      };
+    }
+
+    @Override
+    protected Iterator<Element> iterator() {
+      return new Iterator<Element>() {
+        int i = 0;
+
+        Element r = new Element() {
+          @Override
+          public double get() {
+            if (i == index) {
+              return diagonal.get(index);
+            } else {
+              return 0;
+            }
+          }
+
+          @Override
+          public int index() {
+            return i;
+          }
+
+          @Override
+          public void set(double value) {
+            if (i == index) {
+              diagonal.set(index, value);
+            } else {
+              throw new IllegalArgumentException("Can't set any element but diagonal");
+            }
+          }
+        };
+
+        @Override
+        public boolean hasNext() {
+          return i < diagonal.size() - 1;
+        }
+
+        @Override
+        public Element next() {
+          if (i < SingleElementVector.this.size() - 1) {
+            i++;
+            return r;
+          } else {
+            throw new NoSuchElementException("Attempted to access passed last element of vector");
+          }
+        }
+
+
+        @Override
+        public void remove() {
+          throw new UnsupportedOperationException("Default operation");
+        }
+      };
+    }
+
+    @Override
+    protected Matrix matrixLike(int rows, int columns) {
+      return new DiagonalMatrix(rows, columns);
+    }
+
+    @Override
+    public boolean isDense() {
+      return false;
+    }
+
+    @Override
+    public boolean isSequentialAccess() {
+      return true;
+    }
+
+    @Override
+    public void mergeUpdates(OrderedIntDoubleMapping updates) {
+      throw new UnsupportedOperationException("Default operation");
+    }
+
+    @Override
+    public Vector like() {
+      return new DenseVector(size());
+    }
+
+    @Override
+    public Vector like(int cardinality) {
+      return new DenseVector(cardinality);
+    }
+
+    @Override
+    public void setQuick(int index, double value) {
+      if (index == this.index) {
+        diagonal.set(this.index, value);
+      } else {
+        throw new IllegalArgumentException("Can't set off-diagonal element of DiagonalMatrix");
+      }
+    }
+
+    @Override
+    public int getNumNondefaultElements() {
+      return 1;
+    }
+
+    @Override
+    public double getLookupCost() {
+      return 0;
+    }
+
+    @Override
+    public double getIteratorAdvanceCost() {
+      return 1;
+    }
+
+    @Override
+    public boolean isAddConstantTime() {
+      return false;
+    }
+  }
+
+  /**
+   * Provides a view of the diagonal of a matrix.
+   */
+  @Override
+  public Vector viewDiagonal() {
+    return this.diagonal;
+  }
+
+  /**
+   * Return the value at the given location, without checking bounds
+   *
+   * @param row    an int row index
+   * @param column an int column index
+   * @return the double at the index
+   */
+  @Override
+  public double getQuick(int row, int column) {
+    if (row == column) {
+      return diagonal.get(row);
+    } else {
+      return 0;
+    }
+  }
+
+  /**
+   * Return an empty matrix of the same underlying class as the receiver
+   *
+   * @return a Matrix
+   */
+  @Override
+  public Matrix like() {
+    return new SparseRowMatrix(rowSize(), columnSize());
+  }
+
+  /**
+   * Returns an empty matrix of the same underlying class as the receiver and of the specified
+   * size.
+   *
+   * @param rows    the int number of rows
+   * @param columns the int number of columns
+   */
+  @Override
+  public Matrix like(int rows, int columns) {
+    return new SparseRowMatrix(rows, columns);
+  }
+
+  @Override
+  public void setQuick(int row, int column, double value) {
+    if (row == column) {
+      diagonal.set(row, value);
+    } else {
+      throw new UnsupportedOperationException("Can't set off-diagonal element");
+    }
+  }
+
+  /**
+   * Return the number of values in the recipient
+   *
+   * @return an int[2] containing [row, column] count
+   */
+  @Override
+  public int[] getNumNondefaultElements() {
+    throw new UnsupportedOperationException("Don't understand how to implement this");
+  }
+
+  /**
+   * Return a new matrix containing the subset of the recipient
+   *
+   * @param offset an int[2] offset into the receiver
+   * @param size   the int[2] size of the desired result
+   * @return a new Matrix that is a view of the original
+   * @throws CardinalityException if the length is greater than the cardinality of the receiver
+   * @throws IndexException       if the offset is negative or the offset+length is outside of the
+   *                              receiver
+   */
+  @Override
+  public Matrix viewPart(int[] offset, int[] size) {
+    return new MatrixView(this, offset, size);
+  }
+
+  @Override
+  public Matrix times(Matrix other) {
+    return timesRight(other);
+  }
+
+  @Override
+  public Matrix timesRight(Matrix that) {
+    if (that.numRows() != diagonal.size()) {
+      throw new IllegalArgumentException("Incompatible number of rows in the right operand of matrix multiplication.");
+    }
+    Matrix m = that.like();
+    for (int row = 0; row < diagonal.size(); row++) {
+      m.assignRow(row, that.viewRow(row).times(diagonal.getQuick(row)));
+    }
+    return m;
+  }
+
+  @Override
+  public Matrix timesLeft(Matrix that) {
+    if (that.numCols() != diagonal.size()) {
+      throw new IllegalArgumentException(
+        "Incompatible number of rows in the left operand of matrix-matrix multiplication.");
+    }
+    Matrix m = that.like();
+    for (int col = 0; col < diagonal.size(); col++) {
+      m.assignColumn(col, that.viewColumn(col).times(diagonal.getQuick(col)));
+    }
+    return m;
+  }
+
+  @Override
+  public MatrixFlavor getFlavor() {
+    return MatrixFlavor.DIAGONALLIKE;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/FileBasedMatrix.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/FileBasedMatrix.java b/core/src/main/java/org/apache/mahout/math/FileBasedMatrix.java
new file mode 100644
index 0000000..3a19318
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/FileBasedMatrix.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.math;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.List;
+
+/**
+ * Provides a way to get data from a file and treat it as if it were a matrix, but avoids putting all that
+ * data onto the Java heap.  Instead, the file is mapped into non-heap memory as a DoubleBuffer and we access
+ * that instead.
+ */
+public final class FileBasedMatrix extends AbstractMatrix {
+  private final int rowsPerBlock;
+  private final List<DoubleBuffer> content = Lists.newArrayList();
+
+  /**
+   * Constructs an empty matrix of the given size.
+   *
+   * @param rows    The number of rows in the result.
+   * @param columns The number of columns in the result.
+   */
+  public FileBasedMatrix(int rows, int columns) {
+    super(rows, columns);
+    long maxRows = ((1L << 31) - 1) / (columns * 8);
+    if (rows > maxRows) {
+      rowsPerBlock = (int) maxRows;
+    } else {
+      rowsPerBlock = rows;
+    }
+  }
+
+  private void addData(DoubleBuffer content) {
+    this.content.add(content);
+  }
+
+  public void setData(File f, boolean loadNow) throws IOException {
+    Preconditions.checkArgument(f.length() == rows * columns * 8L, "File " + f + " is wrong length");
+
+    for (int i = 0; i < (rows + rowsPerBlock - 1) / rowsPerBlock; i++) {
+      long start = i * rowsPerBlock * columns * 8L;
+      long size = rowsPerBlock * columns * 8L;
+      MappedByteBuffer buf = new FileInputStream(f).getChannel().map(FileChannel.MapMode.READ_ONLY, start,
+                                                                     Math.min(f.length() - start, size));
+      if (loadNow) {
+        buf.load();
+      }
+      addData(buf.asDoubleBuffer());
+    }
+  }
+
+  public static void writeMatrix(File f, Matrix m) throws IOException {
+    Preconditions.checkArgument(f.canWrite(), "Can't write to output file");
+    FileOutputStream fos = new FileOutputStream(f);
+    try {
+      ByteBuffer buf = ByteBuffer.allocate(m.columnSize() * 8);
+      for (MatrixSlice row : m) {
+        buf.clear();
+        for (Vector.Element element : row.vector().all()) {
+          buf.putDouble(element.get());
+        }
+        buf.flip();
+        fos.write(buf.array());
+      }
+    } finally {
+      fos.close();
+    }
+  }
+
+  /**
+   * Assign the other vector values to the column of the receiver
+   *
+   * @param column the int row to assign
+   * @param other  a Vector
+   * @return the modified receiver
+   * @throws org.apache.mahout.math.CardinalityException
+   *          if the cardinalities differ
+   */
+  @Override
+  public Matrix assignColumn(int column, Vector other) {
+    throw new UnsupportedOperationException("Default operation");
+  }
+
+  /**
+   * Assign the other vector values to the row of the receiver
+   *
+   * @param row   the int row to assign
+   * @param other a Vector
+   * @return the modified receiver
+   * @throws org.apache.mahout.math.CardinalityException
+   *          if the cardinalities differ
+   */
+  @Override
+  public Matrix assignRow(int row, Vector other) {
+    throw new UnsupportedOperationException("Default operation");
+  }
+
+  /**
+   * Return the value at the given indexes, without checking bounds
+   *
+   * @param row    an int row index
+   * @param column an int column index
+   * @return the double at the index
+   */
+  @Override
+  public double getQuick(int row, int column) {
+    int block = row / rowsPerBlock;
+    return content.get(block).get((row % rowsPerBlock) * columns + column);
+  }
+
+  /**
+   * Return an empty matrix of the same underlying class as the receiver
+   *
+   * @return a Matrix
+   */
+  @Override
+  public Matrix like() {
+    throw new UnsupportedOperationException("Default operation");
+  }
+
+  /**
+   * Returns an empty matrix of the same underlying class as the receiver and of the specified size.
+   *
+   * @param rows    the int number of rows
+   * @param columns the int number of columns
+   */
+  @Override
+  public Matrix like(int rows, int columns) {
+    return new DenseMatrix(rows, columns);
+  }
+
+  /**
+   * Set the value at the given index, without checking bounds
+   *
+   * @param row    an int row index into the receiver
+   * @param column an int column index into the receiver
+   * @param value  a double value to set
+   */
+  @Override
+  public void setQuick(int row, int column, double value) {
+    throw new UnsupportedOperationException("Default operation");
+  }
+
+  /**
+   * Return a view into part of a matrix.  Changes to the view will change the
+   * original matrix.
+   *
+   * @param offset an int[2] offset into the receiver
+   * @param size   the int[2] size of the desired result
+   * @return a matrix that shares storage with part of the original matrix.
+   * @throws org.apache.mahout.math.CardinalityException
+   *          if the length is greater than the cardinality of the receiver
+   * @throws org.apache.mahout.math.IndexException
+   *          if the offset is negative or the offset+length is outside of the receiver
+   */
+  @Override
+  public Matrix viewPart(int[] offset, int[] size) {
+    throw new UnsupportedOperationException("Default operation");
+  }
+}

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/FileBasedSparseBinaryMatrix.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/FileBasedSparseBinaryMatrix.java b/core/src/main/java/org/apache/mahout/math/FileBasedSparseBinaryMatrix.java
new file mode 100644
index 0000000..0b0c25e
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/FileBasedSparseBinaryMatrix.java
@@ -0,0 +1,535 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.math;
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.nio.channels.FileChannel;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Provides a way to get data from a file and treat it as if it were a matrix, but avoids putting
+ * all that data onto the Java heap.  Instead, the file is mapped into non-heap memory as a
+ * DoubleBuffer and we access that instead.  The interesting aspect of this is that the values in
+ * the matrix are binary and sparse so we don't need to store the actual data, just the location of
+ * non-zero values.
+ * <p>
+ * Currently file data is formatted as follows:
+ * <p>
+ * <ul> <li>A magic number to indicate the file format.</li> <li>The size of the matrix (max rows
+ * and columns possible)</li> <li>Number of non-zeros in each row.</li> <li>A list of non-zero
+ * columns for each row.  The list starts with a count and then has column numbers</li> </ul>
+ * <p>
+ * It would be preferable to use something like protobufs to define the format so that we can use
+ * different row formats for different kinds of data.  For instance, Golay coding of column numbers
+ * or compressed bit vectors might be good representations for some purposes.
+ */
+public final class FileBasedSparseBinaryMatrix extends AbstractMatrix {
+  private static final int MAGIC_NUMBER_V0 = 0x12d7067d;
+
+  private final List<IntBuffer> data = Lists.newArrayList();
+  private int[] bufferIndex;
+  private int[] rowOffset;
+  private int[] rowSize;
+
+  /**
+   * Constructs an empty matrix of the given size.
+   *
+   * @param rows    The number of rows in the result.
+   * @param columns The number of columns in the result.
+   */
+  public FileBasedSparseBinaryMatrix(int rows, int columns) {
+    super(rows, columns);
+  }
+
+  public void setData(File f) throws IOException {
+    List<ByteBuffer> buffers = Lists.newArrayList();
+    FileChannel input = new FileInputStream(f).getChannel();
+
+    buffers.add(input.map(FileChannel.MapMode.READ_ONLY, 0, Math.min(Integer.MAX_VALUE, f.length())));
+    data.add(buffers.get(0).asIntBuffer());
+    Preconditions.checkArgument(buffers.get(0).getInt() == MAGIC_NUMBER_V0, "Wrong type of file");
+
+    int rows = buffers.get(0).getInt();
+    int cols = buffers.get(0).getInt();
+    Preconditions.checkArgument(rows == rowSize());
+    Preconditions.checkArgument(cols == columnSize());
+
+    rowOffset = new int[rows];
+    rowSize = new int[rows];
+    bufferIndex = new int[rows];
+
+    int offset = 12 + 4 * rows;
+    for (int i = 0; i < rows; i++) {
+      int size = buffers.get(0).getInt();
+      int buffer = 0;
+      while (buffer < buffers.size()) {
+        if (offset + size * 4 <= buffers.get(buffer).limit()) {
+          break;
+        } else {
+          offset -= buffers.get(buffer).capacity();
+        }
+      }
+      if (buffer == buffers.size()) {
+        buffers.add(input.map(FileChannel.MapMode.READ_ONLY, 0, Math.min(Integer.MAX_VALUE, f.length() - offset)));
+        data.add(buffers.get(buffer).asIntBuffer());
+      }
+      rowOffset[i] = offset / 4;
+      rowSize[i] = size;
+      bufferIndex[i] = buffer;
+
+//      final SparseBinaryVector v = new SparseBinaryVector(buffers.get(buffer), columns, offset, size);
+//      this.rows.add(v);
+      offset += size * 4;
+    }
+  }
+
+  public static void writeMatrix(File f, Matrix m) throws IOException {
+    Preconditions.checkArgument(f.canWrite(), "Can't write to output file");
+    FileOutputStream fos = new FileOutputStream(f);
+
+    // write header
+    DataOutputStream out = new DataOutputStream(fos);
+    out.writeInt(MAGIC_NUMBER_V0);
+    out.writeInt(m.rowSize());
+    out.writeInt(m.columnSize());
+
+    // compute offsets and write row headers
+    for (MatrixSlice row : m) {
+      int nondefaultElements = row.vector().getNumNondefaultElements();
+      out.writeInt(nondefaultElements);
+    }
+
+    // write rows
+    for (MatrixSlice row : m) {
+      List<Integer> columns = Lists.newArrayList(Iterables.transform(row.vector().nonZeroes(),
+        new Function<Vector.Element, Integer>() {
+          @Override
+          public Integer apply(Vector.Element element) {
+            return element.index();
+          }
+        }));
+      Collections.sort(columns);
+
+      for (Integer column : columns) {
+        out.writeInt(column);
+      }
+    }
+
+    out.close();
+    fos.close();
+  }
+
+  /**
+   * Assign the other vector values to the column of the receiver
+   *
+   * @param column the int row to assign
+   * @param other  a Vector
+   * @return the modified receiver
+   * @throws org.apache.mahout.math.CardinalityException
+   *          if the cardinalities differ
+   */
+  @Override
+  public Matrix assignColumn(int column, Vector other) {
+    throw new UnsupportedOperationException("Default operation");
+  }
+
+  /**
+   * Assign the other vector values to the row of the receiver
+   *
+   * @param row   the int row to assign
+   * @param other a Vector
+   * @return the modified receiver
+   * @throws org.apache.mahout.math.CardinalityException
+   *          if the cardinalities differ
+   */
+  @Override
+  public Matrix assignRow(int row, Vector other) {
+    throw new UnsupportedOperationException("Default operation");
+  }
+
+  /**
+   * Return the value at the given indexes, without checking bounds
+   *
+   * @param rowIndex    an int row index
+   * @param columnIndex an int column index
+   * @return the double at the index
+   */
+  @Override
+  public double getQuick(int rowIndex, int columnIndex) {
+    IntBuffer tmp = data.get(bufferIndex[rowIndex]).asReadOnlyBuffer();
+    tmp.position(rowOffset[rowIndex]);
+    tmp.limit(rowSize[rowIndex]);
+    tmp = tmp.slice();
+    return searchForIndex(tmp, columnIndex);
+  }
+
+  private static double searchForIndex(IntBuffer row, int columnIndex) {
+    int high = row.limit();
+    if (high == 0) {
+      return 0;
+    }
+    int low = 0;
+    while (high > low) {
+      int mid = (low + high) / 2;
+      if (row.get(mid) < columnIndex) {
+        low = mid + 1;
+      } else {
+        high = mid;
+      }
+    }
+    if (low >= row.limit()) {
+      return 0;
+    } else if (high == low && row.get(low) == columnIndex) {
+      return 1;
+    } else {
+      return 0;
+    }
+  }
+
+  /**
+   * Return an empty matrix of the same underlying class as the receiver
+   *
+   * @return a Matrix
+   */
+  @Override
+  public Matrix like() {
+    throw new UnsupportedOperationException("Default operation");
+  }
+
+  /**
+   * Returns an empty matrix of the same underlying class as the receiver and of the specified
+   * size.
+   *
+   * @param rows    the int number of rows
+   * @param columns the int number of columns
+   */
+  @Override
+  public Matrix like(int rows, int columns) {
+    return new DenseMatrix(rows, columns);
+  }
+
+  /**
+   * Set the value at the given index, without checking bounds
+   *
+   * @param row    an int row index into the receiver
+   * @param column an int column index into the receiver
+   * @param value  a double value to set
+   */
+  @Override
+  public void setQuick(int row, int column, double value) {
+    throw new UnsupportedOperationException("Default operation");
+  }
+
+  /**
+   * Return a view into part of a matrix.  Changes to the view will change the original matrix.
+   *
+   * @param offset an int[2] offset into the receiver
+   * @param size   the int[2] size of the desired result
+   * @return a matrix that shares storage with part of the original matrix.
+   * @throws org.apache.mahout.math.CardinalityException
+   *          if the length is greater than the cardinality of the receiver
+   * @throws org.apache.mahout.math.IndexException
+   *          if the offset is negative or the offset+length is outside of the receiver
+   */
+  @Override
+  public Matrix viewPart(int[] offset, int[] size) {
+    throw new UnsupportedOperationException("Default operation");
+  }
+
+  /**
+   * Returns a view of a row.  Changes to the view will affect the original.
+   *
+   * @param rowIndex Which row to return.
+   * @return A vector that references the desired row.
+   */
+  @Override
+  public Vector viewRow(int rowIndex) {
+    IntBuffer tmp = data.get(bufferIndex[rowIndex]).asReadOnlyBuffer();
+    tmp.position(rowOffset[rowIndex]);
+    tmp.limit(rowOffset[rowIndex] + rowSize[rowIndex]);
+    tmp = tmp.slice();
+    return new SparseBinaryVector(tmp, columnSize());
+  }
+
+  private static class SparseBinaryVector extends AbstractVector {
+    private final IntBuffer buffer;
+    private final int maxIndex;
+
+    private SparseBinaryVector(IntBuffer buffer, int maxIndex) {
+      super(maxIndex);
+      this.buffer = buffer;
+      this.maxIndex = maxIndex;
+    }
+
+    SparseBinaryVector(ByteBuffer row, int maxIndex, int offset, int size) {
+      super(maxIndex);
+      row = row.asReadOnlyBuffer();
+      row.position(offset);
+      row.limit(offset + size * 4);
+      row = row.slice();
+      this.buffer = row.slice().asIntBuffer();
+      this.maxIndex = maxIndex;
+    }
+
+    /**
+     * Subclasses must override to return an appropriately sparse or dense result
+     *
+     * @param rows    the row cardinality
+     * @param columns the column cardinality
+     * @return a Matrix
+     */
+    @Override
+    protected Matrix matrixLike(int rows, int columns) {
+      throw new UnsupportedOperationException("Default operation");
+    }
+
+    /**
+     * Used internally by assign() to update multiple indices and values at once.
+     * Only really useful for sparse vectors (especially SequentialAccessSparseVector).
+     * <p/>
+     * If someone ever adds a new type of sparse vectors, this method must merge (index, value) pairs into the vector.
+     *
+     * @param updates a mapping of indices to values to merge in the vector.
+     */
+    @Override
+    public void mergeUpdates(OrderedIntDoubleMapping updates) {
+      throw new UnsupportedOperationException("Cannot mutate SparseBinaryVector");
+    }
+
+    /**
+     * @return true iff this implementation should be considered dense -- that it explicitly represents
+     *         every value
+     */
+    @Override
+    public boolean isDense() {
+      return false;
+    }
+
+    /**
+     * @return true iff this implementation should be considered to be iterable in index order in an
+     *         efficient way. In particular this implies that {@link #iterator()} and {@link
+     *         #iterateNonZero()} return elements in ascending order by index.
+     */
+    @Override
+    public boolean isSequentialAccess() {
+      return true;
+    }
+
+    /**
+     * Iterates over all elements
+     *
+     * NOTE: Implementations may choose to reuse the Element returned
+     * for performance reasons, so if you need a copy of it, you should call {@link #getElement(int)}
+     * for the given index
+     *
+     * @return An {@link java.util.Iterator} over all elements
+     */
+    @Override
+    public Iterator<Element> iterator() {
+      return new AbstractIterator<Element>() {
+        int i = 0;
+
+        @Override
+        protected Element computeNext() {
+          if (i < maxIndex) {
+            return new Element() {
+              int index = i++;
+              /**
+               * @return the value of this vector element.
+               */
+              @Override
+              public double get() {
+                return getQuick(index);
+              }
+
+              /**
+               * @return the index of this vector element.
+               */
+              @Override
+              public int index() {
+                return index;
+              }
+
+              /**
+               * @param value Set the current element to value.
+               */
+              @Override
+              public void set(double value) {
+                throw new UnsupportedOperationException("Default operation");
+              }
+            };
+          } else {
+            return endOfData();
+          }
+        }
+      };
+    }
+
+    /**
+      * Iterates over all non-zero elements. <p/> NOTE: Implementations may choose to reuse the Element
+      * returned for performance reasons, so if you need a copy of it, you should call {@link
+      * #getElement(int)} for the given index
+      *
+      * @return An {@link java.util.Iterator} over all non-zero elements
+      */
+    @Override
+    public Iterator<Element> iterateNonZero() {
+      return new AbstractIterator<Element>() {
+        int i = 0;
+        @Override
+        protected Element computeNext() {
+          if (i < buffer.limit()) {
+            return new BinaryReadOnlyElement(buffer.get(i++));
+          } else {
+            return endOfData();
+          }
+        }
+      };
+    }
+
+  /**
+     * Return the value at the given index, without checking bounds
+     *
+     * @param index an int index
+     * @return the double at the index
+     */
+    @Override
+    public double getQuick(int index) {
+      return searchForIndex(buffer, index);
+    }
+
+    /**
+     * Return an empty vector of the same underlying class as the receiver
+     *
+     * @return a Vector
+     */
+    @Override
+    public Vector like() {
+      return new RandomAccessSparseVector(size());
+    }
+
+    @Override
+    public Vector like(int cardinality) {
+      return new RandomAccessSparseVector(cardinality);
+    }
+
+    /**
+     * Copy the vector for fast operations.
+     *
+     * @return a Vector
+     */
+    @Override
+    protected Vector createOptimizedCopy() {
+      return new RandomAccessSparseVector(size()).assign(this);
+    }
+
+    /**
+     * Set the value at the given index, without checking bounds
+     *
+     * @param index an int index into the receiver
+     * @param value a double value to set
+     */
+    @Override
+    public void setQuick(int index, double value) {
+      throw new UnsupportedOperationException("Read-only view");
+    }
+
+    /**
+     * Set the value at the given index, without checking bounds
+     *
+     * @param index an int index into the receiver
+     * @param increment a double value to set
+     */
+    @Override
+    public void incrementQuick(int index, double increment) {
+      throw new UnsupportedOperationException("Read-only view");
+    }
+
+    /**
+     * Return the number of values in the recipient which are not the default value.  For instance, for
+     * a sparse vector, this would be the number of non-zero values.
+     *
+     * @return an int
+     */
+    @Override
+    public int getNumNondefaultElements() {
+      return buffer.limit();
+    }
+
+    @Override
+    public double getLookupCost() {
+      return 1;
+    }
+
+    @Override
+    public double getIteratorAdvanceCost() {
+      return 1;
+    }
+
+    @Override
+    public boolean isAddConstantTime() {
+      throw new UnsupportedOperationException("Can't add binary value");
+    }
+  }
+
+  public static class BinaryReadOnlyElement implements Vector.Element {
+    private final int index;
+
+    public BinaryReadOnlyElement(int index) {
+      this.index = index;
+    }
+
+    /**
+     * @return the value of this vector element.
+     */
+    @Override
+    public double get() {
+      return 1;
+    }
+
+    /**
+     * @return the index of this vector element.
+     */
+    @Override
+    public int index() {
+      return index;
+    }
+
+    /**
+     * @param value Set the current element to value.
+     */
+    @Override
+    public void set(double value) {
+      throw new UnsupportedOperationException("Can't set binary value");
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/FunctionalMatrixView.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/FunctionalMatrixView.java b/core/src/main/java/org/apache/mahout/math/FunctionalMatrixView.java
new file mode 100644
index 0000000..9028e23
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/FunctionalMatrixView.java
@@ -0,0 +1,99 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.math;
+
+import org.apache.mahout.math.flavor.BackEnum;
+import org.apache.mahout.math.flavor.MatrixFlavor;
+import org.apache.mahout.math.flavor.TraversingStructureEnum;
+import org.apache.mahout.math.function.IntIntFunction;
+
+/**
+ * Matrix View backed by an {@link IntIntFunction}
+ */
+class FunctionalMatrixView extends AbstractMatrix {
+
+  /**
+   * view generator function
+   */
+  private IntIntFunction gf;
+  private boolean denseLike;
+  private MatrixFlavor flavor;
+
+  public FunctionalMatrixView(int rows, int columns, IntIntFunction gf) {
+    this(rows, columns, gf, false);
+  }
+
+  /**
+   * @param gf        generator function
+   * @param denseLike whether like() should create Dense or Sparse matrix.
+   */
+  public FunctionalMatrixView(int rows, int columns, IntIntFunction gf, boolean denseLike) {
+    super(rows, columns);
+    this.gf = gf;
+    this.denseLike = denseLike;
+    flavor = new MatrixFlavor.FlavorImpl(BackEnum.JVMMEM, TraversingStructureEnum.BLOCKIFIED, denseLike);
+  }
+
+  @Override
+  public Matrix assignColumn(int column, Vector other) {
+    throw new UnsupportedOperationException("Assignment to a matrix not supported");
+  }
+
+  @Override
+  public Matrix assignRow(int row, Vector other) {
+    throw new UnsupportedOperationException("Assignment to a matrix view not supported");
+  }
+
+  @Override
+  public double getQuick(int row, int column) {
+    return gf.apply(row, column);
+  }
+
+  @Override
+  public Matrix like() {
+    return like(rows, columns);
+  }
+
+  @Override
+  public Matrix like(int rows, int columns) {
+    if (denseLike)
+      return new DenseMatrix(rows, columns);
+    else
+      return new SparseMatrix(rows, columns);
+  }
+
+  @Override
+  public void setQuick(int row, int column, double value) {
+    throw new UnsupportedOperationException("Assignment to a matrix view not supported");
+  }
+
+  @Override
+  public Vector viewRow(int row) {
+    return new MatrixVectorView(this, row, 0, 0, 1, denseLike);
+  }
+
+  @Override
+  public Vector viewColumn(int column) {
+    return new MatrixVectorView(this, 0, column, 1, 0, denseLike);
+  }
+
+  @Override
+  public MatrixFlavor getFlavor() {
+    return flavor;
+  }
+}

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/IndexException.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/IndexException.java b/core/src/main/java/org/apache/mahout/math/IndexException.java
new file mode 100644
index 0000000..489d536
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/IndexException.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.math;
+
+/**
+ * Exception thrown when a matrix or vector is accessed at an index, or dimension,
+ * which does not logically exist in the entity.
+ */
+public class IndexException extends IllegalArgumentException {
+
+  public IndexException(int index, int cardinality) {
+    super("Index " + index + " is outside allowable range of [0," + cardinality + ')');
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/LengthCachingVector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/LengthCachingVector.java b/core/src/main/java/org/apache/mahout/math/LengthCachingVector.java
new file mode 100644
index 0000000..770ccc4
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/LengthCachingVector.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.math;
+
+/**
+ * Marker interface for vectors that may cache their squared length.
+ */
+interface LengthCachingVector {
+  /**
+   * Gets the currently cached squared length or if there is none, recalculates
+   * the value and returns that.
+   * @return The sum of the squares of all elements in the vector.
+   */
+  double getLengthSquared();
+
+  /**
+   * Invalidates the length cache.  This should be called by all mutators of the vector.
+   */
+  void invalidateCachedLength();
+}

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/Matrices.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/Matrices.java b/core/src/main/java/org/apache/mahout/math/Matrices.java
new file mode 100644
index 0000000..5d8b5c5
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/Matrices.java
@@ -0,0 +1,167 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.math;
+
+import com.google.common.base.Preconditions;
+import org.apache.mahout.common.RandomUtils;
+import org.apache.mahout.math.function.DoubleFunction;
+import org.apache.mahout.math.function.Functions;
+import org.apache.mahout.math.function.IntIntFunction;
+
+import java.util.Random;
+
+public final class Matrices {
+
+  /**
+   * Create a matrix view based on a function generator.
+   * <p>
+   * The generator needs to be idempotent, i.e. returning same value
+   * for each combination of (row, column) argument sent to generator's
+   * {@link IntIntFunction#apply(int, int)} call.
+   *
+   * @param rows      Number of rows in a view
+   * @param columns   Number of columns in a view.
+   * @param gf        view generator
+   * @param denseLike type of matrix returne dby {@link org.apache.mahout.math.Matrix#like()}.
+   * @return new matrix view.
+   */
+  public static Matrix functionalMatrixView(final int rows,
+                                                  final int columns,
+                                                  final IntIntFunction gf,
+                                                  final boolean denseLike) {
+    return new FunctionalMatrixView(rows, columns, gf, denseLike);
+  }
+
+  /**
+   * Shorter form of {@link Matrices#functionalMatrixView(int, int,
+   * org.apache.mahout.math.function.IntIntFunction, boolean)}.
+   */
+  public static Matrix functionalMatrixView(final int rows,
+                                                  final int columns,
+                                                  final IntIntFunction gf) {
+    return new FunctionalMatrixView(rows, columns, gf);
+  }
+
+  /**
+   * A read-only transposed view of a matrix argument.
+   *
+   * @param m original matrix
+   * @return transposed view of original matrix
+   */
+  public static Matrix transposedView(final Matrix m) {
+
+    Preconditions.checkArgument(!(m instanceof SparseColumnMatrix));
+
+    if (m instanceof TransposedMatrixView) {
+      return ((TransposedMatrixView) m).getDelegate();
+    } else {
+      return new TransposedMatrixView(m);
+    }
+  }
+
+  /**
+   * Random Gaussian matrix view.
+   *
+   * @param seed generator seed
+   */
+  public static Matrix gaussianView(final int rows,
+                                          final int columns,
+                                          long seed) {
+    return functionalMatrixView(rows, columns, gaussianGenerator(seed), true);
+  }
+
+
+  /**
+   * Matrix view based on uniform [-1,1) distribution.
+   *
+   * @param seed generator seed
+   */
+  public static Matrix symmetricUniformView(final int rows,
+                                                  final int columns,
+                                                  int seed) {
+    return functionalMatrixView(rows, columns, uniformSymmetricGenerator(seed), true);
+  }
+
+  /**
+   * Matrix view based on uniform [0,1) distribution.
+   *
+   * @param seed generator seed
+   */
+  public static Matrix uniformView(final int rows,
+                                         final int columns,
+                                         int seed) {
+    return functionalMatrixView(rows, columns, uniformGenerator(seed), true);
+  }
+
+  /**
+   * Generator for a matrix populated by random Gauissian values (Gaussian matrix view)
+   *
+   * @param seed The seed for the matrix.
+   * @return Gaussian {@link IntIntFunction} generating matrix view with normal values
+   */
+  public static IntIntFunction gaussianGenerator(final long seed) {
+    final Random rnd = RandomUtils.getRandom(seed);
+    return new IntIntFunction() {
+      @Override
+      public double apply(int first, int second) {
+        rnd.setSeed(seed ^ (((long) first << 32) | (second & 0xffffffffL)));
+        return rnd.nextGaussian();
+      }
+    };
+  }
+
+  private static final double UNIFORM_DIVISOR = Math.pow(2.0, 64);
+
+  /**
+   * Uniform [-1,1) matrix generator function.
+   * <p>
+   * WARNING: to keep things performant, it is stateful and so not thread-safe.
+   * You'd need to create a copy per thread (with same seed) if shared between threads.
+   *
+   * @param seed - random seed initializer
+   * @return Uniform {@link IntIntFunction} generator
+   */
+  public static IntIntFunction uniformSymmetricGenerator(final int seed) {
+    return new IntIntFunction() {
+      private byte[] data = new byte[8];
+
+      @Override
+      public double apply(int row, int column) {
+        long d = ((long) row << Integer.SIZE) | (column & 0xffffffffL);
+        for (int i = 0; i < 8; i++, d >>>= 8) data[i] = (byte) d;
+        long hash = MurmurHash.hash64A(data, seed);
+        return hash / UNIFORM_DIVISOR;
+      }
+    };
+  }
+
+  /**
+   * Uniform [0,1) matrix generator function
+   *
+   * @param seed generator seed
+   */
+  public static IntIntFunction uniformGenerator(final int seed) {
+    return Functions.chain(new DoubleFunction() {
+      @Override
+      public double apply(double x) {
+        return (x + 1.0) / 2.0;
+      }
+    }, uniformSymmetricGenerator(seed));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/Matrix.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/Matrix.java b/core/src/main/java/org/apache/mahout/math/Matrix.java
new file mode 100644
index 0000000..57fab78
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/Matrix.java
@@ -0,0 +1,413 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.math;
+
+import org.apache.mahout.math.flavor.MatrixFlavor;
+import org.apache.mahout.math.function.DoubleDoubleFunction;
+import org.apache.mahout.math.function.DoubleFunction;
+import org.apache.mahout.math.function.VectorFunction;
+
+import java.util.Map;
+
+/** The basic interface including numerous convenience functions */
+public interface Matrix extends Cloneable, VectorIterable {
+
+  /** @return a formatted String suitable for output */
+  String asFormatString();
+
+  /**
+   * Assign the value to all elements of the receiver
+   *
+   * @param value a double value
+   * @return the modified receiver
+   */
+  Matrix assign(double value);
+
+  /**
+   * Assign the values to the receiver
+   *
+   * @param values a double[] of values
+   * @return the modified receiver
+   * @throws CardinalityException if the cardinalities differ
+   */
+  Matrix assign(double[][] values);
+
+  /**
+   * Assign the other vector values to the receiver
+   *
+   * @param other a Matrix
+   * @return the modified receiver
+   * @throws CardinalityException if the cardinalities differ
+   */
+  Matrix assign(Matrix other);
+
+  /**
+   * Apply the function to each element of the receiver
+   *
+   * @param function a DoubleFunction to apply
+   * @return the modified receiver
+   */
+  Matrix assign(DoubleFunction function);
+
+  /**
+   * Apply the function to each element of the receiver and the corresponding element of the other argument
+   *
+   * @param other    a Matrix containing the second arguments to the function
+   * @param function a DoubleDoubleFunction to apply
+   * @return the modified receiver
+   * @throws CardinalityException if the cardinalities differ
+   */
+  Matrix assign(Matrix other, DoubleDoubleFunction function);
+
+  /**
+   * Assign the other vector values to the column of the receiver
+   *
+   * @param column the int row to assign
+   * @param other  a Vector
+   * @return the modified receiver
+   * @throws CardinalityException if the cardinalities differ
+   */
+  Matrix assignColumn(int column, Vector other);
+
+  /**
+   * Assign the other vector values to the row of the receiver
+   *
+   * @param row   the int row to assign
+   * @param other a Vector
+   * @return the modified receiver
+   * @throws CardinalityException if the cardinalities differ
+   */
+  Matrix assignRow(int row, Vector other);
+
+  /**
+   * Collects the results of a function applied to each row of a matrix.
+   * @param f  The function to be applied to each row.
+   * @return  The vector of results.
+   */
+  Vector aggregateRows(VectorFunction f);
+
+  /**
+   * Collects the results of a function applied to each column of a matrix.
+   * @param f  The function to be applied to each column.
+   * @return  The vector of results.
+   */
+  Vector aggregateColumns(VectorFunction f);
+
+  /**
+   * Collects the results of a function applied to each element of a matrix and then
+   * aggregated.
+   * @param combiner  A function that combines the results of the mapper.
+   * @param mapper  A function to apply to each element.
+   * @return  The result.
+   */
+  double aggregate(DoubleDoubleFunction combiner, DoubleFunction mapper);
+
+  /**
+   * @return The number of rows in the matrix.
+   */
+  int columnSize();
+
+  /**
+   * @return Returns the number of rows in the matrix.
+   */
+  int rowSize();
+
+  /**
+   * Return a copy of the recipient
+   *
+   * @return a new Matrix
+   */
+  Matrix clone();
+
+  /**
+   * Returns matrix determinator using Laplace theorem
+   *
+   * @return a matrix determinator
+   */
+  double determinant();
+
+  /**
+   * Return a new matrix containing the values of the recipient divided by the argument
+   *
+   * @param x a double value
+   * @return a new Matrix
+   */
+  Matrix divide(double x);
+
+  /**
+   * Return the value at the given indexes
+   *
+   * @param row    an int row index
+   * @param column an int column index
+   * @return the double at the index
+   * @throws IndexException if the index is out of bounds
+   */
+  double get(int row, int column);
+
+  /**
+   * Return the value at the given indexes, without checking bounds
+   *
+   * @param row    an int row index
+   * @param column an int column index
+   * @return the double at the index
+   */
+  double getQuick(int row, int column);
+
+  /**
+   * Return an empty matrix of the same underlying class as the receiver
+   *
+   * @return a Matrix
+   */
+  Matrix like();
+
+  /**
+   * Returns an empty matrix of the same underlying class as the receiver and of the specified size.
+   *
+   * @param rows    the int number of rows
+   * @param columns the int number of columns
+   */
+  Matrix like(int rows, int columns);
+
+  /**
+   * Return a new matrix containing the element by element difference of the recipient and the argument
+   *
+   * @param x a Matrix
+   * @return a new Matrix
+   * @throws CardinalityException if the cardinalities differ
+   */
+  Matrix minus(Matrix x);
+
+  /**
+   * Return a new matrix containing the sum of each value of the recipient and the argument
+   *
+   * @param x a double
+   * @return a new Matrix
+   */
+  Matrix plus(double x);
+
+  /**
+   * Return a new matrix containing the element by element sum of the recipient and the argument
+   *
+   * @param x a Matrix
+   * @return a new Matrix
+   * @throws CardinalityException if the cardinalities differ
+   */
+  Matrix plus(Matrix x);
+
+  /**
+   * Set the value at the given index
+   *
+   * @param row    an int row index into the receiver
+   * @param column an int column index into the receiver
+   * @param value  a double value to set
+   * @throws IndexException if the index is out of bounds
+   */
+  void set(int row, int column, double value);
+
+  void set(int row, double[] data);
+
+  /**
+   * Set the value at the given index, without checking bounds
+   *
+   * @param row    an int row index into the receiver
+   * @param column an int column index into the receiver
+   * @param value  a double value to set
+   */
+  void setQuick(int row, int column, double value);
+
+  /**
+   * Return the number of values in the recipient
+   *
+   * @return an int[2] containing [row, column] count
+   */
+  int[] getNumNondefaultElements();
+
+  /**
+   * Return a new matrix containing the product of each value of the recipient and the argument
+   *
+   * @param x a double argument
+   * @return a new Matrix
+   */
+  Matrix times(double x);
+
+  /**
+   * Return a new matrix containing the product of the recipient and the argument
+   *
+   * @param x a Matrix argument
+   * @return a new Matrix
+   * @throws CardinalityException if the cardinalities are incompatible
+   */
+  Matrix times(Matrix x);
+
+  /**
+   * Return a new matrix that is the transpose of the receiver
+   *
+   * @return the transpose
+   */
+  Matrix transpose();
+
+  /**
+   * Return the sum of all the elements of the receiver
+   *
+   * @return a double
+   */
+  double zSum();
+
+  /**
+   * Return a map of the current column label bindings of the receiver
+   *
+   * @return a {@code Map<String, Integer>}
+   */
+  Map<String, Integer> getColumnLabelBindings();
+
+  /**
+   * Return a map of the current row label bindings of the receiver
+   *
+   * @return a {@code Map<String, Integer>}
+   */
+  Map<String, Integer> getRowLabelBindings();
+
+  /**
+   * Sets a map of column label bindings in the receiver
+   *
+   * @param bindings a {@code Map<String, Integer>} of label bindings
+   */
+  void setColumnLabelBindings(Map<String, Integer> bindings);
+
+  /**
+   * Sets a map of row label bindings in the receiver
+   *
+   * @param bindings a {@code Map<String, Integer>} of label bindings
+   */
+  void setRowLabelBindings(Map<String, Integer> bindings);
+
+  /**
+   * Return the value at the given labels
+   *
+   * @param rowLabel    a String row label
+   * @param columnLabel a String column label
+   * @return the double at the index
+   * 
+   * @throws IndexException if the index is out of bounds
+   */
+  double get(String rowLabel, String columnLabel);
+
+  /**
+   * Set the value at the given index
+   *
+   * @param rowLabel    a String row label
+   * @param columnLabel a String column label
+   * @param value       a double value to set
+   * @throws IndexException if the index is out of bounds
+   */
+  void set(String rowLabel, String columnLabel, double value);
+
+  /**
+   * Set the value at the given index, updating the row and column label bindings
+   *
+   * @param rowLabel    a String row label
+   * @param columnLabel a String column label
+   * @param row         an int row index
+   * @param column      an int column index
+   * @param value       a double value
+   */
+  void set(String rowLabel, String columnLabel, int row, int column, double value);
+
+  /**
+   * Sets the row values at the given row label
+   *
+   * @param rowLabel a String row label
+   * @param rowData  a double[] array of row data
+   */
+  void set(String rowLabel, double[] rowData);
+
+  /**
+   * Sets the row values at the given row index and updates the row labels
+   *
+   * @param rowLabel the String row label
+   * @param row      an int the row index
+   * @param rowData  a double[] array of row data
+   */
+  void set(String rowLabel, int row, double[] rowData);
+
+  /*
+   * Need stories for these but keeping them here for now.
+   * 
+   */
+  // void getNonZeros(IntArrayList jx, DoubleArrayList values);
+  // void foreachNonZero(IntDoubleFunction f);
+  // double aggregate(DoubleDoubleFunction aggregator, DoubleFunction map);
+  // double aggregate(Matrix other, DoubleDoubleFunction aggregator,
+  // DoubleDoubleFunction map);
+  // NewMatrix assign(Matrix y, DoubleDoubleFunction function, IntArrayList
+  // nonZeroIndexes);
+
+  /**
+   * Return a view into part of a matrix.  Changes to the view will change the
+   * original matrix.
+   *
+   * @param offset an int[2] offset into the receiver
+   * @param size   the int[2] size of the desired result
+   * @return a matrix that shares storage with part of the original matrix.
+   * @throws CardinalityException if the length is greater than the cardinality of the receiver
+   * @throws IndexException       if the offset is negative or the offset+length is outside of the receiver
+   */
+  Matrix viewPart(int[] offset, int[] size);
+
+  /**
+   * Return a view into part of a matrix.  Changes to the view will change the
+   * original matrix.
+   *
+   * @param rowOffset           The first row of the view
+   * @param rowsRequested       The number of rows in the view
+   * @param columnOffset        The first column in the view
+   * @param columnsRequested    The number of columns in the view
+   * @return a matrix that shares storage with part of the original matrix.
+   * @throws CardinalityException if the length is greater than the cardinality of the receiver
+   * @throws IndexException       if the offset is negative or the offset+length is outside of the
+   *                              receiver
+   */
+  Matrix viewPart(int rowOffset, int rowsRequested, int columnOffset, int columnsRequested);
+
+  /**
+   * Return a reference to a row.  Changes to the view will change the original matrix.
+   * @param row  The index of the row to return.
+   * @return A vector that shares storage with the original.
+   */
+  Vector viewRow(int row);
+
+  /**
+   * Return a reference to a column.  Changes to the view will change the original matrix.
+   * @param column  The index of the column to return.
+   * @return A vector that shares storage with the original.
+   */
+  Vector viewColumn(int column);
+
+  /**
+   * Returns a reference to the diagonal of a matrix. Changes to the view will change
+   * the original matrix.
+   * @return A vector that shares storage with the original matrix.
+   */
+  Vector viewDiagonal();
+
+  /**
+   * Get matrix structural flavor (operations performance hints). This is optional operation, may
+   * throw {@link java.lang.UnsupportedOperationException}.
+   */
+  MatrixFlavor getFlavor();
+}

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/MatrixSlice.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/MatrixSlice.java b/core/src/main/java/org/apache/mahout/math/MatrixSlice.java
new file mode 100644
index 0000000..51378c1
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/MatrixSlice.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.math;
+
+public class MatrixSlice extends DelegatingVector {
+  private int index;
+
+  public MatrixSlice(Vector v, int index) {
+    super(v);
+    this.index = index;
+  }
+
+  public Vector vector() {
+    return getVector();
+  }
+
+  public int index() {
+    return index;
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/MatrixTimesOps.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/MatrixTimesOps.java b/core/src/main/java/org/apache/mahout/math/MatrixTimesOps.java
new file mode 100644
index 0000000..30d2afb
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/MatrixTimesOps.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.math;
+
+/**
+ * Optional interface for optimized matrix multiplications.
+ * Some concrete Matrix implementations may mix this in.
+ */
+public interface MatrixTimesOps {
+  /**
+   * computes matrix product of (this * that)
+   */
+  Matrix timesRight(Matrix that);
+
+  /**
+   * Computes matrix product of (that * this)
+   */
+  Matrix timesLeft(Matrix that);
+
+}

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/MatrixVectorView.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/MatrixVectorView.java b/core/src/main/java/org/apache/mahout/math/MatrixVectorView.java
new file mode 100644
index 0000000..6ad44b5
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/MatrixVectorView.java
@@ -0,0 +1,292 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.math;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Provides a virtual vector that is really a row or column or diagonal of a matrix.
+ */
+public class MatrixVectorView extends AbstractVector {
+  private Matrix matrix;
+  private int row;
+  private int column;
+  private int rowStride;
+  private int columnStride;
+  private boolean isDense = true;
+
+  public MatrixVectorView(Matrix matrix, int row, int column, int rowStride, int columnStride, boolean isDense) {
+    this(matrix, row, column, rowStride, columnStride);
+    this.isDense = isDense;
+  }
+
+  public MatrixVectorView(Matrix matrix, int row, int column, int rowStride, int columnStride) {
+    super(viewSize(matrix, row, column, rowStride, columnStride));
+    if (row < 0 || row >= matrix.rowSize()) {
+      throw new IndexException(row, matrix.rowSize());
+    }
+    if (column < 0 || column >= matrix.columnSize()) {
+      throw new IndexException(column, matrix.columnSize());
+    }
+
+    this.matrix = matrix;
+    this.row = row;
+    this.column = column;
+    this.rowStride = rowStride;
+    this.columnStride = columnStride;
+  }
+
+  private static int viewSize(Matrix matrix, int row, int column, int rowStride, int columnStride) {
+    if (rowStride != 0 && columnStride != 0) {
+      int n1 = (matrix.numRows() - row) / rowStride;
+      int n2 = (matrix.numCols() - column) / columnStride;
+      return Math.min(n1, n2);
+    } else if (rowStride > 0) {
+      return (matrix.numRows() - row) / rowStride;
+    } else {
+      return (matrix.numCols() - column) / columnStride;
+    }
+  }
+
+  /**
+   * @return true iff the {@link Vector} implementation should be considered
+   *         dense -- that it explicitly represents every value
+   */
+  @Override
+  public boolean isDense() {
+    return isDense;
+  }
+
+  /**
+   * @return true iff {@link Vector} should be considered to be iterable in
+   *         index order in an efficient way. In particular this implies that {@link #iterator()} and
+   *         {@link #iterateNonZero()} return elements in ascending order by index.
+   */
+  @Override
+  public boolean isSequentialAccess() {
+    return true;
+  }
+
+  /**
+   * Iterates over all elements <p>
+   * NOTE: Implementations may choose to reuse the Element returned
+   * for performance reasons, so if you need a copy of it, you should call {@link #getElement(int)} for
+   * the given index
+   *
+   * @return An {@link java.util.Iterator} over all elements
+   */
+  @Override
+  public Iterator<Element> iterator() {
+    final LocalElement r = new LocalElement(0);
+    return new Iterator<Element>() {
+      private int i;
+
+      @Override
+      public boolean hasNext() {
+        return i < size();
+      }
+
+      @Override
+      public Element next() {
+        if (i >= size()) {
+          throw new NoSuchElementException();
+        }
+        r.index = i++;
+        return r;
+      }
+
+      @Override
+      public void remove() {
+        throw new UnsupportedOperationException("Can't remove from a view");
+      }
+    };
+  }
+
+  /**
+   * Iterates over all non-zero elements. <p>
+   * NOTE: Implementations may choose to reuse the Element
+   * returned for performance reasons, so if you need a copy of it, you should call {@link
+   * #getElement(int)} for the given index
+   *
+   * @return An {@link java.util.Iterator} over all non-zero elements
+   */
+  @Override
+  public Iterator<Element> iterateNonZero() {
+
+    return new Iterator<Element>() {
+      class NonZeroElement implements Element {
+        int index;
+
+        @Override
+        public double get() {
+          return getQuick(index);
+        }
+
+        @Override
+        public int index() {
+          return index;
+        }
+
+        @Override
+        public void set(double value) {
+          invalidateCachedLength();
+          setQuick(index, value);
+        }
+      }
+
+      private final NonZeroElement element = new NonZeroElement();
+      private int index = -1;
+      private int lookAheadIndex = -1;
+
+      @Override
+      public boolean hasNext() {
+        if (lookAheadIndex == index) {  // User calls hasNext() after a next()
+          lookAhead();
+        } // else user called hasNext() repeatedly.
+        return lookAheadIndex < size();
+      }
+
+      private void lookAhead() {
+        lookAheadIndex++;
+        while (lookAheadIndex < size() && getQuick(lookAheadIndex) == 0.0) {
+          lookAheadIndex++;
+        }
+      }
+
+      @Override
+      public Element next() {
+        if (lookAheadIndex == index) { // If user called next() without checking hasNext().
+          lookAhead();
+        }
+
+        index = lookAheadIndex;
+
+        if (index >= size()) { // If the end is reached.
+          throw new NoSuchElementException();
+        }
+
+        element.index = index;
+        return element;
+      }
+
+      @Override
+      public void remove() {
+        throw new UnsupportedOperationException();
+      }
+    };
+  }
+
+  /**
+   * Return the value at the given index, without checking bounds
+   *
+   * @param index an int index
+   * @return the double at the index
+   */
+  @Override
+  public double getQuick(int index) {
+    return matrix.getQuick(row + rowStride * index, column + columnStride * index);
+  }
+
+  /**
+   * Return an empty vector of the same underlying class as the receiver
+   *
+   * @return a Vector
+   */
+  @Override
+  public Vector like() {
+    return matrix.like(size(), 1).viewColumn(0);
+  }
+
+  @Override
+  public Vector like(int cardinality) {
+    return matrix.like(cardinality, 1).viewColumn(0);
+  }
+
+  /**
+   * Set the value at the given index, without checking bounds
+   *
+   * @param index an int index into the receiver
+   * @param value a double value to set
+   */
+  @Override
+  public void setQuick(int index, double value) {
+    matrix.setQuick(row + rowStride * index, column + columnStride * index, value);
+  }
+
+  /**
+   * Return the number of values in the recipient
+   *
+   * @return an int
+   */
+  @Override
+  public int getNumNondefaultElements() {
+    return size();
+  }
+
+  @Override
+  public double getLookupCost() {
+    // TODO: what is a genuine value here?
+    return 1;
+  }
+
+  @Override
+  public double getIteratorAdvanceCost() {
+    // TODO: what is a genuine value here?
+    return 1;
+  }
+
+  @Override
+  public boolean isAddConstantTime() {
+    // TODO: what is a genuine value here?
+    return true;
+  }
+
+  @Override
+  protected Matrix matrixLike(int rows, int columns) {
+    return matrix.like(rows, columns);
+  }
+
+  @Override
+  public Vector clone() {
+    MatrixVectorView r = (MatrixVectorView) super.clone();
+    r.matrix = matrix.clone();
+    r.row = row;
+    r.column = column;
+    r.rowStride = rowStride;
+    r.columnStride = columnStride;
+    return r;
+  }
+
+  /**
+   * Used internally by assign() to update multiple indices and values at once.
+   * Only really useful for sparse vectors (especially SequentialAccessSparseVector).
+   * <p>
+   * If someone ever adds a new type of sparse vectors, this method must merge (index, value) pairs into the vector.
+   *
+   * @param updates a mapping of indices to values to merge in the vector.
+   */
+  @Override
+  public void mergeUpdates(OrderedIntDoubleMapping updates) {
+    int[] indices = updates.getIndices();
+    double[] values = updates.getValues();
+    for (int i = 0; i < updates.getNumMappings(); ++i) {
+      matrix.setQuick(row + rowStride * indices[i], column + columnStride * indices[i], values[i]);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/MatrixView.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/MatrixView.java b/core/src/main/java/org/apache/mahout/math/MatrixView.java
new file mode 100644
index 0000000..951515b
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/MatrixView.java
@@ -0,0 +1,160 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.math;
+
+import org.apache.mahout.math.flavor.MatrixFlavor;
+
+/** Implements subset view of a Matrix */
+public class MatrixView extends AbstractMatrix {
+
+  private Matrix matrix;
+
+  // the offset into the Matrix
+  private int[] offset;
+
+  /**
+   * Construct a view of the matrix with given offset and cardinality
+   *
+   * @param matrix      an underlying Matrix
+   * @param offset      the int[2] offset into the underlying matrix
+   * @param size        the int[2] size of the view
+   */
+  public MatrixView(Matrix matrix, int[] offset, int[] size) {
+    super(size[ROW], size[COL]);
+    int rowOffset = offset[ROW];
+    if (rowOffset < 0) {
+      throw new IndexException(rowOffset, rowSize());
+    }
+
+    int rowsRequested = size[ROW];
+    if (rowOffset + rowsRequested > matrix.rowSize()) {
+      throw new IndexException(rowOffset + rowsRequested, matrix.rowSize());
+    }
+
+    int columnOffset = offset[COL];
+    if (columnOffset < 0) {
+      throw new IndexException(columnOffset, columnSize());
+    }
+
+    int columnsRequested = size[COL];
+    if (columnOffset + columnsRequested > matrix.columnSize()) {
+      throw new IndexException(columnOffset + columnsRequested, matrix.columnSize());
+    }
+    this.matrix = matrix;
+    this.offset = offset;
+  }
+
+  @Override
+  public Matrix clone() {
+    MatrixView clone = (MatrixView) super.clone();
+    clone.matrix = matrix.clone();
+    clone.offset = offset.clone();
+    return clone;
+  }
+
+  @Override
+  public double getQuick(int row, int column) {
+    return matrix.getQuick(offset[ROW] + row, offset[COL] + column);
+  }
+
+  @Override
+  public Matrix like() {
+    return matrix.like(rowSize(), columnSize());
+  }
+
+  @Override
+  public Matrix like(int rows, int columns) {
+    return matrix.like(rows, columns);
+  }
+
+  @Override
+  public void setQuick(int row, int column, double value) {
+    matrix.setQuick(offset[ROW] + row, offset[COL] + column, value);
+  }
+
+  @Override
+  public int[] getNumNondefaultElements() {
+    return new int[]{rowSize(), columnSize()};
+
+  }
+
+  @Override
+  public Matrix viewPart(int[] offset, int[] size) {
+    if (offset[ROW] < 0) {
+      throw new IndexException(offset[ROW], 0);
+    }
+    if (offset[ROW] + size[ROW] > rowSize()) {
+      throw new IndexException(offset[ROW] + size[ROW], rowSize());
+    }
+    if (offset[COL] < 0) {
+      throw new IndexException(offset[COL], 0);
+    }
+    if (offset[COL] + size[COL] > columnSize()) {
+      throw new IndexException(offset[COL] + size[COL], columnSize());
+    }
+    int[] origin = this.offset.clone();
+    origin[ROW] += offset[ROW];
+    origin[COL] += offset[COL];
+    return new MatrixView(matrix, origin, size);
+  }
+
+  @Override
+  public Matrix assignColumn(int column, Vector other) {
+    if (rowSize() != other.size()) {
+      throw new CardinalityException(rowSize(), other.size());
+    }
+    for (int row = 0; row < rowSize(); row++) {
+      matrix.setQuick(row + offset[ROW], column + offset[COL], other
+          .getQuick(row));
+    }
+    return this;
+  }
+
+  @Override
+  public Matrix assignRow(int row, Vector other) {
+    if (columnSize() != other.size()) {
+      throw new CardinalityException(columnSize(), other.size());
+    }
+    for (int col = 0; col < columnSize(); col++) {
+      matrix
+          .setQuick(row + offset[ROW], col + offset[COL], other.getQuick(col));
+    }
+    return this;
+  }
+
+  @Override
+  public Vector viewColumn(int column) {
+    if (column < 0 || column >= columnSize()) {
+      throw new IndexException(column, columnSize());
+    }
+    return matrix.viewColumn(column + offset[COL]).viewPart(offset[ROW], rowSize());
+  }
+
+  @Override
+  public Vector viewRow(int row) {
+    if (row < 0 || row >= rowSize()) {
+      throw new IndexException(row, rowSize());
+    }
+    return matrix.viewRow(row + offset[ROW]).viewPart(offset[COL], columnSize());
+  }
+
+  @Override
+  public MatrixFlavor getFlavor() {
+    return matrix.getFlavor();
+  }
+}

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/MurmurHash.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/MurmurHash.java b/core/src/main/java/org/apache/mahout/math/MurmurHash.java
new file mode 100644
index 0000000..13f3a07
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/MurmurHash.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.math;
+
+import com.google.common.primitives.Ints;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * <p>This is a very fast, non-cryptographic hash suitable for general hash-based
+ * lookup.  See http://murmurhash.googlepages.com/ for more details.
+ * </p>
+ * <p>The C version of MurmurHash 2.0 found at that site was ported
+ * to Java by Andrzej Bialecki (ab at getopt org).</p>
+ */
+public final class MurmurHash {
+
+  private MurmurHash() {}
+
+  /**
+   * Hashes an int.
+   * @param data The int to hash.
+   * @param seed The seed for the hash.
+   * @return The 32 bit hash of the bytes in question.
+   */
+  public static int hash(int data, int seed) {
+    return hash(ByteBuffer.wrap(Ints.toByteArray(data)), seed);
+  }
+
+  /**
+   * Hashes bytes in an array.
+   * @param data The bytes to hash.
+   * @param seed The seed for the hash.
+   * @return The 32 bit hash of the bytes in question.
+   */
+  public static int hash(byte[] data, int seed) {
+    return hash(ByteBuffer.wrap(data), seed);
+  }
+
+  /**
+   * Hashes bytes in part of an array.
+   * @param data    The data to hash.
+   * @param offset  Where to start munging.
+   * @param length  How many bytes to process.
+   * @param seed    The seed to start with.
+   * @return        The 32-bit hash of the data in question.
+   */
+  public static int hash(byte[] data, int offset, int length, int seed) {
+    return hash(ByteBuffer.wrap(data, offset, length), seed);
+  }
+
+  /**
+   * Hashes the bytes in a buffer from the current position to the limit.
+   * @param buf    The bytes to hash.
+   * @param seed   The seed for the hash.
+   * @return       The 32 bit murmur hash of the bytes in the buffer.
+   */
+  public static int hash(ByteBuffer buf, int seed) {
+    // save byte order for later restoration
+    ByteOrder byteOrder = buf.order();
+    buf.order(ByteOrder.LITTLE_ENDIAN);
+
+    int m = 0x5bd1e995;
+    int r = 24;
+
+    int h = seed ^ buf.remaining();
+
+    while (buf.remaining() >= 4) {
+      int k = buf.getInt();
+
+      k *= m;
+      k ^= k >>> r;
+      k *= m;
+
+      h *= m;
+      h ^= k;
+    }
+
+    if (buf.remaining() > 0) {
+      ByteBuffer finish = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
+      // for big-endian version, use this first:
+      // finish.position(4-buf.remaining());
+      finish.put(buf).rewind();
+      h ^= finish.getInt();
+      h *= m;
+    }
+
+    h ^= h >>> 13;
+    h *= m;
+    h ^= h >>> 15;
+
+    buf.order(byteOrder);
+    return h;
+  }
+
+
+  public static long hash64A(byte[] data, int seed) {
+    return hash64A(ByteBuffer.wrap(data), seed);
+  }
+
+  public static long hash64A(byte[] data, int offset, int length, int seed) {
+    return hash64A(ByteBuffer.wrap(data, offset, length), seed);
+  }
+
+  public static long hash64A(ByteBuffer buf, int seed) {
+    ByteOrder byteOrder = buf.order();
+    buf.order(ByteOrder.LITTLE_ENDIAN);
+
+    long m = 0xc6a4a7935bd1e995L;
+    int r = 47;
+
+    long h = seed ^ (buf.remaining() * m);
+
+    while (buf.remaining() >= 8) {
+      long k = buf.getLong();
+
+      k *= m;
+      k ^= k >>> r;
+      k *= m;
+
+      h ^= k;
+      h *= m;
+    }
+
+    if (buf.remaining() > 0) {
+      ByteBuffer finish = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);
+      // for big-endian version, do this first:
+      // finish.position(8-buf.remaining());
+      finish.put(buf).rewind();
+      h ^= finish.getLong();
+      h *= m;
+    }
+
+    h ^= h >>> r;
+    h *= m;
+    h ^= h >>> r;
+
+    buf.order(byteOrder);
+    return h;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/mahout/blob/545648f6/core/src/main/java/org/apache/mahout/math/MurmurHash3.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/mahout/math/MurmurHash3.java b/core/src/main/java/org/apache/mahout/math/MurmurHash3.java
new file mode 100644
index 0000000..bd0bb6b
--- /dev/null
+++ b/core/src/main/java/org/apache/mahout/math/MurmurHash3.java
@@ -0,0 +1,84 @@
+/*
+ *  This code is public domain.
+ *
+ *  The MurmurHash3 algorithm was created by Austin Appleby and put into the public domain.
+ *  See http://code.google.com/p/smhasher/
+ *
+ *  This java port was authored by
+ *  Yonik Seeley and was placed into the public domain per
+ *  https://github.com/yonik/java_util/blob/master/src/util/hash/MurmurHash3.java.
+ */
+
+package org.apache.mahout.math;
+
+/**
+ *  <p>
+ *  This produces exactly the same hash values as the final C+
+ + *  version of MurmurHash3 and is thus suitable for producing the same hash values across
+ *  platforms.
+ *  <p>
+ *  The 32 bit x86 version of this hash should be the fastest variant for relatively short keys like ids.
+ *  <p>
+ *  Note - The x86 and x64 versions do _not_ produce the same results, as the
+ *  algorithms are optimized for their respective platforms.
+ *  <p>
+ *  See also http://github.com/yonik/java_util for future updates to this file.
+ */
+public final class MurmurHash3 {
+
+  private MurmurHash3() {}
+
+  /** Returns the MurmurHash3_x86_32 hash. */
+  public static int murmurhash3x8632(byte[] data, int offset, int len, int seed) {
+
+    int c1 = 0xcc9e2d51;
+    int c2 = 0x1b873593;
+
+    int h1 = seed;
+    int roundedEnd = offset + (len & 0xfffffffc);  // round down to 4 byte block
+
+    for (int i = offset; i < roundedEnd; i += 4) {
+      // little endian load order
+      int k1 = (data[i] & 0xff) | ((data[i + 1] & 0xff) << 8) | ((data[i + 2] & 0xff) << 16) | (data[i + 3] << 24);
+      k1 *= c1;
+      k1 = (k1 << 15) | (k1 >>> 17);  // ROTL32(k1,15);
+      k1 *= c2;
+
+      h1 ^= k1;
+      h1 = (h1 << 13) | (h1 >>> 19);  // ROTL32(h1,13);
+      h1 = h1 * 5 + 0xe6546b64;
+    }
+
+    // tail
+    int k1 = 0;
+
+    switch(len & 0x03) {
+      case 3:
+        k1 = (data[roundedEnd + 2] & 0xff) << 16;
+        // fallthrough
+      case 2:
+        k1 |= (data[roundedEnd + 1] & 0xff) << 8;
+        // fallthrough
+      case 1:
+        k1 |= data[roundedEnd] & 0xff;
+        k1 *= c1;
+        k1 = (k1 << 15) | (k1 >>> 17);  // ROTL32(k1,15);
+        k1 *= c2;
+        h1 ^= k1;
+      default:
+    }
+
+    // finalization
+    h1 ^= len;
+
+    // fmix(h1);
+    h1 ^= h1 >>> 16;
+    h1 *= 0x85ebca6b;
+    h1 ^= h1 >>> 13;
+    h1 *= 0xc2b2ae35;
+    h1 ^= h1 >>> 16;
+
+    return h1;
+  }
+
+}