indii/ml/aux/GaussianPdf.hpp

00001 #ifndef INDII_ML_AUX_GAUSSIANPDF_HPP
00002 #define INDII_ML_AUX_GAUSSIANPDF_HPP
00003 
00004 #include "Pdf.hpp"
00005 
00006 #include "boost/serialization/split_member.hpp"
00007 
00008 namespace indii {
00009   namespace ml {
00010     namespace aux {
00011 /**
00012  * Multivariate Gaussian probability distribution.
00013  *
00014  * @author Lawrence Murray <lawrence@indii.org>
00015  * @version $Rev: 538 $
00016  * @date $Date: 2008-08-31 14:41:10 +0100 (Sun, 31 Aug 2008) $
00017  *
00018  * @section Serialization
00019  *
00020  * This class supports serialization through the Boost.Serialization
00021  * library. Two issues are worth noting.
00022  *
00023  * Firstly, Boost.uBLAS has limited serialization support in its CVS
00024  * snapshot at time of writing (3 Sep 2007). It appears limited to the
00025  * serialization of basic vectors and matrices: symmetric matrices do
00026  * not appear to be supported, for example.
00027  *
00028  * Secondly, it's arguable whether serializing pre-calculations is
00029  * useful or not. It makes for larger messages in a parallel
00030  * environment, the cost of sending which may exceed the savings of
00031  * the precalculations in the first place.
00032  *
00033  * The implementation here takes the path of least resistance in both
00034  * cases. We choose to use the limited Boost.uBLAS serialization
00035  * features anyway for ease of implementation, presuming that
00036  * eventually full serialization support will be provided. We also
00037  * choose to serialize just the bare essentials, excluding
00038  * pre-calculation results.
00039  */
00040 class GaussianPdf : public Pdf {
00041 public:
00042   /**
00043    * Default constructor.
00044    *
00045    * Initialises the Gaussian with zero dimensions. This should
00046    * generally only be used when the object is to be restored from a
00047    * serialization.
00048    */
00049   GaussianPdf();
00050 
00051   /**
00052    * Construct Gaussian given mean and covariance.
00053    *
00054    * @param mu \f$\mathbf{\mu}\f$; mean of the Gaussian.
00055    * @param sigma \f$\Sigma\f$; covariance of the Gaussian.
00056    */
00057   GaussianPdf(const vector& mu, const symmetric_matrix& sigma);
00058 
00059   /**
00060    * Construct Gaussian given dimensionality. The mean and covariance
00061    * remain uninitialised, and should be set with setExpectation() and
00062    * setCovariance().
00063    *
00064    * @param N \f$N\f$; number of dimensions of the Gaussian.
00065    */
00066   GaussianPdf(unsigned int N);
00067 
00068   /**
00069    * Assignment operator. Both sides must have the same dimensionality.
00070    */
00071   GaussianPdf& operator=(const GaussianPdf& o);
00072 
00073   /**
00074    * Destructor.
00075    */
00076   virtual ~GaussianPdf();
00077 
00078   virtual void setDimensions(const unsigned int N,
00079       const bool preserve = false);
00080 
00081   /**
00082    * Get the expected value of the distribution.
00083    *
00084    * @return \f$\mathbf{\mu}\f$; expected value of the distribution.
00085    */
00086   virtual const vector& getExpectation() const;
00087 
00088   /**
00089    * Get the covariance of the distribution.
00090    *
00091    * @return \f$\Sigma\f$; covariance of the distribution.
00092    */
00093   virtual const symmetric_matrix& getCovariance() const;
00094 
00095   virtual const vector& getExpectation();
00096 
00097   virtual const symmetric_matrix& getCovariance();
00098 
00099   /**
00100    * Set the mean of the Gaussian. The new mean vector must have the
00101    * same size as the previous one.
00102    *
00103    * @param mu \f$\mathbf{\mu}\f$; mean of the Gaussian.
00104    */
00105   virtual void setExpectation(const vector& mu);
00106 
00107   /**
00108    * Set the covariance of the Gaussian. The new covariance matrix
00109    * must have the same size as the previous one.
00110    *
00111    * @param sigma \f$\Sigma\f$; covariance of the Gaussian.
00112    */
00113   virtual void setCovariance(const symmetric_matrix& sigma);
00114 
00115   /**
00116    * Sample from the Gaussian.
00117    *
00118    * @li Let \f$\mathbf{z}\f$ be a vector of \f$N\f$ independent
00119    * normal variates.
00120    * @li Then the sample is \f$\mathbf{x} = \mathbf{\mu} +
00121    * L\mathbf{z}\f$, where \f$L\f$ is the Cholesky decomposition of
00122    * the covariance matrix \f$\Sigma\f$.
00123    *
00124    * @return The sample \f$\mathbf{x}\f$
00125    */
00126   virtual vector sample();
00127 
00128   /**
00129    * @deprecated Use densityAt() instead.
00130    */
00131   double calculateDensity(const vector& x);
00132 
00133   /**
00134    * Calculate the density at a given point.
00135    *
00136    * \f[p(\mathbf{x}) = \frac{1}{\sqrt{(2\pi)^N|\Sigma|}}
00137    *   \exp\big({-\frac{1}{2}(\mathbf{x}-\mathbf{\mu})^T \Sigma^{-1} 
00138    *   (\mathbf{x}-\mathbf{\mu})\big)}
00139    * \f]
00140    *
00141    * @param x \f$\mathbf{x}\f$; point at which to evaluate the
00142    * density.
00143    *
00144    * @return \f$p(\mathbf{x})\f$; the density at \f$\mathbf{x}\f$.
00145    */
00146   virtual double densityAt(const vector& x);
00147 
00148 protected:
00149   /**
00150    * Called when changes are made to the distribution, such as when
00151    * the expectation or covariance is changed. This allows
00152    * pre-calculations to be refreshed.
00153    */
00154   virtual void dirty();
00155 
00156 private:
00157   /**
00158    * \f$\mu\f$; mean of the distribution.
00159    */
00160   vector mu;
00161 
00162   /**
00163    * \f$\Sigma\f$; covariance of the distribution.
00164    */
00165   symmetric_matrix sigma;
00166 
00167   /**
00168    * \f$L\f$ where \f$\Sigma = LL^T\f$ is the Cholesky decomposition
00169    * of the covariance matrix.
00170    */
00171   lower_triangular_matrix L;
00172 
00173   /**
00174    * \f$\Sigma^{-1}\f$
00175    */
00176   symmetric_matrix sigmaI;
00177 
00178   /**
00179    * Diagonal of \f$\Sigma^{-1}\f$.
00180    */
00181   vector sigmaIDiag;
00182 
00183   /**
00184    * \f$\det(\Sigma)\f$
00185    */
00186   double sigmaDet;
00187 
00188   /**
00189    * \f$\frac{1}{Z}\f$
00190    */
00191   double ZI;
00192 
00193   /**
00194    * Is the expectation zero?
00195    */
00196   bool isMuZero;
00197 
00198   /**
00199    * Is the covariance matrix diagonal?
00200    */
00201   bool isSigmaIDiagonal;
00202 
00203   /**
00204    * Has the Cholesky decomposition of the covariance matrix been computed?
00205    */
00206   bool haveCholesky;
00207 
00208   /**
00209    * Has the inverse of the covariance matrix been computed?
00210    */
00211   bool haveInverse;
00212 
00213   /**
00214    * Has the determinant of the covariance matrix been computed?
00215    */
00216   bool haveDeterminant;
00217 
00218   /**
00219    * Has the normalising constant for the density function been
00220    * computed?
00221    */
00222   bool haveZ;
00223 
00224   /**
00225    * Have optimisations for density calculations been determined?
00226    */
00227   bool haveDensityOptimisations;
00228 
00229   /**
00230    * Calculate the Cholesky decomposition of the covariance matrix.
00231    */
00232   void calculateCholesky();
00233 
00234   /**
00235    * Calculate the inverse of the covariance matrix. This exploits the
00236    * calculation of the Cholesky decomposition
00237    */
00238   void calculateInverse();
00239 
00240   /**
00241    * Calculate the determinant of the covariance matrix,
00242    * \f$|\Sigma|\f$. This exploits the calculation of the Cholesky
00243    * decomposition \f$L\f$. For any matrices \f$A\f$ and \f$B\f$,
00244    * \f$|AB| = |A||B|\f$. Given that \f$\Sigma = LL^T\f$, \f$|\Sigma|
00245    * = |L|^2\f$. The determinant of a triangular matrix is simply the
00246    * product of the elements on its diagonal, so \f$|L|\f$ is easy to
00247    * calculate.
00248    */
00249   void calculateDeterminant();
00250 
00251   /**
00252    * Calculate the normalising constant \f$\frac{1}{Z}\f$ for the
00253    * density function.
00254    *
00255    * \f[Z = \sqrt{(2\pi)^N|\Sigma|}\f]
00256    */
00257   void calculateZ();
00258 
00259   /**
00260    * Calculate optimisations for the calculation of densities.
00261    */
00262   void calculateDensityOptimisations();
00263 
00264   /**
00265    * Serialize.
00266    */
00267   template<class Archive>
00268   void save(Archive& ar, const unsigned int version) const;
00269 
00270   /**
00271    * Restore from serialization.
00272    */
00273   template<class Archive>
00274   void load(Archive& ar, const unsigned int version);
00275 
00276   /*
00277    * Boost.Serialization requirements.
00278    */
00279   BOOST_SERIALIZATION_SPLIT_MEMBER()
00280   friend class boost::serialization::access;
00281 
00282 };
00283 
00284     }
00285   }
00286 }
00287 
00288 #include "boost/serialization/base_object.hpp"
00289 
00290 template<class Archive>
00291 void indii::ml::aux::GaussianPdf::save(Archive& ar,
00292     const unsigned int version) const {
00293   ar & boost::serialization::base_object<Pdf>(*this);
00294   ar & mu;
00295 
00296   /* serialization of symmetric_matrix not yet supported in ublas */
00297   const aux::matrix tmp(sigma);
00298   ar & tmp;
00299 }
00300 
00301 template<class Archive>
00302 void indii::ml::aux::GaussianPdf::load(Archive& ar,
00303     const unsigned int version) {
00304   ar & boost::serialization::base_object<Pdf>(*this);
00305 
00306   mu.resize(N, false);
00307   sigma.resize(N, false);
00308   L.resize(N,N, false);
00309   sigmaI.resize(N, false);
00310   sigmaIDiag.resize(N, false);
00311 
00312   ar & mu;
00313 
00314   /* serialization of symmetric_matrix not yet supported in ublas */
00315   aux::matrix tmp(N,N);
00316   ar & tmp;
00317   noalias(sigma) = boost::numeric::ublas::symmetric_adaptor<aux::matrix>(tmp);
00318 
00319   haveCholesky = false;
00320   haveInverse = false;
00321   haveDeterminant = false;
00322   haveZ = false;
00323   haveDensityOptimisations = false;
00324 }
00325 
00326 #endif

Generated on Wed Dec 17 15:11:57 2008 for dysii Dynamical Systems Library by  doxygen 1.5.3