ComputeNorm.cpp

Go to the documentation of this file.
00001 /*
00002 This file is part of LIA_RAL which is a set of software based on ALIZE
00003 toolkit for speaker recognition. ALIZE toolkit is required to use LIA_RAL.
00004 
00005 LIA_RAL project is a development project was initiated by the computer
00006 science laboratory of Avignon / France (Laboratoire Informatique d'Avignon -
00007 LIA) [http://lia.univ-avignon.fr <http://lia.univ-avignon.fr/>]. Then it
00008 was supported by two national projects of the French Research Ministry:
00009         - TECHNOLANGUE program [http://www.technolangue.net]
00010         - MISTRAL program [http://mistral.univ-avignon.fr]
00011 
00012 LIA_RAL is free software: you can redistribute it and/or modify
00013 it under the terms of the GNU Lesser General Public License as
00014 published by the Free Software Foundation, either version 3 of
00015 the License, or any later version.
00016 
00017 LIA_RAL is distributed in the hope that it will be useful,
00018 but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00020 GNU Lesser General Public License for more details.
00021 
00022 You should have received a copy of the GNU Lesser General Public
00023 License along with LIA_RAL.
00024 If not, see [http://www.gnu.org/licenses/].
00025 
00026 The LIA team as well as the LIA_RAL project team wants to highlight the
00027 limits of voice authentication in a forensic context.
00028 The "Person Authentification by Voice: A Need of Caution" paper
00029 proposes a good overview of this point (cf. "Person
00030 Authentification by Voice: A Need of Caution", Bonastre J.F.,
00031 Bimbot F., Boe L.J., Campbell J.P., Douglas D.A., Magrin-
00032 chagnolleau I., Eurospeech 2003, Genova].
00033 The conclusion of the paper of the paper is proposed bellow:
00034 [Currently, it is not possible to completely determine whether the
00035 similarity between two recordings is due to the speaker or to other
00036 factors, especially when: (a) the speaker does not cooperate, (b) there
00037 is no control over recording equipment, (c) recording conditions are not
00038 known, (d) one does not know whether the voice was disguised and, to a
00039 lesser extent, (e) the linguistic content of the message is not
00040 controlled. Caution and judgment must be exercised when applying speaker
00041 recognition techniques, whether human or automatic, to account for these
00042 uncontrolled factors. Under more constrained or calibrated situations,
00043 or as an aid for investigative purposes, judicious application of these
00044 techniques may be suitable, provided they are not considered as infallible.
00045 At the present time, there is no scientific process that enables one to
00046 uniquely characterize a persones voice or to identify with absolute
00047 certainty an individual from his or her voice.]
00048 
00049 Copyright (C) 2004-2010
00050 Laboratoire d'informatique d'Avignon [http://lia.univ-avignon.fr]
00051 LIA_RAL admin [alize@univ-avignon.fr]
00052 Jean-Francois Bonastre [jean-francois.bonastre@univ-avignon.fr]
00053 */
00054 
00055 #if !defined(ALIZE_ComputeNorm_cpp)
00056 #define ALIZE_ComputeNorm_cpp
00057 
00058 #include <iostream>
00059 #include <fstream>  
00060 #include <cstdio> 
00061 #include <cassert> 
00062 #include <cmath>
00063 #include <cstdlib>
00064 
00065 #include "liatools.h"
00066 #include "ComputeNorm.h"
00067 
00068 
00069 // JF Bonastre 4/11/2009 - cleaning and add dichotomic search in Norm
00070 // JF Bonastre 27/4/2010 -cleaning and add 
00071 //                          * impostor (target independent) selection
00072 //                          * High score discard
00073 //                                                      * Low score discard
00074 //                          * Median computation instead of aryth mean
00075                           
00076 
00077 using namespace alize;
00078 using namespace std;
00079 
00080 
00081 class DistribNorm{
00082         LKVector tabScore; // table of norm scores
00083         /* Use of LKVector ALIZE object, it provides sort functions */
00084         String *tabIdImp; // table of norm scores
00085         Config conf;
00086         public:
00087         void init();
00088         void addScore(double, const String&);
00089         bool computeMeanStd(double &, double&, char,double,double);
00090         unsigned long size();
00091         void print();
00092         DistribNorm(Config &);  
00093         ~DistribNorm();
00094 };
00095 
00096 void DistribNorm::init(){
00097         tabScore.clear(); 
00098 }
00099 
00100 unsigned long DistribNorm::size(){
00101         return tabScore.size();
00102 }
00103 
00104 void DistribNorm::addScore(double d, const String& idImp){
00105         LKVector::type t;
00106         unsigned long ind;
00107         /* idx value allows to keep in memory the impostor name related to each score, even after applying the sort function */
00108         /* After sorting, the name of an impostor is retrieved thanks to the tabIdImp[idx] */
00109         
00110         if(tabScore.size() == 0)
00111                 ind = (unsigned long)0;
00112         else
00113                 ind = (tabScore.size());
00114         t.lk = d;
00115         t.idx = ind;
00116         tabIdImp[ind] = idImp;
00117         tabScore.addValue(t);
00118 }
00119 
00120 
00121 bool DistribNorm::computeMeanStd(double &mean,double &std,char mode, double percentH,double percentL){
00122         if(tabScore.size() == 0) return false;
00123         else{
00124                 unsigned long size=tabScore.size();
00125                 unsigned long begin=0;
00126                 unsigned long end=size;
00127                 if ((percentH!=0) || (percentL!=0)){
00128                         tabScore.descendingSort();
00129                         unsigned long discardH=(unsigned long) (((double) size) * percentH);
00130                         unsigned long discardL=(unsigned long) (((double) size) * percentL);
00131                         size-=(discardH+discardL);
00132                         begin=discardH;
00133                         end=tabScore.size()-discardL;
00134                         if (debug) cout<<"discardH["<<discardH<<"] discardL["<<discardL<<"] begin["<<begin<<"] end["<<end<<"]"<<endl;   
00135                    }
00136                 double sum=0;
00137                 double sum2=0;
00138                 switch (mode){
00139                         case 0: //classical mean computation    
00140                                         for(unsigned int i=begin; i<end; i++){
00141                                                 sum += tabScore[i].lk;  
00142                                                 sum2 += tabScore[i].lk * tabScore[i].lk;
00143                                                 }
00144                                         mean=sum/(double)(size);
00145                                         std=sqrt((sum2/(double)(size)-(mean*mean)));  
00146                                         break;
00147                         case 1: // Median instead of mean
00148                                         mean=tabScore[begin+(size/2)].lk;
00149                                         for(unsigned int i=begin; i<end; i++)
00150                                                 sum += abs(tabScore[i].lk-mean); 
00151                                         std=sum/(double)(size);
00152                                         break;
00153                         default: cout <<"mean compute mode["<<mode<<"] unknown"<<endl;
00154                                          exit(0);
00155                 }                               
00156         
00157             return true;
00158         }
00159 }
00160 
00161 /*
00162 double DistribNorm::std(){
00163         double m;       
00164 
00165         if(tabScore.size() == 0){
00166                 cout << "No normalization score available for std computation: std=1.0" << endl;
00167                 return 1.0;      
00168         }
00169         m = mean();
00170         return 
00171 }*/
00172 
00173 
00174 void DistribNorm::print(){
00175         cout << "Distrib Score Print (nbScore=" << tabScore.size() << ")" << endl;
00176         for(unsigned int i=0; i<tabScore.size(); i++){
00177                 cout << tabIdImp[tabScore[i].idx] << " ";
00178                 printf("%.8lE ", tabScore[i].lk);
00179         }
00180         cout << endl;
00181 }
00182 
00183 DistribNorm::DistribNorm(Config &config){
00184         conf = config;
00185         unsigned long nbScoreMax = (unsigned long)(conf.getParam("maxScoreDistribNb").toLong());
00186         tabIdImp = new String[nbScoreMax];      
00187 //      meanVal = 0.0;
00188 //      stdVal = 1.0;
00189 }
00190 
00191 DistribNorm::~DistribNorm() {
00192         delete []tabIdImp;
00193 }
00194 
00195 class NormSeg{
00196         String name;
00197         double mean;
00198         double std;
00199         bool computed;
00200 //      double sum;
00201 //      double sum2;
00202         unsigned long nb;
00203         DistribNorm *distribNorm; // A pointer on an imp score distrib used once for computing the norm parameters
00204         public:
00205         double getMean(char,double,double);
00206         double getStd(char,double,double);
00207         unsigned long getNb();
00208         String getName();
00209         void setNb(unsigned long);
00210         void set(String,double,double); 
00211         void setName(String); 
00212         void addScore(double,const String &imp);
00213         void newDistribNorm(Config &);
00214         void deleteDistribNorm();
00215         NormSeg();
00216         ~NormSeg();
00217 };
00218 void NormSeg::addScore(double score,const String & imp){
00219         distribNorm->addScore(score,imp);
00220 }
00221 double NormSeg::getMean(char computeMode,double discardH,double discardL){
00222         if (!computed){
00223                         if (!distribNorm->computeMeanStd(mean,std,computeMode,discardH,discardL)){
00224                         cout << "Problem: empty impostor cohort"<<endl;
00225                         exit(0);
00226                     }
00227                 computed=true;
00228                 }
00229         return mean; 
00230 }
00231 
00232 double NormSeg::getStd(char computeMode,double discardH,double discardL){
00233         if (!computed){
00234                 if (!distribNorm->computeMeanStd(mean,std,computeMode,discardH,discardL)){
00235                         cout << "Problem: empty impostor cohort"<<endl;
00236                         exit(0);
00237                     }
00238                 computed=true;
00239                 }
00240         return std;     
00241 }
00242 
00243 unsigned long NormSeg::getNb(){
00244         return nb; 
00245 }
00246 
00247 String NormSeg::getName(){
00248         return name; 
00249 }
00250 
00251 
00252 void NormSeg::setNb(unsigned long m){
00253         nb = m; 
00254 }
00255 
00256 void NormSeg::set(String n,double m,double s){
00257         name = n; 
00258         mean = m; 
00259         std = s;
00260         computed=true; 
00261 }
00262 void NormSeg::setName(String n){
00263         name = n; 
00264 }
00265 void NormSeg::newDistribNorm(Config &config){
00266         distribNorm=new DistribNorm(config);
00267 }
00268 void NormSeg::deleteDistribNorm(){
00269         delete distribNorm;
00270         distribNorm=NULL;
00271 }
00272 NormSeg::NormSeg(){
00273          distribNorm=NULL; // initialize at NULL the distribNorm, initialized independently of NormSeg but freezed automatically
00274 }
00275 NormSeg::~NormSeg(){ // Clean, if needed, the DistribNorm
00276         if (distribNorm) deleteDistribNorm();
00277 }
00278 
00279 class Norm {
00280         NormSeg *normTab;        // table of normSeg => seg (or Id for znorm) name associated with mean and std values
00281         unsigned long nbNorm;    // number of normSeg in tabScore
00282         unsigned long nbNormMax; // Max number of normSeg in tabScore
00283         unsigned long findEntityIdxInNorm(String);             // Find where to add the seg info
00284         void moveEntity(unsigned long,unsigned long); // Make the room for the new Entity
00285         unsigned long idxLastFind;             // Save the idx of the last segment search
00286         char _computeMode;             // The mode for mean/std computation
00287                                                                   // 0=classical
00288                                                                   // 1=MedianBased                                                        
00289     double _percentH;        // % of Highest scores discarded
00290     double _percentL;        // % of Lowest scores discarded                                              
00291         public:
00292         bool findEntityInNorm(String,unsigned long &);   
00293         double getMean(unsigned long);
00294         double getStd(unsigned long);
00295         //double getSum(unsigned long);
00296         //double getSum2(unsigned long);
00297         unsigned long getNb(unsigned long);
00298         void print();
00299         unsigned long addSeg(String, double, double);
00300 //      unsigned long addSeg(String, double, double, unsigned long);
00301         unsigned long findAddSeg(String,Config&); // TAKE CARE, DO NOT INITIALIZE MEAN AND COV
00302         void addScore(unsigned long,double,const String &);
00303         void deleteAllDistribNorm(); // Clean the memory (done automatically - in ~NormSeg() - but could be asked manually)
00304         void setNormAndFreeDistrib();// Compute Mean and Cov and free the DistribNorm (per seg)
00305 //      void setNorm();              // Same, but not clean the DistribNorm
00306         Norm(unsigned long);         // Create a Norm object, with x NormSeg and Classical mean/std computation
00307         Norm(unsigned long, char,double,double); // Id but with a defined type of computation for mean/std
00308         ~Norm();
00309 };
00310 void Norm::setNormAndFreeDistrib(){
00311         for(unsigned long idx=0; idx<nbNorm; idx++){
00312                 normTab[idx].getMean(_computeMode,_percentH,_percentL);
00313                 normTab[idx].deleteDistribNorm();       
00314                 }
00315 }
00316 
00317 void Norm::addScore(unsigned long idx,double score,const String & imp)
00318 {               
00319         normTab[idx].addScore(score,imp);
00320 }
00321 void Norm::deleteAllDistribNorm(){              // clean the distribNorm to save space
00322         for(unsigned long i=0; i<nbNorm; i++)
00323                 normTab[i].deleteDistribNorm(); 
00324 }
00325 // Make the room for the new element
00326 // Could be time consumming. good to sort the score file (.res) before
00327 void Norm::moveEntity(unsigned long beg,unsigned long end){ 
00328         
00329         if (debug || (verboseLevel>2)) 
00330                 cout << "moveEntity beg["<<beg<<"] end["<<end<<"]"<<endl;
00331         for (unsigned idx=end;idx>beg;idx--)
00332                 normTab[idx]=normTab[idx-1];
00333         //memmove((void*)&(normTab[beg+1]),(void*)&(normTab[beg]),sizeof(NormSeg)*((beg-end)+1));
00334 }
00335 unsigned long Norm::findEntityIdxInNorm(String name){
00336         unsigned long beg=0;    
00337         unsigned long end=nbNorm-1;
00338         unsigned long idx=0;    
00339         if (nbNorm==0) return 0; // empty...
00340         while ((end-beg)>1){
00341                 idx=(beg+end)/2;
00342                 if (name > normTab[idx].getName())
00343                         beg=idx;
00344                         else end=idx;
00345                 }
00346         if (name <=normTab[beg].getName()) return beg;
00347                 else if (name>normTab[end].getName()) return end+1;
00348                         else return end; 
00349 }
00350 bool Norm::findEntityInNorm(String name,unsigned long & idx){
00351         if(nbNorm == 0) {idx=0;return false;}
00352         // last one searched?
00353         if (normTab[idxLastFind].getName() == name){
00354                 idx=idxLastFind;
00355                 return true;            
00356         }
00357         idx=findEntityIdxInNorm(name);
00358         if(normTab[idx].getName() == name){
00359                 idxLastFind=idx; 
00360                 return true;
00361                 }
00362         else return false; 
00363 }
00364 
00365 void Norm::print(){
00366         cout << "nbnorm: " << nbNorm << endl; 
00367         for(unsigned long i=0; i<nbNorm; i++){
00368                 cout << normTab[i].getName() << " " << getMean(i) << " " << getStd(i) << endl; 
00369         } 
00370 }
00371 
00372 double Norm::getMean(unsigned long ind){
00373         return normTab[ind].getMean(_computeMode,_percentH,_percentL);
00374 }
00375 
00376 double Norm::getStd(unsigned long ind){
00377         return normTab[ind].getStd(_computeMode,_percentH,_percentL);
00378 }
00379 
00380 unsigned long Norm::getNb(unsigned long ind){
00381         return normTab[ind].getNb();
00382 }
00383 
00384 unsigned long Norm::findAddSeg(String name,Config & config){ // TAKE CARE, JUST ADD THE SEG, DO NOT INITIALIZE MEAN/COV
00385         if(nbNorm == (nbNormMax)){
00386                 cout << "Table norm Capacity out of bound: " << nbNorm << endl; 
00387                 exit(-1);
00388         }
00389         unsigned long idx;
00390         if (!findEntityInNorm(name,idx)){       // the seg is missing
00391                 if (debug) cout <<"addSeg:seg["<<name<<"] idx["<<idx<<"]"<<endl;
00392                 moveEntity(idx,nbNorm);                      // Make the room for the new Entity
00393                 normTab[idx].setName(name);
00394                 nbNorm++;
00395                 normTab[idx].newDistribNorm(config);
00396         }
00397     return idx;
00398 }
00399 
00400 unsigned long Norm::addSeg(String name, double mean, double std){
00401         if(nbNorm == (nbNormMax)){
00402                 cout << "Table norm Capacity out of bound: " << nbNorm << endl; 
00403                 exit(-1);
00404         }
00405         unsigned long idx=findEntityIdxInNorm(name);   // Find where to add the seg info
00406         if (debug) cout <<"addSeg:seg["<<name<<"] idx["<<idx<<"]"<<endl;
00407         moveEntity(idx,nbNorm);                      // Make the room for the new Entity
00408         normTab[idx].set(name,mean,std); 
00409         nbNorm++;       
00410     return (idx);
00411 }
00412 
00413 Norm::Norm(unsigned long nbMax){
00414          _computeMode=0;
00415          _percentH=0;_percentL=0;
00416          nbNorm = 0;
00417          nbNormMax = nbMax;
00418          normTab = new NormSeg[nbNormMax];
00419          idxLastFind=0;
00420 }
00421 Norm::Norm(unsigned long nbMax, char compute,double percentH,double percentL){
00422          _computeMode=compute;
00423          _percentH=percentH;
00424          _percentL=percentL;
00425          nbNorm = 0;
00426          nbNormMax = nbMax;
00427          normTab = new NormSeg[nbNormMax];
00428          idxLastFind=0;
00429 }
00430 Norm::~Norm(){
00431         delete [] normTab; 
00432 }
00433 
00434 // Get the imp scores, for one seg or once for all
00435 //-------------------------------------------------------------------------------------------------------
00436 bool selectImp(String &fieldOne,String& fieldTwo,XList &impList,char selectMode)
00437 {
00438         bool select;
00439         switch (selectMode){
00440                 case 0:select=true;break; // No selection
00441                 case 1:select=(impList.findLine(fieldTwo) !=NULL);break; // target independent selection 
00442                 default:select=true;cout <<"selectMode unknown. No impostor scores selection is applied"<<endl;
00443                 }     
00444         return select;                       
00445 }                                                                                                                               
00446 void getAllScores(XList &list, unsigned long indFieldOne, unsigned long indFieldTwo, unsigned long indScore, Norm &norm,XList &impList,char selectMode,Config &config){
00447         XLine *linep;
00448         // ind* are used to locate information in NIST File in the case of format change
00449         list.getLine(0);
00450         while ((linep=list.getLine()) != NULL){
00451                 String fieldOne=linep->getElement(indFieldOne);
00452                 String fieldTwo=linep->getElement(indFieldTwo);
00453                 double score=linep->getElement(indScore).toDouble();                     
00454                 if (selectImp(fieldOne,fieldTwo,impList,selectMode)){ 
00455                    // If no selection of impostor scores is needed or if there is a selection and the impostor is in the list 
00456                    // Find the index in norm or add a seg/id in norm if needed, return the idx of the seg
00457                    // And initialize (memory ans others) the corresponding DistribNorm if needed
00458            unsigned long idx=norm.findAddSeg(fieldOne,config);
00459                    norm.addScore(idx,score, fieldTwo);
00460                    }
00461                 }       
00462 }       
00463                 
00464 // getAllScoresFirstNormed computes the score distributions for t or znorm AFTER applying firstNorm     normalization
00465 // used for ztnorm and tznorm                                                                                           
00466 void getAllScoresFirstNormed(XList &list, unsigned long indFieldOne, unsigned long indFieldTwo,unsigned long indScore, Norm &firstNorm, 
00467                         Norm &outNorm,XList &impList,char selectMode,Config &config){
00468         XLine *linep;
00469         // TODO Replace 0 and 3 by the indElt, indIdImp
00470         list.getLine(0);
00471         while ((linep=list.getLine()) != NULL){
00472                 String fieldOne=linep->getElement(indFieldOne);
00473                 String fieldTwo=linep->getElement(indFieldTwo);
00474                 double score=linep->getElement(indScore).toDouble();             
00475                 unsigned long ind;              
00476                 if (selectImp(fieldOne,fieldTwo,impList,selectMode)){ 
00477                         // If no selection of impostor scores is needed or if there is a selection and the impostor is in the list 
00478                         if(firstNorm.findEntityInNorm(fieldTwo,ind)){
00479                             unsigned long idx=outNorm.findAddSeg(fieldOne,config);
00480                                 outNorm.addScore(idx,(score - firstNorm.getMean(ind)) / firstNorm.getStd(ind), fieldTwo);
00481                         }
00482                         else{
00483                                 cout << "distribution for["<<fieldTwo<<"] not found!" << endl;
00484                                 cout <<"line:"<<linep<<endl;
00485                                 exit(-1); 
00486                                 }
00487                 }
00488         }
00489 }               
00490 //-------------------------------------------------------------------------------------------------------
00491 int ComputeNorm(Config& config)
00492 {
00493 
00494         using namespace alize;
00495         using namespace std;
00496 
00497         int decision=0; // TODO change ASAP
00498     String outputNISTFileName = config.getParam("outputFileBaseName");                        // Result file BAsenamein NIST style (.nist) result file format
00499     String znormFilesExtension = config.getParam("znormFilesExtension");                      // Result file znorm extension
00500     String tnormFilesExtension = config.getParam("tnormFilesExtension");                      // Result file tnorm extension
00501     String tznormFilesExtension = config.getParam("tznormFilesExtension");                    // Result file tztnorm extension
00502     String ztnormFilesExtension = config.getParam("ztnormFilesExtension");                    // Result file tztnorm extension
00503   
00504         // Norm Type = znorm, tnorm ou ztnorm
00505         unsigned long maxIdNb = (unsigned long)(config.getParam("maxIdNb").toLong());
00506         unsigned long maxSegNb = (unsigned long)(config.getParam("maxSegNb").toLong());
00507         String normType = config.getParam("normType");
00508         String testNistFile = config.getParam("testNistFile"); 
00509     char selectMode=0;       // 0 if no selection, 1 if target independent selection
00510     XList impList;
00511     if (config.existsParam("impostorIDList")){
00512         selectMode=1; // Target independent Impostor score selection mode       
00513         impList.load(config.getParam("impostorIDList"),config);
00514     }  
00515         char computeMode = (char)(config.getParam("meanMode").toLong()); // 0 classical, 1 Median
00516         double percentH=(double)(config.getParam("percentH").toDouble()); // % of hihest scores discarded
00517         double percentL=(double)(config.getParam("percentL").toDouble());// % of lowest scores discarded
00518         
00519         // Define the field of the score files
00520         char fieldGender=(char) config.getParam("fieldGender").toLong();
00521         char fieldName=(char)config.getParam("fieldName").toLong();
00522         //char fieldDecision=(char)config.getParam("fieldDecision").toLong(); // not used
00523         char fieldSeg=(char)config.getParam("fieldSeg").toLong();
00524         char fieldLLR=(char)config.getParam("fieldLLR").toLong();
00525         
00526         XList testList(testNistFile, config);
00527         testList.getLine(0); // goto first line still to debug
00528         
00529         try{            
00530         if(normType == "tnorm"){        
00531                 String outputFilename=outputNISTFileName+tnormFilesExtension;      // Create the complete output file filename
00532                 ofstream outFile(outputFilename.c_str(),ios::out | ios::trunc);    // Initialise the output file
00533                 Norm tnorm(maxSegNb,computeMode,percentH,percentL);// storage of mean and std for all segments
00534                 String tnormNistFile = config.getParam("tnormNistFile"); 
00535                 if (verbose) cout << "Tnorm, reading tnormList"<<endl;
00536                 XList tnormList(tnormNistFile, config);
00537                 getAllScores(tnormList, fieldSeg, fieldName, fieldLLR, tnorm,impList,selectMode,config);
00538                 tnorm.setNormAndFreeDistrib(); // finalize the mean/cov computation and free the score (the per seg DistribNorm)
00539 
00540                 if (verbose) cout << "Tnorm, begin the test list"<<endl;
00541                 XLine * linep;
00542                 while ((linep=testList.getLine()) != NULL){
00543                         // The test segment filename
00544                         String seg=linep->getElement(fieldSeg);
00545                         unsigned long ind;
00546                         if(debug) cout << endl << "findEntityInNorm SEG[" << seg << "]";                                
00547                         if (!tnorm.findEntityInNorm(seg,ind)){// Problem, the seg parameters are not present...
00548                                 cout << "tnorm impostor score not found for seg["<<seg<<endl;
00549                                 exit(-1); 
00550                                 }
00551                         if(debug) cout << " idx["<< ind<< "]"<<endl;                                                                            
00552                         double score = ((linep->getElement(fieldLLR)).toDouble() - tnorm.getMean(ind)) / tnorm.getStd(ind);
00553                 outputResultLine(score, linep->getElement(fieldName), seg, linep->getElement(fieldGender), decision, outFile);  
00554                 }
00555                 outFile.close();                        
00556             if(debug||verbose){
00557                         cout << "tnorm distrib" << endl;
00558                 tnorm.print();           
00559                 }
00560                       
00561         }
00562     else if(normType == "znorm"){       
00563         String outputFilename=outputNISTFileName+znormFilesExtension;      // Create the complete output file filename
00564                 ofstream outFile(outputFilename.c_str(),ios::out | ios::trunc);    // Initialise the output file
00565                 if(verbose) cout << endl << "Compute Znorm" << endl; 
00566                 // storage of mean and std for all segments
00567                 Norm znorm(maxIdNb,computeMode,percentH,percentL);
00568                 String znormNistFile = config.getParam("znormNistFile");        
00569                 XList znormList(znormNistFile, config);
00570                 XLine * linep;          
00571                 if (verbose) cout << "Computing once the Znorm distributions"<<endl<<
00572                                                          "Take Care, really faster if the score files are sorted!"<<endl;
00573                 getAllScores(znormList, fieldName, fieldSeg, fieldLLR, znorm,impList,selectMode,config);
00574                 znorm.setNormAndFreeDistrib(); // finalize the mean/cov computation and free the score (the per seg DistribNorm)
00575                 
00576                 while ((linep=testList.getLine()) != NULL){
00577                         // The test segment filename
00578                         String id=linep->getElement(fieldName);
00579                         unsigned long ind;      
00580                         if(verboseLevel>2) cout << endl << "Compute Znorm [" << id << "]"<< endl;                                                       
00581                         if(debug) cout << endl << "findEntityInNorm Id[" << id << "]";                          
00582                         if (!znorm.findEntityInNorm(id,ind)){// Problem, the seg parameters are not present...
00583                                 cout << "znorm impostor score not found for id["<<id<<endl;
00584                                 exit(-1); 
00585                             }
00586                         if(debug) cout << " idx["<< ind<< "]"<<endl;                                            
00587                         double score = ((linep->getElement(fieldLLR)).toDouble() - znorm.getMean(ind)) / znorm.getStd(ind);
00588                 outputResultLine(score, id, linep->getElement(fieldSeg), linep->getElement(fieldGender), decision, outFile);
00589                     }    
00590                 outFile.close();                    
00591             if(debug||verbose){
00592                         cout << "znorm distrib" << endl;
00593                 znorm.print();           
00594                     }   
00595             }
00596      else if(normType == "ztnorm"){ // Ztnorm outputs ztnorm AND tnorm results
00597         String outputTnormFilename=outputNISTFileName+tnormFilesExtension;          // Create the complete output file filename
00598         String outputZtnormFilename=outputNISTFileName+ztnormFilesExtension;    // Create the complete output file filename
00599         
00600                 ofstream outFileTnorm(outputTnormFilename.c_str(),ios::out | ios::trunc);      // Initialise the output file
00601                 ofstream outFileZtnorm(outputZtnormFilename.c_str(),ios::out | ios::trunc);    // Initialise the output file
00602                 if(verbose) cout << endl << "Compute ZTnorm (and tnorm)" << endl; 
00603                 // storage of mean and std for all segments
00604                 Norm tnorm(maxSegNb,computeMode,percentH,percentL);
00605                 Norm znorm(maxIdNb,computeMode,percentH,percentL);
00606                 Norm ztnorm(maxSegNb,computeMode,percentH,percentL);
00607                 
00608                 String tnormNistFile = config.getParam("tnormNistFile"); 
00609                 String znormNistFile = config.getParam("znormNistFile"); 
00610                 String ztnormNistFile = config.getParam("ztnormNistFile"); 
00611                 XList tnormList(tnormNistFile, config);
00612                 XList znormList(znormNistFile, config);
00613                 XList ztnormList(ztnormNistFile, config);
00614                                 
00615                 // tnorm distribution for the impostor segments (from imp_imp) in ztnorm                
00616                 if (verbose) cout << "Computing once the Tnorm distribution for impostor segments"<<endl<<
00617                                                          "Take Care, really faster if the score files are sorted!"<<endl;
00618                 getAllScores(ztnormList, fieldSeg, fieldName, fieldLLR, ztnorm,impList,selectMode,config);
00619                 ztnorm.setNormAndFreeDistrib(); // finalize the mean/cov computation and free the score (the per seg DistribNorm)
00620                 // compute the tnorm distributions for the (test) seg in tnorm
00621             if (verbose) cout << "Computing once all the tnorm distributions for the test segments "<<endl
00622                                               << "Take Care, really faster if the score files are sorted!"<<endl;
00623                 getAllScores(tnormList, fieldSeg, fieldName, fieldLLR, tnorm,impList,selectMode,config);
00624                 tnorm.setNormAndFreeDistrib(); // finalize the mean/cov computation and free the score (the per seg DistribNorm)
00625                 
00626                 // compute the znorm distrib for the tnormed scores in znorm
00627                 if (verbose) cout << "Computing once all the znorm (tnormed) distributions "<<endl
00628                                               << "Take Care, really faster if the score files are sorted!"<<endl;
00629                 getAllScoresFirstNormed(znormList, fieldName, fieldSeg, fieldLLR, ztnorm, znorm,impList,selectMode,config);
00630                 znorm.setNormAndFreeDistrib();// finalize the mean/cov computation and free the score (the per seg DistribNorm)
00631         
00632                 // for all the test lines (one test seg against several target speakers)
00633                 XLine * linep;
00634                 while ((linep=testList.getLine()) != NULL){
00635                         // The test segment filename
00636                         String seg=linep->getElement(fieldSeg);    // the test seg 
00637                         String id= linep->getElement(fieldName);   // the Id (target spk)
00638                         if (verboseLevel>2) cout << "ztnorm seg["<<seg<<"] Id["<<id<<"]"<<endl;
00639                         unsigned long ind;              
00640                         // segment tnorm distribution already computed ?
00641                         if(debug) cout << endl << "findEntityInNorm SEG[" << seg << "]";                                
00642                         if (!tnorm.findEntityInNorm(seg,ind)){// Problem, the seg parameters are not present...
00643                                 cout << "tnorm impostor distribution not found for seg["<<seg<<"]"<<endl;
00644                                 exit(-1); 
00645                                 }
00646                         if(debug) cout << " idx["<< ind<< "]"<<endl;    
00647                         double scoreTNorm = ((linep->getElement(fieldLLR)).toDouble() - tnorm.getMean(ind)) / tnorm.getStd(ind);
00648 
00649                         // ID mean and std already computed ?
00650                         if(!znorm.findEntityInNorm(id,ind)){// Problem, the seg parameters are not present...
00651                                 cout << "znorm(tnormed) distribution not found for id["<<id<<"]"<<endl;
00652                                 exit(-1); 
00653                                 }
00654                         double score = (scoreTNorm - znorm.getMean(ind)) / znorm.getStd(ind);
00655                         
00656                     outputResultLine(score, linep->getElement(fieldName), seg, linep->getElement(fieldGender), decision, outFileZtnorm);
00657                     outputResultLine(scoreTNorm, linep->getElement(fieldName), seg, linep->getElement(fieldGender), decision, outFileTnorm);
00658                 }             
00659                 outFileZtnorm.close();
00660                 outFileTnorm.close();
00661             if(debug||verbose){
00662                     cout << "tnorm distrib" << endl;
00663                         tnorm.print();           
00664                         cout << "znorm distrib" << endl;
00665                         znorm.print();           
00666                 }
00667         }     
00668            else if(normType == "tznorm"){ // tznorm outputs tznorm and znorm scores
00669         String outputTznormFilename=outputNISTFileName+tznormFilesExtension;    // Create the complete output file filename     
00670         String outputZnormFilename=outputNISTFileName+znormFilesExtension;          // Create the complete output file filename         
00671                 ofstream outFileTznorm(outputTznormFilename.c_str(),ios::out | ios::trunc);    // Initialise the output file
00672                 ofstream outFileZnorm(outputZnormFilename.c_str(),ios::out | ios::trunc);    // Initialise the output file
00673                 if(verbose) cout << endl << "Compute TZnorm" << endl; 
00674                 // storage of mean and std for all segments
00675                 Norm tnorm(maxSegNb,computeMode,percentH,percentL);
00676                 Norm znorm(maxIdNb,computeMode,percentH,percentL);
00677                 Norm tznorm(maxSegNb,computeMode,percentH,percentL);
00678                 
00679                 String tnormNistFile = config.getParam("tnormNistFile"); 
00680                 String znormNistFile = config.getParam("znormNistFile"); 
00681                 String tznormNistFile = config.getParam("ztnormNistFile"); 
00682                 XList tnormList(tnormNistFile, config);
00683                 XList znormList(znormNistFile, config);
00684                 XList tznormList(tznormNistFile, config);
00685                 
00686                 // compute znorm distribs for the target speakers ID in znorm 
00687                 if (verbose) cout << "Compute Znorm distribs for the target speakers (using znorm scores)"<<endl
00688                                                   <<"Computing once all the impostor distribution "<<endl
00689                                               << "Take Care, really faster if the score files are sorted!"<<endl;
00690                 getAllScores(znormList, fieldName, fieldSeg, fieldLLR, znorm,impList,selectMode,config);
00691                 znorm.setNormAndFreeDistrib(); // finalize the mean/cov computation and free the score (the per seg DistribNorm)                
00692                 
00693                 // compute znorm distribs for the impostor ID in tznorm 
00694                 if (verbose) cout << "Compute znorm distribs for the impostor speakers (using ztnorm scores)"
00695                                                   << "Computing once all the impostor distribution "<<endl
00696                                               << "Take Care, really faster if the score files are sorted!"<<endl;
00697                 getAllScores(tznormList, fieldName, fieldSeg, fieldLLR, tznorm,impList,selectMode,config);
00698                 tznorm.setNormAndFreeDistrib(); // finalize the mean/cov computation and free the score (the per seg DistribNorm)               
00699         
00700                 // compute tnorm distribs for the znormed scores
00701                 if (verbose) cout << "Compute tnorm distribs of the znormed scores "<<endl
00702                                                   << "Computing once all the impostor distribution "<<endl
00703                                               << "Take Care, really faster if the score files are sorted!"<<endl;
00704                 getAllScoresFirstNormed(tnormList, fieldSeg, fieldName, fieldLLR, tznorm, tnorm,impList,selectMode,config);
00705                 tnorm.setNormAndFreeDistrib();// finalize the mean/cov computation and free the score (the per seg DistribNorm)
00706                 if(debug|| verbose){
00707                     cout << "tnorm distrib" << endl;
00708                         tnorm.print();           
00709                         cout << "znorm distrib" << endl;
00710                         znorm.print();    
00711                     cout << "tznorm distrib" << endl;
00712                         tznorm.print();                  
00713                 }               
00714                 // for all the test lines (one test seg against several target speakers)
00715                 if (verbose) cout << "begin the test list"<<endl;
00716                 XLine * linep;
00717                 while ((linep=testList.getLine()) != NULL){
00718                         // The test segment filename
00719                         String seg=linep->getElement(fieldSeg);    // the test seg 
00720                         String id= linep->getElement(fieldName);   // the Id (target spk)
00721                         if (verboseLevel>2) cout << "tznorm seg["<<seg<<"] Id["<<id<<"]"<<endl;
00722                         unsigned long ind;              
00723                         // id mean and std already computed ?
00724                         if(debug) cout << endl << "findEntityInNorm SEG[" << seg << "]";                                
00725                         if (!znorm.findEntityInNorm(id,ind)){// Problem, the id parameters are not present...
00726                                 cout << "znorm distribution not found for id["<<id<<"]"<<endl;
00727                                 exit(-1); 
00728                                 }
00729                         if(debug) cout << " idx["<< ind<< "]"<<endl;    
00730                         double scoreZNorm = ((linep->getElement(fieldLLR)).toDouble() - znorm.getMean(ind)) / znorm.getStd(ind);
00731                         // segment mean and std already computed ?
00732                         if(!tnorm.findEntityInNorm(seg,ind)){// Problem, the seg parameters are not present...
00733                                 cout << "tnorm(znormed) distribution not found for seg["<<seg<<"]"<<endl;
00734                                 exit(-1); 
00735                                 }
00736                         double score = (scoreZNorm - tnorm.getMean(ind)) / tnorm.getStd(ind);
00737                         
00738                     outputResultLine(score, linep->getElement(fieldName), seg, linep->getElement(fieldGender), decision, outFileTznorm);
00739                     outputResultLine(scoreZNorm, linep->getElement(fieldName), seg, linep->getElement(fieldGender), decision, outFileZnorm);
00740                     if (verboseLevel>2) outputResultLine(score, linep->getElement(fieldName), seg, linep->getElement(fieldGender), decision, cout);
00741 
00742                 }             
00743                 outFileTznorm.close();
00744                 outFileZnorm.close();
00745             if(debug || verbose){
00746                     cout << "tnorm distrib" << endl;
00747                         tnorm.print();           
00748                         cout << "znorm distrib" << endl;
00749                         znorm.print();           
00750                 }
00751         }   
00752         else {
00753                   cout << "unknown normalization mode:"<<normType<<endl;
00754                   exit(-1); 
00755                   }   
00756         } //try
00757         catch (Exception& e){ 
00758                 cout << e.toString().c_str() << endl;
00759         }
00760 
00761               
00762     return 0;
00763 }
00764 
00765 #endif //!defined(ALIZE_ComputeNorm_cpp)