/*******************************************************************************
* Copyright (c) 2009-2013 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.rascalmpl.eclipse.library.vis.util;
public class LinearSolver {
class TridiagonalRow{
double a, b, c, d;
void normalize(){
a/=b;
c/=b;
d/=b;
b = 1;
}
void substract(double factor, TridiagonalRow other){
a-=other.a*factor;
b-=other.b*factor;
c-=other.c*factor;
d-=other.d*factor;
}
}
//
// public static double[] solveTridiagonal(TridiagonalRow[] rows){
//
// // downwards sweep
// TridiagonalRow prev = rows[0];
// for(int i = 1 ; i < rows.length ; i++){
// TridiagonalRow cur = rows[i];
// cur.substract(cur.a/prev.b, prev);
// prev = cur;
// }
// // upwards sweep
// prev = rows[rows.length-1];
// for(int i = rows.length - 1 ; i >= 0 ; i--){
// TridiagonalRow cur = rows[i];
// cur.substract(cur.c/prev.b, prev);
// prev = cur;
// }
// for(TridiagonalRow r : rows){
// r.normalize();
// }
// }
// Solves a triadiagonal matrix, see http://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm
// public static double[] solveTridiagonal(double[] a, double []b, double[] c, double[] d){
// // forward sweep
// c[0] = c[0]/b[0];
// d[0] = d[0]/b[0];
// for(int i = 1 ; i < c.length ; i++){
// double m = c[i-1] * a[i];
// c[i] = c[i]/(b[i]-m);
// d[i] = (d[i] - d[i-1]*a[i])/(b[i] - m);
// }
// // backward sweep
// int last = c.length -1;
// double[] res = new double[c.length];
// res[last] = d[last];
// for(int i = last - 1 ; i >= 0 ; i--){
// res[i] = d[i] - c[i]*res[i+1];
// }
// return res;
// }
// Solves a system of linear equations
// assumes a that all rows are of same length, the last elements is the constant
// only works when forall i.coefficients[i][i] != 0
// and nrEquations == nrUnkowns i.e. coefficients.length == coefficients[0].length - 1
// also the system should be solvable :)
// works in place!
// uses partial pivoting for more numerical stability (see wikipeadia gaussian elim)
public static void gaussianElim(double[][] coefficients){
toRowEchelonForm(coefficients);
toRowCaconicalForm(coefficients);
toRowCaconicalForm(coefficients);
}
private static void toRowEchelonForm(double[][] coefficients) {
for(int curUnkown = 0 ; curUnkown < coefficients.length ; curUnkown++){
swapMax(coefficients, curUnkown);
normalize(coefficients,curUnkown);
substractFromRest(coefficients,curUnkown);
}
}
private static void normalize(double[][] coefficients, int curUnkown){
double factor = coefficients[curUnkown][curUnkown];
for(int i = 0 ; i < coefficients.length+1; i++){
coefficients[curUnkown][i]/=factor;
}
}
private static void substractFromRest(double[][] coefficients, int curUnkown) {
int nrEqs ;
nrEqs = coefficients.length;
for(int curEq = curUnkown + 1 ; curEq < nrEqs ; curEq++){
substractToEliminate(coefficients, curUnkown, curEq);
}
}
private static void substractToEliminate(double[][] coefficients,
int curUnkown, int curEq) {
double factor = coefficients[curEq][curUnkown] / coefficients[curUnkown][curUnkown];
for(int i = 0 ; i < coefficients.length + 1 ; i++){
coefficients[curEq][i] -= factor * coefficients[curUnkown][i];
}
}
private static void swapMax(double[][] coefficients,
int curUnkown) {
int maxUnkownEq = 0;
for(int curEq = 1 ; curEq < coefficients.length ; curEq++){
if(coefficients[curEq][curUnkown] > coefficients[maxUnkownEq][curUnkown]){
maxUnkownEq = curEq;
}
}
double[] tmp = coefficients[maxUnkownEq];
coefficients[maxUnkownEq] = coefficients[curUnkown];
coefficients[curUnkown] = tmp;
}
//assumes row echelon form
private static void toRowCaconicalForm(double[][] coefficients){
for(int curUnkown = coefficients.length-1; curUnkown >= 0 ; curUnkown--){
for(int i = 0 ; i < curUnkown ; i++){
substractToEliminate(coefficients,curUnkown,i);
}
}
}
}