added support for any kind of field in linear algebra

we can now use FieldMatrix<Fraction> and use exact LU-decomposition
on such matrices to solve linear systems

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@766485 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2009-04-19 16:39:40 +00:00
parent d60149c7f8
commit 2d343b1a30
25 changed files with 6661 additions and 10 deletions

View File

@ -109,6 +109,16 @@
<Method name="getDataRef" params="" returns="double[][]" />
<Bug pattern="EI_EXPOSE_REP" />
</Match>
<Match>
<Class name="org.apache.commons.math.linear.FieldMatrixImpl"/>
<Method name="&lt;init>" params="org.apache.commons.math.FieldElement[][],boolean" returns="void" />
<Bug pattern="EI_EXPOSE_REP2" />
</Match>
<Match>
<Class name="org.apache.commons.math.linear.FieldMatrixImpl"/>
<Method name="getDataRef" params="" returns="org.apache.commons.math.FieldElement[][]" />
<Bug pattern="EI_EXPOSE_REP" />
</Match>
<Match>
<Class name="org.apache.commons.math.linear.DenseRealMatrix"/>
<Method name="&lt;init>" params="int,int,double[][],boolean" returns="void" />
@ -127,6 +137,11 @@
<Method name="getDataRef" params="" returns="double[]" />
<Bug pattern="EI_EXPOSE_REP" />
</Match>
<Match>
<Class name="org.apache.commons.math.linear.FieldVectorImpl"/>
<Method name="getDataRef" params="" returns="org.apache.commons.math.FieldElement[]" />
<Bug pattern="EI_EXPOSE_REP" />
</Match>
<!-- The following cases are intentional unit tests for null parameters -->
<Match>

View File

@ -230,6 +230,12 @@ public class MessagesResources_fr
{ "too small integration interval: length = {0}",
"intervalle d''int\u00e9gration trop petit : {0}" },
// org.apache.commons.math.ode.stiff.BDFIntegrator
{ "unsupported order {0} for BDF methods, must be between {1} and {2}",
"ordre {0} non support\u00e9 pour les m\u00e9thodes BDF, doit \u00eatre entre {1} et {2}" },
{ "corrector failed to converge after {0} iterations at t = {1}",
"\u00e9chec de convergence du correcteur apr\u00e8s {0} it\u00e9rations \u00e0 t = {1}" },
// org.apache.commons.math.ode.ContinuousOutputModel
// org.apache.commons.math.optimization.direct.DirectSearchOptimizer
{ "unexpected exception caught",
@ -276,6 +282,7 @@ public class MessagesResources_fr
"dimension de vecteur erronn\u00e9e : {0} \u00e0 la place de {1}" },
// org.apache.commons.math.linear.RealVectorImpl
// org.apache.commons.math.linear.FieldVectorImpl
// org.apache.commons.math.linear.SparseRealVector
{ "index {0} out of allowed range [{1}, {2}]",
"index {0} hors de la plage autoris\u00e9e [{1}, {2}]" },
@ -285,6 +292,7 @@ public class MessagesResources_fr
"la position {0} et la taille {1} sont incompatibles avec la taille du tableau d''entr\u00e9e {2}"},
// org.apache.commons.math.linear.AbstractRealMatrix
// org.apache.commons.math.linear.AbstractFieldMatrix
{ "invalid row dimension: {0} (must be positive)",
"nombre de lignes invalide : {0} (doit \u00eatre positif)" },
{ "invalid column dimension: {0} (must be positive)",

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,10 @@ import java.math.BigDecimal;
* returns the element in the first row, first column of the matrix.</p>
*
* @version $Revision$ $Date$
* @deprecated as of 2.0, replaced by {@link FieldMatrix} with a {@link
* org.apache.commons.math.util.BigReal} parameter
*/
@Deprecated
public interface BigMatrix {
/**

View File

@ -49,8 +49,11 @@ import org.apache.commons.math.linear.decomposition.SingularMatrixException;
* is 0-based -- e.g., <code>getEntry(0, 0)</code>
* returns the element in the first row, first column of the matrix.</li></ul></p>
*
* @deprecated as of 2.0, replaced by {@link FieldMatrixImpl} with a {@link
* org.apache.commons.math.util.BigReal} parameter
* @version $Revision$ $Date$
*/
@Deprecated
public class BigMatrixImpl implements BigMatrix, Serializable {
/** Serialization id */

View File

@ -0,0 +1,65 @@
/*
* 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.commons.math.linear;
import org.apache.commons.math.FieldElement;
/**
* Default implementation of the {@link FieldMatrixChangingVisitor} interface.
* <p>
* This class is a convenience to create custom visitors without defining all
* methods. This class provides default implementations that do nothing.
* </p>
*
* @param <T> the type of the field elements
* @version $Revision$ $Date$
* @since 2.0
*/
public class DefaultFieldMatrixChangingVisitor<T extends FieldElement<T>>
implements FieldMatrixChangingVisitor<T> {
/** Serializable version identifier. */
private static final long serialVersionUID = -7138694000397476118L;
/** Zero element of the field. */
private final T zero;
/** Build a new instance.
* @param zero additive identity of the field
*/
public DefaultFieldMatrixChangingVisitor(final T zero) {
this.zero = zero;
}
/** {@inheritDoc} */
public void start(int rows, int columns,
int startRow, int endRow, int startColumn, int endColumn) {
}
/** {@inheritDoc} */
public T visit(int row, int column, T value)
throws MatrixVisitorException {
return value;
}
/** {@inheritDoc} */
public T end() {
return zero;
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.commons.math.linear;
import org.apache.commons.math.FieldElement;
/**
* Default implementation of the {@link FieldMatrixPreservingVisitor} interface.
* <p>
* This class is a convenience to create custom visitors without defining all
* methods. This class provides default implementations that do nothing.
* </p>
*
* @param <T> the type of the field elements
* @version $Revision$ $Date$
* @since 2.0
*/
public class DefaultFieldMatrixPreservingVisitor<T extends FieldElement<T>>
implements FieldMatrixPreservingVisitor<T> {
/** Serializable version identifier. */
private static final long serialVersionUID = 7998898965168636198L;
/** Zero element of the field. */
private final T zero;
/** Build a new instance.
* @param zero additive identity of the field
*/
public DefaultFieldMatrixPreservingVisitor(final T zero) {
this.zero = zero;
}
/** {@inheritDoc} */
public void start(int rows, int columns,
int startRow, int endRow, int startColumn, int endColumn) {
}
/** {@inheritDoc} */
public void visit(int row, int column, T value)
throws MatrixVisitorException {
}
/** {@inheritDoc} */
public T end() {
return zero;
}
}

View File

@ -0,0 +1,819 @@
/*
* 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.commons.math.linear;
import java.io.Serializable;
import org.apache.commons.math.Field;
import org.apache.commons.math.FieldElement;
import org.apache.commons.math.linear.decomposition.NonSquareMatrixException;
/**
* Interface defining field-valued matrix with basic algebraic operations.
* <p>
* Matrix element indexing is 0-based -- e.g., <code>getEntry(0, 0)</code>
* returns the element in the first row, first column of the matrix.</p>
*
* @param <T> the type of the field elements
* @version $Revision$ $Date$
*/
public interface FieldMatrix<T extends FieldElement<T>> extends Serializable {
/**
* Get the type of field elements of the matrix.
* @return type of field elements of the matrix
*/
Field<T> getField();
/**
* Create a new FieldMatrix<T> of the same type as the instance with the supplied
* row and column dimensions.
*
* @param rowDimension the number of rows in the new matrix
* @param columnDimension the number of columns in the new matrix
* @return a new matrix of the same type as the instance
* @throws IllegalArgumentException if row or column dimension is not positive
* @since 2.0
*/
FieldMatrix<T> createMatrix(final int rowDimension, final int columnDimension);
/**
* Returns a (deep) copy of this.
*
* @return matrix copy
*/
FieldMatrix<T> copy();
/**
* Compute the sum of this and m.
*
* @param m matrix to be added
* @return this + m
* @throws IllegalArgumentException if m is not the same size as this
*/
FieldMatrix<T> add(FieldMatrix<T> m) throws IllegalArgumentException;
/**
* Compute this minus m.
*
* @param m matrix to be subtracted
* @return this + m
* @throws IllegalArgumentException if m is not the same size as this
*/
FieldMatrix<T> subtract(FieldMatrix<T> m) throws IllegalArgumentException;
/**
* Returns the result of adding d to each entry of this.
*
* @param d value to be added to each entry
* @return d + this
*/
FieldMatrix<T> scalarAdd(T d);
/**
* Returns the result multiplying each entry of this by d.
*
* @param d value to multiply all entries by
* @return d * this
*/
FieldMatrix<T> scalarMultiply(T d);
/**
* Returns the result of postmultiplying this by m.
*
* @param m matrix to postmultiply by
* @return this * m
* @throws IllegalArgumentException
* if columnDimension(this) != rowDimension(m)
*/
FieldMatrix<T> multiply(FieldMatrix<T> m) throws IllegalArgumentException;
/**
* Returns the result premultiplying this by <code>m</code>.
* @param m matrix to premultiply by
* @return m * this
* @throws IllegalArgumentException
* if rowDimension(this) != columnDimension(m)
*/
public FieldMatrix<T> preMultiply(FieldMatrix<T> m) throws IllegalArgumentException;
/**
* Returns matrix entries as a two-dimensional array.
*
* @return 2-dimensional array of entries
*/
T[][] getData();
/**
* Gets a submatrix. Rows and columns are indicated
* counting from 0 to n-1.
*
* @param startRow Initial row index
* @param endRow Final row index (inclusive)
* @param startColumn Initial column index
* @param endColumn Final column index (inclusive)
* @return The subMatrix containing the data of the
* specified rows and columns
* @exception MatrixIndexException if the indices are not valid
*/
FieldMatrix<T> getSubMatrix(int startRow, int endRow, int startColumn, int endColumn)
throws MatrixIndexException;
/**
* Gets a submatrix. Rows and columns are indicated
* counting from 0 to n-1.
*
* @param selectedRows Array of row indices.
* @param selectedColumns Array of column indices.
* @return The subMatrix containing the data in the
* specified rows and columns
* @exception MatrixIndexException if row or column selections are not valid
*/
FieldMatrix<T> getSubMatrix(int[] selectedRows, int[] selectedColumns)
throws MatrixIndexException;
/**
* Copy a submatrix. Rows and columns are indicated
* counting from 0 to n-1.
*
* @param startRow Initial row index
* @param endRow Final row index (inclusive)
* @param startColumn Initial column index
* @param endColumn Final column index (inclusive)
* @param destination The arrays where the submatrix data should be copied
* (if larger than rows/columns counts, only the upper-left part will be used)
* @exception MatrixIndexException if the indices are not valid
* @exception IllegalArgumentException if the destination array is too small
*/
void copySubMatrix(int startRow, int endRow, int startColumn, int endColumn,
T[][] destination)
throws MatrixIndexException, IllegalArgumentException;
/**
* Copy a submatrix. Rows and columns are indicated
* counting from 0 to n-1.
*
* @param selectedRows Array of row indices.
* @param selectedColumns Array of column indices.
* @param destination The arrays where the submatrix data should be copied
* (if larger than rows/columns counts, only the upper-left part will be used)
* @exception MatrixIndexException if the indices are not valid
* @exception IllegalArgumentException if the destination array is too small
*/
void copySubMatrix(int[] selectedRows, int[] selectedColumns, T[][] destination)
throws MatrixIndexException, IllegalArgumentException;
/**
* Replace the submatrix starting at <code>row, column</code> using data in
* the input <code>subMatrix</code> array. Indexes are 0-based.
* <p>
* Example:<br>
* Starting with <pre>
* 1 2 3 4
* 5 6 7 8
* 9 0 1 2
* </pre>
* and <code>subMatrix = {{3, 4} {5,6}}</code>, invoking
* <code>setSubMatrix(subMatrix,1,1))</code> will result in <pre>
* 1 2 3 4
* 5 3 4 8
* 9 5 6 2
* </pre></p>
*
* @param subMatrix array containing the submatrix replacement data
* @param row row coordinate of the top, left element to be replaced
* @param column column coordinate of the top, left element to be replaced
* @throws MatrixIndexException if subMatrix does not fit into this
* matrix from element in (row, column)
* @throws IllegalArgumentException if <code>subMatrix</code> is not rectangular
* (not all rows have the same length) or empty
* @throws NullPointerException if <code>subMatrix</code> is null
* @since 2.0
*/
void setSubMatrix(T[][] subMatrix, int row, int column)
throws MatrixIndexException;
/**
* Returns the entries in row number <code>row</code>
* as a row matrix. Row indices start at 0.
*
* @param row the row to be fetched
* @return row matrix
* @throws MatrixIndexException if the specified row index is invalid
*/
FieldMatrix<T> getRowMatrix(int row) throws MatrixIndexException;
/**
* Sets the entries in row number <code>row</code>
* as a row matrix. Row indices start at 0.
*
* @param row the row to be set
* @param matrix row matrix (must have one row and the same number of columns
* as the instance)
* @throws MatrixIndexException if the specified row index is invalid
* @throws InvalidMatrixException if the matrix dimensions do not match one
* instance row
*/
void setRowMatrix(int row, FieldMatrix<T> matrix)
throws MatrixIndexException, InvalidMatrixException;
/**
* Returns the entries in column number <code>column</code>
* as a column matrix. Column indices start at 0.
*
* @param column the column to be fetched
* @return column matrix
* @throws MatrixIndexException if the specified column index is invalid
*/
FieldMatrix<T> getColumnMatrix(int column) throws MatrixIndexException;
/**
* Sets the entries in column number <code>column</code>
* as a column matrix. Column indices start at 0.
*
* @param column the column to be set
* @param matrix column matrix (must have one column and the same number of rows
* as the instance)
* @throws MatrixIndexException if the specified column index is invalid
* @throws InvalidMatrixException if the matrix dimensions do not match one
* instance column
*/
void setColumnMatrix(int column, FieldMatrix<T> matrix)
throws MatrixIndexException, InvalidMatrixException;
/**
* Returns the entries in row number <code>row</code>
* as a vector. Row indices start at 0.
*
* @param row the row to be fetched
* @return row vector
* @throws MatrixIndexException if the specified row index is invalid
*/
FieldVector<T> getRowVector(int row) throws MatrixIndexException;
/**
* Sets the entries in row number <code>row</code>
* as a vector. Row indices start at 0.
*
* @param row the row to be set
* @param vector row vector (must have the same number of columns
* as the instance)
* @throws MatrixIndexException if the specified row index is invalid
* @throws InvalidMatrixException if the vector dimension does not match one
* instance row
*/
void setRowVector(int row, FieldVector<T> vector)
throws MatrixIndexException, InvalidMatrixException;
/**
* Returns the entries in column number <code>column</code>
* as a vector. Column indices start at 0.
*
* @param column the column to be fetched
* @return column vector
* @throws MatrixIndexException if the specified column index is invalid
*/
FieldVector<T> getColumnVector(int column) throws MatrixIndexException;
/**
* Sets the entries in column number <code>column</code>
* as a vector. Column indices start at 0.
*
* @param column the column to be set
* @param vector column vector (must have the same number of rows as the instance)
* @throws MatrixIndexException if the specified column index is invalid
* @throws InvalidMatrixException if the vector dimension does not match one
* instance column
*/
void setColumnVector(int column, FieldVector<T> vector)
throws MatrixIndexException, InvalidMatrixException;
/**
* Returns the entries in row number <code>row</code> as an array.
* <p>
* Row indices start at 0. A <code>MatrixIndexException</code> is thrown
* unless <code>0 <= row < rowDimension.</code></p>
*
* @param row the row to be fetched
* @return array of entries in the row
* @throws MatrixIndexException if the specified row index is not valid
*/
T[] getRow(int row) throws MatrixIndexException;
/**
* Sets the entries in row number <code>row</code>
* as a row matrix. Row indices start at 0.
*
* @param row the row to be set
* @param array row matrix (must have the same number of columns as the instance)
* @throws MatrixIndexException if the specified row index is invalid
* @throws InvalidMatrixException if the array size does not match one
* instance row
*/
void setRow(int row, T[] array)
throws MatrixIndexException, InvalidMatrixException;
/**
* Returns the entries in column number <code>col</code> as an array.
* <p>
* Column indices start at 0. A <code>MatrixIndexException</code> is thrown
* unless <code>0 <= column < columnDimension.</code></p>
*
* @param column the column to be fetched
* @return array of entries in the column
* @throws MatrixIndexException if the specified column index is not valid
*/
T[] getColumn(int column) throws MatrixIndexException;
/**
* Sets the entries in column number <code>column</code>
* as a column matrix. Column indices start at 0.
*
* @param column the column to be set
* @param array column array (must have the same number of rows as the instance)
* @throws MatrixIndexException if the specified column index is invalid
* @throws InvalidMatrixException if the array size does not match one
* instance column
*/
void setColumn(int column, T[] array)
throws MatrixIndexException, InvalidMatrixException;
/**
* Returns the entry in the specified row and column.
* <p>
* Row and column indices start at 0 and must satisfy
* <ul>
* <li><code>0 <= row < rowDimension</code></li>
* <li><code> 0 <= column < columnDimension</code></li>
* </ul>
* otherwise a <code>MatrixIndexException</code> is thrown.</p>
*
* @param row row location of entry to be fetched
* @param column column location of entry to be fetched
* @return matrix entry in row,column
* @throws MatrixIndexException if the row or column index is not valid
*/
T getEntry(int row, int column) throws MatrixIndexException;
/**
* Set the entry in the specified row and column.
* <p>
* Row and column indices start at 0 and must satisfy
* <ul>
* <li><code>0 <= row < rowDimension</code></li>
* <li><code> 0 <= column < columnDimension</code></li>
* </ul>
* otherwise a <code>MatrixIndexException</code> is thrown.</p>
*
* @param row row location of entry to be set
* @param column column location of entry to be set
* @param value matrix entry to be set in row,column
* @throws MatrixIndexException if the row or column index is not valid
* @since 2.0
*/
void setEntry(int row, int column, T value) throws MatrixIndexException;
/**
* Change an entry in the specified row and column.
* <p>
* Row and column indices start at 0 and must satisfy
* <ul>
* <li><code>0 <= row < rowDimension</code></li>
* <li><code> 0 <= column < columnDimension</code></li>
* </ul>
* otherwise a <code>MatrixIndexException</code> is thrown.</p>
*
* @param row row location of entry to be set
* @param column column location of entry to be set
* @param increment value to add to the current matrix entry in row,column
* @throws MatrixIndexException if the row or column index is not valid
* @since 2.0
*/
void addToEntry(int row, int column, T increment) throws MatrixIndexException;
/**
* Change an entry in the specified row and column.
* <p>
* Row and column indices start at 0 and must satisfy
* <ul>
* <li><code>0 <= row < rowDimension</code></li>
* <li><code> 0 <= column < columnDimension</code></li>
* </ul>
* otherwise a <code>MatrixIndexException</code> is thrown.</p>
*
* @param row row location of entry to be set
* @param column column location of entry to be set
* @param factor multiplication factor for the current matrix entry in row,column
* @throws MatrixIndexException if the row or column index is not valid
* @since 2.0
*/
void multiplyEntry(int row, int column, T factor) throws MatrixIndexException;
/**
* Returns the transpose of this matrix.
*
* @return transpose matrix
*/
FieldMatrix<T> transpose();
/**
* Is this a square matrix?
* @return true if the matrix is square (rowDimension = columnDimension)
*/
boolean isSquare();
/**
* Returns the number of rows in the matrix.
*
* @return rowDimension
*/
int getRowDimension();
/**
* Returns the number of columns in the matrix.
*
* @return columnDimension
*/
int getColumnDimension();
/**
* Returns the <a href="http://mathworld.wolfram.com/MatrixTrace.html">
* trace</a> of the matrix (the sum of the elements on the main diagonal).
*
* @return trace
* @throws NonSquareMatrixException if the matrix is not square
*/
T getTrace() throws NonSquareMatrixException;
/**
* Returns the result of multiplying this by the vector <code>v</code>.
*
* @param v the vector to operate on
* @return this*v
* @throws IllegalArgumentException if columnDimension != v.size()
*/
T[] operate(T[] v) throws IllegalArgumentException;
/**
* Returns the result of multiplying this by the vector <code>v</code>.
*
* @param v the vector to operate on
* @return this*v
* @throws IllegalArgumentException if columnDimension != v.size()
*/
FieldVector<T> operate(FieldVector<T> v) throws IllegalArgumentException;
/**
* Returns the (row) vector result of premultiplying this by the vector <code>v</code>.
*
* @param v the row vector to premultiply by
* @return v*this
* @throws IllegalArgumentException if rowDimension != v.size()
*/
T[] preMultiply(T[] v) throws IllegalArgumentException;
/**
* Returns the (row) vector result of premultiplying this by the vector <code>v</code>.
*
* @param v the row vector to premultiply by
* @return v*this
* @throws IllegalArgumentException if rowDimension != v.size()
*/
FieldVector<T> preMultiply(FieldVector<T> v) throws IllegalArgumentException;
/**
* Visit (and possibly change) all matrix entries in row order.
* <p>Row order starts at upper left and iterating through all elements
* of a row from left to right before going to the leftmost element
* of the next row.</p>
* @param visitor visitor used to process all matrix entries
* @exception MatrixVisitorException if the visitor cannot process an entry
* @see #walkInRowOrder(FieldMatrixPreservingVisitor)
* @see #walkInRowOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @return the value returned by {@link FieldMatrixChangingVisitor#end()} at the end
* of the walk
*/
T walkInRowOrder(FieldMatrixChangingVisitor<T> visitor)
throws MatrixVisitorException;
/**
* Visit (but don't change) all matrix entries in row order.
* <p>Row order starts at upper left and iterating through all elements
* of a row from left to right before going to the leftmost element
* of the next row.</p>
* @param visitor visitor used to process all matrix entries
* @exception MatrixVisitorException if the visitor cannot process an entry
* @see #walkInRowOrder(FieldMatrixChangingVisitor)
* @see #walkInRowOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @return the value returned by {@link FieldMatrixPreservingVisitor#end()} at the end
* of the walk
*/
T walkInRowOrder(FieldMatrixPreservingVisitor<T> visitor)
throws MatrixVisitorException;
/**
* Visit (and possibly change) some matrix entries in row order.
* <p>Row order starts at upper left and iterating through all elements
* of a row from left to right before going to the leftmost element
* of the next row.</p>
* @param visitor visitor used to process all matrix entries
* @param startRow Initial row index
* @param endRow Final row index (inclusive)
* @param startColumn Initial column index
* @param endColumn Final column index
* @exception MatrixVisitorException if the visitor cannot process an entry
* @exception MatrixIndexException if the indices are not valid
* @see #walkInRowOrder(FieldMatrixChangingVisitor)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @return the value returned by {@link FieldMatrixChangingVisitor#end()} at the end
* of the walk
*/
T walkInRowOrder(FieldMatrixChangingVisitor<T> visitor,
int startRow, int endRow, int startColumn, int endColumn)
throws MatrixIndexException, MatrixVisitorException;
/**
* Visit (but don't change) some matrix entries in row order.
* <p>Row order starts at upper left and iterating through all elements
* of a row from left to right before going to the leftmost element
* of the next row.</p>
* @param visitor visitor used to process all matrix entries
* @param startRow Initial row index
* @param endRow Final row index (inclusive)
* @param startColumn Initial column index
* @param endColumn Final column index
* @exception MatrixVisitorException if the visitor cannot process an entry
* @exception MatrixIndexException if the indices are not valid
* @see #walkInRowOrder(FieldMatrixChangingVisitor)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor)
* @see #walkInRowOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @return the value returned by {@link FieldMatrixPreservingVisitor#end()} at the end
* of the walk
*/
T walkInRowOrder(FieldMatrixPreservingVisitor<T> visitor,
int startRow, int endRow, int startColumn, int endColumn)
throws MatrixIndexException, MatrixVisitorException;
/**
* Visit (and possibly change) all matrix entries in column order.
* <p>Column order starts at upper left and iterating through all elements
* of a column from top to bottom before going to the topmost element
* of the next column.</p>
* @param visitor visitor used to process all matrix entries
* @exception MatrixVisitorException if the visitor cannot process an entry
* @see #walkInRowOrder(FieldMatrixChangingVisitor)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor)
* @see #walkInRowOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @return the value returned by {@link FieldMatrixChangingVisitor#end()} at the end
* of the walk
*/
T walkInColumnOrder(FieldMatrixChangingVisitor<T> visitor)
throws MatrixVisitorException;
/**
* Visit (but don't change) all matrix entries in column order.
* <p>Column order starts at upper left and iterating through all elements
* of a column from top to bottom before going to the topmost element
* of the next column.</p>
* @param visitor visitor used to process all matrix entries
* @exception MatrixVisitorException if the visitor cannot process an entry
* @see #walkInRowOrder(FieldMatrixChangingVisitor)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor)
* @see #walkInRowOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @return the value returned by {@link FieldMatrixPreservingVisitor#end()} at the end
* of the walk
*/
T walkInColumnOrder(FieldMatrixPreservingVisitor<T> visitor)
throws MatrixVisitorException;
/**
* Visit (and possibly change) some matrix entries in column order.
* <p>Column order starts at upper left and iterating through all elements
* of a column from top to bottom before going to the topmost element
* of the next column.</p>
* @param visitor visitor used to process all matrix entries
* @param startRow Initial row index
* @param endRow Final row index (inclusive)
* @param startColumn Initial column index
* @param endColumn Final column index
* @exception MatrixVisitorException if the visitor cannot process an entry
* @exception MatrixIndexException if the indices are not valid
* @see #walkInRowOrder(FieldMatrixChangingVisitor)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor)
* @see #walkInRowOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @return the value returned by {@link FieldMatrixChangingVisitor#end()} at the end
* of the walk
*/
T walkInColumnOrder(FieldMatrixChangingVisitor<T> visitor,
int startRow, int endRow, int startColumn, int endColumn)
throws MatrixIndexException, MatrixVisitorException;
/**
* Visit (but don't change) some matrix entries in column order.
* <p>Column order starts at upper left and iterating through all elements
* of a column from top to bottom before going to the topmost element
* of the next column.</p>
* @param visitor visitor used to process all matrix entries
* @param startRow Initial row index
* @param endRow Final row index (inclusive)
* @param startColumn Initial column index
* @param endColumn Final column index
* @exception MatrixVisitorException if the visitor cannot process an entry
* @exception MatrixIndexException if the indices are not valid
* @see #walkInRowOrder(FieldMatrixChangingVisitor)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor)
* @see #walkInRowOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @return the value returned by {@link FieldMatrixPreservingVisitor#end()} at the end
* of the walk
*/
T walkInColumnOrder(FieldMatrixPreservingVisitor<T> visitor,
int startRow, int endRow, int startColumn, int endColumn)
throws MatrixIndexException, MatrixVisitorException;
/**
* Visit (and possibly change) all matrix entries using the fastest possible order.
* <p>The fastest walking order depends on the exact matrix class. It may be
* different from traditional row or column orders.</p>
* @param visitor visitor used to process all matrix entries
* @exception MatrixVisitorException if the visitor cannot process an entry
* @see #walkInRowOrder(FieldMatrixChangingVisitor)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor)
* @see #walkInRowOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @return the value returned by {@link FieldMatrixChangingVisitor#end()} at the end
* of the walk
*/
T walkInOptimizedOrder(FieldMatrixChangingVisitor<T> visitor)
throws MatrixVisitorException;
/**
* Visit (but don't change) all matrix entries using the fastest possible order.
* <p>The fastest walking order depends on the exact matrix class. It may be
* different from traditional row or column orders.</p>
* @param visitor visitor used to process all matrix entries
* @exception MatrixVisitorException if the visitor cannot process an entry
* @see #walkInRowOrder(FieldMatrixChangingVisitor)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor)
* @see #walkInRowOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @return the value returned by {@link FieldMatrixPreservingVisitor#end()} at the end
* of the walk
*/
T walkInOptimizedOrder(FieldMatrixPreservingVisitor<T> visitor)
throws MatrixVisitorException;
/**
* Visit (and possibly change) some matrix entries using the fastest possible order.
* <p>The fastest walking order depends on the exact matrix class. It may be
* different from traditional row or column orders.</p>
* @param visitor visitor used to process all matrix entries
* @param startRow Initial row index
* @param endRow Final row index (inclusive)
* @param startColumn Initial column index
* @param endColumn Final column index (inclusive)
* @exception MatrixVisitorException if the visitor cannot process an entry
* @exception MatrixIndexException if the indices are not valid
* @see #walkInRowOrder(FieldMatrixChangingVisitor)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor)
* @see #walkInRowOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @return the value returned by {@link FieldMatrixChangingVisitor#end()} at the end
* of the walk
*/
T walkInOptimizedOrder(FieldMatrixChangingVisitor<T> visitor,
int startRow, int endRow, int startColumn, int endColumn)
throws MatrixIndexException, MatrixVisitorException;
/**
* Visit (but don't change) some matrix entries using the fastest possible order.
* <p>The fastest walking order depends on the exact matrix class. It may be
* different from traditional row or column orders.</p>
* @param visitor visitor used to process all matrix entries
* @param startRow Initial row index
* @param endRow Final row index (inclusive)
* @param startColumn Initial column index
* @param endColumn Final column index (inclusive)
* @exception MatrixVisitorException if the visitor cannot process an entry
* @exception MatrixIndexException if the indices are not valid
* @see #walkInRowOrder(FieldMatrixChangingVisitor)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor)
* @see #walkInRowOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInRowOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor)
* @see #walkInColumnOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @see #walkInColumnOrder(FieldMatrixPreservingVisitor, int, int, int, int)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixPreservingVisitor)
* @see #walkInOptimizedOrder(FieldMatrixChangingVisitor, int, int, int, int)
* @return the value returned by {@link FieldMatrixPreservingVisitor#end()} at the end
* of the walk
*/
T walkInOptimizedOrder(FieldMatrixPreservingVisitor<T> visitor,
int startRow, int endRow, int startColumn, int endColumn)
throws MatrixIndexException, MatrixVisitorException;
}

View File

@ -0,0 +1,64 @@
/*
* 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.commons.math.linear;
import java.io.Serializable;
import org.apache.commons.math.FieldElement;
/**
* Interface defining a visitor for matrix entries.
*
* @param <T> the type of the field elements
* @version $Revision$ $Date$
* @since 2.0
*/
public interface FieldMatrixChangingVisitor<T extends FieldElement<?>> extends Serializable {
/**
* Start visiting a matrix.
* <p>This method is called once before any entry of the matrix is visited.</p>
* @param rows number of rows of the matrix
* @param columns number of columns of the matrix
* @param startRow Initial row index
* @param endRow Final row index (inclusive)
* @param startColumn Initial column index
* @param endColumn Final column index (inclusive)
*/
void start(int rows, int columns,
int startRow, int endRow, int startColumn, int endColumn);
/**
* Visit one matrix entry.
* @param row row index of the entry
* @param column column index of the entry
* @param value current value of the entry
* @return the new value to be set for the entry
* @throws MatrixVisitorException if something wrong occurs
*/
T visit(int row, int column, T value)
throws MatrixVisitorException;
/**
* End visiting a matrix.
* <p>This method is called once after all entries of the matrix have been visited.</p>
* @return the value that the <code>walkInXxxOrder</code> must return
*/
T end();
}

View File

@ -0,0 +1,655 @@
/*
* 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.commons.math.linear;
import java.util.Arrays;
import org.apache.commons.math.Field;
import org.apache.commons.math.FieldElement;
import org.apache.commons.math.MathRuntimeException;
/**
* Implementation of FieldMatrix<T> using a {@link FieldElement}[][] array to store entries.
* <p>
* As specified in the {@link FieldMatrix} interface, matrix element indexing
* is 0-based -- e.g., <code>getEntry(0, 0)</code>
* returns the element in the first row, first column of the matrix.</li></ul>
* </p>
*
* @param <T> the type of the field elements
* @version $Revision$ $Date$
*/
public class FieldMatrixImpl<T extends FieldElement<T>> extends AbstractFieldMatrix<T> {
/** Serializable version identifier */
private static final long serialVersionUID = 7260756672015356458L;
/** Entries of the matrix */
protected T[][] data;
/**
* Get the elements type from an array.
* @param d data array
* @return field to which array elements belong
* @exception IllegalArgumentException if array is empty
*/
private static Field<? extends FieldElement<?>> extractField(final FieldElement<? extends FieldElement<?>>[][] d)
throws IllegalArgumentException {
if (d.length == 0) {
throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one row");
}
if (d[0].length == 0) {
throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one column");
}
return d[0][0].getField();
}
/**
* Get the elements type from an array.
* @param d data array
* @return field to which array elements belong
* @exception IllegalArgumentException if array is empty
*/
private static Field<? extends FieldElement<?>> extractField(final FieldElement<? extends FieldElement<?>>[] d)
throws IllegalArgumentException {
if (d.length == 0) {
throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one row");
}
return d[0].getField();
}
/**
* Creates a matrix with no data
* @param field field to which the elements belong
*/
public FieldMatrixImpl(final Field<T> field) {
super(field);
}
/**
* Create a new FieldMatrix<T> with the supplied row and column dimensions.
*
* @param field field to which the elements belong
* @param rowDimension the number of rows in the new matrix
* @param columnDimension the number of columns in the new matrix
* @throws IllegalArgumentException if row or column dimension is not
* positive
*/
public FieldMatrixImpl(final Field<T> field,
final int rowDimension, final int columnDimension)
throws IllegalArgumentException {
super(field, rowDimension, columnDimension);
data = buildArray(rowDimension, columnDimension);
final T zero = field.getZero();
for (int i = 0; i < rowDimension; ++i) {
Arrays.fill(data[i], zero);
}
}
/**
* Create a new FieldMatrix<T> using the input array as the underlying
* data array.
* <p>The input array is copied, not referenced. This constructor has
* the same effect as calling {@link #FieldMatrixImpl(T[][], boolean)}
* with the second argument set to <code>true</code>.</p>
*
* @param d data for new matrix
* @throws IllegalArgumentException if <code>d</code> is not rectangular
* (not all rows have the same length) or empty
* @throws NullPointerException if <code>d</code> is null
* @see #FieldMatrixImpl(T[][], boolean)
*/
@SuppressWarnings("unchecked")
public FieldMatrixImpl(final T[][] d)
throws IllegalArgumentException, NullPointerException {
super((Field<T>) extractField(d));
copyIn(d);
}
/**
* Create a new FieldMatrix<T> using the input array as the underlying
* data array.
* <p>If an array is built specially in order to be embedded in a
* FieldMatrix<T> and not used directly, the <code>copyArray</code> may be
* set to <code>false</code. This will prevent the copying and improve
* performance as no new array will be built and no data will be copied.</p>
* @param d data for new matrix
* @param copyArray if true, the input array will be copied, otherwise
* it will be referenced
* @throws IllegalArgumentException if <code>d</code> is not rectangular
* (not all rows have the same length) or empty
* @throws NullPointerException if <code>d</code> is null
* @see #FieldMatrixImpl(T[][])
*/
@SuppressWarnings("unchecked")
public FieldMatrixImpl(final T[][] d, final boolean copyArray)
throws IllegalArgumentException, NullPointerException {
super((Field<T>) extractField(d));
if (copyArray) {
copyIn(d);
} else {
if (d == null) {
throw new NullPointerException();
}
final int nRows = d.length;
if (nRows == 0) {
throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one row");
}
final int nCols = d[0].length;
if (nCols == 0) {
throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one column");
}
for (int r = 1; r < nRows; r++) {
if (d[r].length != nCols) {
throw MathRuntimeException.createIllegalArgumentException(
"some rows have length {0} while others have length {1}",
nCols, d[r].length);
}
}
data = d;
}
}
/**
* Create a new (column) FieldMatrix<T> using <code>v</code> as the
* data for the unique column of the <code>v.length x 1</code> matrix
* created.
* <p>The input array is copied, not referenced.</p>
*
* @param v column vector holding data for new matrix
*/
@SuppressWarnings("unchecked")
public FieldMatrixImpl(final T[] v) {
super((Field<T>) extractField(v));
final int nRows = v.length;
data = buildArray(nRows, 1);
for (int row = 0; row < nRows; row++) {
data[row][0] = v[row];
}
}
/** {@inheritDoc} */
@Override
public FieldMatrix<T> createMatrix(final int rowDimension, final int columnDimension)
throws IllegalArgumentException {
return new FieldMatrixImpl<T>(getField(), rowDimension, columnDimension);
}
/** {@inheritDoc} */
@Override
public FieldMatrix<T> copy() {
return new FieldMatrixImpl<T>(copyOut(), false);
}
/** {@inheritDoc} */
@Override
public FieldMatrix<T> add(final FieldMatrix<T> m)
throws IllegalArgumentException {
try {
return add((FieldMatrixImpl<T>) m);
} catch (ClassCastException cce) {
return super.add(m);
}
}
/**
* Compute the sum of this and <code>m</code>.
*
* @param m matrix to be added
* @return this + m
* @throws IllegalArgumentException if m is not the same size as this
*/
public FieldMatrixImpl<T> add(final FieldMatrixImpl<T> m)
throws IllegalArgumentException {
// safety check
checkAdditionCompatible(m);
final int rowCount = getRowDimension();
final int columnCount = getColumnDimension();
final T[][] outData = buildArray(rowCount, columnCount);
for (int row = 0; row < rowCount; row++) {
final T[] dataRow = data[row];
final T[] mRow = m.data[row];
final T[] outDataRow = outData[row];
for (int col = 0; col < columnCount; col++) {
outDataRow[col] = dataRow[col].add(mRow[col]);
}
}
return new FieldMatrixImpl<T>(outData, false);
}
/** {@inheritDoc} */
@Override
public FieldMatrix<T> subtract(final FieldMatrix<T> m)
throws IllegalArgumentException {
try {
return subtract((FieldMatrixImpl<T>) m);
} catch (ClassCastException cce) {
return super.subtract(m);
}
}
/**
* Compute this minus <code>m</code>.
*
* @param m matrix to be subtracted
* @return this + m
* @throws IllegalArgumentException if m is not the same size as this
*/
public FieldMatrixImpl<T> subtract(final FieldMatrixImpl<T> m)
throws IllegalArgumentException {
// safety check
checkSubtractionCompatible(m);
final int rowCount = getRowDimension();
final int columnCount = getColumnDimension();
final T[][] outData = buildArray(rowCount, columnCount);
for (int row = 0; row < rowCount; row++) {
final T[] dataRow = data[row];
final T[] mRow = m.data[row];
final T[] outDataRow = outData[row];
for (int col = 0; col < columnCount; col++) {
outDataRow[col] = dataRow[col].subtract(mRow[col]);
}
}
return new FieldMatrixImpl<T>(outData, false);
}
/** {@inheritDoc} */
@Override
public FieldMatrix<T> multiply(final FieldMatrix<T> m)
throws IllegalArgumentException {
try {
return multiply((FieldMatrixImpl<T>) m);
} catch (ClassCastException cce) {
return super.multiply(m);
}
}
/**
* Returns the result of postmultiplying this by <code>m</code>.
* @param m matrix to postmultiply by
* @return this*m
* @throws IllegalArgumentException
* if columnDimension(this) != rowDimension(m)
*/
public FieldMatrixImpl<T> multiply(final FieldMatrixImpl<T> m)
throws IllegalArgumentException {
// safety check
checkMultiplicationCompatible(m);
final int nRows = this.getRowDimension();
final int nCols = m.getColumnDimension();
final int nSum = this.getColumnDimension();
final T[][] outData = buildArray(nRows, nCols);
for (int row = 0; row < nRows; row++) {
final T[] dataRow = data[row];
final T[] outDataRow = outData[row];
for (int col = 0; col < nCols; col++) {
T sum = getField().getZero();
for (int i = 0; i < nSum; i++) {
sum = sum.add(dataRow[i].multiply(m.data[i][col]));
}
outDataRow[col] = sum;
}
}
return new FieldMatrixImpl<T>(outData, false);
}
/** {@inheritDoc} */
@Override
public T[][] getData() {
return copyOut();
}
/**
* Returns a reference to the underlying data array.
* <p>
* Does <strong>not</strong> make a fresh copy of the underlying data.</p>
*
* @return 2-dimensional array of entries
*/
public T[][] getDataRef() {
return data;
}
/** {@inheritDoc} */
@Override
public void setSubMatrix(final T[][] subMatrix, final int row, final int column)
throws MatrixIndexException {
if (data == null) {
if (row > 0) {
throw MathRuntimeException.createIllegalStateException(
"first {0} rows are not initialized yet",
row);
}
if (column > 0) {
throw MathRuntimeException.createIllegalStateException(
"first {0} columns are not initialized yet",
column);
}
final int nRows = subMatrix.length;
if (nRows == 0) {
throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one row");
}
final int nCols = subMatrix[0].length;
if (nCols == 0) {
throw MathRuntimeException.createIllegalArgumentException("matrix must have at least one column");
}
data = buildArray(subMatrix.length, nCols);
for (int i = 0; i < data.length; ++i) {
if (subMatrix[i].length != nCols) {
throw MathRuntimeException.createIllegalArgumentException(
"some rows have length {0} while others have length {1}",
nCols, subMatrix[i].length);
}
System.arraycopy(subMatrix[i], 0, data[i + row], column, nCols);
}
} else {
super.setSubMatrix(subMatrix, row, column);
}
}
/** {@inheritDoc} */
@Override
public T getEntry(final int row, final int column)
throws MatrixIndexException {
try {
return data[row][column];
} catch (ArrayIndexOutOfBoundsException e) {
throw new MatrixIndexException(
"no entry at indices ({0}, {1}) in a {2}x{3} matrix",
row, column, getRowDimension(), getColumnDimension());
}
}
/** {@inheritDoc} */
@Override
public void setEntry(final int row, final int column, final T value)
throws MatrixIndexException {
try {
data[row][column] = value;
} catch (ArrayIndexOutOfBoundsException e) {
throw new MatrixIndexException(
"no entry at indices ({0}, {1}) in a {2}x{3} matrix",
row, column, getRowDimension(), getColumnDimension());
}
}
/** {@inheritDoc} */
@Override
public void addToEntry(final int row, final int column, final T increment)
throws MatrixIndexException {
try {
data[row][column] = data[row][column].add(increment);
} catch (ArrayIndexOutOfBoundsException e) {
throw new MatrixIndexException(
"no entry at indices ({0}, {1}) in a {2}x{3} matrix",
row, column, getRowDimension(), getColumnDimension());
}
}
/** {@inheritDoc} */
@Override
public void multiplyEntry(final int row, final int column, final T factor)
throws MatrixIndexException {
try {
data[row][column] = data[row][column].multiply(factor);
} catch (ArrayIndexOutOfBoundsException e) {
throw new MatrixIndexException(
"no entry at indices ({0}, {1}) in a {2}x{3} matrix",
row, column, getRowDimension(), getColumnDimension());
}
}
/** {@inheritDoc} */
@Override
public int getRowDimension() {
return (data == null) ? 0 : data.length;
}
/** {@inheritDoc} */
@Override
public int getColumnDimension() {
return ((data == null) || (data[0] == null)) ? 0 : data[0].length;
}
/** {@inheritDoc} */
@Override
public T[] operate(final T[] v)
throws IllegalArgumentException {
final int nRows = this.getRowDimension();
final int nCols = this.getColumnDimension();
if (v.length != nCols) {
throw MathRuntimeException.createIllegalArgumentException(
"vector length mismatch: got {0} but expected {1}",
v.length, nCols);
}
final T[] out = buildArray(nRows);
for (int row = 0; row < nRows; row++) {
final T[] dataRow = data[row];
T sum = getField().getZero();
for (int i = 0; i < nCols; i++) {
sum = sum.add(dataRow[i].multiply(v[i]));
}
out[row] = sum;
}
return out;
}
/** {@inheritDoc} */
@Override
public T[] preMultiply(final T[] v)
throws IllegalArgumentException {
final int nRows = getRowDimension();
final int nCols = getColumnDimension();
if (v.length != nRows) {
throw MathRuntimeException.createIllegalArgumentException(
"vector length mismatch: got {0} but expected {1}",
v.length, nRows);
}
final T[] out = buildArray(nCols);
for (int col = 0; col < nCols; ++col) {
T sum = getField().getZero();
for (int i = 0; i < nRows; ++i) {
sum = sum.add(data[i][col].multiply(v[i]));
}
out[col] = sum;
}
return out;
}
/** {@inheritDoc} */
@Override
public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor)
throws MatrixVisitorException {
final int rows = getRowDimension();
final int columns = getColumnDimension();
visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
for (int i = 0; i < rows; ++i) {
final T[] rowI = data[i];
for (int j = 0; j < columns; ++j) {
rowI[j] = visitor.visit(i, j, rowI[j]);
}
}
return visitor.end();
}
/** {@inheritDoc} */
@Override
public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor)
throws MatrixVisitorException {
final int rows = getRowDimension();
final int columns = getColumnDimension();
visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
for (int i = 0; i < rows; ++i) {
final T[] rowI = data[i];
for (int j = 0; j < columns; ++j) {
visitor.visit(i, j, rowI[j]);
}
}
return visitor.end();
}
/** {@inheritDoc} */
@Override
public T walkInRowOrder(final FieldMatrixChangingVisitor<T> visitor,
final int startRow, final int endRow,
final int startColumn, final int endColumn)
throws MatrixIndexException, MatrixVisitorException {
checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
visitor.start(getRowDimension(), getColumnDimension(),
startRow, endRow, startColumn, endColumn);
for (int i = startRow; i <= endRow; ++i) {
final T[] rowI = data[i];
for (int j = startColumn; j <= endColumn; ++j) {
rowI[j] = visitor.visit(i, j, rowI[j]);
}
}
return visitor.end();
}
/** {@inheritDoc} */
@Override
public T walkInRowOrder(final FieldMatrixPreservingVisitor<T> visitor,
final int startRow, final int endRow,
final int startColumn, final int endColumn)
throws MatrixIndexException, MatrixVisitorException {
checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
visitor.start(getRowDimension(), getColumnDimension(),
startRow, endRow, startColumn, endColumn);
for (int i = startRow; i <= endRow; ++i) {
final T[] rowI = data[i];
for (int j = startColumn; j <= endColumn; ++j) {
visitor.visit(i, j, rowI[j]);
}
}
return visitor.end();
}
/** {@inheritDoc} */
@Override
public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor)
throws MatrixVisitorException {
final int rows = getRowDimension();
final int columns = getColumnDimension();
visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
for (int j = 0; j < columns; ++j) {
for (int i = 0; i < rows; ++i) {
final T[] rowI = data[i];
rowI[j] = visitor.visit(i, j, rowI[j]);
}
}
return visitor.end();
}
/** {@inheritDoc} */
@Override
public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor)
throws MatrixVisitorException {
final int rows = getRowDimension();
final int columns = getColumnDimension();
visitor.start(rows, columns, 0, rows - 1, 0, columns - 1);
for (int j = 0; j < columns; ++j) {
for (int i = 0; i < rows; ++i) {
visitor.visit(i, j, data[i][j]);
}
}
return visitor.end();
}
/** {@inheritDoc} */
@Override
public T walkInColumnOrder(final FieldMatrixChangingVisitor<T> visitor,
final int startRow, final int endRow,
final int startColumn, final int endColumn)
throws MatrixIndexException, MatrixVisitorException {
checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
visitor.start(getRowDimension(), getColumnDimension(),
startRow, endRow, startColumn, endColumn);
for (int j = startColumn; j <= endColumn; ++j) {
for (int i = startRow; i <= endRow; ++i) {
final T[] rowI = data[i];
rowI[j] = visitor.visit(i, j, rowI[j]);
}
}
return visitor.end();
}
/** {@inheritDoc} */
@Override
public T walkInColumnOrder(final FieldMatrixPreservingVisitor<T> visitor,
final int startRow, final int endRow,
final int startColumn, final int endColumn)
throws MatrixIndexException, MatrixVisitorException {
checkSubMatrixIndex(startRow, endRow, startColumn, endColumn);
visitor.start(getRowDimension(), getColumnDimension(),
startRow, endRow, startColumn, endColumn);
for (int j = startColumn; j <= endColumn; ++j) {
for (int i = startRow; i <= endRow; ++i) {
visitor.visit(i, j, data[i][j]);
}
}
return visitor.end();
}
/**
* Returns a fresh copy of the underlying data array.
*
* @return a copy of the underlying data array.
*/
private T[][] copyOut() {
final int nRows = this.getRowDimension();
final T[][] out = buildArray(nRows, getColumnDimension());
// can't copy 2-d array in one shot, otherwise get row references
for (int i = 0; i < nRows; i++) {
System.arraycopy(data[i], 0, out[i], 0, data[i].length);
}
return out;
}
/**
* Replaces data with a fresh copy of the input array.
* <p>
* Verifies that the input array is rectangular and non-empty.</p>
*
* @param in data to copy in
* @throws IllegalArgumentException if input array is empty or not
* rectangular
* @throws NullPointerException if input array is null
*/
private void copyIn(final T[][] in) {
setSubMatrix(in, 0, 0);
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.commons.math.linear;
import java.io.Serializable;
import org.apache.commons.math.FieldElement;
/**
* Interface defining a visitor for matrix entries.
*
* @param <T> the type of the field elements
* @version $Revision$ $Date$
* @since 2.0
*/
public interface FieldMatrixPreservingVisitor<T extends FieldElement<?>> extends Serializable {
/**
* Start visiting a matrix.
* <p>This method is called once before any entry of the matrix is visited.</p>
* @param rows number of rows of the matrix
* @param columns number of columns of the matrix
* @param startRow Initial row index
* @param endRow Final row index (inclusive)
* @param startColumn Initial column index
* @param endColumn Final column index (inclusive)
*/
void start(int rows, int columns,
int startRow, int endRow, int startColumn, int endColumn);
/**
* Visit one matrix entry.
* @param row row index of the entry
* @param column column index of the entry
* @param value current value of the entry
* @throws MatrixVisitorException if something wrong occurs
*/
void visit(int row, int column, T value)
throws MatrixVisitorException;
/**
* End visiting a matrix.
* <p>This method is called once after all entries of the matrix have been visited.</p>
* @return the value that the <code>walkInXxxOrder</code> must return
*/
T end();
}

View File

@ -0,0 +1,364 @@
/*
* 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.commons.math.linear;
import java.io.Serializable;
import org.apache.commons.math.Field;
import org.apache.commons.math.FieldElement;
/**
* Interface defining a field-valued vector with basic algebraic operations.
* <p>
* vector element indexing is 0-based -- e.g., <code>getEntry(0)</code>
* returns the first element of the vector.
* </p>
* <p>
* The various <code>mapXxx</code> and <code>mapXxxToSelf</code> methods operate
* on vectors element-wise, i.e. they perform the same operation (adding a scalar,
* applying a function ...) on each element in turn. The <code>mapXxx</code>
* versions create a new vector to hold the result and do not change the instance.
* The <code>mapXxxToSelf</code> versions use the instance itself to store the
* results, so the instance is changed by these methods. In both cases, the result
* vector is returned by the methods, this allows to use the <i>fluent API</i>
* style, like this:
* </p>
* <pre>
* RealVector result = v.mapAddToSelf(3.0).mapTanToSelf().mapSquareToSelf();
* </pre>
*
* @param <T> the type of the field elements
* @version $Revision$ $Date$
* @since 2.0
*/
public interface FieldVector<T extends FieldElement<T>> extends Serializable {
/**
* Get the type of field elements of the vector.
* @return type of field elements of the vector
*/
Field<T> getField();
/**
* Returns a (deep) copy of this.
* @return vector copy
*/
FieldVector<T> copy();
/**
* Compute the sum of this and v.
* @param v vector to be added
* @return this + v
* @throws IllegalArgumentException if v is not the same size as this
*/
FieldVector<T> add(FieldVector<T> v)
throws IllegalArgumentException;
/**
* Compute the sum of this and v.
* @param v vector to be added
* @return this + v
* @throws IllegalArgumentException if v is not the same size as this
*/
FieldVector<T> add(T[] v)
throws IllegalArgumentException;
/**
* Compute this minus v.
* @param v vector to be subtracted
* @return this + v
* @throws IllegalArgumentException if v is not the same size as this
*/
FieldVector<T> subtract(FieldVector<T> v)
throws IllegalArgumentException;
/**
* Compute this minus v.
* @param v vector to be subtracted
* @return this + v
* @throws IllegalArgumentException if v is not the same size as this
*/
FieldVector<T> subtract(T[] v)
throws IllegalArgumentException;
/**
* Map an addition operation to each entry.
* @param d value to be added to each entry
* @return this + d
*/
FieldVector<T> mapAdd(T d);
/**
* Map an addition operation to each entry.
* <p>The instance <strong>is</strong> changed by this method.</p>
* @param d value to be added to each entry
* @return for convenience, return this
*/
FieldVector<T> mapAddToSelf(T d);
/**
* Map a subtraction operation to each entry.
* @param d value to be subtracted to each entry
* @return this - d
*/
FieldVector<T> mapSubtract(T d);
/**
* Map a subtraction operation to each entry.
* <p>The instance <strong>is</strong> changed by this method.</p>
* @param d value to be subtracted to each entry
* @return for convenience, return this
*/
FieldVector<T> mapSubtractToSelf(T d);
/**
* Map a multiplication operation to each entry.
* @param d value to multiply all entries by
* @return this * d
*/
FieldVector<T> mapMultiply(T d);
/**
* Map a multiplication operation to each entry.
* <p>The instance <strong>is</strong> changed by this method.</p>
* @param d value to multiply all entries by
* @return for convenience, return this
*/
FieldVector<T> mapMultiplyToSelf(T d);
/**
* Map a division operation to each entry.
* @param d value to divide all entries by
* @return this / d
*/
FieldVector<T> mapDivide(T d);
/**
* Map a division operation to each entry.
* <p>The instance <strong>is</strong> changed by this method.</p>
* @param d value to divide all entries by
* @return for convenience, return this
*/
FieldVector<T> mapDivideToSelf(T d);
/**
* Map the 1/x function to each entry.
* @return a vector containing the result of applying the function to each entry
*/
FieldVector<T> mapInv();
/**
* Map the 1/x function to each entry.
* <p>The instance <strong>is</strong> changed by this method.</p>
* @return for convenience, return this
*/
FieldVector<T> mapInvToSelf();
/**
* Element-by-element multiplication.
* @param v vector by which instance elements must be multiplied
* @return a vector containing this[i] * v[i] for all i
* @throws IllegalArgumentException if v is not the same size as this
*/
public FieldVector<T> ebeMultiply(FieldVector<T> v)
throws IllegalArgumentException;
/**
* Element-by-element multiplication.
* @param v vector by which instance elements must be multiplied
* @return a vector containing this[i] * v[i] for all i
* @throws IllegalArgumentException if v is not the same size as this
*/
public FieldVector<T> ebeMultiply(T[] v)
throws IllegalArgumentException;
/**
* Element-by-element division.
* @param v vector by which instance elements must be divided
* @return a vector containing this[i] / v[i] for all i
* @throws IllegalArgumentException if v is not the same size as this
*/
public FieldVector<T> ebeDivide(FieldVector<T> v)
throws IllegalArgumentException;
/**
* Element-by-element division.
* @param v vector by which instance elements must be divided
* @return a vector containing this[i] / v[i] for all i
* @throws IllegalArgumentException if v is not the same size as this
*/
public FieldVector<T> ebeDivide(T[] v)
throws IllegalArgumentException;
/**
* Returns vector entries as a T array.
* @return T array of entries
*/
T[] getData();
/**
* Compute the dot product.
* @param v vector with which dot product should be computed
* @return the scalar dot product between instance and v
* @exception IllegalArgumentException if v is not the same size as this
*/
T dotProduct(FieldVector<T> v)
throws IllegalArgumentException;
/**
* Compute the dot product.
* @param v vector with which dot product should be computed
* @return the scalar dot product between instance and v
* @exception IllegalArgumentException if v is not the same size as this
*/
T dotProduct(T[] v)
throws IllegalArgumentException;
/** Find the orthogonal projection of this vector onto another vector.
* @param v vector onto which instance must be projected
* @return projection of the instance onto v
* @throws IllegalArgumentException if v is not the same size as this
*/
FieldVector<T> projection(FieldVector<T> v)
throws IllegalArgumentException;
/** Find the orthogonal projection of this vector onto another vector.
* @param v vector onto which instance must be projected
* @return projection of the instance onto v
* @throws IllegalArgumentException if v is not the same size as this
*/
FieldVector<T> projection(T[] v)
throws IllegalArgumentException;
/**
* Compute the outer product.
* @param v vector with which outer product should be computed
* @return the square matrix outer product between instance and v
* @exception IllegalArgumentException if v is not the same size as this
*/
FieldMatrix<T> outerProduct(FieldVector<T> v)
throws IllegalArgumentException;
/**
* Compute the outer product.
* @param v vector with which outer product should be computed
* @return the square matrix outer product between instance and v
* @exception IllegalArgumentException if v is not the same size as this
*/
FieldMatrix<T> outerProduct(T[] v)
throws IllegalArgumentException;
/**
* Returns the entry in the specified index.
* <p>
* The index start at 0 and must be lesser than the size,
* otherwise a {@link MatrixIndexException} is thrown.
* </p>
* @param index index location of entry to be fetched
* @return vector entry at index
* @throws MatrixIndexException if the index is not valid
* @see #setEntry(int, T)
*/
T getEntry(int index)
throws MatrixIndexException;
/**
* Set a single element.
* @param index element index.
* @param value new value for the element.
* @exception MatrixIndexException if the index is
* inconsistent with vector size
* @see #getEntry(int)
*/
void setEntry(int index, T value)
throws MatrixIndexException;
/**
* Returns the size of the vector.
* @return size
*/
int getDimension();
/**
* Construct a vector by appending a vector to this vector.
* @param v vector to append to this one.
* @return a new vector
*/
FieldVector<T> append(FieldVector<T> v);
/**
* Construct a vector by appending a T to this vector.
* @param d T to append.
* @return a new vector
*/
FieldVector<T> append(T d);
/**
* Construct a vector by appending a T array to this vector.
* @param a T array to append.
* @return a new vector
*/
FieldVector<T> append(T[] a);
/**
* Get a subvector from consecutive elements.
* @param index index of first element.
* @param n number of elements to be retrieved.
* @return a vector containing n elements.
* @exception MatrixIndexException if the index is
* inconsistent with vector size
*/
FieldVector<T> getSubVector(int index, int n)
throws MatrixIndexException;
/**
* Set a set of consecutive elements.
* @param index index of first element to be set.
* @param v vector containing the values to set.
* @exception MatrixIndexException if the index is
* inconsistent with vector size
* @see #setSubVector(int, T[])
*/
void setSubVector(int index, FieldVector<T> v)
throws MatrixIndexException;
/**
* Set a set of consecutive elements.
* @param index index of first element to be set.
* @param v vector containing the values to set.
* @exception MatrixIndexException if the index is
* inconsistent with vector size
* @see #setSubVector(int, FieldVector)
*/
void setSubVector(int index, T[] v)
throws MatrixIndexException;
/**
* Set all elements to a single value.
* @param value single value to set for all elements
*/
void set(T value);
/**
* Convert the vector to a T array.
* <p>The array is independent from vector data, it's elements
* are copied.</p>
* @return array containing a copy of vector elements
*/
T[] toArray();
}

View File

@ -0,0 +1,802 @@
/*
* 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.commons.math.linear;
import java.lang.reflect.Array;
import java.util.Arrays;
import org.apache.commons.math.Field;
import org.apache.commons.math.FieldElement;
import org.apache.commons.math.MathRuntimeException;
/**
* This class implements the {@link FieldVector<T>} interface with a {@link FieldElement} array.
* @param <T> the type of the field elements
* @version $Revision$ $Date$
* @since 2.0
*/
public class FieldVectorImpl<T extends FieldElement<T>> implements FieldVector<T> {
/** Serializable version identifier. */
private static final long serialVersionUID = 7648186910365927050L;
/** Field to which the elements belong. */
private final Field<T> field;
/** Entries of the vector. */
protected T[] data;
/** Build an array of elements.
* @param length size of the array to build
* @return a new array
*/
@SuppressWarnings("unchecked")
private T[] buildArray(final int length) {
return (T[]) Array.newInstance(field.getZero().getClass(), length);
}
/**
* Build a 0-length vector.
* <p>Zero-length vectors may be used to initialized construction of vectors
* by data gathering. We start with zero-length and use either the {@link
* #FieldVectorImpl(FieldVectorImpl<T>, FieldVectorImpl<T>)} constructor
* or one of the <code>append</code> method ({@link #append(double)}, {@link
* #append(T[])}, {@link #append(FieldVectorImpl<T>)}) to gather data
* into this vector.</p>
* @param field field to which the elements belong
*/
public FieldVectorImpl(final Field<T> field) {
this(field, 0);
}
/**
* Construct a (size)-length vector of zeros.
* @param field field to which the elements belong
* @param size size of the vector
*/
public FieldVectorImpl(Field<T> field, int size) {
this.field = field;
data = buildArray(size);
Arrays.fill(data, field.getZero());
}
/**
* Construct an (size)-length vector with preset values.
* @param size size of the vector
* @param preset fill the vector with this scalar value
*/
public FieldVectorImpl(int size, T preset) {
this(preset.getField(), size);
Arrays.fill(data, preset);
}
/**
* Construct a vector from an array, copying the input array.
* @param d array of Ts.
* @throws IllegalArgumentException if <code>d</code> is empty
*/
public FieldVectorImpl(T[] d)
throws IllegalArgumentException {
try {
field = d[0].getField();
data = d.clone();
} catch (ArrayIndexOutOfBoundsException e) {
throw MathRuntimeException.createIllegalArgumentException(
"vector must have at least one element");
}
}
/**
* Create a new FieldVectorImpl using the input array as the underlying
* data array.
* <p>If an array is built specially in order to be embedded in a
* FieldVectorImpl and not used directly, the <code>copyArray</code> may be
* set to <code>false</code. This will prevent the copying and improve
* performance as no new array will be built and no data will be copied.</p>
* @param d data for new vector
* @param copyArray if true, the input array will be copied, otherwise
* it will be referenced
* @throws IllegalArgumentException if <code>d</code> is empty
* @throws NullPointerException if <code>d</code> is null
* @see #FieldVectorImpl(T[])
*/
public FieldVectorImpl(T[] d, boolean copyArray)
throws NullPointerException, IllegalArgumentException {
try {
field = d[0].getField();
data = copyArray ? d.clone() : d;
} catch (ArrayIndexOutOfBoundsException e) {
throw MathRuntimeException.createIllegalArgumentException(
"vector must have at least one element");
}
}
/**
* Construct a vector from part of a array.
* @param d array of Ts.
* @param pos position of first entry
* @param size number of entries to copy
*/
public FieldVectorImpl(T[] d, int pos, int size) {
if (d.length < pos + size) {
throw MathRuntimeException.createIllegalArgumentException(
"position {0} and size {1} don't fit to the size of the input array {2}",
pos, size, d.length);
}
field = d[0].getField();
data = buildArray(size);
System.arraycopy(d, pos, data, 0, size);
}
/**
* Construct a vector from another vector, using a deep copy.
* @param v vector to copy
*/
public FieldVectorImpl(FieldVector<T> v) {
field = v.getField();
data = buildArray(v.getDimension());
for (int i = 0; i < data.length; ++i) {
data[i] = v.getEntry(i);
}
}
/**
* Construct a vector from another vector, using a deep copy.
* @param v vector to copy
*/
public FieldVectorImpl(FieldVectorImpl<T> v) {
field = v.getField();
data = v.data.clone();
}
/**
* Construct a vector from another vector.
* @param v vector to copy
* @param deep if true perform a deep copy otherwise perform a shallow copy
*/
public FieldVectorImpl(FieldVectorImpl<T> v, boolean deep) {
field = v.getField();
data = deep ? v.data.clone() : v.data;
}
/**
* Construct a vector by appending one vector to another vector.
* @param v1 first vector (will be put in front of the new vector)
* @param v2 second vector (will be put at back of the new vector)
*/
public FieldVectorImpl(FieldVectorImpl<T> v1, FieldVectorImpl<T> v2) {
field = v1.getField();
data = buildArray(v1.data.length + v2.data.length);
System.arraycopy(v1.data, 0, data, 0, v1.data.length);
System.arraycopy(v2.data, 0, data, v1.data.length, v2.data.length);
}
/**
* Construct a vector by appending one vector to another vector.
* @param v1 first vector (will be put in front of the new vector)
* @param v2 second vector (will be put at back of the new vector)
*/
public FieldVectorImpl(FieldVectorImpl<T> v1, T[] v2) {
field = v1.getField();
data = buildArray(v1.data.length + v2.length);
System.arraycopy(v1.data, 0, data, 0, v1.data.length);
System.arraycopy(v2, 0, data, v1.data.length, v2.length);
}
/**
* Construct a vector by appending one vector to another vector.
* @param v1 first vector (will be put in front of the new vector)
* @param v2 second vector (will be put at back of the new vector)
*/
public FieldVectorImpl(T[] v1, FieldVectorImpl<T> v2) {
field = v2.getField();
data = buildArray(v1.length + v2.data.length);
System.arraycopy(v1, 0, data, 0, v1.length);
System.arraycopy(v2.data, 0, data, v1.length, v2.data.length);
}
/**
* Construct a vector by appending one vector to another vector.
* @param v1 first vector (will be put in front of the new vector)
* @param v2 second vector (will be put at back of the new vector)
* @exception IllegalArgumentException if both vectors are empty
*/
public FieldVectorImpl(T[] v1, T[] v2) {
try {
data = buildArray(v1.length + v2.length);
System.arraycopy(v1, 0, data, 0, v1.length);
System.arraycopy(v2, 0, data, v1.length, v2.length);
field = data[0].getField();
} catch (ArrayIndexOutOfBoundsException e) {
throw MathRuntimeException.createIllegalArgumentException(
"vector must have at least one element");
}
}
/** {@inheritDoc} */
public Field<T> getField() {
return field;
}
/** {@inheritDoc} */
public FieldVector<T> copy() {
return new FieldVectorImpl<T>(this, true);
}
/** {@inheritDoc} */
public FieldVector<T> add(FieldVector<T> v) throws IllegalArgumentException {
try {
return add((FieldVectorImpl<T>) v);
} catch (ClassCastException cce) {
checkVectorDimensions(v);
T[] out = buildArray(data.length);
for (int i = 0; i < data.length; i++) {
out[i] = data[i].add(v.getEntry(i));
}
return new FieldVectorImpl<T>(out);
}
}
/** {@inheritDoc} */
public FieldVector<T> add(T[] v) throws IllegalArgumentException {
checkVectorDimensions(v.length);
T[] out = buildArray(data.length);
for (int i = 0; i < data.length; i++) {
out[i] = data[i].add(v[i]);
}
return new FieldVectorImpl<T>(out);
}
/**
* Compute the sum of this and v.
* @param v vector to be added
* @return this + v
* @throws IllegalArgumentException if v is not the same size as this
*/
public FieldVectorImpl<T> add(FieldVectorImpl<T> v)
throws IllegalArgumentException {
return (FieldVectorImpl<T>) add((T[]) v.data);
}
/** {@inheritDoc} */
public FieldVector<T> subtract(FieldVector<T> v) throws IllegalArgumentException {
try {
return subtract((FieldVectorImpl<T>) v);
} catch (ClassCastException cce) {
checkVectorDimensions(v);
T[] out = buildArray(data.length);
for (int i = 0; i < data.length; i++) {
out[i] = data[i].subtract(v.getEntry(i));
}
return new FieldVectorImpl<T>(out);
}
}
/** {@inheritDoc} */
public FieldVector<T> subtract(T[] v) throws IllegalArgumentException {
checkVectorDimensions(v.length);
T[] out = buildArray(data.length);
for (int i = 0; i < data.length; i++) {
out[i] = data[i].subtract(v[i]);
}
return new FieldVectorImpl<T>(out);
}
/**
* Compute this minus v.
* @param v vector to be subtracted
* @return this + v
* @throws IllegalArgumentException if v is not the same size as this
*/
public FieldVectorImpl<T> subtract(FieldVectorImpl<T> v)
throws IllegalArgumentException {
return (FieldVectorImpl<T>) subtract((T[]) v.data);
}
/** {@inheritDoc} */
public FieldVector<T> mapAdd(T d) {
T[] out = buildArray(data.length);
for (int i = 0; i < data.length; i++) {
out[i] = data[i].add(d);
}
return new FieldVectorImpl<T>(out);
}
/** {@inheritDoc} */
public FieldVector<T> mapAddToSelf(T d) {
for (int i = 0; i < data.length; i++) {
data[i] = data[i].add(d);
}
return this;
}
/** {@inheritDoc} */
public FieldVector<T> mapSubtract(T d) {
T[] out = buildArray(data.length);
for (int i = 0; i < data.length; i++) {
out[i] = data[i].subtract(d);
}
return new FieldVectorImpl<T>(out);
}
/** {@inheritDoc} */
public FieldVector<T> mapSubtractToSelf(T d) {
for (int i = 0; i < data.length; i++) {
data[i] = data[i].subtract(d);
}
return this;
}
/** {@inheritDoc} */
public FieldVector<T> mapMultiply(T d) {
T[] out = buildArray(data.length);
for (int i = 0; i < data.length; i++) {
out[i] = data[i].multiply(d);
}
return new FieldVectorImpl<T>(out);
}
/** {@inheritDoc} */
public FieldVector<T> mapMultiplyToSelf(T d) {
for (int i = 0; i < data.length; i++) {
data[i] = data[i].multiply(d);
}
return this;
}
/** {@inheritDoc} */
public FieldVector<T> mapDivide(T d) {
T[] out = buildArray(data.length);
for (int i = 0; i < data.length; i++) {
out[i] = data[i].divide(d);
}
return new FieldVectorImpl<T>(out);
}
/** {@inheritDoc} */
public FieldVector<T> mapDivideToSelf(T d) {
for (int i = 0; i < data.length; i++) {
data[i] = data[i].divide(d);
}
return this;
}
/** {@inheritDoc} */
public FieldVector<T> mapInv() {
T[] out = buildArray(data.length);
final T one = field.getOne();
for (int i = 0; i < data.length; i++) {
out[i] = one.divide(data[i]);
}
return new FieldVectorImpl<T>(out);
}
/** {@inheritDoc} */
public FieldVector<T> mapInvToSelf() {
final T one = field.getOne();
for (int i = 0; i < data.length; i++) {
data[i] = one.divide(data[i]);
}
return this;
}
/** {@inheritDoc} */
public FieldVector<T> ebeMultiply(FieldVector<T> v)
throws IllegalArgumentException {
try {
return ebeMultiply((FieldVectorImpl<T>) v);
} catch (ClassCastException cce) {
checkVectorDimensions(v);
T[] out = buildArray(data.length);
for (int i = 0; i < data.length; i++) {
out[i] = data[i].multiply(v.getEntry(i));
}
return new FieldVectorImpl<T>(out);
}
}
/** {@inheritDoc} */
public FieldVector<T> ebeMultiply(T[] v)
throws IllegalArgumentException {
checkVectorDimensions(v.length);
T[] out = buildArray(data.length);
for (int i = 0; i < data.length; i++) {
out[i] = data[i].multiply(v[i]);
}
return new FieldVectorImpl<T>(out);
}
/**
* Element-by-element multiplication.
* @param v vector by which instance elements must be multiplied
* @return a vector containing this[i] * v[i] for all i
* @exception IllegalArgumentException if v is not the same size as this
*/
public FieldVectorImpl<T> ebeMultiply(FieldVectorImpl<T> v)
throws IllegalArgumentException {
return (FieldVectorImpl<T>) ebeMultiply(v.data);
}
/** {@inheritDoc} */
public FieldVector<T> ebeDivide(FieldVector<T> v)
throws IllegalArgumentException {
try {
return ebeDivide((FieldVectorImpl<T>) v);
} catch (ClassCastException cce) {
checkVectorDimensions(v);
T[] out = buildArray(data.length);
for (int i = 0; i < data.length; i++) {
out[i] = data[i].divide(v.getEntry(i));
}
return new FieldVectorImpl<T>(out);
}
}
/** {@inheritDoc} */
public FieldVector<T> ebeDivide(T[] v)
throws IllegalArgumentException {
checkVectorDimensions(v.length);
T[] out = buildArray(data.length);
for (int i = 0; i < data.length; i++) {
out[i] = data[i].divide(v[i]);
}
return new FieldVectorImpl<T>(out);
}
/**
* Element-by-element division.
* @param v vector by which instance elements must be divided
* @return a vector containing this[i] / v[i] for all i
* @throws IllegalArgumentException if v is not the same size as this
*/
public FieldVectorImpl<T> ebeDivide(FieldVectorImpl<T> v)
throws IllegalArgumentException {
return (FieldVectorImpl<T>) ebeDivide(v.data);
}
/** {@inheritDoc} */
public T[] getData() {
return data.clone();
}
/**
* Returns a reference to the underlying data array.
* <p>Does not make a fresh copy of the underlying data.</p>
* @return array of entries
*/
public T[] getDataRef() {
return data;
}
/** {@inheritDoc} */
public T dotProduct(FieldVector<T> v)
throws IllegalArgumentException {
try {
return dotProduct((FieldVectorImpl<T>) v);
} catch (ClassCastException cce) {
checkVectorDimensions(v);
T dot = field.getZero();
for (int i = 0; i < data.length; i++) {
dot = dot.add(data[i].multiply(v.getEntry(i)));
}
return dot;
}
}
/** {@inheritDoc} */
public T dotProduct(T[] v)
throws IllegalArgumentException {
checkVectorDimensions(v.length);
T dot = field.getZero();
for (int i = 0; i < data.length; i++) {
dot = dot.add(data[i].multiply(v[i]));
}
return dot;
}
/**
* Compute the dot product.
* @param v vector with which dot product should be computed
* @return the scalar dot product between instance and v
* @exception IllegalArgumentException if v is not the same size as this
*/
public T dotProduct(FieldVectorImpl<T> v)
throws IllegalArgumentException {
return dotProduct(v.data);
}
/** {@inheritDoc} */
public FieldVector<T> projection(FieldVector<T> v) {
return v.mapMultiply(dotProduct(v).divide(v.dotProduct(v)));
}
/** {@inheritDoc} */
public FieldVector<T> projection(T[] v) {
return projection(new FieldVectorImpl<T>(v, false));
}
/** Find the orthogonal projection of this vector onto another vector.
* @param v vector onto which instance must be projected
* @return projection of the instance onto v
* @throws IllegalArgumentException if v is not the same size as this
*/
public FieldVectorImpl<T> projection(FieldVectorImpl<T> v) {
return (FieldVectorImpl<T>) v.mapMultiply(dotProduct(v).divide(v.dotProduct(v)));
}
/** {@inheritDoc} */
public FieldMatrix<T> outerProduct(FieldVector<T> v)
throws IllegalArgumentException {
try {
return outerProduct((FieldVectorImpl<T>) v);
} catch (ClassCastException cce) {
checkVectorDimensions(v);
final int m = data.length;
final FieldMatrix<T> out = new FieldMatrixImpl<T>(field, m, m);
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data.length; j++) {
out.setEntry(i, j, data[i].multiply(v.getEntry(j)));
}
}
return out;
}
}
/**
* Compute the outer product.
* @param v vector with which outer product should be computed
* @return the square matrix outer product between instance and v
* @exception IllegalArgumentException if v is not the same size as this
*/
public FieldMatrix<T> outerProduct(FieldVectorImpl<T> v)
throws IllegalArgumentException {
return outerProduct(v.data);
}
/** {@inheritDoc} */
public FieldMatrix<T> outerProduct(T[] v)
throws IllegalArgumentException {
checkVectorDimensions(v.length);
final int m = data.length;
final FieldMatrix<T> out = new FieldMatrixImpl<T>(field, m, m);
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data.length; j++) {
out.setEntry(i, j, data[i].multiply(v[j]));
}
}
return out;
}
/** {@inheritDoc} */
public T getEntry(int index) throws MatrixIndexException {
return data[index];
}
/** {@inheritDoc} */
public int getDimension() {
return data.length;
}
/** {@inheritDoc} */
public FieldVector<T> append(FieldVector<T> v) {
try {
return append((FieldVectorImpl<T>) v);
} catch (ClassCastException cce) {
return new FieldVectorImpl<T>(this,new FieldVectorImpl<T>(v));
}
}
/**
* Construct a vector by appending a vector to this vector.
* @param v vector to append to this one.
* @return a new vector
*/
public FieldVectorImpl<T> append(FieldVectorImpl<T> v) {
return new FieldVectorImpl<T>(this, v);
}
/** {@inheritDoc} */
public FieldVector<T> append(T in) {
final T[] out = buildArray(data.length + 1);
System.arraycopy(data, 0, out, 0, data.length);
out[data.length] = in;
return new FieldVectorImpl<T>(out);
}
/** {@inheritDoc} */
public FieldVector<T> append(T[] in) {
return new FieldVectorImpl<T>(this, in);
}
/** {@inheritDoc} */
public FieldVector<T> getSubVector(int index, int n) {
FieldVectorImpl<T> out = new FieldVectorImpl<T>(field, n);
try {
System.arraycopy(data, index, out.data, 0, n);
} catch (IndexOutOfBoundsException e) {
checkIndex(index);
checkIndex(index + n - 1);
}
return out;
}
/** {@inheritDoc} */
public void setEntry(int index, T value) {
try {
data[index] = value;
} catch (IndexOutOfBoundsException e) {
checkIndex(index);
}
}
/** {@inheritDoc} */
public void setSubVector(int index, FieldVector<T> v) {
try {
try {
set(index, (FieldVectorImpl<T>) v);
} catch (ClassCastException cce) {
for (int i = index; i < index + v.getDimension(); ++i) {
data[i] = v.getEntry(i-index);
}
}
} catch (IndexOutOfBoundsException e) {
checkIndex(index);
checkIndex(index + v.getDimension() - 1);
}
}
/** {@inheritDoc} */
public void setSubVector(int index, T[] v) {
try {
System.arraycopy(v, 0, data, index, v.length);
} catch (IndexOutOfBoundsException e) {
checkIndex(index);
checkIndex(index + v.length - 1);
}
}
/**
* Set a set of consecutive elements.
*
* @param index index of first element to be set.
* @param v vector containing the values to set.
* @exception MatrixIndexException if the index is
* inconsistent with vector size
*/
public void set(int index, FieldVectorImpl<T> v)
throws MatrixIndexException {
setSubVector(index, v.data);
}
/** {@inheritDoc} */
public void set(T value) {
Arrays.fill(data, value);
}
/** {@inheritDoc} */
public T[] toArray(){
return data.clone();
}
/**
* Check if instance and specified vectors have the same dimension.
* @param v vector to compare instance with
* @exception IllegalArgumentException if the vectors do not
* have the same dimension
*/
protected void checkVectorDimensions(FieldVector<T> v)
throws IllegalArgumentException {
checkVectorDimensions(v.getDimension());
}
/**
* Check if instance dimension is equal to some expected value.
*
* @param n expected dimension.
* @exception IllegalArgumentException if the dimension is
* inconsistent with vector size
*/
protected void checkVectorDimensions(int n)
throws IllegalArgumentException {
if (data.length != n) {
throw MathRuntimeException.createIllegalArgumentException(
"vector length mismatch: got {0} but expected {1}",
data.length, n);
}
}
/**
* Test for the equality of two real vectors.
* <p>
* If all coordinates of two real vectors are exactly the same, and none are
* <code>Double.NaN</code>, the two real vectors are considered to be equal.
* </p>
* <p>
* <code>NaN</code> coordinates are considered to affect globally the vector
* and be equals to each other - i.e, if either (or all) coordinates of the
* real vector are equal to <code>Double.NaN</code>, the real vector is equal to
* a vector with all <code>Double.NaN</code> coordinates.
* </p>
*
* @param other Object to test for equality to this
* @return true if two 3D vector objects are equal, false if
* object is null, not an instance of Vector3D, or
* not equal to this Vector3D instance
*
*/
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null) {
return false;
}
try {
FieldVector<T> rhs = (FieldVector<T>) other;
if (data.length != rhs.getDimension()) {
return false;
}
for (int i = 0; i < data.length; ++i) {
if (!data[i].equals(rhs.getEntry(i))) {
return false;
}
}
return true;
} catch (ClassCastException ex) {
// ignore exception
return false;
}
}
/**
* Get a hashCode for the real vector.
* <p>All NaN values have the same hash code.</p>
* @return a hash code value for this object
*/
@Override
public int hashCode() {
int h = 3542;
for (final T a : data) {
h = h ^ a.hashCode();
}
return h;
}
/**
* Check if an index is valid.
* @param index index to check
* @exception MatrixIndexException if index is not valid
*/
private void checkIndex(final int index)
throws MatrixIndexException {
if (index < 0 || index >= getDimension()) {
throw new MatrixIndexException(
"index {0} out of allowed range [{1}, {2}]",
index, 0, getDimension() - 1);
}
}
}

View File

@ -0,0 +1,91 @@
/*
* 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.commons.math.linear.decomposition;
import java.io.Serializable;
import org.apache.commons.math.FieldElement;
import org.apache.commons.math.linear.FieldMatrix;
import org.apache.commons.math.linear.FieldVector;
import org.apache.commons.math.linear.InvalidMatrixException;
/**
* Interface handling decomposition algorithms that can solve A &times; X = B.
* <p>Decomposition algorithms decompose an A matrix has a product of several specific
* matrices from which they can solve A &times; X = B in least squares sense: they find X
* such that ||A &times; X - B|| is minimal.</p>
* <p>Some solvers like {@link LUDecomposition} can only find the solution for
* square matrices and when the solution is an exact linear solution, i.e. when
* ||A &times; X - B|| is exactly 0. Other solvers can also find solutions
* with non-square matrix A and with non-null minimal norm. If an exact linear
* solution exists it is also the minimal norm solution.</p>
*
* @param <T> the type of the field elements
* @version $Revision$ $Date$
* @since 2.0
*/
public interface FieldDecompositionSolver<T extends FieldElement<T>> extends Serializable {
/** Solve the linear equation A &times; X = B for matrices A.
* <p>The A matrix is implicit, it is provided by the underlying
* decomposition algorithm.</p>
* @param b right-hand side of the equation A &times; X = B
* @return a vector X that minimizes the two norm of A &times; X - B
* @exception IllegalArgumentException if matrices dimensions don't match
* @exception InvalidMatrixException if decomposed matrix is singular
*/
T[] solve(final T[] b)
throws IllegalArgumentException, InvalidMatrixException;
/** Solve the linear equation A &times; X = B for matrices A.
* <p>The A matrix is implicit, it is provided by the underlying
* decomposition algorithm.</p>
* @param b right-hand side of the equation A &times; X = B
* @return a vector X that minimizes the two norm of A &times; X - B
* @exception IllegalArgumentException if matrices dimensions don't match
* @exception InvalidMatrixException if decomposed matrix is singular
*/
FieldVector<T> solve(final FieldVector<T> b)
throws IllegalArgumentException, InvalidMatrixException;
/** Solve the linear equation A &times; X = B for matrices A.
* <p>The A matrix is implicit, it is provided by the underlying
* decomposition algorithm.</p>
* @param b right-hand side of the equation A &times; X = B
* @return a matrix X that minimizes the two norm of A &times; X - B
* @exception IllegalArgumentException if matrices dimensions don't match
* @exception InvalidMatrixException if decomposed matrix is singular
*/
FieldMatrix<T> solve(final FieldMatrix<T> b)
throws IllegalArgumentException, InvalidMatrixException;
/**
* Check if the decomposed matrix is non-singular.
* @return true if the decomposed matrix is non-singular
*/
boolean isNonSingular();
/** Get the inverse (or pseudo-inverse) of the decomposed matrix.
* @return inverse matrix
* @throws InvalidMatrixException if decomposed matrix is singular
*/
FieldMatrix<T> getInverse()
throws InvalidMatrixException;
}

