From 97bb725b39130eac9b4e492742a84f57ff61c9d8 Mon Sep 17 00:00:00 2001 From: Steve Martin Date: Tue, 14 Jul 2026 21:30:30 -0400 Subject: [PATCH 1/2] Now using tinytest --- DESCRIPTION | 7 ++-- NEWS.md | 6 +++ R/expected_coverage.R | 3 +- R/inclusion_prob.R | 13 +++---- R/prop_allocation.R | 19 ++++----- R/sps.R | 24 +++++++----- R/sps_iterator.R | 11 +++--- R/sps_repweights.R | 28 ++++++------- .../tinytest}/test-inclusion_prob.R | 33 ++++++++++------ .../tinytest}/test-prop_allocation.R | 27 ++++++++----- {tests/testthat => inst/tinytest}/test-sps.R | 39 ++++++++++++------- .../tinytest}/test-sps_iterator.R | 23 ++++++----- .../tinytest}/test-sps_repweights.R | 21 ++++++---- man/expected_coverage.Rd | 16 ++++---- man/inclusion_prob.Rd | 17 ++++---- man/prop_allocation.Rd | 20 +++++----- man/sps-package.Rd | 5 +++ man/sps.Rd | 24 +++++++----- man/sps_iterator.Rd | 16 ++++---- man/sps_repweights.Rd | 22 ++++++----- tests/testthat.R | 12 ------ tests/tinytest.R | 5 +++ vignettes/take-all.qmd | 2 +- 23 files changed, 230 insertions(+), 163 deletions(-) rename {tests/testthat => inst/tinytest}/test-inclusion_prob.R (91%) rename {tests/testthat => inst/tinytest}/test-prop_allocation.R (94%) rename {tests/testthat => inst/tinytest}/test-sps.R (91%) rename {tests/testthat => inst/tinytest}/test-sps_iterator.R (72%) rename {tests/testthat => inst/tinytest}/test-sps_repweights.R (88%) delete mode 100644 tests/testthat.R create mode 100644 tests/tinytest.R diff --git a/DESCRIPTION b/DESCRIPTION index a455941..e39e30e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: sps Title: Sequential Poisson Sampling -Version: 0.6.3 +Version: 0.6.3.9001 Authors@R: c( person("Steve", "Martin", role = c("aut", "cre", "cph"), @@ -23,12 +23,11 @@ Suggests: kit (>= 0.0.10), knitr, quarto, - testthat (>= 3.0.0) -Config/testthat/edition: 3 + tinytest License: MIT + file LICENSE Encoding: UTF-8 URL: https://marberts.github.io/sps/, https://github.com/marberts/sps BugReports: https://github.com/marberts/sps/issues VignetteBuilder: quarto Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.3 +Config/roxygen2/version: 8.0.0 diff --git a/NEWS.md b/NEWS.md index 1d356ca..e097823 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +## sps (development version) + +- Small improvements to the documentation. + +- Now using `{tinytest}`. + ## sps 0.6.3 - Extra arguments to `sps_iterator()` now work correctly (#9). diff --git a/R/expected_coverage.R b/R/expected_coverage.R index fe3355d..d15d3d0 100644 --- a/R/expected_coverage.R +++ b/R/expected_coverage.R @@ -10,7 +10,7 @@ #' enterprises covered within a stratum when sampling business establishments. #' #' @inheritParams sps -#' @param n A positive integer giving the sample size. +#' @param n `[integer(1) >= 0]` A positive integer giving the sample size. #' #' @returns #' The expected number of strata covered by the sample design. @@ -27,7 +27,6 @@ #' #' # Should get about 7 to 8 strata in a sample on average #' expected_coverage(x, 15, s) -#' #' @export expected_coverage <- function(x, n, strata, alpha = 1e-3, cutoff = Inf) { x <- as.numeric(x) diff --git a/R/inclusion_prob.R b/R/inclusion_prob.R index f6d112f..4f222df 100644 --- a/R/inclusion_prob.R +++ b/R/inclusion_prob.R @@ -52,7 +52,6 @@ #' # Use the inclusion probabilities to calculate the variance of the #' # sample size for Poisson sampling #' sum(pi * (1 - pi)) -#' #' @export inclusion_prob <- function(x, n, strata = NULL, alpha = 1e-3, cutoff = Inf) { x <- as.numeric(x) @@ -78,12 +77,12 @@ becomes_ta <- function(x, alpha = 1e-3, cutoff = Inf) { alpha <- as.numeric(alpha) if (alpha < 0 || alpha > 1) { - stop("'alpha' must be between 0 and 1") + stop("`alpha` must be between 0 and 1") } cutoff <- as.numeric(cutoff) if (cutoff <= 0) { - stop("'cutoff' must be greater than 0") + stop("`cutoff` must be greater than 0") } alpha <- alpha + .Machine$double.eps^0.5 @@ -158,10 +157,10 @@ pi <- function(x, n, alpha, cutoff) { ) } if (alpha < 0 || alpha > 1) { - stop("'alpha' must be between 0 and 1") + stop("`alpha` must be between 0 and 1") } if (cutoff <= 0) { - stop("'cutoff' must be greater than 0") + stop("`cutoff` must be greater than 0") } # Add some fuzz to avoid floating-point rounding stopping some units from @@ -192,10 +191,10 @@ stratified_pi <- function(x, n, strata, alpha, cutoff) { stop("there must be a single sample size for each stratum") } if (length(alpha) != 1L && length(alpha) != nlevels(strata)) { - stop("'alpha' must be a single value or have a value for each stratum") + stop("`alpha` must be a single value or have a value for each stratum") } if (length(cutoff) != 1L && length(cutoff) != nlevels(strata)) { - stop("'cutoff' must be a single value or have a value for each stratum") + stop("`cutoff` must be a single value or have a value for each stratum") } Map(pi, split(x, strata), n, alpha, cutoff) } diff --git a/R/prop_allocation.R b/R/prop_allocation.R index 471d8cd..423d7fe 100644 --- a/R/prop_allocation.R +++ b/R/prop_allocation.R @@ -39,20 +39,22 @@ #' ensures that the initial allocation is feasible. #' #' @inheritParams sps -#' @param n A positive integer giving the sample size. -#' @param initial A positive integer vector giving the initial (or minimal) +#' @param n `[integer(1) >= 0]` A positive integer giving the sample size. +#' @param initial `[integer >= 0]` A positive integer vector giving the initial +#' (or minimal) #' allocation for each stratum, ordered according to the levels of #' `strata`. A single integer is recycled for each stratum using a special #' algorithm to ensure a feasible allocation; see details. Non-integers are #' truncated towards 0. The default allows for no units to be allocated to a #' stratum. -#' @param divisor A function for the divisor (highest-averages) +#' @param divisor `[function]` A function for the divisor (highest-averages) #' apportionment method. The default uses the Jefferson/D'Hondt method. See #' details for other possible functions. -#' @param ties Either 'largest' to break ties in favor of the stratum with the +#' @param ties `[character(1)]` Either 'largest' to break ties in favor of the +#' stratum with the #' largest size (the default), or 'first' to break ties in favor of the #' ordering of `strata`. -#' @param name Name of the divisor function. See details. +#' @param name `[character(1)]` Name of the divisor function. See details. #' #' @returns #' `prop_allocation()` returns a named integer vector of sample sizes for each @@ -83,7 +85,6 @@ #' #' # Generate an allocation #' prop_allocation(x, 15, s, initial = 1) -#' #' @export prop_allocation <- function( x, @@ -148,20 +149,20 @@ divisor_method <- function( "Imperiali" = \(a) a + 2, "Huntington-Hill" = \(a) { if (any(a < 1)) { - stop("'a' must be greater than or equal to 1") + stop("`a` must be greater than or equal to 1") } sqrt(a * (a + 1)) }, "Danish" = \(a) a + 1 / 3, "Adams" = \(a) { if (any(a < 1)) { - stop("'a' must be greater than or equal to 1") + stop("`a` must be greater than or equal to 1") } a }, "Dean" = \(a) { if (any(a < 1)) { - stop("'a' must be greater than or equal to 1") + stop("`a` must be greater than or equal to 1") } a * (a + 1) / (a + 0.5) } diff --git a/R/sps.R b/R/sps.R index 4f20bbc..acc1fad 100644 --- a/R/sps.R +++ b/R/sps.R @@ -136,29 +136,34 @@ stratify <- function(f) { #' \item{Pareto sampling}{`\(x) x / (1 - x)`} #' } #' -#' @param x A positive and finite numeric vector of sizes for units in the -#' population (e.g., revenue for drawing a sample of businesses). -#' @param n A positive integer vector giving the sample size for each stratum, +#' @param x `[numeric >= 0]` A positive and finite numeric vector of sizes for +#' units in the population (e.g., revenue for drawing a sample of businesses). +#' @param n `[integer >= 0]` A positive integer vector giving the sample size +#' for each stratum, #' ordered according to the levels of `strata`. A single value is recycled #' for all strata. Non-integers are truncated towards 0. -#' @param strata A factor, or something that can be coerced into one, giving +#' @param strata `[factor]` A factor, or something that can be coerced into one, +#' giving #' the strata associated with units in the population. The default is to place #' all units into a single stratum. -#' @param prn A numeric vector of permanent random numbers for units in the +#' @param prn `[0 < numeric < 1]` A numeric vector of permanent random numbers +#' for units in the #' population, distributed uniform between 0 and 1. The default does not use #' permanent random numbers, instead generating a random vector when the #' function is called. -#' @param alpha A numeric vector with values between 0 and 1 for each stratum, +#' @param alpha `[0 <= numeric < 1]` A numeric vector with values between 0 and +#' 1 for each stratum, #' ordered according to the levels of `strata`. Units with inclusion #' probabilities greater than or equal to 1 - `alpha` are set to 1 for #' each stratum. A single value is recycled for all strata. The default is #' slightly larger than 0. -#' @param cutoff A positive numeric vector of cutoffs for each stratum, ordered +#' @param cutoff `[numeric >= 0]` A positive numeric vector of cutoffs for each +#' stratum, ordered #' according to the levels of `strata`. Units with `x >= cutoff` get #' an inclusion probability of 1 for each stratum. A single value is recycled #' for all strata. The default does not apply a cutoff. -#' @param dist A function giving the fixed order distribution shape for an order -#' sampling scheme. See details. +#' @param dist `[function]` A function giving the fixed order distribution shape +#' for an order sampling scheme. See details. #' #' @returns #' `sps()` and `ps()` return an object of class `sps_sample`. @@ -273,7 +278,6 @@ stratify <- function(f) { #' order_sampling2(1)(x, 6, prn = u) # sequential Poisson #' order_sampling2(0)(x, 6, prn = u) # successive #' order_sampling2(-1)(x, 6, prn = u) # Pareto -#' #' @export sps <- stratify(order_sampling_(identity)) diff --git a/R/sps_iterator.R b/R/sps_iterator.R index 79663bf..80a56ad 100644 --- a/R/sps_iterator.R +++ b/R/sps_iterator.R @@ -4,12 +4,13 @@ #' sequential Poisson method without replacing previously sampled units. #' #' @inheritParams sps -#' @param n A positive integer giving the initial sample size for the iterator. -#' @param alpha A number between 0 and 1. Units with +#' @param n `[integer(1) >= 0]` A positive integer giving the initial sample +#' size for the iterator. The default is 0. +#' @param alpha `[0 <= numeric(1) < 1]` A number between 0 and 1. Units with #' inclusion probabilities greater than or equal to 1 - `alpha` are set to 1. #' The default is slightly larger than 0. -#' @param cutoff A numeric cutoff. Units with `x >= cutoff` get -#' an inclusion probability of 1. The default does not apply a cutoff. +#' @param cutoff `[numeric(1) >= 0]` A numeric cutoff. Units with `x >= cutoff` +#' get an inclusion probability of 1. The default does not apply a cutoff. #' #' @returns #' A function that returns the next unit in the sample. It take a single @@ -37,7 +38,7 @@ sps_iterator <- function(x, n = 0L, prn = NULL, alpha = 0.001, cutoff = Inf) { prn <- as.numeric(prn) } if (length(x) != length(prn)) { - stop("'x' and 'prn' must be the same length") + stop("`x` and `prn` must be the same length") } s <- order(prn / x) diff --git a/R/sps_repweights.R b/R/sps_repweights.R index 9ad7107..7938581 100644 --- a/R/sps_repweights.R +++ b/R/sps_repweights.R @@ -23,17 +23,19 @@ #' becomes \eqn{(a + \tau - 1) / \tau}. If \eqn{\tau > 1} then the resulting #' bootstrap variance estimator should be multiplied by \eqn{\tau^2}. #' -#' @param w A numeric vector of design (inverse probability) weights for a -#' (sequential) Poisson sample. -#' @param replicates A positive integer that gives the number of bootstrap -#' replicates (1,000 by default). Non-integers are truncated towards 0. -#' @param tau A number greater than or equal to 1 that gives the rescale factor +#' @param w `[numeric >= 1]` A numeric vector of design (inverse probability) +#' weights for a (sequential) Poisson sample. +#' @param replicates `[integer(1) >= 0]` A positive integer that gives the +#' number of bootstrap replicates (1,000 by default). Non-integers are +#' truncated towards 0. +#' @param tau `[numeric(1) >= 1 | function]` A number greater than or equal to 1 +#' that gives the rescale factor #' for the bootstrap weights. Setting to 1 does not rescale the #' weights. This can also be a function that takes a vector of bootstrap #' adjustments and returns a number larger than 1. The default automatically #' picks the smallest feasible rescale factor (up to a small tolerance). -#' @param dist A function that produces random deviates with mean 0 and -#' standard deviation 1, such as [rnorm()]. The default uses the +#' @param dist `[function]` A function that produces random deviates with mean 0 +#' and standard deviation 1, such as [rnorm()]. The default uses the #' pseudo-population method from section 4.1 of Beaumont and Patak (2012); see #' details. #' @@ -94,7 +96,6 @@ #' ) #' #' lapply(dist, sps_repweights, w = weights(samp), replicates = 5, tau = 2) -#' #' @export sps_repweights <- function( w, @@ -124,12 +125,12 @@ sps_repweights <- function( } else { tau <- as.numeric(tau) if (tau < 1) { - stop("'tau' must be greater than or equal to 1") + stop("`tau` must be greater than or equal to 1") } } res <- w * (a + tau) / tau if (any(res < 0)) { - warning("some replicate weights are negative; try increasing 'tau'") + warning("some replicate weights are negative; try increasing `tau`") } dim(res) <- c(length(w), replicates) structure(res, tau = tau) @@ -137,13 +138,14 @@ sps_repweights <- function( #' Automatically scale tau #' @rdname sps_repweights -#' @param tol A non-negative number, strictly less than 1, that gives the -#' tolerance for determining the minimum feasible value of `tau`. +#' @param tol `[0 <= numeric(1) < 1]` A non-negative number, strictly less than +#' 1, that gives the tolerance for determining the minimum feasible value +#' of `tau`. #' @export min_tau <- function(tol) { tol <- as.numeric(tol) if (tol < 0 || tol >= 1) { - stop("'tol' must be in [0, 1)") + stop("`tol` must be in [0, 1)") } function(a) { max(abs(a[a < 0]) / (1 - tol), 1) diff --git a/tests/testthat/test-inclusion_prob.R b/inst/tinytest/test-inclusion_prob.R similarity index 91% rename from tests/testthat/test-inclusion_prob.R rename to inst/tinytest/test-inclusion_prob.R index c32acd8..864ef24 100644 --- a/tests/testthat/test-inclusion_prob.R +++ b/inst/tinytest/test-inclusion_prob.R @@ -1,6 +1,7 @@ set.seed(14235) -test_that("corner cases work as expected", { +# Corner cases work as expected. +local({ expect_equal(inclusion_prob(0, 0), 0) expect_equal( inclusion_prob(1:3, c(0, 1, 0), factor(c(2, 2, 2), levels = 1:3)), @@ -37,7 +38,8 @@ test_that("corner cases work as expected", { expect_equal(becomes_ta(c(1, 3, 2, 3), alpha = 1), c(4, 1, 3, 2)) }) -test_that("argument checking works", { +# Argument checking works. +local({ expect_error(inclusion_prob(-1:4, c(2, 2), gl(2, 3))) expect_error(inclusion_prob(c(NA, 1:5), c(2, 2), gl(2, 3))) expect_error(inclusion_prob(numeric(0), c(2, 2), gl(2, 3))) @@ -66,7 +68,8 @@ test_that("argument checking works", { expect_error(becomes_ta(1:5, 0.5, -1)) }) -test_that("inclusion probs are correct with different rounds of TA removal", { +# Inclusion probs are correct with different rounds of TA removal. +local({ # no rounds x <- c(0:4, 10:8, 5:7, 0) expect_equal(inclusion_prob(x, 4), x / 55 * 4) @@ -89,7 +92,8 @@ test_that("inclusion probs are correct with different rounds of TA removal", { ) }) -test_that("results agree with sampling::inclusionprobabilities()", { +# Results agree with sampling::inclusionprobabilities(). +local({ expect_equal( inclusion_prob(1:20, 12), c(1:16 / 136 * 8, rep(1, 4)) @@ -138,7 +142,8 @@ test_that("results agree with sampling::inclusionprobabilities()", { ) }) -test_that("TAs are added with alpha", { +# TAs are added with alpha. +local({ x <- c(0, 4, 1, 4, 5) expect_equal( inclusion_prob(rep(x, 3), c(3, 3, 3), gl(3, 5), alpha = c(0.1, 0.15, 0.2)), @@ -197,7 +202,8 @@ test_that("TAs are added with alpha", { ) }) -test_that("inclusion probs are a fixed point", { +# Inclusion probs are a fixed point. +local({ x <- 1:10 p <- inclusion_prob(x, 5) expect_equal(p, inclusion_prob(p, 5)) @@ -207,7 +213,8 @@ test_that("inclusion probs are a fixed point", { expect_equal(p, inclusion_prob(p, 3)) }) -test_that("n, alpha, and cutoff recycle", { +# n, alpha, and cutoff recycle. +local({ x <- 1:10 expect_equal( inclusion_prob(x, 3, gl(2, 5)), @@ -225,7 +232,8 @@ test_that("n, alpha, and cutoff recycle", { ) }) -test_that("cutoff is the same as removing units", { +# Cutoff is the same as removing units. +local({ x <- 1:20 expect_equal( inclusion_prob(x[x < 18], 9), @@ -237,7 +245,8 @@ test_that("cutoff is the same as removing units", { ) }) -test_that("cutoff agrees with alpha", { +# Cutoff agrees with alpha. +local({ x <- c(0, 1, 2, 3, 2, 4, 3) expect_equal( inclusion_prob(x, 3, alpha = 0.2), @@ -253,7 +262,8 @@ test_that("cutoff agrees with alpha", { ) }) -test_that("units become TA when expected", { +# Units become TA when expected. +local({ x <- c(6, 4, 3, 4, 2, 1, 4, 2, 2, 1, 2) for (a in seq(0, 1, 0.05)) { @@ -270,7 +280,8 @@ test_that("units become TA when expected", { } }) -test_that("adding a cutoff just offsets when a unit becomes TA", { +# Adding a cutoff just offsets when a unit becomes TA. +local({ x <- c(5, 3, 2, 4, 3) expect_equal(becomes_ta(x, 0.25), c(3, 4, 5, 4, 5)) expect_equal(becomes_ta(x, 0.25, 4), c(NaN, 4, 5, NaN, 5)) diff --git a/tests/testthat/test-prop_allocation.R b/inst/tinytest/test-prop_allocation.R similarity index 94% rename from tests/testthat/test-prop_allocation.R rename to inst/tinytest/test-prop_allocation.R index dc8b54f..5eb9987 100644 --- a/tests/testthat/test-prop_allocation.R +++ b/inst/tinytest/test-prop_allocation.R @@ -1,6 +1,7 @@ set.seed(4321) -test_that("corner cases for allocations work as expected", { +# Corner cases for allocations work as expected. +local({ expect_identical( prop_allocation(numeric(0), 0, factor(integer(0), levels = 1)), c("1" = 0L) @@ -35,7 +36,8 @@ test_that("corner cases for allocations work as expected", { ) }) -test_that("argument checking works for allocations", { +# Argument checking works for allocations. +local({ expect_error(prop_allocation(c(-1, 1, 0), 1, c(1, 1, 2))) expect_error(prop_allocation(c(1, 1, NA), 1, c(1, 1, 2))) expect_error(prop_allocation(c(1, 1, 0), -1, c(1, 1, 2))) @@ -54,7 +56,8 @@ test_that("argument checking works for allocations", { expect_error(prop_allocation(c(1, 0, 1), 2, c(1, 1, 2), initial = c(2, 0))) }) -test_that("simple allocations are correct", { +# Simple allocations are correct. +local({ expect_identical( prop_allocation(rep(1, 10), 4, rep(letters[1:2], 5)), c(a = 2L, b = 2L) @@ -133,7 +136,8 @@ test_that("simple allocations are correct", { ) }) -test_that("ties are broken correctly", { +# Ties are broken correctly. +local({ expect_identical( prop_allocation(rep(1, 9), 8, rep(1:2, c(4, 5))), c("1" = 3L, "2" = 5L) @@ -152,7 +156,8 @@ test_that("ties are broken correctly", { ) }) -test_that("alabama paradox doesn't happen", { +# Alabama paradox doesn't happen. +local({ expect_identical( prop_allocation(rep(1, 14), 10, rep(1:3, c(6, 6, 2))), c("1" = 5L, "2" = 4L, "3" = 1L) @@ -163,7 +168,8 @@ test_that("alabama paradox doesn't happen", { ) }) -test_that("allocations are correct for voting examples", { +# Allocations are correct for voting examples. +local({ # example from https://en.wikipedia.org/wiki/Highest_averages_method x <- rep(1, 1e5) s <- factor( @@ -189,7 +195,8 @@ test_that("allocations are correct for voting examples", { ) }) -test_that("expected coverage works", { +# Expected coverage works. +local({ expect_equal(expected_coverage(0, 0, 1), 0) expect_equal(expected_coverage(1:6, 6, gl(1, 6)), 1) expect_equal(expected_coverage(1:6, 0, gl(1, 6)), 0) @@ -280,7 +287,8 @@ test_that("expected coverage works", { # simulate mean(replicate(1e3, length(unique(s[ps(x, 10)])))) }) -test_that("argument checking for expected coverage works", { +# Argument checking for expected coverage works. +local({ expect_error(expected_coverage(numeric(0), 0, integer(0))) expect_error(expected_coverage(-1:4, 3, gl(2, 3))) expect_error(expected_coverage(c(1:5, NA), 3, gl(2, 3))) @@ -296,7 +304,8 @@ test_that("argument checking for expected coverage works", { expect_error(expected_coverage(1:6, 3, gl(2, 3), alpha = NA)) }) -test_that("divisors are correct", { +# Divisors are correct. +local({ expect_equal(divisor_method("Webster/Sainte-Lague")(1:3), 1:3 + 1 / 2) expect_equal(divisor_method("Imperiali")(1:3), 1:3 + 2) expect_equal(divisor_method("Huntington-Hill")(1:3), sqrt(1:3 * 2:4)) diff --git a/tests/testthat/test-sps.R b/inst/tinytest/test-sps.R similarity index 91% rename from tests/testthat/test-sps.R rename to inst/tinytest/test-sps.R index 9f7941b..5bf21e1 100644 --- a/tests/testthat/test-sps.R +++ b/inst/tinytest/test-sps.R @@ -1,6 +1,7 @@ set.seed(123454) -test_that("corner cases work as expected", { +# Corner cases work as expected. +local({ expect_identical( unclass(sps(numeric(0), 0)), structure(integer(0), weights = numeric(0)) @@ -43,7 +44,8 @@ test_that("corner cases work as expected", { ) }) -test_that("argument checking works", { +# Argument checking works. +local({ expect_error(sps(-1:4, c(2, 2), gl(2, 3))) expect_error(sps(c(NA, 1:5), c(2, 2), gl(2, 3))) expect_error(sps(numeric(0), c(2, 2), gl(2, 3))) @@ -69,7 +71,8 @@ test_that("argument checking works", { expect_error(sps(1:6, c(2, 2), gl(2, 3), cutoff = 2)) }) -test_that("results are sorted", { +# Results are sorted. +local({ x <- c(20, 1:10, 100, 0, 0) samp <- sps(x, c(3, 2, 2), c(1, 1, 2, 1, 3, 1, 2, 3, 2, 1, 3, 3, 3, 1)) expect_identical( @@ -83,7 +86,8 @@ test_that("results are sorted", { ) }) -test_that("two rounds of TA removal works", { +# Two rounds of TA removal works. +local({ x <- c(20, 1:10, 100, 0, 0) samp <- sps(x, 5) expect_equal(samp[c(1, 5)], c(1, 12)) @@ -109,7 +113,8 @@ test_that("two rounds of TA removal works", { ) }) -test_that("strata sizes add up", { +# Strata sizes add up. +local({ s <- c(1, 2, 3, 2, 3, 1, 3, 2, 1, 3, 3, 1, 2, 1, 1, 2, 3, 1, 3, 2, 2) s <- factor(s, 1:4) x <- c(1:10, 10:0) @@ -121,7 +126,8 @@ test_that("strata sizes add up", { ) }) -test_that("permanent random numbers work", { +# Permanent random numbers work. +local({ set.seed(4321) prn <- runif(11) x <- c(100, 1:9, 100) @@ -146,7 +152,8 @@ test_that("permanent random numbers work", { ) }) -test_that("extending a stratified sample works", { +# Extending a stratified sample works. +local({ set.seed(1432) u <- runif(100) x <- c(runif(98), 100, 200) @@ -159,14 +166,16 @@ test_that("extending a stratified sample works", { ) }) -test_that("top-up sampling works", { +# Top-up sampling works. +local({ set.seed(15243) u <- runif(10) x <- 1:10 expect_true(all(sps(x, 4, prn = u)[1:4] %in% sps(x, 5, prn = u))) }) -test_that("pareto order sampling works", { +# Pareto order sampling works. +local({ pareto <- order_sampling(function(x) x / (1 - x)) u <- runif(20) @@ -193,7 +202,8 @@ test_that("pareto order sampling works", { ) }) -test_that("ties are broken by position", { +# Ties are broken by position. +local({ x <- c(4, 1, 3, 2, 4) expect_identical( as.vector(sps(x, 3, prn = inclusion_prob(x, 3))), @@ -201,12 +211,14 @@ test_that("ties are broken by position", { ) }) -test_that("cutoff units are included", { +# Cutoff units are included. +local({ x <- c(4, 1, 3, 2, 4) expect_true(all(c(1, 5) %in% sps(x, 3, cutoff = 4))) }) -test_that("attributes get removed", { +# Attributes get removed. +local({ samp <- sps(1:5, 3) # mathematical functions should treat 'sps' objects as numeric vectors expect_true(inherits(log(samp), "numeric")) @@ -223,7 +235,8 @@ test_that("attributes get removed", { expect_true(inherits(samp, "integer")) }) -test_that("agrees with manual calculation", { +# Agrees with manual calculation. +local({ set.seed(12345) prn <- c(0.99, runif(9)) x <- c(20, 1:5, 7, 6, 100, 8) diff --git a/tests/testthat/test-sps_iterator.R b/inst/tinytest/test-sps_iterator.R similarity index 72% rename from tests/testthat/test-sps_iterator.R rename to inst/tinytest/test-sps_iterator.R index 035b027..e5f394a 100644 --- a/tests/testthat/test-sps_iterator.R +++ b/inst/tinytest/test-sps_iterator.R @@ -1,4 +1,5 @@ -test_that("streaming is the same as drawing", { +# Streaming is the same as drawing. +local({ set.seed(13026) x <- rlnorm(10) u <- runif(10) @@ -6,27 +7,28 @@ test_that("streaming is the same as drawing", { s <- sps_iterator(x, prn = u) for (i in 1:4) { res <- c(res, s()) - expect_setequal(sps(x, i, prn = u), res) + expect_true(setequal(sps(x, i, prn = u), res)) } for (i in 6:10) { res <- c(res, s()) - expect_setequal(sps(x, i, prn = u), res) + expect_true(setequal(sps(x, i, prn = u), res)) } expect_null(s()) s <- sps_iterator(x, n = 4, prn = u) - expect_setequal(c(3, 5), s()) + expect_true(setequal(c(3, 5), s())) res <- c(2, 3, 4, 5, 6) s <- sps_iterator(x, n = 5, prn = u) for (i in 6:10) { res <- c(res, s()) - expect_setequal(sps(x, i, prn = u), res) + expect_true(setequal(sps(x, i, prn = u), res)) } }) -test_that("gives back order with same prn", { +# Gives back order with same prn. +local({ x <- c(1, 4, 5, 3, 2) prn <- rep(0.5, 5) res <- c(3, 2, 4, 5, 1) @@ -36,7 +38,8 @@ test_that("gives back order with same prn", { } }) -test_that("NULL cases work", { +# NULL cases work. +local({ s <- sps_iterator(1:5, n = 5) expect_null(s()) @@ -44,13 +47,15 @@ test_that("NULL cases work", { expect_null(s()) }) -test_that("errors work", { +# Errors work. +local({ expect_error(sps_iterator(1:5, 7)) expect_error(sps_iterator(1:5, prn = 1:6)) expect_error(sps_iterator(0)) }) -test_that("extra args work", { +# Extra args work. +local({ set.seed(1234) prn <- runif(5) s <- sps_iterator(1:5, n = 2, alpha = 0.5, prn = prn) diff --git a/tests/testthat/test-sps_repweights.R b/inst/tinytest/test-sps_repweights.R similarity index 88% rename from tests/testthat/test-sps_repweights.R rename to inst/tinytest/test-sps_repweights.R index e932375..4a6746e 100644 --- a/tests/testthat/test-sps_repweights.R +++ b/inst/tinytest/test-sps_repweights.R @@ -1,6 +1,7 @@ set.seed(1234) -test_that("corner cases work as expected", { +# Corner cases work as expected. +local({ w <- rep(1, 10) # all TA units gives a matrix of 1s @@ -48,7 +49,8 @@ test_that("corner cases work as expected", { ) }) -test_that("argument checking works", { +# Argument checking works +local({ expect_error(sps_repweights(0:5, 5)) expect_error(sps_repweights(c(NA, 1:5), 5)) expect_error(sps_repweights(1:5, -5)) @@ -61,7 +63,8 @@ test_that("argument checking works", { expect_error(min_tau(2)) }) -test_that("rep weights works for TA units", { +# Rep weights works for TA units. +local({ expect_true(all(sps_repweights(1:5, tau = 2) > 0)) expect_true(all(sps_repweights(1:5, tau = 2)[1, ] == 1)) @@ -69,7 +72,8 @@ test_that("rep weights works for TA units", { expect_true(all(sps_repweights(1:5)[1, ] == 1)) }) -test_that("results agree with bootstrapFP:::generalised()", { +# Results agree with bootstrapFP:::generalised(). +local({ # fixed a bug with the exponential case by replacing exp() with rexp() bootstrap_fp <- function(ys, pks, replicates) { n <- length(ys) @@ -97,7 +101,8 @@ test_that("results agree with bootstrapFP:::generalised()", { expect_equal(var1, var2) }) -test_that("auto tau works", { +# Auto tau works.s +local({ set.seed(1234) w <- runif(10) + 1 @@ -115,8 +120,8 @@ test_that("auto tau works", { set.seed(1234) expect_warning(sps_repweights(w, 30, dist = rnorm, tau = tau - 0.001)) - expect_gte(min(sps_repweights(1:5, 5)), 0.0001) + expect_true(min(sps_repweights(1:5, 5)) >= 0.0001) expect_equal(min(sps_repweights(1:5, 5, min_tau(0))), 0) - expect_gte(min(sps_repweights(1:5, 5, min_tau(0.5))), 0.5) - expect_gte(min(sps_repweights(1:5, 5, min_tau(0.05), rnorm)), 0.05) + expect_true(min(sps_repweights(1:5, 5, min_tau(0.5))) >= 0.5) + expect_true(min(sps_repweights(1:5, 5, min_tau(0.05), rnorm)) >= 0.05) }) diff --git a/man/expected_coverage.Rd b/man/expected_coverage.Rd index 0ec12ca..7131e5c 100644 --- a/man/expected_coverage.Rd +++ b/man/expected_coverage.Rd @@ -7,22 +7,25 @@ expected_coverage(x, n, strata, alpha = 0.001, cutoff = Inf) } \arguments{ -\item{x}{A positive and finite numeric vector of sizes for units in the -population (e.g., revenue for drawing a sample of businesses).} +\item{x}{\verb{[numeric >= 0]} A positive and finite numeric vector of sizes for +units in the population (e.g., revenue for drawing a sample of businesses).} -\item{n}{A positive integer giving the sample size.} +\item{n}{\verb{[integer(1) >= 0]} A positive integer giving the sample size.} -\item{strata}{A factor, or something that can be coerced into one, giving +\item{strata}{\verb{[factor]} A factor, or something that can be coerced into one, +giving the strata associated with units in the population. The default is to place all units into a single stratum.} -\item{alpha}{A numeric vector with values between 0 and 1 for each stratum, +\item{alpha}{\verb{[0 <= numeric < 1]} A numeric vector with values between 0 and +1 for each stratum, ordered according to the levels of \code{strata}. Units with inclusion probabilities greater than or equal to 1 - \code{alpha} are set to 1 for each stratum. A single value is recycled for all strata. The default is slightly larger than 0.} -\item{cutoff}{A positive numeric vector of cutoffs for each stratum, ordered +\item{cutoff}{\verb{[numeric >= 0]} A positive numeric vector of cutoffs for each +stratum, ordered according to the levels of \code{strata}. Units with \code{x >= cutoff} get an inclusion probability of 1 for each stratum. A single value is recycled for all strata. The default does not apply a cutoff.} @@ -48,7 +51,6 @@ s <- rep(letters[1:10], each = 3) # Should get about 7 to 8 strata in a sample on average expected_coverage(x, 15, s) - } \seealso{ \code{\link[=prop_allocation]{prop_allocation()}} for generating proportional-to-size allocations. diff --git a/man/inclusion_prob.Rd b/man/inclusion_prob.Rd index 2e5a9ca..a742b84 100644 --- a/man/inclusion_prob.Rd +++ b/man/inclusion_prob.Rd @@ -10,24 +10,28 @@ inclusion_prob(x, n, strata = NULL, alpha = 0.001, cutoff = Inf) becomes_ta(x, alpha = 0.001, cutoff = Inf) } \arguments{ -\item{x}{A positive and finite numeric vector of sizes for units in the -population (e.g., revenue for drawing a sample of businesses).} +\item{x}{\verb{[numeric >= 0]} A positive and finite numeric vector of sizes for +units in the population (e.g., revenue for drawing a sample of businesses).} -\item{n}{A positive integer vector giving the sample size for each stratum, +\item{n}{\verb{[integer >= 0]} A positive integer vector giving the sample size +for each stratum, ordered according to the levels of \code{strata}. A single value is recycled for all strata. Non-integers are truncated towards 0.} -\item{strata}{A factor, or something that can be coerced into one, giving +\item{strata}{\verb{[factor]} A factor, or something that can be coerced into one, +giving the strata associated with units in the population. The default is to place all units into a single stratum.} -\item{alpha}{A numeric vector with values between 0 and 1 for each stratum, +\item{alpha}{\verb{[0 <= numeric < 1]} A numeric vector with values between 0 and +1 for each stratum, ordered according to the levels of \code{strata}. Units with inclusion probabilities greater than or equal to 1 - \code{alpha} are set to 1 for each stratum. A single value is recycled for all strata. The default is slightly larger than 0.} -\item{cutoff}{A positive numeric vector of cutoffs for each stratum, ordered +\item{cutoff}{\verb{[numeric >= 0]} A positive numeric vector of cutoffs for each +stratum, ordered according to the levels of \code{strata}. Units with \code{x >= cutoff} get an inclusion probability of 1 for each stratum. A single value is recycled for all strata. The default does not apply a cutoff.} @@ -81,7 +85,6 @@ n_ta(x, 7) # Use the inclusion probabilities to calculate the variance of the # sample size for Poisson sampling sum(pi * (1 - pi)) - } \seealso{ \code{\link[=sps]{sps()}} for drawing a sequential Poisson sample. diff --git a/man/prop_allocation.Rd b/man/prop_allocation.Rd index e60debe..0ab9529 100644 --- a/man/prop_allocation.Rd +++ b/man/prop_allocation.Rd @@ -27,31 +27,34 @@ divisor_method( ) } \arguments{ -\item{x}{A positive and finite numeric vector of sizes for units in the -population (e.g., revenue for drawing a sample of businesses).} +\item{x}{\verb{[numeric >= 0]} A positive and finite numeric vector of sizes for +units in the population (e.g., revenue for drawing a sample of businesses).} -\item{n}{A positive integer giving the sample size.} +\item{n}{\verb{[integer(1) >= 0]} A positive integer giving the sample size.} -\item{strata}{A factor, or something that can be coerced into one, giving +\item{strata}{\verb{[factor]} A factor, or something that can be coerced into one, +giving the strata associated with units in the population. The default is to place all units into a single stratum.} -\item{initial}{A positive integer vector giving the initial (or minimal) +\item{initial}{\verb{[integer >= 0]} A positive integer vector giving the initial +(or minimal) allocation for each stratum, ordered according to the levels of \code{strata}. A single integer is recycled for each stratum using a special algorithm to ensure a feasible allocation; see details. Non-integers are truncated towards 0. The default allows for no units to be allocated to a stratum.} -\item{divisor}{A function for the divisor (highest-averages) +\item{divisor}{\verb{[function]} A function for the divisor (highest-averages) apportionment method. The default uses the Jefferson/D'Hondt method. See details for other possible functions.} -\item{ties}{Either 'largest' to break ties in favor of the stratum with the +\item{ties}{\verb{[character(1)]} Either 'largest' to break ties in favor of the +stratum with the largest size (the default), or 'first' to break ties in favor of the ordering of \code{strata}.} -\item{name}{Name of the divisor function. See details.} +\item{name}{\verb{[character(1)]} Name of the divisor function. See details.} } \value{ \code{prop_allocation()} returns a named integer vector of sample sizes for each @@ -108,7 +111,6 @@ s <- rep(letters[1:10], each = 3) # Generate an allocation prop_allocation(x, 15, s, initial = 1) - } \references{ Balinksi, M. L. and Young, H. P. (1982). diff --git a/man/sps-package.Rd b/man/sps-package.Rd index d2cfe62..362b2a1 100644 --- a/man/sps-package.Rd +++ b/man/sps-package.Rd @@ -21,6 +21,11 @@ Useful links: \author{ \strong{Maintainer}: Steve Martin \email{marberts@protonmail.com} (\href{https://orcid.org/0000-0003-2544-9480}{ORCID}) [copyright holder] +Authors: +\itemize{ + \item Steve Martin \email{marberts@protonmail.com} (\href{https://orcid.org/0000-0003-2544-9480}{ORCID}) [copyright holder] +} + Other contributors: \itemize{ \item Justin Francis [contributor] diff --git a/man/sps.Rd b/man/sps.Rd index 74067a8..f57415d 100644 --- a/man/sps.Rd +++ b/man/sps.Rd @@ -13,35 +13,40 @@ ps(x, n, strata = NULL, prn = NULL, alpha = 0.001, cutoff = Inf) order_sampling(dist) } \arguments{ -\item{x}{A positive and finite numeric vector of sizes for units in the -population (e.g., revenue for drawing a sample of businesses).} +\item{x}{\verb{[numeric >= 0]} A positive and finite numeric vector of sizes for +units in the population (e.g., revenue for drawing a sample of businesses).} -\item{n}{A positive integer vector giving the sample size for each stratum, +\item{n}{\verb{[integer >= 0]} A positive integer vector giving the sample size +for each stratum, ordered according to the levels of \code{strata}. A single value is recycled for all strata. Non-integers are truncated towards 0.} -\item{strata}{A factor, or something that can be coerced into one, giving +\item{strata}{\verb{[factor]} A factor, or something that can be coerced into one, +giving the strata associated with units in the population. The default is to place all units into a single stratum.} -\item{prn}{A numeric vector of permanent random numbers for units in the +\item{prn}{\verb{[0 < numeric < 1]} A numeric vector of permanent random numbers +for units in the population, distributed uniform between 0 and 1. The default does not use permanent random numbers, instead generating a random vector when the function is called.} -\item{alpha}{A numeric vector with values between 0 and 1 for each stratum, +\item{alpha}{\verb{[0 <= numeric < 1]} A numeric vector with values between 0 and +1 for each stratum, ordered according to the levels of \code{strata}. Units with inclusion probabilities greater than or equal to 1 - \code{alpha} are set to 1 for each stratum. A single value is recycled for all strata. The default is slightly larger than 0.} -\item{cutoff}{A positive numeric vector of cutoffs for each stratum, ordered +\item{cutoff}{\verb{[numeric >= 0]} A positive numeric vector of cutoffs for each +stratum, ordered according to the levels of \code{strata}. Units with \code{x >= cutoff} get an inclusion probability of 1 for each stratum. A single value is recycled for all strata. The default does not apply a cutoff.} -\item{dist}{A function giving the fixed order distribution shape for an order -sampling scheme. See details.} +\item{dist}{\verb{[function]} A function giving the fixed order distribution shape +for an order sampling scheme. See details.} } \value{ \code{sps()} and \code{ps()} return an object of class \code{sps_sample}. @@ -184,7 +189,6 @@ order_sampling2 <- function(x) order_sampling(igpd(x)) order_sampling2(1)(x, 6, prn = u) # sequential Poisson order_sampling2(0)(x, 6, prn = u) # successive order_sampling2(-1)(x, 6, prn = u) # Pareto - } \references{ Matei, A., and Tillé, Y. (2007). Computational aspects of order diff --git a/man/sps_iterator.Rd b/man/sps_iterator.Rd index eca248b..3c00435 100644 --- a/man/sps_iterator.Rd +++ b/man/sps_iterator.Rd @@ -7,22 +7,24 @@ sps_iterator(x, n = 0L, prn = NULL, alpha = 0.001, cutoff = Inf) } \arguments{ -\item{x}{A positive and finite numeric vector of sizes for units in the -population (e.g., revenue for drawing a sample of businesses).} +\item{x}{\verb{[numeric >= 0]} A positive and finite numeric vector of sizes for +units in the population (e.g., revenue for drawing a sample of businesses).} -\item{n}{A positive integer giving the initial sample size for the iterator.} +\item{n}{\verb{[integer(1) >= 0]} A positive integer giving the initial sample +size for the iterator. The default is 0.} -\item{prn}{A numeric vector of permanent random numbers for units in the +\item{prn}{\verb{[0 < numeric < 1]} A numeric vector of permanent random numbers +for units in the population, distributed uniform between 0 and 1. The default does not use permanent random numbers, instead generating a random vector when the function is called.} -\item{alpha}{A number between 0 and 1. Units with +\item{alpha}{\verb{[0 <= numeric(1) < 1]} A number between 0 and 1. Units with inclusion probabilities greater than or equal to 1 - \code{alpha} are set to 1. The default is slightly larger than 0.} -\item{cutoff}{A numeric cutoff. Units with \code{x >= cutoff} get -an inclusion probability of 1. The default does not apply a cutoff.} +\item{cutoff}{\verb{[numeric(1) >= 0]} A numeric cutoff. Units with \code{x >= cutoff} +get an inclusion probability of 1. The default does not apply a cutoff.} } \value{ A function that returns the next unit in the sample. It take a single diff --git a/man/sps_repweights.Rd b/man/sps_repweights.Rd index 1dce2da..eeeb3cf 100644 --- a/man/sps_repweights.Rd +++ b/man/sps_repweights.Rd @@ -10,25 +10,28 @@ sps_repweights(w, replicates = 1000L, tau = min_tau(1e-04), dist = NULL) min_tau(tol) } \arguments{ -\item{w}{A numeric vector of design (inverse probability) weights for a -(sequential) Poisson sample.} +\item{w}{\verb{[numeric >= 1]} A numeric vector of design (inverse probability) +weights for a (sequential) Poisson sample.} -\item{replicates}{A positive integer that gives the number of bootstrap -replicates (1,000 by default). Non-integers are truncated towards 0.} +\item{replicates}{\verb{[integer(1) >= 0]} A positive integer that gives the +number of bootstrap replicates (1,000 by default). Non-integers are +truncated towards 0.} -\item{tau}{A number greater than or equal to 1 that gives the rescale factor +\item{tau}{\verb{[numeric(1) >= 1 | function]} A number greater than or equal to 1 +that gives the rescale factor for the bootstrap weights. Setting to 1 does not rescale the weights. This can also be a function that takes a vector of bootstrap adjustments and returns a number larger than 1. The default automatically picks the smallest feasible rescale factor (up to a small tolerance).} -\item{dist}{A function that produces random deviates with mean 0 and -standard deviation 1, such as \code{\link[=rnorm]{rnorm()}}. The default uses the +\item{dist}{\verb{[function]} A function that produces random deviates with mean 0 +and standard deviation 1, such as \code{\link[=rnorm]{rnorm()}}. The default uses the pseudo-population method from section 4.1 of Beaumont and Patak (2012); see details.} -\item{tol}{A non-negative number, strictly less than 1, that gives the -tolerance for determining the minimum feasible value of \code{tau}.} +\item{tol}{\verb{[0 <= numeric(1) < 1]} A non-negative number, strictly less than +1, that gives the tolerance for determining the minimum feasible value +of \code{tau}.} } \value{ \code{sps_repweights()} returns a matrix of bootstrap replicate weights @@ -93,7 +96,6 @@ dist <- list( ) lapply(dist, sps_repweights, w = weights(samp), replicates = 5, tau = 2) - } \references{ Beaumont, J.-F. and Patak, Z. (2012). On the Generalized diff --git a/tests/testthat.R b/tests/testthat.R deleted file mode 100644 index 3ce858d..0000000 --- a/tests/testthat.R +++ /dev/null @@ -1,12 +0,0 @@ -# This file is part of the standard setup for testthat. -# It is recommended that you do not modify it. -# -# Where should you do additional test configuration? -# Learn more about the roles of various files in: -# * https://r-pkgs.org/tests.html -# * https://testthat.r-lib.org/reference/test_package.html#special-files - -library(testthat) -library(sps) - -test_check("sps") diff --git a/tests/tinytest.R b/tests/tinytest.R new file mode 100644 index 0000000..20c352e --- /dev/null +++ b/tests/tinytest.R @@ -0,0 +1,5 @@ + +if (requireNamespace("tinytest", quietly = TRUE)) { + tinytest::test_package("sps") +} + diff --git a/vignettes/take-all.qmd b/vignettes/take-all.qmd index 03dc2c0..a6b1273 100644 --- a/vignettes/take-all.qmd +++ b/vignettes/take-all.qmd @@ -41,7 +41,7 @@ to place units with an inclusion probability greater than $1 - \alpha$, for some small $\alpha$, into the take-all stratum. Unless $\alpha = 0$, the usual algorithm for finding take-all units can put units into the take-all stratum that have an inclusion probability less than $1 - \alpha$. We can see this with the -following example (with a larger value for $\alpha$). +following example (with a larger value for $\alpha$ for illustration). ```{r} pi <- function(x, n) { From c7f6fb0a59be350392d769c2cd0a0e2cbd438ef0 Mon Sep 17 00:00:00 2001 From: Steve Martin Date: Tue, 14 Jul 2026 21:32:24 -0400 Subject: [PATCH 2/2] Removed lint --- tests/tinytest.R | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/tinytest.R b/tests/tinytest.R index 20c352e..8830610 100644 --- a/tests/tinytest.R +++ b/tests/tinytest.R @@ -1,5 +1,3 @@ - if (requireNamespace("tinytest", quietly = TRUE)) { tinytest::test_package("sps") } -