gKitGL
Cdf.h
00001 
00002 #ifndef _GK_CDF_H
00003 #define _GK_CDF_H
00004 
00005 #include <cmath>
00006 #include <vector>
00007 #include <cassert>
00008 
00009 #include "Sampler.h"
00010 
00011 
00012 namespace gk {
00013     
00014 //! construction d'une fonction de repartition et choix aleatoire d'un element en fonction de la fonction de repartition. 
00015 class Cdf
00016 {
00017     std::vector<float> m_cdf;
00018     float m_total;
00019     
00020 public:
00021     //! constructeur, indique le nombre d'elements (optionnel).
00022     Cdf( const int reserve= 0 ) 
00023         :
00024         m_cdf(),
00025         m_total(0.f)
00026     {
00027         if(reserve > 0)
00028             m_cdf.reserve(reserve);
00029     }
00030     
00031     //! insere un element dans la fonction de repartition.
00032     void insert( const float v )
00033     {
00034         assert( v != 0.f );      // la pdf doit etre strictement positive
00035         assert(!isnan(v));
00036         assert(!isinf(v));
00037 
00038         // accumule les valeurs pour 'construire' la fonction de repartition.
00039         m_total= m_total + v;
00040         m_cdf.push_back(m_total);        
00041     }
00042     
00043 #if 1
00044     //! choisit un element, renvoie son indice et la probabilite de l'avoir choisi.
00045     //! utilise une recherche lineaire.
00046     float sampleSlow( int& id ) const
00047     {
00048         assert(m_cdf.empty() == false);
00049 
00050         // choisit une valeur aleatoire entre 0 et 1
00051         const float r= drand48() * m_total;
00052         
00053         // verifie le premier element
00054         id= 0;
00055         if(r < m_cdf[0])
00056             return m_cdf[0] / m_total;
00057         
00058         // recherche l'element i tel que cdf[i-1] < r*total < cdf[i]
00059         const int count= (int) m_cdf.size();
00060         for(int i= 1; i < count; i++)
00061         {
00062             if(r < m_cdf[i])
00063             {
00064                 id= i;
00065                 return (m_cdf[i] - m_cdf[i -1]) / m_total;
00066             }
00067         }
00068         
00069         // renvoie le dernier element
00070         id= count -1;
00071         return (m_cdf[id] - m_cdf[id -1]) / m_total;
00072     }
00073 #endif
00074 
00075     //! choisit un element, renvoie son indice et la probabilite de l'avoir choisi.
00076     //! utilise une recherche dichotomique dans l'ensemble de valeurs strictement croissant.
00077     float sample( const float u, int& id ) const
00078     {
00079         assert(m_cdf.empty() == false);
00080         
00081         const float r= u * m_total;
00082         // recherche l'element i tel que cdf[i-1] < r*total < cdf[i]
00083         int p= 0;
00084         int q= (int) m_cdf.size();
00085         while(p < q)
00086         {
00087             const int m= (p+q) / 2;
00088             if(m_cdf[m] < r)
00089                 p= m+1;
00090             else
00091                 q= m;
00092         }
00093         assert(p >= 0 && p < (int) m_cdf.size());
00094         
00095         // retrouve la valeur associee a l'element et renvoie la probabilite de l'avoir selectionne
00096         id= p;
00097         if(p > 0) 
00098             return (m_cdf[p] - m_cdf[p -1]) / m_total;
00099         else
00100             return m_cdf[0] / m_total;
00101     }
00102     
00103     float sample( Sampler& sampler, int& id ) const
00104     {
00105         // choisit une valeur aleatoire entre 0 et 1
00106         return sample(sampler.uniformFloat(), id);
00107     }
00108     
00109     //! renvoie la probabilite d'avoir selectionne un element.
00110     float pdf( const int id ) const
00111     {
00112         assert(m_cdf.empty() == false);
00113         
00114         if(id == 0)
00115             return m_cdf[0] / m_total;
00116         else
00117             return (m_cdf[id] - m_cdf[id -1]) / m_total;
00118     }
00119     
00120     //! choisit un element uniformement, renvoie son indice et la probabilite de l'avoir choisi.
00121     float sampleUniform( Sampler& sampler, int &id ) const
00122     {
00123         assert(m_cdf.empty() == false);
00124         // choisit une valeur aleatoire entre 0 et n-1
00125         id= drand48() * ((int) m_cdf.size() -1);
00126         assert(id < (int) m_cdf.size());
00127         // renvoie la probabilite d'avoir selectionne la valeur : 1 / n
00128         return 1.f / (float) m_cdf.size();
00129     }
00130     
00131     //! renvoie la probabilite d'avoir selection un element.
00132     float pdfUniform( const int id ) const
00133     {
00134         assert(m_cdf.empty() == false);
00135         return 1.f / (float) m_cdf.size();
00136     }
00137     
00138     //! renvoie le total de la fonction de repartition.
00139     float total( ) const
00140     {
00141         return m_total;
00142     }
00143 };
00144 
00145 }
00146 
00147 #endif
 All Classes Namespaces Functions Variables Typedefs Enumerator Friends