Matrix.h

Go to the documentation of this file.
00001 /*
00002         This file is part of ALIZE which is an open-source tool for 
00003         speaker recognition.
00004 
00005     ALIZE is free software: you can redistribute it and/or modify
00006     it under the terms of the GNU Lesser General Public License as 
00007     published by the Free Software Foundation, either version 3 of 
00008     the License, or any later version.
00009 
00010     ALIZE is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU Lesser General Public License for more details.
00014 
00015     You should have received a copy of the GNU Lesser General Public 
00016     License along with ALIZE.
00017     If not, see <http://www.gnu.org/licenses/>.
00018         
00019         ALIZE is a development project initiated by the ELISA consortium
00020         [alize.univ-avignon.fr/] and funded by the French Research 
00021         Ministry in the framework of the TECHNOLANGUE program 
00022         [www.technolangue.net]
00023 
00024         The ALIZE project team wants to highlight the limits of voice
00025         authentication in a forensic context.
00026         The "Person  Authentification by Voice: A Need of Caution" paper 
00027         proposes a good overview of this point (cf. "Person  
00028         Authentification by Voice: A Need of Caution", Bonastre J.F., 
00029         Bimbot F., Boe L.J., Campbell J.P., Douglas D.A., Magrin-
00030         chagnolleau I., Eurospeech 2003, Genova].
00031         The conclusion of the paper of the paper is proposed bellow:
00032         [Currently, it is not possible to completely determine whether the 
00033         similarity between two recordings is due to the speaker or to other 
00034         factors, especially when: (a) the speaker does not cooperate, (b) there 
00035         is no control over recording equipment, (c) recording conditions are not 
00036         known, (d) one does not know whether the voice was disguised and, to a 
00037         lesser extent, (e) the linguistic content of the message is not 
00038         controlled. Caution and judgment must be exercised when applying speaker 
00039         recognition techniques, whether human or automatic, to account for these 
00040         uncontrolled factors. Under more constrained or calibrated situations, 
00041         or as an aid for investigative purposes, judicious application of these 
00042         techniques may be suitable, provided they are not considered as infallible.
00043         At the present time, there is no scientific process that enables one to 
00044         uniquely characterize a person=92s voice or to identify with absolute 
00045         certainty an individual from his or her voice.]
00046         Contact Jean-Francois Bonastre for more information about the licence or
00047         the use of ALIZE
00048 
00049         Copyright (C) 2003-2010
00050         Laboratoire d'informatique d'Avignon [lia.univ-avignon.fr]
00051         ALIZE admin [alize@univ-avignon.fr]
00052         Jean-Francois Bonastre [jean-francois.bonastre@univ-avignon.fr]
00053 */
00054 
00055 #if !defined(ALIZE_Matrix_h)
00056 #define ALIZE_Matrix_h
00057 
00058 #if defined(_WIN32)
00059 #if defined(ALIZE_EXPORTS)
00060 #define ALIZE_API __declspec(dllexport)
00061 #else
00062 #define ALIZE_API __declspec(dllimport)
00063 #endif
00064 #else
00065 #define ALIZE_API
00066 #endif
00067 
00068 #include <new>
00069 #include <math.h>
00070 
00071 #include <cstdio>
00072 #include <iostream>
00073 #include <fstream>
00074 #include <memory.h>
00075 #include <cstdlib>
00076 //#if defined(_WIN32)
00077 //#include <malloc.h>
00078 //#endif
00079 
00080 #include "RealVector.h"
00081 #include "DoubleSquareMatrix.h"
00082 #include "alizeString.h"
00083 #include "Exception.h"
00084 #include "Config.h"
00085 #include "Feature.h"
00086 
00087 #define TINY 1.0e-20 
00088 
00089 // Définition du Rand pour Windows
00090 #if defined(_WIN32)
00091         #define drand48()((double)rand()/RAND_MAX)
00092         #define srand48(n)srand((n));
00093 #endif
00094 
00095 using namespace std;
00096 
00097 namespace alize
00098 {
00110 
00111   template <class T> class ALIZE_API Matrix : public Object
00112   {
00113     friend class TestMatrix;
00114 
00115   public:
00116   
00121     Matrix(unsigned long rows = 0, unsigned long cols = 0)
00122       :Object(), _cols(cols), _rows(rows), _array(rows*cols, rows*cols) {}
00123 
00127     explicit Matrix(const FileName& f)
00128       :Object() { load(f, Config()); }
00129 
00134     explicit Matrix(const FileName& f, const Config& c)
00135       :Object() { load(f, c); }
00136       
00141     template <class R> explicit Matrix(const RealVector<R>& v)
00142     {
00143       _cols = v.size();
00144       _rows = 1;
00145       _array = v;
00146     }
00147       
00152     explicit Matrix(const Feature &f)
00153     {
00154       _array.setSize(f.getVectSize());
00155       _cols = f.getVectSize();
00156       _rows = 1;      
00157       for (unsigned long i=0; i<f.getVectSize(); i++)
00158         _array[i]=(T)f[i];
00159     }
00160     
00164     explicit Matrix(const DoubleSquareMatrix &M)
00165     {
00166       _cols = M.size();
00167       _rows =M.size();      
00168       for (unsigned long i=0; i<_rows; i++)
00169               for (unsigned long j=0; j<_cols; j++)
00170                     _array[i*_rows+j]=(T)M(i,j);
00171     }
00172       
00176     Matrix<T>& operator=(const Matrix<T>& m)
00177     {
00178       _array = m._array;
00179       _cols = m._cols;
00180       _rows = m._rows;
00181       return *this;
00182     }
00183     
00184     bool operator==(const Matrix<T>& m) const
00185     {
00186       return (_cols == m._cols && _rows == m._rows && _array == m._array);
00187     }
00188 
00189     bool operator!=(const Matrix<T>& m) const { return !(*this == m); }
00190 
00191     Matrix(const Matrix<T>& m)
00192     :Object(), _cols(m._cols), _rows(m._rows), _array(m._array) {}
00193 
00194     virtual ~Matrix() {}
00195 
00198     unsigned long cols() const { return _cols; }
00199 
00202     unsigned long rows() const { return _rows; }
00203 
00208     void setDimensions(const unsigned long rows, const unsigned long cols)
00209     {
00210       _cols = cols;
00211       _rows = rows;
00212       _array.setSize(cols*rows);
00213     }
00214 
00218     template <class R> void setAllValues(R v) { _array.setAllValues(v); }
00219 
00226     T& operator()(unsigned long row, unsigned long col)
00227     {
00228       assertIsInBounds(__FILE__, __LINE__, col, _cols);
00229       assertIsInBounds(__FILE__, __LINE__, row, _rows);
00230       return _array[row*_cols+col];
00231     }
00232 
00239     T operator()(unsigned long row, unsigned long col) const
00240     {
00241       assertIsInBounds(__FILE__, __LINE__, col, _cols);
00242       assertIsInBounds(__FILE__, __LINE__, row, _rows);
00243       return _array[row*_cols+col];
00244     }
00245 
00249     Matrix<T>& transpose()
00250     {
00251       unsigned long c, r, cc, rr;
00252       RealVector<T> tmp = _array;
00253       T* t = tmp.getArray();
00254       T* p = _array.getArray();
00255       for (r=0, rr=0; r<_rows; r++, rr+=_cols)
00256         for (c=0, cc=0; c<_cols; c++, cc+=_rows)
00257           p[r+cc] = t[c+rr];
00258       r = _rows;
00259       _rows = _cols;
00260       _cols = r;
00261       return *this;
00262     }
00263 
00267     Matrix<T> transpose() const
00268     {
00269       Matrix<T> tmp = *this;
00270       return tmp.transpose();
00271     }
00272 
00276     Matrix<T>& invert()
00277     {
00278       if(_cols!=_rows)
00279         throw Exception("Cannot invert matrix, non square matrix", __FILE__, __LINE__);
00280 
00281       int n = _cols;
00282       int i,j;
00283       T** a=(T**)malloc((n+1)*sizeof(T*));
00284       for (i=0;i<=n;i++)
00285         a[i]=(T*)malloc((n+1)*sizeof(T));
00286       for(j=1;j<=n;j++)
00287         for(i=1;i<=n;i++)
00288           a[i][j] = (*this)(i-1,j-1);
00289 
00290       int*indx = (int*)malloc((n+1)*sizeof(int));
00291       T** y = (T**)malloc((n+1)*sizeof(T*));     
00292       for (i=0;i<=n;i++)
00293         y[i]=(T*)malloc((n+1)*sizeof(T));  
00294       
00295       T* d = (T*)malloc((n+1)*sizeof(T)); 
00296       ludcmp(a,n,indx,d);
00297       free(d);
00298 
00299       T* col = (T*)malloc((n+1)*sizeof(T));            
00300       for(j=1;j<=n;j++)
00301       {
00302         for(i=1;i<=n;i++)
00303           col[i]=(T)0.0;
00304         col[j]=(T)1.0;
00305         lubksb(a,n,indx,col);
00306         for(i=1;i<=n;i++)
00307           y[i][j]=col[i];
00308       }
00309 
00310       for(j=1;j<=n;j++)
00311         for(i=1;i<=n;i++)
00312           (*this)(i-1,j-1) = y[i][j];
00313 
00314         free(col);
00315       free(indx);
00316       for (i=0;i<=n;i++)
00317       {
00318         free(a[i]);
00319         free(y[i]);
00320         a[i] = NULL;
00321         y[i] = NULL;
00322       }
00323       free(a);
00324       free(y);
00325       return *this;
00326     }
00327 
00331     Matrix<T> invert() const
00332     {
00333       Matrix<T> tmp = *this;
00334       return tmp.invert();
00335     }
00336 
00342     Matrix<T> operator*(const Matrix<T>& m) const
00343     {
00344       if (_cols != m._rows)
00345         throw Exception("Cannot multiply matrices", __FILE__, __LINE__);
00346       const unsigned long cols = m._cols;
00347       Matrix<T> tmp(_rows, cols);
00348       tmp.setAllValues(0.0);
00349       T* pTmp = tmp._array.getArray();
00350       T* pM = m._array.getArray();
00351       T* p = _array.getArray();
00352       unsigned long i, j, k, i_cols, itmp_cols, kcols;
00353       for (i=0, i_cols=0, itmp_cols=0; i<_rows; i++, i_cols+=_cols, itmp_cols += cols)
00354         for (j=0; j<cols; j++)
00355           for (k=0, kcols=0; k<_cols; k++, kcols+=cols)
00356             pTmp[itmp_cols+j] += p[i_cols+k] * pM[kcols+j];
00357       return tmp;
00358     }
00359 
00364     Matrix<T>& operator*=(const Matrix<T>& m)
00365     {
00366       (*this) = (*this)*m;
00367       return *this;
00368     }
00369 
00374     Matrix<T>& operator*=(double v)
00375     {
00376       _array *= v;
00377       return *this;
00378     }
00379 
00385     Matrix<T> operator*(double v) const
00386     {
00387       Matrix<T> tmp = *this;
00388       tmp._array *= v;
00389       return tmp;
00390     }
00391 
00397     Matrix<T> operator+(const Matrix<T>& m) const
00398     {
00399       Matrix<T> tmp(*this);
00400       tmp._array += m._array;
00401       return tmp;
00402     }
00403 
00408     Matrix<T>& operator+=(const Matrix<T>& m)
00409     {
00410       if (_cols != m._cols || _rows != m._rows)
00411         throw Exception("Dimensions of matrices do not match", __FILE__, __LINE__);
00412       _array += m._array;
00413       return *this;
00414     }
00415 
00421     Matrix<T> operator-(const Matrix<T>& m) const
00422     {
00423       Matrix<T> tmp(*this);
00424       tmp._array -= m._array;
00425       return tmp;
00426     }
00427 
00432     Matrix<T>& operator-=(const Matrix<T>& m)
00433     {
00434       if (_cols != m._cols || _rows != m._rows)
00435         throw Exception("Dimensions of matrices do not match", __FILE__, __LINE__);
00436       _array -= m._array;
00437       return *this;
00438     }    
00439 
00444     void save(const FileName& f) { save(f, Config()); }
00445     
00451     void save(const FileName& f, const Config& c)
00452     {
00453      if (c.getParam("saveMatrixFormat")=="DT") saveDT(f,c);
00454      else if (c.getParam("saveMatrixFormat")=="DB") saveDB(f,c); 
00455       else throw Exception("saveMatrixFormat unknown! DT (Dense Text) or DB (Dense Binary)",__FILE__,__LINE__);
00456     }
00457     
00464     void saveDT(const FileName& f, const Config& c)
00465     {
00466       XList l;
00467       l.addLine().addElement(String::valueOf(_rows))
00468                  .addElement(String::valueOf(_cols));
00469       for (unsigned long j=0; j<_rows; j++)
00470       {
00471         XLine& li = l.addLine();
00472         for (unsigned long i=0; i<_cols; i++)
00473           li.addElement(String::valueOf((*this)(j,i)));
00474       }
00475       l.save(f, c);
00476     }
00477     
00483     void saveDB(const FileName&f,const Config& c)
00484     {
00485       try {
00486             ofstream outputMat(f.c_str(),ios::out|ios::binary);
00487             if(!outputMat)
00488                 throw IOException("Cannot open file", __FILE__, __LINE__,f);
00489             unsigned long rows=this->rows();
00490             unsigned long cols=this->cols();        
00491             T * array=_array.getArray();
00492             outputMat.write((char*)&rows,sizeof(rows));
00493             outputMat.write((char*)&cols,sizeof(cols));    
00494             outputMat.write((char*)array,rows*cols*sizeof(T));
00495             outputMat.close();
00496           }
00497           catch (Exception& e) {cout << e.toString().c_str() << endl;}
00498     }
00499     
00504     void load(const FileName& f) { load(f, Config()); }
00505     
00511     void load(const FileName& f, const Config& c)
00512     {
00513       if (c.getParam("loadMatrixFormat")=="DT") loadDT(f,c);
00514       else if (c.getParam("loadMatrixFormat")=="DB") loadDB(f,c); 
00515       else throw Exception("loadMatrixFormat unknown! DT (Dense Text) or DB (Dense Binary)",__FILE__,__LINE__);
00516     }
00523     void loadDT(const FileName& f, const Config& c)
00524     {
00525       XList l(f, c);
00526       unsigned long rows = l.getLine(0).getElement(0).toLong();
00527       unsigned long cols = l.getLine(0).getElement(1).toLong();
00528       setDimensions(rows,cols);
00529       l.rewind();
00530       l.getLine();
00531       XLine* p;
00532       String* s;
00533       unsigned long j = 0;
00534       while ((p = l.getLine()))
00535       {
00536         unsigned long i = 0;
00537         while ((s = p->getElement()))
00538         {
00539           (*this)(j, i) = (T) s->toDouble();
00540           i++;
00541         }
00542         j++;
00543       }
00544     }
00545     
00551     void loadDB(const FileName&f,const Config& c)
00552     {
00553       try {
00554             ifstream inputMat(f.c_str(),ios::in|ios::binary);
00555             if(!inputMat){
00556               throw IOException("Cannot open file", __FILE__, __LINE__,f);
00557           }
00558             unsigned long rows;
00559             unsigned long cols;
00560             inputMat.read((char*)&rows,sizeof(rows));
00561             inputMat.read((char*)&cols,sizeof(cols)); 
00562             setDimensions(rows,cols);
00563             inputMat.read((char*)_array.getArray(),rows*cols*sizeof(T));
00564             inputMat.close();
00565           }
00566           catch (Exception& e) {cout << e.toString().c_str() << endl;}
00567     }
00568 
00572     void randomInit()
00573     {
00574       try {
00575         for ( unsigned long r=0; r<_rows; r++ )     
00576                 for ( unsigned long c=0; c<_cols; c++ )         
00577                         (*this)(r,c)= (T) drand48();
00578           }
00579           catch (Exception& e) {cout << e.toString().c_str() << endl;}
00580     }
00581     
00586     T* getArray() const { return _array.getArray(); }
00587 
00588     virtual String toString() const
00589     {
00590       String s = Object::toString()
00591         + "\n  dimensions  = " + String::valueOf(_rows)+"x"+String::valueOf(_cols);
00592       for (unsigned long j=0; j<_rows; j++)
00593       {
00594          for (unsigned long i=0; i<_cols; i++)
00595          s += "\n  [" + String::valueOf(j)
00596             + "," + String::valueOf(i)
00597             + "] = " + String::valueOf((*this)(j,i));
00598         s += "\n";
00599       }
00600       return s;
00601     }
00602 
00603     virtual String getClassName() const { return "Matrix"; }
00604 
00612     Matrix<T> crop(unsigned long line, unsigned long col, unsigned long n_rows, unsigned long n_cols)
00613     {
00614         if( (line + n_rows > _rows) || (col + n_cols > _cols) ){
00615                 throw Exception("Cannot crop a such big Matrix",__FILE__,__LINE__);
00616         }
00617         
00618         Matrix<T> subM(n_rows, n_cols);
00619         T* subm=subM.getArray();
00620         T* array = _array.getArray();
00621         
00622         for(unsigned long i=0; i<n_rows; i++){
00623                 for(unsigned long j=0; j<n_cols; j++){
00624                         subm[i*n_cols+j] =  array[(line+i)*_cols+col+j];
00625                 }
00626         }
00627         return subM;
00628     } 
00629     
00635     void concatCols(const Matrix<T>& M1, const Matrix<T>& M2){
00636         
00637         //Verify the number of columns of the two matrices
00638         if( M1.cols() != M2.cols() ){
00639                 throw Exception("Cannot concatenate the given matrices, wrong dimensionality",__FILE__,__LINE__);
00640         }
00641         
00642         unsigned long nrows = M1.rows()+M2.rows();
00643         this->setDimensions(nrows,M1.cols());
00644         
00645         T* m1=M1.getArray();
00646         T* m2 = M2.getArray();
00647 
00648         for(unsigned long i=0; i<M1.cols()*M1.rows(); i++){
00649                 _array[i] =  m1[i];
00650         }
00651         for(unsigned long i=0; i<M2.cols()*M2.rows(); i++){
00652                 _array[i+M1.cols()*M1.rows()] =  m2[i];
00653         }
00654     }
00655 
00661     void concatRows(const Matrix<T>& M1, const Matrix<T>& M2){
00662         
00663         //Verify the number of columns of the two matrices
00664         if( M1.rows() != M2.rows() ){
00665                 throw Exception("Cannot concatenate the given matrices, wrong dimensionality",__FILE__,__LINE__);
00666         }
00667         
00668         unsigned long ncols = M1.cols()+M2.cols();
00669         this->setDimensions(M1.rows(),ncols);
00670         
00671         T* m1=M1.getArray();
00672         T* m2 = M2.getArray();
00673         
00674         for(unsigned long r=0; r<M1.rows(); r++){
00675                 for(unsigned long c1=0; c1<M1.cols(); c1++){
00676                         _array[r*ncols + c1] =  m1[r*M1.cols()+c1];
00677                 }
00678                 
00679                 for(unsigned long c2=0; c2<M2.cols(); c2++){
00680                         _array[r*ncols + M1.cols() + c2] =  m2[r*M2.cols()+c2];
00681                 }
00682         }
00683     }
00684 
00685 
00686 
00687   private:
00688 
00689     unsigned long _cols;
00690     unsigned long _rows;
00691     RealVector<T> _array;
00692 
00693         unsigned long fabs(unsigned long x) { return x; };
00694     void ludcmp(T **a, int n, int *indx, T *d)
00695     {
00696       int i,imax,j,k;
00697       T big,dum,sum,temp;
00698       T *vv;
00699       vv=(T*)malloc((n+1)*sizeof(T));
00700       for(i=0;i<=n;i++) vv[i]=(T)0.0;
00701       *d=(T)1.0; 
00702       //fprintf(stderr,"%d ",*d);      
00703       for (i=1;i<=n;i++) { 
00704           big=(T)0.0; 
00705           //fprintf(stderr,"%d ",i);           
00706           for (j=1;j<=n;j++)
00707               if ((temp=(T)fabs(a[i][j])) > big) big=(T)temp;
00708           if (big == 0.0) big=big;//fprintf(stderr,"Ciao");
00709           vv[i]=(T)(1.0/big);
00710       }
00711       //fprintf(stderr,"step 1\n");      
00712       for (j=1;j<=n;j++) { 
00713           for (i=1;i<j;i++) { 
00714               sum=a[i][j];
00715               for (k=1;k<i;k++) sum -= a[i][k]*a[k][j];
00716               a[i][j]=sum;
00717           }
00718           //    fprintf(stderr,"step 2\n");   
00719           big=(T)0.0;
00720           for (i=j;i<=n;i++) {
00721               sum=a[i][j];
00722               for (k=1;k<j;k++) sum -= a[i][k]*a[k][j];
00723               a[i][j]=sum;
00724               if ( (dum=vv[i]*(T)fabs(sum)) >= big) {
00725                   big=dum;
00726                   imax=i;
00727               }
00728           }
00729           if (j != imax) {
00730               for (k=1;k<=n;k++) {
00731                   dum=a[imax][k];
00732                   a[imax][k]=a[j][k];
00733                   a[j][k]=dum;
00734               }
00735               *d = -(*d); 
00736               vv[imax]=vv[j];
00737           }
00738           indx[j]=imax;
00739           if (a[j][j] == 0.0) a[j][j]=(T)TINY;
00740           if (j != n) {
00741               dum=(T)(1.0/(a[j][j]));
00742               for (i=j+1;i<=n;i++) a[i][j] *= dum;
00743           }
00744       } 
00745       free(vv);
00746     }
00747 
00748     void lubksb(T **a, int n, int *indx, T b[])
00749     {
00750       int i,ii=0,ip,j;
00751       T sum;
00752       for (i=1;i<=n;i++) { 
00753           ip=indx[i];
00754           sum=b[ip];
00755           b[ip]=b[i];
00756           if (ii)
00757           for (j=ii;j<=i-1;j++) sum -= a[i][j]*b[j];
00758           else if (sum) ii=i;
00759           b[i]=sum; 
00760       }
00761       for (i=n;i>=1;i--) { 
00762           sum=b[i];
00763           for (j=i+1;j<=n;j++) sum -= a[i][j]*b[j];
00764           b[i]=sum/a[i][i]; 
00765       } 
00766     }
00767 
00768   };
00769 
00770   typedef Matrix<double> DoubleMatrix;
00771 #if defined(_WIN32)
00772   template class Matrix<double>;
00773   template class Matrix<unsigned long>;
00774 #endif
00775   
00776 } // end namespace alize
00777 
00778 #endif  // ALIZE_Matrix_h
00779