Documentation
This repository contains a small, simple and efficient module, implementing various Kullback-Leibler divergences for parametric 1D continuous or discrete distributions. For more information, see the homepage on GitHub.
Index
KullbackLeibler.KLKullbackLeibler.klBernKullbackLeibler.klBinKullbackLeibler.klExpKullbackLeibler.klGammaKullbackLeibler.klGaussKullbackLeibler.klNegBinKullbackLeibler.klPoissonKullbackLeibler.klucbKullbackLeibler.klucbBernKullbackLeibler.klucbExpKullbackLeibler.klucbGammaKullbackLeibler.klucbGaussKullbackLeibler.klucbPoisson
Kullback-Leibler divergences
Generic interface for
Distributionsobjects:
KullbackLeibler.KL — Method.function KL( D1, D2 )Common function to compute the Kullback-Leibler for some continuous and discrete 1D parametric distributions (of module Distributions).
See doc for continuous distributions and doc for discrete distributions.
Currently supported: Bernoulli, Binomial, Poisson, NegativeBinomial (discrete) and Exponential, Gamma, Gaussian (continuous).
Examples:
Bernoulli:
julia> Bern1 = Distributions.Bernoulli(0.33)
Distributions.Bernoulli{Float64}(p=0.33)
julia> Bern2 = Distributions.Bernoulli(0.42)
Distributions.Bernoulli{Float64}(p=0.42)
julia> ex_kl_1 = KL( Bern1, Bern2 ) # Calc KL divergence for Bernoulli R.V
0.017063...
julia> klBern(0.33, 0.42) # same!
0.017063...Binomial:
julia> Bin1 = Distributions.Binomial(13, 0.33)
Distributions.Binomial{Float64}(n=13, p=0.33)
julia> Bin2 = Distributions.Binomial(13, 0.42) # must have same parameter n
Distributions.Binomial{Float64}(n=13, p=0.42)
julia> ex_kl_2 = KL( Bin1, Bin2 ) # Calc KL divergence for Binomial R.V
0.221828...Poisson:
julia> Pois1 = Distributions.Poisson(0.33)
Distributions.Poisson{Float64}(λ=0.33)
julia> Pois2 = Distributions.Poisson(0.92)
Distributions.Poisson{Float64}(λ=0.92)
julia> ex_kl_3 = KL( Pois1, Pois2 ) # Calc KL divergence for Poisson R.V
0.251657Exponential:
julia> Exp1 = Distributions.Exponential( 0.33 )
Distributions.Exponential{Float64}(θ=0.33)
julia> Exp2 = Distributions.Exponential( 0.42 )
Distributions.Exponential{Float64}(θ=0.42)
julia> ex_kl_4 = KL( Exp1, Exp2 ) # Calc KL div for Exponential R.V
0.0268763Gamma:
julia> Gam1 = Distributions.Gamma(0.5, 0.33)
Distributions.Gamma{Float64}(α=0.5, θ=0.33)
julia> Gam2 = Distributions.Gamma(0.5, 0.42) # must have same parameter α
Distributions.Gamma{Float64}(α=0.5, θ=0.42)
julia> ex_kl_5 = KL( Gam1, Gam2 ) # Calc KL divergence for Gamma R.V
0.0134381NegativeBinomial:
julia> NegBin1 = Distributions.NegativeBinomial(40, 0.33)
Distributions.NegativeBinomial{Float64}(r=40, p=0.33)
julia> NegBin2 = Distributions.NegativeBinomial(40, 0.99) # must have same parameter r
Distributions.NegativeBinomial{Float64}(r=40, p=0.99)
julia> ex_kl_6 = KL( NegBin1, NegBin2 ) # Calc KL divergence for NegativeBinomial R.V
17.277824Gaussian:
julia> Gauss1 = Distributions.Gaussian(0.33, 1)
Distributions.Normal{Float64}(μ=0.33, σ=1.0)
julia> Gauss2 = Distributions.Gaussian(0.42, 1) # can have same σ
Distributions.Normal{Float64}(μ=0.42, σ=1.0)
julia> ex_kl_7 = KL( Gauss1, Gauss2 ) # Calc KL divergence for Gaussian R.V
0.0040499...
julia> Gauss3 = Distributions.Gaussian(0.42, 10) # but can also have a different σ
Distributions.Normal{Float64}(μ=0.33, σ=10.0)
julia> ex_kl_7 = KL( Gauss1, Gauss3 ) # Calc KL divergence for Gaussian R.V
0.656697...Specific functions:
KullbackLeibler.klBern — Method.function klBern(x, y)Kullback-Leibler divergence for Bernoulli distributions. https://en.wikipedia.org/wiki/Bernoulli_distribution#Kullback.E2.80.93Leibler_divergence
julia> klBern(0.5, 0.5)
0.0
julia> klBern(0.1, 0.9)
1.757779...
julia> klBern(0.9, 0.1) # And this KL is symmetric
1.757779...
julia> klBern(0.4, 0.5)
0.020135...
julia> klBern(0.01, 0.99)
4.503217...Special values:
julia> klBern(0, 1) # Should be +Inf, but 0 --> eps, 1 --> 1 - eps
34.539575...KullbackLeibler.klBin — Method.function klBin(x, y, n)Kullback-Leibler divergence for Binomial distributions. https://math.stackexchange.com/questions/320399/kullback-leibner-divergence-of-binomial-distributions
It is simply the n times
klBernon x and y.
Warning: The two distributions must have the same parameter n, and x, y are p, q in (0, 1).
julia> klBin(0.5, 0.5, 10)
0.0
julia> klBin(0.1, 0.9, 10)
17.57779...
julia> klBin(0.9, 0.1, 10) # And this KL is symmetric
17.57779...
julia> klBin(0.4, 0.5, 10)
0.20135...
julia> klBin(0.01, 0.99, 10)
45.03217...Special values:
julia> klBin(0, 1, 10) # Should be +Inf, but 0 --> eps, 1 --> 1 - eps
345.39575...KullbackLeibler.klPoisson — Method.function klPoisson(x, y)Kullback-Leibler divergence for Poison distributions. https://en.wikipedia.org/wiki/Poisson_distribution#Kullback.E2.80.93Leibler_divergence
julia> klPoisson(3, 3)
0.0
julia> klPoisson(2, 1)
0.386294...
julia> klPoisson(1, 2) # And this KL is non-symmetric
0.306852...
julia> klPoisson(3, 6)
0.920558...
julia> klPoisson(6, 8)
0.273907...Special values:
julia> klPoisson(1, 0) # Should be +Inf, but 0 --> eps, 1 --> 1 - eps
33.538776...
julia> klPoisson(0, 0)
0.0KullbackLeibler.klExp — Method.function klExp(x, y)Kullback-Leibler divergence for exponential distributions. https://en.wikipedia.org/wiki/Exponential_distribution#Kullback.E2.80.93Leibler_divergence
julia> klExp(3, 3)
0.0
julia> klExp(3, 6)
0.193147...
julia> klExp(1, 2) # Only the proportion between x and y is used
0.193147...
julia> klExp(2, 1) # And this KL is non-symmetric
0.306852...
julia> klExp(4, 2) # Only the proportion between x and y is used
0.306852...
julia> klExp(6, 8)
0.037682...x, y have to be positive:
julia> klExp(-3, 2)
Inf
julia> klExp(3, -2)
Inf
julia> klExp(-3, -2)
InfKullbackLeibler.klGamma — Method.function klGamma(x, y, a=1)Kullback-Leibler divergence for gamma distributions. https://en.wikipedia.org/wiki/Gamma_distribution#Kullback.E2.80.93Leibler_divergence
It is simply the a times
klExpon x and y.
.. math::
\mathrm{KL}(\Gamma(x, a), \Gamma(y, a)) = \begin{cases}
a \times \left( \frac{x}{y} - 1 - \log(\frac{x}{y}) \right) & \text{if} x > 0, y > 0\\
+\infty & \text{otherwise}
\end{cases}Warning: The two distributions must have the same parameter a.
julia> klGamma(3, 3)
0.0
julia> klGamma(3, 6)
0.193147...
julia> klGamma(1, 2) # Only the proportion between x and y is used
0.193147...
julia> klGamma(2, 1) # And this KL is non-symmetric
0.306852...
julia> klGamma(4, 2) # Only the proportion between x and y is used
0.306852...
julia> klGamma(6, 8)
0.037682...x, y have to be positive:
julia> klGamma(-3, 2)
Inf
julia> klGamma(3, -2)
Inf
julia> klGamma(-3, -2)
InfKullbackLeibler.klNegBin — Method.function klNegBin(x, y, r=1)Kullback-Leibler divergence for negative binomial distributions. https://en.wikipedia.org/wiki/Negative_binomial_distribution
Warning: The two distributions must have the same parameter r.
julia> klNegBin(0.5, 0.5)
0.0
julia> klNegBin(0.1, 0.9)
-0.711611...
julia> klNegBin(0.9, 0.1) # And this KL is non-symmetric
2.0321564...
julia> klNegBin(0.4, 0.5)
-0.130653...
julia> klNegBin(0.01, 0.99)
-0.717353...Special values:
julia> klBern(0, 1) # Should be +Inf, but 0 --> eps, 1 --> 1 - eps
34.539575...With other values for
r:
julia> klNegBin(0.5, 0.5, r=2)
0.0
julia> klNegBin(0.1, 0.9, r=2)
-0.832991...
julia> klNegBin(0.1, 0.9, r=4)
-0.914890...
julia> klNegBin(0.9, 0.1, r=2) # And this KL is non-symmetric
2.3325528...
julia> klNegBin(0.4, 0.5, r=2)
-0.154572...
julia> klNegBin(0.01, 0.99, r=2)
-0.836257...KullbackLeibler.klGauss — Method.function klGauss(x, y, sig2x=0.25, sig2y=0.25)Kullback-Leibler divergence for Gaussian distributions of means $x$ and $y$ and variances $sig2x$ and $sig2y$, $\nu_1 = \mathcal{N}(x, \sigma_x^2)$ and $\nu_2 = \mathcal{N}(y, \sigma_x^2)$:
See https://en.wikipedia.org/wiki/Normal_distribution#Other_properties
By default, sig2y is assumed to be sig2x (same variance).
julia> klGauss(3, 3)
0.0
julia> klGauss(3, 6)
18.0
julia> klGauss(1, 2)
2.0
julia> klGauss(2, 1) # And this KL is symmetric
2.0
julia> klGauss(4, 2)
8.0
julia> klGauss(6, 8)
8.0x, y can be negative:
julia> klGauss(-3, 2)
50.0
julia> klGauss(3, -2)
50.0
julia> klGauss(-3, -2)
2.0
julia> klGauss(3, 2)
2.0With other values for
sig2x:
julia> klGauss(3, 3, sig2x=10)
0.0
julia> klGauss(3, 6, sig2x=10)
0.45
julia> klGauss(1, 2, sig2x=10)
0.05
julia> klGauss(2, 1, sig2x=10) # And this KL is symmetric
0.05
julia> klGauss(4, 2, sig2x=10)
0.2
julia> klGauss(6, 8, sig2x=10)
0.2With different values for
sig2xandsig2y:
julia> klGauss(0, 0, sig2x=0.25, sig2y=0.5)
-0.0284...
julia> klGauss(0, 0, sig2x=0.25, sig2y=1.0)
0.2243...
julia> klGauss(0, 0, sig2x=0.5, sig2y=0.25) # not symmetric here!
1.1534...
julia> klGauss(0, 1, sig2x=0.25, sig2y=0.5)
0.9715...
julia> klGauss(0, 1, sig2x=0.25, sig2y=1.0)
0.7243...
julia> klGauss(0, 1, sig2x=0.5, sig2y=0.25) # not symmetric here!
3.1534...
julia> klGauss(1, 0, sig2x=0.25, sig2y=0.5)
0.9715...
julia> klGauss(1, 0, sig2x=0.25, sig2y=1.0)
0.7243...
julia> klGauss(1, 0, sig2x=0.5, sig2y=0.25) # not symmetric here!
3.1534...Warning: Using
Policies.klUCB(and variants) withklGaussis equivalent to usePolicies.UCB, so prefer the simpler version. (this is only for the Python version)
KL-UCB indexes functions
Generic function:
KullbackLeibler.klucb — Method.function klucb(x, d, kl, upperbound, lowerbound=-Inf, precision=1e-6, max_iterations=50)The generic kl-UCB index computation.
x: value of the cum reward,
d: upper bound on the divergence,
kl: the KL divergence to be used (
klBern,klGauss, etc),upperbound, lowerbound=-Inf: the known bound of the values x,
precision=1e-6: the threshold from where to stop the research,
max_iterations: max number of iterations of the loop (safer to bound it to reduce time complexity).
Note: It uses a bisection search, and one call to $kl$ for each step of the bisection search.
For example, for klucbBern, the two steps are to first compute an upperbound (as precise as possible) and the compute the kl-UCB index:
julia> x, d = 0.9, 0.2 # mean x, exploration term d
julia> upperbound = min(1.0, klucbGauss(x, d, sig2x=0.25)) # variance 1/4 for [0,1] bounded distributions
julia> upperbound
1.0
julia> klucb(x, d, klBern, upperbound, lowerbound=0, precision=1e-3, max_iterations=10)
0.9941...
julia> klucb(x, d, klBern, upperbound, lowerbound=0, precision=1e-6, max_iterations=10)
0.994482...
julia> klucb(x, d, klBern, upperbound, lowerbound=0, precision=1e-3, max_iterations=50)
0.9941...
julia> klucb(x, d, klBern, upperbound, lowerbound=0, precision=1e-6, max_iterations=100) # more and more precise!
0.994489...Note: See below for more examples for different KL divergence functions.
Specific ones:
KullbackLeibler.klucbBern — Method.function klucbBern(x, d, precision=1e-6)kl-UCB index computation for Bernoulli distributions, using klucb.
Influence of x:
julia> klucbBern(0.1, 0.2)
0.378391...
julia> klucbBern(0.5, 0.2)
0.787088...
julia> klucbBern(0.9, 0.2)
0.994489...Influence of d:
julia> klucbBern(0.1, 0.4)
0.519475...
julia> klucbBern(0.1, 0.9)
0.734714...
julia> klucbBern(0.5, 0.4)
0.871035...
julia> klucbBern(0.5, 0.9)
0.956809...
julia> klucbBern(0.9, 0.4)
0.999285...
julia> klucbBern(0.9, 0.9)
0.999995...KullbackLeibler.klucbGauss — Method.function klucbGauss(x, d, sig2x=0.25, precision=0.0)kl-UCB index computation for Gaussian distributions.
Note: it does not require any search.
Warning: it works only if the good variance constant is given.
Influence of x:
julia> klucbGauss(0.1, 0.2)
0.416227...
julia> klucbGauss(0.5, 0.2)
0.816227...
julia> klucbGauss(0.9, 0.2)
1.216227...
- Influence of d:
julia julia> klucbGauss(0.1, 0.4) 0.547213... julia> klucbGauss(0.1, 0.9) 0.770820...
julia> klucbGauss(0.5, 0.4) 0.947213... julia> klucbGauss(0.5, 0.9) 1.170820...
julia> klucbGauss(0.9, 0.4) 1.347213... julia> klucbGauss(0.9, 0.9) 1.570820... ```
Warning: Using
Policies.klUCB(and variants) withklucbGaussis equivalent to usePolicies.UCB, so prefer the simpler version (this is only for the Python version).
KullbackLeibler.klucbPoisson — Method.function klucbPoisson(x, d, precision=1e-6)kl-UCB index computation for Poisson distributions, using klucb.
Influence of x:
julia> klucbPoisson(0.1, 0.2)
0.450523...
julia> klucbPoisson(0.5, 0.2)
1.089376...
julia> klucbPoisson(0.9, 0.2)
1.640112...Influence of d:
julia> klucbPoisson(0.1, 0.4)
0.693684...
julia> klucbPoisson(0.1, 0.9)
1.252796...
julia> klucbPoisson(0.5, 0.4)
1.422933...
julia> klucbPoisson(0.5, 0.9)
2.122985...
julia> klucbPoisson(0.9, 0.4)
2.033691...
julia> klucbPoisson(0.9, 0.9)
2.831573...KullbackLeibler.klucbExp — Method.function klucbExp(x, d, precision=1e-6)kl-UCB index computation for exponential distributions, using klucb.
Influence of x:
julia> klucbExp(0.1, 0.2)
0.202741...
julia> klucbExp(0.5, 0.2)
1.013706...
julia> klucbExp(0.9, 0.2)
1.824671...Influence of d:
julia> klucbExp(0.1, 0.4)
0.285792...
julia> klucbExp(0.1, 0.9)
0.559088...
julia> klucbExp(0.5, 0.4)
1.428962...
julia> klucbExp(0.5, 0.9)
2.795442...
julia> klucbExp(0.9, 0.4)
2.572132...
julia> klucbExp(0.9, 0.9)
5.031795...KullbackLeibler.klucbGamma — Method.function klucbGamma(x, d, precision=1e-6)kl-UCB index computation for Gamma distributions, using klucb.
Influence of x:
julia> klucbGamma(0.1, 0.2)
0.202...
julia> klucbGamma(0.5, 0.2)
1.013...
julia> klucbGamma(0.9, 0.2)
1.824...Influence of d:
julia> klucbGamma(0.1, 0.4)
0.285...
julia> klucbGamma(0.1, 0.9)
0.559...
julia> klucbGamma(0.5, 0.4)
1.428...
julia> klucbGamma(0.5, 0.9)
2.795...
julia> klucbGamma(0.9, 0.4)
2.572...
julia> klucbGamma(0.9, 0.9)
5.031...