using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VisualMath.Accord.Math.Decompositions
{
using System;
using VisualMath.Accord.Math;
///
/// LU decomposition of a rectangular matrix.
///
///
///
/// For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
/// unit lower triangular matrix L, an n-by-n upper triangular matrix U,
/// and a permutation vector piv of length m so that A(piv) = L*U.
/// If m < n, then L is m-by-m and U is m-by-n.
///
/// The LU decomposition with pivoting always exists, even if the matrix is
/// singular, so the constructor will never fail. The primary use of the
/// LU decomposition is in the solution of square systems of simultaneous
/// linear equations. This will fail if returns
/// .
///
///
///
public sealed class LuDecomposition
{
private double[,] lu;
private int pivotSign;
private int[] pivotVector;
/// Construct a new LU decomposition.
/// The matrix A to be decomposed.
public LuDecomposition(double[,] value)
: this(value, false)
{
}
/// Construct a LU decomposition.
/// The matrix A to be decomposed.
/// True if the decomposition should be performed on
/// the transpose of A rather than A itself, false otherwise. Default is false.
public LuDecomposition(double[,] value, bool transpose)
{
if (value == null)
{
throw new ArgumentNullException("value", "Matrix cannot be null.");
}
if ((!transpose && value.GetLength(0) < value.GetLength(1)) ||
(transpose && value.GetLength(1) < value.GetLength(0)))
{
throw new ArgumentException("Matrix has more columns than rows.", "value");
}
this.lu = transpose ? value.Transpose() : (double[,])value.Clone();
int rows = lu.GetLength(0);
int cols = lu.GetLength(1);
this.pivotVector = new int[rows];
for (int i = 0; i < rows; i++)
pivotVector[i] = i;
pivotSign = 1;
double[] LUcolj = new double[rows];
// Outer loop.
for (int j = 0; j < cols; j++)
{
// Make a copy of the j-th column to localize references.
for (int i = 0; i < rows; i++)
LUcolj[i] = lu[i, j];
// Apply previous transformations.
for (int i = 0; i < rows; i++)
{
// Most of the time is spent in the following dot product.
int kmax = System.Math.Min(i, j);
double s = 0.0;
for (int k = 0; k < kmax; k++)
s += lu[i, k] * LUcolj[k];
lu[i, j] = LUcolj[i] -= s;
}
// Find pivot and exchange if necessary.
int p = j;
for (int i = j + 1; i < rows; i++)
{
if (System.Math.Abs(LUcolj[i]) > System.Math.Abs(LUcolj[p]))
p = i;
}
if (p != j)
{
for (int k = 0; k < cols; k++)
{
double t = lu[p, k];
lu[p, k] = lu[j, k];
lu[j, k] = t;
}
int v = pivotVector[p];
pivotVector[p] = pivotVector[j];
pivotVector[j] = v;
pivotSign = -pivotSign;
}
// Compute multipliers.
if (j < rows & lu[j, j] != 0.0)
{
for (int i = j + 1; i < rows; i++)
lu[i, j] /= lu[j, j];
}
}
}
/// Returns if the matrix is non-singular.
public bool NonSingular
{
get
{
for (int j = 0; j < lu.GetLength(1); j++)
if (lu[j, j] == 0)
return false;
return true;
}
}
/// Returns the determinant of the matrix.
public double Determinant
{
get
{
if (lu.GetLength(0) != lu.GetLength(1))
throw new InvalidOperationException("Matrix must be square.");
double determinant = (double)pivotSign;
for (int j = 0; j < lu.GetLength(1); j++)
determinant *= lu[j, j];
return determinant;
}
}
/// Returns the lower triangular factor L with A=LU.
public double[,] LowerTriangularFactor
{
get
{
int rows = lu.GetLength(0);
int columns = lu.GetLength(1);
double[,] X = new double[rows, columns];
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
if (i > j)
X[i, j] = lu[i, j];
else if (i == j)
X[i, j] = 1.0;
else
X[i, j] = 0.0;
}
}
return X;
}
}
/// Returns the lower triangular factor L with A=LU.
public double[,] UpperTriangularFactor
{
get
{
int rows = lu.GetLength(0);
int columns = lu.GetLength(1);
double[,] X = new double[rows, columns];
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
if (i <= j)
X[i, j] = lu[i, j];
else
X[i, j] = 0.0;
}
}
return X;
}
}
/// Returns the pivot permuation vector.
public double[] PivotPermutationVector
{
get
{
int rows = lu.GetLength(0);
double[] p = new double[rows];
for (int i = 0; i < rows; i++)
p[i] = (double)this.pivotVector[i];
return p;
}
}
/// Solves a set of equation systems of type A * X = I.
public double[,] Inverse()
{
if (!this.NonSingular)
{
throw new InvalidOperationException("Matrix is singular");
}
int rows = lu.GetLength(1);
int columns = lu.GetLength(1);
int count = rows;
// Copy right hand side with pivoting
double[,] X = new double[rows, columns];
for (int i = 0; i < rows; i++)
{
int k = pivotVector[i];
X[i, k] = 1.0;
}
// Solve L*Y = B(piv,:)
for (int k = 0; k < columns; k++)
for (int i = k + 1; i < columns; i++)
for (int j = 0; j < count; j++)
X[i, j] -= X[k, j] * lu[i, k];
// Solve U*X = I;
for (int k = columns - 1; k >= 0; k--)
{
for (int j = 0; j < count; j++)
X[k, j] /= lu[k, k];
for (int i = 0; i < k; i++)
for (int j = 0; j < count; j++)
X[i, j] -= X[k, j] * lu[i, k];
}
return X;
}
/// Solves a set of equation systems of type A * X = B.
/// Right hand side matrix with as many rows as A and any number of columns.
/// Matrix X so that L * U * X = B.
public double[,] Solve(double[,] value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (value.GetLength(0) != this.lu.GetLength(0))
{
throw new ArgumentException("Invalid matrix dimensions.", "value");
}
if (!this.NonSingular)
{
throw new InvalidOperationException("Matrix is singular");
}
// Copy right hand side with pivoting
int count = value.GetLength(1);
double[,] X = value.Submatrix(pivotVector, 0, count - 1);
int columns = lu.GetLength(1);
// Solve L*Y = B(piv,:)
for (int k = 0; k < columns; k++)
for (int i = k + 1; i < columns; i++)
for (int j = 0; j < count; j++)
X[i, j] -= X[k, j] * lu[i, k];
// Solve U*X = Y;
for (int k = columns - 1; k >= 0; k--)
{
for (int j = 0; j < count; j++)
X[k, j] /= lu[k, k];
for (int i = 0; i < k; i++)
for (int j = 0; j < count; j++)
X[i, j] -= X[k, j] * lu[i, k];
}
return X;
}
/// Solves a set of equation systems of type X * A = B.
/// Right hand side matrix with as many columns as A and any number of rows.
/// Matrix X so that X * L * U = A.
public double[,] SolveTranspose(double[,] value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (value.GetLength(0) != this.lu.GetLength(0))
{
throw new ArgumentException("Invalid matrix dimensions.", "value");
}
if (!this.NonSingular)
{
throw new InvalidOperationException("Matrix is singular");
}
// Copy right hand side with pivoting
double[,] X = value.Submatrix(null, pivotVector);
int count = X.GetLength(1);
int columns = lu.GetLength(1);
// Solve L*Y = B(piv,:)
for (int k = 0; k < columns; k++)
for (int i = k + 1; i < columns; i++)
for (int j = 0; j < count; j++)
X[j, i] -= X[j, k] * lu[i, k];
// Solve U*X = Y;
for (int k = columns - 1; k >= 0; k--)
{
for (int j = 0; j < count; j++)
X[j, k] /= lu[k, k];
for (int i = 0; i < k; i++)
for (int j = 0; j < count; j++)
X[j, i] -= X[j, k] * lu[i, k];
}
return X;
}
/// Solves a set of equation systems of type A * X = B.
/// Right hand side matrix with as many rows as A and any number of columns.
/// Matrix X so that L * U * X = B.
public double[] Solve(double[] value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (value.Length != this.lu.GetLength(0))
{
throw new ArgumentException("Invalid matrix dimensions.", "value");
}
if (!this.NonSingular)
{
throw new InvalidOperationException("Matrix is singular");
}
// Copy right hand side with pivoting
int count = value.Length;
double[] b = new double[count];
for (int i = 0; i < b.Length; i++)
b[i] = value[pivotVector[i]];
int rows = lu.GetLength(1);
int columns = lu.GetLength(1);
// Solve L*Y = B
double[] X = new double[count];
for (int i = 0; i < rows; i++)
{
X[i] = b[i];
for (int j = 0; j < i; j++)
X[i] -= lu[i, j] * X[j];
}
// Solve U*X = Y;
for (int i = rows - 1; i >= 0; i--)
{
//double sum = 0.0;
for (int j = columns - 1; j > i; j--)
X[i] -= lu[i, j] * X[j];
X[i] /= lu[i, i];
}
return X;
}
}
}