STK++ 1.0
STK_Law_MultivariateNormal.h
Go to the documentation of this file.
00001 /*--------------------------------------------------------------------*/
00002 /*     Copyright (C) 2004-2011  Serge Iovleff
00003 
00004  This program is free software; you can redistribute it and/or modify
00005  it under the terms of the GNU Lesser General Public License as
00006  published by the Free Software Foundation; either version 2 of the
00007  License, or (at your option) any later version.
00008 
00009  This program is distributed in the hope that it will be useful,
00010  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  GNU Lesser General Public License for more details.
00013 
00014  You should have received a copy of the GNU Lesser General Public
00015  License along with this program; if not, write to the
00016  Free Software Foundation, Inc.,
00017  59 Temple Place,
00018  Suite 330,
00019  Boston, MA 02111-1307
00020  USA
00021 
00022  Contact : Serge.Iovleff@stkpp.org
00023  */
00024 
00025 /*
00026  * Project:  stkpp::STatistiK::Law
00027  * created on: 29 juil. 2011
00028  * Purpose:  define the templated MultivariateNormal law.
00029  * Author:   iovleff, serge.iovleff@stkpp.org
00030  *
00031  **/
00032 
00037 #ifndef STK_MUTIVARIATENORMAL_H
00038 #define STK_MUTIVARIATENORMAL_H
00039 
00040 #include "STK_Law_ITMultivariate.h"
00041 #include "STK_Law_Normal.h"
00042 
00043 #include "../../Algebra/include/STK_EigenvaluesSymmetric.h"
00044 
00045 #include "../include/STK_Const_Math.h"
00046 
00047 #include "../../Algebra/include/STK_LinAlgebra1D.h"
00048 #include "../../Algebra/include/STK_LinAlgebra2D.h"
00049 
00050 namespace STK
00051 {
00052 
00053 namespace Law
00054 {
00055 
00089 template <class Container1D>
00090 class MultivariateNormal: public ITMultivariate<Real, Container1D>
00091 {
00092   public:
00097     MultivariateNormal( Container1D const& mu, MatrixSquare const& sigma)
00098                       : ITMultivariate<Real, Container1D>(_T("Normal Multivariate"))
00099                       , mu_(mu)
00100                       , sigma_(sigma)
00101                       , decomp_(&sigma_)
00102                       , invEigenvalues_(mu_.range())
00103                       , squareroot_(sigma_.range())
00104     { update();}
00105 
00107     virtual ~MultivariateNormal() { ;}
00108 
00112     inline Container1D const& mu() { return mu_;}
00116     inline MatrixSquare const& sigma() { return sigma_;}
00120     inline EigenvaluesSymmetric const& decomp() { return decomp_;}
00122     virtual void update()
00123     {
00124       // check dimensions
00125       if (mu_.range() != sigma_.range())
00126       { throw runtime_error(_T("In MultivariateNormal::MultivariateNormal(mu, sigma) "
00127                                "mu_.range() != sigma_.range().\n"));
00128       }
00129       // decomposition of the covariance matrix
00130       if (!decomp_.run())
00131       { throw runtime_error(_T("In MultivariateNormal::MultivariateNormal(mu, sigma) "
00132                                "decomposition of sigma fail.\n"));
00133       }
00134       // compute the inverse of the eigenvalues of sigma_ and the squareroot_
00135       // matrix needed by rand
00136       invEigenvalues_.resize(mu_.range());
00137       squareroot_.resize(mu_.range());
00138       // get dimension
00139       Integer first = mu_.first(), rank = decomp_.rank(), last = first + rank -1;
00140       for (Integer j=first; j<= last; j++)
00141       {
00142         invEigenvalues_[j] = 1./decomp_.eigenvalues()[j];
00143         Real squareRoot = sqrt((double)decomp_.eigenvalues()[j]);
00144         for (Integer i= first; i <= last; ++i)
00145         {
00146           squareroot_(i,j) = decomp_.rotation()(i,j)*squareRoot;
00147         }
00148       }
00149       first = last+1; last = mu_.last();
00150       for (Integer j=first; j<= last; j++)
00151       {
00152         invEigenvalues_[j] = 0.;
00153         Real squareRoot = sqrt((double)decomp_.eigenvalues()[j]);
00154         for (Integer i= first; i <= last; ++i)
00155         {
00156           squareroot_(i,j) = decomp_.rotation()(i,j)*squareRoot;
00157         }
00158       }
00159     }
00170     virtual Real pdf( ITContainer1D<Real, Container1D> const& x) const
00171     {
00172       // check determinant is not 0
00173       if (decomp_.det() == 0.)
00174       { throw runtime_error("In MultivariateNormal::pdf(x) "
00175                                  "|sigma| == 0.\n"
00176                                  );
00177       }
00178       // check ranges
00179       if (x.range() != mu_.range() )
00180       {
00181         throw runtime_error("In MultivariateNormal::pdf(x)"
00182                                  "x.range() != mu_.range()\n"
00183                                 );
00184       }
00185       return exp((double)lpdf(x));
00186     }
00187 
00193     Real lpdf( ITContainer1D<Real, Container1D> const& x) const
00194     {
00195       // check ranges
00196       if (x.range() != mu_.range() )
00197       {
00198         throw runtime_error(_T("In MultivariateNormal::pdf(x)"
00199                                "x.range() != mu_.range()\n"));
00200       }
00201       // compute x - mu
00202       Vector xbar;
00203       diff(x, mu_, xbar);
00204       // compute P'(x-mu)
00205       Vector xrot;
00206       multLeftTranspose(decomp_.rotation(), xbar, xrot);
00207       // compute pdf using (x-mu)'PD^{-1}P'(x-mu)
00208       Real res = 0.5 * weightedNormTwo2<Vector, Vector>(xrot, invEigenvalues_)
00209                + invEigenvalues_.size() * Const::_LNSQRT2PI_
00210                + 0.5 * log((double)decomp_.det());
00211       return -res;
00212     }
00213 
00219     template < class TContainer2D>
00220     Real logLikelihood( TContainer2D const& data) const
00221     {
00222       // check ranges
00223       if (data.rangeHo() != mu_.range() )
00224       {
00225         throw runtime_error(_T("Error in n MultivariateNormal::logLikehood(x)\nWhat: "
00226                                "data.rangeHo() != mu_.range()\n"));
00227       }
00228 
00229       // compute x - mu
00230       Vector xres(mu_.range()), xrot(mu_.range());
00231       // get dimensions of the samples and sum over all log-likelihood values
00232       const Integer first = data.firstRow(), last = data.lastRow();
00233       Real sum = 0.0;
00234       for (Integer i=first; i<= last; i++)
00235       {
00236         // compute residual
00237         xres = data(i) - mu_;
00238         // compute P'(x-mu)
00239         multLeftTranspose(decomp_.rotation(), xres, xrot);
00240         // compute lpdf using (x-mu)'PD^{-1}P'(x-mu)
00241         Real res = 0.5 * weightedNormTwo2(xrot, invEigenvalues_);
00242         sum += res;
00243       }
00244       sum += data.sizeVe()*( invEigenvalues_.size() * Const::_LNSQRT2PI_
00245                            + 0.5 * log((double)decomp_.det())
00246                            );
00247       return -sum;
00248     }
00249 
00254     virtual void rand( ITContainer1D<Real, Container1D>& x) const
00255     {
00256       // create intermediary container
00257       Container1D x_iid(x.range());
00258       // fill it with iid N(0,1) variates
00259       Normal(0., 1.).rand1D<Container1D>(x_iid);
00260       // rotate with squareroot_
00261       mult(squareroot_, x_iid, x);
00262       // translate with mu_
00263       x.asLeaf() += mu_;
00264     }
00270     virtual void rand( ITContainer1D<Real, Container1D> const& x) const
00271     {
00272       // create intermediary container
00273       Container1D x_iid(x.range());
00274       // create intermediary reference container
00275       Container1D x_ref(x.asLeaf(), true);
00276       // fill it with iid N(0,1) variates
00277       Normal(0., 1.).rand1D<Container1D>(x_iid);
00278       // rotate with squareroot_
00279       mult(squareroot_, x_iid, x_ref);
00280       // translate with mu_
00281       x_ref += mu_;
00282     }
00283 
00284   protected:
00286     Container1D mu_;
00288     MatrixSquare sigma_;
00290     EigenvaluesSymmetric decomp_;
00292     Vector invEigenvalues_;
00294     MatrixSquare squareroot_;
00295 };
00296 
00297 } // namespace Law
00298 
00299 } // namespace STK
00300 
00301 #endif /* STK_MUTIVARIATENORMAL_H */