added kullback leibler for gaussian cases

This commit is contained in:
toni
2017-03-09 18:57:47 +01:00
parent 62087fe072
commit e48d3bafcd
9 changed files with 374 additions and 8 deletions

View File

@@ -8,5 +8,6 @@
#include "distribution/VonMises.h"
#include "distribution/Region.h"
#include "distribution/Triangle.h"
#include "distribution/NormalN.h"
#endif // DISTRIBUTIONS_H

View File

@@ -44,6 +44,15 @@ namespace Distribution {
gen.seed(seed);
}
/** get the mean value */
const T getMu() {
return this->mu;
}
/** get the standard deviation */
const T getSigma() {
return this->sigma;
}
/** get the probability for the given value */
static T getProbability(const T mu, const T sigma, const T val) {

View File

@@ -0,0 +1,50 @@
#ifndef NORMALN_H
#define NORMALN_H
#include <eigen3/Eigen/Dense>
namespace Distribution {
class NormalDistributionN {
private:
const Eigen::VectorXd mu;
const Eigen::MatrixXd sigma;
const double _a;
const Eigen::MatrixXd _sigmaInv;
public:
/** ctor */
NormalDistributionN(const Eigen::VectorXd mu, const Eigen::MatrixXd sigma) :
mu(mu), sigma(sigma), _a( 1.0 / std::sqrt( (sigma * 2.0 * M_PI).determinant() ) ), _sigmaInv(sigma.inverse()) {
}
/** get probability for the given value */
double getProbability(const Eigen::VectorXd val) const {
const double b = ((val-mu).transpose() * _sigmaInv * (val-mu));
return _a * std::exp(-b/2.0);
}
/** get the mean vector */
const Eigen::VectorXd getMu(){
return this->mu;
}
/** get covariance matrix */
const Eigen::MatrixXd getSigma(){
return this->sigma;
}
const Eigen::MatrixXd getSigmaInv(){
return this->_sigmaInv;
}
};
}
#endif // NORMALN_H

View File

@@ -0,0 +1,90 @@
#ifndef KULLBACKLEIBLER_H
#define KULLBACKLEIBLER_H
#include "../distribution/Normal.h"
#include "../distribution/NormalN.h"
#include "../../Assertions.h"
#include <string>
namespace Divergence {
template <typename Scalar> class KullbackLeibler {
public:
/** Calculate the Kullback Leibler Distance for a univariate Gaussian distribution
* Info: https://tgmstat.wordpress.com/2013/07/10/kullback-leibler-divergence/
*/
static inline Scalar getUnivariateGauss(Distribution::Normal<Scalar> norm1, Distribution::Normal<Scalar> norm2){
auto sigma1Quad = norm1.getSigma() * norm1.getSigma();
auto sigma2Quad = norm2.getSigma() * norm2.getSigma();
auto mu12Quad = (norm1.getMu() - norm2.getMu()) * (norm1.getMu() - norm2.getMu());
auto log1 = std::log(norm1.getSigma());
auto log2 = std::log(norm2.getSigma());
// kl = log(sigma_2 / sigma_1) + ((sigma_1^2 + (mu_1 - mu_2)^2) / 2 * sigma_2^2) - 0.5
double klb = (log2 - log1) + ((sigma1Quad + mu12Quad)/(2.0 * sigma2Quad)) - 0.5;
//klb is always greater 0
if(klb < 0.0){
Assert::doThrow("The Kullback Leibler Distance is < 0! Thats not possible");
}
return klb;
}
/** Calculate the Kullback Leibler Distance for a univariate Gaussian distribution symmetric*/
static inline Scalar getUnivariateGaussSymmetric(Distribution::Normal<Scalar> norm1, Distribution::Normal<Scalar> norm2){
return getUnivariateGauss(norm1, norm2) + getUnivariateGauss(norm2, norm1);
}
/** Calculate the Kullback Leibler Distance for a multivariate Gaussian distribution */
static inline Scalar getMultivariateGauss(Distribution::NormalDistributionN norm1, Distribution::NormalDistributionN norm2){
//both gaussian have the same dimension.
Assert::equal(norm1.getMu().rows(), norm2.getMu().rows(), "mean vectors do not have the same dimension");
Assert::equal(norm1.getSigma().rows(), norm2.getSigma().rows(), "cov matrices do not have the same dimension");
Assert::equal(norm1.getSigma().cols(), norm2.getSigma().cols(), "cov matrices do not have the same dimension");
//log
auto det1 = norm1.getSigma().determinant();
auto det2 = norm2.getSigma().determinant();
auto log1 = std::log(det1);
auto log2 = std::log(det2);
//trace
Eigen::MatrixXd toTrace(norm1.getSigma().rows(),norm1.getSigma().cols());
toTrace = norm2.getSigmaInv() * norm1.getSigma();
auto trace = toTrace.trace();
//transpose
Eigen::VectorXd toTranspose(norm1.getMu().rows());
toTranspose = norm2.getMu() - norm1.getMu();
auto transpose = toTranspose.transpose();
//rawdensity
auto rawDensity = transpose * norm2.getSigmaInv() * toTranspose;
auto dimension = norm1.getMu().rows();
//0.5 * ((log(det(cov_2)/det(cov_1)) + tr(cov_2^-1 cov_1) + (mu_2 - mu_1)^T * cov_2^-1 * (mu_2 - mu_1) - dimension)
double klb = 0.5 * ((log2 - log1) + trace + rawDensity - dimension);
//klb is always greater 0
if(klb < 0.0){
Assert::doThrow("The Kullback Leibler Distance is < 0! Thats not possible");
}
return klb;
}
/** Calculate the Kullback Leibler Distance for a multivariate Gaussian distribution symmetric*/
static inline Scalar getMultivariateGaussSymmetric(Distribution::NormalDistributionN norm1, Distribution::NormalDistributionN norm2){
return getMultivariateGauss(norm1, norm2) + getMultivariateGauss(norm2, norm1);
}
};
}
#endif // KULLBACKLEIBLER_H