All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ejml.alg.block.BlockTriangularSolver Maven / Gradle / Ivy

Go to download

A fast and easy to use dense matrix linear algebra library written in Java.

The newest version!
/*
 * 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 org.ejml.alg.block;

import org.ejml.data.D1Submatrix64F;

import static org.ejml.alg.block.BlockInnerMultiplication.blockMultMinus;


/**
 * 

* Contains triangular solvers for {@link org.ejml.data.BlockMatrix64F} block aligned sub-matrices. *

* *

* For a more detailed description of a similar algorithm see: * Page 30 in "Fundamentals of Matrix Computations" 2nd Ed. by David S. Watkins * or any description of a block triangular solver in any other computational linear algebra book. *

* * @author Peter Abeles */ public class BlockTriangularSolver { /** * Inverts an upper or lower triangular block submatrix. * * @param blockLength * @param upper Is it upper or lower triangular. * @param T Triangular matrix that is to be inverted. Must be block aligned. Not Modified. * @param T_inv Where the inverse is stored. This can be the same as T. Modified. * @param temp Work space variable that is size blockLength*blockLength. */ public static void invert( final int blockLength , final boolean upper , final D1Submatrix64F T , final D1Submatrix64F T_inv , final double temp[] ) { if( upper ) throw new IllegalArgumentException("Upper triangular matrices not supported yet"); if( temp.length < blockLength*blockLength ) throw new IllegalArgumentException("Temp must be at least blockLength*blockLength long."); if( T.row0 != T_inv.row0 || T.row1 != T_inv.row1 || T.col0 != T_inv.col0 || T.col1 != T_inv.col1) throw new IllegalArgumentException("T and T_inv must be at the same elements in the matrix"); final int M = T.row1-T.row0; final double dataT[] = T.original.data; final double dataX[] = T_inv.original.data; final int offsetT = T.row0*T.original.numCols+M*T.col0; for( int i = 0; i < M; i += blockLength ) { int heightT = Math.min(T.row1-(i+T.row0),blockLength); int indexII = offsetT + T.original.numCols*(i+T.row0) + heightT*(i+T.col0); for( int j = 0; j < i; j += blockLength ) { int widthX = Math.min(T.col1-(j+T.col0),blockLength); for( int w = 0; w < temp.length; w++ ) { temp[w] = 0; } for( int k = j; k < i; k += blockLength ) { int widthT = Math.min(T.col1-(k+T.col0),blockLength); int indexL = offsetT + T.original.numCols*(i+T.row0) + heightT*(k+T.col0); int indexX = offsetT + T.original.numCols*(k+T.row0) + widthT*(j+T.col0); blockMultMinus(dataT,dataX,temp,indexL,indexX,0,heightT,widthT,widthX); } int indexX = offsetT + T.original.numCols*(i+T.row0) + heightT*(j+T.col0); BlockInnerTriangularSolver.solveL(dataT,temp,heightT,widthX,heightT,indexII,0); System.arraycopy(temp,0,dataX,indexX,widthX*heightT); } BlockInnerTriangularSolver.invertLower(dataT,dataX,heightT,indexII,indexII); } } /** * Inverts an upper or lower triangular block submatrix. * * @param blockLength * @param upper Is it upper or lower triangular. * @param T Triangular matrix that is to be inverted. Overwritten with solution. Modified. * @param temp Work space variable that is size blockLength*blockLength. */ public static void invert( final int blockLength , final boolean upper , final D1Submatrix64F T , final double temp[] ) { if( upper ) throw new IllegalArgumentException("Upper triangular matrices not supported yet"); if( temp.length < blockLength*blockLength ) throw new IllegalArgumentException("Temp must be at least blockLength*blockLength long."); final int M = T.row1-T.row0; final double dataT[] = T.original.data; final int offsetT = T.row0*T.original.numCols+M*T.col0; for( int i = 0; i < M; i += blockLength ) { int heightT = Math.min(T.row1-(i+T.row0),blockLength); int indexII = offsetT + T.original.numCols*(i+T.row0) + heightT*(i+T.col0); for( int j = 0; j < i; j += blockLength ) { int widthX = Math.min(T.col1-(j+T.col0),blockLength); for( int w = 0; w < temp.length; w++ ) { temp[w] = 0; } for( int k = j; k < i; k += blockLength ) { int widthT = Math.min(T.col1-(k+T.col0),blockLength); int indexL = offsetT + T.original.numCols*(i+T.row0) + heightT*(k+T.col0); int indexX = offsetT + T.original.numCols*(k+T.row0) + widthT*(j+T.col0); blockMultMinus(dataT,dataT,temp,indexL,indexX,0,heightT,widthT,widthX); } int indexX = offsetT + T.original.numCols*(i+T.row0) + heightT*(j+T.col0); BlockInnerTriangularSolver.solveL(dataT,temp,heightT,widthX,heightT,indexII,0); System.arraycopy(temp,0,dataT,indexX,widthX*heightT); } BlockInnerTriangularSolver.invertLower(dataT,heightT,indexII); } } /** *

* Performs an in-place solve operation on the provided block aligned sub-matrices.
*
* B = T-1 B
*
* where T is a triangular matrix. T or B can be transposed. T is a square matrix of arbitrary * size and B has the same number of rows as T and an arbitrary number of columns. *

* * @param blockLength Size of the inner blocks. * @param upper If T is upper or lower triangular. * @param T An upper or lower triangular matrix. Not modified. * @param B A matrix whose height is the same as T's width. Solution is written here. Modified. */ public static void solve( final int blockLength , final boolean upper , final D1Submatrix64F T , final D1Submatrix64F B , final boolean transT ) { if( upper ) { solveR(blockLength,T,B,transT); } else { solveL(blockLength,T,B,transT); } } /** *

* Performs an in-place solve operation where T is contained in a single block.
*
* B = T-1 B
*
* where T is a triangular matrix contained in an inner block. T or B can be transposed. T must be a single complete inner block * and B is either a column block vector or row block vector. *

* * @param blockLength Size of the inner blocks in the block matrix. * @param upper If T is upper or lower triangular. * @param T An upper or lower triangular matrix that is contained in an inner block. Not modified. * @param B A block aligned row or column submatrix. Modified. * @param transT If T is transposed or not. * @param transB If B is transposed or not. */ public static void solveBlock( final int blockLength , final boolean upper , final D1Submatrix64F T , final D1Submatrix64F B , final boolean transT ,final boolean transB ) { int Trows = T.row1-T.row0; if( Trows > blockLength ) throw new IllegalArgumentException("T can be at most the size of a block"); // number of rows in a block. The submatrix can be smaller than a block final int blockT_rows = Math.min(blockLength,T.original.numRows-T.row0); final int blockT_cols = Math.min(blockLength,T.original.numCols-T.col0); int offsetT = T.row0*T.original.numCols+blockT_rows*T.col0; final double dataT[] = T.original.data; final double dataB[] = B.original.data; if( transB ) { if( upper ) { if ( transT ) { throw new IllegalArgumentException("Operation not yet supported"); } else { throw new IllegalArgumentException("Operation not yet supported"); } } else { if ( transT ) { throw new IllegalArgumentException("Operation not yet supported"); } else { for( int i = B.row0; i < B.row1; i += blockLength ) { int N = Math.min(B.row1 , i + blockLength ) - i; int offsetB = i*B.original.numCols + N*B.col0; BlockInnerTriangularSolver.solveLTransB(dataT,dataB,blockT_rows,N,blockT_rows,offsetT,offsetB); } } } } else { if( Trows != B.row1-B.row0 ) throw new IllegalArgumentException("T and B must have the same number of rows."); if( upper ) { if ( transT ) { for( int i = B.col0; i < B.col1; i += blockLength ) { int offsetB = B.row0*B.original.numCols + Trows*i; int N = Math.min(B.col1 , i + blockLength ) - i; BlockInnerTriangularSolver.solveTransU(dataT,dataB,Trows,N,Trows,offsetT,offsetB); } } else { for( int i = B.col0; i < B.col1; i += blockLength ) { int offsetB = B.row0*B.original.numCols + Trows*i; int N = Math.min(B.col1 , i + blockLength ) - i; BlockInnerTriangularSolver.solveU(dataT,dataB,Trows,N,Trows,offsetT,offsetB); } } } else { if ( transT ) { for( int i = B.col0; i < B.col1; i += blockLength ) { int offsetB = B.row0*B.original.numCols + Trows*i; int N = Math.min(B.col1 , i + blockLength ) - i; BlockInnerTriangularSolver.solveTransL(dataT,dataB,Trows,N,blockT_cols,offsetT,offsetB); } } else { for( int i = B.col0; i < B.col1; i += blockLength ) { int offsetB = B.row0*B.original.numCols + Trows*i; int N = Math.min(B.col1 , i + blockLength ) - i; BlockInnerTriangularSolver.solveL(dataT,dataB,Trows,N,blockT_cols,offsetT,offsetB); } } } } } /** *

* Solves lower triangular systems:
*
* B = L-1 B
*
*

* *

Reverse or forward substitution is used depending upon L being transposed or not.

* * @param blockLength * @param L Lower triangular with dimensions m by m. Not modified. * @param B A matrix with dimensions m by n. Solution is written into here. Modified. * @param transL Is the triangular matrix transposed? */ public static void solveL( final int blockLength , final D1Submatrix64F L, final D1Submatrix64F B , boolean transL ) { D1Submatrix64F Y = new D1Submatrix64F(B.original); D1Submatrix64F Linner = new D1Submatrix64F(L.original); D1Submatrix64F Binner = new D1Submatrix64F(B.original); int lengthL = B.row1 - B.row0; int startI,stepI; if( transL ) { startI = lengthL - lengthL % blockLength; if( startI == lengthL && lengthL >= blockLength ) startI -= blockLength; stepI = -blockLength; } else { startI = 0; stepI = blockLength; } for( int i = startI; ; i += stepI ) { if( transL ) { if( i < 0 ) break; } else { if( i >= lengthL ) break; } // width and height of the inner T(i,i) block int widthT = Math.min(blockLength, lengthL-i); Linner.col0 = L.col0 + i; Linner.col1 = Linner.col0 + widthT; Linner.row0 = L.row0 + i; Linner.row1 = Linner.row0 + widthT; Binner.col0 = B.col0; Binner.col1 = B.col1; Binner.row0 = B.row0 + i; Binner.row1 = Binner.row0 + widthT; // solve the top row block // B(i,:) = T(i,i)^-1 Y(i,:) solveBlock(blockLength,false, Linner,Binner,transL,false); boolean updateY; if( transL ) { updateY = Linner.row0 > 0; } else { updateY = Linner.row1 < L.row1; } if( updateY ) { // Y[i,:] = Y[i,:] - sum j=1:i-1 { T[i,j] B[j,i] } // where i is the next block down // The summation is a block inner product if( transL ) { Linner.col1 = Linner.col0; Linner.col0 = Linner.col1 - blockLength; Linner.row1 = L.row1; //Tinner.col1 = Tinner.col1; // Binner.row0 = Binner.row0; Binner.row1 = B.row1; Y.row0 = Binner.row0-blockLength; Y.row1 = Binner.row0; } else { Linner.row0 = Linner.row1; Linner.row1 = Math.min(Linner.row0+blockLength, L.row1); Linner.col0 = L.col0; //Tinner.col1 = Tinner.col1; Binner.row0 = B.row0; //Binner.row1 = Binner.row1; Y.row0 = Binner.row1; Y.row1 = Math.min(Y.row0+blockLength,B.row1); } // step through each block column for( int k = B.col0; k < B.col1; k += blockLength ) { Binner.col0 = k; Binner.col1 = Math.min(k+blockLength,B.col1); Y.col0 = Binner.col0; Y.col1 = Binner.col1; if( transL ) { // Y = Y - T^T * B BlockMultiplication.multMinusTransA(blockLength, Linner,Binner,Y); } else { // Y = Y - T * B BlockMultiplication.multMinus(blockLength, Linner,Binner,Y); } } } } } /** *

* Solves upper triangular systems:
*
* B = R-1 B
*
*

* *

Only the first B.numRows rows in R will be processed. Lower triangular elements are ignored.

* *

Reverse or forward substitution is used depending upon L being transposed or not.

* * @param blockLength * @param R Upper triangular with dimensions m by m. Not modified. * @param B A matrix with dimensions m by n. Solution is written into here. Modified. * @param transR Is the triangular matrix transposed? */ public static void solveR( final int blockLength , final D1Submatrix64F R, final D1Submatrix64F B , boolean transR ) { int lengthR = B.row1 - B.row0; if( R.getCols() != lengthR ) { throw new IllegalArgumentException("Number of columns in R must be equal to the number of rows in B"); } else if( R.getRows() != lengthR ) { throw new IllegalArgumentException("Number of rows in R must be equal to the number of rows in B"); } D1Submatrix64F Y = new D1Submatrix64F(B.original); D1Submatrix64F Rinner = new D1Submatrix64F(R.original); D1Submatrix64F Binner = new D1Submatrix64F(B.original); int startI,stepI; if( transR ) { startI = 0; stepI = blockLength; } else { startI = lengthR - lengthR % blockLength; if( startI == lengthR && lengthR >= blockLength ) startI -= blockLength; stepI = -blockLength; } for( int i = startI; ; i += stepI ) { if( transR ) { if( i >= lengthR ) break; } else { if( i < 0 ) break; } // width and height of the inner T(i,i) block int widthT = Math.min(blockLength, lengthR-i); Rinner.col0 = R.col0 + i; Rinner.col1 = Rinner.col0 + widthT; Rinner.row0 = R.row0 + i; Rinner.row1 = Rinner.row0 + widthT; Binner.col0 = B.col0; Binner.col1 = B.col1; Binner.row0 = B.row0 + i; Binner.row1 = Binner.row0 + widthT; // solve the top row block // B(i,:) = T(i,i)^-1 Y(i,:) solveBlock(blockLength,true, Rinner,Binner,transR,false); boolean updateY; if( transR ) { updateY = Rinner.row1 < R.row1; } else { updateY = Rinner.row0 > 0; } if( updateY ) { // Y[i,:] = Y[i,:] - sum j=1:i-1 { T[i,j] B[j,i] } // where i is the next block down // The summation is a block inner product if( transR ) { Rinner.col0 = Rinner.col1; Rinner.col1 = Math.min(Rinner.col0+blockLength, R.col1); Rinner.row0 = R.row0; //Rinner.row1 = Rinner.row1; Binner.row0 = B.row0; //Binner.row1 = Binner.row1; Y.row0 = Binner.row1; Y.row1 = Math.min(Y.row0+blockLength,B.row1); } else { Rinner.row1 = Rinner.row0; Rinner.row0 = Rinner.row1 - blockLength; Rinner.col1 = R.col1; // Binner.row0 = Binner.row0; Binner.row1 = B.row1; Y.row0 = Binner.row0-blockLength; Y.row1 = Binner.row0; } // step through each block column for( int k = B.col0; k < B.col1; k += blockLength ) { Binner.col0 = k; Binner.col1 = Math.min(k+blockLength,B.col1); Y.col0 = Binner.col0; Y.col1 = Binner.col1; if( transR ) { // Y = Y - T^T * B BlockMultiplication.multMinusTransA(blockLength, Rinner,Binner,Y); } else { // Y = Y - T * B BlockMultiplication.multMinus(blockLength, Rinner,Binner,Y); } } } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy