Permalink
300484d Jan 4, 2017
2131 lines (1909 sloc) 80.5 KB
// Accord Math Library
// The Accord.NET Framework
// http://accord-framework.net
//
// Copyright © César Souza, 2009-2017
// cesarsouza at gmail.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// ======================================================================
// This code has been generated by a tool; do not edit manually. Instead,
// edit the T4 template Matrix.Elementwise.tt so this file can be regenerated.
// ======================================================================
namespace Accord.Math
{
using System;
using System.CodeDom.Compiler;
using Accord.Math;
using System.Runtime.CompilerServices;
using Accord.Math.Decompositions;
//[GeneratedCode("Accord.NET T4 Templates", "3.1")]
public static partial class Matrix
{
/// <summary>
/// Returns the solution matrix if the matrix is square or the least squares solution otherwise.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="rightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
/// <example>
/// <code>
/// // Create a matrix. Please note that this matrix
/// // is singular (i.e. not invertible), so only a
/// // least squares solution would be feasible here.
///
/// Double[,] matrix =
/// {
/// { 1, 2, 3 },
/// { 4, 5, 6 },
/// { 7, 8, 9 },
/// };
///
/// // Define a right side matrix b:
/// Double[,] rightSide = { {1}, {2}, {3} };
///
/// // Solve the linear system Ax = b by finding x:
/// Double[,] x = Matrix.Solve(matrix, rightSide, leastSquares: true);
///
/// // The answer should be { {-1/18}, {2/18}, {5/18} }.
/// </code>
/// </example>
///
public static Double[,] Solve(this Double[,] matrix, Double[,] rightSide, bool leastSquares = false)
{
int rows = matrix.GetLength(0);
int cols = matrix.GetLength(1);
if (rows != rightSide.GetLength(0))
throw new DimensionMismatchException("rightSide",
"The number of rows in the right hand side matrix must be "
+ "equal to the number of rows in the problem matrix.");
if (leastSquares)
{
return new SingularValueDecomposition(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(rightSide);
}
if (rows == cols)
{
// Solve by LU Decomposition if matrix is square.
return new LuDecomposition(matrix).Solve(rightSide);
}
else
{
if (cols < rows)
{
// Solve by QR Decomposition if not.
return new QrDecomposition(matrix).Solve(rightSide);
}
else
{
return new SingularValueDecomposition(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(rightSide);
}
}
}
/// <summary>
/// Returns the solution matrix if the matrix is square or the least squares solution otherwise.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="rightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
/// <example>
/// <code>
/// // Create a matrix. Please note that this matrix
/// // is singular (i.e. not invertible), so only a
/// // least squares solution would be feasible here.
///
/// Double[,] matrix =
/// {
/// { 1, 2, 3 },
/// { 4, 5, 6 },
/// { 7, 8, 9 },
/// };
///
/// // Define a right side vector b:
/// Double[] rightSide = { 1, 2, 3 };
///
/// // Solve the linear system Ax = b by finding x:
/// Double[] x = Matrix.Solve(matrix, rightSide, leastSquares: true);
///
/// // The answer should be { -1/18, 2/18, 5/18 }.
/// </code>
/// </example>
///
public static Double[] Solve(this Double[,] matrix, Double[] rightSide, bool leastSquares = false)
{
if (matrix == null)
throw new ArgumentNullException("matrix");
if (rightSide == null)
throw new ArgumentNullException("rightSide");
int rows = matrix.GetLength(0);
int cols = matrix.GetLength(1);
if (rows != rightSide.Length)
throw new DimensionMismatchException("rightSide",
"The right hand side vector must have the same length"
+ "as there are rows of the problem matrix.");
if (leastSquares)
{
return new SingularValueDecomposition(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(rightSide);
}
if (rows == cols)
{
// Solve by LU Decomposition if matrix is square.
return new LuDecomposition(matrix).Solve(rightSide);
}
else
{
if (cols < rows)
{
// Solve by QR Decomposition if not.
return new QrDecomposition(matrix).Solve(rightSide);
}
else
{
return new SingularValueDecomposition(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(rightSide);
}
}
}
/// <summary>
/// Computes the inverse of a matrix.
/// </summary>
///
public static Double[,] Inverse(this Double[,] matrix)
{
return Inverse(matrix, false);
}
/// <summary>
/// Computes the inverse of a matrix.
/// </summary>
///
public static Double[,] Inverse(this Double[,] matrix, bool inPlace)
{
int rows = matrix.GetLength(0);
int cols = matrix.GetLength(1);
if (rows != cols)
throw new ArgumentException("Matrix must be square", "matrix");
if (rows == 3)
{
// Special case for 3x3 matrices
Double a = matrix[0, 0], b = matrix[0, 1], c = matrix[0, 2];
Double d = matrix[1, 0], e = matrix[1, 1], f = matrix[1, 2];
Double g = matrix[2, 0], h = matrix[2, 1], i = matrix[2, 2];
Double den = a * (e * i - f * h) -
b * (d * i - f * g) +
c * (d * h - e * g);
if (den == 0)
throw new SingularMatrixException();
Double m = 1 / den;
var inv = (inPlace) ? matrix : new Double[3, 3];
inv[0, 0] = m * (e * i - f * h);
inv[0, 1] = m * (c * h - b * i);
inv[0, 2] = m * (b * f - c * e);
inv[1, 0] = m * (f * g - d * i);
inv[1, 1] = m * (a * i - c * g);
inv[1, 2] = m * (c * d - a * f);
inv[2, 0] = m * (d * h - e * g);
inv[2, 1] = m * (b * g - a * h);
inv[2, 2] = m * (a * e - b * d);
return inv;
}
if (rows == 2)
{
// Special case for 2x2 matrices
Double a = matrix[0, 0], b = matrix[0, 1];
Double c = matrix[1, 0], d = matrix[1, 1];
Double den = a * d - b * c;
if (den == 0)
throw new SingularMatrixException();
Double m = 1 / den;
var inv = (inPlace) ? matrix : new Double[2, 2];
inv[0, 0] = +m * d;
inv[0, 1] = -m * b;
inv[1, 0] = -m * c;
inv[1, 1] = +m * a;
return inv;
}
return new LuDecomposition(matrix, false, inPlace).Inverse();
}
/// <summary>
/// Computes the pseudo-inverse of a matrix.
/// </summary>
///
public static Double[,] PseudoInverse(this Double[,] matrix)
{
return new SingularValueDecomposition(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Inverse();
}
/// <summary>
/// Returns the solution matrix if the matrix is square or the least squares solution otherwise.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="rightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
/// <example>
/// <code>
/// // Create a matrix. Please note that this matrix
/// // is singular (i.e. not invertible), so only a
/// // least squares solution would be feasible here.
///
/// Double[,] matrix =
/// {
/// { 1, 2, 3 },
/// { 4, 5, 6 },
/// { 7, 8, 9 },
/// };
///
/// // Define a right side matrix b:
/// Double[,] rightSide = { {1}, {2}, {3} };
///
/// // Solve the linear system Ax = b by finding x:
/// Double[,] x = Matrix.Solve(matrix, rightSide, leastSquares: true);
///
/// // The answer should be { {-1/18}, {2/18}, {5/18} }.
/// </code>
/// </example>
///
public static Double[][] Solve(this Double[][] matrix, Double[][] rightSide, bool leastSquares = false)
{
if (matrix.Length != rightSide[0].Length)
{
throw new DimensionMismatchException("rightSide",
"The number of rows in the right hand side matrix must be "
+ "equal to the number of rows in the problem matrix.");
}
return matrix.Decompose(leastSquares).Solve(rightSide);
}
/// <summary>
/// Returns the solution matrix if the matrix is square or the least squares solution otherwise.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="rightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
/// <example>
/// <code>
/// // Create a matrix. Please note that this matrix
/// // is singular (i.e. not invertible), so only a
/// // least squares solution would be feasible here.
///
/// Double[,] matrix =
/// {
/// { 1, 2, 3 },
/// { 4, 5, 6 },
/// { 7, 8, 9 },
/// };
///
/// // Define a right side vector b:
/// Double[] rightSide = { 1, 2, 3 };
///
/// // Solve the linear system Ax = b by finding x:
/// Double[] x = Matrix.Solve(matrix, rightSide, leastSquares: true);
///
/// // The answer should be { -1/18, 2/18, 5/18 }.
/// </code>
/// </example>
///
public static Double[] Solve(this Double[][] matrix, Double[] rightSide, bool leastSquares = false)
{
if (matrix.Length != rightSide.Length)
{
throw new DimensionMismatchException("rightSide",
"The right hand side vector must have the same length"
+ "as there are rows of the problem matrix.");
}
return matrix.Decompose(leastSquares).Solve(rightSide);
}
/// <summary>
/// Returns the solution matrix for a linear system involving a diagonal matrix ion the right-hand side.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="diagonalRightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
public static Double[][] SolveForDiagonal(this Double[][] matrix, Double[] diagonalRightSide, bool leastSquares = false)
{
if (matrix.Length != diagonalRightSide.Length)
{
throw new DimensionMismatchException("diagonalRightSide",
"The right hand side matrix must have the same length"
+ "as there are rows of the problem matrix.");
}
return matrix.Decompose(leastSquares).SolveForDiagonal(diagonalRightSide);
}
/// <summary>
/// Creates a matrix decomposition that be used to compute the solution matrix if the
/// matrix is square or the least squares solution otherwise.
/// </summary>
///
public static ISolverMatrixDecomposition<Double> Decompose(this Double[,] matrix, bool leastSquares = false)
{
int rows = matrix.Rows();
int cols = matrix.Columns();
if (leastSquares)
{
return new SingularValueDecomposition(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true);
}
if (rows == cols)
{
// Solve by LU Decomposition if matrix is square.
return new LuDecomposition(matrix);
}
else
{
if (cols < rows)
{
// Solve by QR Decomposition if not.
return new QrDecomposition(matrix);
}
else
{
return new SingularValueDecomposition(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true);
}
}
}
/// <summary>
/// Creates a matrix decomposition that be used to compute the solution matrix if the
/// matrix is square or the least squares solution otherwise.
/// </summary>
///
public static ISolverArrayDecomposition<Double> Decompose(this Double[][] matrix, bool leastSquares = false)
{
int rows = matrix.Rows();
int cols = matrix.Columns();
if (leastSquares)
{
return new JaggedSingularValueDecomposition(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true);
}
if (rows == cols)
{
// Solve by LU Decomposition if matrix is square.
return new JaggedLuDecomposition(matrix);
}
else
{
if (cols < rows)
{
// Solve by QR Decomposition if not.
return new JaggedQrDecomposition(matrix);
}
else
{
return new JaggedSingularValueDecomposition(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true);
}
}
}
/// <summary>
/// Computes the inverse of a matrix.
/// </summary>
///
public static Double[][] Inverse(this Double[][] matrix)
{
return Inverse(matrix, false);
}
/// <summary>
/// Computes the inverse of a matrix.
/// </summary>
///
public static Double[][] Inverse(this Double[][] matrix, bool inPlace)
{
int rows = matrix.Length;
int cols = matrix[0].Length;
if (rows != cols)
throw new ArgumentException("Matrix must be square", "matrix");
if (rows == 3)
{
// Special case for 3x3 matrices
Double a = matrix[0][0], b = matrix[0][1], c = matrix[0][2];
Double d = matrix[1][0], e = matrix[1][1], f = matrix[1][2];
Double g = matrix[2][0], h = matrix[2][1], i = matrix[2][2];
Double den = a * (e * i - f * h) -
b * (d * i - f * g) +
c * (d * h - e * g);
if (den == 0)
throw new SingularMatrixException();
Double m = 1 / den;
var inv = matrix;
if (!inPlace)
{
inv = new Double[3][];
for (int j = 0; j < inv.Length; j++)
inv[j] = new Double[3];
}
inv[0][0] = m * (e * i - f * h);
inv[0][1] = m * (c * h - b * i);
inv[0][2] = m * (b * f - c * e);
inv[1][0] = m * (f * g - d * i);
inv[1][1] = m * (a * i - c * g);
inv[1][2] = m * (c * d - a * f);
inv[2][0] = m * (d * h - e * g);
inv[2][1] = m * (b * g - a * h);
inv[2][2] = m * (a * e - b * d);
return inv;
}
if (rows == 2)
{
// Special case for 2x2 matrices
Double a = matrix[0][0], b = matrix[0][1];
Double c = matrix[1][0], d = matrix[1][1];
Double den = a * d - b * c;
if (den == 0)
throw new SingularMatrixException();
Double m = 1 / den;
var inv = matrix;
if (!inPlace)
{
inv = new Double[2][];
for (int j = 0; j < inv.Length; j++)
inv[j] = new Double[2];
}
inv[0][0] = +m * d;
inv[0][1] = -m * b;
inv[1][0] = -m * c;
inv[1][1] = +m * a;
return inv;
}
return new JaggedLuDecomposition(matrix, false, inPlace).Inverse();
}
/// <summary>
/// Computes the pseudo-inverse of a matrix.
/// </summary>
///
public static Double[][] PseudoInverse(this Double[][] matrix)
{
return new JaggedSingularValueDecomposition(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Inverse();
}
/// <summary>
/// Divides two matrices by multiplying A by the inverse of B.
/// </summary>
///
/// <param name="a">The first matrix.</param>
/// <param name="b">The second matrix (which will be inverted).</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="b"/> is singular; false otherwise. Default is false.</param>
///
/// <returns>The result from the division <c>AB^-1</c> of the given matrices.</returns>
///
public static Double[,] Divide(this Double[,] a, Double[,] b, bool leastSquares = false)
{
int rows = b.Rows();
int cols = b.Columns();
if (leastSquares)
{
return new SingularValueDecomposition(b.Transpose(),
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(a.Transpose()).Transpose();
}
if (rows == cols && cols == a.Rows())
{
// Solve by LU Decomposition if matrix is square.
return new LuDecomposition(b, true).SolveTranspose(a);
}
else
{
if (rows <= cols)
{
// Solve by QR Decomposition if not.
return new QrDecomposition(b, true).SolveTranspose(a);
}
else
{
return new SingularValueDecomposition(b.Transpose(),
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(a.Transpose()).Transpose();
}
}
}
/// <summary>
/// Divides two matrices by multiplying A by the inverse of B.
/// </summary>
///
/// <param name="a">The first matrix.</param>
/// <param name="b">The second matrix (which will be inverted).</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="b"/> is singular; false otherwise. Default is false.</param>
///
/// <returns>The result from the division <c>AB^-1</c> of the given matrices.</returns>
///
public static Double[][] Divide(this Double[][] a, Double[][] b, bool leastSquares = false)
{
int rows = b.Rows();
int cols = b.Columns();
if (leastSquares)
{
return new JaggedSingularValueDecomposition(b.Transpose(),
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(a.Transpose()).Transpose();
}
if (rows == cols && cols == a.Rows())
{
// Solve by LU Decomposition if matrix is square.
return new JaggedLuDecomposition(b, true).SolveTranspose(a);
}
else
{
if (rows <= cols)
{
// Solve by QR Decomposition if not.
return new JaggedQrDecomposition(b, true).SolveTranspose(a);
}
else
{
return new JaggedSingularValueDecomposition(b.Transpose(),
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(a.Transpose()).Transpose();
}
}
}
/// <summary>
/// Gets the null-space of a column vector.
/// </summary>
///
public static Double[][] Null(this Double[] vector)
{
return Null(Jagged.ColumnVector(vector));
}
/// <summary>
/// Gets the null-space of a matrix.
/// </summary>
///
public static Double[][] Null(this Double[][] matrix)
{
var qr = new JaggedQrDecomposition(matrix, economy: false);
var Q = qr.OrthogonalFactor;
var threshold = matrix.GetLength().Max() * Constants.DoubleEpsilon;
int[] idx = qr.Diagonal.Find(x => (Double)Math.Abs(x) < threshold);
return Q.GetColumns(idx);
}
/// <summary>
/// Gets the null-space of a matrix.
/// </summary>
///
public static Double[,] Null(this Double[,] matrix)
{
var qr = new QrDecomposition(matrix, economy: false);
var Q = qr.OrthogonalFactor;
var threshold = matrix.GetLength().Max() * Constants.DoubleEpsilon;
int[] idx = qr.Diagonal.Find(x => (Double)Math.Abs(x) < threshold);
return Q.GetColumns(idx);
}
/// <summary>
/// Returns the solution matrix if the matrix is square or the least squares solution otherwise.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="rightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
/// <example>
/// <code>
/// // Create a matrix. Please note that this matrix
/// // is singular (i.e. not invertible), so only a
/// // least squares solution would be feasible here.
///
/// Single[,] matrix =
/// {
/// { 1, 2, 3 },
/// { 4, 5, 6 },
/// { 7, 8, 9 },
/// };
///
/// // Define a right side matrix b:
/// Single[,] rightSide = { {1}, {2}, {3} };
///
/// // Solve the linear system Ax = b by finding x:
/// Single[,] x = Matrix.Solve(matrix, rightSide, leastSquares: true);
///
/// // The answer should be { {-1/18}, {2/18}, {5/18} }.
/// </code>
/// </example>
///
public static Single[,] Solve(this Single[,] matrix, Single[,] rightSide, bool leastSquares = false)
{
int rows = matrix.GetLength(0);
int cols = matrix.GetLength(1);
if (rows != rightSide.GetLength(0))
throw new DimensionMismatchException("rightSide",
"The number of rows in the right hand side matrix must be "
+ "equal to the number of rows in the problem matrix.");
if (leastSquares)
{
return new SingularValueDecompositionF(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(rightSide);
}
if (rows == cols)
{
// Solve by LU Decomposition if matrix is square.
return new LuDecompositionF(matrix).Solve(rightSide);
}
else
{
if (cols < rows)
{
// Solve by QR Decomposition if not.
return new QrDecompositionF(matrix).Solve(rightSide);
}
else
{
return new SingularValueDecompositionF(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(rightSide);
}
}
}
/// <summary>
/// Returns the solution matrix if the matrix is square or the least squares solution otherwise.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="rightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
/// <example>
/// <code>
/// // Create a matrix. Please note that this matrix
/// // is singular (i.e. not invertible), so only a
/// // least squares solution would be feasible here.
///
/// Single[,] matrix =
/// {
/// { 1, 2, 3 },
/// { 4, 5, 6 },
/// { 7, 8, 9 },
/// };
///
/// // Define a right side vector b:
/// Single[] rightSide = { 1, 2, 3 };
///
/// // Solve the linear system Ax = b by finding x:
/// Single[] x = Matrix.Solve(matrix, rightSide, leastSquares: true);
///
/// // The answer should be { -1/18, 2/18, 5/18 }.
/// </code>
/// </example>
///
public static Single[] Solve(this Single[,] matrix, Single[] rightSide, bool leastSquares = false)
{
if (matrix == null)
throw new ArgumentNullException("matrix");
if (rightSide == null)
throw new ArgumentNullException("rightSide");
int rows = matrix.GetLength(0);
int cols = matrix.GetLength(1);
if (rows != rightSide.Length)
throw new DimensionMismatchException("rightSide",
"The right hand side vector must have the same length"
+ "as there are rows of the problem matrix.");
if (leastSquares)
{
return new SingularValueDecompositionF(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(rightSide);
}
if (rows == cols)
{
// Solve by LU Decomposition if matrix is square.
return new LuDecompositionF(matrix).Solve(rightSide);
}
else
{
if (cols < rows)
{
// Solve by QR Decomposition if not.
return new QrDecompositionF(matrix).Solve(rightSide);
}
else
{
return new SingularValueDecompositionF(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(rightSide);
}
}
}
/// <summary>
/// Computes the inverse of a matrix.
/// </summary>
///
public static Single[,] Inverse(this Single[,] matrix)
{
return Inverse(matrix, false);
}
/// <summary>
/// Computes the inverse of a matrix.
/// </summary>
///
public static Single[,] Inverse(this Single[,] matrix, bool inPlace)
{
int rows = matrix.GetLength(0);
int cols = matrix.GetLength(1);
if (rows != cols)
throw new ArgumentException("Matrix must be square", "matrix");
if (rows == 3)
{
// Special case for 3x3 matrices
Single a = matrix[0, 0], b = matrix[0, 1], c = matrix[0, 2];
Single d = matrix[1, 0], e = matrix[1, 1], f = matrix[1, 2];
Single g = matrix[2, 0], h = matrix[2, 1], i = matrix[2, 2];
Single den = a * (e * i - f * h) -
b * (d * i - f * g) +
c * (d * h - e * g);
if (den == 0)
throw new SingularMatrixException();
Single m = 1 / den;
var inv = (inPlace) ? matrix : new Single[3, 3];
inv[0, 0] = m * (e * i - f * h);
inv[0, 1] = m * (c * h - b * i);
inv[0, 2] = m * (b * f - c * e);
inv[1, 0] = m * (f * g - d * i);
inv[1, 1] = m * (a * i - c * g);
inv[1, 2] = m * (c * d - a * f);
inv[2, 0] = m * (d * h - e * g);
inv[2, 1] = m * (b * g - a * h);
inv[2, 2] = m * (a * e - b * d);
return inv;
}
if (rows == 2)
{
// Special case for 2x2 matrices
Single a = matrix[0, 0], b = matrix[0, 1];
Single c = matrix[1, 0], d = matrix[1, 1];
Single den = a * d - b * c;
if (den == 0)
throw new SingularMatrixException();
Single m = 1 / den;
var inv = (inPlace) ? matrix : new Single[2, 2];
inv[0, 0] = +m * d;
inv[0, 1] = -m * b;
inv[1, 0] = -m * c;
inv[1, 1] = +m * a;
return inv;
}
return new LuDecompositionF(matrix, false, inPlace).Inverse();
}
/// <summary>
/// Computes the pseudo-inverse of a matrix.
/// </summary>
///
public static Single[,] PseudoInverse(this Single[,] matrix)
{
return new SingularValueDecompositionF(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Inverse();
}
/// <summary>
/// Returns the solution matrix if the matrix is square or the least squares solution otherwise.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="rightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
/// <example>
/// <code>
/// // Create a matrix. Please note that this matrix
/// // is singular (i.e. not invertible), so only a
/// // least squares solution would be feasible here.
///
/// Single[,] matrix =
/// {
/// { 1, 2, 3 },
/// { 4, 5, 6 },
/// { 7, 8, 9 },
/// };
///
/// // Define a right side matrix b:
/// Single[,] rightSide = { {1}, {2}, {3} };
///
/// // Solve the linear system Ax = b by finding x:
/// Single[,] x = Matrix.Solve(matrix, rightSide, leastSquares: true);
///
/// // The answer should be { {-1/18}, {2/18}, {5/18} }.
/// </code>
/// </example>
///
public static Single[][] Solve(this Single[][] matrix, Single[][] rightSide, bool leastSquares = false)
{
if (matrix.Length != rightSide[0].Length)
{
throw new DimensionMismatchException("rightSide",
"The number of rows in the right hand side matrix must be "
+ "equal to the number of rows in the problem matrix.");
}
return matrix.Decompose(leastSquares).Solve(rightSide);
}
/// <summary>
/// Returns the solution matrix if the matrix is square or the least squares solution otherwise.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="rightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
/// <example>
/// <code>
/// // Create a matrix. Please note that this matrix
/// // is singular (i.e. not invertible), so only a
/// // least squares solution would be feasible here.
///
/// Single[,] matrix =
/// {
/// { 1, 2, 3 },
/// { 4, 5, 6 },
/// { 7, 8, 9 },
/// };
///
/// // Define a right side vector b:
/// Single[] rightSide = { 1, 2, 3 };
///
/// // Solve the linear system Ax = b by finding x:
/// Single[] x = Matrix.Solve(matrix, rightSide, leastSquares: true);
///
/// // The answer should be { -1/18, 2/18, 5/18 }.
/// </code>
/// </example>
///
public static Single[] Solve(this Single[][] matrix, Single[] rightSide, bool leastSquares = false)
{
if (matrix.Length != rightSide.Length)
{
throw new DimensionMismatchException("rightSide",
"The right hand side vector must have the same length"
+ "as there are rows of the problem matrix.");
}
return matrix.Decompose(leastSquares).Solve(rightSide);
}
/// <summary>
/// Returns the solution matrix for a linear system involving a diagonal matrix ion the right-hand side.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="diagonalRightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
public static Single[][] SolveForDiagonal(this Single[][] matrix, Single[] diagonalRightSide, bool leastSquares = false)
{
if (matrix.Length != diagonalRightSide.Length)
{
throw new DimensionMismatchException("diagonalRightSide",
"The right hand side matrix must have the same length"
+ "as there are rows of the problem matrix.");
}
return matrix.Decompose(leastSquares).SolveForDiagonal(diagonalRightSide);
}
/// <summary>
/// Creates a matrix decomposition that be used to compute the solution matrix if the
/// matrix is square or the least squares solution otherwise.
/// </summary>
///
public static ISolverMatrixDecomposition<Single> Decompose(this Single[,] matrix, bool leastSquares = false)
{
int rows = matrix.Rows();
int cols = matrix.Columns();
if (leastSquares)
{
return new SingularValueDecompositionF(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true);
}
if (rows == cols)
{
// Solve by LU Decomposition if matrix is square.
return new LuDecompositionF(matrix);
}
else
{
if (cols < rows)
{
// Solve by QR Decomposition if not.
return new QrDecompositionF(matrix);
}
else
{
return new SingularValueDecompositionF(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true);
}
}
}
/// <summary>
/// Creates a matrix decomposition that be used to compute the solution matrix if the
/// matrix is square or the least squares solution otherwise.
/// </summary>
///
public static ISolverArrayDecomposition<Single> Decompose(this Single[][] matrix, bool leastSquares = false)
{
int rows = matrix.Rows();
int cols = matrix.Columns();
if (leastSquares)
{
return new JaggedSingularValueDecompositionF(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true);
}
if (rows == cols)
{
// Solve by LU Decomposition if matrix is square.
return new JaggedLuDecompositionF(matrix);
}
else
{
if (cols < rows)
{
// Solve by QR Decomposition if not.
return new JaggedQrDecompositionF(matrix);
}
else
{
return new JaggedSingularValueDecompositionF(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true);
}
}
}
/// <summary>
/// Computes the inverse of a matrix.
/// </summary>
///
public static Single[][] Inverse(this Single[][] matrix)
{
return Inverse(matrix, false);
}
/// <summary>
/// Computes the inverse of a matrix.
/// </summary>
///
public static Single[][] Inverse(this Single[][] matrix, bool inPlace)
{
int rows = matrix.Length;
int cols = matrix[0].Length;
if (rows != cols)
throw new ArgumentException("Matrix must be square", "matrix");
if (rows == 3)
{
// Special case for 3x3 matrices
Single a = matrix[0][0], b = matrix[0][1], c = matrix[0][2];
Single d = matrix[1][0], e = matrix[1][1], f = matrix[1][2];
Single g = matrix[2][0], h = matrix[2][1], i = matrix[2][2];
Single den = a * (e * i - f * h) -
b * (d * i - f * g) +
c * (d * h - e * g);
if (den == 0)
throw new SingularMatrixException();
Single m = 1 / den;
var inv = matrix;
if (!inPlace)
{
inv = new Single[3][];
for (int j = 0; j < inv.Length; j++)
inv[j] = new Single[3];
}
inv[0][0] = m * (e * i - f * h);
inv[0][1] = m * (c * h - b * i);
inv[0][2] = m * (b * f - c * e);
inv[1][0] = m * (f * g - d * i);
inv[1][1] = m * (a * i - c * g);
inv[1][2] = m * (c * d - a * f);
inv[2][0] = m * (d * h - e * g);
inv[2][1] = m * (b * g - a * h);
inv[2][2] = m * (a * e - b * d);
return inv;
}
if (rows == 2)
{
// Special case for 2x2 matrices
Single a = matrix[0][0], b = matrix[0][1];
Single c = matrix[1][0], d = matrix[1][1];
Single den = a * d - b * c;
if (den == 0)
throw new SingularMatrixException();
Single m = 1 / den;
var inv = matrix;
if (!inPlace)
{
inv = new Single[2][];
for (int j = 0; j < inv.Length; j++)
inv[j] = new Single[2];
}
inv[0][0] = +m * d;
inv[0][1] = -m * b;
inv[1][0] = -m * c;
inv[1][1] = +m * a;
return inv;
}
return new JaggedLuDecompositionF(matrix, false, inPlace).Inverse();
}
/// <summary>
/// Computes the pseudo-inverse of a matrix.
/// </summary>
///
public static Single[][] PseudoInverse(this Single[][] matrix)
{
return new JaggedSingularValueDecompositionF(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Inverse();
}
/// <summary>
/// Divides two matrices by multiplying A by the inverse of B.
/// </summary>
///
/// <param name="a">The first matrix.</param>
/// <param name="b">The second matrix (which will be inverted).</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="b"/> is singular; false otherwise. Default is false.</param>
///
/// <returns>The result from the division <c>AB^-1</c> of the given matrices.</returns>
///
public static Single[,] Divide(this Single[,] a, Single[,] b, bool leastSquares = false)
{
int rows = b.Rows();
int cols = b.Columns();
if (leastSquares)
{
return new SingularValueDecompositionF(b.Transpose(),
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(a.Transpose()).Transpose();
}
if (rows == cols && cols == a.Rows())
{
// Solve by LU Decomposition if matrix is square.
return new LuDecompositionF(b, true).SolveTranspose(a);
}
else
{
if (rows <= cols)
{
// Solve by QR Decomposition if not.
return new QrDecompositionF(b, true).SolveTranspose(a);
}
else
{
return new SingularValueDecompositionF(b.Transpose(),
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(a.Transpose()).Transpose();
}
}
}
/// <summary>
/// Divides two matrices by multiplying A by the inverse of B.
/// </summary>
///
/// <param name="a">The first matrix.</param>
/// <param name="b">The second matrix (which will be inverted).</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="b"/> is singular; false otherwise. Default is false.</param>
///
/// <returns>The result from the division <c>AB^-1</c> of the given matrices.</returns>
///
public static Single[][] Divide(this Single[][] a, Single[][] b, bool leastSquares = false)
{
int rows = b.Rows();
int cols = b.Columns();
if (leastSquares)
{
return new JaggedSingularValueDecompositionF(b.Transpose(),
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(a.Transpose()).Transpose();
}
if (rows == cols && cols == a.Rows())
{
// Solve by LU Decomposition if matrix is square.
return new JaggedLuDecompositionF(b, true).SolveTranspose(a);
}
else
{
if (rows <= cols)
{
// Solve by QR Decomposition if not.
return new JaggedQrDecompositionF(b, true).SolveTranspose(a);
}
else
{
return new JaggedSingularValueDecompositionF(b.Transpose(),
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(a.Transpose()).Transpose();
}
}
}
/// <summary>
/// Gets the null-space of a column vector.
/// </summary>
///
public static Single[][] Null(this Single[] vector)
{
return Null(Jagged.ColumnVector(vector));
}
/// <summary>
/// Gets the null-space of a matrix.
/// </summary>
///
public static Single[][] Null(this Single[][] matrix)
{
var qr = new JaggedQrDecompositionF(matrix, economy: false);
var Q = qr.OrthogonalFactor;
var threshold = matrix.GetLength().Max() * Constants.SingleEpsilon;
int[] idx = qr.Diagonal.Find(x => (Single)Math.Abs(x) < threshold);
return Q.GetColumns(idx);
}
/// <summary>
/// Gets the null-space of a matrix.
/// </summary>
///
public static Single[,] Null(this Single[,] matrix)
{
var qr = new QrDecompositionF(matrix, economy: false);
var Q = qr.OrthogonalFactor;
var threshold = matrix.GetLength().Max() * Constants.SingleEpsilon;
int[] idx = qr.Diagonal.Find(x => (Single)Math.Abs(x) < threshold);
return Q.GetColumns(idx);
}
/// <summary>
/// Returns the solution matrix if the matrix is square or the least squares solution otherwise.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="rightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
/// <example>
/// <code>
/// // Create a matrix. Please note that this matrix
/// // is singular (i.e. not invertible), so only a
/// // least squares solution would be feasible here.
///
/// Decimal[,] matrix =
/// {
/// { 1, 2, 3 },
/// { 4, 5, 6 },
/// { 7, 8, 9 },
/// };
///
/// // Define a right side matrix b:
/// Decimal[,] rightSide = { {1}, {2}, {3} };
///
/// // Solve the linear system Ax = b by finding x:
/// Decimal[,] x = Matrix.Solve(matrix, rightSide, leastSquares: true);
///
/// // The answer should be { {-1/18}, {2/18}, {5/18} }.
/// </code>
/// </example>
///
public static Decimal[,] Solve(this Decimal[,] matrix, Decimal[,] rightSide, bool leastSquares = false)
{
int rows = matrix.GetLength(0);
int cols = matrix.GetLength(1);
if (rows != rightSide.GetLength(0))
throw new DimensionMismatchException("rightSide",
"The number of rows in the right hand side matrix must be "
+ "equal to the number of rows in the problem matrix.");
if (leastSquares)
{
return new SingularValueDecompositionD(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(rightSide);
}
if (rows == cols)
{
// Solve by LU Decomposition if matrix is square.
return new LuDecompositionD(matrix).Solve(rightSide);
}
else
{
if (cols < rows)
{
// Solve by QR Decomposition if not.
return new QrDecompositionD(matrix).Solve(rightSide);
}
else
{
return new SingularValueDecompositionD(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(rightSide);
}
}
}
/// <summary>
/// Returns the solution matrix if the matrix is square or the least squares solution otherwise.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="rightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
/// <example>
/// <code>
/// // Create a matrix. Please note that this matrix
/// // is singular (i.e. not invertible), so only a
/// // least squares solution would be feasible here.
///
/// Decimal[,] matrix =
/// {
/// { 1, 2, 3 },
/// { 4, 5, 6 },
/// { 7, 8, 9 },
/// };
///
/// // Define a right side vector b:
/// Decimal[] rightSide = { 1, 2, 3 };
///
/// // Solve the linear system Ax = b by finding x:
/// Decimal[] x = Matrix.Solve(matrix, rightSide, leastSquares: true);
///
/// // The answer should be { -1/18, 2/18, 5/18 }.
/// </code>
/// </example>
///
public static Decimal[] Solve(this Decimal[,] matrix, Decimal[] rightSide, bool leastSquares = false)
{
if (matrix == null)
throw new ArgumentNullException("matrix");
if (rightSide == null)
throw new ArgumentNullException("rightSide");
int rows = matrix.GetLength(0);
int cols = matrix.GetLength(1);
if (rows != rightSide.Length)
throw new DimensionMismatchException("rightSide",
"The right hand side vector must have the same length"
+ "as there are rows of the problem matrix.");
if (leastSquares)
{
return new SingularValueDecompositionD(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(rightSide);
}
if (rows == cols)
{
// Solve by LU Decomposition if matrix is square.
return new LuDecompositionD(matrix).Solve(rightSide);
}
else
{
if (cols < rows)
{
// Solve by QR Decomposition if not.
return new QrDecompositionD(matrix).Solve(rightSide);
}
else
{
return new SingularValueDecompositionD(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(rightSide);
}
}
}
/// <summary>
/// Computes the inverse of a matrix.
/// </summary>
///
public static Decimal[,] Inverse(this Decimal[,] matrix)
{
return Inverse(matrix, false);
}
/// <summary>
/// Computes the inverse of a matrix.
/// </summary>
///
public static Decimal[,] Inverse(this Decimal[,] matrix, bool inPlace)
{
int rows = matrix.GetLength(0);
int cols = matrix.GetLength(1);
if (rows != cols)
throw new ArgumentException("Matrix must be square", "matrix");
if (rows == 3)
{
// Special case for 3x3 matrices
Decimal a = matrix[0, 0], b = matrix[0, 1], c = matrix[0, 2];
Decimal d = matrix[1, 0], e = matrix[1, 1], f = matrix[1, 2];
Decimal g = matrix[2, 0], h = matrix[2, 1], i = matrix[2, 2];
Decimal den = a * (e * i - f * h) -
b * (d * i - f * g) +
c * (d * h - e * g);
if (den == 0)
throw new SingularMatrixException();
Decimal m = 1 / den;
var inv = (inPlace) ? matrix : new Decimal[3, 3];
inv[0, 0] = m * (e * i - f * h);
inv[0, 1] = m * (c * h - b * i);
inv[0, 2] = m * (b * f - c * e);
inv[1, 0] = m * (f * g - d * i);
inv[1, 1] = m * (a * i - c * g);
inv[1, 2] = m * (c * d - a * f);
inv[2, 0] = m * (d * h - e * g);
inv[2, 1] = m * (b * g - a * h);
inv[2, 2] = m * (a * e - b * d);
return inv;
}
if (rows == 2)
{
// Special case for 2x2 matrices
Decimal a = matrix[0, 0], b = matrix[0, 1];
Decimal c = matrix[1, 0], d = matrix[1, 1];
Decimal den = a * d - b * c;
if (den == 0)
throw new SingularMatrixException();
Decimal m = 1 / den;
var inv = (inPlace) ? matrix : new Decimal[2, 2];
inv[0, 0] = +m * d;
inv[0, 1] = -m * b;
inv[1, 0] = -m * c;
inv[1, 1] = +m * a;
return inv;
}
return new LuDecompositionD(matrix, false, inPlace).Inverse();
}
/// <summary>
/// Computes the pseudo-inverse of a matrix.
/// </summary>
///
public static Decimal[,] PseudoInverse(this Decimal[,] matrix)
{
return new SingularValueDecompositionD(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Inverse();
}
/// <summary>
/// Returns the solution matrix if the matrix is square or the least squares solution otherwise.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="rightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
/// <example>
/// <code>
/// // Create a matrix. Please note that this matrix
/// // is singular (i.e. not invertible), so only a
/// // least squares solution would be feasible here.
///
/// Decimal[,] matrix =
/// {
/// { 1, 2, 3 },
/// { 4, 5, 6 },
/// { 7, 8, 9 },
/// };
///
/// // Define a right side matrix b:
/// Decimal[,] rightSide = { {1}, {2}, {3} };
///
/// // Solve the linear system Ax = b by finding x:
/// Decimal[,] x = Matrix.Solve(matrix, rightSide, leastSquares: true);
///
/// // The answer should be { {-1/18}, {2/18}, {5/18} }.
/// </code>
/// </example>
///
public static Decimal[][] Solve(this Decimal[][] matrix, Decimal[][] rightSide, bool leastSquares = false)
{
if (matrix.Length != rightSide[0].Length)
{
throw new DimensionMismatchException("rightSide",
"The number of rows in the right hand side matrix must be "
+ "equal to the number of rows in the problem matrix.");
}
return matrix.Decompose(leastSquares).Solve(rightSide);
}
/// <summary>
/// Returns the solution matrix if the matrix is square or the least squares solution otherwise.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="rightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
/// <example>
/// <code>
/// // Create a matrix. Please note that this matrix
/// // is singular (i.e. not invertible), so only a
/// // least squares solution would be feasible here.
///
/// Decimal[,] matrix =
/// {
/// { 1, 2, 3 },
/// { 4, 5, 6 },
/// { 7, 8, 9 },
/// };
///
/// // Define a right side vector b:
/// Decimal[] rightSide = { 1, 2, 3 };
///
/// // Solve the linear system Ax = b by finding x:
/// Decimal[] x = Matrix.Solve(matrix, rightSide, leastSquares: true);
///
/// // The answer should be { -1/18, 2/18, 5/18 }.
/// </code>
/// </example>
///
public static Decimal[] Solve(this Decimal[][] matrix, Decimal[] rightSide, bool leastSquares = false)
{
if (matrix.Length != rightSide.Length)
{
throw new DimensionMismatchException("rightSide",
"The right hand side vector must have the same length"
+ "as there are rows of the problem matrix.");
}
return matrix.Decompose(leastSquares).Solve(rightSide);
}
/// <summary>
/// Returns the solution matrix for a linear system involving a diagonal matrix ion the right-hand side.
/// </summary>
///
/// <param name="matrix">The matrix for the linear problem.</param>
/// <param name="diagonalRightSide">The right side <c>b</c>.</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="matrix"/> is singular; false otherwise. Default is false.</param>
///
/// <remarks>
/// Please note that this does not check if the matrix is non-singular
/// before attempting to solve. If a least squares solution is desired
/// in case the matrix is singular, pass true to the <paramref name="leastSquares"/>
/// parameter when calling this function.
/// </remarks>
///
public static Decimal[][] SolveForDiagonal(this Decimal[][] matrix, Decimal[] diagonalRightSide, bool leastSquares = false)
{
if (matrix.Length != diagonalRightSide.Length)
{
throw new DimensionMismatchException("diagonalRightSide",
"The right hand side matrix must have the same length"
+ "as there are rows of the problem matrix.");
}
return matrix.Decompose(leastSquares).SolveForDiagonal(diagonalRightSide);
}
/// <summary>
/// Creates a matrix decomposition that be used to compute the solution matrix if the
/// matrix is square or the least squares solution otherwise.
/// </summary>
///
public static ISolverMatrixDecomposition<Decimal> Decompose(this Decimal[,] matrix, bool leastSquares = false)
{
int rows = matrix.Rows();
int cols = matrix.Columns();
if (leastSquares)
{
return new SingularValueDecompositionD(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true);
}
if (rows == cols)
{
// Solve by LU Decomposition if matrix is square.
return new LuDecompositionD(matrix);
}
else
{
if (cols < rows)
{
// Solve by QR Decomposition if not.
return new QrDecompositionD(matrix);
}
else
{
return new SingularValueDecompositionD(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true);
}
}
}
/// <summary>
/// Creates a matrix decomposition that be used to compute the solution matrix if the
/// matrix is square or the least squares solution otherwise.
/// </summary>
///
public static ISolverArrayDecomposition<Decimal> Decompose(this Decimal[][] matrix, bool leastSquares = false)
{
int rows = matrix.Rows();
int cols = matrix.Columns();
if (leastSquares)
{
return new JaggedSingularValueDecompositionD(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true);
}
if (rows == cols)
{
// Solve by LU Decomposition if matrix is square.
return new JaggedLuDecompositionD(matrix);
}
else
{
if (cols < rows)
{
// Solve by QR Decomposition if not.
return new JaggedQrDecompositionD(matrix);
}
else
{
return new JaggedSingularValueDecompositionD(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true);
}
}
}
/// <summary>
/// Computes the inverse of a matrix.
/// </summary>
///
public static Decimal[][] Inverse(this Decimal[][] matrix)
{
return Inverse(matrix, false);
}
/// <summary>
/// Computes the inverse of a matrix.
/// </summary>
///
public static Decimal[][] Inverse(this Decimal[][] matrix, bool inPlace)
{
int rows = matrix.Length;
int cols = matrix[0].Length;
if (rows != cols)
throw new ArgumentException("Matrix must be square", "matrix");
if (rows == 3)
{
// Special case for 3x3 matrices
Decimal a = matrix[0][0], b = matrix[0][1], c = matrix[0][2];
Decimal d = matrix[1][0], e = matrix[1][1], f = matrix[1][2];
Decimal g = matrix[2][0], h = matrix[2][1], i = matrix[2][2];
Decimal den = a * (e * i - f * h) -
b * (d * i - f * g) +
c * (d * h - e * g);
if (den == 0)
throw new SingularMatrixException();
Decimal m = 1 / den;
var inv = matrix;
if (!inPlace)
{
inv = new Decimal[3][];
for (int j = 0; j < inv.Length; j++)
inv[j] = new Decimal[3];
}
inv[0][0] = m * (e * i - f * h);
inv[0][1] = m * (c * h - b * i);
inv[0][2] = m * (b * f - c * e);
inv[1][0] = m * (f * g - d * i);
inv[1][1] = m * (a * i - c * g);
inv[1][2] = m * (c * d - a * f);
inv[2][0] = m * (d * h - e * g);
inv[2][1] = m * (b * g - a * h);
inv[2][2] = m * (a * e - b * d);
return inv;
}
if (rows == 2)
{
// Special case for 2x2 matrices
Decimal a = matrix[0][0], b = matrix[0][1];
Decimal c = matrix[1][0], d = matrix[1][1];
Decimal den = a * d - b * c;
if (den == 0)
throw new SingularMatrixException();
Decimal m = 1 / den;
var inv = matrix;
if (!inPlace)
{
inv = new Decimal[2][];
for (int j = 0; j < inv.Length; j++)
inv[j] = new Decimal[2];
}
inv[0][0] = +m * d;
inv[0][1] = -m * b;
inv[1][0] = -m * c;
inv[1][1] = +m * a;
return inv;
}
return new JaggedLuDecompositionD(matrix, false, inPlace).Inverse();
}
/// <summary>
/// Computes the pseudo-inverse of a matrix.
/// </summary>
///
public static Decimal[][] PseudoInverse(this Decimal[][] matrix)
{
return new JaggedSingularValueDecompositionD(matrix,
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Inverse();
}
/// <summary>
/// Divides two matrices by multiplying A by the inverse of B.
/// </summary>
///
/// <param name="a">The first matrix.</param>
/// <param name="b">The second matrix (which will be inverted).</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="b"/> is singular; false otherwise. Default is false.</param>
///
/// <returns>The result from the division <c>AB^-1</c> of the given matrices.</returns>
///
public static Decimal[,] Divide(this Decimal[,] a, Decimal[,] b, bool leastSquares = false)
{
int rows = b.Rows();
int cols = b.Columns();
if (leastSquares)
{
return new SingularValueDecompositionD(b.Transpose(),
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(a.Transpose()).Transpose();
}
if (rows == cols && cols == a.Rows())
{
// Solve by LU Decomposition if matrix is square.
return new LuDecompositionD(b, true).SolveTranspose(a);
}
else
{
if (rows <= cols)
{
// Solve by QR Decomposition if not.
return new QrDecompositionD(b, true).SolveTranspose(a);
}
else
{
return new SingularValueDecompositionD(b.Transpose(),
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(a.Transpose()).Transpose();
}
}
}
/// <summary>
/// Divides two matrices by multiplying A by the inverse of B.
/// </summary>
///
/// <param name="a">The first matrix.</param>
/// <param name="b">The second matrix (which will be inverted).</param>
/// <param name="leastSquares">True to produce a solution even if the
/// <paramref name="b"/> is singular; false otherwise. Default is false.</param>
///
/// <returns>The result from the division <c>AB^-1</c> of the given matrices.</returns>
///
public static Decimal[][] Divide(this Decimal[][] a, Decimal[][] b, bool leastSquares = false)
{
int rows = b.Rows();
int cols = b.Columns();
if (leastSquares)
{
return new JaggedSingularValueDecompositionD(b.Transpose(),
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(a.Transpose()).Transpose();
}
if (rows == cols && cols == a.Rows())
{
// Solve by LU Decomposition if matrix is square.
return new JaggedLuDecompositionD(b, true).SolveTranspose(a);
}
else
{
if (rows <= cols)
{
// Solve by QR Decomposition if not.
return new JaggedQrDecompositionD(b, true).SolveTranspose(a);
}
else
{
return new JaggedSingularValueDecompositionD(b.Transpose(),
computeLeftSingularVectors: true,
computeRightSingularVectors: true,
autoTranspose: true).Solve(a.Transpose()).Transpose();
}
}
}
/// <summary>
/// Gets the null-space of a column vector.
/// </summary>
///
public static Decimal[][] Null(this Decimal[] vector)
{
return Null(Jagged.ColumnVector(vector));
}
/// <summary>
/// Gets the null-space of a matrix.
/// </summary>
///
public static Decimal[][] Null(this Decimal[][] matrix)
{
var qr = new JaggedQrDecompositionD(matrix, economy: false);
var Q = qr.OrthogonalFactor;
var threshold = matrix.GetLength().Max() * Constants.DecimalEpsilon;
int[] idx = qr.Diagonal.Find(x => (Decimal)Math.Abs(x) < threshold);
return Q.GetColumns(idx);
}
/// <summary>
/// Gets the null-space of a matrix.
/// </summary>
///
public static Decimal[,] Null(this Decimal[,] matrix)
{
var qr = new QrDecompositionD(matrix, economy: false);
var Q = qr.OrthogonalFactor;
var threshold = matrix.GetLength().Max() * Constants.DecimalEpsilon;
int[] idx = qr.Diagonal.Find(x => (Decimal)Math.Abs(x) < threshold);
return Q.GetColumns(idx);
}
}
}