View File

@ -0,0 +1,97 @@
/*
* 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.commons.math.linear.decomposition;
import java.io.Serializable;
import org.apache.commons.math.FieldElement;
import org.apache.commons.math.linear.FieldMatrix;
/**
* An interface to classes that implement an algorithm to calculate the
* LU-decomposition of a real matrix.
* <p>The LU-decomposition of matrix A is a set of three matrices: P, L and U
* such that P&times;A = L&times;U. P is a rows permutation matrix that is used
* to rearrange the rows of A before so that it can be decomposed. L is a lower
* triangular matrix with unit diagonal terms and U is an upper triangular matrix.</p>
* <p>This interface is based on the class with similar name from the now defunct
* <a href="http://math.nist.gov/javanumerics/jama/">JAMA</a> library.</p>
* <ul>
* <li>a {@link #getP() getP} method has been added,</li>
* <li>the <code>det</code> method has been renamed as {@link #getDeterminant()
* getDeterminant},</li>
* <li>the <code>getDoublePivot</code> method has been removed (but the int based
* {@link #getPivot() getPivot} method has been kept),</li>
* <li>the <code>solve</code> and <code>isNonSingular</code> methods have been replaced
* by a {@link #getSolver() getSolver} method and the equivalent methods provided by
* the returned {@link DecompositionSolver}.</li>
* </ul>
*
* @param <T> the type of the field elements
* @see <a href="http://mathworld.wolfram.com/LUDecomposition.html">MathWorld</a>
* @see <a href="http://en.wikipedia.org/wiki/LU_decomposition">Wikipedia</a>
* @version $Revision$ $Date$
* @since 2.0
*/
public interface FieldLUDecomposition<T extends FieldElement<T>> extends Serializable {
/**
* Returns the matrix L of the decomposition.
* <p>L is an lower-triangular matrix</p>
* @return the L matrix (or null if decomposed matrix is singular)
*/
FieldMatrix<T> getL();
/**
* Returns the matrix U of the decomposition.
* <p>U is an upper-triangular matrix</p>
* @return the U matrix (or null if decomposed matrix is singular)
*/
FieldMatrix<T> getU();
/**
* Returns the P rows permutation matrix.
* <p>P is a sparse matrix with exactly one element set to 1.0 in
* each row and each column, all other elements being set to 0.0.</p>
* <p>The positions of the 1 elements are given by the {@link #getPivot()
* pivot permutation vector}.</p>
* @return the P rows permutation matrix (or null if decomposed matrix is singular)
* @see #getPivot()
*/
FieldMatrix<T> getP();
/**
* Returns the pivot permutation vector.
* @return the pivot permutation vector
* @see #getP()
*/
int[] getPivot();
/**
* Return the determinant of the matrix
* @return determinant of the matrix
*/
T getDeterminant();
/**
* Get a solver for finding the A &times; X = B solution in exact linear sense.
* @return a solver
*/
FieldDecompositionSolver<T> getSolver();
}

