Skip to content

js_divergence

Computes the Jensen-Shannon divergence between two distributions.

What does it measure?

Jensen-Shannon divergence answers: how different are two distributions, on a scale from 0 to 1?

It is the symmetric, bounded sibling of KL divergence. Rather than measuring the one-directional cost of approximating P with Q, JSD considers both directions symmetrically by comparing each distribution to their average M=(P+Q)/2.

Key advantages over KL divergence:

  • Always well-defined, even when the distributions have disjoint supports.
  • Symmetric: JSD(PQ)=JSD(QP).
  • Bounded: JSD[0,1] bits, making it easy to interpret.
  • Its square root JSD is a proper metric distance.

Formula

JSD(PQ)=12DKL(PM)+12DKL(QM),M=P+Q2

Because M is a mixture of P and Q, every value in supp(P)supp(Q) has positive probability in M, making both KL terms always finite.

Signature

rust
pub fn js_divergence<T>(p: &[T], q: &[T]) -> Result<f64, InfoError>
where
    T: Eq + Hash
rust
pub fn js_divergence_unchecked<T>(p: &[T], q: &[T]) -> f64
where
    T: Eq + Hash

Parameters

ParameterDescription
pSamples from the first distribution P
qSamples from the second distribution Q

The slices do not need to have the same length.

Returns

JSD(PQ)[0,1] in bits, or:

ErrorWhen
InfoError::EmptyInputEither slice is empty

Examples

rust
use entropium::js_divergence;

// Identical distributions → JSD = 0
let p = vec![0, 1, 0, 1];
assert_eq!(js_divergence(&p, &p).unwrap(), 0.0);

// Completely disjoint supports → maximum divergence = 1 bit
let p = vec![0, 0, 0];
let q = vec![1, 1, 1];
assert!((js_divergence(&p, &q).unwrap() - 1.0).abs() < 1e-12);

// Always symmetric
let p = vec![0, 0, 1, 2];
let q = vec![1, 1, 2, 0];
let jsd_pq = js_divergence(&p, &q).unwrap();
let jsd_qp = js_divergence(&q, &p).unwrap();
assert!((jsd_pq - jsd_qp).abs() < 1e-12);

// Result is always in [0, 1]
let p = vec![0u8, 0, 0, 1, 2, 2];
let q = vec![0u8, 1, 1, 1, 2, 2];
let jsd = js_divergence(&p, &q).unwrap();
assert!(jsd >= 0.0 && jsd <= 1.0);

Practical uses

  • Distribution comparison: anywhere you would use KL divergence but need a symmetric, bounded result — e.g. comparing language models, comparing histograms of sensor readings before and after an event.
  • Generative model evaluation: JSD is the theoretical loss of the original GAN formulation. Minimising JSD between the real and generated distributions is equivalent to training a perfect discriminator.
  • Text similarity: compare the word-frequency distributions of two documents. A JSD of 0 means identical word distributions; 1 means no shared vocabulary.
  • Dataset shift detection: compute JSD between a training-time feature distribution and a production-time feature distribution. Values above a threshold trigger a retraining alert.

Properties

PropertyStatement
Non-negativityJSD(P|Q)0
SymmetryJSD(P|Q)=JSD(Q|P)
Bounded0JSD(P|Q)1 bit
IdentityJSD(P|Q)=0 iff P=Q
MaximumJSD(P|Q)=1 iff supp(P)supp(Q)=
MetricJSD satisfies the triangle inequality

Released under the MIT OR Apache-2.0 License.