Nothing
context("test-summ_entropy")
# Input data --------------------------------------------------------------
def_clip <- exp(-20)
max_entropy <- -log(def_clip)
# Custom expectations -----------------------------------------------------
expect_relative_summ_entropy2_works <- function(f, g) {
expect_equal(
summ_entropy2(f, g, method = "relative"),
summ_entropy2(f, g, method = "cross") - summ_entropy(f)
)
expect_equal(
summ_entropy2(g, f, method = "relative"),
summ_entropy2(g, f, method = "cross") - summ_entropy(g)
)
}
# summ_entropy ------------------------------------------------------------
# There are also tests in `cross_entropy()`
test_that("summ_entropy works with 'discrete' functions", {
expect_equal_stat(summ_entropy, stat_list[["binom"]], "entropy")
# Output isn't exact because of tail trimming during `as_d()` and not exact
# value of entropy in `stat_list[["pois"]][["entropy"]]`
expect_equal_stat(summ_entropy, stat_list[["pois"]], "entropy", thres = 8e-4)
})
test_that("summ_entropy works with 'continuous' functions", {
expect_equal_stat(summ_entropy, stat_list[["beta"]], "entropy", thres = 3e-5)
# Big threshold because original density goes to infinity at edges
expect_equal_stat(
summ_entropy, stat_list[["beta_inf"]], "entropy", thres = 0.25
)
expect_equal_stat(summ_entropy, stat_list[["chisq"]], "entropy", thres = 2e-5)
# Big threshold because original density goes to infinity at left edge
expect_equal_stat(
summ_entropy, stat_list[["chisq_inf"]], "entropy", thres = 8e-2
)
expect_equal_stat(summ_entropy, stat_list[["exp"]], "entropy", thres = 2e-5)
expect_equal_stat(summ_entropy, stat_list[["norm"]], "entropy", thres = 4e-5)
expect_equal_stat(
summ_entropy, stat_list[["norm_2"]], "entropy", thres = 4e-5
)
expect_equal_stat(summ_entropy, stat_list[["unif"]], "entropy")
})
test_that("summ_entropy works with dirac-like functions", {
expect_equal(summ_entropy(new_d(10, "discrete")), 0)
# Entropy of dirac-like "continuous" function is computed from symmetric
# triangular distribution with width 2*1e-8
expect_equal(summ_entropy(new_d(10, "continuous")), 0.5 + log(1e-8))
})
test_that("summ_entropy handles zero probabilities/densities", {
cur_d_dis <- new_d(data.frame(x = 1:3, prob = c(0, 0.5, 0.5)), "discrete")
expect_equal(summ_entropy(cur_d_dis), -2 * 0.5 * log(0.5))
cur_d_con <- new_d(data.frame(x = 1:4, y = c(0, 1, 0, 0)), "continuous")
ref_d_con <- new_d(data.frame(x = 1:3, y = c(0, 1, 0)), "continuous")
expect_equal(summ_entropy(cur_d_con), summ_entropy(ref_d_con))
})
test_that("summ_entropy validates input", {
expect_error(summ_entropy("a"), "`f`.*not pdqr-function")
})
# summ_entropy2 -----------------------------------------------------------
# More tests in `cross_entropy()`
test_that("summ_entropy2 works with 'discrete' functions", {
f <- new_d(1:4, "discrete")
g <- new_d(3:7, "discrete")
# Method "relative"
expect_relative_summ_entropy2_works(f, g)
# Method "cross"
expect_equal(
summ_entropy2(f, g, method = "cross"),
-2 * 0.25 * log(0.2) + 2 * 0.25 * max_entropy
)
expect_equal(
summ_entropy2(g, f, method = "cross"),
-2 * 0.2 * log(0.25) + 3 * 0.2 * max_entropy
)
})
test_that("summ_entropy2 works with 'continuous' functions", {
f <- new_d(data.frame(x = c(0, 4), y = c(1, 1) / 4), "continuous")
g <- new_d(data.frame(x = c(-1, 9), y = c(1, 1) / 10), "continuous")
# Method "relative"
expect_relative_summ_entropy2_works(f, g)
# Method "cross"
expect_equal(summ_entropy2(f, g, method = "cross"), -4 * 0.25 * log(0.1))
expect_equal(
summ_entropy2(g, f, method = "cross"),
-4 * 0.1 * log(0.25) + 6 * 0.1 * max_entropy
)
})
test_that("summ_entropy2 works with dirac-like 'continuous' functions", {
f <- new_d(data.frame(x = c(0, 4), y = c(1, 1) / 4), "continuous")
g_dirac <- new_d(2, "continuous")
# Method "relative"
expect_relative_summ_entropy2_works(f, g_dirac)
# Method "cross"
expect_equal(summ_entropy2(f, g_dirac, method = "cross"), max_entropy)
expect_equal(summ_entropy2(g_dirac, f, method = "cross"), -log(0.25))
})
test_that("summ_entropy2 handles numerical representation accuracy", {
# More info in corresponding `cross_entropy()` test
approx_unif <- new_d(
data.frame(x = 0:1, y = c(0.5 - 0.3, 0.3 - 0.1) / 2), "continuous"
)
beta <- as_d(dbeta, shape1 = 1, shape2 = 2)
expect_equal(summ_entropy2(beta, approx_unif, method = "cross"), 0)
})
test_that("summ_entropy2 throws error on inputs of different types", {
expect_error(summ_entropy2(d_dis, d_con), "`f`.*`g`.*same type")
expect_error(summ_entropy2(d_con, d_dis), "`f`.*`g`.*same type")
})
test_that("summ_entropy2 uses `clip` argument", {
f <- new_d(data.frame(x = 1:2, y = c(1, 1)), "continuous")
g <- new_d(data.frame(x = 3:4, y = c(1, 1)), "continuous")
expect_equal(summ_entropy2(f, g, method = "cross", clip = exp(-10)), 10)
})
test_that("summ_entropy2 validates input", {
expect_error(summ_entropy2("a", d_dis), "`f`.*not pdqr-function")
expect_error(summ_entropy2(d_dis, "a"), "`g`.*not pdqr-function")
expect_error(summ_entropy2(d_dis, d_dis, clip = "a"), "`clip`.*number")
expect_error(summ_entropy2(d_dis, d_dis, clip = 1:2), "`clip`.*single")
expect_error(summ_entropy2(d_dis, d_dis, clip = -1), "`clip`.*non-negative")
})
# cross_entropy -----------------------------------------------------------
test_that("cross_entropy works with 'discrete' functions", {
# Simple uniform discrete distribution
f <- new_d(1:15, "discrete")
expect_equal(cross_entropy(f, f), -log(1 / 15))
# Two distributions with different `x`s
f <- new_d(1:4, "discrete")
g <- new_d(3:7, "discrete")
expect_equal(
cross_entropy(f, g),
-2 * 0.25 * log(0.2) + 2 * 0.25 * max_entropy
)
expect_equal(
cross_entropy(g, f),
-2 * 0.2 * log(0.25) + 3 * 0.2 * max_entropy
)
})
test_that("cross_entropy works with 'continuous' functions", {
# Simple uniform distribution
f <- new_d(data.frame(x = c(0, 4), y = c(1, 1) / 4), "continuous")
g <- new_d(data.frame(x = c(-1, 9), y = c(1, 1) / 10), "continuous")
expect_equal(cross_entropy(f, f), log(4))
expect_equal(cross_entropy(g, g), log(10))
expect_equal(cross_entropy(f, g), -4 * 0.25 * log(0.1))
expect_equal(
cross_entropy(g, f),
-4 * 0.1 * log(0.25) + 6 * 0.1 * max_entropy
)
# Real world examples
f <- as_d(dbeta, shape1 = 1, shape2 = 2, support = c(0, 1))
g <- as_d(dbeta, shape1 = 2, shape2 = 1, support = c(0, 1))
expect_equal(cross_entropy(f, f), log(beta(1, 2)) - psigamma(2) + psigamma(3))
expect_equal(cross_entropy(g, g), log(beta(2, 1)) - psigamma(2) + psigamma(3))
expect_equal(cross_entropy(f, g), 1.5 - log(2))
expect_equal(cross_entropy(g, f), 1.5 - log(2))
})
test_that("cross_entropy handles zero plateaus in 'continuous' functions", {
d_unif <- new_d(data.frame(x = c(1, 6), y = c(1, 1) / 5), "continuous")
f <- new_d(data.frame(x = 1:4, y = c(0, 1, 0, 0)), "continuous")
g <- new_d(data.frame(x = 3:6, y = c(0, 0, 1, 0)), "continuous")
expect_equal(cross_entropy(f, d_unif), -log(0.2))
# `-integral{log(f(x))}` on `[1; 3]` equals 2
expect_equal(cross_entropy(d_unif, f), 0.2 * 2 + 3 * 0.2 * max_entropy)
# These are equal to `max_entropy` because `f` and `g` intersect only on
# zero plateau.
expect_equal(cross_entropy(f, g), max_entropy)
expect_equal(cross_entropy(g, f), max_entropy)
})
test_that("cross_entropy works with dirac-like 'continuous' functions", {
f <- new_d(data.frame(x = c(0, 4), y = c(1, 1) / 4), "continuous")
g_dirac <- new_d(2, "continuous")
expect_equal(cross_entropy(f, g_dirac), max_entropy)
expect_equal(cross_entropy(g_dirac, f), -log(0.25))
# Entropy of dirac-like function is computed from symmetric triangular
# distribution with width 2*1e-8
expect_equal(cross_entropy(g_dirac, g_dirac), 0.5 + log(1e-8))
})
test_that("cross_entropy returns maximum value with non-overlapping supports", {
# Type "discrete"
f_dis <- new_d(1:4, "discrete")
g_dis <- new_d(5:8, "discrete")
expect_equal(cross_entropy(f_dis, g_dis, clip = exp(-20)), 20)
expect_equal(cross_entropy(g_dis, f_dis, clip = exp(-20)), 20)
expect_equal(cross_entropy(f_dis, g_dis, clip = exp(-10)), 10)
# Type "continuous"
f_con <- new_d(data.frame(x = 1:2, y = c(1, 1)), "continuous")
g_con <- new_d(data.frame(x = 2:3, y = c(1, 1)), "continuous")
h_con <- new_d(data.frame(x = 3:4, y = c(1, 1)), "continuous")
expect_equal(cross_entropy(f_con, g_con, clip = exp(-20)), 20)
expect_equal(cross_entropy(g_con, f_con, clip = exp(-20)), 20)
expect_equal(cross_entropy(f_con, h_con, clip = exp(-20)), 20)
expect_equal(cross_entropy(h_con, f_con, clip = exp(-20)), 20)
expect_equal(cross_entropy(f_con, g_con, clip = exp(-10)), 10)
})
test_that("cross_entropy handles numerical representation accuracy", {
# Here `y` values are not **exactly** equal but differ by ~1.38e-17 (on most
# platforms, according to "Note" from `==`'s help page).
approx_unif <- new_d(
data.frame(x = 0:1, y = c(0.5 - 0.3, 0.3 - 0.1) / 2), "continuous"
)
beta <- as_d(dbeta, shape1 = 1, shape2 = 2)
# When this type of issue is in place, one of the previous implementations
# checked for slope of second function being equal to 0 as `sl_g != 0`. This
# returned `FALSE` and proceeded with great errors because `sl_g` is used in
# fraction denominator several times. This was fixed by using
# `!is_near(sl_g, 0, tol = 1e-10)` instead.
# Here output should be equal to 0 because `log(1)` is zero
expect_equal(cross_entropy(beta, approx_unif), 0)
})
test_that("cross_entropy throws error on inputs of different types", {
expect_error(cross_entropy(d_dis, d_con), "`f`.*`g`.*same type")
expect_error(cross_entropy(d_con, d_dis), "`f`.*`g`.*same type")
})
# cross_entropy_dis -------------------------------------------------------
# Tested in `cross_entropy()`
# cross_entropy_con -------------------------------------------------------
# Tested in `cross_entropy()`
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.