Nothing
# Various tests should have random accuracy draws, probably with lots of
# weight on 1
describe("discover", {
fds_equivalent <- function(fds1, fds2) {
setequal(attrs_order(fds1), attrs_order(fds2)) &&
setequal(fds1, fds2)
}
expect_equiv_deps <- function(deps1, deps2) {
expect_setequal(attrs_order(deps1), attrs_order(deps2))
expect_setequal(
deps1,
functional_dependency(
unclass(deps2),
attrs_order(deps1)
)
)
}
expect_equiv_deps_except_names <- function(deps1, deps2) {
expect_equiv_deps(rename_attrs(deps1, attrs_order(deps2)), deps2)
}
expect_equiv_non_removed_attr_deps <- function(deps1, deps2) {
removed_attr <- setdiff(attrs_order(deps1), attrs_order(deps2))
expect_length(removed_attr, 1)
filtered <- deps1
filtered <- functional_dependency(
unclass(filtered[vapply(
filtered,
\(fd) !is.element(removed_attr, unlist(fd)),
logical(1)
)]),
setdiff(attrs_order(deps1), removed_attr)
)
expect_equiv_deps(filtered, deps2)
}
expect_det_subsets_kept <- function(deps1, deps2) {
expect_identical(attrs_order(deps1), attrs_order(deps2))
expect_true(all(apply(outer(deps1, deps2, ">="), 1, any)))
}
terminates_then <- function(fn, accuracy, ...) {
function(df) {
res <- with_timeout(discover(df, accuracy = accuracy, ...))
if (is.null(res))
return(fail("discover() timed out"))
fn(res)
}
}
terminates_then_compare <- function(fn, ...) {
function(df) {
res <- with_timeout(discover(df, ...))
if (is.null(res))
return(fail("discover() timed out"))
fn(df, res)
}
}
both_terminate_then <- function(fn, accuracy, ...) {
function(df1, df2) {
res1 <- with_timeout(discover(df1, accuracy = accuracy, ...))
if (is.null(res1))
return(fail("first discover() timed out"))
res2 <- with_timeout(discover(df2, accuracy = accuracy, ...))
if (is.null(res2))
return(fail("second discover() timed out"))
fn(res1, res2)
}
}
terminates_with_and_without_full_cache_then <- function(fn, accuracy, ...) {
function(df) {
res_cache <- with_timeout(discover(
df,
accuracy = accuracy,
full_cache = TRUE,
...
))
if (is.null(res_cache))
return(fail("discover() with full_cache = TRUE timed out"))
res_nocache <- with_timeout(discover(
df,
accuracy = accuracy,
full_cache = FALSE,
...
))
if (is.null(res_nocache))
return(fail("discover() with full_cache = FALSE timed out"))
fn(res_cache, res_nocache)
}
}
terminates_with_and_without_store_cache_then <- function(fn, accuracy, ...) {
function(df) {
res_store <- with_timeout(discover(
df,
accuracy = accuracy,
full_cache = TRUE,
store_cache = TRUE,
...
))
if (is.null(res_store))
return(fail("discover() with store_cache = TRUE timed out"))
res_nostore <- with_timeout(discover(
df,
accuracy = accuracy,
full_cache = TRUE,
store_cache = FALSE,
...
))
if (is.null(res_nostore))
return(fail("discover() with store_cache = FALSE timed out"))
fn(res_store, res_nostore)
}
}
terminates_with_and_without_bijection_skip_then <- function(fn, accuracy, ...) {
function(df) {
res_skip <- with_timeout(discover(
df,
accuracy = accuracy,
full_cache = TRUE,
store_cache = TRUE,
skip_bijections = TRUE,
...
))
if (is.null(res_skip))
return(fail("discover() with skip_bijections = TRUE timed out"))
res_noskip <- with_timeout(discover(
df,
accuracy = accuracy,
full_cache = TRUE,
store_cache = TRUE,
skip_bijections = FALSE,
...
))
if (is.null(res_noskip))
return(fail("discover() with skip_bijections = FALSE timed out"))
fn(res_skip, res_noskip)
}
}
# input requirements
it("expects attribute names to be unique", {
df <- data.frame(A = 1:3, B = c(1, 1, 2), A = c(1, 2, 2), check.names = FALSE)
expect_error(discover(df, method = "DFD"), "^duplicate column names: A$")
expect_error(discover(df, method = "FDHitsSep"), "^duplicate column names: A$")
expect_error(discover(df, method = "FDHitsJoint"), "^duplicate column names: A$")
})
# input edge cases
it("can take attributes with same name as arguments for paste(), e.g. sep", {
df1 <- data.frame(
b = NA,
j = c(TRUE, NA, NA, NA),
u = c(FALSE, TRUE, TRUE, NA),
recycle0 = c(FALSE, TRUE, TRUE, TRUE),
collapse = c(FALSE, FALSE, TRUE, NA),
sep = c(TRUE, TRUE, NA, NA)
)
df2 <- df1[, c("recycle0", "j", "collapse", "b", "u", "sep")]
terminates_with_and_without_cache <- function(...) {
terminates_with_and_without_full_cache_then(
\(x, y) succeed(),
1,
...
)
}
terminates_with_and_without_cache(method = "DFD")(df1)
terminates_with_and_without_cache(method = "FDHitsSep")(df1)
terminates_with_and_without_cache(method = "FDHitsJoint")(df1)
terminates_with_and_without_cache(method = "DFD")(df2)
terminates_with_and_without_cache(method = "FDHitsSep")(df2)
terminates_with_and_without_cache(method = "FDHitsJoint")(df2)
})
it("can include the rownames, equivalent to adding them as first column", {
x <- data.frame(
a = c(1, 1, 1, 2, 2, 3, 3, 3, 4),
b = c(1, 1, 1, 1, 1, 2, 2, 2, 3),
row.names = letters[1:9]
)
default <- discover(x, keep_rownames = TRUE)
explicit <- discover(x, keep_rownames = "id")
expected <- discover(x)
expect_setequal(
default,
discover(cbind(data.frame(row = rownames(x)), x))
)
expect_setequal(
explicit,
discover(cbind(data.frame(id = rownames(x)), x))
)
})
it("correctly simplifies date attributes with varying standard/daylight savings", {
# example from nycflights13::weather
df <- data.frame(
month = c(11L, 11L, 11L),
day = c(3L, 3L, 4L),
hour = 1L,
time = as.POSIXct(
# 2013-11-03 01:00:00 EDT,
# 2013-11-03 01:00:00 EST,
# 2013-11-04 01:00:00 EST
c(1383454800L, 1383458400L, 1383544800L),
origin = "1970-01-01 00:00:00 UTC",
tz = "America/New_York"
)
)
stopifnot(df[1, "time"] != df[2, "time"])
deps <- discover(df, method = "DFD")
expect_length(deps[dependant(deps) == "time"], 0L)
deps2 <- discover(df, method = "FDHitsSep")
expect_length(deps2[dependant(deps2) == "time"], 0L)
deps3 <- discover(df, method = "FDHitsJoint")
expect_length(deps3[dependant(deps3) == "time"], 0L)
})
it("correctly simplifies floating-point numbers to high accuracy", {
df <- data.frame(
x = c(
47.37661580000000327573,
47.37661580000000327573
),
y = c(
8.549177500000007,
8.549177499999999
)
)
expect_identical(
discover(df, digits = 8, method = "DFD"),
functional_dependency(
list(list(character(), "x"), list(character(), "y")),
c("x", "y")
)
)
expect_identical(
discover(df, digits = 8, method = "FDHitsSep"),
functional_dependency(
list(list(character(), "x"), list(character(), "y")),
c("x", "y")
)
)
expect_identical(
discover(df, digits = 8, method = "FDHitsJoint"),
functional_dependency(
list(list(character(), "x"), list(character(), "y")),
c("x", "y")
)
)
expect_identical(
discover(df, digits = 15, method = "DFD"),
functional_dependency(
list(list(character(), "x")),
c("x", "y")
)
)
expect_identical(
discover(df, digits = 15, method = "FDHitsSep"),
functional_dependency(
list(list(character(), "x")),
c("x", "y")
)
)
expect_identical(
discover(df, digits = 15, method = "FDHitsJoint"),
functional_dependency(
list(list(character(), "x")),
c("x", "y")
)
)
})
it("correctly handles attributes with non-df-standard names", {
df <- data.frame(1:3, c(1, 1, 2), c(1, 2, 2)) |>
stats::setNames(c("A 1", "B 2", "C 3"))
deps_dfd <- discover(df, method = "DFD")
A_1_deps_dfd <- dependant(deps_dfd) == "A 1"
A_1_detsets_dfd <- detset(deps_dfd[A_1_deps_dfd])
expect_identical(A_1_detsets_dfd, list(c("B 2", "C 3")))
deps_sep <- discover(df, method = "FDHitsSep")
A_1_deps_sep <- dependant(deps_sep) == "A 1"
A_1_detsets_sep <- detset(deps_sep[A_1_deps_sep])
expect_identical(A_1_detsets_sep, list(c("B 2", "C 3")))
deps_jnt <- discover(df, method = "FDHitsJoint")
A_1_deps_jnt <- dependant(deps_jnt) == "A 1"
A_1_detsets_jnt <- detset(deps_jnt[A_1_deps_jnt])
expect_identical(A_1_detsets_jnt, list(c("B 2", "C 3")))
})
# example inputs
it("finds dependencies for the team data in test-synthesise", {
df <- data.frame(
team = c(
'Red', 'Red', 'Red', 'Orange', 'Orange',
'Yellow', 'Yellow', 'Green', 'Green', 'Blue'
),
jersey_num = c(
1, 2, 3, 1, 2,
1, 5, 8, 2, 2
),
player_name = c(
'A', 'B', 'C', 'D', 'A',
'E', 'B', 'A', 'G', 'H'
),
city = c(
'boston', 'boston', 'boston', 'chicago', 'chicago',
'honolulu', 'honolulu', 'boston', 'boston', 'austin'
),
state = c(
'MA', 'MA', 'MA', 'IL', 'IL',
'HI', 'HI', 'MA', 'MA', 'TX'
)
)
expected_deps <- functional_dependency(
list(
list(c('player_name', 'jersey_num'), "team"),
list(c('player_name', 'team'), "jersey_num"),
list(c('team', 'jersey_num'), "player_name"),
list('team', "city"),
list('state', "city"),
list(c('player_name', 'jersey_num'), "city"),
list('team', "state"),
list(c('player_name', 'jersey_num'), "state"),
list('city', "state")
),
c("team", "jersey_num", "player_name", "city", "state")
)
deps_dfd <- discover(df, method = "DFD")
expect_identical(attrs_order(deps_dfd), attrs_order(expected_deps))
expect_true(all(is.element(expected_deps, deps_dfd)))
deps_sep <- discover(df, method = "FDHitsSep")
expect_identical(attrs_order(deps_sep), attrs_order(expected_deps))
expect_true(all(is.element(expected_deps, deps_sep)))
deps_jnt <- discover(df, method = "FDHitsJoint")
expect_identical(attrs_order(deps_jnt), attrs_order(expected_deps))
expect_true(all(is.element(expected_deps, deps_jnt)))
})
it("finds dependencies for the team data in original's edit demo", {
df <- data.frame(
team = c("tigers", "elephants", "foxes", "snakes", "dolphins", "eagles"),
city = c("boston", "chicago", "miami", "austin", "honolulu", "houston"),
state = c("MA", "IL", "FL", "TX", "HI", "TX"),
roster_size = c(20L, 21L, 20L, 20L, 19L, 21L)
)
expected_deps <- functional_dependency(
list(
list("city", "team"),
list("team", "city"),
list("team", "state"),
list("city", "state"),
list("team", "roster_size"),
list("city", "roster_size")
),
c("team", "city", "state", "roster_size")
)
deps_dfd <- discover(df, method = "DFD")
expect_identical(attrs_order(deps_dfd), attrs_order(expected_deps))
expect_true(all(is.element(expected_deps, deps_dfd)))
deps_sep <- discover(df, method = "FDHitsSep")
expect_identical(attrs_order(deps_sep), attrs_order(expected_deps))
expect_true(all(is.element(expected_deps, deps_sep)))
deps_jnt <- discover(df, method = "FDHitsJoint")
expect_identical(attrs_order(deps_jnt), attrs_order(expected_deps))
expect_true(all(is.element(expected_deps, deps_jnt)))
})
it("finds dependencies for Wikipedia 1NF->2NF->3NF example", {
df <- data.frame(
Title = rep(
c(
"Beginning MySQL Database Design and Optimization",
"The Relational Model for Database Management: Version 2"
),
each = 2
),
Format = c("Hardcover", "E-book", "E-book", "Paperback"),
Author = rep(c("Chad Russell", "E.F. Codd"), each = 2),
Author_Nationality = rep(c("American", "British"), each = 2),
Price = c(4999L, 2234L, 1388L, 3999L),
Thickness = "Thick",
Genre_ID = rep(1:2, each = 2),
Genre_Name = rep(c("Tutorial", "Popular science"), each = 2),
Publisher_ID = rep(1:2, each = 2)
)
expected_deps <- functional_dependency(
list(
list("Title", "Author"),
list("Author", "Author_Nationality"),
list(c("Title", "Format"), "Price"),
list(character(), "Thickness"),
list("Title", "Genre_ID"),
list("Genre_ID", "Genre_Name"),
list("Title", "Publisher_ID")
),
c(
"Title",
"Format",
"Author",
"Author_Nationality",
"Price",
"Thickness",
"Genre_ID",
"Genre_Name",
"Publisher_ID"
)
)
deps_dfd <- discover(df, method = "DFD")
deps_sep <- discover(df, method = "FDHitsSep")
deps_jnt <- discover(df, method = "FDHitsJoint")
expect_identical(attrs_order(deps_dfd), attrs_order(expected_deps))
expect_identical(attrs_order(deps_sep), attrs_order(expected_deps))
expect_identical(attrs_order(deps_jnt), attrs_order(expected_deps))
expect_true(all(is.element(expected_deps, deps_dfd)))
expect_true(all(is.element(expected_deps, deps_sep)))
expect_true(all(is.element(expected_deps, deps_jnt)))
})
it("gives a deterministic result, except for per-dependant dependency order", {
two_copies <- function(fn) function(df) fn(df, df)
forall(
gen_df(4, 6),
two_copies(both_terminate_then(expect_equiv_deps, accuracy = 1, method = "DFD"))
)
forall(
gen_df(4, 6),
two_copies(both_terminate_then(expect_equiv_deps, accuracy = 1, method = "FDHitsSep"))
)
forall(
gen_df(4, 6),
two_copies(both_terminate_then(expect_equiv_deps, accuracy = 1, method = "FDHitsJoint"))
)
})
it("doesn't have excluded attributes in any determinant sets", {
gen_df_and_exclude <- function(nrow, ncol, remove_dup_rows = FALSE) {
gen_df(nrow, ncol, minrow = 1L, mincol = 1L, remove_dup_rows) |>
gen.and_then(\(df) list(df, gen.element(names(df))))
}
terminates_with_exclusion_then_no_trivial <- function(accuracy, ...) {
function(df, attr) {
deps <- with_timeout(discover(df, accuracy = accuracy, exclude = attr, ...))
if (is.null(deps))
return(fail("discover() with exclude timed out"))
# test exclusion_not_in_determinant_sets
expect_false(attr %in% unlist(detset(deps)))
}
}
forall(
gen_df_and_exclude(4, 6),
terminates_with_exclusion_then_no_trivial(1, method = "DFD"),
curry = TRUE
)
forall(
gen_df_and_exclude(4, 6),
terminates_with_exclusion_then_no_trivial(1, method = "FDHitsSep"),
curry = TRUE
)
forall(
gen_df_and_exclude(4, 6),
terminates_with_exclusion_then_no_trivial(1, method = "FDHitsJoint"),
curry = TRUE
)
})
it("gives determinants for unique attributes", {
df <- data.frame(A = 1:3, B = c(1, 1, 2), C = c(1, 2, 2))
deps_dfd <- discover(df, method = "DFD")
A_deps_dfd <- dependant(deps_dfd) == "A"
A_detsets_dfd <- detset(deps_dfd[A_deps_dfd])
expect_identical(A_detsets_dfd, list(c("B", "C")))
deps_sep <- discover(df, method = "FDHitsSep")
A_deps_sep <- dependant(deps_sep) == "A"
A_detsets_sep <- detset(deps_sep[A_deps_sep])
expect_identical(A_detsets_sep, list(c("B", "C")))
deps_jnt <- discover(df, method = "FDHitsJoint")
A_deps_jnt <- dependant(deps_jnt) == "A"
A_detsets_jnt <- detset(deps_jnt[A_deps_jnt])
expect_identical(A_detsets_jnt, list(c("B", "C")))
})
it("gives a minimal functional dependency set", {
forall(
gen_df(6, 7),
terminates_then(expect_valid_minimal_functional_dependency, 1, method = "DFD")
)
forall(
gen_df(6, 7),
terminates_then(expect_valid_minimal_functional_dependency, 1, method = "FDHitsSep")
)
forall(
gen_df(6, 7),
terminates_then(expect_valid_minimal_functional_dependency, 1, method = "FDHitsJoint")
)
})
it("gives satisfied functional dependencies", {
expect_satisfied <- function(data, fds) {
attrs <- Map(c, detset(fds), dependant(fds))
projections <- lapply(attrs, \(a) df_unique(data[, a, drop = FALSE]))
Map(
\(p, ds) !df_anyDuplicated(p[, ds, drop = FALSE]),
projections,
detset(fds)
) |>
Reduce(f = `&&`, init = TRUE) |>
expect_true()
}
forall(
gen_df(6, 7),
terminates_then_compare(expect_satisfied, method = "DFD")
)
forall(
gen_df(6, 7),
terminates_then_compare(expect_satisfied, method = "FDHitsSep")
)
forall(
gen_df(6, 7),
terminates_then_compare(expect_satisfied, method = "FDHitsJoint")
)
})
# metamorphic tests
it("loses FDs involving a removed attribute, keeps the rest", {
gen_df_and_remove_col <- function(nrow, ncol, remove_dup_rows = FALSE) {
gen_df(nrow, ncol, minrow = 1L, mincol = 1L, remove_dup_rows) |>
gen.and_then(\(df) list(df, gen.int(ncol(df)))) |>
gen.with(uncurry(\(df, n) {
list(df, df[, -n, drop = FALSE])
}))
}
forall(
gen_df_and_remove_col(4, 6),
both_terminate_then(expect_equiv_non_removed_attr_deps, 1, method = "DFD"),
curry = TRUE
)
forall(
gen_df_and_remove_col(4, 6),
both_terminate_then(expect_equiv_non_removed_attr_deps, 1, method = "FDHitsSep"),
curry = TRUE
)
forall(
gen_df_and_remove_col(4, 6),
both_terminate_then(expect_equiv_non_removed_attr_deps, 1, method = "FDHitsJoint"),
curry = TRUE
)
})
it("keeps subsets of all FDs if a row is removed, might have more", {
gen_df_and_remove_row <- function(nrow, ncol) {
gen_df(nrow, ncol, minrow = 1L, mincol = 1L, remove_dup_rows = TRUE) |>
gen.and_then(\(df) list(df, gen.element(seq_len(nrow(df))))) |>
gen.with(uncurry(\(df, n) {
list(df, df[-n, , drop = FALSE])
}))
}
forall(
gen_df_and_remove_row(4, 6),
both_terminate_then(expect_det_subsets_kept, 1, method = "DFD"),
curry = TRUE
)
forall(
gen_df_and_remove_row(4, 6),
both_terminate_then(expect_det_subsets_kept, 1, method = "FDHitsSep"),
curry = TRUE
)
forall(
gen_df_and_remove_row(4, 6),
both_terminate_then(expect_det_subsets_kept, 1, method = "FDHitsJoint"),
curry = TRUE
)
})
it("is commutative with changing attribute names", {
gen_df_and_name_change <- function(nrow, ncol, remove_dup_rows = FALSE) {
gen_df(nrow, ncol, minrow = 1L, mincol = 1L, remove_dup_rows) |>
gen.and_then(\(df) list(df, gen.sample(LETTERS, ncol(df)))) |>
gen.with(uncurry(\(df, new_names) {
list(df, stats::setNames(df, new_names))
}))
}
forall(
gen_df_and_name_change(4, 6),
both_terminate_then(expect_equiv_deps_except_names, 1, method = "DFD"),
curry = TRUE
)
forall(
gen_df_and_name_change(4, 6),
both_terminate_then(expect_equiv_deps_except_names, 1, method = "FDHitsSep"),
curry = TRUE
)
forall(
gen_df_and_name_change(4, 6),
both_terminate_then(expect_equiv_deps_except_names, 1, method = "FDHitsJoint"),
curry = TRUE
)
})
it("is invariant to an attribute's values being permuted", {
gen_perm <- function(vals) {
indices <- lookup_indices(vals)
uniq <- unique(indices)
matches <- match(indices, uniq)
gen.sample(uniq, length(uniq)) |>
gen.with(\(perm) perm[matches])
}
gen_df_and_value_perm <- function(
nrow,
ncol,
remove_dup_rows = FALSE
) {
gen_df(nrow, ncol, minrow = 1L, mincol = 1L, remove_dup_rows) |>
gen.and_then(\(df) list(gen.pure(df), gen.int(ncol(df)))) |>
gen.and_then(uncurry(\(df, attr) list(
gen.pure(df),
gen.pure(attr),
gen_perm(df[[attr]])
))) |>
gen.with(uncurry(\(df, attr, perm) {
permed <- df
permed[, attr] <- permed[perm, attr, drop = FALSE]
list(df, permed)
}))
}
forall(
gen_df_and_value_perm(4, 6),
both_terminate_then(expect_equiv_deps, 1, method = "DFD"),
curry = TRUE
)
forall(
gen_df_and_value_perm(4, 6),
both_terminate_then(expect_equiv_deps, 1, method = "FDHitsSep"),
curry = TRUE
)
forall(
gen_df_and_value_perm(4, 6),
both_terminate_then(expect_equiv_deps, 1, method = "FDHitsJoint"),
curry = TRUE
)
})
it("is invariant to an attribute's class being losslessly changed", {
forall(
gen_df_and_type_change(4, 6),
both_terminate_then(expect_equiv_deps, 1, method = "DFD"),
curry = TRUE
)
forall(
gen_df_and_type_change(4, 6),
both_terminate_then(expect_equiv_deps, 1, method = "FDHitsSep"),
curry = TRUE
)
forall(
gen_df_and_type_change(4, 6),
both_terminate_then(expect_equiv_deps, 1, method = "FDHitsJoint"),
curry = TRUE
)
})
it("is invariant to attributes being reordered, except for attrs_order", {
gen_df_and_attr_perm <- function(
nrow,
ncol,
remove_dup_rows = FALSE
) {
gen_df(nrow, ncol, minrow = 1L, mincol = 1L, remove_dup_rows) |>
gen.and_then(\(df) list(
gen.pure(df),
gen.sample(seq_along(df), size = ncol(df))
)) |>
gen.with(uncurry(\(df, perm) {
list(df, df[, perm, drop = FALSE])
}))
}
forall(
gen_df_and_attr_perm(4, 6),
both_terminate_then(expect_equiv_deps, 1, method = "DFD"),
curry = TRUE
)
forall(
gen_df_and_attr_perm(4, 6),
both_terminate_then(expect_equiv_deps, 1, method = "FDHitsSep"),
curry = TRUE
)
forall(
gen_df_and_attr_perm(4, 6),
both_terminate_then(expect_equiv_deps, 1, method = "FDHitsJoint"),
curry = TRUE
)
})
it("is invariant to changes of accuracy within same required row count when using DFD", {
gen_df_and_accuracy_nrow <- function(nrow, ncol, remove_dup_rows = FALSE) {
gen_df(nrow, ncol, minrow = 1L, mincol = 1L, remove_dup_rows) |>
gen.and_then(\(df) list(df, gen.int(nrow(df)))) |>
gen.with(uncurry(\(df, n) {
prop <- n/nrow(df)
low <- (n - 1)/nrow(df) + 1e-9
list(df, low, prop)
}))
}
both_bounds_terminate_then <- function(fn, ...) {
function(df, low, high) {
res1 <- with_timeout(discover(df, accuracy = low, ...))
if (is.null(res1))
return(fail("discover() with lower accuracy timed out"))
res2 <- with_timeout(discover(df, accuracy = high, ...))
if (is.null(res2))
return(fail("discover() with higher accuracy timed out"))
fn(res1, res2)
}
}
forall(
gen_df_and_accuracy_nrow(4, 6),
both_bounds_terminate_then(expect_equiv_deps, method = "DFD"),
curry = TRUE
)
})
it(
paste(
"is invariant to:",
"- having a non-false keep_rownames vs. adding row names as first column",
"- method used (if accuracy = 1)",
"- excluding a class vs. excluding attributes in that class vs. subsetting results",
"- filtering by dependants/detset_limit vs. by subsetting results",
"- whether stripped partitions or their sizes are cached",
"- whether partition is transferred between dependants",
"- whether bijections are skipped (if accuracy = 1)",
sep = "\n"
),
{
expect_invariant_to_input_options <- function(
df,
accuracy,
keep_rownames,
dependants,
detset_limit
) {
logical_cols <- names(df)[vapply(df, inherits, logical(1), "logical")]
arglists <- expand.grid(
if (isFALSE(keep_rownames))
list(list(df = df, keep_rownames = FALSE))
else{
tmp <- if (isTRUE(keep_rownames)) "row" else keep_rownames
nm <- make.unique_after(tmp, names(df))
list(
list(df = df, keep_rownames = nm),
list(
df = cbind(setNames(data.frame(rownames(df)), nm), df),
keep_rownames = FALSE
)
)
},
list(list(accuracy = accuracy)),
c(
list(list(method = "DFD")),
if (accuracy == 1)
list(list(method = "FDHitsSep"), list(method = "FDHitsJoint"))
),
list(
list(),
list(exclude_class = "logical"),
list(exclude = logical_cols)
),
list(
list(),
list(dependants = dependants)
),
list(
list(),
list(detset_limit = detset_limit)
),
list(
list(full_cache = FALSE),
list(full_cache = TRUE)
),
list(
list(store_cache = FALSE),
list(store_cache = TRUE)
),
c(
list(list(skip_bijections = FALSE)),
if (accuracy == 1) list(list(skip_bijections = TRUE))
)
) |>
unname() |>
apply(1, \(x) do.call(c, x), simplify = FALSE)
results <- lapply(
arglists,
\(lst) {
base <- with_timeout(do.call(discover, lst))
if (is.null(base))
return(base)
if (is.null(lst[["exclude"]]) && is.null(lst[["exclude_class"]]))
base <- base[vapply(
detset(base),
Negate(is.element %>>% any),
logical(1),
el = logical_cols
)]
if (is.null(lst[["dependants"]]))
base <- base[dependant(base) %in% dependants]
if (is.null(lst[["detset_limit"]]))
base <- base[lengths(detset(base)) <= detset_limit]
base
}
)
if (any(vapply(results, is.null, logical(1))))
return(fail("some argument lists time out"))
expect_true(all(vapply(results, fds_equivalent, logical(1), results[[1]])))
}
forall(
gen_df(4, 6) |>
gen.and_then(\(x) {
list(
gen.pure(x),
gen.choice(gen.pure(1), gen.unif(0, 1), prob = c(80, 20)),
gen.choice(
gen.element(c(FALSE, TRUE)),
gen_attr_name(9) |>
gen.with(\(nm) make.unique_after(nm, names(x)))
),
gen.sample_resampleable(names(x), from = 0, to = ncol(x)),
gen.element(0:(ncol(x) - 1L))
)
}),
expect_invariant_to_input_options,
curry = TRUE
)
}
)
})
describe("lookup_table", {
it("works", {
forall(
gen_df(6, 7),
lookup_table %>>% expect_no_error
)
})
it("returns a data frame with same duplicated() output", {
forall(
gen_df(6, 7),
expect_biidentical(lookup_table %>>% duplicated, df_duplicated)
)
})
it("distinguishes between matchables in list columns", {
NA_example <- data.frame(a = rep(1:2, 2))
NA_example$b <- list(NA_integer_, NA_integer_, NA_real_, NA_real_)
expect_identical(anyDuplicated(lookup_table(NA_example)), 0L)
number_example <- data.frame(a = rep(1:2, 2))
number_example$b <- list(1L, 2L, 1, 2)
expect_identical(anyDuplicated(lookup_table(number_example)), 0L)
})
})
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.