org.ejml.alg.dense.misc.GenerateInverseFromMinor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ejml Show documentation
Show all versions of ejml Show documentation
A fast and easy to use dense matrix linear algebra library written in Java.
/*
* Copyright (c) 2009-2012, Peter Abeles. All Rights Reserved.
*
* This file is part of Efficient Java Matrix Library (EJML).
*
* EJML is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* EJML 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with EJML. If not, see .
*/
package org.ejml.alg.dense.misc;
import org.ejml.alg.generic.CodeGeneratorMisc;
import java.io.FileNotFoundException;
import java.io.PrintStream;
/**
* Generates unrolled matrix from minor analytical functions. these can run much faster than LU but will only
* work for small matrices.
*
* When computing the determinants for each minor there are some repeat calculations going on. I manually
* removed those by storing them in a local variable and only computing it once. Despite reducing the FLOP count
* it didn't seem to noticeably improve performance in a runtime benchmark..
*
* @author Peter Abeles
*/
public class GenerateInverseFromMinor {
String className = "UnrolledInverseFromMinor";
PrintStream stream;
int N;
public GenerateInverseFromMinor() throws FileNotFoundException {
stream = new PrintStream(className +".java");
}
public void createClass(int N) {
printTop(N);
printCalls(N);
for( int i = 2; i <= N; i++ ) {
printFunction(i);
}
stream.print("}\n");
}
private void printTop(int N) {
String foo = CodeGeneratorMisc.COPYRIGHT +
"\n" +
"package org.ejml.alg.dense.misc;\n" +
"\n" +
"import org.ejml.data.DenseMatrix64F;\n" +
"\n" +
"\n" +
"/**\n" +
" * This code was auto generated by {@link GenerateInverseFromMinor} and should not be modified\n" +
" * directly. The input matrix is scaled make it much less prone to overflow and underflow issues.\n" +
" * \n" +
" * @author Peter Abeles\n" +
" */\n" +
"public class "+className+" {\n"+
" \n" +
" public static final int MAX = "+N+";\n";
stream.print(foo);
}
private void printCalls( int N )
{
stream.print(
" \n" +
" public static void inv( DenseMatrix64F mat , DenseMatrix64F inv ) {\n");
stream.print(" double max = Math.abs(mat.data[0]);\n" +
" int N = mat.getNumElements();\n" +
" \n" +
" for( int i = 1; i < N; i++ ) {\n" +
" double a = Math.abs(mat.data[i]);\n" +
" if( a > max ) max = a;\n" +
" }\n\n");
stream.print(
" if( mat.numRows == 2 ) {\n" +
" inv2(mat,inv,1.0/max);\n");
for( int i = 3; i <= N; i++ ) {
stream.print(" } else if( mat.numRows == "+i+" ) {\n" +
" inv"+i+"(mat,inv,1.0/max); \n");
}
stream.print(" } else {\n" +
" throw new IllegalArgumentException(\"Not supported\");\n" +
" }\n" +
" }\n\n");
}
private void printFunction( int N )
{
stream.print(" public static void inv"+N+"( DenseMatrix64F mat , DenseMatrix64F inv , double scale )\n" +
" {\n" +
" double []data = mat.data;\n"+
"\n");
// extracts the first minor
this.N = N;
int matrix[] = new int[N*N];
int index = 0;
for( int i = 1; i <= N; i++ ) {
for( int j = 1; j <= N; j++ , index++) {
matrix[index] = index;
stream.print(" double "+a(index)+" = data[ "+index+" ]*scale;\n");
}
}
stream.println();
// compute all the minors
index = 0;
for( int i = 1; i <= N; i++ ) {
for( int j = 1; j <= N; j++ , index++) {
stream.print(" double m"+i+""+j+" = ");
if( (i+j) % 2 == 1 )
stream.print("-( ");
printTopMinor(matrix,i-1,j-1,N);
if( (i+j) % 2 == 1 )
stream.print(")");
stream.print(";\n");
}
}
stream.println();
// compute the determinant
stream.print(" double det = (a11*m11");
for( int i = 2; i <= N; i++ ) {
stream.print(" + "+a(i-1)+"*m"+1+""+i);
}
stream.println(")/scale;");
stream.println();
stream.print(" data = inv.data;\n");
index = 0;
for( int i = 1; i <= N; i++ ) {
for( int j = 1; j <= N; j++ , index++) {
stream.print(" data["+index+"] = m"+j+""+i+" / det;\n");
}
}
stream.println();
stream.print(" }\n");
stream.print("\n");
}
private void printTopMinor( int m[] , int row , int col , int N )
{
int d[] = createMinor(m,row,col,N);
det(d,0,N-1);
}
private int[] createMinor( int m[] , int row , int col , int N )
{
int M = N-1;
int[] ret = new int[ M*M ];
int index = 0;
for( int i = 0; i < N; i++ ) {
if( i == row ) continue;
for( int j = 0; j < N; j++ ) {
if( j == col ) continue;
ret[index++] = m[i*N+j];
}
}
return ret;
}
private void det( int m[] , int row , int N )
{
if( N == 1 ) {
stream.print(a(m[0]));
} else if( N == 2 ) {
stream.print(a(m[0])+"*"+a(m[3])+" - "+a(m[1])+"*"+a(m[2]));
} else {
int M = N-1;
for( int i = 0; i < N; i++ ) {
int d[] = createMinor(m,0,i,N);
int pow = i;
if( pow % 2 == 0 )
stream.print(" + "+a(m[i])+"*(");
else
stream.print(" - "+a(m[i])+"*(");
det(d,row+1,M);
stream.print(")");
}
}
}
private String a( int index )
{
int i = index/N+1;
int j = index%N+1;
return "a"+i+""+j;
}
public static void main( String args[] ) throws FileNotFoundException {
GenerateInverseFromMinor gen = new GenerateInverseFromMinor();
gen.createClass(5);
}
}