/*
* Concept profile generation tool suite
* Copyright (C) 2015 Biosemantics Group, Erasmus University Medical Center,
* Rotterdam, The Netherlands
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package org.erasmusmc.math.matrix;
import org.erasmusmc.math.space.Space;
import org.erasmusmc.math.vector.Vector;
/**
* <p>Title: ACS Viewer</p>
* <p>Description: A viewer to visualize Associative Concept Spaces</p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Company: Erasmus MC, Medical Informatics</p>
* @author Peter-Jan Roes
* @version 1.0
*/
/** Determines a decomposition of a matrix A into a lower triangular matrix L
* and an upper triangular matrix U such that L*U is a permutation of A.
* This decomposition can be used to solve systems of linear equations
* and to determine the inverse of a matrix.
*/
public class PermutedLUDecomposition<R, C> extends RowArrayMatrix<R, C> {
protected Object[] indices;
protected double d;
public PermutedLUDecomposition(Matrix<R, C> matrix) throws Exception {
super(matrix);
// From Numerical Recipes, function ludcmp
Space<R> rowSpace = getRowSpace();
int rows = rowSpace.getDimensions();
int columns = getColumnSpace().getDimensions();
double[] implicitScalings = new double[rows];
indices = new Object[rows];
d = 1;
for (int i = 0; i < rows; i++) {
double big = 0;
for (int j = 0; j < columns; j++)
big = Math.max(big, Math.abs(values[i][j]));
if (big == 0)
throw new Exception("Singular matrix in LUDecomposition");
else
implicitScalings[i] = 1d / big;
}
int imax = 0;
for (int j = 0; j < columns; j++) {
double sum;
for (int i = 0; i < j; i++) {
sum = values[i][j];
for (int k = 0; k < i; k++)
sum -= values[i][k] * values[k][j];
values[i][j] = sum;
}
double maximum = 0;
for (int i = j; i < rows; i++) {
sum = values[i][j];
for (int k = 0; k < j; k++)
sum -= values[i][k] * values[k][j];
values[i][j] = sum;
double figureOfMerit = implicitScalings[i] * Math.abs(sum);
if (figureOfMerit >= maximum) {
maximum = figureOfMerit;
imax = i;
}
}
if (j != imax) {
swapRows(j, imax);
d = -d;
implicitScalings[imax] = implicitScalings[j];
}
indices[j] = rowSpace.objectForIndex(imax);
if (values[j][j] == 0d)
throw new Exception("Singular matrix in LUDecomposition");
if (j != rows - 1) {
double factor = 1d / values[j][j];
for (int i = j + 1; i < rows; i++)
values[i][j] *= factor;
}
}
}
public Matrix<R, C> getL() {
RowArrayMatrix<R, C> result = new RowArrayMatrix<R, C>(getRowSpace(), getColumnSpace());
int rows = getRowSpace().getDimensions();
for (int i = 1; i < rows; i++)
for (int j = 0; j < i; j++)
result.values[i][j] = values[i][j];
result.setMainDiagonal(1);
result.setAboveDiagonal(0);
return result;
}
public Matrix<R, C> getU() {
RowArrayMatrix<R, C> result = new RowArrayMatrix<R, C>(getRowSpace(), getColumnSpace());
int rows = getRowSpace().getDimensions();
int columns= getColumnSpace().getDimensions();
for (int i = 0; i < rows; i++)
for (int j = i; j < columns; j++)
result.values[i][j] = values[i][j];
result.setBelowDiagonal(0);
return result;
}
public void substituteBack(Vector b) {
// From Numerical Recipes, function lubksb
double sum;
int ii = -1;
Space rowSpace = b.getSpace();
int rows = rowSpace.getDimensions();
for (int i = 0; i < rows; i++) {
Object row = rowSpace.objectForIndex(i);
Object ip = indices[i];
sum = b.get(ip);
b.set(ip, b.get(row));
if (ii != -1)
for (int j = ii; j <= i - 1; j++)
sum -= values[i][j] * b.get(rowSpace.objectForIndex(j));
else if (sum != 0d)
ii = i;
b.set(row, sum);
}
for (int i = rows - 1; i >= 0; i--) {
Object row = rowSpace.objectForIndex(i);
sum = b.get(row);
for (int j = i + 1; j < rows; j++)
sum -= values[i][j] * b.get(rowSpace.objectForIndex(j));
b.set(row, sum / values[i][i]);
}
}
public void substituteBack(Matrix matrix) {
for (Object column: matrix.getColumnSpace())
substituteBack(matrix.getColumn(column));
}
public int[] getPermutation() {
int[] result = new int[indices.length];
for (int i = 0; i < result.length; i++)
result[i] = i;
for (int i = 0; i < result.length; i++) {
int row = rowSpace.indexOfObject((R) indices[i]);
int swap = result[row];
result[row] = result[i];
result[i] = swap;
}
return result;
}
}