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 [45/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/package.html
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/package.html?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/package.html (added)
+++ lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/package.html Thu Dec 17 23:22:16 2009
@@ -0,0 +1,789 @@
+<HTML>
+<BODY>
+Matrix <i>interfaces and factories</i>; efficient and flexible dense and sparse
+1, 2, 3 and d-dimensional matrices holding objects or primitive data types such
+as <tt>int</tt>, <tt>double</tt>, etc; Templated, fixed sized (not dynamically
+resizable); Also known as <i>multi-dimensional arrays</i> or<i> Data Cubes</i>.
+Note that d-dimensional and <tt>int</tt> based matrices are not yet provided.
+<p></p>
+
+<h1><a name="Overview"></a>Getting Started</h1>
+<ol>
+ <li><a href="#Overview">Overview</a></li>
+ <li><a href="#Introduction">Introduction</a></li>
+ <li><a href="#SemanticsOfViews">Semantics of Views</a></li>
+ <li><a href="#FunctionObjects">Functional Programming with Objects</a></li>
+ <li><a href="#Algorithms">Algorithms</a></li>
+ <li><a href="#LinearAlgebra">Linear Algebra</a></li>
+ <li><a href="#Orthogonality">Orthogonality and Polymorphism</a></li>
+ <li><a href="#PackageOrganization">Package Organization, Naming Conventions,
+ Policies</a></li>
+ <li><a href="#Performance">Performance</a></li>
+ <li><a href="#Notes">Notes</a></li>
+</ol>
+<h2></h2>
+
+<h2>1. Overview</h2>
+
+<p>The matrix package offers flexible object oriented abstractions modelling multi-dimensional
+ arrays, resembling the way they can be manipulated in Fortran. It is designed
+ to be scalable, not only in terms of performance and memory requirements, but
+ also in terms of the number of operations that make sense on such data structures.
+ Features include</p>
+<table width="75%" border="0" bgcolor="#EEEEEE">
+<tr valign="top" align="left">
+ <td>
+ <table border="0" cellpadding="0" cellspacing="0" width="358">
+ <tr>
+ <td colspan="2" bgcolor="#770000">
+ <p align="CENTER"><font color="#FFFFFF"><b>Multi-dimensional Array
+ Types</b></font>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td align="LEFT" width="180">
+ <ul>
+ <li>dense
+ <li>sparse hashed
+ <li>sparse row compressed
+ </ul>
+ </td>
+ <td align="LEFT" width="180">
+ <ul>
+ <li>1-d, 2-d, 3-d
+ </ul>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td>
+ <table border="0" cellpadding="0" cellspacing="0" width="358">
+ <tr>
+ <td colspan="2" bgcolor="#770000">
+ <p align="CENTER"><font color="#FFFFFF"><b>Matrix Operations</b></font>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td align="LEFT" width="180">
+ <ul>
+ <li>matrix-matrix multiply
+ <li>matrix-vector multiply
+ <li>inner, outer products
+ <li>tranposition
+ </ul>
+ </td>
+ <td align="LEFT" width="180">
+ <ul>
+ <li>equation solving
+ <li>permutation (pivoting)
+ <li>integer powers
+ <li>norms
+ <li>trace
+ </ul>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+<tr valign="top" align="left">
+ <td>
+ <table border="0" cellpadding="0" cellspacing="0" width="358">
+ <tr>
+ <td colspan="2" bgcolor="#770000">
+ <p align="CENTER"><font color="#FFFFFF"><b>Array Views (by Reference)</b></font>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td align="LEFT" width="180">
+ <ul>
+ <li>sub-range
+ <li>slice
+ <li>dice
+ <li>flip
+ <li>stride
+ </ul>
+ </td>
+ <td align="LEFT" width="180">
+ <ul>
+ <li>selection
+ <li>sort
+ </ul>
+ <ul>
+ <li>assigment
+ <li>copying
+ </ul>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td>
+ <table border="0" cellpadding="0" cellspacing="0" width="358">
+ <tr>
+ <td valign="MIDDLE" colspan="2" bgcolor="#770000">
+ <p align="CENTER"><font color="#FFFFFF"><b>Matrix Factorizations and
+ Decompositions</b></font>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td width="180" align="LEFT">
+ <ul>
+ <li>LU
+ <li>QR
+ <li>Cholesky
+ <li>eigenvectors and eigenvalues
+ <li>singular value (SVD)
+ </ul>
+ </td>
+ <td align="LEFT" width="180">
+ <ul>
+ <li> inverse
+ <li>pseudoinverse
+ <li>condition
+ <li>determinant
+ <li>rank
+ </ul>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+<tr valign="top" align="left">
+ <td>
+ <table border="0" cellpadding="0" cellspacing="0" width="358">
+ <tr>
+ <td colspan="2" bgcolor="#770000">
+ <p align="CENTER"><font color="#FFFFFF"><b>Elementwise Array Operations</b></font>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td align="LEFT" width="180">
+ <ul>
+ <li>addition
+ <li>subtraction
+ <li>multiplication
+ <li>division
+ <li>power
+ <li>square root
+ <li>logarithm
+ <li>exponential
+ <li>absolute value
+ <li>trigonometric functions
+ </ul>
+ </td>
+ <td align="LEFT" width="180">
+ <ul>
+ <li> assignment
+ <li>functional programming via user-defined functions (for transformations,
+ aggregations, selections, sorting)
+ <li>comparison
+ </ul>
+ </td>
+ </tr>
+ </table>
+ <p> </p>
+ </td>
+ <td>
+ <table border="0" cellpadding="0" cellspacing="0" width="358" height="55">
+ <tr>
+ <td valign="MIDDLE" colspan="2" bgcolor="#770000">
+ <p align="CENTER"><font color="#FFFFFF"><b>Columnwise Data Analysis</b></font>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td width="180" align="LEFT">
+ <ul>
+ <li>covariance, correlation matrix
+ <li>maximum
+ <li>minimum
+ <li>mean
+ <li>variance, standard deviation
+ <li>median
+ <li>exact and approximate quantiles
+ </ul>
+ </td>
+ <td align="LEFT" width="180">
+ <ul>
+ <li>(cumulative) sum
+ <li>(cumulative) product
+ <li>harmonic, geometric mean
+ <li>skew, kurtosis
+ <li>moments
+ <li>frequencies
+ <li>sorting
+ </ul>
+ </td>
+ </tr>
+ </table>
+ </td>
+</tr>
+<tr valign="top" align="left">
+ <td>
+ <table border="0" cellpadding="0" cellspacing="0" width="358">
+ <tr>
+ <td colspan="2" bgcolor="#770000">
+ <p align="CENTER"><font color="#FFFFFF"><b>Array and Matrix Utilities</b></font>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td align="LEFT" width="180">
+ <ul>
+ <li> dense and sparse creation
+ <li>string formatting
+ <li>up-down or left-right concatenation
+ <li>create, extract block matrix
+ </ul>
+ </td>
+ <td align="LEFT" width="180">
+ <ul>
+ <li>create, extract diagonals
+ <li>extract upper, lower triangular parts
+ <li>random matrix, array
+ </ul>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td>
+ <p> </p>
+ </td>
+</tr>
+</table>
+<p>File-based I/O can be achieved through the standard Java-built-in serialization
+ mechanism. All classes implement the {@link java.io.Serializable} interface.
+ However, the toolkit is entirely decoupled from advanced I/O and visualisation
+ techniques. It provides data structures and algorithms only. </p>
+
+<p> This toolkit borrows many fundamental concepts and terminology from the IBM
+ <a href="http://math.nist.gov/javanumerics/array/"> Array</a> package written
+ by Jose Moreira, Marc Snir and Sam Midkiff. They introduced well designed multi-dimensional
+ arrays to the Java world.
+
+<p><a href="#Overview">Back</a> to Overview
+
+<h2><a name="Introduction"></a>2. Introduction</h2>
+
+<p>Multi-dimensional arrays are arguably <i>the</i> most frequently used abstraction
+ in scientific and technical codes. They support a broad variety of applications
+ in the domain of Physics, Linear Algebra, Computational Fluid Dynamics, Relational
+ Algebra, Statistics, Graphics Rendering and others. For example many physics
+ problems can be mapped to matrix problems: Linear and nonlinear systems of equations,
+ linear differential equations, quantum mechanical eigenvalue problems, Tensors,
+ etc. Physics<i> NTuples</i> are essentially 2-d arrays. In the area of Online
+ Analytic Processing <i>(OLAP</i>) multi-dimensional arrays are called <i>Data
+ Cubes</i>. In this toolkit they are called <i>Matrices</i>, simply because the
+ term <i>Array</i> is already heavily overloaded and <i>Data Cube</i> is somewhat
+ fuzzy to many people.</p>
+
+<h2></h2>
+
+<p>Matrices are basically rectangular grids with each cell in the grid containing
+ a single value. Cells are accessed via zero-based integer indexes. Matrices
+ can be characterized by</p>
+<ul>
+ <li><i>Rank</i>: The number of dimensions (axes). Most frequently used are one and
+ two dimensions.
+ </li>
+ <li><i>Shape:</i> Each dimension has a certain number of slots. All slots together
+ make up the shape. For example, a 2-dimensional 10 x 50 matrix has 10 slots
+ along its first dimension, and 50 slots along its second dimension, yielding
+ 500 cells.
+ </li>
+ <li><i>Value type</i>: The type of value to be stored in each cell. Can be integer,
+ floating point or an arbitrary object.
+ </li>
+</ul>
+<p>Here is an example of a <tt>8x8x8</tt> matrix and other matrices.
+
+<p><img src="doc-files/slice.gif" width="644" height="401">
+
+<p>As broad as the spectrum of applications using multi-dimensional matrices is
+ the number of operations meaningful on them. Only a smallish subset of those
+ operations are provided in this library. We hope that this will change over
+ time. However, core multi-purpose functionality such as <i>subrange</i>, <i>slice</i>,
+ <i>dice</i>, <i>flip</i>, <i>stride</i>, <i>selection</i> and<i> sort</i> views
+ as well as <i>copying</i> and <i>numerical transformations</i> (*,/,+,-,...)
+ are efficiently provided. The primary motivation for views is ease-of-use. Views
+ allow to express otherwise complex aggregate operations in simple terms. They
+ seek to present a matrix in different ways to a user and/or functions operating
+ on a matrix. Subranging, slicing, dicing, flipping, striding, selecting and
+ sorting are virtual transformations: they merely alter the way we see the <i>same
+ data</i>. They produce <i>views</i>, which are objects that know only about
+ certain regions of the entire matrix. Views all point to the same data, so changes
+ in the view are reflected in the original matrix, all other possibly nested
+ views of the original matrix, and vice-versa. Pete and Jane can look at a flower
+ in many different ways although it remains one single flower. If Pete steps
+ on top of the flower, Jane will certainly note. Which is not the case when copying
+ is applied, since it is a materializing transformation. It means, the connection
+ between the original and the copy is lost. If Pete is stepping on top of a rose
+ and Jane is admiring another one, it won't have any impact on her. Views can
+ arbitrarily be nested. They eliminate the need for explicit region operations.
+ Any operation on a matrix can be used as a region restricted operation by operating
+ on a matrix view instead of the whole matrix. Here are some examples:
+
+<p>
+<table border="0">
+<tr>
+ <td>Lets construct a dense 3 x 4 matrix</td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td>
+ <p><tt>DoubleMatrix2D matrix;<br>
+ matrix </tt><tt>= new DenseDoubleMatrix2D(3,4);<br>
+ </tt><tt>//matrix </tt><tt>= new SparseDoubleMatrix2D(3,4);</tt><tt> </tt><tt>//
+ has same interface<br>
+ </tt><tt>//matrix </tt><tt>= new RCDoubleMatrix2D(3,4);</tt><tt> </tt><tt>
+ // has same interface<br>
+ </tt><tt></tt><tt>log.info(matrix); </tt></p>
+ </td>
+ <td nowrap><tt>3 x 4 matrix: <br>
+ 0 0 0 0 <br>
+ 0 0 0 0 <br>
+ 0 0 0 0 </tt></td>
+</tr>
+<tr>
+ <td> We can get rid of the typed distinction between sparse and dense matrices.
+ Use a factory, as follows
+ </td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td>
+ <p><tt>DoubleFactory2D factory;<br>
+ if (wantDense) factory = DoubleFactory2D.dense;<br>
+ else if (wantSparseHashed) factory = DoubleFactory2D.sparse;<br>
+ else factory = DoubleFactory2D.rowCompressed;<br>
+ <br>
+ // From now on all instantiations will go via the factory -<br>
+ // No explicit constructor calls anymore</tt><tt><br>
+ DoubleMatrix2D matrix = factory.make(3,4);<br>
+ log.info(matrix);</tt></p>
+ </td>
+ <td nowrap><tt>3 x 4 matrix: <br>
+ 0 0 0 0 <br>
+ 0 0 0 0 <br>
+ 0 0 0 0 </tt></td>
+</tr>
+<tr>
+ <td>The shape can be retrieved with <br>
+ <tt>int rows = matrix.rows(); <br>
+ int columns = matrix.columns();</tt></td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td>We set and get a cell value:</td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td>
+ <p><tt>int row = 2, column = 0;<br>
+ </tt><tt>matrix.set(row,column, 7);<br>
+ log.info(matrix.get(row,column));<br>
+ // --> 7</tt></p>
+ </td>
+ <td nowrap><tt>3 x 4 matrix <br>
+ 0 0 0 0 <br>
+ 0 0 0 0 <br>
+ 7 0 0 0 </tt></td>
+</tr>
+<tr>
+ <td>Looping is done as expected:</td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td><tt>
+ <pre>
+double sum = 0;
+for (int row=rows; --row >= 0; ) {
+ for (int column=columns; --column >= 0; ) {
+ sum += matrix.get(row,column); // bounds check
+ //sum += matrix.getQuick(row,column); // no bounds check
+ }
+}
+log.info(sum);
+</pre>
+ </tt></td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td>The following idiom uses a subranging view to set all cells of the box
+ <br>
+ starting at <tt>[1,0]</tt> with width and height of 2 to the value <tt>1</tt>:
+ </td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td><tt>matrix.viewPart(1,0,2,2).assign(1);<br>
+ log.info(matrix); <br>
+ </tt></td>
+ <td nowrap><tt>3 x 4 matrix <br>
+ 0 0 0 0 <br>
+ 1 1 0 0 <br>
+ 1 1 0 0 </tt></td>
+</tr>
+<tr>
+ <td>
+ <p>A dicing view can be used to print the matrix in a different format (4
+ x 3). This is equivalent to a zero-copy transposition:</p>
+ </td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td><tt>log.info(matrix.viewDice())</tt></td>
+ <td nowrap><tt>4 x 3 matrix <br>
+ 0 1 1 <br>
+ 0 1 1 <br>
+ 0 0 0 <br>
+ 0 0 0 </tt></td>
+</tr>
+<tr>
+ <td>
+ <p>Next, a flipping view mirrors the matrix. </p>
+ </td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td><tt>log.info(matrix.viewColumnFlip());</tt></td>
+ <td nowrap><tt>3 x 4 matrix <br>
+ 0 0 0 0 <br>
+ 0 0 1 1 <br>
+ 0 0 1 1 </tt></td>
+</tr>
+<tr>
+ <td>
+ <p>A slicing view shows the second row, a 1-dimensional matrix:</p>
+ </td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td><tt>log.info(matrix.viewRow(1)); </tt></td>
+ <td nowrap><tt>4 matrix <br>
+ 1 1 0 0 </tt></td>
+</tr>
+<tr>
+ <td>
+ <p>Note that the result of a slicing operation is not a 2-d matrix with
+ one row, but a true 1-d <b>type</b> with all capabilities of the type,
+ namely {@link org.apache.mahout.math.matrix.DoubleMatrix1D}, generated in constant
+ time.</p>
+
+ <p>The slicing view is now fed into some external algorithm expecting a
+ 1-dimensional matrix:<br>
+ <tt>someAlgorithm(matrix.viewRow(1));</tt></p>
+ </td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td>If the algorithm is designed such that it modifies data of the row, <br>
+ but we want to avoid any side-effects, we can feed it a copy of the row:
+ <tt><br>
+ someAlgorithm(matrix.viewRow(1).copy());</tt></td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td>A stride view shows every row and every second column. It is useful for
+ scatter/gather operations.
+ </td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td><tt>log.info(matrix.viewStrides(1,2)); </tt></td>
+ <td nowrap><tt>3 x 2 matrix <br>
+ 0 0<br>
+ 1 0<br>
+ 1 0</tt></td>
+</tr>
+<tr>
+ <td>A selection view shows explicitly specified rows and columns. Imagine
+ a 2-d matrix. Columns are attributes <i>energy</i>, <i>tracks</i>, <i>momentum</i>,
+ the rows hold <tt>N</tt> such measurements, as recorded by some device.
+ We want to operate on some subset of the columns and exclude some measurements
+ not of interest for our analysis.
+ </td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td><tt>int[] rowIndexes = {0,2};<br>
+ int[] columnIndexes = {2,3,1,1};<br>
+ log.info(matrix.viewSelection(rowIndexes,columnIndexes)); </tt></td>
+ <td nowrap><tt>2 x 4 matrix <br>
+ 0 0 0 0 <br>
+ 0 0 1 1 </tt></td>
+</tr>
+<tr>
+ <td>A sort view with row flipping shows rows sorted descending by column 1:</td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td><tt>log.info(matrix.viewSorted(1).viewRowFlip()); </tt></td>
+ <td nowrap><tt>3 x 4 matrix <br>
+ 1 1 0 0 <br>
+ 1 1 0 0 <br>
+ 0 0 0 0 </tt></td>
+</tr>
+<tr>
+ <td>Last, lets combine some of the methods to stimulate imagination:</td>
+ <td nowrap> </td>
+</tr>
+<tr>
+ <td><tt>matrix.viewPart(0,1,2,2).viewRowFlip().viewColumn(0).assign(2);<br>
+ log.info(matrix); <br>
+ </tt></td>
+ <td nowrap><tt>3 x 4 matrix <br>
+ 0 2 0 0 <br>
+ 1 2 0 0 <br>
+ 1 1 0 0 </tt></td>
+</tr>
+</table>
+<p><a href="#Overview">Back</a> to Overview
+
+<h2></h2>
+
+<h2><a name="SemanticsOfViews"></a>3. Semantics of Views </h2>
+
+<p>Find out more about the <a href="doc-files/semanticsOfViews.html">precise semantics</a>
+ of views and basic operations.</p>
+
+<p><a href="#Overview">Back</a> to Overview
+
+<h2></h2>
+
+<h2><a name="Orthogonality"></a>4. Orthogonality and Polymorphism</h2>
+
+<p>If this section sounds trivial and obvious, you can safely skip it.<br>
+ The desire for orthogonality is a desire for "plug and play". Orthogonality
+ demands that everything can be plugged together with everything, or, in other
+ words, that different things can be handled in the same way. Of course only
+ things that syntactically and semantically share a common set of interfaces
+ can be handled in the same way, or work together in the same way. Polymorphism
+ is an implementation mechanism supporting orthogonality. It is about being able
+ to exchange things without noticing any difference. Again, as long as the things
+ adhere to some common interface.</p>
+
+<p>The common interface for matrices is defined in abstract base classes (e.g.
+ {@link org.apache.mahout.math.matrix.DoubleMatrix2D}). Note that looking at the documentation
+ of some concrete instantiable class (e.g. {@link org.apache.mahout.math.matrix.impl.DenseDoubleMatrix2D},
+ {@link org.apache.mahout.math.matrix.impl.SparseDoubleMatrix2D}, {@link
+ impl.RCDoubleMatrix2D}<img
+ src="../doc-files/new.gif" width="32" height="22" align="top">)
+ will not reveal more information than can be obtained by looking at the abstract
+ base classes. The convention is that concrete classes <i>do no subsetting or
+ supersetting</i>. They override methods to implement behaviour dictated by abstract
+ classes, or to improve performance, but they do not introduce any new functionality.
+</p>
+
+<p>Although each matrix of a given rank and value type comes with dense and sparse
+ implementations and a multitude of views, there is from the user interface perspective
+ no difference between them. All implementations have exactly the same interface
+ with exactly the same semantics attached. In particular, everything that "can
+ be done" with a dense matrix can also be done with a sparse specie, and
+ vice-versa. The same principle applies to views. </p>
+
+<p><i>This implies that any internal or external function expecting as argument
+ an abstract matrix (and any operation defined on an abstract matrix) can be
+ used with any kind of matrix of the given rank and value type, whether it be
+ dense, sparse, sub-ranged, selected, strided, sorted, flipped, transposed, or
+ any arbitrary combination thereof. For example, dense matrices can be multiplied/assigned/transformed/compared
+ with sparse matrices, dense stride views with dense flip views, dense sorted
+ flipped sub-range views with sparse selection views, in all conceivable permutations.
+ The result is a powerful and flexible tool.</i></p>
+
+<h2></h2>
+
+<p><a href="#Overview">Back</a> to Overview
+
+<h2><a name="FunctionObjects"></a>5. Function Objects</h2>
+
+<p>Function objects conveniently allow to express arbitrary functions in a generic
+ manner. Essentially, a function object is an object that can perform a function
+ on some arguments. It has a minimal interface: a method <tt>apply</tt> that
+ takes the arguments, computes something and returns some result value. Function
+ objects are comparable to function pointers in C used for call-backs. Here are
+ some examples demonstrating how function objects can be used to </p>
+<ol>
+ <li><a href="doc-files/function1.html">transform</a> a matrix A into another
+ matrix B which is a function of the original matrix A (and optionally yet
+ another matrix C)
+ </li>
+ <li><a href="doc-files/function2.html">aggregate</a> cell values or a function
+ of them
+ </li>
+ <li><a href="doc-files/function3.html">generate selection views</a> for cells
+ satisfying a given condition
+ </li>
+ <li><a href="doc-files/function4.html">sort</a> matrix rows or columns into
+ a user specified order
+ </li>
+ <li>You will most likely use them to do many more powerful things</li>
+</ol>
+<p>Usually, assign operations are heavily optimized for frequently used function
+ objects like plus, minus, mult, div, plusMult, minusMult, etc. Concerning the
+ performance of unoptimized function objects, see {@link org.apache.mahout.math.jet.math.Functions}.</p>
+
+<p></p>
+
+<p><a href="#Overview">Back</a> to Overview
+
+<h2></h2>
+
+<h2><a name="Algorithms"></a>6. Algorithms </h2>
+
+<p>As already stated, the spectrum of applications using multi-dimensional matrices
+ is large and so is the number of operations meaningful on them. One single flat
+ interface cannot satisfy all needs and would soon get unmanageably fat. To avoid
+ interface bloat, it can be a good idea to separate algorithms from data structures.
+ Special purpose algorithms, wrappers, mediators etc. should therefore go into
+ external packages and classes. By using the common interfaces defined in abstract
+ classes, algorithms can be implemented such that they generically work both
+ on sparse and dense matrices and all their views. This will ensure scalability
+ over time, as more and more features are added. </p>
+
+<p>Some algorithms for formatting, sorting, statistics and partitioning, are,
+ for example, provided in the package {@link org.apache.mahout.math.matrix.doublealgo}. </p>
+
+<p><a href="#Overview">Back</a> to Overview</p>
+
+<h2></h2>
+
+<h2><a name="LinearAlgebra"></a>7. Linear Algebra</h2>
+
+<p>See the documentation of the linear algebra package {@link org.apache.mahout.math.matrix.linalg}.</p>
+
+<p><a href="#Overview">Back</a> to Overview </p>
+
+<h2><a name="PackageOrganization"></a>8. Package Organization, Naming Conventions,
+ Policies</h2>
+<h4>Class Naming / Inheritance</h4>
+
+<p>Have a look at the javadoc <a href="package-tree.html">tree view</a> to get
+ the broad picture. The classes for matrices of a given rank are derived from
+ a common abstract base class named <tt><ValueType>Matrix<Rank>D</tt>,
+ which is in many ways equivalent to an "interface". <b>99% of the
+ time you will operate on these abstract classes only</b>. For example, all 2-dimensional
+ matrices operating on <tt>double</tt> values are derived from {@link org.apache.mahout.math.matrix.DoubleMatrix2D}.
+ This is the interface to operate on.</p>
+
+<p>Class naming for concrete instantiable classes follows the schema <tt><Property><ValueType>Matrix<Rank>D</tt>.
+ For example, we have a {@link org.apache.mahout.math.matrix.impl.DenseDoubleMatrix2D}, a
+ {@link org.apache.mahout.math.matrix.impl.SparseDoubleMatrix2D}, a {@link
+ impl.DenseIntMatrix3D},
+ and so on. All concrete instantiable classes are separated into an extra package,
+ {@link org.apache.mahout.math.matrix.impl}, to clearly distinguish between interfaces and
+ implementations.</p>
+
+<p>{@link org.apache.mahout.math.matrix.DoubleMatrix2D} in turn is derived from an abstract
+ base class tying together all 2-dimensional matrices regardless of value type,
+ {@link org.apache.mahout.math.matrix.impl.AbstractMatrix2D}, which finally is rooted in grandmother
+ {@link org.apache.mahout.math.matrix.impl.AbstractMatrix}.</p>
+
+<p>The abstract base classes provide skeleton implementations for all but few
+ methods. Experimental data layouts can easily be implemented and inherit a rich
+ set of functionality. For example, to implement a fully functional 2-d or 3-d
+ matrix, only 6 abstract methods need to be overridden: <tt>getQuick, setQuick,
+ like, like1D, viewSelectionLike</tt>.</p>
+<h4>Method Naming</h4>
+
+<p>In order to improve browsing and better keep an overview, the namespace of
+ logically related operations is localized: Methods getting and setting individual
+ cell values are named <tt>get</tt> and <tt>set</tt>. Methods constructing views
+ are named <tt>viewXXX</tt> (e.g. <tt>viewPart</tt>). Copying/assignment methods
+ are named <tt>copy</tt> and <tt>assignXXX</tt>. Mathematical operations are
+ named <tt>zXXX</tt> (e.g. <tt>zMult</tt>). Generic aggregation operations are
+ named <tt>aggregateXXX</tt>.</p>
+<h4>Convenience Methods</h4>
+
+<p>To keep interfaces lean and manageable, we tried to avoid littering them with
+ convenience methods obfuscating more fundamental concepts. Convenience operations
+ expressible in one to three lines of code are omitted. For example, all operations
+ modifying cell values modify the receiver (<tt>this</tt>) itself. There are
+ no methods to fill results into empty result matrices. Use idioms like <tt>result
+ = matrix.copy().mult(5)</tt> to achieve the same functionality. Some convenience
+ methods are provided in the factory classes as well as in external packages
+ like {@link org.apache.mahout.math.matrix.doublealgo}.</p>
+
+<p><a href="#Overview">Back</a> to Overview
+
+<h2><a name="Performance"></a>9. Performance</h2>
+
+<p>The following statements apply to all currently implemented features (i.e.
+ dense and sparse matrices including all view kinds), except where indicated.</p>
+
+<p> Constant factors are kept as small as possible.Views are constructed in guaranteed
+ <tt>O(1)</tt>, i.e. constant time, except for selection views and sort views:
+ Selection views take time linear in the number of indexes, sort views take <tt>O(N*logN)</tt>
+ on average. Getting/setting a cell value takes <i>guaranteed </i>constant time
+ for <font color="#CC0000">dense</font> matrices (and all their views), while
+ it takes <i>expected</i> constant time for sparse hash matrices (and all their
+ views). More specifically, on <font color="#CC0000">sparse hash</font> matrices,
+ these operations can, although highly improbable, degenerate to time linear
+ in the number of non-zero cells. This is because of the nature of hashing: Average
+ case behaviour is extremely good, worst case behaviour is bad. </p>
+
+<p><font color="#CE0000">Sparse row compressed</font> matrices have the following
+ characteristics: Getting a cell value takes time<tt> O(log nzr)</tt> where <tt>nzr</tt>
+ is the number of non-zeros of the touched row. This is usually quick, because
+ typically there are only few nonzeros per row. So, in practice, get has <i>expected</i>
+ constant time. Setting a cell value takes <i> </i>worst-case time <tt>O(nz)</tt>
+ where <tt>nzr</tt> is the total number of non-zeros in the matrix. This can
+ be extremely slow, but if you traverse coordinates properly, each write is done
+ much quicker. For how to do this and other tips, see the <a href="doc-files/performanceNotes.html">performance
+ notes</a>. <img src="../doc-files/new.gif" width="32" height="22" align="middle">
+</p>
+
+<p></p>
+
+<p>Some preliminary benchmarks can be found in the <a href="doc-files/PerformanceLogFrame.html">performance
+ log</a>.</p>
+
+<p>All matrices use strided 32-bit integer arithmetic for linear cell addressing,
+ similar to Fortran. The chosen cell addressing implementation is the key feature
+ enabling the easy implementation and good performance of advanced views.</p>
+
+<p>All methods are bounds checking, except for trusting variants of <tt>get</tt>
+ and <tt>set</tt> called <tt>getQuick</tt> and <tt>setQuick</tt> which should
+ and are used in expensive (often cubic) loops where it is dramatically cheaper
+ to check bounds before entering the loop, not in the loop. Fundamentally time
+ critical methods of dense matrices override default implementations such that
+ iteration eliminates function calls, minimizes cell addressing overhead and
+ gets pipelined. Some operations use processor cache oriented optimization techniques
+ such as memory layout aware iteration, blocking of slow changing operands followed
+ by logical optimizations such as sparsity detection.</p>
+
+<p>In order to eliminate expensive call chains, views directly point to the data
+ without indirection, no matter how deeply nested they are. In particular they
+ are not implemented with delegation. In fact they are not nested at all, even
+ if they logically appear like that. There is largely no distinction between
+ views and non-views. Note that this is not true for row-compressed matrices;
+ their views are wrappers and do use delegation (aka call chains). <img src="../doc-files/new.gif" width="32"
+ height="22" align="top"></p>
+
+<p>Although view objects occupy only a couple of bytes, generating temporary views
+ at very high frequency can lead to heavy garbage collection. </p>
+
+<p>To keep the overhead minimal, copying operations are highly optimized. They
+ sometimes boil down to <tt>System.arraycopy</tt> (which is nothing else than
+ a byte-aligned C <tt>memmove</tt>). Also note that memory access patterns (cache
+ locality) of self-modifying matrix operations are better than for result matrix
+ modifying operations.</p>
+
+<p><a href="#Overview">Back</a> to Overview
+
+<h2></h2>
+
+<h2><a name="Notes"></a>10. Notes </h2>
+
+<h2></h2>
+
+<p>Matrices are not dynamically resizable; it is impossible to physically insert
+ or remove cells. Some logical cell removal and insertion can be achieved by
+ means of views. To achieve physical cell removal or insertion, a new matrix
+ with the needed shape must be constructed and cells copied. Note, however, that
+ there are convenience methods to do many kind of resizing operations.</p>
+
+<p>Another current limitation is the inability to address more than 2<sup>31</sup>
+ cells. This can be a problem for very large sparse matrices. 64-bit addressing
+ is possible, but unlikely to be implemented unless there is serious demand.</p>
+
+<p><a href="#Overview">Back</a> to Overview</p>
+</BODY>
+</HTML>
Propchange: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/package.html
------------------------------------------------------------------------------
svn:eol-style = native
Added: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/package.html
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/package.html?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/package.html (added)
+++ lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/package.html Thu Dec 17 23:22:16 2009
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+Core base classes; Operations on primitive arrays such as sorting, partitioning and permuting.
+</BODY>
+</HTML>
Propchange: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/package.html
------------------------------------------------------------------------------
svn:eol-style = native
Added: lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/GenericSortingTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/GenericSortingTest.java?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/GenericSortingTest.java (added)
+++ lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/GenericSortingTest.java Thu Dec 17 23:22:16 2009
@@ -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.GenericSorting;
+import org.apache.mahout.math.Swapper;
+import org.apache.mahout.math.function.IntComparator;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class GenericSortingTest extends Assert {
+
+ private static class SomethingToSort implements Swapper, IntComparator {
+ private final int[] data;
+
+ private SomethingToSort(int[] data) {
+ this.data = data;
+ }
+
+ @Override
+ public void swap(int a, int b) {
+ int temp = data[a];
+ data[a] = data[b];
+ data[b] = temp;
+ }
+
+ @Override
+ public int compare(int o1, int o2) {
+ if (data[o1] < data[o2]) {
+ return -1;
+ } else if (data[o1] > data[o2]) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ @Test
+ public void testQuickSort() {
+ int[] td = new int[20];
+ for (int x = 0; x < 20; x ++) {
+ td[x] = 20 - x;
+ }
+ SomethingToSort sts = new SomethingToSort(td);
+ GenericSorting.quickSort(0, 20, sts, sts);
+ for (int x = 0; x < 20; x ++) {
+ assertEquals(x+1, td[x]);
+ }
+ }
+
+ private static class SomethingToSortStable implements Swapper, IntComparator {
+ private final String[] data;
+
+ private SomethingToSortStable(String[] data) {
+ this.data = data;
+ }
+
+ @Override
+ public void swap(int a, int b) {
+ String temp = data[a];
+ data[a] = data[b];
+ data[b] = temp;
+ }
+
+ @Override
+ public int compare(int o1, int o2) {
+ return data[o1].compareTo(data[o2]);
+ }
+ }
+
+ @Test
+ public void testMergeSort() {
+ String[] sd = {new String("z"), new String("a"), new String("a"), new String("q"), new String("1")};
+ String[] correct = {sd[4], sd[1], sd[2], sd[3], sd[0]};
+
+ SomethingToSortStable sts = new SomethingToSortStable(sd);
+ GenericSorting.mergeSort(0, 5, sts, sts);
+
+ for (int x = 0; x < 5; x ++) {
+ assertSame(correct[x], sd[x]);
+ }
+ }
+}
Propchange: lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/GenericSortingTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/MatrixTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/MatrixTest.java?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/MatrixTest.java (added)
+++ lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/MatrixTest.java Thu Dec 17 23:22:16 2009
@@ -0,0 +1,664 @@
+/**
+ * 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 junit.framework.TestCase;
+import org.apache.hadoop.io.DataOutputBuffer;
+import org.apache.mahout.math.AbstractMatrix;
+import org.apache.mahout.math.CardinalityException;
+import org.apache.mahout.math.DenseMatrix;
+import org.apache.mahout.math.DenseVector;
+import org.apache.mahout.math.IndexException;
+import org.apache.mahout.math.Matrix;
+import org.apache.mahout.math.NegateFunction;
+import org.apache.mahout.math.PlusFunction;
+import org.apache.mahout.math.UnboundLabelException;
+import org.apache.mahout.math.Vector;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class MatrixTest extends TestCase {
+
+ protected static final int ROW = AbstractMatrix.ROW;
+
+ protected static final int COL = AbstractMatrix.COL;
+
+ protected final double[][] values = {{1.1, 2.2}, {3.3, 4.4},
+ {5.5, 6.6}};
+
+ protected final double[] vectorAValues = {1.0 / 1.1, 2.0 / 1.1};
+
+ protected final double[] vectorBValues = {5.0, 10.0, 100.0};
+
+ protected Matrix test;
+
+ protected MatrixTest(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ test = matrixFactory(values);
+ }
+
+ public abstract Matrix matrixFactory(double[][] values);
+
+ public void testCardinality() {
+ int[] c = test.size();
+ assertEquals("row cardinality", values.length, c[ROW]);
+ assertEquals("col cardinality", values[0].length, c[COL]);
+ }
+
+ public void testCopy() {
+ int[] c = test.size();
+ Matrix copy = test.clone();
+ assertEquals("wrong class", copy.getClass(), test.getClass());
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']',
+ test.getQuick(row, col), copy.getQuick(row, col));
+ }
+ }
+ }
+
+ public void testGetQuick() {
+ int[] c = test.size();
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']', values[row][col], test
+ .getQuick(row, col));
+ }
+ }
+ }
+
+ public void testHaveSharedCells() {
+ assertTrue("same", test.haveSharedCells(test));
+ assertFalse("different", test.haveSharedCells(test.clone()));
+ }
+
+ public void testLike() {
+ Matrix like = test.like();
+ assertEquals("type", like.getClass(), test.getClass());
+ assertEquals("rows", test.size()[ROW], like.size()[ROW]);
+ assertEquals("columns", test.size()[COL], like.size()[COL]);
+ }
+
+ public void testLikeIntInt() {
+ Matrix like = test.like(4, 4);
+ assertEquals("type", like.getClass(), test.getClass());
+ assertEquals("rows", 4, like.size()[ROW]);
+ assertEquals("columns", 4, like.size()[COL]);
+ }
+
+ public void testSetQuick() {
+ int[] c = test.size();
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ test.setQuick(row, col, 1.23);
+ assertEquals("value[" + row + "][" + col + ']', 1.23, test.getQuick(
+ row, col));
+ }
+ }
+ }
+
+ public void testSize() {
+ int[] c = test.getNumNondefaultElements();
+ assertEquals("row size", values.length, c[ROW]);
+ assertEquals("col size", values[0].length, c[COL]);
+ }
+
+ public void testViewPart() {
+ int[] offset = {1, 1};
+ int[] size = {2, 1};
+ Matrix view = test.viewPart(offset, size);
+ int[] c = view.size();
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']',
+ values[row + 1][col + 1], view.getQuick(row, col));
+ }
+ }
+ }
+
+ public void testViewPartCardinality() {
+ int[] offset = {1, 1};
+ int[] size = {3, 3};
+ try {
+ test.viewPart(offset, size);
+ fail("exception expected");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ } catch (IndexException e) {
+ fail("cardinality exception expected");
+ }
+ }
+
+ public void testViewPartIndexOver() {
+ int[] offset = {1, 1};
+ int[] size = {2, 2};
+ try {
+ test.viewPart(offset, size);
+ fail("exception expected");
+ } catch (CardinalityException e) {
+ fail("index exception expected");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testViewPartIndexUnder() {
+ int[] offset = {-1, -1};
+ int[] size = {2, 2};
+ try {
+ test.viewPart(offset, size);
+ fail("exception expected");
+ } catch (CardinalityException e) {
+ fail("index exception expected");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testAssignDouble() {
+ int[] c = test.size();
+ test.assign(4.53);
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']', 4.53, test.getQuick(
+ row, col));
+ }
+ }
+ }
+
+ public void testAssignDoubleArrayArray() {
+ int[] c = test.size();
+ test.assign(new double[3][2]);
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']', 0.0, test.getQuick(row,
+ col));
+ }
+ }
+ }
+
+ public void testAssignDoubleArrayArrayCardinality() {
+ int[] c = test.size();
+ try {
+ test.assign(new double[c[ROW] + 1][c[COL]]);
+ fail("exception expected");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testAssignMatrixBinaryFunction() {
+ int[] c = test.size();
+ test.assign(test, new PlusFunction());
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']', 2 * values[row][col],
+ test.getQuick(row, col));
+ }
+ }
+ }
+
+ public void testAssignMatrixBinaryFunctionCardinality() {
+ try {
+ test.assign(test.transpose(), new PlusFunction());
+ fail("exception expected");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testAssignMatrix() {
+ int[] c = test.size();
+ Matrix value = test.like();
+ value.assign(test);
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']',
+ test.getQuick(row, col), value.getQuick(row, col));
+ }
+ }
+ }
+
+ public void testAssignMatrixCardinality() {
+ try {
+ test.assign(test.transpose());
+ fail("exception expected");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testAssignUnaryFunction() {
+ int[] c = test.size();
+ test.assign(new NegateFunction());
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']', -values[row][col], test
+ .getQuick(row, col));
+ }
+ }
+ }
+
+ public void testDivide() {
+ int[] c = test.size();
+ Matrix value = test.divide(4.53);
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']',
+ values[row][col] / 4.53, value.getQuick(row, col));
+ }
+ }
+ }
+
+ public void testGet() {
+ int[] c = test.size();
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']', values[row][col], test
+ .get(row, col));
+ }
+ }
+ }
+
+ public void testGetIndexUnder() {
+ int[] c = test.size();
+ try {
+ for (int row = -1; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ test.get(row, col);
+ }
+ }
+ fail("index exception expected");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testGetIndexOver() {
+ int[] c = test.size();
+ try {
+ for (int row = 0; row < c[ROW] + 1; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ test.get(row, col);
+ }
+ }
+ fail("index exception expected");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testMinus() {
+ int[] c = test.size();
+ Matrix value = test.minus(test);
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']', 0.0, value.getQuick(
+ row, col));
+ }
+ }
+ }
+
+ public void testMinusCardinality() {
+ try {
+ test.minus(test.transpose());
+ fail("cardinality exception expected");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testPlusDouble() {
+ int[] c = test.size();
+ Matrix value = test.plus(4.53);
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']',
+ values[row][col] + 4.53, value.getQuick(row, col));
+ }
+ }
+ }
+
+ public void testPlusMatrix() {
+ int[] c = test.size();
+ Matrix value = test.plus(test);
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']', values[row][col] * 2,
+ value.getQuick(row, col));
+ }
+ }
+ }
+
+ public void testPlusMatrixCardinality() {
+ try {
+ test.plus(test.transpose());
+ fail("cardinality exception expected");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testSetUnder() {
+ int[] c = test.size();
+ try {
+ for (int row = -1; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ test.set(row, col, 1.23);
+ }
+ }
+ fail("index exception expected");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testSetOver() {
+ int[] c = test.size();
+ try {
+ for (int row = 0; row < c[ROW] + 1; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ test.set(row, col, 1.23);
+ }
+ }
+ fail("index exception expected");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testTimesDouble() {
+ int[] c = test.size();
+ Matrix value = test.times(4.53);
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']',
+ values[row][col] * 4.53, value.getQuick(row, col));
+ }
+ }
+ }
+
+ public void testTimesMatrix() {
+ int[] c = test.size();
+ Matrix transpose = test.transpose();
+ Matrix value = test.times(transpose);
+ int[] v = value.size();
+ assertEquals("rows", c[ROW], v[ROW]);
+ assertEquals("cols", c[ROW], v[COL]);
+
+ Matrix expected = new DenseMatrix(new double[][]{{5.0, 11.0, 17.0},
+ {11.0, 25.0, 39.0}, {17.0, 39.0, 61.0}}).times(1.21);
+
+ for (int i = 0; i < expected.numCols(); i++) {
+ for (int j = 0; j < expected.numRows(); j++) {
+ assertTrue("Matrix times transpose not correct: " + i + ", " + j
+ + "\nexpected:\n\t" + expected.asFormatString() + "\nactual:\n\t"
+ + value.asFormatString(),
+ Math.abs(expected.get(i, j) - value.get(i, j)) < 1e-12);
+ }
+ }
+
+ Matrix timestest = new DenseMatrix(10, 1);
+ /* will throw ArrayIndexOutOfBoundsException exception without MAHOUT-26 */
+ timestest.transpose().times(timestest);
+ }
+
+ public void testTimesVector() {
+ Vector vectorA = new DenseVector(vectorAValues);
+ Vector testTimesVectorA = test.times(vectorA);
+ Vector expected = new DenseVector(new double[]{5.0, 11.0, 17.0});
+ assertTrue("Matrix times vector not equals: " + vectorA.asFormatString()
+ + " != " + testTimesVectorA.asFormatString(),
+ expected.minus(testTimesVectorA).norm(2) < 1e-12);
+ try {
+ test.times(testTimesVectorA);
+ fail("Cardinalities do not match, should throw exception");
+ } catch (CardinalityException ce) {
+ assertTrue(true);
+ }
+ }
+
+ public void testTimesSquaredTimesVector() {
+ Vector vectorA = new DenseVector(vectorAValues);
+ Vector ttA = test.timesSquared(vectorA);
+ Vector ttASlow = test.transpose().times(test.times(vectorA));
+ assertTrue("M'Mv != M.timesSquared(v): " + ttA.asFormatString()
+ + " != " + ttASlow.asFormatString(),
+ ttASlow.minus(ttA).norm(2) < 1e-12);
+
+ }
+
+ public void testTimesMatrixCardinality() {
+ Matrix other = test.like(5, 8);
+ try {
+ test.times(other);
+ fail("cardinality exception expected");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testTranspose() {
+ int[] c = test.size();
+ Matrix transpose = test.transpose();
+ int[] t = transpose.size();
+ assertEquals("rows", c[COL], t[ROW]);
+ assertEquals("cols", c[ROW], t[COL]);
+ for (int row = 0; row < c[ROW]; row++) {
+ for (int col = 0; col < c[COL]; col++) {
+ assertEquals("value[" + row + "][" + col + ']',
+ test.getQuick(row, col), transpose.getQuick(col, row));
+ }
+ }
+ }
+
+ public void testZSum() {
+ double sum = test.zSum();
+ assertEquals("zsum", 23.1, sum);
+ }
+
+ public void testAssignRow() {
+ double[] data = {2.1, 3.2};
+ test.assignRow(1, new DenseVector(data));
+ assertEquals("test[1][0]", 2.1, test.getQuick(1, 0));
+ assertEquals("test[1][1]", 3.2, test.getQuick(1, 1));
+ }
+
+ public void testAssignRowCardinality() {
+ double[] data = {2.1, 3.2, 4.3};
+ try {
+ test.assignRow(1, new DenseVector(data));
+ fail("expecting cardinality exception");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testAssignColumn() {
+ double[] data = {2.1, 3.2, 4.3};
+ test.assignColumn(1, new DenseVector(data));
+ assertEquals("test[0][1]", 2.1, test.getQuick(0, 1));
+ assertEquals("test[1][1]", 3.2, test.getQuick(1, 1));
+ assertEquals("test[2][1]", 4.3, test.getQuick(2, 1));
+ }
+
+ public void testAssignColumnCardinality() {
+ double[] data = {2.1, 3.2};
+ try {
+ test.assignColumn(1, new DenseVector(data));
+ fail("expecting cardinality exception");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testGetRow() {
+ Vector row = test.getRow(1);
+ assertEquals("row size", 2, row.getNumNondefaultElements());
+ }
+
+ public void testGetRowIndexUnder() {
+ try {
+ test.getRow(-1);
+ fail("expecting index exception");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testGetRowIndexOver() {
+ try {
+ test.getRow(5);
+ fail("expecting index exception");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testGetColumn() {
+ Vector column = test.getColumn(1);
+ assertEquals("row size", 3, column.getNumNondefaultElements());
+ }
+
+ public void testGetColumnIndexUnder() {
+ try {
+ test.getColumn(-1);
+ fail("expecting index exception");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testGetColumnIndexOver() {
+ try {
+ test.getColumn(5);
+ fail("expecting index exception");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testDetermitant() {
+ Matrix m = matrixFactory(new double[][]{{1, 3, 4}, {5, 2, 3},
+ {1, 4, 2}});
+ assertEquals("determinant", 43.0, m.determinant());
+ }
+
+ public void testAsFormatString() {
+ String string = test.asFormatString();
+ int[] cardinality = {values.length, values[0].length};
+ Matrix m = AbstractMatrix.decodeMatrix(string);
+ for (int row = 0; row < cardinality[ROW]; row++) {
+ for (int col = 0; col < cardinality[COL]; col++) {
+ assertEquals("m[" + row + ',' + col + ']', test.get(row, col), m.get(
+ row, col));
+ }
+ }
+ }
+
+ public void testLabelBindings() {
+ Matrix m = matrixFactory(new double[][]{{1, 3, 4}, {5, 2, 3},
+ {1, 4, 2}});
+ assertNull("row bindings", m.getRowLabelBindings());
+ assertNull("col bindings", m.getColumnLabelBindings());
+ Map<String, Integer> rowBindings = new HashMap<String, Integer>();
+ rowBindings.put("Fee", 0);
+ rowBindings.put("Fie", 1);
+ rowBindings.put("Foe", 2);
+ m.setRowLabelBindings(rowBindings);
+ assertEquals("row", rowBindings, m.getRowLabelBindings());
+ Map<String, Integer> colBindings = new HashMap<String, Integer>();
+ colBindings.put("Foo", 0);
+ colBindings.put("Bar", 1);
+ colBindings.put("Baz", 2);
+ m.setColumnLabelBindings(colBindings);
+ assertEquals("row", rowBindings, m.getRowLabelBindings());
+ assertEquals("Fee", m.get(0, 1), m.get("Fee", "Bar"));
+
+ double[] newrow = {9, 8, 7};
+ m.set("Foe", newrow);
+ assertEquals("FeeBaz", m.get(0, 2), m.get("Fee", "Baz"));
+ }
+
+ public void testSettingLabelBindings() {
+ Matrix m = matrixFactory(new double[][]{{1, 3, 4}, {5, 2, 3},
+ {1, 4, 2}});
+ assertNull("row bindings", m.getRowLabelBindings());
+ assertNull("col bindings", m.getColumnLabelBindings());
+ m.set("Fee", "Foo", 1, 2, 9);
+ assertNotNull("row", m.getRowLabelBindings());
+ assertNotNull("row", m.getRowLabelBindings());
+ assertEquals("Fee", 1, m.getRowLabelBindings().get("Fee").intValue());
+ assertEquals("Fee", 2, m.getColumnLabelBindings().get("Foo").intValue());
+ assertEquals("FeeFoo", m.get(1, 2), m.get("Fee", "Foo"));
+ try {
+ m.get("Fie", "Foe");
+ fail("Expected UnboundLabelException");
+ } catch (IndexException e) {
+ fail("Expected UnboundLabelException");
+ } catch (UnboundLabelException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testLabelBindingSerialization() {
+ Matrix m = matrixFactory(new double[][]{{1, 3, 4}, {5, 2, 3},
+ {1, 4, 2}});
+ assertNull("row bindings", m.getRowLabelBindings());
+ assertNull("col bindings", m.getColumnLabelBindings());
+ Map<String, Integer> rowBindings = new HashMap<String, Integer>();
+ rowBindings.put("Fee", 0);
+ rowBindings.put("Fie", 1);
+ rowBindings.put("Foe", 2);
+ m.setRowLabelBindings(rowBindings);
+ assertEquals("row", rowBindings, m.getRowLabelBindings());
+ Map<String, Integer> colBindings = new HashMap<String, Integer>();
+ colBindings.put("Foo", 0);
+ colBindings.put("Bar", 1);
+ colBindings.put("Baz", 2);
+ m.setColumnLabelBindings(colBindings);
+ String json = m.asFormatString();
+ Matrix mm = AbstractMatrix.decodeMatrix(json);
+ assertEquals("Fee", m.get(0, 1), mm.get("Fee", "Bar"));
+ }
+
+ public void testMatrixWritable() throws IOException {
+ Matrix m = matrixFactory(new double[][]{{1, 3, 4}, {5, 2, 3},
+ {1, 4, 2}});
+ DataOutputBuffer out = new DataOutputBuffer();
+ m.write(out);
+ out.close();
+
+ DataInputStream in = new DataInputStream(new ByteArrayInputStream(out
+ .getData()));
+ Matrix m2 = m.like();
+ m2.readFields(in);
+ in.close();
+ assertEquals("row size", m.size()[ROW], m2.size()[ROW]);
+ assertEquals("col size", m.size()[COL], m2.size()[COL]);
+ }
+}
Propchange: lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/MatrixTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/TestDenseMatrix.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/TestDenseMatrix.java?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/TestDenseMatrix.java (added)
+++ lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/TestDenseMatrix.java Thu Dec 17 23:22:16 2009
@@ -0,0 +1,34 @@
+/**
+ * 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.DenseMatrix;
+import org.apache.mahout.math.Matrix;
+
+public class TestDenseMatrix extends MatrixTest {
+
+ public TestDenseMatrix(String name) {
+ super(name);
+ }
+
+ @Override
+ public Matrix matrixFactory(double[][] values) {
+ return new DenseMatrix(values);
+ }
+
+}
Propchange: lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/TestDenseMatrix.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/TestDenseVector.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/TestDenseVector.java?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/TestDenseVector.java (added)
+++ lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/TestDenseVector.java Thu Dec 17 23:22:16 2009
@@ -0,0 +1,426 @@
+/**
+ * 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 junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.mahout.math.AbstractVector;
+import org.apache.mahout.math.CardinalityException;
+import org.apache.mahout.math.DenseVector;
+import org.apache.mahout.math.IndexException;
+import org.apache.mahout.math.Matrix;
+import org.apache.mahout.math.NegateFunction;
+import org.apache.mahout.math.PlusFunction;
+import org.apache.mahout.math.TimesFunction;
+import org.apache.mahout.math.Vector;
+
+public class TestDenseVector extends TestCase {
+
+ final double[] values = {1.1, 2.2, 3.3};
+
+ final Vector test = new DenseVector(values);
+
+ public TestDenseVector(String name) {
+ super(name);
+ }
+
+ public void testAsFormatString() {
+ String formatString = test.asFormatString();
+ Vector vec = AbstractVector.decodeVector(formatString);
+ assertEquals(vec, test);
+ }
+
+ public void testCardinality() {
+ assertEquals("cardinality", 3, test.size());
+ }
+
+ public void testCopy() throws Exception {
+ Vector copy = test.clone();
+ for (int i = 0; i < test.size(); i++) {
+ assertEquals("copy [" + i + ']', test.get(i), copy.get(i));
+ }
+ }
+
+ public void testGet() throws Exception {
+ for (int i = 0; i < test.size(); i++) {
+ assertEquals("get [" + i + ']', values[i], test.get(i));
+ }
+ }
+
+ public void testGetOver() {
+ try {
+ test.get(test.size());
+ fail("expected exception");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testGetUnder() {
+ try {
+ test.get(-1);
+ fail("expected exception");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testSet() throws Exception {
+ test.set(2, 4.5);
+ for (int i = 0; i < test.size(); i++) {
+ if (i == 2) {
+ assertEquals("set [" + i + ']', 4.5, test.get(i));
+ } else {
+ assertEquals("set [" + i + ']', values[i], test.get(i));
+ }
+ }
+ }
+
+
+ public void testIterator() throws Exception {
+ Iterator<Vector.Element> iterator = test.iterateNonZero();
+ checkIterator(iterator, values, 3);
+
+ iterator = test.iterateAll();
+ checkIterator(iterator, values, 3);
+
+ double[] doubles = {0.0, 5.0, 0, 3.0};
+ DenseVector zeros = new DenseVector(doubles);
+ iterator = zeros.iterateNonZero();
+ checkIterator(iterator, doubles, 2);
+ iterator = zeros.iterateAll();
+ checkIterator(iterator, doubles, doubles.length);
+
+ doubles = new double[]{0.0, 0.0, 0, 0.0};
+ zeros = new DenseVector(doubles);
+ iterator = zeros.iterateNonZero();
+ checkIterator(iterator, doubles, 0);
+ iterator = zeros.iterateAll();
+ checkIterator(iterator, doubles, doubles.length);
+
+ }
+
+ private static void checkIterator(Iterator<Vector.Element> nzIter, double[] values, int expectedNum) {
+ int i = 0;
+ while (nzIter.hasNext()) {
+ Vector.Element elt = nzIter.next();
+ assertEquals((elt.index()) + " Value: " + values[elt.index()] + " does not equal: " + elt.get(),
+ values[elt.index()], elt.get(), 0.0);
+ i++;
+ }
+ assertEquals(i + " does not equal: " + expectedNum, i, expectedNum);
+ }
+
+ public void testSize() throws Exception {
+ assertEquals("size", 3, test.getNumNondefaultElements());
+ }
+
+ public void testViewPart() throws Exception {
+ Vector part = test.viewPart(1, 2);
+ assertEquals("part size", 2, part.getNumNondefaultElements());
+ for (int i = 0; i < part.size(); i++) {
+ assertEquals("part[" + i + ']', values[i + 1], part.get(i));
+ }
+ }
+
+ public void testViewPartUnder() {
+ try {
+ test.viewPart(-1, values.length);
+ fail("no exception");
+ } catch (CardinalityException e) {
+ fail("wrong exception");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testViewPartOver() {
+ try {
+ test.viewPart(2, values.length);
+ fail("no exception");
+ } catch (CardinalityException e) {
+ fail("wrong exception");
+ } catch (IndexException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testViewPartCardinality() {
+ try {
+ test.viewPart(1, values.length + 1);
+ fail("no exception");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ } catch (IndexException e) {
+ fail("wrong exception");
+ }
+ }
+
+ public void testDecodeVector() throws Exception {
+ Vector val = AbstractVector.decodeVector(test.asFormatString());
+ for (int i = 0; i < test.size(); i++) {
+ assertEquals("get [" + i + ']', test.get(i), val.get(i));
+ }
+ }
+
+ public void testDenseVectorDoubleArray() throws Exception {
+ for (int i = 0; i < test.size(); i++) {
+ assertEquals("test[" + i + ']', values[i], test.get(i));
+ }
+ }
+
+ public void testDenseVectorInt() throws Exception {
+ Vector val = new DenseVector(4);
+ assertEquals("cardinality", 4, val.size());
+ for (int i = 0; i < test.size(); i++) {
+ assertEquals("get [" + i + ']', 0.0, val.get(i));
+ }
+ }
+
+ public void testDot() throws Exception {
+ double res = test.dot(test);
+ assertEquals("dot", 1.1 * 1.1 + 2.2 * 2.2 + 3.3 * 3.3, res);
+ }
+
+ public void testDotCardinality() {
+ try {
+ test.dot(new DenseVector(test.size() + 1));
+ fail("expected exception");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testNormalize() throws Exception {
+ Vector res = test.normalize();
+ double mag = Math.sqrt(1.1 * 1.1 + 2.2 * 2.2 + 3.3 * 3.3);
+ for (int i = 0; i < test.size(); i++) {
+ assertEquals("dot", values[i] / mag, res.get(i));
+ }
+ }
+
+ public void testMinus() throws Exception {
+ Vector val = test.minus(test);
+ assertEquals("cardinality", 3, val.size());
+ for (int i = 0; i < test.size(); i++) {
+ assertEquals("get [" + i + ']', 0.0, val.get(i));
+ }
+ }
+
+ public void testPlusDouble() throws Exception {
+ Vector val = test.plus(1);
+ assertEquals("cardinality", 3, val.size());
+ for (int i = 0; i < test.size(); i++) {
+ assertEquals("get [" + i + ']', values[i] + 1, val.get(i));
+ }
+ }
+
+ public void testPlusVector() throws Exception {
+ Vector val = test.plus(test);
+ assertEquals("cardinality", 3, val.size());
+ for (int i = 0; i < test.size(); i++) {
+ assertEquals("get [" + i + ']', values[i] * 2, val.get(i));
+ }
+ }
+
+ public void testPlusVectorCardinality() {
+ try {
+ test.plus(new DenseVector(test.size() + 1));
+ fail("expected exception");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testTimesDouble() throws Exception {
+ Vector val = test.times(3);
+ assertEquals("cardinality", 3, val.size());
+ for (int i = 0; i < test.size(); i++) {
+ assertEquals("get [" + i + ']', values[i] * 3, val.get(i));
+ }
+ }
+
+ public void testDivideDouble() throws Exception {
+ Vector val = test.divide(3);
+ assertEquals("cardinality", 3, val.size());
+ for (int i = 0; i < test.size(); i++) {
+ assertEquals("get [" + i + ']', values[i] / 3, val.get(i));
+ }
+ }
+
+ public void testTimesVector() throws Exception {
+ Vector val = test.times(test);
+ assertEquals("cardinality", 3, val.size());
+ for (int i = 0; i < test.size(); i++) {
+ assertEquals("get [" + i + ']', values[i] * values[i], val.get(i));
+ }
+ }
+
+ public void testTimesVectorCardinality() {
+ try {
+ test.times(new DenseVector(test.size() + 1));
+ fail("expected exception");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testZSum() {
+ double expected = 0;
+ for (double value : values) {
+ expected += value;
+ }
+ assertEquals("wrong zSum", expected, test.zSum());
+ }
+
+ public void testAssignDouble() {
+ test.assign(0);
+ for (int i = 0; i < values.length; i++) {
+ assertEquals("value[" + i + ']', 0.0, test.getQuick(i));
+ }
+ }
+
+ public void testAssignDoubleArray() throws Exception {
+ double[] array = new double[test.size()];
+ test.assign(array);
+ for (int i = 0; i < values.length; i++) {
+ assertEquals("value[" + i + ']', 0.0, test.getQuick(i));
+ }
+ }
+
+ public void testAssignDoubleArrayCardinality() {
+ double[] array = new double[test.size() + 1];
+ try {
+ test.assign(array);
+ fail("cardinality exception expected");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testAssignVector() throws Exception {
+ Vector other = new DenseVector(test.size());
+ test.assign(other);
+ for (int i = 0; i < values.length; i++) {
+ assertEquals("value[" + i + ']', 0.0, test.getQuick(i));
+ }
+ }
+
+ public void testAssignVectorCardinality() {
+ Vector other = new DenseVector(test.size() - 1);
+ try {
+ test.assign(other);
+ fail("cardinality exception expected");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testAssignUnaryFunction() {
+ test.assign(new NegateFunction());
+ for (int i = 0; i < values.length; i++) {
+ assertEquals("value[" + i + ']', -values[i], test.getQuick(i));
+ }
+ }
+
+ public void testAssignBinaryFunction() throws Exception {
+ test.assign(test, new PlusFunction());
+ for (int i = 0; i < values.length; i++) {
+ assertEquals("value[" + i + ']', 2 * values[i], test.getQuick(i));
+ }
+ }
+
+ public void testAssignBinaryFunction2() throws Exception {
+ test.assign(new PlusFunction(), 4);
+ for (int i = 0; i < values.length; i++) {
+ assertEquals("value[" + i + ']', values[i] + 4, test.getQuick(i));
+ }
+ }
+
+ public void testAssignBinaryFunction3() throws Exception {
+ test.assign(new TimesFunction(), 4);
+ for (int i = 0; i < values.length; i++) {
+ assertEquals("value[" + i + ']', values[i] * 4, test.getQuick(i));
+ }
+ }
+
+ public void testAssignBinaryFunctionCardinality() {
+ try {
+ test.assign(test.like(2), new PlusFunction());
+ fail("Cardinality exception expected");
+ } catch (CardinalityException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testThisHaveSharedCells() throws Exception {
+ assertTrue("test not shared?", test.haveSharedCells(test));
+ }
+
+ public void testViewHaveSharedCells() throws Exception {
+ Vector view = test.viewPart(1, 2);
+ assertTrue("view not shared?", view.haveSharedCells(test));
+ assertTrue("test not shared?", test.haveSharedCells(view));
+ }
+
+ public void testViewsHaveSharedCells() throws Exception {
+ Vector view1 = test.viewPart(0, 2);
+ Vector view2 = test.viewPart(1, 2);
+ assertTrue("view1 not shared?", view1.haveSharedCells(view2));
+ assertTrue("view2 not shared?", view2.haveSharedCells(view1));
+ }
+
+ public void testLike() {
+ assertTrue("not like", test.like() instanceof DenseVector);
+ }
+
+ public void testLikeN() {
+ Vector other = test.like(5);
+ assertTrue("not like", other instanceof DenseVector);
+ assertEquals("size", 5, other.size());
+ }
+
+ public void testCrossProduct() {
+ Matrix result = test.cross(test);
+ assertEquals("row size", test.size(), result.size()[0]);
+ assertEquals("col size", test.size(), result.size()[1]);
+ for (int row = 0; row < result.size()[0]; row++) {
+ for (int col = 0; col < result.size()[1]; col++) {
+ assertEquals("cross[" + row + "][" + col + ']', test.getQuick(row)
+ * test.getQuick(col), result.getQuick(row, col));
+ }
+ }
+ }
+
+ public void testLabelIndexing() {
+ Map<String, Integer> bindings = new HashMap<String, Integer>();
+ bindings.put("Fee", 0);
+ bindings.put("Fie", 1);
+ bindings.put("Foe", 2);
+ test.setLabelBindings(bindings);
+ assertEquals("Fee", test.get(0), test.get("Fee"));
+ assertEquals("Fie", test.get(1), test.get("Fie"));
+ assertEquals("Foe", test.get(2), test.get("Foe"));
+ test.set("Fie", 15.3);
+ assertEquals("Fie", test.get(1), test.get("Fie"));
+ }
+}
Propchange: lucene/mahout/trunk/math/src/test/java/org/apache/mahout/math/TestDenseVector.java
------------------------------------------------------------------------------
svn:eol-style = native