DistribGF.cpp

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_DistribGF_cpp)
00056 #define ALIZE_DistribGF_cpp
00057 
00058 
00059 #if defined(_WIN32)
00060   #include <cfloat> // for _isnan()
00061   #define ISNAN(x) _isnan(x)
00062 //#elif defined(__APPLE__)
00063 //  #define ISNAN(x) std::isnan(x)
00064 #elif defined(linux) || defined(__linux) || defined(__CYGWIN__) || defined(__APPLE__)
00065   #define ISNAN(x) isnan(x)
00066 #else
00067   #error "Unsupported OS\n"
00068 #endif
00069 
00070 #include <new>
00071 #include <cmath>
00072 #include <cstdlib>
00073 #include <memory.h>
00074 #include "DistribGF.h"
00075 #include "alizeString.h"
00076 #include "Feature.h"
00077 #include "Exception.h"
00078 #include "Config.h"
00079 
00080 
00081 using namespace alize;
00082 using namespace std;
00083 
00084 //-------------------------------------------------------------------------
00085 DistribGF::DistribGF(const unsigned long vectSize)
00086  :Distrib(vectSize), _covInvMatr(_vectSize),
00087  _cst(0.0), _tmpVect(_vectSize) {}
00088 //-------------------------------------------------------------------------
00089 DistribGF::DistribGF(const Config& c)
00090  :Distrib(c.getParam_vectSize()>0?c.getParam_vectSize():1),
00091  _covInvMatr(_vectSize), _cst(0.0), _tmpVect(_vectSize) {}
00092 //-------------------------------------------------------------------------
00093 void DistribGF::reset() // random init
00094 {
00095   throw Exception("Do not use this method temporary", __FILE__, __LINE__);
00096 // TODO: HOW TO FILL A POSITIVE-DEFINITE SYMMETRIC MATRIX WITH RANDOM VALUES ?
00097 
00098   //srand(time(NULL));
00099   /*if (_pCovMatr == NULL)
00100     _pCovMatr = createMatrix();
00101 
00102   for (unsigned long i=0; i< _vectSize; i++)
00103   {
00104     for (unsigned long j=0; j<_vectSize; j++)
00105     {
00106       (*_pCovMatr)(i,j) = (rand()+1.0)/(RAND_MAX+1.0); // always > 0.0
00107     }
00108     _meanVect[i] = (double)rand()*2/RAND_MAX - 1.0;
00109   }
00110   computeAll();*/
00111 }
00112 //-------------------------------------------------------------------------
00113 DistribGF& DistribGF::create(const K&, const unsigned long vectSize)
00114 {
00115   DistribGF* p = new (std::nothrow) DistribGF(vectSize);
00116   assertMemoryIsAllocated(p, __FILE__, __LINE__);
00117   return *p;
00118 }
00119 //-------------------------------------------------------------------------
00120 DistribGF& DistribGF::create(const K&, const Config& c)
00121 { return create(K::k, c.getParam_vectSize()); }
00122 //-------------------------------------------------------------------------
00123 DistribGF::DistribGF(const DistribGF& d)
00124 :Distrib(d._vectSize), _covMatr(d._covMatr), _covInvMatr(d._covInvMatr),
00125  _cst(d._cst), _tmpVect(d._vectSize)
00126 {
00127   _meanVect = d._meanVect;
00128   _det = d._det;
00129 }
00130 //-------------------------------------------------------------------------
00131 const Distrib& DistribGF::operator=(const Distrib& d) // virtual
00132 {
00133   const DistribGF* p = dynamic_cast<const DistribGF*>(&d);
00134   if (p == NULL)
00135     throw Exception("incompatible distrib", __FILE__, __LINE__);
00136   return operator=(*p);
00137 }
00138 //-------------------------------------------------------------------------
00139 const DistribGF& DistribGF::operator=(const DistribGF& d)
00140 {
00141   if (_vectSize != d._vectSize)
00142     throw Exception("target distrib vectSize ("
00143         + String::valueOf(_vectSize) + ") != source distrib vectSize ("
00144         + String::valueOf(d._vectSize) + ")", __FILE__, __LINE__);
00145   _meanVect = d._meanVect;
00146   _covInvMatr = d._covInvMatr;
00147   _covMatr = d._covMatr;
00148   _det = d._det;
00149   _cst = d._cst;
00150   return *this;
00151 }
00152 //-------------------------------------------------------------------------
00153 bool DistribGF::operator==(const Distrib& d) const
00154 {
00155   const DistribGF* p = dynamic_cast<const DistribGF*>(&d);
00156   if (p == NULL || _meanVect != p->_meanVect ||
00157     (_covMatr.size() == 0 && p->_covMatr.size() != 0) ||
00158     (_covMatr.size() != 0 && p->_covMatr.size() == 0))
00159     return false;
00160   if (_covMatr.size() == 0)
00161     return (_covInvMatr == p->_covInvMatr);
00162   return _covMatr == p->_covMatr;
00163 }  
00164 //-------------------------------------------------------------------------
00165 DistribGF& DistribGF::duplicate(const K&) const
00166 { return static_cast<DistribGF&>(clone()); }
00167 //-------------------------------------------------------------------------
00168 Distrib& DistribGF::clone() const // private
00169 {
00170   DistribGF* p = new (std::nothrow) DistribGF(*this);
00171   assertMemoryIsAllocated(p, __FILE__, __LINE__);
00172   return *p;
00173 }
00174 //-------------------------------------------------------------------------
00175 // TODO : A OPTIMISER !!
00176 //-------------------------------------------------------------------------
00177 lk_t DistribGF::computeLK(const Feature& frame) const
00178 {
00179   if (frame.getVectSize() != _vectSize)
00180     throw Exception("distrib vectSize ("
00181         + String::valueOf(_vectSize) + ") != feature vectSize ("
00182       + String::valueOf(frame.getVectSize()) + ")", __FILE__, __LINE__);
00183 
00184   real_t tmp = 0.0;
00185   real_t tmp2;
00186   unsigned long i, j, ii;
00187   real_t*      m = _meanVect.getArray();
00188   real_t*      x = _tmpVect.getArray();
00189   real_t*      c = _covInvMatr.getArray();
00190   Feature::data_t* f = frame.getDataVector();
00191 
00192   for (j=0; j<_vectSize; j++)
00193     x[j] = f[j] - m[j];
00194   for (i=0; i<_vectSize; i++)
00195   {
00196     tmp2 = 0.0;
00197     ii = i*_vectSize;
00198     for (j=0; j<_vectSize; j++)
00199       tmp2 += x[j] * c[j+ii];
00200     tmp += tmp2 * x[i];
00201   }
00202 
00203   tmp = _cst * exp(-0.5*tmp);
00204   if (ISNAN(tmp))
00205     return EPS_LK;
00206   return tmp;
00207 }
00208 //-------------------------------------------------------------------------
00209 lk_t DistribGF::computeLK(const Feature& frame, unsigned long idx) const
00210 {
00211   real_t x = frame[idx] - _meanVect[idx];
00212   real_t tmp = _cst * exp(-0.5 * x * x * _covInvMatr(idx, idx) );
00213   if (ISNAN(tmp))
00214     return EPS_LK;
00215   return tmp;
00216 }
00217 //-------------------------------------------------------------------------
00218 void DistribGF::computeAll()
00219 {
00220   // compute det and cov inv --------------------------------
00221 
00222   _det = _covMatr.invert(_covInvMatr);
00223 
00224   // compute cst -------------------------------
00225 
00226   if (_det > EPS_LK)
00227     _cst = 1.0 / ( pow(_det, 0.5) * pow( PI2 , _vectSize/2.0 ) );
00228   else
00229     _cst = 1.0 / ( pow(EPS_LK, 0.5) * pow( PI2 , _vectSize/2.0 ) );
00230 
00231   // remove cov matrix
00232   _covMatr.setSize(0, true);
00233 }
00234 //-------------------------------------------------------------------------
00235 void DistribGF::setCov(real_t v, unsigned long col, unsigned long row)
00236 {
00237   _covMatr.setSize(_vectSize);
00238   if (v < MIN_COV)
00239     v = MIN_COV;
00240   _covMatr(col, row) = v;
00241 }
00242 //-------------------------------------------------------------------------
00243 void DistribGF::setCovInv(const K&, const real_t v, const unsigned long col,
00244                                                    const  unsigned long row)
00245 { _covInvMatr(col, row) = v; }
00246 //-------------------------------------------------------------------------
00247 real_t DistribGF::getCov(unsigned long col, unsigned long row) const
00248 {
00249   _covMatr.setSize(_vectSize);
00250   return _covMatr(col, row);
00251 }
00252 //-------------------------------------------------------------------------
00253 real_t DistribGF::getCovInv(const unsigned long col,
00254                             const unsigned long row) const
00255 { return _covInvMatr(col, row); }
00256 //-------------------------------------------------------------------------
00257 DoubleSquareMatrix& DistribGF::getCovInvMatrix() {return _covInvMatr;}
00258 //-------------------------------------------------------------------------
00259 const DoubleSquareMatrix& DistribGF::getCovInvMatrix() const {return _covInvMatr;}
00260 //-------------------------------------------------------------------------
00261 DoubleSquareMatrix& DistribGF::getCovMatrix() { return _covMatr; }
00262 //-------------------------------------------------------------------------
00263 const DoubleSquareMatrix& DistribGF::getCovMatrix() const { return _covMatr; }
00264 //-------------------------------------------------------------------------
00265 String DistribGF::getClassName() const { return "DistribGF"; }
00266 //-------------------------------------------------------------------------
00267 String DistribGF::toString() const
00268 {
00269   String s = Object::toString()
00270   + "\n  vectSize  = " + String::valueOf(_vectSize)
00271   + "\n  det     = " + String::valueOf(_det)
00272   + "\n  cst     = " + String::valueOf(_cst);
00273   
00274   
00275   if (_covMatr.size() != 0)
00276     for (unsigned long i=0; i<_vectSize; i++)
00277       for (unsigned long j=0; j<_vectSize; j++)
00278         s += "\n  cov["+String::valueOf(i)+","+String::valueOf(j)+"] = "
00279           + String::valueOf(_covMatr(i,j))
00280           + "  covInv["+String::valueOf(i)+","+String::valueOf(j)+"] = "
00281           + String::valueOf(_covInvMatr(i,j));
00282   else
00283     for (unsigned long i=0; i<_vectSize; i++)
00284       for (unsigned long j=0; j<_vectSize; j++)
00285         s += "\n  covInv["+String::valueOf(i)+","+String::valueOf(j)+"] = "
00286           + String::valueOf(_covInvMatr(i,j));
00287     for (unsigned long i=0; i<_vectSize; i++)
00288         s += "\n  mean[" + String::valueOf(i) + "] = "
00289           + String::valueOf(_meanVect[i]);
00290   return s;
00291 }
00292 //-------------------------------------------------------------------------
00293 DistribGF::~DistribGF() {}
00294 //-------------------------------------------------------------------------
00295 #endif // !defined(ALIZE_DistribGF_cpp)
00296