00001
00014 #ifndef _DLR_GAUSSIANDISTRIBUTION_H_
00015 #define _DLR_GAUSSIANDISTRIBUTION_H_
00016
00017 #include <iostream>
00018 #include <string>
00019 #include <dlrNumeric/array1D.h>
00020 #include <dlrNumeric/array2D.h>
00021
00022 namespace dlr {
00023
00047 template <class VectorType>
00048 class GaussianDistribution {
00049 public:
00050
00051
00057 typedef VectorType vector_type;
00058
00059
00060
00064 GaussianDistribution();
00065
00066
00074 GaussianDistribution(const Array1D<double>& mean,
00075 const Array2D<double>& covariance);
00076
00077
00083 GaussianDistribution(const GaussianDistribution<VectorType> &source);
00084
00085
00090 ~GaussianDistribution();
00091
00092
00101 inline void
00102 addSample(const VectorType& point);
00103
00104
00115 inline size_t
00116 getCardinality() const {return m_sampleData.size();}
00117
00118
00127 inline const Array2D<double>&
00128 getCovariance() const;
00129
00130
00139 inline const Array1D<double>&
00140 getMean() const;
00141
00142
00156 void
00157 setSampleData(const std::vector<VectorType>& sampleData);
00158
00159
00178 double
00179 operator()(const VectorType& x) const;
00180
00181
00190 GaussianDistribution<VectorType>&
00191 operator=(const GaussianDistribution<VectorType>& source);
00192
00193 private:
00194
00195
00202 void
00203 computeSecondaryStatistics();
00204
00205
00213 void
00214 computeStatistics();
00215
00216
00230 inline void
00231 lazyEvaluationFunction() const;
00232
00233
00234
00235
00236 Array2D<double> m_covariance;
00237 Array2D<double> m_inverseCovariance;
00238 Array1D<double> m_mean;
00239 bool m_mutable;
00240 bool m_needsUpdate;
00241 std::vector<VectorType> m_sampleData;
00242 double m_scalingConstant;
00243 };
00244
00245
00246
00247
00248
00249 };
00250
00251
00252
00253
00254
00255
00256
00257 #include <cmath>
00258 #include <sstream>
00259 #include <vector>
00260 #include <dlrCommon/exception.h>
00261 #include <dlrNumeric/numericTraits.h>
00262 #include <dlrNumeric/utilities.h>
00263 #include <dlrLinearAlgebra/linearAlgebra.h>
00264
00265 namespace dlr {
00266
00267
00268 template <class VectorType>
00269 GaussianDistribution<VectorType>::
00270 GaussianDistribution()
00271 : m_covariance(),
00272 m_inverseCovariance(),
00273 m_mean(),
00274 m_mutable(true),
00275 m_needsUpdate(true),
00276 m_sampleData(),
00277 m_scalingConstant(0.0)
00278 {
00279
00280 }
00281
00282
00283 template <class VectorType>
00284 GaussianDistribution<VectorType>::
00285 GaussianDistribution(const Array1D<double>& mean,
00286 const Array2D<double>& covariance)
00287 : m_covariance(covariance.copy()),
00288 m_inverseCovariance(),
00289 m_mean(mean.copy()),
00290 m_mutable(false),
00291 m_needsUpdate(false),
00292 m_sampleData(),
00293 m_scalingConstant(0.0)
00294 {
00295 this->computeSecondaryStatistics();
00296 }
00297
00298
00299 template <class VectorType>
00300 GaussianDistribution<VectorType>::
00301 GaussianDistribution(const GaussianDistribution<VectorType> &source)
00302 : m_covariance(source.m_covariance.copy()),
00303 m_inverseCovariance(source.m_inverseCovariance.copy()),
00304 m_mean(source.m_mean.copy()),
00305 m_mutable(source.m_mutable),
00306 m_needsUpdate(source.m_needsUpdate),
00307 m_sampleData(source.m_sampleData),
00308 m_scalingConstant(source.m_scalingConstant)
00309
00310 {
00311
00312 }
00313
00314
00315
00316 template <class VectorType>
00317 GaussianDistribution<VectorType>::
00318 ~GaussianDistribution()
00319 {
00320
00321 }
00322
00323
00324
00325 template <class VectorType>
00326 void
00327 GaussianDistribution<VectorType>::
00328 addSample(const VectorType& point)
00329 {
00330 if(!m_mutable) {
00331 DLR_THROW3(LogicException,
00332 "GaussianDistribution::addSample(const VectorType&)",
00333 "Attempt to add sample points when mean and covariance "
00334 "have been set explicitly.");
00335 }
00336
00337
00338 if(m_sampleData.size() == 0) {
00339
00340 if(point.size() == 0) {
00341 DLR_THROW3(ValueException,
00342 "GaussianDistribution::addSample(...)",
00343 "Sample points cannot have size == 0.");
00344 }
00345 } else {
00346
00347 if(point.size() != m_sampleData[0].size()) {
00348 std::ostringstream message;
00349 message << "Sample point should have size == "
00350 << m_sampleData[0].size() << ", but instead has size == "
00351 << point.size() << ".";
00352 DLR_THROW3(ValueException,
00353 "GaussianDistribution::addSample(...)",
00354 message.str().c_str());
00355 }
00356 }
00357
00358
00359 m_sampleData.push_back(point);
00360
00361
00362 m_needsUpdate = true;
00363 }
00364
00365
00366
00367 template <class VectorType>
00368 const Array2D<double>&
00369 GaussianDistribution<VectorType>::
00370 getCovariance() const
00371 {
00372
00373 this->lazyEvaluationFunction();
00374
00375
00376 return m_covariance;
00377 }
00378
00379
00380 template <class VectorType>
00381 const Array1D<double>&
00382 GaussianDistribution<VectorType>::
00383 getMean() const
00384 {
00385
00386 this->lazyEvaluationFunction();
00387
00388
00389 return m_mean;
00390 }
00391
00392
00393
00394 template <class VectorType>
00395 void
00396 GaussianDistribution<VectorType>::
00397 setSampleData(const std::vector<VectorType>& sampleData)
00398 {
00399 if(!m_mutable) {
00400 DLR_THROW3(LogicException,
00401 "GaussianDistribution::addSample(const VectorType&)",
00402 "Attempt to add sample points when mean and covariance "
00403 "have been set explicitly.");
00404 }
00405
00406
00407 if(sampleData.size() != 0) {
00408
00409 size_t dimensionality = sampleData[0].size();
00410 if(dimensionality == 0) {
00411 DLR_THROW3(ValueException,
00412 "GaussianDistribution::setSampleData(...)",
00413 "Sample points cannot have size == 0.");
00414 }
00415
00416 for(size_t index = 0; index < sampleData.size(); ++index) {
00417 if(sampleData[index].size() != dimensionality) {
00418 std::ostringstream message;
00419 message << "Sample point number " << index << " should have size == "
00420 << dimensionality << ", but instead has size == "
00421 << sampleData[index].size() << ".";
00422 DLR_THROW3(ValueException,
00423 "GaussianDistribution::setSampleData(...)",
00424 message.str().c_str());
00425 }
00426 }
00427 }
00428
00429
00430 m_sampleData = sampleData;
00431
00432
00433 m_needsUpdate = true;
00434 }
00435
00436
00437
00438 template <class VectorType>
00439 double
00440 GaussianDistribution<VectorType>::
00441 operator()(const VectorType& x) const
00442 {
00443
00444 this->lazyEvaluationFunction();
00445
00446
00447 if(x.size() != m_mean.size()) {
00448 std::ostringstream message;
00449 message << "Distribution has dimensionality " << m_mean.size() << ", "
00450 << "but input point has dimensionality " << x.size() << "."
00451 << std::endl;
00452 DLR_THROW3(ValueException,
00453 "GaussianDistribution::operator()(const VectorType&)",
00454 message.str().c_str());
00455 }
00456
00457
00458
00459
00460 Array1D<double> normalizedX = m_mean.copy();
00461 for(size_t index = 0; index < m_mean.size(); ++index) {
00462 normalizedX -= x[index];
00463 }
00464 Array1D<double> inverseCovarianceTimesNormalizedX =
00465 matrixMultiply(m_inverseCovariance, normalizedX);
00466 double exponent = dot(normalizedX, inverseCovarianceTimesNormalizedX);
00467
00468
00469 double returnValue = m_scalingConstant * std::exp(exponent);
00470 return returnValue;
00471 }
00472
00473
00474 template <class VectorType>
00475 GaussianDistribution<VectorType>&
00476 GaussianDistribution<VectorType>::
00477 operator=(const GaussianDistribution<VectorType>& source)
00478 {
00479 m_covariance = source.m_covariance.copy();
00480 m_inverseCovariance = source.m_inverseCovariance.copy();
00481 m_mean = source.m_mean.copy();
00482 m_mutable = source.m_mutable;
00483 m_needsUpdate = source.m_needsUpdate;
00484 m_sampleData = source.m_sampleData;
00485 m_scalingConstant = source.m_scalingConstant;
00486 return *this;
00487 }
00488
00489
00490
00491
00492 template <class VectorType>
00493 void
00494 GaussianDistribution<VectorType>::
00495 computeSecondaryStatistics()
00496 {
00497
00498
00499
00500
00501 double determinantValue = determinant(m_covariance);
00502 if(std::fabs(determinantValue) < 1.0E-10) {
00503 DLR_THROW3(StateException,
00504 "GaussianDistribution::computeSecondaryStatistics()",
00505 "Computed covariance matrix is singular. Perhaps "
00506 "more sample points are needed?");
00507 }
00508
00509
00510 m_scalingConstant =
00511 1.0 / std::sqrt(std::pow(static_cast<double>(2.0 * dlr::numeric::constants::pi),
00512 static_cast<double>(m_mean.size()))
00513 * determinantValue);
00514
00515
00516
00517 try {
00518 m_inverseCovariance = inverse(m_covariance);
00519 } catch(const ValueException&) {
00520 DLR_THROW3(RunTimeException,
00521 "GaussianDistribution::computeSecondaryStatistics()",
00522 "Something is dreadfully wrong, m_covariance has "
00523 "non-zero determinant, yet inverse(m_covariance) fails.");
00524 }
00525 }
00526
00527
00528
00529
00530 template <class VectorType>
00531 void
00532 GaussianDistribution<VectorType>::
00533 computeStatistics()
00534 {
00535
00536 if(m_sampleData.size() == 0) {
00537 DLR_THROW3(StateException,
00538 "GaussianDistribution::computeStatistics()",
00539 "Can't compute statistics since no sample points have been "
00540 "provided.");
00541 }
00542
00543
00544
00545
00546
00547
00548 size_t numberOfSamples = m_sampleData.size();
00549 size_t dimensionality = m_sampleData[0].size();
00550
00551 m_mean.reinit(dimensionality);
00552 m_mean = 0.0;
00553 m_covariance.reinit(dimensionality, dimensionality);
00554 m_covariance = 0.0;
00555 for(typename std::vector<VectorType>::iterator
00556 pointIterator = m_sampleData.begin();
00557 pointIterator != m_sampleData.end();
00558 ++pointIterator) {
00559 for(size_t index0 = 0; index0 < dimensionality; ++index0) {
00560 m_mean[index0] += (*pointIterator)[index0];
00561 for(size_t index1 = index0; index1 < dimensionality; ++index1) {
00562
00563
00564
00565 m_covariance(index0, index1) +=
00566 (*pointIterator)[index0] * (*pointIterator)[index1];
00567 }
00568 }
00569 }
00570 m_mean /= static_cast<double>(numberOfSamples);
00571
00572
00573
00574
00575 for(size_t index0 = 0; index0 < dimensionality; ++index0) {
00576 for(size_t index1 = index0; index1 < dimensionality; ++index1) {
00577
00578 m_covariance(index0, index1) -=
00579 numberOfSamples * m_mean[index0] * m_mean[index1];
00580
00581 if(index0 != index1) {
00582 m_covariance(index1, index0) = m_covariance(index0, index1);
00583 }
00584 }
00585 }
00586 m_covariance /= static_cast<double>(numberOfSamples - 1);
00587
00588
00589 this->computeSecondaryStatistics();
00590 }
00591
00592
00593 template <class VectorType>
00594 void
00595 GaussianDistribution<VectorType>::
00596 lazyEvaluationFunction() const
00597 {
00598 if(m_needsUpdate) {
00599
00600 const_cast<GaussianDistribution<VectorType>*>(this)->computeStatistics();
00601 }
00602 }
00603
00604
00605 };
00606
00607 #endif // #ifdef _DLR_GAUSSIANDISTRIBUTION_H_
00608