// matrix.java jplewis 99 // modified // jan03 minor // dec01 scruff // nov01 scruff convenience methods // feb01 scruff printFull // dec00 scruff floatClone/doubleClone methods // nov00 scruff // sep00 switch from cstdio.printf to numberformat // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library 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 // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this library; if not, write to the // Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. // // contact info: zilla@computer.org package ZS; import java.io.*; import java.text.NumberFormat; import zlib.*; final public class matrix { // beware _stdout does not get flushed the same way/time as system.out. public static PrintWriter _stdout = new PrintWriter(System.out); public static NumberFormat _nf; public static NumberFormat _if; // for ints static { _nf = NumberFormat.getInstance(); _nf.setMinimumFractionDigits(3); _nf.setMaximumFractionDigits(3); _nf.setGroupingUsed ( false ); // do not do 15,000 (no comma) // for integers _if = NumberFormat.getInstance(); _if.setMinimumFractionDigits(0); _if.setMaximumFractionDigits(0); } /** */ public static void setFractionDigits(int n) { _nf.setMinimumFractionDigits(n); _nf.setMaximumFractionDigits(n); } //---------------------------------------------------------------- // matrix. int,float,double //---------------------------------------------------------------- /** */ public static void print(String msg, int[][] M) { print(_stdout, msg, M); _stdout.flush(); } /** * TODO: does printing int with _if work? */ public static void print(PrintWriter f, String msg, int[][] M) { int nr = M.length; int nc = M[0].length; f.println(msg); for( int ir=0; ir < nr; ir++ ) { f.print("[ "); if (nc <= 10) for(int ic=0; ic= xres) ? (xres-1) : (x+6); f.print("row "+y+" "+x+".."+end+": "); } f.print(_nf.format(A[y][x]) + " "); } f.println(""); } //y if (f == _stdout) f.flush(); else f.close(); } //printFull /** * print the whole thing to a file, for debugging. */ public static void printFull(String msg, double[][] A, String path) throws IOException { PrintWriter f = (path.equals("stdout") ? _stdout : new PrintWriter(new BufferedWriter(new FileWriter(path)))); f.print(msg); int yres = A.length; int xres = A[0].length; for( int y=0; y < yres; y++ ) { for( int x=0; x < xres; x++ ) { if (x%7 == 0) { f.println(""); int end = ((x+6) >= xres) ? (xres-1) : (x+6); f.print("row "+y+" "+x+".."+end+": "); } f.print(_nf.format(A[y][x]) + " "); } f.println(""); } //y if (f == _stdout) f.flush(); else f.close(); } //printFull //---------------------------------------------------------------- /** * print every element of a 1d float array, for detailed debugging. */ public static void printFull(String msg, float[] v, String path) throws IOException { PrintWriter f = (path.equals("stdout") ? _stdout : new PrintWriter(new BufferedWriter(new FileWriter(path)))); f.print(msg); int len = v.length; for( int x=0; x < len; x++ ) { if (x%7 == 0) { f.println(""); int end = ((x+6) >= len) ? (len-1) : (x+6); f.print(x+".."+end+": "); } f.print(_nf.format(v[x]) + " "); } //x f.println(""); if (f == _stdout) f.flush(); else f.close(); } //printFull /** * print every element of a 1d double array, for detailed debugging. */ public static void printFull(String msg, double[] v, String path) throws IOException { PrintWriter f = (path.equals("stdout") ? _stdout : new PrintWriter(new BufferedWriter(new FileWriter(path)))); f.print(msg); int len = v.length; f.println("--> v[0] = " + v[0]); for( int x=0; x < len; x++ ) { if (x%7 == 0) { f.println(""); int end = ((x+6) >= len) ? (len-1) : (x+6); f.print(x+".."+end+": "); } f.print(_nf.format(v[x]) + " "); } //x f.println(""); if (f == _stdout) f.flush(); else f.close(); } //printFull //---------------------------------------------------------------- // dimension compare //---------------------------------------------------------------- /** @deprecated moved to zlib.array */ public static void assertCongruent(int[] v1, int[] v2) { zliberror._assert(v1.length == v2.length, "vector length mismatch"); } //assertCongruent /** @deprecated moved to zlib.array */ public static void assertCongruent(float[] v1, float[] v2) { zliberror._assert(v1.length == v2.length, "vector length mismatch"); } //assertCongruent /** @deprecated moved to zlib.array */ public static void assertCongruent(double[] v1, double[] v2) { zliberror._assert(v1.length == v2.length, "vector length mismatch"); } //assertCongruent /** @deprecated moved to zlib.array */ public static void assertCongruent(int[][] m1, int[][] m2) { zliberror._assert((m1.length == m2.length) && (m1[0].length == m2[0].length), "matrix dimension mismatch"); } //assertCongruent /** @deprecated moved to zlib.array */ public static void assertCongruent(float[][] m1, float[][] m2) { zliberror._assert((m1.length == m2.length) && (m1[0].length == m2[0].length), "matrix dimension mismatch"); } //assertCongruent /** @deprecated moved to zlib.array */ public static void assertCongruent(double[][] m1, double[][] m2) { zliberror._assert((m1.length == m2.length) && (m1[0].length == m2[0].length), "matrix dimension mismatch"); } //assertCongruent /** @deprecated moved to zlib.array */ public static void assertDim(int[][] m, int nr, int nc) { zliberror._assert((m.length == nr) && (m[0].length == nc)); } //assertDim /** @deprecated moved to zlib.array */ public static void assertDim(float[][] m, int nr, int nc) { zliberror._assert((m.length == nr) && (m[0].length == nc)); } //assertDim /** @deprecated moved to zlib.array */ public static void assertDim(double[][] m, int nr, int nc) { zliberror._assert((m.length == nr) && (m[0].length == nc)); } //assertDim /** @deprecated moved to zlib.array */ public static void assertDim(int[] m, int nr) { zliberror._assert(m.length == nr); } //assertDim /** @deprecated moved to zlib.array */ public static void assertDim(float[] m, int nr) { zliberror._assert(m.length == nr); } //assertDim /** @deprecated moved to zlib.array */ public static void assertDim(double[] m, int nr) { zliberror._assert(m.length == nr); } //assertDim //---------------------------------------------------------------- /** * data is an array of n-dimensional data, not a matrix * depending on how you look at it. * Get the min/max bounds for each dimension. * Could be called column bounds. */ public static void getNDBounds(double[][] data, double[][] bounds) { int nd = data[0].length; zliberror._assert(nd == bounds.length, "matrix.getNDbounds:1"); zliberror._assert(bounds[0].length == 2, "matrix.getNDbounds:2"); for( int id=0; id < nd; id++ ) { bounds[id][0] = Double.POSITIVE_INFINITY; bounds[id][1] = Double.NEGATIVE_INFINITY; } int ndata = data.length; for( int i=0; i < ndata; i++ ) { for( int id=0; id < nd; id++ ) { double v = data[i][id]; if (v < bounds[id][0]) bounds[id][0] = v; if (v > bounds[id][1]) bounds[id][1] = v; } } } //getBounds //---------------------------------------------------------------- // clone //---------------------------------------------------------------- /** @deprecated moved to zlib.array */ public static double[][] clone(double[][] m) { double[][] mc = (double[][])m.clone(); for( int r=0; r < mc.length; r++ ) { mc[r] = (double[])m[r].clone(); } return mc; } //clone /** * return a double[][] copy of this float matrix * @deprecated moved to zlib.array */ public static double[][] doubleClone(float[][] matrix) { int nr = matrix.length; int nc = matrix[0].length; double[][] cmatrix = new double[nr][nc]; for( int r = 0; r < nr; r++ ) { for( int c = 0; c < nc; c++ ) { cmatrix[r][c] = matrix[r][c]; } } return cmatrix; } //doubleClone //---------------------------------------------------------------- /** * return a double[] copy of this float vector * @deprecated moved to zlib.array */ public static double[] doubleClone(float[] vec) { int nr = vec.length; double[] cvec = new double[nr]; for( int r = 0; r < nr; r++ ) { cvec[r] = vec[r]; } return cvec; } //doubleClone //---------------------------------------------------------------- /** * return a float[][] copy of this double matrix * @deprecated moved to zlib.array */ public static float[][] floatClone(double[][] matrix) { int nr = matrix.length; int nc = matrix[0].length; float[][] cmatrix = new float[nr][nc]; for( int r = 0; r < nr; r++ ) { for( int c = 0; c < nc; c++ ) { cmatrix[r][c] = (float)matrix[r][c]; } } return cmatrix; } //floatClone //---------------------------------------------------------------- /** * return a float[] copy of this double vector * @deprecated moved to zlib.array */ public static float[] floatClone(double[] vec) { int nr = vec.length; float[] cvec = new float[nr]; for( int r = 0; r < nr; r++ ) { cvec[r] = (float)vec[r]; } return cvec; } //floatClone //---------------------------------------------------------------- //---------------------------------------------------------------- // actual matrix operations //---------------------------------------------------------------- //---------------------------------------------------------------- //---------------------------------------------------------------- // zero //---------------------------------------------------------------- /** */ public static void zero(float[][] mat) { int nr = mat.length; int nc = mat[0].length; for( int r = 0; r < nr; r++ ) { float[] mr = mat[r]; for( int c = 0; c < nc; c++ ) { mr[c] = 0.f; } } } //zero /** */ public static void zero(double[][] mat) { int nr = mat.length; int nc = mat[0].length; for( int r = 0; r < nr; r++ ) { double[] mr = mat[r]; for( int c = 0; c < nc; c++ ) { mr[c] = 0.; } } } //zero //---------------------------------------------------------------- // colonEx, colonSet - matlab : operator //---------------------------------------------------------------- /** * colonExtract, like the matlab : operator, but only works with 2d arrays * colonex(0,0) = matlab mat(:,1) result is [nr,1] * colonex(0,1) = matlab mat(:,2) * colonex(1,0) = matlab mat(1,:) * colonex(1,1) = matlab mat(2,:) result is [1,nc] */ public static int[][] colonEx(int[][] mat, int dim, int el) { int nr = mat.length; int nc = mat[0].length; int[] size = new int[]{ nr,nc }; int[][] v = null; // dim=0 if (dim == 0) { int vdim = size[dim]; v = new int[vdim][1]; for( int i = 0; i < vdim; i++ ) { v[i][0] = mat[i][el]; } } else if (dim == 1) { int vdim = size[dim]; v = new int[1][vdim]; for( int i = 0; i < vdim; i++ ) { v[0][i] = mat[el][i]; } } else zliberror._assert(false, "colonEx only handles 2d arrays"); return v; } //colonEx /** * colonSet(m,0,k,v) = matlab mat(:,k+1) = v * colonSet(m,1,k,v) = matlab mat(k+1,:) = v */ public static void colonSet(int[][] mat, int dim, int el, int[][] v) { int nr = mat.length; int nc = mat[0].length; int[] size = new int[]{ nr,nc }; // dim=0 if (dim == 0) { int vdim = size[dim]; array.assertDim(v, vdim,1); for( int i = 0; i < vdim; i++ ) { mat[i][el] = v[i][0]; } } else if (dim == 1) { int vdim = size[dim]; array.assertDim(v, 1,vdim); for( int i = 0; i < vdim; i++ ) { mat[el][i] = v[0][i]; } } else zliberror._assert(false, "extract only handles 2d arrays"); } //colonSet //---------------------------------------------------------------- // identity //---------------------------------------------------------------- /** * float version */ public static void setIdentity(float[][] mat) { int nr = mat.length; int nc = mat[0].length; for( int r = 0; r < nr; r++ ) { for( int c = 0; c < nc; c++ ) { if (r == c) mat[r][c] = 1.f; else mat[r][c] = 0.f; } } } //setIdentity /** */ public static void setIdentity(double[][] mat) { int nr = mat.length; int nc = mat[0].length; for( int r = 0; r < nr; r++ ) { for( int c = 0; c < nc; c++ ) { if (r == c) mat[r][c] = 1.; else mat[r][c] = 0.; } } } //setIdentity //---------------------------------------------------------------- // min,max //---------------------------------------------------------------- /** */ public static int[][] min(int[][] m1, int[][] m2) { int nr = m1.length; int nc = m1[0].length; int[][] mr = new int[nr][nc]; min( m1, m2, mr ); return mr; } //min(int) /** */ public static void min(int[][] m1, int[][] m2, int[][] mr) { array.assertCongruent(m1, m2); int nr = m1.length; int nc = m1[0].length; for( int ir = 0; ir < nr; ir++ ) { int[] m1row = m1[ir]; int[] m2row = m2[ir]; int[] mrrow = mr[ir]; for( int ic = 0; ic < nc; ic++ ) { int m1v = m1row[ic]; int m2v = m2row[ic]; mrrow[ic] = (m1v < m2v) ? m1v : m2v; } } } //min(int) /** */ public static int[][] max(int[][] m1, int[][] m2) { int nr = m1.length; int nc = m1[0].length; int[][] mr = new int[nr][nc]; max( m1, m2, mr ); return mr; } //add(int) /** */ public static void max(int[][] m1, int[][] m2, int[][] mr) { array.assertCongruent(m1, m2); int nr = m1.length; int nc = m1[0].length; for( int ir = 0; ir < nr; ir++ ) { int[] m1row = m1[ir]; int[] m2row = m2[ir]; int[] mrrow = mr[ir]; for( int ic = 0; ic < nc; ic++ ) { int m1v = m1row[ic]; int m2v = m2row[ic]; mrrow[ic] = (m1v > m2v) ? m1v : m2v; } } } //max(int) //---------------------------------------------------------------- // scale //---------------------------------------------------------------- /** * functional */ public static float[] scalefun(float scale, float[] v) { int len = v.length; float[] sv = new float[len]; for( int i = 0; i < len; i++ ) { sv[i] = v[i] * scale; } return sv; } //scale public static void scale(float scale, float[] v) { int len = v.length; for( int i = 0; i < len; i++ ) { v[i] *= scale; } } //scale /** * functional */ public static double[] scalefun(double scale, double[] v) { int len = v.length; double[] sv = new double[len]; for( int i = 0; i < len; i++ ) { sv[i] = v[i] * scale; } return sv; } //scale public static void scale(double scale, double[] v) { int len = v.length; for( int i = 0; i < len; i++ ) { v[i] *= scale; } } //scale //---------------------------------------------------------------- // add //---------------------------------------------------------------- /** * functional */ public static int[][] addfun(int[][] m1, int[][] m2) { int nr = m1.length; int nc = m1[0].length; int[][] mr = new int[nr][nc]; add( m1, m2, mr ); return mr; } //add(int) /** */ public static void add(int[][] m1, int[][] m2, int[][] mr) { array.assertCongruent(m1, m2); array.assertCongruent(m1, mr); int nr = m1.length; int nc = m1[0].length; for( int ir = 0; ir < nr; ir++ ) { int[] m1row = m1[ir]; int[] m2row = m2[ir]; int[] mrrow = mr[ir]; for( int ic = 0; ic < nc; ic++ ) { mrrow[ic] = m1row[ic] + m2row[ic]; } } } //add(int) /** * mr = s1*v1 + s2*v2 */ public static void addscaled(float s1, float[] v1, float s2, float[] v2, float[] vr) { array.assertCongruent(v1, v2); array.assertCongruent(v1, vr); int len = v1.length; for( int i = 0; i < len; i++ ) { vr[i] = s1*v1[i] + s2*v2[i]; } } //addscaled(float) /** * mr = s1*m1 + s2*m2 */ public static void addscaled(float s1, float[][] m1, float s2, float[][] m2, float[][] mr) { array.assertCongruent(m1, m2); array.assertCongruent(m1, mr); int nr = m1.length; int nc = m1[0].length; for( int ir = 0; ir < nr; ir++ ) { float[] m1row = m1[ir]; float[] m2row = m2[ir]; float[] mrrow = mr[ir]; for( int ic = 0; ic < nc; ic++ ) { mrrow[ic] = s1 * m1row[ic] + s2 * m2row[ic]; } } } //addscaled(float) /** * mr = s1*m1 + s2*m2 */ public static void addscaled(double s1, double[][] m1, double s2, double[][] m2, double[][] mr) { array.assertCongruent(m1, m2); array.assertCongruent(m1, mr); int nr = m1.length; int nc = m1[0].length; for( int ir = 0; ir < nr; ir++ ) { double[] m1row = m1[ir]; double[] m2row = m2[ir]; double[] mrrow = mr[ir]; for( int ic = 0; ic < nc; ic++ ) { mrrow[ic] = s1 * m1row[ic] + s2 * m2row[ic]; } } } //addscaled(double) //---------------------------------------------------------------- /** */ public static float[][] addfun(float[][] m1, float[][] m2) { int nr = m1.length; int nc = m1[0].length; float[][] mr = new float[nr][nc]; add( m1, m2, mr ); return mr; } //add(float) public static void add(float[][] m1, float[][] m2, float[][] mr) { array.assertCongruent(m1, m2); array.assertCongruent(m1, mr); int nr = m1.length; int nc = m1[0].length; for( int ir = 0; ir < nr; ir++ ) { float[] m1row = m1[ir]; float[] m2row = m2[ir]; float[] mrrow = mr[ir]; for( int ic = 0; ic < nc; ic++ ) { mrrow[ic] = m1row[ic] + m2row[ic]; } } } //add(float) //---------------------------------------------------------------- /** */ public static double[][] addfun(double[][] m1, double[][] m2) { int nr = m1.length; int nc = m1[0].length; double[][] mr = new double[nr][nc]; add( m1, m2, mr ); return mr; } //add(double) public static void add(final double[][] m1, final double[][] m2, double[][] mr) { array.assertCongruent(m1, m2); array.assertCongruent(m1, mr); int nr = m1.length; int nc = m1[0].length; for( int ir = 0; ir < nr; ir++ ) { double[] m1row = m1[ir]; double[] m2row = m2[ir]; double[] mrrow = mr[ir]; for( int ic = 0; ic < nc; ic++ ) { mrrow[ic] = m1row[ic] + m2row[ic]; } } } //add(double) public static void add(final double[] v1, final double[] v2, double[] v3) { int len = v1.length; zliberror._assert(v2.length == len); zliberror._assert(v3.length == len); for( int i = 0; i < len; i++ ) { v3[i] = v1[i] + v2[i]; } } //add // dont like the 'addfun' naming public static double[] add(final double[] v1, final double[] v2) { int len = v1.length; zliberror._assert(v2.length == len); double[] v3 = new double[len]; add(v1, v2, v3); return v3; } //add //---------------------------------------------------------------- // BLAS-like naming conventions: // saxpy = scalar a x + y = ax+y // gaxpy = general a x + y = Ax+y // sscal = single scale = a x // dscal = double scale = a x // (zilla) // funsaxpy = functional version, returns //---------------------------------------------------------------- /** */ public static double[][] alloc(int nr, int nc) { return new double[nr][nc]; } /** */ public static double[] alloc(int nr) { return new double[nr]; } //---------------------------------------------------------------- /** * todo is there a better algorithm? * maybe not, jama uses this algorithm */ public static double[][] transpose(final double[][] A) { int N = A.length; zliberror._assert(A[0].length == N, "transpose needs sqauare matrix"); double[][] B = alloc(N,N); for( int r=0; r < N; r++ ) { for( int c=0; c < N; c++ ) { B[r][c] = A[c][r]; } } return B; } //transpose //---------------------------------------------------------------- // matrix-matrix multiply //---------------------------------------------------------------- /** * Conformal matrix multiply M3[n1,n3] = M1[n1,n2] * M2[n2,n3]; * M3 must be distinct from M1,M2. */ public static void multiply(final double[][] A, final double[][] B, double[][] C) { int nr = A.length; int nc = B[0].length; int ni = A[0].length; zliberror._assert(ni == B.length, "matrices do not conform"); for( int r=0; r < nr; r++ ) { for( int c=0; c < nc; c++ ) { double sum = 0.0; for( int i=0; i < ni; i++ ) { sum += (A[r][i] * B[i][c]); } C[r][c] = sum; } } } //multiply public static double[][] multiply(final double[][] A, final double[][] B) { int nr = A.length; int nc = B[0].length; double[][] C = new double[nr][nc]; multiply(A,B, C); return C; } //multiply //---------------------------------------------------------------- // matrix-vector multiply //---------------------------------------------------------------- /** * multiply M,v */ public static double[] multiply(final double[][] M, final double[] v1) { int nr = M.length; int nc = M[0].length; zliberror._assert(v1.length == nc); double[] v2 = new double[nr]; for( int r=0; r < nr; r++ ) { double sum = 0.0; for( int c=0; c < nc; c++ ) sum += (M[r][c] * v1[c]); v2[r] = sum; } return v2; } /*multiply*/ /** * multiply M,v1 -> v2 */ public static void multiply(final double[][] M, final double[] v1, double[] v2) { int nr = M.length; int nc = M[0].length; zliberror._assert(v1.length == nc); zliberror._assert(v2.length == nr); for( int r=0; r < nr; r++ ) { double sum = 0.0; for( int c=0; c < nc; c++ ) sum += (M[r][c] * v1[c]); v2[r] = sum; } } /*multiply*/ } //matrix /* matrix.c -3 - a few general matrix routines * modified * 9apr/2 ansi update * * package: Mat * todo: * include solve(), renamed to MatSolve() for conflicts. */ /**************************************************************** /+* Copies M1 to M2. +/ final public static void MatCopy(M1,M2,m,n) Flotype *M1,*M2; int4 m,n; { Zbcopy((char *)M1,(char *)M2,m*n*sizeof(Flotype)); } /+Copy+/ /+OLDENTRY MatMul(M1,M2,M3,N) Square matrix multiply M3 = M1*M2; M3 must be distinct from M1,M2. +/ final public static void MatMul(A_,B_,C_,N) Flotype *A_,*B_,*C_; int4 N; { register int4 r,c,i; register Flotype sum; # define A(i,j) A_[(i)*N+(j)] # define B(i,j) B_[(i)*N+(j)] # define C(i,j) C_[(i)*N+(j)] for( r=0; r < N; r++ ) { for( c=0; c < N; c++ ) { sum = 0.0; for( i=0; i < N; i++ ) { sum += A(r,i) * B(i,c); } C(r,c) = sum; } } # undef A # undef B # undef C } /+matmul+/ /+OLDENTRY double MatInvert(M,N) Inverts M in place using Gauss-Jordan elimination, returning the determinant. Code from 'invert' in IBM scientific subroutine library (public domain). +/ double MatInvert( mat, n ) register Flotype mat[]; register int4 n; { # define MAXMAT 100 double det; register Flotype biga, hold; int4 l[MAXMAT], m[MAXMAT]; register int4 i,j,k; int4 ij,jk,ik,ji, iz, ki, kj; int4 jp,jq,jr; int4 nk,kk; extern double fabs(); if( n >= MAXMAT ) { fprintf( stderr, "Matrix Invert : %d too large \n", n); return 0.0; } det = 1.0; nk = -n; for(k=0; kk) { ki=k-n; for(i=0; ik) { jp=n*i; for(j=0; j=0; k--) { i=l[k]; if(i>k) { jq=n*k; jr=n*i; for(j=0; jk) { ki=k-n; for(i=0; imax) { max = fabs(a(k,i)); j = k; } if (max<=0.) return(0.); /+ if no nonzero pivot, PUNT +/ if (j!=i) { /+ swap rows i and j +/ for (k=i; k=0; i--) { /+ solve for x[i] (put it in b[i]) +/ sum = b[i]; for (k=i+1; k