// Made for repeated calls for the same size objects (arrays).
// Similar to ArrayUtil but is made to recycle arrays for faster performance. 
// But be careful, repeated calls to methods returning objects (arrays) will
// overwrite the object (array) that was returned previuosly by the same call.


public class Numerical {

    public Numerical() {}
    
    private int[] indxc, indxr, ipiv;
    public synchronized void gaussj(double a[][], double b[][]) throws IllegalArgumentException {
	int n = a.length;
	int m = b[0].length;
	
	if(indxc == null) {
	    indxc = new int[n];
	    indxr = new int[n];
	    ipiv = new int[n];
	}
	else if(indxc.length != n) {
	    indxc = new int[n];
	    indxr = new int[n];
	    ipiv = new int[n];
	}
	
	for(int j=0;j<n;j++) ipiv[j] = -1;

	for(int i=0;i<n;i++) {
	    int icol=-1, irow=-1;
	    double big=0.0;
	    for(int j=0;j<n;j++)
		if (ipiv[j] != 0)
		    for (int k=0;k<n;k++) {
			if(ipiv[k] == -1) {
			    if(Math.abs(a[j][k]) >= big) {
				big=Math.abs(a[j][k]);
				irow=j;
				icol=k;
			    }
			} else if (ipiv[k] > 0) throw new IllegalArgumentException("gaussj: Singular Matrix-1");
		    }
	    ++(ipiv[icol]);
	    if(irow != icol) {
		for(int l=0;l<n;l++) {
		    double temp = a[irow][l];
		    a[irow][l] = a[icol][l];
		    a[icol][l] = temp;
		}
		for(int l=0;l<m;l++) {
		    double temp = b[irow][l];
		    b[irow][l] = b[icol][l];
		    b[icol][l] = temp;
		}
	    }
	    indxr[i]=irow;
	    indxc[i]=icol;
	    if(a[icol][icol] == 0.0) throw new IllegalArgumentException("gaussj: Singular Matrix-2");
	    double pivinv=1.0/a[icol][icol];
	    a[icol][icol]=1.0;
	    for (int l=0;l<n;l++) a[icol][l] *= pivinv;
	    for (int l=0;l<m;l++) b[icol][l] *= pivinv;
	    for (int ll=0;ll<n;ll++)
		if (ll != icol) {
		    double dum=a[ll][icol];
		    a[ll][icol]=0.0;
		    for (int l=0;l<n;l++) a[ll][l] -= a[icol][l]*dum;
		    for (int l=0;l<m;l++) b[ll][l] -= b[icol][l]*dum;
		}
	}
	for (int l=n-1;l>=0;l--) {
	    if (indxr[l] != indxc[l])
		for (int k=0;k<n;k++) {
		    double temp = a[k][indxr[l]];
		    a[k][indxr[l]] = a[k][indxc[l]];
		    a[k][indxc[l]] = temp;
		}
	}
    } 
}
