/*************************************************************************/ /* */ /* Centre for Speech Technology Research */ /* University of Edinburgh, UK */ /* Copyright (c) 1995,1996 */ /* All Rights Reserved. */ /* */ /* Permission is hereby granted, free of charge, to use and distribute */ /* this software and its documentation without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of this work, and to */ /* permit persons to whom this work is furnished to do so, subject to */ /* the following conditions: */ /* 1. The code must retain the above copyright notice, this list of */ /* conditions and the following disclaimer. */ /* 2. Any modifications must be clearly marked as such. */ /* 3. Original authors' names are not deleted. */ /* 4. The authors' names are not used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */ /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */ /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */ /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */ /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */ /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */ /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */ /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */ /* THIS SOFTWARE. */ /* */ /*************************************************************************/ /* Author : Simon King */ /* Date : April 1995 */ /*-----------------------------------------------------------------------*/ /* EST_FMatrix Class auxiliary functions */ /* */ /*=======================================================================*/ #include "EST_FMatrix.h" #include "EST_system.h" #include #include #include "EST_unix.h" #include "EST_math.h" #include bool polynomial_fit(EST_FVector &x, EST_FVector &y, EST_FVector &co_effs, int order) { EST_FVector weights; weights.resize(x.n()); for(int i=0; i= 1" << endl; return false; } if(x.n() != y.n()){ cerr << "polynomial_fit : x and y must have same dimension" << endl; return false; } if(weights.n() != y.n()){ cerr << "polynomial_fit : weights must have same dimension as x and y" << endl; return false; } if(x.n() <= order){ cerr << "polynomial_fit : x and y must have at least order+1 elements" << endl; return false; } // matrix of basis function values EST_FMatrix A; A.resize(x.n(),order+1); EST_FVector y1; y1.resize(y.n()); for(int row=0;row v) v = a.a_no_check(i, j); return v; } int square(const EST_FMatrix &a) { return a.num_rows() == a.num_columns(); } // add all elements in matrix. float sum(const EST_FMatrix &a) { int i, j; float t = 0.0; for (i = 0; i < a.num_rows(); ++i) for (j = 0; j < a.num_columns(); ++j) t += a.a_no_check(i, j); return t; } // set all elements not on the diagonal to zero. EST_FMatrix diagonalise(const EST_FMatrix &a) { int i; EST_FMatrix b(a, 0); // initialise and fill b with zeros if (a.num_rows() != a.num_columns()) { cerr << "diagonalise: non-square matrix "; return b; } for (i = 0; i < a.num_rows(); ++i) b(i, i) = a.a_no_check(i, i); return b; } // set all elements not on the diagonal to zero. void inplace_diagonalise(EST_FMatrix &a) { // NB - will work on non-square matrices without warning int i,j; for (i = 0; i < a.num_rows(); ++i) for (j = 0; j < a.num_columns(); ++j) if(i != j) a.a_no_check(i, j) = 0; } EST_FMatrix sub(const EST_FMatrix &a, int row, int col) { int i, j, I, J; int n = a.num_rows() - 1; EST_FMatrix s(n, n); for (i = I = 0; i < n; ++i, ++I) { if (I == row) ++I; for (j = J = 0; j < n; ++j, ++J) { if (J == col) ++J; s(i, j) = a.a(I, J); } } // cout << "sub: row " << row << " col " << col << "\n" << s; return s; } EST_FMatrix row(const EST_FMatrix &a, int row) { EST_FMatrix s(1, a.num_columns()); int i; for (i = 0; i < a.num_columns(); ++i) s(0, i) = a.a(row, i); return s; } EST_FMatrix column(const EST_FMatrix &a, int col) { EST_FMatrix s(a.num_rows(), 1); int i; for (i = 0; i < a.num_rows(); ++i) s(i, 0) = a.a(i, col); return s; } EST_FMatrix triangulate(const EST_FMatrix &a) { EST_FMatrix b(a, 0); int i, j; for (i = 0; i < a.num_rows(); ++i) for (j = i; j < a.num_rows(); ++j) b(j, i) = a.a(j, i); return b; } void transpose(const EST_FMatrix &a,EST_FMatrix &b) { int i, j; b.resize(a.num_columns(), a.num_rows()); for (i = 0; i < b.num_rows(); ++i) for (j = 0; j < b.num_columns(); ++j) b.a_no_check(i, j) = a.a_no_check(j, i); } EST_FMatrix backwards(EST_FMatrix &a) { int i, j, n; n = a.num_columns(); EST_FMatrix t(n, n); for (i = 0; i < n; ++i) for (j = 0; j < n; ++j) t(n - i - 1, n - j - 1) = a.a(i, j); return t; } // changed name from abs as it causes on at least on POSIX machine // where int abs(int) is a macro EST_FMatrix fmatrix_abs(const EST_FMatrix &a) { int i, j; EST_FMatrix b(a, 0); for (i = 0; i < a.num_rows(); ++i) for (j = 0; j < a.num_columns(); ++j) b.a_no_check(i, j) = fabs(a.a_no_check(i, j)); return b; } static void row_swap(int from, int to, EST_FMatrix &a) { int i; float f; if (from == to) return; for (i=0; i < a.num_columns(); i++) { f = a.a_no_check(to,i); a.a_no_check(to,i) = a.a_no_check(from,i); a.a_no_check(from,i) = f; } } int inverse(const EST_FMatrix &a,EST_FMatrix &inv) { int singularity=0; return inverse(a,inv,singularity); } int inverse(const EST_FMatrix &a,EST_FMatrix &inv,int &singularity) { // Used to use a function written by Richard Tobin (in C) but // we no longer need C functionality any more. This algorithm // follows that in "Introduction to Algorithms", Cormen, Leiserson // and Rivest (p759) and the term Gauss-Jordon is used for some part, // As well as looking back at Richard's. // This also keeps a record of which rows are which from the original // so that it can return which column actually has the singularity // in it if it fails to find an inverse. int i, j, k; int n = a.num_rows(); EST_FMatrix b = a; // going to destructively manipulate b to get inv EST_FMatrix pos; // the original position float biggest,s; int r=0,this_row,all_zeros; singularity = -1; if (a.num_rows() != a.num_columns()) return FALSE; // Make the inverse the identity matrix. inv.resize(n,n); pos.resize(n,1); for (i=0; i biggest) { r = j; biggest = fabs(b.a_no_check(j,i)); } } if (biggest == 0.0) // oops found a singularity { singularity = (int)pos.a_no_check(i,0); return FALSE; } // Swap current with biggest this_row = (int)pos.a_no_check(i,0); // in case we need this number row_swap(r,i,b); row_swap(r,i,inv); row_swap(r,i,pos); // Make b(i,i) = 1 s = b(i,i); for (k=0; k j) ? this_row : j); return FALSE; } } } return TRUE; } int pseudo_inverse(const EST_FMatrix &a, EST_FMatrix &inv) { int singularity=0; return pseudo_inverse(a,inv,singularity); } int pseudo_inverse(const EST_FMatrix &a, EST_FMatrix &inv,int &singularity) { // for non-square matrices // useful for solving linear eqns // (e.g. polynomial fitting) // is it square ? if( a.num_rows() == a.num_columns() ) return inverse(a,inv,singularity); if( a.num_rows() < a.num_columns() ) return FALSE; EST_FMatrix a_trans,atrans_a,atrans_a_inverse; transpose(a,a_trans); multiply(a_trans,a,atrans_a); if (!inverse(atrans_a,atrans_a_inverse,singularity)) return FALSE; multiply(atrans_a_inverse,a_trans,inv); return TRUE; } float determinant(const EST_FMatrix &a) { int i, j; int n = a.num_rows(); float det; if (!square(a)) { cerr << "Tried to take determinant of non-square matrix\n"; return 0.0; } EST_FVector A(n); if (n == 2) // special case of 2x2 determinant return (a.a_no_check(0,0) * a.a_no_check(1,1)) - (a.a_no_check(0,1) * a.a_no_check(1,0)); float p; // create cofactor matrix j = 1; for (i = 0; i < n; ++i) { p = (float)(i + j + 2); // because i & j should start at 1 // cout << "power " <