Added solve methods using double[][] to linear algebra decomposition solvers.

JIRA: MATH-564

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1097730 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2011-04-29 08:48:38 +00:00
parent 40daf0a0d5
commit 1047f93f68
12 changed files with 138 additions and 30 deletions

View File

@ -273,15 +273,34 @@ public class CholeskyDecompositionImpl implements CholeskyDecomposition {
return new ArrayRealVector(solve(b.getDataRef()), false); return new ArrayRealVector(solve(b.getDataRef()), false);
} }
/** {@inheritDoc} */ /** Solve the linear equation A × X = B for matrices A.
public RealMatrix solve(RealMatrix b) { * <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
* @param reUseB if true, the b array will be reused and returned,
* instead of being copied
* @return a matrix X that minimizes the two norm of A &times; X - B
* @throws org.apache.commons.math.exception.DimensionMismatchException
* if the matrices dimensions do not match.
* @throws SingularMatrixException
* if the decomposed matrix is singular.
*/
private double[][] solve(double[][] b, boolean reUseB) {
final int m = lTData.length; final int m = lTData.length;
if (b.getRowDimension() != m) { if (b.length != m) {
throw new DimensionMismatchException(b.getRowDimension(), m); throw new DimensionMismatchException(b.length, m);
} }
final int nColB = b.getColumnDimension(); final int nColB = b[0].length;
double[][] x = b.getData(); final double[][] x;
if (reUseB) {
x = b;
} else {
x = new double[b.length][nColB];
for (int i = 0; i < b.length; ++i) {
System.arraycopy(b[i], 0, x[i], 0, nColB);
}
}
// Solve LY = b // Solve LY = b
for (int j = 0; j < m; j++) { for (int j = 0; j < m; j++) {
@ -316,10 +335,20 @@ public class CholeskyDecompositionImpl implements CholeskyDecomposition {
} }
} }
return new Array2DRowRealMatrix(x, false); return x;
} }
/** {@inheritDoc} */
public double[][] solve(double[][] b) {
return solve(b, false);
}
/** {@inheritDoc} */
public RealMatrix solve(RealMatrix b) {
return new Array2DRowRealMatrix(solve(b.getData(), true), false);
}
/** {@inheritDoc} */ /** {@inheritDoc} */
public RealMatrix getInverse() { public RealMatrix getInverse() {
return solve(MatrixUtils.createRealIdentityMatrix(lTData.length)); return solve(MatrixUtils.createRealIdentityMatrix(lTData.length));

View File

@ -59,6 +59,18 @@ public interface DecompositionSolver {
*/ */
RealVector solve(final RealVector b); RealVector solve(final RealVector b);
/** 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
* @throws org.apache.commons.math.exception.DimensionMismatchException
* if the matrices dimensions do not match.
* @throws SingularMatrixException
* if the decomposed matrix is singular.
*/
double[][] solve(final double[][] b);
/** Solve the linear equation A &times; X = B for matrices A. /** Solve the linear equation A &times; X = B for matrices A.
* <p>The A matrix is implicit, it is provided by the underlying * <p>The A matrix is implicit, it is provided by the underlying
* decomposition algorithm.</p> * decomposition algorithm.</p>

View File

@ -338,37 +338,48 @@ public class EigenDecompositionImpl implements EigenDecomposition {
return new ArrayRealVector(bp, false); return new ArrayRealVector(bp, false);
} }
/** /** Solve the linear equation A &times; X = B for matrices A.
* Solve the linear equation A &times; X = B for symmetric matrices A. * <p>The A matrix is implicit, it is provided by the underlying
* <p> * decomposition algorithm.</p>
* This method only find exact linear solutions, i.e. solutions for * @param b right-hand side of the equation A &times; X = B
* which ||A &times; X - B|| is exactly 0. * @param reUseB if true, the b array will be reused and returned,
* </p> * instead of being copied
* @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
* @return a Matrix X that minimizes the two norm of A &times; X - B * @throws org.apache.commons.math.exception.DimensionMismatchException
* @throws DimensionMismatchException if the matrices dimensions do not match. * if the matrices dimensions do not match.
* @throws SingularMatrixException if the decomposed matrix is singular. * @throws SingularMatrixException
* if the decomposed matrix is singular.
*/ */
public RealMatrix solve(final RealMatrix b) { private double[][] solve(double[][] b, boolean reUseB) {
if (!isNonSingular()) { if (!isNonSingular()) {
throw new SingularMatrixException(); throw new SingularMatrixException();
} }
final int m = realEigenvalues.length; final int m = realEigenvalues.length;
if (b.getRowDimension() != m) { if (b.length != m) {
throw new DimensionMismatchException(b.getRowDimension(), m); throw new DimensionMismatchException(b.length, m);
} }
final int nColB = b.getColumnDimension(); final int nColB = b[0].length;
final double[][] bp = new double[m][nColB]; final double[][] bp;
if (reUseB) {
bp = b;
} else {
bp = new double[m][nColB];
}
final double[] tmpCol = new double[m];
for (int k = 0; k < nColB; ++k) { for (int k = 0; k < nColB; ++k) {
for (int i = 0; i < m; ++i) {
tmpCol[i] = b[i][k];
bp[i][k] = 0;
}
for (int i = 0; i < m; ++i) { for (int i = 0; i < m; ++i) {
final ArrayRealVector v = eigenvectors[i]; final ArrayRealVector v = eigenvectors[i];
final double[] vData = v.getDataRef(); final double[] vData = v.getDataRef();
double s = 0; double s = 0;
for (int j = 0; j < m; ++j) { for (int j = 0; j < m; ++j) {
s += v.getEntry(j) * b.getEntry(j, k); s += v.getEntry(j) * tmpCol[j];
} }
s /= realEigenvalues[i]; s /= realEigenvalues[i];
for (int j = 0; j < m; ++j) { for (int j = 0; j < m; ++j) {
@ -377,10 +388,20 @@ public class EigenDecompositionImpl implements EigenDecomposition {
} }
} }
return MatrixUtils.createRealMatrix(bp); return bp;
} }
/** {@inheritDoc} */
public double[][] solve(double[][] b) {
return solve(b, false);
}
/** {@inheritDoc} */
public RealMatrix solve(RealMatrix b) {
return new Array2DRowRealMatrix(solve(b.getData(), true), false);
}
/** /**
* Check if the decomposed matrix is non-singular. * Check if the decomposed matrix is non-singular.
* @return true if the decomposed matrix is non-singular * @return true if the decomposed matrix is non-singular

View File

@ -337,17 +337,17 @@ public class LUDecompositionImpl implements LUDecomposition {
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
public RealMatrix solve(RealMatrix b) { public double[][] solve(double[][] b) {
final int m = pivot.length; final int m = pivot.length;
if (b.getRowDimension() != m) { if (b.length != m) {
throw new DimensionMismatchException(b.getRowDimension(), m); throw new DimensionMismatchException(b.length, m);
} }
if (singular) { if (singular) {
throw new SingularMatrixException(); throw new SingularMatrixException();
} }
final int nColB = b.getColumnDimension(); final int nColB = b[0].length;
// Apply permutations to b // Apply permutations to b
final double[][] bp = new double[m][nColB]; final double[][] bp = new double[m][nColB];
@ -355,7 +355,7 @@ public class LUDecompositionImpl implements LUDecomposition {
final double[] bpRow = bp[row]; final double[] bpRow = bp[row];
final int pRow = pivot[row]; final int pRow = pivot[row];
for (int col = 0; col < nColB; col++) { for (int col = 0; col < nColB; col++) {
bpRow[col] = b.getEntry(pRow, col); bpRow[col] = b[pRow][col];
} }
} }
@ -387,7 +387,13 @@ public class LUDecompositionImpl implements LUDecomposition {
} }
} }
return new Array2DRowRealMatrix(bp, false); return bp;
}
/** {@inheritDoc} */
public RealMatrix solve(RealMatrix b) {
return new Array2DRowRealMatrix(solve(b.getData()), false);
} }
/** {@inheritDoc} */ /** {@inheritDoc} */

View File

@ -337,6 +337,11 @@ public class QRDecompositionImpl implements QRDecomposition {
return new ArrayRealVector(solve(b.getDataRef()), false); return new ArrayRealVector(solve(b.getDataRef()), false);
} }
/** {@inheritDoc} */
public double[][] solve(double[][] b) {
return solve(new BlockRealMatrix(b)).getData();
}
/** {@inheritDoc} */ /** {@inheritDoc} */
public RealMatrix solve(RealMatrix b) { public RealMatrix solve(RealMatrix b) {
final int n = qrt.length; final int n = qrt.length;

View File

@ -301,6 +301,22 @@ public class SingularValueDecompositionImpl implements SingularValueDecompositio
return pseudoInverse.operate(b); return pseudoInverse.operate(b);
} }
/**
* Solve the linear equation A &times; X = B in least square sense.
* <p>
* The m&times;n matrix A may not be square, the solution X is such that
* ||A &times; X - B|| is minimal.
* </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
* @throws org.apache.commons.math.exception.DimensionMismatchException
* if the matrices dimensions do not match.
*/
public double[][] solve(final double[][] b) {
return pseudoInverse.multiply(MatrixUtils.createRealMatrix(b)).getData();
}
/** /**
* Solve the linear equation A &times; X = B in least square sense. * Solve the linear equation A &times; X = B in least square sense.
* <p> * <p>

View File

@ -52,6 +52,9 @@ The <action> type attribute can be add,update,fix,remove.
If the output is not quite correct, check for invisible trailing spaces! If the output is not quite correct, check for invisible trailing spaces!
--> -->
<release version="3.0" date="TBD" description="TBD"> <release version="3.0" date="TBD" description="TBD">
<action dev="luc" type="add" issue="MATH-564">
Added solve methods using double[][] to linear algebra decomposition solvers.
</action>
<action dev="erans" type="add" issue="MATH-562"> <action dev="erans" type="add" issue="MATH-562">
Added an interpolator adapter for data with known period. Added an interpolator adapter for data with known period.
</action> </action>

View File

@ -81,6 +81,9 @@ public class CholeskySolverTest {
// using RealMatrix // using RealMatrix
Assert.assertEquals(0, solver.solve(b).subtract(xRef).getNorm(), 1.0e-13); Assert.assertEquals(0, solver.solve(b).subtract(xRef).getNorm(), 1.0e-13);
// using double[][]
Assert.assertEquals(0, MatrixUtils.createRealMatrix(solver.solve(b.getData())).subtract(xRef).getNorm(), 1.0e-13);
// using double[] // using double[]
for (int i = 0; i < b.getColumnDimension(); ++i) { for (int i = 0; i < b.getColumnDimension(); ++i) {
Assert.assertEquals(0, Assert.assertEquals(0,

View File

@ -120,6 +120,10 @@ public class EigenSolverTest {
RealMatrix solution=es.solve(b); RealMatrix solution=es.solve(b);
Assert.assertEquals(0, solution.subtract(xRef).getNorm(), 2.5e-12); Assert.assertEquals(0, solution.subtract(xRef).getNorm(), 2.5e-12);
// using double[][]
solution = MatrixUtils.createRealMatrix(es.solve(b.getData()));
Assert.assertEquals(0, solution.subtract(xRef).getNorm(), 2.5e-12);
// using double[] // using double[]
for (int i = 0; i < b.getColumnDimension(); ++i) { for (int i = 0; i < b.getColumnDimension(); ++i) {
Assert.assertEquals(0, Assert.assertEquals(0,

View File

@ -143,6 +143,9 @@ public class LUSolverTest {
// using RealMatrix // using RealMatrix
Assert.assertEquals(0, solver.solve(b).subtract(xRef).getNorm(), 1.0e-13); Assert.assertEquals(0, solver.solve(b).subtract(xRef).getNorm(), 1.0e-13);
// using double[][]
Assert.assertEquals(0, MatrixUtils.createRealMatrix(solver.solve(b.getData())).subtract(xRef).getNorm(), 1.0e-13);
// using double[] // using double[]
for (int i = 0; i < b.getColumnDimension(); ++i) { for (int i = 0; i < b.getColumnDimension(); ++i) {
Assert.assertEquals(0, Assert.assertEquals(0,

View File

@ -137,6 +137,9 @@ public class QRSolverTest {
// using RealMatrix // using RealMatrix
Assert.assertEquals(0, solver.solve(b).subtract(xRef).getNorm(), 2.0e-16 * xRef.getNorm()); Assert.assertEquals(0, solver.solve(b).subtract(xRef).getNorm(), 2.0e-16 * xRef.getNorm());
// using double[][]
Assert.assertEquals(0, MatrixUtils.createRealMatrix(solver.solve(b.getData())).subtract(xRef).getNorm(), 2.0e-16 * xRef.getNorm());
// using double[] // using double[]
for (int i = 0; i < b.getColumnDimension(); ++i) { for (int i = 0; i < b.getColumnDimension(); ++i) {
final double[] x = solver.solve(b.getColumn(i)); final double[] x = solver.solve(b.getColumn(i));

View File

@ -101,6 +101,9 @@ public class SingularValueSolverTest {
// using RealMatrix // using RealMatrix
Assert.assertEquals(0, solver.solve(b).subtract(xRef).getNorm(), normTolerance); Assert.assertEquals(0, solver.solve(b).subtract(xRef).getNorm(), normTolerance);
// using double[][]
Assert.assertEquals(0, MatrixUtils.createRealMatrix(solver.solve(b.getData())).subtract(xRef).getNorm(), normTolerance);
// using double[] // using double[]
for (int i = 0; i < b.getColumnDimension(); ++i) { for (int i = 0; i < b.getColumnDimension(); ++i) {
Assert.assertEquals(0, Assert.assertEquals(0,