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:
parent
40daf0a0d5
commit
1047f93f68
|
@ -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 × 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 × 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));
|
||||||
|
|
|
@ -59,6 +59,18 @@ public interface DecompositionSolver {
|
||||||
*/
|
*/
|
||||||
RealVector solve(final RealVector b);
|
RealVector solve(final RealVector b);
|
||||||
|
|
||||||
|
/** Solve the linear equation A × 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 × X = B
|
||||||
|
* @return a matrix X that minimizes the two norm of A × 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 × X = B for matrices A.
|
/** Solve the linear equation A × 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>
|
||||||
|
|
|
@ -338,37 +338,48 @@ public class EigenDecompositionImpl implements EigenDecomposition {
|
||||||
return new ArrayRealVector(bp, false);
|
return new ArrayRealVector(bp, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Solve the linear equation A × X = B for matrices A.
|
||||||
* Solve the linear equation A × 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 × X = B
|
||||||
* which ||A × 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 × X = B
|
* @return a matrix X that minimizes the two norm of A × X - B
|
||||||
* @return a Matrix X that minimizes the two norm of A × 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
|
||||||
|
|
|
@ -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} */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -301,6 +301,22 @@ public class SingularValueDecompositionImpl implements SingularValueDecompositio
|
||||||
return pseudoInverse.operate(b);
|
return pseudoInverse.operate(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solve the linear equation A × X = B in least square sense.
|
||||||
|
* <p>
|
||||||
|
* The m×n matrix A may not be square, the solution X is such that
|
||||||
|
* ||A × X - B|| is minimal.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param b Right-hand side of the equation A × X = B
|
||||||
|
* @return a matrix X that minimizes the two norm of A × 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 × X = B in least square sense.
|
* Solve the linear equation A × X = B in least square sense.
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue