Nothing
# Copyright (c) 2020-2023 Nuno Fachada
# Distributed under the MIT License (http://opensource.org/licenses/MIT)
# ################################## #
# Test clugen() mandatory parameters #
# ################################## #
# Create parameter combinations to test
targs <- expand.grid(seed = seeds, nd = num_dims,
nclu = num_clusters,
tpts = num_points,
astd = angles_stds,
len = llengths_mus,
len_std = llengths_sigmas,
lat_std = lat_stds)
# Loop through all parameter combinations
for (i in seq.int(1, nrow(targs))) {
# Get current parameters
seed <- targs[i, "seed"]
nd <- targs[i, "nd"]
nclu <- targs[i, "nclu"]
tpts <- targs[i, "tpts"]
astd <- targs[i, "astd"]
len <- targs[i, "len"]
len_std <- targs[i, "len_std"]
lat_std <- targs[i, "lat_std"]
# Set seed
set.seed(seed)
# Create combination of seed-depending parameters (line directions + clu seps)
tsargs <- expand.grid(direc = append(asplit(get_vecs(ndirs, nd), 1),
list(matrix(rnorm(nclu * nd),
ncol = nd))),
clusep = asplit(get_clu_seps(nd), 1))
# Loop through line directions and line centers
for (j in seq.int(1, nrow(tsargs))) {
# Get current line direction + line center
direc <- tsargs[j, "direc"][[1]]
clusep <- tsargs[j, "clusep"][[1]]
# Determine test name for current parameter set
test_desc <- paste0("clugen mandatory params: ",
"seed=", seed, ", nd=", nd, ", nclu=", nclu,
", tpts=", tpts, ", astd=", astd, ", len=", len,
", len_std=", len_std, ", lat_std=", lat_std,
", direc=[", paste(direc, collapse = ", "),
"], clusep=[", paste(clusep, collapse = ", "), "]")
# Perform tests for current parameter set
test_that(test_desc, {
# By default, allow_empty is false, so clugen() must be given more points
# than clusters...
if (tpts >= nclu) {
# ...in which case it runs without problem
expect_warning(r <- clugen(nd, nclu, tpts, direc, astd,
clusep, len, len_std, lat_std),
regexp = NA)
# Check dimensions of result variables
expect_equal(dim(r$points), c(tpts, nd))
expect_equal(length(r$clusters), tpts)
expect_equal(dim(r$projections), c(tpts, nd))
expect_equal(length(r$sizes), nclu)
expect_equal(dim(r$centers), c(nclu, nd))
expect_equal(dim(r$directions), c(nclu, nd))
expect_equal(length(r$angles), nclu)
expect_equal(length(r$lengths), nclu)
# Check point cluster indexes
expect_equal(unique(as.numeric(r$clusters)), 1:nclu)
# Check total points
expect_equal(sum(r$sizes), tpts)
# Check that cluster directions have the correct angles with the main
# direction
if (nd > 1) {
# In case direction is just a vector, repeat it num_cluster times
# into a matrix...
if (is.vector(direc)
|| (is.array(direc) && length(dim(direc)) == 1)) {
direc <- matrix(direc,
nrow = nclu,
ncol = length(direc),
byrow = TRUE)
}
# ...so we can check each cluster direction separately
for (i in 1:nclu) {
expect_equal(angle_btw(direc[i, ], r$directions[i, ]),
abs(r$angles[i]))
}
}
} else {
# ...otherwise an error will be thrown
expect_error(r <- clugen(nd, nclu, tpts, direc, astd,
clusep, len, len_std, lat_std),
paste("A total of", tpts, "points is not enough for", nclu,
"non-empty clusters"))
}
})
}
}
# ################################# #
# Test clugen() optional parameters #
# ################################# #
# Valid arguments
nclu <- 7
tpts <- 500
astd <- pi / 256
len_mu <- 9
len_std <- 1.2
lat_std <- 2
# Alternative functions used for testing
prjdist_equi <- function(l, n) seq(from = -l / 2, to = l / 2, length.out = n)
ptdist_projs_plus_1 <- function(projs, ls, l, cd, cc) projs + 1
csz_equi <- function(nclu, tpts, ae) {
cs <- vector(mode = "integer", length = nclu)
for (i in 1:tpts) {
cs[i %% nclu + 1] <- cs[i %% nclu + 1] + 1
}
cs
}
cctr_on_a_line <- function(nclu, cs, co) {
1:nclu * matrix(0, nrow = nclu, ncol = length(cs))
}
llen_unif_10_20 <- function(nclu, l, lsd) stats::runif(nclu, min = 10, max = 20)
lang_same <- function(nclu, astd) vector(mode = "double", length = nclu)
# Create parameter combinations to test
if (testthat:::on_cran() || is_test_mode("cran")) {
# Light tests, for CRAN
targs <- expand.grid(seed = seeds, nd = 2, ae = TRUE,
prjdist_fn = list("norm", "unif"),
ptdist_fn = list("n-1", "n"),
csz_fn = list(clusizes),
cctr_fn = list(clucenters),
llen_fn = list(llengths),
lang_fn = list(angle_deltas))
} else {
# Other testing modes will be more thorough
targs <- expand.grid(seed = seeds, nd = c(2, 7), ae = allow_empties,
prjdist_fn = list("norm", "unif", prjdist_equi),
ptdist_fn = list("n-1", "n", ptdist_projs_plus_1),
csz_fn = list(clusizes, csz_equi),
cctr_fn = list(clucenters, cctr_on_a_line),
llen_fn = list(llengths, llen_unif_10_20),
lang_fn = list(angle_deltas, lang_same))
}
# Loop through all parameter combinations
for (i in seq.int(1, nrow(targs))) {
# Get current parameters
seed <- targs[i, "seed"]
nd <- targs[i, "nd"]
ae <- targs[i, "ae"]
prjdist_fn <- targs[i, "prjdist_fn"][[1]]
ptdist_fn <- targs[i, "ptdist_fn"][[1]]
csz_fn <- targs[i, "csz_fn"][[1]]
cctr_fn <- targs[i, "cctr_fn"][[1]]
llen_fn <- targs[i, "llen_fn"][[1]]
lang_fn <- targs[i, "lang_fn"][[1]]
# Set seed
set.seed(seed)
# Create combination of seed-depending parameters (line directions + clu seps)
tsargs <- expand.grid(direc = asplit(get_vecs(ndirs, nd), 1),
clusep = asplit(get_clu_seps(nd), 1))
# Loop through line directions and line centers
for (j in seq.int(1, nrow(tsargs))) {
# Get current line direction + line center
direc <- tsargs[j, "direc"][[1]]
clusep <- tsargs[j, "clusep"][[1]]
# Determine test name for current parameter set
test_desc <- paste0("clugen optional params: ",
"seed = ", seed, ", nd=", nd, ", nclu=", nclu,
", tpts=", tpts, "ae=", ae,
", ptdist_fn='",
format(prjdist_fn)[length(format(prjdist_fn))],
"', ptoff_fn='",
format(ptdist_fn)[length(format(ptdist_fn))],
"', czn_fn='",
format(csz_fn)[length(format(csz_fn))],
"'",
"', cctr_fn='",
format(cctr_fn)[length(format(cctr_fn))],
"'",
"', llen_fn='",
format(llen_fn)[length(format(llen_fn))],
"'",
"', lang_fn='",
format(lang_fn)[length(format(lang_fn))],
"'")
# Perform tests for current parameter set
test_that(test_desc, {
# ...in which case it runs without problem
expect_warning(r <- clugen(nd, nclu, tpts, direc, astd,
clusep, len_mu, len_std, lat_std,
allow_empty = ae,
proj_dist_fn = prjdist_fn,
point_dist_fn = ptdist_fn,
clusizes_fn = csz_fn,
clucenters_fn = cctr_fn,
llengths_fn = llen_fn,
angle_deltas_fn = lang_fn,
seed = seed),
regexp = NA)
# Check dimensions of result variables
expect_equal(dim(r$points), c(tpts, nd))
expect_equal(length(r$clusters), tpts)
expect_equal(dim(r$projections), c(tpts, nd))
expect_equal(length(r$sizes), nclu)
expect_equal(dim(r$centers), c(nclu, nd))
expect_equal(dim(r$directions), c(nclu, nd))
expect_equal(length(r$angles), nclu)
expect_equal(length(r$lengths), nclu)
# Check point cluster indexes
if (!ae) {
expect_equal(unique(as.numeric(r$clusters)), 1:nclu)
} else {
expect_true(all(as.numeric(r$clusters) <= nclu))
}
# Check total points
expect_equal(sum(r$sizes), tpts)
# This might not be the case if the specified clusize_fn does not obey
# the total number of points
# Check that cluster directions have the correct angles with the main
# direction
if (nd > 1) {
for (i in 1:nclu) {
expect_equal(angle_btw(direc, r$directions[i, ]),
abs(r$angles[i]))
}
}
})
}
}
# ######################################## #
# Test clugen() optional direct parameters #
# ######################################## #
# Valid arguments
astd <- pi / 333
len_mu <- 6
len_std <- 1.1
lat_std <- 1.6
# Create parameter combinations to test
if (testthat:::on_cran() || is_test_mode("cran")) {
# Light tests, for CRAN
targs <- expand.grid(seed = seeds, nd = 2, nclu = 6)
} else {
# Other testing modes will be more thorough
targs <- expand.grid(seed = seeds, nd = c(1, 5), nclu = c(1, 6))
}
# Loop through all parameter combinations
for (i in seq.int(1, nrow(targs))) {
# Get current parameters
seed <- targs[i, "seed"]
nd <- targs[i, "nd"]
nclu <- targs[i, "nclu"]
# Set seed
set.seed(seed)
# Create combination of seed-depending parameters
direc <- rnorm(nd)
clusep <- 100 * rnorm(nd)
csz_direct <- sample(1:100, nclu, replace = TRUE)
cctr_direct <- matrix(100 * rnorm(nd * nclu), nrow = nclu)
llen_direct <- runif(nclu, min = 0, max = 100)
lang_direct <- runif(nclu, min = -pi / 2, max = pi / 2)
tpts <- sum(csz_direct)
# Determine test name for current parameter set
test_desc <- paste0("clugen optional params (direct): ",
"seed = ", seed, ", nd=", nd, ", nclu=", nclu,
", direc=[", paste(direc, collapse = ", "),
", clusep=[", paste(clusep, collapse = ", "),
", csz_direct=[", paste(csz_direct, collapse = ", "),
", cctr_direct=[", paste(cctr_direct, collapse = ", "),
", llen_direct=[", paste(llen_direct, collapse = ", "),
", lang_direct=[", paste(lang_direct, collapse = ", "))
# Perform tests for current parameter set
test_that(test_desc, {
# ...in which case it runs without problem
expect_warning(r <- clugen(nd, nclu, tpts, direc, astd,
clusep, len_mu, len_std, lat_std,
allow_empty = ae,
clusizes_fn = csz_direct,
clucenters_fn = cctr_direct,
llengths_fn = llen_direct,
angle_deltas_fn = lang_direct,
seed = seed),
regexp = NA)
# Check dimensions of result variables
expect_equal(dim(r$points), c(tpts, nd))
expect_equal(length(r$clusters), tpts)
expect_equal(dim(r$projections), c(tpts, nd))
expect_equal(length(r$sizes), nclu)
expect_equal(dim(r$centers), c(nclu, nd))
expect_equal(dim(r$directions), c(nclu, nd))
expect_equal(length(r$angles), nclu)
expect_equal(length(r$lengths), nclu)
# Check point cluster indexes
if (!ae) {
expect_equal(unique(as.numeric(r$clusters)), 1:nclu)
} else {
expect_true(all(as.numeric(r$clusters) <= nclu))
}
# Check total points
expect_equal(sum(r$sizes), tpts)
# This might not be the case if the specified clusize_fn does not obey
# the total number of points
# Check that cluster directions have the correct angles with the main
# direction
if (nd > 1) {
for (i in 1:nclu) {
expect_equal(angle_btw(direc, r$directions[i, ]),
abs(r$angles[i]))
}
}
})
}
# ##################### #
# Reproducibility tests #
# ##################### #
# Valid parameters
nd <- 2
nclu <- 4
tpts <- 300
direc <- c(1, 1)
astd <- pi / 64
clusep <- c(7, 6.5)
len_mu <- 4.1
len_std <- 0.5
lat_std <- 0.2
for (seed in seeds) {
test_that(paste0("clugen reproducibility: seed=", seed), {
# Get results for run 1 with current seed
expect_warning(r1 <- clugen(nd, nclu, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
seed = seed),
regexp = NA)
# Get results for run 2 with current seed
expect_warning(r2 <- clugen(nd, nclu, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
seed = seed),
regexp = NA)
# Check that results are exactly the same
expect_equal(r1, r2)
})
}
# ######################## #
# Test clugen() exceptions #
# ######################## #
for (seed in seeds) {
# Valid parameters
nd <- 3
nclu <- 5
tpts <- 1000
direc <- c(1, 0, 0)
astd <- pi / 64
clusep <- c(10, 10, 5)
len_mu <- 5
len_std <- 0.5
lat_std <- 0.3
ae <- TRUE
clu_off <- c(-1.5, 0, 2)
prj_dist <- "unif"
pt_dist <- "n-1"
csizes_fn <- clusizes
ccenters_fn <- clucenters
llengths_fn <- llengths
langles_fn <- angle_deltas
test_that(paste0("clugen exceptions: seed=", seed), {
# Test passes with valid arguments
expect_warning(r <- clugen(nd, nclu, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = NA)
# Test passes with zero points since allow_empty is set to true
expect_warning(r <- clugen(nd, nclu, 0, direc, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = NA)
# Invalid number of dimensions
expect_error(r <- clugen(0, nclu, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = "Number of dimensions, `num_dims`, must be > 0",
fixed = TRUE)
# Invalid number of clusters
expect_error(r <- clugen(nd, 0, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = "Number of clusters, `num_clust`, must be > 0",
fixed = TRUE)
# Direction needs to have magnitude > 0
expect_error(r <- clugen(nd, nclu, tpts, c(0, 0, 0), astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = "`direction` must have magnitude > 0",
fixed = TRUE)
# Direction needs to have nd dims
bad_dir <- c(1, 1)
expect_error(r <- clugen(nd, nclu, tpts, bad_dir, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = paste0("Length of directions in `direction` must be ",
"equal to `num_dims` (",
length(bad_dir), " != ", nd, ")"),
fixed = TRUE)
# Specific direction for each cluster requires one direction per cluster
expect_error(r <- clugen(nd, nclu, tpts,
# but we're passing one extra direction
matrix(rnorm(nd * (nclu + 1)), ncol = nd),
astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = paste0("Number of rows in `direction` must be the ",
"same as the number of clusters (",
nclu + 1, " != ", nclu, ")"),
fixed = TRUE)
# Direction needs to be a 1D array (vector) or 2D array (matrix)
expect_error(r <- clugen(nd, nclu, tpts,
# but we're passing a 3D array
array(rnorm(nd * nclu * 2), c(nd, nclu, 2)),
astd, clusep, len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = paste0("`direction` must be a vector (1D array) ",
"or a matrix (2D array)"),
fixed = TRUE)
# cluster_sep needs to have nd dims
bad_clusep <- c(10, 10)
expect_error(r <- clugen(nd, nclu, tpts, direc, astd,
bad_clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = paste0("Length of `cluster_sep` must be equal to ",
"`num_dims` (",
length(bad_clusep), " != ", nd, ")"),
fixed = TRUE)
# cluster_offset needs to have nd dims
bad_cluoff <- c(0, 1)
expect_error(r <- clugen(nd, nclu, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = bad_cluoff,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = paste0("Length of `cluster_offset` must be equal to ",
"`num_dims` (",
length(bad_cluoff), " != ", nd, ")"),
fixed = TRUE)
# Unknown proj_dist_fn given as string
expect_error(r <- clugen(nd, nclu, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = "invalid",
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = paste0("`proj_dist_fn` has to be either \"norm\", ",
"\"unif\" or user-defined function"),
fixed = TRUE)
# Invalid proj_dist_fn given as function
expect_error(r <- clugen(nd, nclu, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = csizes_fn,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
"argument")
# Unknown point_dist_fn given as string
expect_error(r <- clugen(nd, nclu, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = "invalid",
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = paste0("point_dist_fn has to be either \"n-1\",",
" \"n\" or a user-defined function"),
fixed = TRUE)
# Invalid point_dist_fn given as function
expect_error(r <- clugen(nd, nclu, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = llengths_fn,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = "argument")
# Invalid direct clusizes
expect_error(r <- clugen(nd, nclu, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = sample(1:(tpts * nclu), nclu + 1),
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = paste0("`clusizes_fn` has to be either a function or",
" a `num_clusters`-sized vector"),
fixed = TRUE)
# Invalid direct clucenters
expect_error(r <- clugen(nd, nclu, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = matrix(rnorm(nd * (nclu + 1)),
nrow = nclu + 1),
llengths_fn = llengths_fn,
angle_deltas_fn = langles_fn,
seed = seed),
regexp = paste0("clucenters_fn has to be either a function or",
" a matrix of size `num_clusters` x `num_dims`"),
fixed = TRUE)
# Invalid direct llengths
expect_error(r <- clugen(nd, nclu, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = runif(nclu + 1),
angle_deltas_fn = langles_fn,
seed = seed),
regexp = paste0("`llengths_fn` has to be either a function or",
" a `num_clusters`-sized vector"),
fixed = TRUE)
# Invalid direct langles
expect_error(r <- clugen(nd, nclu, tpts, direc, astd, clusep,
len_mu, len_std, lat_std,
allow_empty = ae,
cluster_offset = clu_off,
proj_dist_fn = prj_dist,
point_dist_fn = pt_dist,
clusizes_fn = csizes_fn,
clucenters_fn = ccenters_fn,
llengths_fn = llengths_fn,
angle_deltas_fn = runif(nclu + 1),
seed = seed),
regexp = paste0("`angle_deltas_fn` has to be either a function",
" or a `num_clusters`-sized vector"),
fixed = TRUE)
})
}
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.