|
STK++ 1.0
|
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 */