/*
* Copyright (c) 2009-2013, Peter Abeles. All Rights Reserved.
*
* This file is part of Efficient Java Matrix Library (EJML).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package mikera.matrixx.solve.impl;
/**
* <p>
* This contains algorithms for solving systems of equations where T is a
* non-singular triangular matrix:<br>
* <br>
* T*x = b<br>
* <br>
* where x and b are vectors, and T is an n by n matrix. T can either be a lower or upper triangular matrix.<br>
* </p>
* <p>
* These functions are designed for use inside of other algorithms. To use them directly
* is dangerous since no sanity checks are performed.
* </p>
*
* @author Peter Abeles
*/
public class TriangularSolver {
/**
* <p>
* Inverts a square lower triangular matrix: L = L<sup>-1</sup>
* </p>
*
*
* @param L
* @param m
*/
public static void invertLower( double L[] , int m ) {
for( int i = 0; i < m; i++ ) {
double L_ii = L[ i*m + i ];
for( int j = 0; j < i; j++ ) {
double val = 0;
for( int k = j; k < i; k++ ) {
val += L[ i*m + k] * L[ k*m + j ];
}
L[ i*m + j ] = -val / L_ii;
}
L[ i*m + i ] = 1.0 / L_ii;
}
}
public static void invertLower( double L[] , double L_inv[] , int m ) {
for( int i = 0; i < m; i++ ) {
double L_ii = L[ i*m + i ];
for( int j = 0; j < i; j++ ) {
double val = 0;
for( int k = j; k < i; k++ ) {
val -= L[ i*m + k] * L_inv[ k*m + j ];
}
L_inv[ i*m + j ] = val / L_ii;
}
L_inv[ i*m + i ] = 1.0 / L_ii;
}
}
/**
* <p>
* Solves for non-singular lower triangular matrices using forward substitution.
* <br>
* b = L<sup>-1</sup>b<br>
* <br>
* where b is a vector, L is an n by n matrix.<br>
* </p>
*
* @param L An n by n non-singular lower triangular matrix. Not modified.
* @param b A vector of length n. Modified.
* @param n The size of the matrices.
*/
public static void solveL( double L[] , double []b , int n )
{
// for( int i = 0; i < n; i++ ) {
// double sum = b[i];
// for( int k=0; k<i; k++ ) {
// sum -= L[i*n+k]* b[k];
// }
// b[i] = sum / L[i*n+i];
// }
for( int i = 0; i < n; i++ ) {
double sum = b[i];
int indexL = i*n;
for( int k=0; k<i; k++ ) {
sum -= L[indexL++]* b[k];
}
b[i] = sum / L[indexL];
}
}
/**
*
* L is a m by m matrix
* B is a m by n matrix
*
* @param L
* @param b
* @param m
* @param n
*/
public static void solveL( double L[] , double []b , int m , int n )
{
for( int j = 0; j < n; j++ ) {
for( int i = 0; i < m; i++ ) {
double sum = b[i*n+j];
for( int k=0; k<i; k++ ) {
sum -= L[i*m+k]* b[k*n+j];
}
b[i*n+j] = sum / L[i*m+i];
}
}
}
/**
* <p>
* This is a forward substitution solver for non-singular lower triangular matrices.
* <br>
* b = (L<sup>T</sup>)<sup>-1</sup>b<br>
* <br>
* where b is a vector, L is an n by n matrix.<br>
* </p>
* <p>
* L is a lower triangular matrix, but it comes up with a solution as if it was
* an upper triangular matrix that was computed by transposing L.
* </p>
*
* @param L An n by n non-singular lower triangular matrix. Not modified.
* @param b A vector of length n. Modified.
* @param n The size of the matrices.
*/
public static void solveTranL( double L[] , double []b , int n )
{
for( int i =n-1; i>=0; i-- ) {
double sum = b[i];
for( int k = i+1; k <n; k++ ) {
sum -= L[k*n+i]* b[k];
}
b[i] = sum/L[i*n+i];
}
}
/**
* <p>
* This is a forward substitution solver for non-singular upper triangular matrices.
* <br>
* b = U<sup>-1</sup>b<br>
* <br>
* where b is a vector, U is an n by n matrix.<br>
* </p>
*
* @param U An n by n non-singular upper triangular matrix. Not modified.
* @param b A vector of length n. Modified.
* @param n The size of the matrices.
*/
public static void solveU( double U[] , double []b , int n )
{
// for( int i =n-1; i>=0; i-- ) {
// double sum = b[i];
// for( int j = i+1; j <n; j++ ) {
// sum -= U[i*n+j]* b[j];
// }
// b[i] = sum/U[i*n+i];
// }
for( int i =n-1; i>=0; i-- ) {
double sum = b[i];
int indexU = i*n+i+1;
for( int j = i+1; j <n; j++ ) {
sum -= U[indexU++]* b[j];
}
b[i] = sum/U[i*n+i];
}
}
public static void solveU( double U[] , double []b , int sideLength , int minRow , int maxRow )
{
// for( int i =maxRow-1; i>=minRow; i-- ) {
// double sum = b[i];
// for( int j = i+1; j <maxRow; j++ ) {
// sum -= U[i*sideLength+j]* b[j];
// }
// b[i] = sum/U[i*sideLength+i];
// }
for( int i =maxRow-1; i>=minRow; i-- ) {
double sum = b[i];
int indexU = i*sideLength+i+1;
for( int j = i+1; j <maxRow; j++ ) {
sum -= U[indexU++]* b[j];
}
b[i] = sum/U[i*sideLength+i];
}
}
/**
* <p>
* This is a forward substitution solver for non-singular upper triangular matrices which are
* a sub-matrix inside a larger. The columns of 'b' are solved for individually
* <br>
* b = U<sup>-1</sup>b<br>
* <br>
* where b is a matrix, U is an n by n matrix.<br>
* </p>
*
* @param U Matrix containing the upper triangle system
* @param startU Index of the first element in U
* @param strideU stride between rows
* @param widthU How wide the square matrix is
* @param b Matrix containing the solution to the system. Overwritten with the solution.
* @param startB Index of the first element in B
* @param strideB stride between rows
* @param widthB How wide the matrix is. Length is the same as U's width
*/
public static void solveU( double []U , int startU , int strideU , int widthU ,
double []b , int startB , int strideB , int widthB )
{
for( int colB = 0; colB < widthB; colB++ ) {
for( int i =widthU-1; i>=0; i-- ) {
double sum = b[startB + i*strideB + colB];
for( int j = i+1; j <widthU; j++ ) {
sum -= U[startU + i*strideU+j]* b[startB + j*strideB + colB ];
}
b[startB + i*strideB + colB] = sum/U[ startU + i*strideU + i ];
}
}
// todo comment out the above and optimize it
}
}