indii/ml/aux/StandardMixturePdf.hpp

00001 #ifndef INDII_ML_AUX_STANDARDMIXTUREPDF_HPP
00002 #define INDII_ML_AUX_STANDARDMIXTUREPDF_HPP
00003 
00004 #include "MixturePdf.hpp"
00005 
00006 namespace indii {
00007   namespace ml {
00008     namespace aux {
00009 /**
00010  * Mixture probability density with standard calculation of covariance.
00011  *
00012  * @author Lawrence Murray <lawrence@indii.org>
00013  * @version $Rev: 564 $
00014  * @date $Date: 2008-09-12 16:35:34 +0100 (Fri, 12 Sep 2008) $
00015  *
00016  * @param T Component type, should be derivative of Pdf.
00017  *
00018  * @see MixturePdf for more information regarding the serialization
00019  * and parallelisation features of this class.
00020  */
00021 template <class T>
00022 class StandardMixturePdf : public MixturePdf<T> {
00023 public:
00024   /**
00025    * Default constructor.
00026    *
00027    * Initialises the mixture with zero dimensions. This should
00028    * generally only be used when the object is to be restored from a
00029    * serialization. Indeed, there is no other way to resize the
00030    * mixture to nonzero dimensionality except by subsequently
00031    * restoring from a serialization.
00032    */
00033   StandardMixturePdf();
00034 
00035   /**
00036    * Constructor. One or more components should be added with
00037    * add() after construction.
00038    *
00039    * @param N Dimensionality of the distribution.
00040    */
00041   StandardMixturePdf(const unsigned int N);
00042 
00043   /**
00044    * Constructor.
00045    *
00046    * @param x The first component.
00047    * @param w Unnormalised weight of the component.
00048    *
00049    * This is particularly useful for creating single component
00050    * mixtures of any type for parallel environments.
00051    */
00052   StandardMixturePdf(const T& x, const double w = 1.0);
00053 
00054   /**
00055    * Destructor.
00056    */
00057   virtual ~StandardMixturePdf();
00058 
00059   virtual void setDimensions(const unsigned int N,
00060       const bool preserve = false);
00061 
00062   /**
00063    * Get the covariance of the distribution. The covariance is defined
00064    * as:
00065    *
00066    * \f[ \frac{1}{W}\sum_{i=1}^{K} w^{(i)}(\Sigma^{(i)} +
00067    * \mathbf{\mu}^{(i)} (\mathbf{\mu}^{(i)})^{T}) -
00068    * \mathbf{\mu}\mathbf{\mu}^{T} \f]
00069    *
00070    * where \f$\mathbf{\mu}^{(i)}\f$, \f$\Sigma^{(i)}\f$ and
00071    * \f$w^{(i)}\f$ are the mean, covariance and weight of the
00072    * \f$i\f$th component, respectively, and \f$\mathbf{\mu}\f$ the
00073    * overall mean.
00074    *
00075    * @return \f$\Sigma\f$; covariance of the distribution.
00076    */
00077   virtual const symmetric_matrix& getCovariance();
00078 
00079   /**
00080    * Get the covariance of the full distribution.
00081    *
00082    * @return \f$\Sigma\f$; covariance of the full distribution.
00083    */
00084   symmetric_matrix getDistributedCovariance();
00085 
00086 protected:
00087   virtual void dirty();
00088 
00089 private:
00090   /**
00091    * Last calculated covariance.
00092    */
00093   symmetric_matrix sigma;
00094 
00095   /**
00096    * Last calculated unnormalized covariance.
00097    */
00098   symmetric_matrix Zsigma;
00099 
00100   /**
00101    * Is the last calculated covariance up to date?
00102    */
00103   bool haveSigma;
00104 
00105   /**
00106    * Calculate covariance from current components.
00107    *
00108    * The covariance is calculated as:
00109    *
00110    * \f[\Sigma =
00111    * \frac{1}{W}\sum_{i=1}^{K}w_i(\Sigma_i+\mathbf{\mu}_i\mathbf{\mu}_i^T)
00112    * - \bar{\mathbf{\mu}}\bar{\mathbf{\mu}}^T
00113    * \f]
00114    *
00115    * where \f$\mathbf{\mu}_i\f$ and \f$\Sigma_i\f$ are the mean and
00116    * covariance of the \f$i\f$th component, respectively, and
00117    * \f$\bar{\mathbf{\mu}}\f$ is the mean of means.
00118    */
00119   void calculateCovariance();
00120 
00121   /**
00122    * Serialize.
00123    */
00124   template<class Archive>
00125   void save(Archive& ar, const unsigned int version) const;
00126 
00127   /**
00128    * Restore from serialization.
00129    */
00130   template<class Archive>
00131   void load(Archive& ar, const unsigned int version);
00132 
00133   /*
00134    * Boost.Serialization requirements.
00135    */
00136   BOOST_SERIALIZATION_SPLIT_MEMBER()
00137   friend class boost::serialization::access;
00138 
00139 };
00140 
00141     }
00142   }
00143 }
00144 
00145 #include "boost/serialization/base_object.hpp"
00146 
00147 namespace ublas = boost::numeric::ublas;
00148 
00149 template <class T>
00150 indii::ml::aux::StandardMixturePdf<T>::StandardMixturePdf() :
00151     indii::ml::aux::MixturePdf<T>(0), sigma(0), Zsigma(0) {
00152   haveSigma = false;
00153 }
00154 
00155 template <class T>
00156 indii::ml::aux::StandardMixturePdf<T>::StandardMixturePdf(
00157     const unsigned int N) : indii::ml::aux::MixturePdf<T>(N), sigma(N),
00158     Zsigma(N) {
00159   haveSigma = false;
00160 }
00161 
00162 template <class T>
00163 indii::ml::aux::StandardMixturePdf<T>::StandardMixturePdf(const T& x,
00164     const double w) : indii::ml::aux::MixturePdf<T>(x.getDimensions()),
00165     sigma(x.getDimensions()), Zsigma(x.getDimensions()) {
00166   haveSigma = false;
00167   add(x, w);
00168 }
00169 
00170 template <class T>
00171 indii::ml::aux::StandardMixturePdf<T>::~StandardMixturePdf() {
00172   //
00173 }
00174 
00175 template <class T>
00176 void indii::ml::aux::StandardMixturePdf<T>::setDimensions(
00177     const unsigned int N, const bool preserve) {
00178   MixturePdf<T>::setDimensions(N, preserve);
00179 
00180   Zsigma.resize(N, preserve);
00181   sigma.resize(N, preserve);
00182 }
00183 
00184 template <class T>
00185 const indii::ml::aux::symmetric_matrix& indii::ml::aux::StandardMixturePdf<
00186     T>::getCovariance() {
00187   if (!haveSigma) {
00188     calculateCovariance();
00189   }
00190   return sigma;
00191 }
00192 
00193 template <class T>
00194 indii::ml::aux::symmetric_matrix indii::ml::aux::StandardMixturePdf<
00195     T>::getDistributedCovariance() {
00196   boost::mpi::communicator world;
00197   const unsigned int size = world.size();
00198   
00199   if (size == 0) {
00200     return getCovariance();
00201   } else {
00202     const unsigned int N = this->getDimensions();
00203 
00204     boost::mpi::communicator world;
00205     matrix Zsigma_d(N,N), sigma_d(N,N);
00206     vector mu_d(N);
00207 
00208     if (this->getTotalWeight() > 0.0) {
00209       if (!haveSigma) {
00210         calculateCovariance();
00211       }
00212     } else {
00213       Zsigma.clear();
00214     }
00215 
00216     noalias(mu_d) = this->getDistributedExpectation();
00217     noalias(Zsigma_d) = boost::mpi::all_reduce(world, matrix(Zsigma),
00218         std::plus<matrix>());
00219     noalias(sigma_d) = Zsigma_d / this->getDistributedTotalWeight() -
00220         outer_prod(mu_d, mu_d);
00221 
00222     return ublas::symmetric_adaptor<matrix, ublas::lower>(sigma_d);
00223   }
00224 }
00225 
00226 template <class T>
00227 void indii::ml::aux::StandardMixturePdf<T>::dirty() {
00228   MixturePdf<T>::dirty();
00229   haveSigma = false;
00230 }
00231 
00232 template <class T>
00233 void indii::ml::aux::StandardMixturePdf<T>::calculateCovariance() {
00234   /* pre-condition */
00235   assert (this->getTotalWeight() > 0.0);
00236 
00237   double w;
00238   const vector& mu = this->getExpectation();
00239   unsigned int i;
00240 
00241   Zsigma.clear();
00242   for (i = 0; i < this->getSize(); i++) {
00243     w = this->getWeight(i);
00244     const vector& mu_i = this->get(i).getExpectation();
00245     const symmetric_matrix& sigma_i = this->get(i).getCovariance();
00246 
00247     noalias(Zsigma) += w * (sigma_i + outer_prod(mu_i, mu_i));
00248   }
00249   noalias(sigma) = Zsigma / this->getTotalWeight() - outer_prod(mu, mu);
00250   haveSigma = true;
00251 }
00252 
00253 template <class T>
00254 template <class Archive>
00255 void indii::ml::aux::StandardMixturePdf<T>::save(Archive& ar,
00256     const unsigned int version) const {
00257   ar & boost::serialization::base_object<
00258       indii::ml::aux::MixturePdf<T> >(*this);
00259 }
00260 
00261 template <class T>
00262 template <class Archive>
00263 void indii::ml::aux::StandardMixturePdf<T>::load(Archive& ar,
00264     const unsigned int version) {
00265   ar & boost::serialization::base_object<
00266       indii::ml::aux::MixturePdf<T> >(*this);
00267 
00268   sigma.resize(this->getDimensions(), false);
00269   Zsigma.resize(this->getDimensions(), false);
00270   haveSigma = false;
00271 }
00272 
00273 #endif
00274 

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