blob: e7b1c820a85e337dc137a8c434489c9d2b625224 [file] [log] [blame]
//#####################################################################
// Copyright 2002-2004, Ronald Fedkiw, Neil Molino, Igor Neverov, Eftychios Sifakis, Joseph Teran.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class MATRIX_NXN
//#####################################################################
#ifndef __MATRIX_NXN__
#define __MATRIX_NXN__
#include <assert.h>
#include "VECTOR_ND.h"
#include "../Math_Tools/exchange.h"
#include "../Math_Tools/max.h"
namespace PhysBAM
{
template<class T>
class MATRIX_NXN
{
public:
int n; // size of the n by n matrix
T *x; // pointer to the one dimensional data
T small_number;
MATRIX_NXN<T> *L, *U, *inverse;
VECTOR_ND<T> *p;
MATRIX_NXN()
: n (0), x (0), small_number ( (T) 1e-8), L (0), U (0), inverse (0), p (0)
{}
MATRIX_NXN (const int n_input)
: n (n_input), small_number ( (T) 1e-8), L (0), U (0), inverse (0), p (0)
{
x = new T[n * n];
for (int k = 0; k < n * n; k++) x[k] = 0;
}
MATRIX_NXN (const MATRIX_NXN<T>& matrix_input)
: n (matrix_input.n), small_number (matrix_input.small_number), L (0), U (0), inverse (0), p (0)
{
x = new T[n * n];
for (int k = 0; k < n * n; k++) x[k] = matrix_input.x[k];
}
~MATRIX_NXN()
{
if (x) delete [] x;
if (L) delete L;
if (U) delete (U);
if (p) delete p;
if (inverse) delete inverse;
}
T& operator() (const int i, const int j)
{
assert (i >= 1 && i <= n);
assert (j >= 1 && j <= n);
return * (x + (i - 1) * n + (j - 1));
}
const T& operator() (const int i, const int j) const
{
assert (i >= 1 && i <= n);
assert (j >= 1 && j <= n);
return * (x + (i - 1) * n + (j - 1));
}
MATRIX_NXN<T>& operator= (const MATRIX_NXN<T>& A)
{
delete L;
delete U;
delete inverse;
delete p;
L = U = inverse = 0;
p = 0;
if (!x || n != A.n)
{
delete[] x;
x = new T[A.n * A.n];
}
n = A.n;
for (int k = 0; k < n * n; k++) x[k] = A.x[k];
return *this;
}
MATRIX_NXN<T>& operator+= (const MATRIX_NXN<T>& A)
{
for (int i = 0; i < n * n; i++) x[i] += A.x[i];
return *this;
}
MATRIX_NXN<T>& operator-= (const MATRIX_NXN<T>& A)
{
for (int i = 0; i < n * n; i++) x[i] -= A.x[i];
return *this;
}
MATRIX_NXN<T>& operator*= (const T a)
{
for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) (* (x + i * n + j)) *= a;
return *this;
}
MATRIX_NXN<T> operator+ (const MATRIX_NXN<T>& A) const
{
assert (A.n == n);
MATRIX_NXN<T> result (n);
for (int i = 0; i < n * n; i++) result.x[i] = x[i] + A.x[i];
return result;
}
MATRIX_NXN<T> operator- (const MATRIX_NXN<T>& A) const
{
assert (A.n == n);
MATRIX_NXN<T> result (n);
for (int i = 0; i < n * n; i++) result.x[i] = x[i] - A.x[i];
return result;
}
MATRIX_NXN<T> operator* (const T a) const
{
MATRIX_NXN<T> result (n);
for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) (* (result.x + i * n + j)) = (* (x + i * n + j)) * a;
return result;
}
VECTOR_ND<T> operator* (const VECTOR_ND<T>& y) const
{
assert (y.n == n);
VECTOR_ND<T> result (n);
for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) (* (result.x + i)) += (* (x + i * n + j)) * (* (y.x + j));
return result;
}
VECTOR_ND<T> Transpose_Times (const VECTOR_ND<T>& y) const
{
assert (y.n == n);
VECTOR_ND<T> result (n);
for (int j = 0; j < n; j++) for (int i = 0; i < n; i++) (* (result.x + i)) += (* (x + j * n + i)) * (* (y.x + j));
return result;
}
MATRIX_NXN<T> operator* (const MATRIX_NXN<T>& A) const
{
assert (A.n == n);
MATRIX_NXN<T> result (n);
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
T total = (T) 0;
for (int k = 0; k < n; k++) total += (* (x + i * n + k)) * (* (A.x + k * n + j));
(* (result.x + i * n + j)) = total;
}
}
return result;
}
void Set_Identity_Matrix()
{
Set_Zero_Matrix();
for (int i = 1; i <= n; i++) (*this) (i, i) = 1;
}
void Set_Zero_Matrix()
{
for (int i = 0; i < n * n; i++) x[i] = 0;
}
static MATRIX_NXN<T> Identity_Matrix (const int n)
{
MATRIX_NXN<T> A (n);
for (int i = 1; i <= n; i++) A (i, i) = (T) 1;
return A;
}
MATRIX_NXN<T> Transpose() const
{
MATRIX_NXN<T> A (n);
for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++) A (i, j) = A (j, i) = * (x + (i - 1) * n + (j - 1));
return A;
}
T Trace() const
{
T trace = 0;
for (int i = 1; i <= n; i++) trace += (* (x + (i - 1) * n + (i - 1)));
return trace;
}
MATRIX_NXN<T> Normal_Equations_Matrix() const
{
MATRIX_NXN<T> result (n);
for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) result (i, j) += * (x + (k - 1) * n + i - 1)** (x + (k - 1) * n + j - 1);
return result;
}
VECTOR_ND<T> Lower_Triangular_Solve (const VECTOR_ND<T>& b) const
{
assert (n == b.n);
VECTOR_ND<T> x (n);
for (int i = 1; i <= n; i++)
{
x (i) = b (i);
for (int j = 1; j <= i - 1; j++) x (i) -= (*this) (i, j) * x (j);
x (i) /= (*this) (i, i);
}
return x;
}
VECTOR_ND<T> Upper_Triangular_Solve (const VECTOR_ND<T>& b) const
{
assert (n == b.n);
VECTOR_ND<T> x (n);
for (int i = n; i >= 1; i--)
{
x (i) = b (i);
for (int j = n; j >= i + 1; j--) x (i) -= (*this) (i, j) * x (j);
x (i) /= (*this) (i, i);
}
return x;
}
void LU_Factorization()
{
int i, j, k;
if (L) delete L;
L = new MATRIX_NXN<T> (n);
if (U) delete (U);
U = new MATRIX_NXN<T> (*this);
for (j = 1; j <= n; j++) // for each column
{
for (i = j; i <= n; i++) (*L) (i, j) = (*U) (i, j) / (*U) (j, j); // fill in the column for L
for (i = j + 1; i <= n; i++) for (k = j; k <= n; k++) (*U) (i, k) -= (*L) (i, j) * (*U) (j, k);
}
} // sweep across each row below row j
VECTOR_ND<T> LU_Solve (const VECTOR_ND<T>& b)
{
LU_Factorization();
return U->Upper_Triangular_Solve (L->Lower_Triangular_Solve (b));
}
void LU_Inverse()
{
if (inverse) delete inverse;
inverse = new MATRIX_NXN<T> (n);
LU_Factorization();
for (int j = 1; j <= n; j++) // for each column
{
VECTOR_ND<T> b (n);
b (j) = 1; // piece of the identity matrix
VECTOR_ND<T> x = U->Upper_Triangular_Solve (L->Lower_Triangular_Solve (b));
for (int i = 1; i <= n; i++) (*inverse) (i, j) = x (i);
}
}
void PLU_Factorization()
{
int i, j, k;
if (L) delete L;
L = new MATRIX_NXN<T> (n);
if (U) delete (U);
U = new MATRIX_NXN<T> (*this);
if (p) delete p;
p = new VECTOR_ND<T> (n);
for (i = 1; i <= n; i++) (*p) (i) = (T) i; // initialize p
for (j = 1; j <= n; j++) // for each column
{
// find the largest element and switch rows
int row = j;
T value = fabs ( (*U) (j, j));
for (i = j + 1; i <= n; i++) if (fabs ( (*U) (i, j)) > value)
{
row = i;
value = fabs ( (*U) (i, j));
}
if (row != j) // need to switch rows
{
exchange ( (*p) (j), (*p) (row)); // update permutation matrix
for (k = 1; k <= j - 1; k++) exchange ( (*L) (j, k), (*L) (row, k)); // update L
for (k = j; k <= n; k++) exchange ( (*U) (j, k), (*U) (row, k));
} // update U
// standard LU factorization steps
for (i = j; i <= n; i++) (*L) (i, j) = (*U) (i, j) / (*U) (j, j); // fill in the column for L
for (i = j + 1; i <= n; i++) for (k = j; k <= n; k++) (*U) (i, k) -= (*L) (i, j) * (*U) (j, k);
}
} // sweep across each row below row j
VECTOR_ND<T> PLU_Solve (const VECTOR_ND<T>& b)
{
PLU_Factorization();
VECTOR_ND<T> x = b;
return U->Upper_Triangular_Solve (L->Lower_Triangular_Solve (x.Permute (*p)));
}
void PLU_Inverse()
{
if (inverse) delete inverse;
inverse = new MATRIX_NXN<T> (n);
PLU_Factorization();
for (int j = 1; j <= n; j++) // for each column
{
VECTOR_ND<T> b (n);
b (j) = 1; // piece of the identity matrix
VECTOR_ND<T> x = U->Upper_Triangular_Solve (L->Lower_Triangular_Solve (b.Permute (*p)));
for (int i = 1; i <= n; i++) (*inverse) (i, j) = x (i);
}
}
void Gauss_Seidel_Single_Iteration (VECTOR_ND<T>& x, const VECTOR_ND<T>& b) const
{
assert (x.n == b.n && x.n == n);
for (int i = 1; i <= n; i++)
{
T rho = 0;
for (int j = 1; j < i; j++) rho += (*this) (i, j) * x (j);
for (int j = i + 1; j <= n; j++) rho += (*this) (i, j) * x (j);
x (i) = (b (i) - rho) / (*this) (i, i);
}
}
T Norm() const // L_infinity norm - maximum row sum
{
T max_sum = 0;
for (int i = 1; i <= n; i++)
{
T sum = 0;
for (int j = 1; j <= n; j++) sum += fabs ( (*this) (i, j));
max_sum = max (sum, max_sum);
}
return max_sum;
}
T Condition_Number()
{
PLU_Inverse(); // makes sure the inverse is up to date
return Norm() * inverse->Norm();
}
void Cholesky_Factorization() // LL^{transpose} factorization
{
int i, j, k;
if (L) delete L;
L = new MATRIX_NXN<T> (n);
if (U) delete (U);
U = new MATRIX_NXN<T> (*this);
for (j = 1; j <= n; j++) // for each column
{
for (k = 1; k <= j - 1; k++) for (i = j; i <= n; i++) (*U) (i, j) -= (*L) (j, k) * (*L) (i, k); // subtract off the known stuff in previous columns
(*L) (j, j) = sqrt ( (*U) (j, j));
for (i = j + 1; i <= n; i++) (*L) (i, j) = (*U) (i, j) / (*L) (j, j);
} // update L
for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) (*U) (i, j) = (*L) (j, i);
} // put L^{transpose} into U
VECTOR_ND<T> Cholesky_Solve (const VECTOR_ND<T>& b)
{
Cholesky_Factorization();
return U->Upper_Triangular_Solve (L->Lower_Triangular_Solve (b));
}
void Cholesky_Inverse()
{
if (inverse) delete inverse;
inverse = new MATRIX_NXN<T> (n);
Cholesky_Factorization();
for (int j = 1; j <= n; j++) // for each column
{
VECTOR_ND<T> b (n);
b (j) = 1; // piece of the identity matrix
VECTOR_ND<T> x = U->Upper_Triangular_Solve (L->Lower_Triangular_Solve (b));
for (int i = 1; i <= n; i++) (*inverse) (i, j) = x (i);
}
}
static bool Conjugate_Gradient (const MATRIX_NXN<T>& A, VECTOR_ND<T>& x, const VECTOR_ND<T>& b, const int max_iter = 30, const T tolerance = 1e-6)
{
T alpha, beta, rho, rho_1;
VECTOR_ND<T> p (b.n), q (b.n), r (b.n);
r = b - A * x;
if (r.Sup_Norm() <= tolerance) return true;
for (int i = 1; i <= max_iter; i++)
{
rho = VECTOR_ND<T>::Dot_Product (r, r);
if (i == 1) p = r;
else
{
beta = rho / rho_1;
p = r + beta * p;
}
q = A * p;
alpha = rho / VECTOR_ND<T>::Dot_Product (p, q);
x += alpha * p;
r -= alpha * q;
if (r.Sup_Norm() <= tolerance) return true;
rho_1 = rho;
}
return false;
}
void Write_To_Screen() const
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++) std::cout << (*this) (i, j) << " ";
std::cout << std::endl;
}
}
//#####################################################################
};
template<class T> inline MATRIX_NXN<T> operator* (const T a, const MATRIX_NXN<T>& A)
{
MATRIX_NXN<T> result (A.n);
for (int i = 0; i < A.n; i++) for (int j = 0; j < A.n; j++) (* (result.x + i * A.n + j)) = a * (* (A.x + i * A.n + j));
return result;
}
template<class T> inline MATRIX_NXN<T> operator* (const int a, const MATRIX_NXN<T>& A)
{
MATRIX_NXN<T> result (A.n);
for (int i = 0; i < A.n; i++) for (int j = 0; j < A.n; j++) (* (result.x + i * A.n + j)) = a * (* (A.x + i * A.n + j));
return result;
}
template<class T> inline std::istream& operator>> (std::istream& input_stream, MATRIX_NXN<T>& A)
{
for (int i = 0; i < A.n; i++) for (int j = 0; j < A.n; j++) input_stream >> (* (A.x + i * A.n + j));
return input_stream;
}
template<class T> inline std::ostream& operator<< (std::ostream& output_stream, const MATRIX_NXN<T>& A)
{
for (int i = 0; i < A.n; i++)
{
for (int j = 0; j < A.n; j++) output_stream << (* (A.x + i * A.n + j)) << " ";
output_stream << std::endl;
}
return output_stream;
}
}
#endif