View File

@ -0,0 +1,441 @@
/*
* 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.commons.math.linear.decomposition;
import java.lang.reflect.Array;
import org.apache.commons.math.Field;
import org.apache.commons.math.FieldElement;
import org.apache.commons.math.MathRuntimeException;
import org.apache.commons.math.linear.FieldMatrix;
import org.apache.commons.math.linear.FieldMatrixImpl;
import org.apache.commons.math.linear.FieldVector;
import org.apache.commons.math.linear.FieldVectorImpl;
import org.apache.commons.math.linear.InvalidMatrixException;
/**
* Calculates the LUP-decomposition of a square matrix.
* <p>The LUP-decomposition of a matrix A consists of three matrices
* L, U and P that satisfy: PA = LU, L is lower triangular, and U is
* upper triangular and P is a permutation matrix. All matrices are
* m&times;m.</p>
* <p>Since {@link FieldElement field elements} do not provide an ordering
* operator, the permutation matrix is computed here only in order to avoid
* a zero pivot element, no attempt is done to get the largest pivot element.</p>
*
* @param <T> the type of the field elements
* @version $Revision$ $Date$
* @since 2.0
*/
public class FieldLUDecompositionImpl<T extends FieldElement<T>> implements FieldLUDecomposition<T> {
/** Serializable version identifier. */
private static final long serialVersionUID = 1954692554563387537L;
/** Field to which the elements belong. */
private final Field<T> field;
/** Entries of LU decomposition. */
private T lu[][];
/** Pivot permutation associated with LU decomposition */
private int[] pivot;
/** Parity of the permutation associated with the LU decomposition */
private boolean even;
/** Singularity indicator. */
private boolean singular;
/** Cached value of L. */
private FieldMatrix<T> cachedL;
/** Cached value of U. */
private FieldMatrix<T> cachedU;
/** Cached value of P. */
private FieldMatrix<T> cachedP;
/**
* Calculates the LU-decomposition of the given matrix.
* @param matrix The matrix to decompose.
* @exception NonSquareMatrixException if matrix is not square
*/
public FieldLUDecompositionImpl(FieldMatrix<T> matrix)
throws NonSquareMatrixException {
if (!matrix.isSquare()) {
throw new NonSquareMatrixException(matrix.getRowDimension(), matrix.getColumnDimension());
}
final int m = matrix.getColumnDimension();
field = matrix.getField();
lu = matrix.getData();
pivot = new int[m];
cachedL = null;
cachedU = null;
cachedP = null;
// Initialize permutation array and parity
for (int row = 0; row < m; row++) {
pivot[row] = row;
}
even = true;
singular = false;
// Loop over columns
for (int col = 0; col < m; col++) {
T sum = field.getZero();
// upper
for (int row = 0; row < col; row++) {
final T[] luRow = lu[row];
sum = luRow[col];
for (int i = 0; i < row; i++) {
sum = sum.subtract(luRow[i].multiply(lu[i][col]));
}
luRow[col] = sum;
}
// lower
int nonZero = col; // permutation row
for (int row = col; row < m; row++) {
final T[] luRow = lu[row];
sum = luRow[col];
for (int i = 0; i < col; i++) {
sum = sum.subtract(luRow[i].multiply(lu[i][col]));
}
luRow[col] = sum;
if (lu[nonZero][col].equals(field.getZero())) {
// try to select a better permutation choice
++nonZero;
}
}
// Singularity check
if (nonZero >= m) {
singular = true;
return;
}
// Pivot if necessary
if (nonZero != col) {
T tmp = field.getZero();
for (int i = 0; i < m; i++) {
tmp = lu[nonZero][i];
lu[nonZero][i] = lu[col][i];
lu[col][i] = tmp;
}
int temp = pivot[nonZero];
pivot[nonZero] = pivot[col];
pivot[col] = temp;
even = !even;
}
// Divide the lower elements by the "winning" diagonal elt.
final T luDiag = lu[col][col];
for (int row = col + 1; row < m; row++) {
final T[] luRow = lu[row];
luRow[col] = luRow[col].divide(luDiag);
}
}
}
/** {@inheritDoc} */
public FieldMatrix<T> getL() {
if ((cachedL == null) && !singular) {
final int m = pivot.length;
cachedL = new FieldMatrixImpl<T>(field, m, m);
for (int i = 0; i < m; ++i) {
final T[] luI = lu[i];
for (int j = 0; j < i; ++j) {
cachedL.setEntry(i, j, luI[j]);
}
cachedL.setEntry(i, i, field.getOne());
}
}
return cachedL;
}
/** {@inheritDoc} */
public FieldMatrix<T> getU() {
if ((cachedU == null) && !singular) {
final int m = pivot.length;
cachedU = new FieldMatrixImpl<T>(field, m, m);
for (int i = 0; i < m; ++i) {
final T[] luI = lu[i];
for (int j = i; j < m; ++j) {
cachedU.setEntry(i, j, luI[j]);
}
}
}
return cachedU;
}
/** {@inheritDoc} */
public FieldMatrix<T> getP() {
if ((cachedP == null) && !singular) {
final int m = pivot.length;
cachedP = new FieldMatrixImpl<T>(field, m, m);
for (int i = 0; i < m; ++i) {
cachedP.setEntry(i, pivot[i], field.getOne());
}
}
return cachedP;
}
/** {@inheritDoc} */
public int[] getPivot() {
return pivot.clone();
}
/** {@inheritDoc} */
public T getDeterminant() {
if (singular) {
return field.getZero();
} else {
final int m = pivot.length;
T determinant = even ? field.getOne() : field.getZero().subtract(field.getOne());
for (int i = 0; i < m; i++) {
determinant = determinant.multiply(lu[i][i]);
}
return determinant;
}
}
/** {@inheritDoc} */
public FieldDecompositionSolver<T> getSolver() {
return new Solver<T>(field, lu, pivot, singular);
}
/** Specialized solver. */
private static class Solver<T extends FieldElement<T>> implements FieldDecompositionSolver<T> {
/** Serializable version identifier. */
private static final long serialVersionUID = -6353105415121373022L;
/** Field to which the elements belong. */
private final Field<T> field;
/** Entries of LU decomposition. */
private final T lu[][];
/** Pivot permutation associated with LU decomposition. */
private final int[] pivot;
/** Singularity indicator. */
private final boolean singular;
/**
* Build a solver from decomposed matrix.
* @param field field to which the matrix elements belong
* @param lu entries of LU decomposition
* @param pivot pivot permutation associated with LU decomposition
* @param singular singularity indicator
*/
private Solver(final Field<T> field, final T[][] lu,
final int[] pivot, final boolean singular) {
this.field = field;
this.lu = lu;
this.pivot = pivot;
this.singular = singular;
}
/** {@inheritDoc} */
public boolean isNonSingular() {
return !singular;
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
public T[] solve(T[] b)
throws IllegalArgumentException, InvalidMatrixException {
final int m = pivot.length;
if (b.length != m) {
throw MathRuntimeException.createIllegalArgumentException(
"vector length mismatch: got {0} but expected {1}",
b.length, m);
}
if (singular) {
throw new SingularMatrixException();
}
final T[] bp = (T[]) Array.newInstance(field.getZero().getClass(), m);
// Apply permutations to b
for (int row = 0; row < m; row++) {
bp[row] = b[pivot[row]];
}
// Solve LY = b
for (int col = 0; col < m; col++) {
final T bpCol = bp[col];
for (int i = col + 1; i < m; i++) {
bp[i] = bp[i].subtract(bpCol.multiply(lu[i][col]));
}
}
// Solve UX = Y
for (int col = m - 1; col >= 0; col--) {
bp[col] = bp[col].divide(lu[col][col]);
final T bpCol = bp[col];
for (int i = 0; i < col; i++) {
bp[i] = bp[i].subtract(bpCol.multiply(lu[i][col]));
}
}
return bp;
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
public FieldVector<T> solve(FieldVector<T> b)
throws IllegalArgumentException, InvalidMatrixException {
try {
return solve((FieldVectorImpl<T>) b);
} catch (ClassCastException cce) {
final int m = pivot.length;
if (b.getDimension() != m) {
throw MathRuntimeException.createIllegalArgumentException(
"vector length mismatch: got {0} but expected {1}",
b.getDimension(), m);
}
if (singular) {
throw new SingularMatrixException();
}
final T[] bp = (T[]) Array.newInstance(field.getZero().getClass(), m);
// Apply permutations to b
for (int row = 0; row < m; row++) {
bp[row] = b.getEntry(pivot[row]);
}
// Solve LY = b
for (int col = 0; col < m; col++) {
final T bpCol = bp[col];
for (int i = col + 1; i < m; i++) {
bp[i] = bp[i].subtract(bpCol.multiply(lu[i][col]));
}
}
// Solve UX = Y
for (int col = m - 1; col >= 0; col--) {
bp[col] = bp[col].divide(lu[col][col]);
final T bpCol = bp[col];
for (int i = 0; i < col; i++) {
bp[i] = bp[i].subtract(bpCol.multiply(lu[i][col]));
}
}
return new FieldVectorImpl<T>(bp, false);
}
}
/** Solve the linear equation A &times; X = B.
* <p>The A matrix is implicit here. It is </p>
* @param b right-hand side of the equation A &times; X = B
* @return a vector X such that A &times; X = B
* @exception IllegalArgumentException if matrices dimensions don't match
* @exception InvalidMatrixException if decomposed matrix is singular
*/
public FieldVectorImpl<T> solve(FieldVectorImpl<T> b)
throws IllegalArgumentException, InvalidMatrixException {
return new FieldVectorImpl<T>(solve(b.getDataRef()), false);
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
public FieldMatrix<T> solve(FieldMatrix<T> b)
throws IllegalArgumentException, InvalidMatrixException {
final int m = pivot.length;
if (b.getRowDimension() != m) {
throw MathRuntimeException.createIllegalArgumentException(
"dimensions mismatch: got {0}x{1} but expected {2}x{3}",
b.getRowDimension(), b.getColumnDimension(), m, "n");
}
if (singular) {
throw new SingularMatrixException();
}
final int nColB = b.getColumnDimension();
// Apply permutations to b
final T[][] bp = (T[][]) Array.newInstance(field.getZero().getClass(), new int[] { m, nColB });
for (int row = 0; row < m; row++) {
final T[] bpRow = bp[row];
final int pRow = pivot[row];
for (int col = 0; col < nColB; col++) {
bpRow[col] = b.getEntry(pRow, col);
}
}
// Solve LY = b
for (int col = 0; col < m; col++) {
final T[] bpCol = bp[col];
for (int i = col + 1; i < m; i++) {
final T[] bpI = bp[i];
final T luICol = lu[i][col];
for (int j = 0; j < nColB; j++) {
bpI[j] = bpI[j].subtract(bpCol[j].multiply(luICol));
}
}
}
// Solve UX = Y
for (int col = m - 1; col >= 0; col--) {
final T[] bpCol = bp[col];
final T luDiag = lu[col][col];
for (int j = 0; j < nColB; j++) {
bpCol[j] = bpCol[j].divide(luDiag);
}
for (int i = 0; i < col; i++) {
final T[] bpI = bp[i];
final T luICol = lu[i][col];
for (int j = 0; j < nColB; j++) {
bpI[j] = bpI[j].subtract(bpCol[j].multiply(luICol));
}
}
}
return new FieldMatrixImpl<T>(bp, false);
}
/** {@inheritDoc} */
public FieldMatrix<T> getInverse() throws InvalidMatrixException {
final int m = pivot.length;
final T one = field.getOne();
FieldMatrix<T> identity = new FieldMatrixImpl<T>(field, m, m);
for (int i = 0; i < m; ++i) {
identity.setEntry(i, i, one);
}
return solve(identity);
}
}
}

View File

@ -28,7 +28,7 @@ import org.apache.commons.math.linear.RealVectorImpl;
/**
* Calculates the LUP-decomposition of a square matrix.
* <p>The LUP-decomposition of a matrix A consists of three matrices
* L, U and P that satisfy: A = LUP, L is lower triangular, and U is
* L, U and P that satisfy: PA = LU, L is lower triangular, and U is
* upper triangular and P is a permutation matrix. All matrices are
* m&times;m.</p>
* <p>As shown by the presence of the P matrix, this decomposition is
@ -146,10 +146,12 @@ public class LUDecompositionImpl implements LUDecomposition {
// Pivot if necessary
if (max != col) {
double tmp = 0;
final double[] luMax = lu[max];
final double[] luCol = lu[col];
for (int i = 0; i < m; i++) {
tmp = lu[max][i];
lu[max][i] = lu[col][i];
lu[col][i] = tmp;
tmp = luMax[i];
luMax[i] = luCol[i];
luCol[i] = tmp;
}
int temp = pivot[max];
pivot[max] = pivot[col];
@ -288,16 +290,18 @@ public class LUDecompositionImpl implements LUDecomposition {
// Solve LY = b
for (int col = 0; col < m; col++) {
final double bpCol = bp[col];
for (int i = col + 1; i < m; i++) {
bp[i] -= bp[col] * lu[i][col];
bp[i] -= bpCol * lu[i][col];
}
}
// Solve UX = Y
for (int col = m - 1; col >= 0; col--) {
bp[col] /= lu[col][col];
final double bpCol = bp[col];
for (int i = 0; i < col; i++) {
bp[i] -= bp[col] * lu[i][col];
bp[i] -= bpCol * lu[i][col];
}
}
@ -331,16 +335,18 @@ public class LUDecompositionImpl implements LUDecomposition {
// Solve LY = b
for (int col = 0; col < m; col++) {
final double bpCol = bp[col];
for (int i = col + 1; i < m; i++) {
bp[i] -= bp[col] * lu[i][col];
bp[i] -= bpCol * lu[i][col];
}
}
// Solve UX = Y
for (int col = m - 1; col >= 0; col--) {
bp[col] /= lu[col][col];
final double bpCol = bp[col];
for (int i = 0; i < col; i++) {
bp[i] -= bp[col] * lu[i][col];
bp[i] -= bpCol * lu[i][col];
}
}

View File

@ -39,6 +39,10 @@ The <action> type attribute can be add,update,fix,remove.
</properties>
<body>
<release version="2.0" date="TBD" description="TBD">
<action dev="luc" type="add" >
Added support for any type of field in linear algebra (FielxMatrix, FieldVector,
FieldLUDecomposition)
</action>
<action dev="luc" type="add" >
Added general Field and FieldElement interfaces to allow generic algorithms
to operate on fields. The library already provides several implementations:

View File

@ -62,6 +62,7 @@
<li><a href="linear.html#a3.3_Real_vectors">3.3 Real vectors</a></li>
<li><a href="linear.html#a3.4_Solving_linear_systems">3.4 Solving linear systems</a></li>
<li><a href="linear.html#a3.5_Eigenvalueseigenvectors_and_singular_valuessingular_vectors">3.5 Eigenvalues/eigenvectors and singular values/singular vectors</a></li>
<li><a href="linear.html#a3.6_Non-real_fields_complex_fractions_...">3.6 Non-real fields (complex, fractions ...)</a></li>
</ul></li>
<li><a href="analysis.html">4. Numerical Analysis</a>
<ul>
@ -84,7 +85,7 @@
<li><a href="utilities.html#a6.2_Double_array_utilities">6.2 Double array utilities</a></li>
<li><a href="utilities.html#a6.3_intdouble_hash_map">6.3 int/double hash map</a></li>
<li><a href="utilities.html#a6.4_Continued_Fractions">6.4 Continued Fractions</a></li>
<li><a href="utilities.html#a6.5_binomial_coefficients,_factorials_and_other_common_math_functions">6.5 binomial coefficients, factorials and other common math functions</a></li>
<li><a href="utilities.html#a6.5_binomial_coefficients_factorials_and_other_common_math_functions">6.5 binomial coefficients, factorials and other common math functions</a></li>
</ul></li>
<li><a href="complex.html">7. Complex Numbers</a>
<ul>

View File

@ -184,6 +184,19 @@ RealVector solution = solver.solve(constants);
vector spaces (which may have different dimensions).
</p>
</subsection>
<subsection name="3.6 Non-real fields (complex, fractions ...)" href="field">
<p>
In addition to the real field, matrices and vectors using non-real <a
href="../apidocs/org/apache/commons/math/FieldElement.html">field elements</a> can be used.
The fields already supported by the library are:
<ul>
<li><a href="../apidocs/org/apache/commons/math/complex/Complex.html">Complex</a></li>
<li><a href="../apidocs/org/apache/commons/math/fraction/Fraction.html">Fraction</a></li>
<li><a href="../apidocs/org/apache/commons/math/fraction/BigFraction.html">BigFraction</a></li>
<li><a href="../apidocs/org/apache/commons/math/util/BigReal.html">BigReal</a></li>
</ul>
</p>
</subsection>
</section>
</body>
</document>

View File

@ -28,6 +28,7 @@ import junit.framework.AssertionFailedError;
import org.apache.commons.math.complex.Complex;
import org.apache.commons.math.complex.ComplexFormat;
import org.apache.commons.math.linear.FieldMatrix;
import org.apache.commons.math.linear.RealMatrix;
/**
@ -282,6 +283,34 @@ public class TestUtils {
}
}
/** verifies that two matrices are equal */
public static void assertEquals(FieldMatrix<? extends FieldElement<?>> expected,
FieldMatrix<? extends FieldElement<?>> observed) {
if (observed == null) {
Assert.fail("Observed is null");
}
if (expected.getColumnDimension() != observed.getColumnDimension() ||
expected.getRowDimension() != observed.getRowDimension()) {
StringBuffer messageBuffer = new StringBuffer();
messageBuffer.append("Observed has incorrect dimensions.");
messageBuffer.append("\nobserved is " + observed.getRowDimension() +
" x " + observed.getColumnDimension());
messageBuffer.append("\nexpected " + expected.getRowDimension() +
" x " + expected.getColumnDimension());
Assert.fail(messageBuffer.toString());
}
for (int i = 0; i < expected.getRowDimension(); ++i) {
for (int j = 0; j < expected.getColumnDimension(); ++j) {
FieldElement<?> eij = expected.getEntry(i, j);
FieldElement<?> oij = observed.getEntry(i, j);
Assert.assertEquals(eij, oij);
}
}
}
/** verifies that two arrays are close (sup norm) */
public static void assertEquals(String msg, double[] m, double[] n,
double tolerance) {
@ -294,4 +323,15 @@ public class TestUtils {
}
}
/** verifies that two arrays are equal */
public static void assertEquals(FieldElement<? extends FieldElement<?>>[] m,
FieldElement<? extends FieldElement<?>>[] n) {
if (m.length != n.length) {
Assert.fail("vectors not same length");
}
for (int i = 0; i < m.length; i++) {
Assert.assertEquals(m[i],n[i]);
}
}
}

View File

@ -29,7 +29,7 @@ import org.apache.commons.math.linear.decomposition.NonSquareMatrixException;
*
* @version $Revision$ $Date$
*/
@Deprecated
public final class BigMatrixImplTest extends TestCase {
// Test data for String constructors

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,625 @@
/*
* 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.commons.math.linear;
import java.io.Serializable;
import java.lang.reflect.Array;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.commons.math.Field;
import org.apache.commons.math.FieldElement;
import org.apache.commons.math.fraction.Fraction;
import org.apache.commons.math.fraction.FractionField;
/**
* Test cases for the {@link FieldVectorImpl} class.
*
* @version $Revision$ $Date$
*/
public class FieldVectorImplTest extends TestCase {
//
protected Fraction[][] ma1 = {
{new Fraction(1), new Fraction(2), new Fraction(3)},
{new Fraction(4), new Fraction(5), new Fraction(6)},
{new Fraction(7), new Fraction(8), new Fraction(9)}
};
protected Fraction[] vec1 = {new Fraction(1), new Fraction(2), new Fraction(3)};
protected Fraction[] vec2 = {new Fraction(4), new Fraction(5), new Fraction(6)};
protected Fraction[] vec3 = {new Fraction(7), new Fraction(8), new Fraction(9)};
protected Fraction[] vec4 = { new Fraction(1), new Fraction(2), new Fraction(3),
new Fraction(4), new Fraction(5), new Fraction(6),
new Fraction(7), new Fraction(8), new Fraction(9)};
protected Fraction[] vec_null = {new Fraction(0), new Fraction(0), new Fraction(0)};
protected Fraction[] dvec1 = {new Fraction(1), new Fraction(2), new Fraction(3),
new Fraction(4), new Fraction(5), new Fraction(6),
new Fraction(7), new Fraction(8), new Fraction(9)};
protected Fraction[][] mat1 = {
{new Fraction(1), new Fraction(2), new Fraction(3)},
{new Fraction(4), new Fraction(5), new Fraction(6)},
{new Fraction(7), new Fraction(8), new Fraction(9)}
};
// Testclass to test the FieldVector<Fraction> interface
// only with enough content to support the test
public static class FieldVectorTestImpl<T extends FieldElement<T>>
implements FieldVector<T>, Serializable {
private static final long serialVersionUID = 3970959016014158539L;
private final Field<T> field;
/** Entries of the vector. */
protected T[] data;
/** Build an array of elements.
* @param length size of the array to build
* @return a new array
*/
@SuppressWarnings("unchecked")
private T[] buildArray(final int length) {
return (T[]) Array.newInstance(field.getZero().getClass(), length);
}
public FieldVectorTestImpl(T[] d) {
field = d[0].getField();
data = d.clone();
}
public Field<T> getField() {
return field;
}
private UnsupportedOperationException unsupported() {
return new UnsupportedOperationException("Not supported, unneeded for test purposes");
}
public FieldVector<T> copy() {
throw unsupported();
}
public FieldVector<T> add(FieldVector<T> v) throws IllegalArgumentException {
throw unsupported();
}
public FieldVector<T> add(T[] v) throws IllegalArgumentException {
throw unsupported();
}
public FieldVector<T> subtract(FieldVector<T> v) throws IllegalArgumentException {
throw unsupported();
}
public FieldVector<T> subtract(T[] v) throws IllegalArgumentException {
throw unsupported();
}
public FieldVector<T> mapAdd(T d) {
throw unsupported();
}
public FieldVector<T> mapAddToSelf(T d) {
throw unsupported();
}
public FieldVector<T> mapSubtract(T d) {
throw unsupported();
}
public FieldVector<T> mapSubtractToSelf(T d) {
throw unsupported();
}
public FieldVector<T> mapMultiply(T d) {
T[] out = buildArray(data.length);
for (int i = 0; i < data.length; i++) {
out[i] = data[i].multiply(d);
}
return new FieldVectorTestImpl<T>(out);
}
public FieldVector<T> mapMultiplyToSelf(T d) {
throw unsupported();
}
public FieldVector<T> mapDivide(T d) {
throw unsupported();
}
public FieldVector<T> mapDivideToSelf(T d) {
throw unsupported();
}
public FieldVector<T> mapInv() {
throw unsupported();
}
public FieldVector<T> mapInvToSelf() {
throw unsupported();
}
public FieldVector<T> ebeMultiply(FieldVector<T> v) throws IllegalArgumentException {
throw unsupported();
}
public FieldVector<T> ebeMultiply(T[] v) throws IllegalArgumentException {
throw unsupported();
}
public FieldVector<T> ebeDivide(FieldVector<T> v) throws IllegalArgumentException {
throw unsupported();
}
public FieldVector<T> ebeDivide(T[] v) throws IllegalArgumentException {
throw unsupported();
}
public T[] getData() {
return data.clone();
}
public T dotProduct(FieldVector<T> v) throws IllegalArgumentException {
T dot = field.getZero();
for (int i = 0; i < data.length; i++) {
dot = dot.add(data[i].multiply(v.getEntry(i)));
}
return dot;
}
public T dotProduct(T[] v) throws IllegalArgumentException {
T dot = field.getZero();
for (int i = 0; i < data.length; i++) {
dot = dot.add(data[i].multiply(v[i]));
}
return dot;
}
public FieldVector<T> projection(FieldVector<T> v) throws IllegalArgumentException {
throw unsupported();
}
public FieldVector<T> projection(T[] v) throws IllegalArgumentException {
throw unsupported();
}
public FieldMatrix<T> outerProduct(FieldVector<T> v) throws IllegalArgumentException {
throw unsupported();
}
public FieldMatrix<T> outerProduct(T[] v) throws IllegalArgumentException {
throw unsupported();
}
public T getEntry(int index) throws MatrixIndexException {
return data[index];
}
public int getDimension() {
return data.length;
}
public FieldVector<T> append(FieldVector<T> v) {
throw unsupported();
}
public FieldVector<T> append(T d) {
throw unsupported();
}
public FieldVector<T> append(T[] a) {
throw unsupported();
}
public FieldVector<T> getSubVector(int index, int n) throws MatrixIndexException {
throw unsupported();
}
public void setEntry(int index, T value) throws MatrixIndexException {
throw unsupported();
}
public void setSubVector(int index, FieldVector<T> v) throws MatrixIndexException {
throw unsupported();
}
public void setSubVector(int index, T[] v) throws MatrixIndexException {
throw unsupported();
}
public void set(T value) {
throw unsupported();
}
public T[] toArray() {
throw unsupported();
}
}
public static Test suite() {
TestSuite suite = new TestSuite(FieldVectorImplTest.class);
suite.setName("FieldVectorImpl<Fraction> Tests");
return suite;
}
public void testConstructors() {
FieldVectorImpl<Fraction> v0 = new FieldVectorImpl<Fraction>(FractionField.getInstance());
assertEquals(0, v0.getDimension());
FieldVectorImpl<Fraction> v1 = new FieldVectorImpl<Fraction>(FractionField.getInstance(), 7);
assertEquals(7, v1.getDimension());
assertEquals(new Fraction(0), v1.getEntry(6));
FieldVectorImpl<Fraction> v2 = new FieldVectorImpl<Fraction>(5, new Fraction(123, 100));
assertEquals(5, v2.getDimension());
assertEquals(new Fraction(123, 100), v2.getEntry(4));
FieldVectorImpl<Fraction> v3 = new FieldVectorImpl<Fraction>(vec1);
assertEquals(3, v3.getDimension());
assertEquals(new Fraction(2), v3.getEntry(1));
FieldVectorImpl<Fraction> v4 = new FieldVectorImpl<Fraction>(vec4, 3, 2);
assertEquals(2, v4.getDimension());
assertEquals(new Fraction(4), v4.getEntry(0));
try {
new FieldVectorImpl<Fraction>(vec4, 8, 3);
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException ex) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
}
FieldVector<Fraction> v5_i = new FieldVectorImpl<Fraction>(dvec1);
assertEquals(9, v5_i.getDimension());
assertEquals(new Fraction(9), v5_i.getEntry(8));
FieldVectorImpl<Fraction> v5 = new FieldVectorImpl<Fraction>(dvec1);
assertEquals(9, v5.getDimension());
assertEquals(new Fraction(9), v5.getEntry(8));
FieldVectorImpl<Fraction> v6 = new FieldVectorImpl<Fraction>(dvec1, 3, 2);
assertEquals(2, v6.getDimension());
assertEquals(new Fraction(4), v6.getEntry(0));
try {
new FieldVectorImpl<Fraction>(dvec1, 8, 3);
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException ex) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
}
FieldVectorImpl<Fraction> v7 = new FieldVectorImpl<Fraction>(v1);
assertEquals(7, v7.getDimension());
assertEquals(new Fraction(0), v7.getEntry(6));
FieldVectorTestImpl<Fraction> v7_i = new FieldVectorTestImpl<Fraction>(vec1);
FieldVectorImpl<Fraction> v7_2 = new FieldVectorImpl<Fraction>(v7_i);
assertEquals(3, v7_2.getDimension());
assertEquals(new Fraction(2), v7_2.getEntry(1));
FieldVectorImpl<Fraction> v8 = new FieldVectorImpl<Fraction>(v1, true);
assertEquals(7, v8.getDimension());
assertEquals(new Fraction(0), v8.getEntry(6));
assertNotSame("testData not same object ", v1.data, v8.data);
FieldVectorImpl<Fraction> v8_2 = new FieldVectorImpl<Fraction>(v1, false);
assertEquals(7, v8_2.getDimension());
assertEquals(new Fraction(0), v8_2.getEntry(6));
assertEquals(v1.data, v8_2.data);
FieldVectorImpl<Fraction> v9 = new FieldVectorImpl<Fraction>(v1, v3);
assertEquals(10, v9.getDimension());
assertEquals(new Fraction(1), v9.getEntry(7));
}
public void testDataInOut() {
FieldVectorImpl<Fraction> v1 = new FieldVectorImpl<Fraction>(vec1);
FieldVectorImpl<Fraction> v2 = new FieldVectorImpl<Fraction>(vec2);
FieldVectorImpl<Fraction> v4 = new FieldVectorImpl<Fraction>(vec4);
FieldVectorTestImpl<Fraction> v2_t = new FieldVectorTestImpl<Fraction>(vec2);
FieldVector<Fraction> v_append_1 = v1.append(v2);
assertEquals(6, v_append_1.getDimension());
assertEquals(new Fraction(4), v_append_1.getEntry(3));
FieldVector<Fraction> v_append_2 = v1.append(new Fraction(2));
assertEquals(4, v_append_2.getDimension());
assertEquals(new Fraction(2), v_append_2.getEntry(3));
FieldVector<Fraction> v_append_3 = v1.append(vec2);
assertEquals(6, v_append_3.getDimension());
assertEquals(new Fraction(4), v_append_3.getEntry(3));
FieldVector<Fraction> v_append_4 = v1.append(v2_t);
assertEquals(6, v_append_4.getDimension());
assertEquals(new Fraction(4), v_append_4.getEntry(3));
FieldVector<Fraction> v_copy = v1.copy();
assertEquals(3, v_copy.getDimension());
assertNotSame("testData not same object ", v1.data, v_copy.getData());
Fraction[] a_frac = v1.toArray();
assertEquals(3, a_frac.length);
assertNotSame("testData not same object ", v1.data, a_frac);
// FieldVectorImpl<Fraction> vout4 = (FieldVectorImpl<Fraction>) v1.clone();
// assertEquals(3, vout4.getDimension());
// assertEquals(v1.data, vout4.data);
FieldVector<Fraction> vout5 = v4.getSubVector(3, 3);
assertEquals(3, vout5.getDimension());
assertEquals(new Fraction(5), vout5.getEntry(1));
try {
v4.getSubVector(3, 7);
fail("MatrixIndexException expected");
} catch (MatrixIndexException ex) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
}
FieldVectorImpl<Fraction> v_set1 = (FieldVectorImpl<Fraction>) v1.copy();
v_set1.setEntry(1, new Fraction(11));
assertEquals(new Fraction(11), v_set1.getEntry(1));
try {
v_set1.setEntry(3, new Fraction(11));
fail("MatrixIndexException expected");
} catch (MatrixIndexException ex) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
}
FieldVectorImpl<Fraction> v_set2 = (FieldVectorImpl<Fraction>) v4.copy();
v_set2.set(3, v1);
assertEquals(new Fraction(1), v_set2.getEntry(3));
assertEquals(new Fraction(7), v_set2.getEntry(6));
try {
v_set2.set(7, v1);
fail("MatrixIndexException expected");
} catch (MatrixIndexException ex) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
}
FieldVectorImpl<Fraction> v_set3 = (FieldVectorImpl<Fraction>) v1.copy();
v_set3.set(new Fraction(13));
assertEquals(new Fraction(13), v_set3.getEntry(2));
try {
v_set3.getEntry(23);
fail("ArrayIndexOutOfBoundsException expected");
} catch (ArrayIndexOutOfBoundsException ex) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
}
FieldVectorImpl<Fraction> v_set4 = (FieldVectorImpl<Fraction>) v4.copy();
v_set4.setSubVector(3, v2_t);
assertEquals(new Fraction(4), v_set4.getEntry(3));
assertEquals(new Fraction(7), v_set4.getEntry(6));
try {
v_set4.setSubVector(7, v2_t);
fail("MatrixIndexException expected");
} catch (MatrixIndexException ex) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
}
FieldVectorImpl<Fraction> vout10 = (FieldVectorImpl<Fraction>) v1.copy();
FieldVectorImpl<Fraction> vout10_2 = (FieldVectorImpl<Fraction>) v1.copy();
assertEquals(vout10, vout10_2);
vout10_2.setEntry(0, new Fraction(11, 10));
assertNotSame(vout10, vout10_2);
}
public void testMapFunctions() {
FieldVectorImpl<Fraction> v1 = new FieldVectorImpl<Fraction>(vec1);
//octave = v1 .+ 2.0
FieldVector<Fraction> v_mapAdd = v1.mapAdd(new Fraction(2));
Fraction[] result_mapAdd = {new Fraction(3), new Fraction(4), new Fraction(5)};
checkArray("compare vectors" ,result_mapAdd,v_mapAdd.getData());
//octave = v1 .+ 2.0
FieldVector<Fraction> v_mapAddToSelf = v1.copy();
v_mapAddToSelf.mapAddToSelf(new Fraction(2));
Fraction[] result_mapAddToSelf = {new Fraction(3), new Fraction(4), new Fraction(5)};
checkArray("compare vectors" ,result_mapAddToSelf,v_mapAddToSelf.getData());
//octave = v1 .- 2.0
FieldVector<Fraction> v_mapSubtract = v1.mapSubtract(new Fraction(2));
Fraction[] result_mapSubtract = {new Fraction(-1), new Fraction(0), new Fraction(1)};
checkArray("compare vectors" ,result_mapSubtract,v_mapSubtract.getData());
//octave = v1 .- 2.0
FieldVector<Fraction> v_mapSubtractToSelf = v1.copy();
v_mapSubtractToSelf.mapSubtractToSelf(new Fraction(2));
Fraction[] result_mapSubtractToSelf = {new Fraction(-1), new Fraction(0), new Fraction(1)};
checkArray("compare vectors" ,result_mapSubtractToSelf,v_mapSubtractToSelf.getData());
//octave = v1 .* 2.0
FieldVector<Fraction> v_mapMultiply = v1.mapMultiply(new Fraction(2));
Fraction[] result_mapMultiply = {new Fraction(2), new Fraction(4), new Fraction(6)};
checkArray("compare vectors" ,result_mapMultiply,v_mapMultiply.getData());
//octave = v1 .* 2.0
FieldVector<Fraction> v_mapMultiplyToSelf = v1.copy();
v_mapMultiplyToSelf.mapMultiplyToSelf(new Fraction(2));
Fraction[] result_mapMultiplyToSelf = {new Fraction(2), new Fraction(4), new Fraction(6)};
checkArray("compare vectors" ,result_mapMultiplyToSelf,v_mapMultiplyToSelf.getData());
//octave = v1 ./ 2.0
FieldVector<Fraction> v_mapDivide = v1.mapDivide(new Fraction(2));
Fraction[] result_mapDivide = {new Fraction(1, 2), new Fraction(1), new Fraction(3, 2)};
checkArray("compare vectors" ,result_mapDivide,v_mapDivide.getData());
//octave = v1 ./ 2.0
FieldVector<Fraction> v_mapDivideToSelf = v1.copy();
v_mapDivideToSelf.mapDivideToSelf(new Fraction(2));
Fraction[] result_mapDivideToSelf = {new Fraction(1, 2), new Fraction(1), new Fraction(3, 2)};
checkArray("compare vectors" ,result_mapDivideToSelf,v_mapDivideToSelf.getData());
//octave = v1 .^-1
FieldVector<Fraction> v_mapInv = v1.mapInv();
Fraction[] result_mapInv = {new Fraction(1),new Fraction(1, 2),new Fraction(1, 3)};
checkArray("compare vectors" ,result_mapInv,v_mapInv.getData());
//octave = v1 .^-1
FieldVector<Fraction> v_mapInvToSelf = v1.copy();
v_mapInvToSelf.mapInvToSelf();
Fraction[] result_mapInvToSelf = {new Fraction(1),new Fraction(1, 2),new Fraction(1, 3)};
checkArray("compare vectors" ,result_mapInvToSelf,v_mapInvToSelf.getData());
}
public void testBasicFunctions() {
FieldVectorImpl<Fraction> v1 = new FieldVectorImpl<Fraction>(vec1);
FieldVectorImpl<Fraction> v2 = new FieldVectorImpl<Fraction>(vec2);
new FieldVectorImpl<Fraction>(vec_null);
FieldVectorTestImpl<Fraction> v2_t = new FieldVectorTestImpl<Fraction>(vec2);
//octave = v1 + v2
FieldVectorImpl<Fraction> v_add = v1.add(v2);
Fraction[] result_add = {new Fraction(5), new Fraction(7), new Fraction(9)};
checkArray("compare vect" ,v_add.getData(),result_add);
FieldVectorTestImpl<Fraction> vt2 = new FieldVectorTestImpl<Fraction>(vec2);
FieldVector<Fraction> v_add_i = v1.add(vt2);
Fraction[] result_add_i = {new Fraction(5), new Fraction(7), new Fraction(9)};
checkArray("compare vect" ,v_add_i.getData(),result_add_i);
//octave = v1 - v2
FieldVectorImpl<Fraction> v_subtract = v1.subtract(v2);
Fraction[] result_subtract = {new Fraction(-3), new Fraction(-3), new Fraction(-3)};
checkArray("compare vect" ,v_subtract.getData(),result_subtract);
FieldVector<Fraction> v_subtract_i = v1.subtract(vt2);
Fraction[] result_subtract_i = {new Fraction(-3), new Fraction(-3), new Fraction(-3)};
checkArray("compare vect" ,v_subtract_i.getData(),result_subtract_i);
// octave v1 .* v2
FieldVectorImpl<Fraction> v_ebeMultiply = v1.ebeMultiply(v2);
Fraction[] result_ebeMultiply = {new Fraction(4), new Fraction(10), new Fraction(18)};
checkArray("compare vect" ,v_ebeMultiply.getData(),result_ebeMultiply);
FieldVector<Fraction> v_ebeMultiply_2 = v1.ebeMultiply(v2_t);
Fraction[] result_ebeMultiply_2 = {new Fraction(4), new Fraction(10), new Fraction(18)};
checkArray("compare vect" ,v_ebeMultiply_2.getData(),result_ebeMultiply_2);
// octave v1 ./ v2
FieldVectorImpl<Fraction> v_ebeDivide = v1.ebeDivide(v2);
Fraction[] result_ebeDivide = {new Fraction(1, 4), new Fraction(2, 5), new Fraction(1, 2)};
checkArray("compare vect" ,v_ebeDivide.getData(),result_ebeDivide);
FieldVector<Fraction> v_ebeDivide_2 = v1.ebeDivide(v2_t);
Fraction[] result_ebeDivide_2 = {new Fraction(1, 4), new Fraction(2, 5), new Fraction(1, 2)};
checkArray("compare vect" ,v_ebeDivide_2.getData(),result_ebeDivide_2);
// octave dot(v1,v2)
Fraction dot = v1.dotProduct(v2);
assertEquals("compare val ",new Fraction(32), dot);
// octave dot(v1,v2_t)
Fraction dot_2 = v1.dotProduct(v2_t);
assertEquals("compare val ",new Fraction(32), dot_2);
FieldMatrix<Fraction> m_outerProduct = v1.outerProduct(v2);
assertEquals("compare val ",new Fraction(4), m_outerProduct.getEntry(0,0));
FieldMatrix<Fraction> m_outerProduct_2 = v1.outerProduct(v2_t);
assertEquals("compare val ",new Fraction(4), m_outerProduct_2.getEntry(0,0));
FieldVectorImpl<Fraction> v_projection = v1.projection(v2);
Fraction[] result_projection = {new Fraction(128, 77), new Fraction(160, 77), new Fraction(192, 77)};
checkArray("compare vect", v_projection.getData(), result_projection);
FieldVector<Fraction> v_projection_2 = v1.projection(v2_t);
Fraction[] result_projection_2 = {new Fraction(128, 77), new Fraction(160, 77), new Fraction(192, 77)};
checkArray("compare vect", v_projection_2.getData(), result_projection_2);
}
public void testMisc() {
FieldVectorImpl<Fraction> v1 = new FieldVectorImpl<Fraction>(vec1);
FieldVectorImpl<Fraction> v4 = new FieldVectorImpl<Fraction>(vec4);
FieldVector<Fraction> v4_2 = new FieldVectorImpl<Fraction>(vec4);
String out1 = v1.toString();
assertTrue("some output ", out1.length()!=0);
/*
Fraction[] dout1 = v1.copyOut();
assertEquals(3, dout1.length);
assertNotSame("testData not same object ", v1.data, dout1);
*/
try {
v1.checkVectorDimensions(2);
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException ex) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
}
try {
v1.checkVectorDimensions(v4);
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException ex) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
}
try {
v1.checkVectorDimensions(v4_2);
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException ex) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
}
}
/** verifies that two vectors are equals */
protected void checkArray(String msg, Fraction[] m, Fraction[] n) {
if (m.length != n.length) {
fail("vectors have different lengths");
}
for (int i = 0; i < m.length; i++) {
assertEquals(msg + " " + i + " elements differ", m[i],n[i]);
}
}
}

View File

@ -0,0 +1,309 @@
/*
* 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.commons.math.linear.decomposition;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.commons.math.TestUtils;
import org.apache.commons.math.fraction.Fraction;
import org.apache.commons.math.fraction.FractionField;
import org.apache.commons.math.linear.FieldMatrix;
import org.apache.commons.math.linear.FieldMatrixImpl;
import org.apache.commons.math.linear.InvalidMatrixException;
public class FieldLUDecompositionImplTest extends TestCase {
private Fraction[][] testData = {
{ new Fraction(1), new Fraction(2), new Fraction(3)},
{ new Fraction(2), new Fraction(5), new Fraction(3)},
{ new Fraction(1), new Fraction(0), new Fraction(8)}
};
private Fraction[][] testDataMinus = {
{ new Fraction(-1), new Fraction(-2), new Fraction(-3)},
{ new Fraction(-2), new Fraction(-5), new Fraction(-3)},
{ new Fraction(-1), new Fraction(0), new Fraction(-8)}
};
private Fraction[][] luData = {
{ new Fraction(2), new Fraction(3), new Fraction(3) },
{ new Fraction(2), new Fraction(3), new Fraction(7) },
{ new Fraction(6), new Fraction(6), new Fraction(8) }
};
// singular matrices
private Fraction[][] singular = {
{ new Fraction(2), new Fraction(3) },
{ new Fraction(2), new Fraction(3) }
};
private Fraction[][] bigSingular = {
{ new Fraction(1), new Fraction(2), new Fraction(3), new Fraction(4) },
{ new Fraction(2), new Fraction(5), new Fraction(3), new Fraction(4) },
{ new Fraction(7), new Fraction(3), new Fraction(256), new Fraction(1930) },
{ new Fraction(3), new Fraction(7), new Fraction(6), new Fraction(8) }
}; // 4th row = 1st + 2nd
public FieldLUDecompositionImplTest(String name) {
super(name);
}
public static Test suite() {
TestSuite suite = new TestSuite(FieldLUDecompositionImplTest.class);
suite.setName("FieldLUDecompositionImpl Tests");
return suite;
}
/** test dimensions */
public void testDimensions() {
FieldMatrix<Fraction> matrix = new FieldMatrixImpl<Fraction>(testData);
FieldLUDecomposition<Fraction> LU = new FieldLUDecompositionImpl<Fraction>(matrix);
assertEquals(testData.length, LU.getL().getRowDimension());
assertEquals(testData.length, LU.getL().getColumnDimension());
assertEquals(testData.length, LU.getU().getRowDimension());
assertEquals(testData.length, LU.getU().getColumnDimension());
assertEquals(testData.length, LU.getP().getRowDimension());
assertEquals(testData.length, LU.getP().getColumnDimension());
}
/** test non-square matrix */
public void testNonSquare() {
try {
new FieldLUDecompositionImpl<Fraction>(new FieldMatrixImpl<Fraction>(new Fraction[][] {
{ Fraction.ZERO, Fraction.ZERO },
{ Fraction.ZERO, Fraction.ZERO },
{ Fraction.ZERO, Fraction.ZERO }
}));
} catch (InvalidMatrixException ime) {
// expected behavior
} catch (Exception e) {
fail("wrong exception caught");
}
}
/** test PA = LU */
public void testPAEqualLU() {
FieldMatrix<Fraction> matrix = new FieldMatrixImpl<Fraction>(testData);
FieldLUDecomposition<Fraction> lu = new FieldLUDecompositionImpl<Fraction>(matrix);
FieldMatrix<Fraction> l = lu.getL();
FieldMatrix<Fraction> u = lu.getU();
FieldMatrix<Fraction> p = lu.getP();
TestUtils.assertEquals(p.multiply(matrix), l.multiply(u));
matrix = new FieldMatrixImpl<Fraction>(testDataMinus);
lu = new FieldLUDecompositionImpl<Fraction>(matrix);
l = lu.getL();
u = lu.getU();
p = lu.getP();
TestUtils.assertEquals(p.multiply(matrix), l.multiply(u));
matrix = new FieldMatrixImpl<Fraction>(FractionField.getInstance(), 17, 17);
for (int i = 0; i < matrix.getRowDimension(); ++i) {
matrix.setEntry(i, i, Fraction.ONE);
}
lu = new FieldLUDecompositionImpl<Fraction>(matrix);
l = lu.getL();
u = lu.getU();
p = lu.getP();
TestUtils.assertEquals(p.multiply(matrix), l.multiply(u));
matrix = new FieldMatrixImpl<Fraction>(singular);
lu = new FieldLUDecompositionImpl<Fraction>(matrix);
assertFalse(lu.getSolver().isNonSingular());
assertNull(lu.getL());
assertNull(lu.getU());
assertNull(lu.getP());
matrix = new FieldMatrixImpl<Fraction>(bigSingular);
lu = new FieldLUDecompositionImpl<Fraction>(matrix);
assertFalse(lu.getSolver().isNonSingular());
assertNull(lu.getL());
assertNull(lu.getU());
assertNull(lu.getP());
}
/** test that L is lower triangular with unit diagonal */
public void testLLowerTriangular() {
FieldMatrix<Fraction> matrix = new FieldMatrixImpl<Fraction>(testData);
FieldMatrix<Fraction> l = new FieldLUDecompositionImpl<Fraction>(matrix).getL();
for (int i = 0; i < l.getRowDimension(); i++) {
assertEquals(Fraction.ONE, l.getEntry(i, i));
for (int j = i + 1; j < l.getColumnDimension(); j++) {
assertEquals(Fraction.ZERO, l.getEntry(i, j));
}
}
}
/** test that U is upper triangular */
public void testUUpperTriangular() {
FieldMatrix<Fraction> matrix = new FieldMatrixImpl<Fraction>(testData);
FieldMatrix<Fraction> u = new FieldLUDecompositionImpl<Fraction>(matrix).getU();
for (int i = 0; i < u.getRowDimension(); i++) {
for (int j = 0; j < i; j++) {
assertEquals(Fraction.ZERO, u.getEntry(i, j));
}
}
}
/** test that P is a permutation matrix */
public void testPPermutation() {
FieldMatrix<Fraction> matrix = new FieldMatrixImpl<Fraction>(testData);
FieldMatrix<Fraction> p = new FieldLUDecompositionImpl<Fraction>(matrix).getP();
FieldMatrix<Fraction> ppT = p.multiply(p.transpose());
FieldMatrix<Fraction> id =
new FieldMatrixImpl<Fraction>(FractionField.getInstance(),
p.getRowDimension(), p.getRowDimension());
for (int i = 0; i < id.getRowDimension(); ++i) {
id.setEntry(i, i, Fraction.ONE);
}
TestUtils.assertEquals(id, ppT);
for (int i = 0; i < p.getRowDimension(); i++) {
int zeroCount = 0;
int oneCount = 0;
int otherCount = 0;
for (int j = 0; j < p.getColumnDimension(); j++) {
final Fraction e = p.getEntry(i, j);
if (e.equals(Fraction.ZERO)) {
++zeroCount;
} else if (e.equals(Fraction.ONE)) {
++oneCount;
} else {
++otherCount;
}
}
assertEquals(p.getColumnDimension() - 1, zeroCount);
assertEquals(1, oneCount);
assertEquals(0, otherCount);
}
for (int j = 0; j < p.getColumnDimension(); j++) {
int zeroCount = 0;
int oneCount = 0;
int otherCount = 0;
for (int i = 0; i < p.getRowDimension(); i++) {
final Fraction e = p.getEntry(i, j);
if (e.equals(Fraction.ZERO)) {
++zeroCount;
} else if (e.equals(Fraction.ONE)) {
++oneCount;
} else {
++otherCount;
}
}
assertEquals(p.getRowDimension() - 1, zeroCount);
assertEquals(1, oneCount);
assertEquals(0, otherCount);
}
}
/** test singular */
public void testSingular() {
FieldLUDecomposition<Fraction> lu =
new FieldLUDecompositionImpl<Fraction>(new FieldMatrixImpl<Fraction>(testData));
assertTrue(lu.getSolver().isNonSingular());
lu = new FieldLUDecompositionImpl<Fraction>(new FieldMatrixImpl<Fraction>(singular));
assertFalse(lu.getSolver().isNonSingular());
lu = new FieldLUDecompositionImpl<Fraction>(new FieldMatrixImpl<Fraction>(bigSingular));
assertFalse(lu.getSolver().isNonSingular());
}
/** test matrices values */
public void testMatricesValues1() {
FieldLUDecomposition<Fraction> lu =
new FieldLUDecompositionImpl<Fraction>(new FieldMatrixImpl<Fraction>(testData));
FieldMatrix<Fraction> lRef = new FieldMatrixImpl<Fraction>(new Fraction[][] {
{ new Fraction(1), new Fraction(0), new Fraction(0) },
{ new Fraction(2), new Fraction(1), new Fraction(0) },
{ new Fraction(1), new Fraction(-2), new Fraction(1) }
});
FieldMatrix<Fraction> uRef = new FieldMatrixImpl<Fraction>(new Fraction[][] {
{ new Fraction(1), new Fraction(2), new Fraction(3) },
{ new Fraction(0), new Fraction(1), new Fraction(-3) },
{ new Fraction(0), new Fraction(0), new Fraction(-1) }
});
FieldMatrix<Fraction> pRef = new FieldMatrixImpl<Fraction>(new Fraction[][] {
{ new Fraction(1), new Fraction(0), new Fraction(0) },
{ new Fraction(0), new Fraction(1), new Fraction(0) },
{ new Fraction(0), new Fraction(0), new Fraction(1) }
});
int[] pivotRef = { 0, 1, 2 };
// check values against known references
FieldMatrix<Fraction> l = lu.getL();
TestUtils.assertEquals(lRef, l);
FieldMatrix<Fraction> u = lu.getU();
TestUtils.assertEquals(uRef, u);
FieldMatrix<Fraction> p = lu.getP();
TestUtils.assertEquals(pRef, p);
int[] pivot = lu.getPivot();
for (int i = 0; i < pivotRef.length; ++i) {
assertEquals(pivotRef[i], pivot[i]);
}
// check the same cached instance is returned the second time
assertTrue(l == lu.getL());
assertTrue(u == lu.getU());
assertTrue(p == lu.getP());
}
/** test matrices values */
public void testMatricesValues2() {
FieldLUDecomposition<Fraction> lu =
new FieldLUDecompositionImpl<Fraction>(new FieldMatrixImpl<Fraction>(luData));
FieldMatrix<Fraction> lRef = new FieldMatrixImpl<Fraction>(new Fraction[][] {
{ new Fraction(1), new Fraction(0), new Fraction(0) },
{ new Fraction(3), new Fraction(1), new Fraction(0) },
{ new Fraction(1), new Fraction(0), new Fraction(1) }
});
FieldMatrix<Fraction> uRef = new FieldMatrixImpl<Fraction>(new Fraction[][] {
{ new Fraction(2), new Fraction(3), new Fraction(3) },
{ new Fraction(0), new Fraction(-3), new Fraction(-1) },
{ new Fraction(0), new Fraction(0), new Fraction(4) }
});
FieldMatrix<Fraction> pRef = new FieldMatrixImpl<Fraction>(new Fraction[][] {
{ new Fraction(1), new Fraction(0), new Fraction(0) },
{ new Fraction(0), new Fraction(0), new Fraction(1) },
{ new Fraction(0), new Fraction(1), new Fraction(0) }
});
int[] pivotRef = { 0, 2, 1 };
// check values against known references
FieldMatrix<Fraction> l = lu.getL();
TestUtils.assertEquals(lRef, l);
FieldMatrix<Fraction> u = lu.getU();
TestUtils.assertEquals(uRef, u);
FieldMatrix<Fraction> p = lu.getP();
TestUtils.assertEquals(pRef, p);
int[] pivot = lu.getPivot();
for (int i = 0; i < pivotRef.length; ++i) {
assertEquals(pivotRef[i], pivot[i]);
}
// check the same cached instance is returned the second time
assertTrue(l == lu.getL());
assertTrue(u == lu.getU());
assertTrue(p == lu.getP());
}
}