R Under development (unstable) (2026-09-16 r90549) -- "Unsuffered Consequences" Copyright (C) 2026 The R Foundation for Statistical Computing Platform: x86_64-pc-linux-gnu R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. Natural language support but running in an English locale R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > pkgname <- "rmoriebricklayer" > source(file.path(R.home("share"), "R", "examples-header.R")) > options(warn = 1) > library('rmoriebricklayer') > > base::assign(".oldSearch", base::search(), pos = 'CheckExEnv') > base::assign(".old_wd", base::getwd(), pos = 'CheckExEnv') > cleanEx() > nameEx("admissions") > ### * admissions > > flush(stderr()); flush(stdout()) > > ### Name: admissions > ### Title: Admissions implied by a population and a length of stay > ### Aliases: admissions > > ### ** Examples > > # Lakner (p.20) runs this the other way: t = 365, an average daily > # population of 25 and 1,750 admissions imply a stay of 5.2 days. > alos_implied <- 25 * 365 / 1750 > round(alos_implied, 1) [1] 5.2 > > # and back again > admissions(25, alos_implied) [1] 1750 > > > > cleanEx() > nameEx("adp") > ### * adp > > flush(stderr()); flush(stdout()) > > ### Name: adp > ### Title: Average daily population > ### Aliases: adp > > ### ** Examples > > # Lakner's own worked example (p.15): 3,000 inmates served 13,500 > # detention days in a year. > adp(13500) [1] 36.9863 > > # per-person days give the same total > adp(c(10, 20, 30), t = 30) [1] 2 > > > > cleanEx() > nameEx("adp_from_counts") > ### * adp_from_counts > > flush(stderr()); flush(stdout()) > > ### Name: adp_from_counts > ### Title: Person-days estimated from periodic headcounts > ### Aliases: adp_from_counts > > ### ** Examples > > # Lakner (p.21): counts on 255 days summing to 34,935 imply just over > # fifty thousand detention days across the year. > adp_from_counts(rep(34935 / 255, 255)) [1] 50005 > > > > cleanEx() > nameEx("agent_bundle") > ### * agent_bundle > > flush(stderr()); flush(stdout()) > > ### Name: agent_bundle > ### Title: Agent-assisted reproducibility-bundle help > ### Aliases: agent_bundle > > ### ** Examples > > > # With no rmorie binary on PATH the call returns an install hint, not an > # error -- safe to run anywhere: > if (!nzchar(Sys.which("rmorie"))) agent_bundle("hello") [1] "rmorie CLI not found on PATH. Install rmorie-cli to use agent_bundle()." > > > > cleanEx() > nameEx("alos") > ### * alos > > flush(stderr()); flush(stdout()) > > ### Name: alos > ### Title: Average length of stay > ### Aliases: alos > > ### ** Examples > > # Lakner (p.17): 2,700 inmates admitted and released served 12,150 > # detention days between them. > alos(12150, 2700) [1] 4.5 > > > > cleanEx() > nameEx("apply_schema_validation") > ### * apply_schema_validation > > flush(stderr()); flush(stdout()) > > ### Name: apply_schema_validation > ### Title: Apply Schema Validation, Stopping on Fatal Issues > ### Aliases: apply_schema_validation > > ### ** Examples > > prov <- list(schema = list(expected_columns = "id")) > apply_schema_validation(data.frame(id = 1), prov) > # A missing required column is fatal: > try(apply_schema_validation(data.frame(x = 1), prov)) Error : Missing required columns: id > > > > cleanEx() > nameEx("ascii_fallback") > ### * ascii_fallback > > flush(stderr()); flush(stdout()) > > ### Name: ascii_fallback > ### Title: Use Text As-Is, Falling Back to ASCII When It Cannot Be > ### Represented > ### Aliases: ascii_fallback > > ### ** Examples > > # By default valid UTF-8 is preserved (accents kept where supported). > ascii_fallback("\u00c1ngela") # "\u00c1ngela" [1] "Ángela" > > # force = TRUE always transliterates (for ASCII-only destinations > # such as a package DESCRIPTION). > ascii_fallback("\u00c1ngela", force = TRUE) # "Angela" [1] "Angela" > > # Plain ASCII is returned unchanged either way. > ascii_fallback("plain name") [1] "plain name" > > # Vectorised; each element handled independently. > ascii_fallback(c("caf\u00e9", "resume"), force = TRUE) [1] "cafe" "resume" > > > > cleanEx() > nameEx("band_sensitivity") > ### * band_sensitivity > > flush(stderr()); flush(stdout()) > > ### Name: band_sensitivity > ### Title: How much a result depends on the open band's assumed cap > ### Aliases: band_sensitivity print.rmbl_band_sensitivity > > ### ** Examples > > b <- parse_bands(c("1", "2 to 5", "6 to 10", "Greater than 10")) > counts <- c(1200, 430, 110, 38) > > s <- band_sensitivity(b, counts) > s ── Sensitivity to the open top band's assumed cap ──────────────── cap value 11.55000 0.4254708 15.09841 0.4346095 19.73696 0.4461100 25.80058 0.4604302 33.72707 0.4780278 44.08875 0.4993060 57.63375 0.5245371 75.34008 0.5537719 98.48616 0.5867522 128.74322 0.6228545 168.29590 0.6610951 220.00000 0.7002144 span over the caps tried: 0.2747 (53.7% of the typical value) The statistic moves by more than a tenth of itself across the caps tried, so it is a property of the assumption as much as of the data. Report the range, not a single figure. ────────────────────────────────────────────────────────────────── > > # A statistic that barely moves has been measured; one that swings > # has not. > band_sensitivity(b, counts, statistic = mean) ── Sensitivity to the open top band's assumed cap ──────────────── cap value 11.55000 2.257283 15.09841 2.295202 19.73696 2.344771 25.80058 2.409567 33.72707 2.494271 44.08875 2.604998 57.63375 2.749742 75.34008 2.938955 98.48616 3.186298 128.74322 3.509629 168.29590 3.932296 220.00000 4.484814 span over the caps tried: 2.228 (83.2% of the typical value) The statistic moves by more than a tenth of itself across the caps tried, so it is a property of the assumption as much as of the data. Report the range, not a single figure. ────────────────────────────────────────────────────────────────── > > > > cleanEx() > nameEx("band_values") > ### * band_values > > flush(stderr()); flush(stdout()) > > ### Name: band_values > ### Title: Representative values for banded categories > ### Aliases: band_values > > ### ** Examples > > b <- parse_bands(c("1", "2 to 5", "6 to 10", "Greater than 10")) > > band_values(b) label lower upper open_lower open_upper value assumed 1 1 1 1 FALSE FALSE 1.0 FALSE 2 2 to 5 2 5 FALSE FALSE 3.5 FALSE 3 6 to 10 6 10 FALSE FALSE 8.0 FALSE 4 Greater than 10 11 NA FALSE TRUE 16.5 TRUE > > # The lower and upper rules bracket the truth. > band_values(b, rule = "lower")$value [1] 1 2 6 11 > band_values(b, rule = "upper", open_upper_cap = 40)$value [1] 1 5 10 40 > > > > cleanEx() > nameEx("benford_test") > ### * benford_test > > flush(stderr()); flush(stdout()) > > ### Name: benford_test > ### Title: Benford first-digit test > ### Aliases: benford_test > > ### ** Examples > > # A quantity spanning several orders of magnitude follows the law. > set.seed(3) > benford_test(10^stats::runif(2000, 0, 6)) ── Benford first-digit screen ──────────────────────────────────── ✓ consistent with Benford's law values used 2,000 chi-square 10.073 df 8 p-value 0.26 digit observed expected shape 1 0.298 0.301 #################### 2 0.169 0.176 ########### 3 0.126 0.125 ######## 4 0.092 0.097 ###### 5 0.073 0.079 ##### 6 0.072 0.067 ##### 7 0.054 0.058 #### 8 0.060 0.051 #### 9 0.055 0.046 #### ────────────────────────────────────────────────────────────────── > > # Digits drawn uniformly do not. > benford_test(as.numeric(paste0(sample(1:9, 2000, TRUE), "000"))) ── Benford first-digit screen ──────────────────────────────────── ! departs from Benford's law (screen only, not a verdict) values used 2,000 chi-square 769.038 df 8 p-value <2e-16 digit observed expected shape 1 0.106 0.301 ################# 2 0.123 0.176 #################### 3 0.123 0.125 #################### 4 0.112 0.097 ################## 5 0.103 0.079 ################# 6 0.102 0.067 ################# 7 0.099 0.058 ################ 8 0.119 0.051 ################### 9 0.112 0.046 ################## ────────────────────────────────────────────────────────────────── > > # The expected proportions are the closed form. > b <- benford_test(10^stats::runif(500, 0, 5)) > all.equal(b$expected / b$n, log10(1 + 1 / (1:9))) [1] "names for target but not for current" > > # Zeros carry no leading digit and are excluded from n. > benford_test(c(0, 0, 1, 2, 3))$n [1] 3 > > > > cleanEx() > nameEx("bricklayer_fetch") > ### * bricklayer_fetch > > flush(stderr()); flush(stdout()) > > ### Name: bricklayer_fetch > ### Title: Fetch a URL to disk with an Internet Archive fallback > ### (C++/libcurl) > ### Aliases: bricklayer_fetch > > ### ** Examples > > # Inputs are validated before any network access: > try(bricklayer_fetch("", tempfile())) # empty url -> error Error in bricklayer_fetch("", tempfile()) : nzchar(url) is not TRUE > > > > > cleanEx() > nameEx("bricklayer_fetch_parse_siu") > ### * bricklayer_fetch_parse_siu > > flush(stderr()); flush(stdout()) > > ### Name: bricklayer_fetch_parse_siu > ### Title: Fetch and parse one SIU director's report > ### Aliases: bricklayer_fetch_parse_siu > > ### ** Examples > > > > > cleanEx() > nameEx("bricklayer_fetch_siu") > ### * bricklayer_fetch_siu > > flush(stderr()); flush(stdout()) > > ### Name: bricklayer_fetch_siu > ### Title: Fetch an Ontario SIU director's report by drid > ### Aliases: bricklayer_fetch_siu > > ### ** Examples > > > > > cleanEx() > nameEx("bricklayer_json_from_json") > ### * bricklayer_json_from_json > > flush(stderr()); flush(stdout()) > > ### Name: bricklayer_json_from_json > ### Title: Parse JSON into R objects (jsonlite's fromJSON, natively) > ### Aliases: bricklayer_json_from_json > > ### ** Examples > > bricklayer_json_from_json('[{"a":1,"b":"x"},{"a":2,"b":"y"}]') a b 1 1 x 2 2 y > bricklayer_json_from_json('[[1,2],[3,4]]') [,1] [,2] [1,] 1 2 [2,] 3 4 > > > > cleanEx() > nameEx("bricklayer_json_to_json") > ### * bricklayer_json_to_json > > flush(stderr()); flush(stdout()) > > ### Name: bricklayer_json_to_json > ### Title: Encode an R object as JSON (jsonlite's toJSON, natively) > ### Aliases: bricklayer_json_to_json > > ### ** Examples > > bricklayer_json_to_json(list(a = 1:3, b = "x"), auto_unbox = TRUE) [1] "{\"a\":[1,2,3],\"b\":\"x\"}" attr(,"class") [1] "json" > bricklayer_json_to_json(data.frame(id = 1:2, v = c(1.5, NA)), pretty = TRUE) [1] "[\n {\n \"id\": 1,\n \"v\": 1.5\n },\n {\n \"id\": 2\n }\n]" attr(,"class") [1] "json" > > > > cleanEx() > nameEx("bricklayer_parse_siu") > ### * bricklayer_parse_siu > > flush(stderr()); flush(stdout()) > > ### Name: bricklayer_parse_siu > ### Title: Parse an SIU director's report into the schema fields > ### Aliases: bricklayer_parse_siu > > ### ** Examples > > f <- bricklayer_parse_siu(system.file("extdata", + "siu_synthetic_report.html", + package = "rmoriebricklayer")) > f[["number_of_subject_officers"]] [1] "2" > > > > cleanEx() > nameEx("bricklayer_siu_iso_date") > ### * bricklayer_siu_iso_date > > flush(stderr()); flush(stdout()) > > ### Name: bricklayer_siu_iso_date > ### Title: Convert a human-readable SIU report date to ISO format > ### Aliases: bricklayer_siu_iso_date > > ### ** Examples > > bricklayer_siu_iso_date(c("January 5, 2023", "not a date")) [1] "2023-01-05" "" > > > > cleanEx() > nameEx("bricklayer_siu_resolve_so") > ### * bricklayer_siu_resolve_so > > flush(stderr()); flush(stdout()) > > ### Name: bricklayer_siu_resolve_so > ### Title: Resolve the subject-official count from SIU report text > ### Aliases: bricklayer_siu_resolve_so > > ### ** Examples > > bricklayer_siu_resolve_so( + "Subject Officials\nSO #1 Interviewed\nSO #2 Declined interview") $count [1] 2 $reason [1] "section: max(ordinal 2, entries 2)" > > > > cleanEx() > nameEx("bricklayer_siu_schema") > ### * bricklayer_siu_schema > > flush(stderr()); flush(stdout()) > > ### Name: bricklayer_siu_schema > ### Title: The panel-reviewed SIU report field schema > ### Aliases: bricklayer_siu_schema > > ### ** Examples > > bricklayer_siu_schema() name is_count 1 police_service FALSE 2 date_of_incident_iso FALSE 3 date_siu_notified_iso FALSE 4 date_of_director_decision_iso FALSE 5 siu_investigators TRUE 6 siu_forensics_investigators TRUE 7 number_of_witness_officials TRUE 8 number_of_civilian_witnesses TRUE 9 number_of_subject_officers TRUE 10 age_affected FALSE 11 sex_gender_affected FALSE 12 charges_recommended FALSE 13 directors_name FALSE 14 location_of_call FALSE 15 specific_injuries FALSE 16 relevant_legislation FALSE description 1 the police service(s) whose officials the SIU investigated 2 the date the incident occurred (ISO YYYY-MM-DD) 3 the date the SIU was notified/invoked (ISO YYYY-MM-DD) 4 the date of the Director's decision (ISO YYYY-MM-DD) 5 the number of SIU investigators assigned 6 the number of SIU forensic investigators assigned 7 the count of distinct WITNESS officers/officials (WO) 8 the count of distinct civilian witnesses (CW) 9 the count of distinct SUBJECT officers/officials (SO); a witness-officer-only investigation is 0 10 the age (or age range) of the affected person/complainant 11 the sex/gender of the affected person/complainant 12 whether charges were recommended/laid, and against whom 13 the name of the SIU Director who decided 14 the location/address where the incident occurred 15 the specific injuries the affected person sustained 16 the legislation/Criminal Code sections the Director analysed > > > > cleanEx() > nameEx("bricklayer_siu_text") > ### * bricklayer_siu_text > > flush(stderr()); flush(stdout()) > > ### Name: bricklayer_siu_text > ### Title: Convert SIU report HTML to plain text > ### Aliases: bricklayer_siu_text > > ### ** Examples > > bricklayer_siu_text("

Number of SIU Investigators assigned: 3

") [1] " Number of SIU Investigators assigned: 3\n" > > > > cleanEx() > nameEx("capsule_attest") > ### * capsule_attest > > flush(stderr()); flush(stdout()) > > ### Name: capsule_attest > ### Title: Attest a capsule, binding a signature to what it covers > ### Aliases: capsule_attest capsule_check_attestation > > ### ** Examples > > m <- make_manifest(list(dataset = "otis", rows = 1200L), + environment = FALSE) > key <- fips_keygen("ML-DSA-65") > att <- capsule_attest(m, key, note = "counts as published") > > # a verifier needs the attestation and the manifest, nothing else > res <- capsule_check_attestation(att, m) > res$ok [1] TRUE > res$checks check ok 1 attestation_complete TRUE 2 manifest_digest TRUE 3 signature TRUE detail 1 2 efa1b7387f225380245de0b5170999e87ad4044f3e8fd2ef6a6bfbc2bd0a9c90 3 > > # any change to the manifest breaks it > m2 <- m > m2$meta$rows <- 1201L > capsule_check_attestation(att, m2)$ok [1] FALSE > > # and so does presenting a different key > capsule_check_attestation(att, m, + key_expected = fips_keygen("ML-DSA-65")$public)$ok [1] FALSE > > > > cleanEx() > nameEx("capsule_bundle") > ### * capsule_bundle > > flush(stderr()); flush(stdout()) > > ### Name: capsule_bundle > ### Title: Bundle a capsule into one signed artifact > ### Aliases: capsule_bundle capsule_bundle_read capsule_bundle_verify > > ### ** Examples > > dir <- tempfile() > dir.create(dir) > write.csv(data.frame(x = 1:3), file.path(dir, "data.csv"), + row.names = FALSE) > m <- make_manifest(list(dataset = "demo"), environment = FALSE) > key <- fips_keygen("ML-DSA-44") > > b <- capsule_bundle(dir, m, key, note = "as published") > capsule_bundle_verify(attr(b, "path"), dir, manifest = m)$ok [1] TRUE > > # touch a byte of the data and the bundle no longer holds > write.csv(data.frame(x = 1:4), file.path(dir, "data.csv"), + row.names = FALSE) > capsule_bundle_verify(attr(b, "path"), dir, manifest = m)$ok [1] FALSE > unlink(dir, recursive = TRUE) > > > > cleanEx() > nameEx("capsule_drift") > ### * capsule_drift > > flush(stderr()); flush(stdout()) > > ### Name: capsule_drift > ### Title: Compare a fetched data frame with the one a capsule was pinned > ### against > ### Aliases: capsule_drift > > ### ** Examples > > set.seed(5) > ref <- data.frame( + value = stats::rnorm(300), + size = stats::runif(300, 1, 10), + grade = sample(c("a", "b", "c"), 300, TRUE) + ) > > # A fresh draw from the same process: no drift. > same <- data.frame( + value = stats::rnorm(300), + size = stats::runif(300, 1, 10), + grade = sample(c("a", "b", "c"), 300, TRUE) + ) > d <- capsule_drift(ref, same) > d$any_drift [1] FALSE > > # A silently rescaled column, and a new category, are both caught. > moved <- same > moved$size <- moved$size * 3 > moved$grade[1:100] <- "z" > capsule_drift(ref, moved) ── Capsule drift report ────────────────────────────────────────── ✗ DRIFT DETECTED reference rows 300 current rows 300 columns tested 3 alpha 0.01 ── Per-column tests ────────────────────────────────────────────── column type stat p psi ✗ grade categorical 121 <2e-16 – ✗ size numeric 0.743 <2e-16 4.299 ✓ value numeric 0.05 0.847 0.092 ────────────────────────────────────────────────────────────────── > > # The PSI is always reported as an effect size, but on a sample this > # small it is not allowed to raise the flag by itself -- binning noise > # alone would clear 0.25. Lower psi_min_n to override that. > capsule_drift(ref, same)$columns$psi [1] 0.09244204 0.06635985 NA > > # Structural changes are reported rather than tested. > capsule_drift(ref, same[, c("value", "grade")])$removed [1] "size" > > > > cleanEx() > nameEx("capsule_falsify") > ### * capsule_falsify > > flush(stderr()); flush(stdout()) > > ### Name: capsule_falsify > ### Title: Run falsification controls against a statistic > ### Aliases: capsule_falsify > > ### ** Examples > > set.seed(1) > d <- data.frame(x = rnorm(200)) > d$y <- 0.8 * d$x + rnorm(200) > # a real association survives its controls > real <- capsule_falsify(d, function(z) cor(z$x, z$y), + treatment = "x", n = 199, seed = 42) > real$controls[, c("control", "passed")] control passed 1 permutation TRUE 2 placebo TRUE 3 random_common_cause TRUE 4 subset_stability TRUE > > # and a statistic that ignores the data fails the ones that can see it > fake <- capsule_falsify(d, function(z) 0.5, treatment = "x", + n = 199, seed = 42) > fake$controls[fake$controls$control == "permutation", "passed"] [1] FALSE > > > > cleanEx() > nameEx("capsule_power") > ### * capsule_power > > flush(stderr()); flush(stdout()) > > ### Name: capsule_power > ### Title: Detect an injected effect of known size > ### Aliases: capsule_power > > ### ** Examples > > set.seed(1) > d <- data.frame(x = rnorm(120), y = rnorm(120)) > # inject a linear effect of x on y > inj <- function(z, size) { + z$y <- z$y + size * z$x + z + } > pw <- capsule_power(d, function(z) cor(z$x, z$y), inj, + sizes = c(0, 0.3, 0.6), treatment = "x", + n = 99, reps = 5, seed = 42) > pw$curve size detected reps rate 1 0.0 0 5 0 2 0.3 5 5 1 3 0.6 5 5 1 > > # The rate at size 0 estimates the false-positive rate. With few > # repetitions it is usually 0, because alpha is small -- five draws > # at 0.05 come up empty about three times in four -- so read it as a > # sanity check that it is not LARGE, not as an estimate of alpha. > pw$curve[pw$curve$size == 0, "rate"] [1] 0 > > > > cleanEx() > nameEx("capsule_report") > ### * capsule_report > > flush(stderr()); flush(stdout()) > > ### Name: capsule_report > ### Title: Assess a capsule in one call > ### Aliases: capsule_report > > ### ** Examples > > set.seed(1) > ref <- data.frame( + id = 1:200, + score = stats::runif(200, 0, 10), + grade = sample(c("a", "b", "c"), 200, TRUE), + stringsAsFactors = FALSE + ) > > # A fresh extract from the same process: nothing to report. > cur <- ref > cur$score <- stats::runif(200, 0, 10) > capsule_report(cur, reference = ref, schema = infer_schema(ref)) ── Capsule report ──────────────────────────────────────────────── ✓ these checks found nothing rows 200 columns 3 missing cells 0.0% complete rows 100.0% digest e1cbf9a9949ba4eed8e386aea8a43d6a No finding is proof of correctness: each check has a stated blind spot, and a small sample has little power. ────────────────────────────────────────────────────────────────── > > # One rescaled column and a new category: both surface, worst first. > bad <- cur > bad$score <- bad$score * 5 > bad$grade[1:80] <- "z" > r <- capsule_report(bad, reference = ref, schema = infer_schema(ref)) > r ── Capsule report ──────────────────────────────────────────────── ✗ WARNINGS: something moved rows 200 columns 3 missing cells 0.0% complete rows 100.0% digest 7510d7d7b267d81f4f26ea389443f4dc ── Findings (4) ────────────────────────────────────────────────── ✗ warn drift grade categorical test, p = <2e-16 ✗ warn drift score numeric test, p = <2e-16 ✗ warn schema range_score Column 'score' has 161 value(s) outside [-0.8488307, 10.90645] ✗ warn schema unexpected_grade Column 'grade' has unexpected values: z ────────────────────────────────────────────────────────────────── > r$verdict [1] "warn" > r$findings[, c("severity", "check", "subject")] severity check subject 1 warn drift grade 2 warn drift score 3 warn schema range_score 4 warn schema unexpected_grade > > # A missing column is fatal, because nothing downstream can run. > capsule_report(bad[, c("id", "score")], reference = ref, + schema = infer_schema(ref))$verdict [1] "fatal" > > > > cleanEx() > nameEx("capsule_sign") > ### * capsule_sign > > flush(stderr()); flush(stdout()) > > ### Name: capsule_sign > ### Title: Sign a capsule manifest > ### Aliases: capsule_sign > > ### ** Examples > > # Symmetric: one shared secret. > sig <- capsule_sign("sha256:abc123", key = "shared-secret", + scheme = "hmac") > capsule_verify("sha256:abc123", sig, "shared-secret") [1] TRUE > capsule_verify("sha256:TAMPERED", sig, "shared-secret") [1] FALSE > > # Post-quantum: the verifier needs only the public root. > key <- pqc_keygen(height = 2) > s1 <- capsule_sign("manifest-1", key) > capsule_verify("manifest-1", s1, signing_public_key(key)) [1] TRUE > > # Carry the advanced key state forward for the next signature. > key <- s1$key_state > key$next_index [1] 1 > s2 <- capsule_sign("manifest-2", key) > capsule_verify("manifest-2", s2, signing_public_key(key)) [1] TRUE > > # A signature does not transfer to another message. > capsule_verify("manifest-1", s2, signing_public_key(key)) [1] FALSE > > > > cleanEx() > nameEx("capsule_verify") > ### * capsule_verify > > flush(stderr()); flush(stdout()) > > ### Name: capsule_verify > ### Title: Verify a capsule manifest signature > ### Aliases: capsule_verify > > ### ** Examples > > key <- pqc_keygen(height = 2) > sig <- capsule_sign("pinned-manifest", key) > pub <- signing_public_key(key) > > capsule_verify("pinned-manifest", sig, pub) [1] TRUE > > # Every way of being wrong returns FALSE. > capsule_verify("edited-manifest", sig, pub) # message changed [1] FALSE > bad <- sig; bad$signature <- paste0("ff", substring(bad$signature, 3)) > capsule_verify("pinned-manifest", bad, pub) # signature edited [1] FALSE > capsule_verify("pinned-manifest", sig, + signing_public_key(pqc_keygen(height = 2))) # foreign key [1] FALSE > > # A truncated signature is not verified, and does not error. > trunc <- sig; trunc$signature <- substring(sig$signature, 1, 64) > capsule_verify("pinned-manifest", trunc, pub) [1] FALSE > > > > cleanEx() > nameEx("capture_dependencies") > ### * capture_dependencies > > flush(stderr()); flush(stdout()) > > ### Name: capture_dependencies > ### Title: Where each loaded package came from > ### Aliases: capture_dependencies > > ### ** Examples > > deps <- capture_dependencies(c("stats", "utils")) > deps[, c("package", "version")] package version 1 stats 4.7.0 2 utils 4.7.0 > > # a package with no repository field records that fact > is.na(capture_dependencies("stats")$repository) [1] TRUE > > > > cleanEx() > nameEx("capture_environment") > ### * capture_environment > > flush(stderr()); flush(stdout()) > > ### Name: capture_environment > ### Title: Capture the Analysis Environment for a Manifest > ### Aliases: capture_environment > > ### ** Examples > > # Record specific packages' versions alongside the session facts. > env <- capture_environment(c("stats", "utils")) > env$r_version [1] "4.7.0" > env$os [1] "Linux 7.1.3-200.fc44.x86_64" > env$packages # named character vector of versions stats utils "4.7.0" "4.7.0" > > # Default captures every currently loaded namespace. > names(capture_environment())[1:4] [1] "r_version" "platform" "os" "captured_utc" > > > > cleanEx() > nameEx("cert_chain_verify") > ### * cert_chain_verify > > flush(stderr()); flush(stdout()) > > ### Name: cert_chain_verify > ### Title: Verify a certificate chain > ### Aliases: cert_chain_verify > > ### ** Examples > > ## Not run: > ##D res <- cert_chain_verify("tsa.crt", trust = "ca.crt", > ##D purpose = "timeStamping") > ##D res$ok > ##D res$checks > ## End(Not run) > > > > cleanEx() > nameEx("cert_parse") > ### * cert_parse > > flush(stderr()); flush(stdout()) > > ### Name: cert_parse > ### Title: Parse an X.509 certificate > ### Aliases: cert_parse > > ### ** Examples > > # Certificates come from outside the package, so there is nothing to > # parse offline; this is the shape of the call. > ## Not run: > ##D cert <- cert_parse("tsa.crt") > ##D cert$subject > ##D cert$not_after > ##D cert$extended_key_usage > ## End(Not run) > > > > cleanEx() > nameEx("chunk_file") > ### * chunk_file > > flush(stderr()); flush(stdout()) > > ### Name: chunk_file > ### Title: Split a file into fixed-size chunks > ### Aliases: chunk_file > > ### ** Examples > > p <- tempfile() > writeLines(rep("some capsule content", 50), p) > > # One small chunk size to show the splitting. > ch <- chunk_file(p, chunk_bytes = 128) > length(ch) [1] 9 > > # The chunks reconstruct the file and pin it as a Merkle root. > merkle_root(ch) [1] "c4cb691d88a0dbf1dad9767c19095d54ac6958e6411e06d81dced0dba895c382" > > # They are the file's bytes, so they concatenate back to it exactly. > identical(unlist(ch), readBin(p, "raw", file.size(p))) [1] TRUE > > # Editing the file changes exactly one leaf. > unlink(p) > > > > cleanEx() > nameEx("cite_capsule") > ### * cite_capsule > > flush(stderr()); flush(stdout()) > > ### Name: cite_capsule > ### Title: Generate a Data Citation From Provenance > ### Aliases: cite_capsule > > ### ** Examples > > prov <- list( + captured_at_utc = "2026-06-23T04:41:40Z", + dataset = list(publisher = "Ontario Ministry of the Solicitor General", + licence_short = "OGL-Ontario", + package_slug = "data-on-inmates-in-ontario"), + resource = list(name = "Restrictive Confinement - Detailed Dataset", + direct_url = "https://data.ontario.ca/example.csv") + ) > cit <- cite_capsule(prov) > > # Plain-text citation ready to paste. > cat(cit$text) Ontario Ministry of the Solicitor General (2026). Restrictive Confinement - Detailed Dataset [Data set]. https://data.ontario.ca/example.csv Retrieved 2026-06-23. Licence: OGL-Ontario.> > # BibTeX @misc entry for LaTeX bibliographies. > cat(cit$bibtex) @misc{dataoninmatesinontario2026, author = {{Ontario Ministry of the Solicitor General}}, title = {Restrictive Confinement - Detailed Dataset}, year = {2026}, url = {https://data.ontario.ca/example.csv}, note = {Retrieved 2026-06-23; licence: OGL-Ontario}, }> > # NULL provenance returns NULL (composes safely). > cite_capsule(NULL) NULL > > > > cleanEx() > nameEx("clean_column_names") > ### * clean_column_names > > flush(stderr()); flush(stdout()) > > ### Name: clean_column_names > ### Title: Tidy the column names of an ingested table > ### Aliases: clean_column_names > > ### ** Examples > > clean_column_names(c("Total Population (2021)", "% change", + "Ville / City", "dup", "dup")) [1] "total_population_2021" "pct_change" "ville_city" [4] "dup" "dup_2" > > # Applied to a data frame, with the original names retained. > df <- data.frame(`Total Pop` = 1:2, `% change` = 3:4, + check.names = FALSE) > cleaned <- clean_column_names(df) > names(cleaned) [1] "total_pop" "pct_change" > attr(cleaned, "original_names") [1] "Total Pop" "% change" > > # Other cases. > clean_column_names(c("Total Pop"), case = "lower_camel") [1] "totalPop" > clean_column_names(c("Total Pop"), case = "upper_camel") [1] "TotalPop" > clean_column_names(c("Total Pop"), case = "screaming_snake") [1] "TOTAL_POP" > > > > cleanEx() > nameEx("concentration") > ### * concentration > > flush(stderr()); flush(stdout()) > > ### Name: concentration > ### Title: Concentration of a total across units > ### Aliases: concentration gini lorenz top_share > > ### ** Examples > > # Ten units holding one each: no concentration. > gini(rep(1, 10)) [1] 0 > > # One unit holding everything: the maximum for ten units. > gini(c(rep(0, 9), 1)) [1] 0.9 > 1 - 1 / 10 [1] 0.9 > > placements <- c(rep(1, 1200), rep(3, 430), rep(8, 110), rep(20, 38)) > gini(placements) [1] 0.461225 > > # What the most frequent few account for. > top_share(placements, c(0.01, 0.05, 0.1)) fraction units share 1 0.01 18 0.08716707 2 0.05 89 0.28280872 3 0.10 178 0.41888620 > > head(lorenz(placements)) population value 1 0.0000000000 0.0000000000 2 0.0005624297 0.0002421308 3 0.0011248594 0.0004842615 4 0.0016872891 0.0007263923 5 0.0022497188 0.0009685230 6 0.0028121485 0.0012106538 > > > > cleanEx() > nameEx("core_blake2b") > ### * core_blake2b > > flush(stderr()); flush(stdout()) > > ### Name: core_blake2b > ### Title: BLAKE2b digest, optionally keyed > ### Aliases: core_blake2b > > ### ** Examples > > # The RFC 7693 test vector for BLAKE2b-512 of "abc". > core_blake2b("abc", length = 64) [1] "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923" > > # 32 bytes by default, the same width as SHA-256. > core_blake2b("abc") [1] "bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319" > nchar(core_blake2b("abc")) [1] 64 > > # Any digest length, which SHA-2 cannot do. > core_blake2b("abc", length = 8) [1] "d8bb14d833d59559" > > # Keyed, so it authenticates without an HMAC construction. > core_blake2b("manifest", key = "secret") [1] "0fa448067a359db7f409a8de6a616a39d51393c32532bce014075308cbb1f222" > core_blake2b("manifest", key = "secret") == + core_blake2b("manifest", key = "other") [1] FALSE > > # Vectorised, and raw input hashes the same bytes. > core_blake2b(c("a", "b")) [1] "8928aae63c84d87ea098564d1e03ad813f107add474e56aedd286349c0c03ea4" [2] "6e5c1f45cbaf19f94230ba3501c378a5335af71a331b5b5aed62792332288dc3" > identical(core_blake2b("abc"), core_blake2b(charToRaw("abc"))) [1] TRUE > > > > cleanEx() > nameEx("core_bootstrap_mean") > ### * core_bootstrap_mean > > flush(stderr()); flush(stdout()) > > ### Name: core_bootstrap_mean > ### Title: Bootstrap replicate means (C backend) > ### Aliases: core_bootstrap_mean > > ### ** Examples > > set.seed(1) > x <- stats::rnorm(50, mean = 5) > > reps <- core_bootstrap_mean(x, B = 500, seed = 7) > length(reps) [1] 500 > > # The replicates centre on the sample mean, and their spread estimates > # the standard error. > c(sample = mean(x), bootstrap = mean(reps)) sample bootstrap 5.100448 5.097066 > c(bootstrap_se = stats::sd(reps), formula_se = stats::sd(x) / sqrt(length(x))) bootstrap_se formula_se 0.1174288 0.1175769 > > # A percentile confidence interval for the mean. > stats::quantile(reps, c(0.025, 0.975)) 2.5% 97.5% 4.864298 5.311439 > > # Reproducible: the same seed gives the same replicates, and R's own > # random stream is not consumed. > identical(core_bootstrap_mean(x, 100, seed = 1), + core_bootstrap_mean(x, 100, seed = 1)) [1] TRUE > > > > cleanEx() > nameEx("core_cov") > ### * core_cov > > flush(stderr()); flush(stdout()) > > ### Name: core_cov > ### Title: Covariance matrix of a numeric matrix (C backend) > ### Aliases: core_cov > > ### ** Examples > > X <- cbind(a = c(1, 2, 3, 4), b = c(2, 4, 7, 8), c = c(5, 3, 2, 1)) > core_cov(X) a b c a 1.666667 3.500000 -2.166667 b 3.500000 7.583333 -4.583333 c -2.166667 -4.583333 2.916667 > > # Agrees with stats::cov(). > all.equal(core_cov(X), stats::cov(X)) [1] TRUE > > # The diagonal is the column variances. > all.equal(diag(core_cov(X)), apply(X, 2, stats::var)) [1] TRUE > > # Data frames are accepted. > core_cov(data.frame(u = 1:5, v = c(2, 1, 4, 3, 6))) u v u 2.5 2.5 v 2.5 3.7 > > > > cleanEx() > nameEx("core_crc32") > ### * core_crc32 > > flush(stderr()); flush(stdout()) > > ### Name: core_crc32 > ### Title: CRC-32 checksum (C backend) > ### Aliases: core_crc32 > > ### ** Examples > > # The standard check value: CRC-32("123456789") is 0xCBF43926. > core_crc32("123456789") [1] 3421780262 > core_crc32("123456789") == 0xCBF43926 [1] TRUE > > # The empty input has checksum zero. > core_crc32("") [1] 0 > > # Vectorised, and sensitive to a single changed byte. > core_crc32(c("brick", "brack")) [1] 928041788 960731780 > > # Raw bytes work the same way. > core_crc32(charToRaw("123456789")) [1] 3421780262 > > > > cleanEx() > nameEx("core_gamma_cdf") > ### * core_gamma_cdf > > flush(stderr()); flush(stdout()) > > ### Name: core_gamma_cdf > ### Title: Regularized incomplete gamma function (C backend) > ### Aliases: core_gamma_cdf > > ### ** Examples > > core_gamma_cdf(3.5, c(0.5, 1, 4, 12)) [1] 0.005171463 0.040159631 0.667406097 0.998860649 > > # Identical to the unit-rate gamma CDF. > all.equal(core_gamma_cdf(3.5, c(0.5, 1, 4, 12)), + stats::pgamma(c(0.5, 1, 4, 12), shape = 3.5)) [1] TRUE > > # Shape 1 is the exponential distribution. > all.equal(core_gamma_cdf(1, c(0.5, 2)), stats::pexp(c(0.5, 2))) [1] TRUE > > # A chi-square tail on k degrees of freedom is 1 - P(k/2, q/2). > 1 - core_gamma_cdf(2 / 2, 5.99 / 2) # about 0.05 on 2 df [1] 0.05003663 > > > > cleanEx() > nameEx("core_hawkes_nll") > ### * core_hawkes_nll > > flush(stderr()); flush(stdout()) > > ### Name: core_hawkes_nll > ### Title: Hawkes-process negative log-likelihood (C backend) > ### Aliases: core_hawkes_nll > > ### ** Examples > > set.seed(4) > times <- sort(stats::runif(40, 0, 10)) > > # Exponential kernel: log-baseline -0.5, branching 0.3, decay 1.2. > core_hawkes_nll(times, 10, "exponential", c(-0.5, 0.3, 1.2)) [1] -1.8753 > > # Lower is better, so this is what an optimiser minimises. > nll <- function(p) core_hawkes_nll(times, 10, "exponential", p) > fit <- stats::optim(c(-0.5, 0.3, 1.2), nll) > fit$par [1] 1.03407757 0.99899989 0.08854609 > > # A branching ratio at or above 1 is not a stationary process, and is > # reported as the infeasible sentinel rather than a number. > core_hawkes_nll(times, 10, "exponential", c(-0.5, 1.5, 1.2)) == 1e12 [1] TRUE > > # The heavier-tailed kernels take two shape parameters. > core_hawkes_nll(times, 10, "gamma", c(-0.5, 0.3, 2, 1.5)) [1] -1.550628 > > > > cleanEx() > nameEx("core_ipw_weights") > ### * core_ipw_weights > > flush(stderr()); flush(stdout()) > > ### Name: core_ipw_weights > ### Title: Trimmed inverse-probability weights (C backend) > ### Aliases: core_ipw_weights > > ### ** Examples > > treat <- c(1, 0, 1, 0) > e <- c(0.5, 0.25, 0.02, 0.9) > > core_ipw_weights(treat, e) [1] 2.000000 1.333333 50.000000 10.000000 > > # A balanced score gives weight 2 to either arm. > core_ipw_weights(c(1, 0), c(0.5, 0.5)) [1] 2 2 > > # Without trimming the third observation would carry weight 50; the > # default clamp holds it to 100 at the 0.01 floor, and a looser floor > # tames it further. > core_ipw_weights(treat, e, trim_lo = 0.10) [1] 2.000000 1.333333 10.000000 10.000000 > > # Logical treatment indicators work too. > core_ipw_weights(c(TRUE, FALSE), c(0.4, 0.4)) [1] 2.500000 1.666667 > > > > cleanEx() > nameEx("core_moments") > ### * core_moments > > flush(stderr()); flush(stdout()) > > ### Name: core_moments > ### Title: Mean, variance, skewness and kurtosis in one pass (C backend) > ### Aliases: core_moments > > ### ** Examples > > core_moments(c(2, 4, 4, 4, 5, 5, 7, 9)) mean variance skewness kurtosis 5.000000 4.571429 0.656250 -0.218750 > > # The first two entries agree with base R. > m <- core_moments(1:10) > all.equal(m[["mean"]], mean(1:10)) [1] TRUE > all.equal(m[["variance"]], stats::var(1:10)) [1] TRUE > > # A symmetric sample has no skew; excess kurtosis is near 0 for normal > # data and positive for a heavy-tailed sample. > core_moments(c(-2, -1, 0, 1, 2))[["skewness"]] [1] 0 > core_moments(c(rep(0, 20), -8, 8))[["kurtosis"]] > 0 [1] TRUE > > # Too short to define a shape statistic: NaN rather than a guess. > core_moments(c(1, 2)) mean variance skewness kurtosis 1.5 0.5 NaN NaN > > > > cleanEx() > nameEx("core_normal_logpdf") > ### * core_normal_logpdf > > flush(stderr()); flush(stdout()) > > ### Name: core_normal_logpdf > ### Title: Normal log-density (C backend) > ### Aliases: core_normal_logpdf > > ### ** Examples > > core_normal_logpdf(c(-1, 0, 1)) [1] -1.4189385 -0.9189385 -1.4189385 > > # Identical to stats::dnorm(log = TRUE). > all.equal(core_normal_logpdf(-2:2, 0.3, 1.7), + stats::dnorm(-2:2, 0.3, 1.7, log = TRUE)) [1] TRUE > > # Still finite where the density itself underflows to zero. > stats::dnorm(50) # 0 [1] 0 > core_normal_logpdf(50) # about -1251 [1] -1250.919 > > > > cleanEx() > nameEx("core_normal_pdf") > ### * core_normal_pdf > > flush(stderr()); flush(stdout()) > > ### Name: core_normal_pdf > ### Title: Normal density (C backend) > ### Aliases: core_normal_pdf > > ### ** Examples > > # Standard normal density at a few quantiles. > core_normal_pdf(c(-1, 0, 1)) [1] 0.2419707 0.3989423 0.2419707 > > # Peak of the standard normal is 1/sqrt(2*pi) at x = 0. > core_normal_pdf(0) [1] 0.3989423 > > # Shift and scale via `mean` and `sd`. > core_normal_pdf(5, mean = 5, sd = 2) # peak of N(5, 2) [1] 0.1994711 > core_normal_pdf(c(0, 5, 10), mean = 5, sd = 2) [1] 0.00876415 0.19947114 0.00876415 > > # Identical to stats::dnorm(). > all.equal(core_normal_pdf(-2:2, 0, 1), stats::dnorm(-2:2, 0, 1)) [1] TRUE > > > > cleanEx() > nameEx("core_sha256") > ### * core_sha256 > > flush(stderr()); flush(stdout()) > > ### Name: core_sha256 > ### Title: SHA-256 hex digest (C backend) > ### Aliases: core_sha256 > > ### ** Examples > > # Hash a character scalar (NIST test vector for "abc"). > core_sha256("abc") [1] "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" > # ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad > > # Vectorised over character input: one digest per element. > core_sha256(c("abc", "def")) [1] "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" [2] "cb8379ac2098aa165029e3938a51da0bcecfc008fd6795f401178647f96c5b34" > > # Raw input hashes the bytes directly; identical to the character form. > identical(core_sha256("abc"), core_sha256(charToRaw("abc"))) [1] TRUE > > # Fingerprint an arbitrary object via its serialization. > core_sha256(serialize(list(a = 1L, b = "x"), NULL)) [1] "d8e966b9a409614aef2ce3a849533bc8a10c3d67c7bcf58c43929b93a4113378" > > > > cleanEx() > nameEx("core_sha512") > ### * core_sha512 > > flush(stderr()); flush(stdout()) > > ### Name: core_sha512 > ### Title: SHA-512 hex digest (C backend) > ### Aliases: core_sha512 > > ### ** Examples > > # FIPS 180-4 test vector for "abc". > core_sha512("abc") [1] "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" > > # Vectorised over character input. > core_sha512(c("abc", "def")) [1] "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" [2] "40a855bf0a93c1019d75dd5b59cd8157608811dd75c5977e07f3bc4be0cad98b22dde4db9ddb429fc2ad3cf9ca379fedf6c1dc4d4bb8829f10c2f0ee04a66663" > > # Raw input hashes the bytes directly, and agrees with the character > # form for the same bytes. > identical(core_sha512("abc"), core_sha512(charToRaw("abc"))) [1] TRUE > > # Twice the digest width of SHA-256. > c(sha256 = nchar(core_sha256("abc")), sha512 = nchar(core_sha512("abc"))) sha256 sha512 64 128 > > > > cleanEx() > nameEx("core_weighted") > ### * core_weighted > > flush(stderr()); flush(stdout()) > > ### Name: core_weighted > ### Title: Weighted mean and variance (C backend) > ### Aliases: core_weighted > > ### ** Examples > > x <- c(10, 20, 30, 40) > w <- c(1, 1, 2, 4) > core_weighted(x, w) mean variance 31.2500 169.0476 > > # The mean agrees with base R. > all.equal(core_weighted(x, w)[["mean"]], stats::weighted.mean(x, w)) [1] TRUE > > # Equal weights recover the unweighted variance. > all.equal(core_weighted(x, rep(1, 4))[["variance"]], stats::var(x)) [1] TRUE > > # A single dominant weight pulls the mean onto that observation. > core_weighted(x, c(1, 1, 1, 1000))[["mean"]] [1] 39.94018 > > > > cleanEx() > nameEx("correlation_table") > ### * correlation_table > > flush(stderr()); flush(stdout()) > > ### Name: correlation_table > ### Title: Full pairwise correlation table > ### Aliases: correlation_table > > ### ** Examples > > set.seed(1) > df <- data.frame(a = stats::rnorm(100), b = stats::rnorm(100)) > df$c <- df$a + stats::rnorm(100, sd = 0.2) > > correlation_table(df) ── Correlations (spearman) ─────────────────────────────────────── x y correlation n_pairs a b 0.039 100 a c 0.967 100 b c 0.015 100 ────────────────────────────────────────────────────────────────── > > # n_pairs shows how much data each figure rests on. > gappy <- df > gappy$a[1:80] <- NA > correlation_table(gappy) ── Correlations (spearman) ─────────────────────────────────────── x y correlation n_pairs a b 0.165 20 a c 0.959 20 b c 0.015 100 ────────────────────────────────────────────────────────────────── > > # A pair with too little overlap is NA, not a number from nothing. > thin <- df > thin$a[1:99] <- NA > correlation_table(thin)$correlation [1] NA NA 0.01508551 > > > > cleanEx() > nameEx("count_trend") > ### * count_trend > > flush(stderr()); flush(stdout()) > > ### Name: count_trend > ### Title: Trend in a count series, as a rate ratio per period > ### Aliases: count_trend > > ### ** Examples > > # A count falling by about 15% a year. > set.seed(3) > y <- stats::rpois(8, lambda = 200 * 0.85^(0:7)) > fit <- count_trend(y) > round(fit$rate_ratio, 3) [1] 0.869 > > # With a varying denominator the trend is in the rate. > count_trend(c(20, 25, 30), offset = c(1000, 1500, 2500))$rate_ratio [1] 0.7708656 > > > > cleanEx() > nameEx("cramers_v") > ### * cramers_v > > flush(stderr()); flush(stdout()) > > ### Name: cramers_v > ### Title: Association in a contingency table > ### Aliases: cramers_v > > ### ** Examples > > tbl <- rbind(c(120, 80), c(40, 160)) > cramers_v(tbl) $v [1] 0.4056758 $chisq [1] 66.66667 $df [1] 1 $p_value [1] 3.215263e-16 $n [1] 400 $min_expected [1] 80 $cells_below [1] 0 $method [1] "chi-square approximation" > > # No association gives a V near zero. > cramers_v(rbind(c(100, 100), c(100, 100)))$v [1] 0 > > # A sparse table's uncorrected V overstates the association. > sparse <- rbind(c(3, 1), c(1, 3)) > c(raw = cramers_v(sparse, bias_correct = FALSE)$v, + corrected = cramers_v(sparse)$v) raw corrected 0.5000000 0.3535534 > > > > cleanEx() > nameEx("derive_key") > ### * derive_key > > flush(stderr()); flush(stdout()) > > ### Name: derive_key > ### Title: Derive a key from a passphrase > ### Aliases: derive_key > > ### ** Examples > > # The published PBKDF2-HMAC-SHA256 vector: "password", "salt", 1 round. > derive_key("password", "salt", iterations = 1) [1] "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b" > > # Deterministic, so verification can repeat it. > identical(derive_key("pw", "s", 1000), derive_key("pw", "s", 1000)) [1] TRUE > > # The salt, the passphrase and the iteration count all change the key. > derive_key("pw", "salt-a", 1000) == derive_key("pw", "salt-b", 1000) [1] FALSE > derive_key("pw", "s", 1000) == derive_key("pw", "s", 2000) [1] FALSE > > # Use it to sign a manifest from a passphrase rather than raw bytes. > salt <- paste(format(random_bytes(16)), collapse = "") > key <- derive_key("correct horse battery staple", salt) > sig <- capsule_sign("manifest-digest", key, scheme = "hmac") > capsule_verify("manifest-digest", sig, key) [1] TRUE > > # A longer key is a prefix-consistent extension of a shorter one. > identical(substring(derive_key("pw", "s", 10, length = 64), 1, 64), + derive_key("pw", "s", 10, length = 32)) [1] TRUE > > > > cleanEx() > nameEx("digest_object") > ### * digest_object > > flush(stderr()); flush(stdout()) > > ### Name: digest_object > ### Title: Digest an arbitrary R object > ### Aliases: digest_object > > ### ** Examples > > digest_object(list(a = 1L, b = "x")) [1] "49cceaf96020b3b5c40d2ffbac114a1d7a93474aa083516da4df3f82e7afd1c4" > > # Stable across calls, and sensitive to any change. > identical(digest_object(1:10), digest_object(1:10)) [1] TRUE > digest_object(1:10) == digest_object(1:11) [1] FALSE > > # Attributes are part of the object, so they are part of the digest. > digest_object(matrix(1:6, nrow = 2)) == digest_object(1:6) [1] FALSE > > # Any of the hashes, and a keyed fingerprint. > digest_object(mtcars, algo = "sha512") [1] "3bea6c8e5b622c3677149de5c31be5e4d0592767a8e97d14f16690ea72aa5ba0d7354e18d1bce2bc3ba836b392871f67e4fc97076ce6745c3a9e5a5fbf884a96" > digest_object(mtcars, algo = "crc32") [1] 1371658137 > digest_object(mtcars, algo = "blake2b", key = "secret") [1] "0137c7e84d6663d0032c112b7973b672b79123f65246b3c93ed31a80239454b3" > > # A data frame's digest pins the data, so it can go in a manifest. > digest_object(data.frame(x = 1:3)) [1] "74275c3f5e3bcc768b6156bf46ddb2ce0f026d383547a486b3b57dbc23417a32" > > > > cleanEx() > nameEx("download_data") > ### * download_data > > flush(stderr()); flush(stdout()) > > ### Name: download_data > ### Title: Download a File > ### Aliases: download_data > > ### ** Examples > > > > > cleanEx() > nameEx("drift_chisq") > ### * drift_chisq > > flush(stderr()); flush(stdout()) > > ### Name: drift_chisq > ### Title: Chi-square test for a categorical column > ### Aliases: drift_chisq > > ### ** Examples > > ref <- c(a = 50, b = 30, c = 20) > > # Counts matching the reference proportions: nothing to report. > drift_chisq(c(a = 100, b = 60, c = 40), ref) statistic df p_value 0 2 1 > > # A reallocated mix is detected. > drift_chisq(c(a = 40, b = 60, c = 100), ref) statistic df p_value 126 2 0 > > # Agrees with stats::chisq.test(). > o <- c(a = 40, b = 60, c = 100) > all.equal(drift_chisq(o, ref)[["statistic"]], + as.numeric(stats::chisq.test(o, p = ref / sum(ref))$statistic)) [1] TRUE > > # Raw vectors are tabulated for you. > drift_chisq(c("a", "a", "b", "b"), c("a", "b")) statistic df p_value 0 1 1 > > # A category the reference rules out, but which occurs, is a flat > # contradiction rather than a large finite statistic. > drift_chisq(c("a", "a", "b", "d"), c("a", "a", "b", "b")) statistic df p_value Inf 1 0 > > # When a new category is legitimate, compare two samples instead. > drift_homogeneity(c("a", "a", "b", "b"), c("a", "a", "b", "d")) statistic df p_value 1.3333333 2.0000000 0.5134171 > > > > cleanEx() > nameEx("drift_homogeneity") > ### * drift_homogeneity > > flush(stderr()); flush(stdout()) > > ### Name: drift_homogeneity > ### Title: Chi-square test of homogeneity for two categorical samples > ### Aliases: drift_homogeneity > > ### ** Examples > > set.seed(1) > a <- sample(c("x", "y", "z"), 300, TRUE) > b <- sample(c("x", "y", "z"), 300, TRUE) > > # Two draws from the same distribution: no evidence of a difference. > drift_homogeneity(a, b) statistic df p_value 0.5150386 2.0000000 0.7729667 > > # A reallocated mix is detected. > drift_homogeneity(a, sample(c("x", "y", "z"), 300, TRUE, + prob = c(0.7, 0.2, 0.1))) statistic df p_value 6.978222e+01 2.000000e+00 6.661338e-16 > > # Agrees with stats::chisq.test() on the 2-by-k table. > tab <- rbind(table(a), table(b)) > all.equal(drift_homogeneity(a, b)[["statistic"]], + as.numeric(stats::chisq.test(tab)$statistic)) [1] TRUE > > # It is more conservative than treating the reference as known, which > # is exactly the point. > drift_homogeneity(a, b)[["p_value"]] >= drift_chisq(b, a)[["p_value"]] [1] TRUE > > > > cleanEx() > nameEx("drift_ks") > ### * drift_ks > > flush(stderr()); flush(stdout()) > > ### Name: drift_ks > ### Title: Two-sample Kolmogorov-Smirnov test (C backend) > ### Aliases: drift_ks > > ### ** Examples > > set.seed(1) > ref <- stats::rnorm(200) > > # The same distribution: a small D and a large p-value. > drift_ks(ref, stats::rnorm(200)) statistic p_value n_eff 0.0600000 0.8642828 100.0000000 > > # A shifted distribution is detected. > drift_ks(ref, stats::rnorm(200, mean = 0.8)) statistic p_value n_eff 3.250000e-01 1.338317e-09 1.000000e+02 > > # So is a change in spread alone, which a mean comparison would miss. > drift_ks(ref, stats::rnorm(200, sd = 2.5)) statistic p_value n_eff 3.150000e-01 4.813445e-09 1.000000e+02 > > # The statistic agrees with stats::ks.test(). > a <- stats::rnorm(60); b <- stats::rnorm(45, 0.6) > all.equal(drift_ks(a, b)[["statistic"]], + as.numeric(suppressWarnings(stats::ks.test(a, b))$statistic)) [1] TRUE > > # Identical samples have nothing to report. > drift_ks(ref, ref)[["statistic"]] [1] 0 > > > > cleanEx() > nameEx("drift_psi") > ### * drift_psi > > flush(stderr()); flush(stdout()) > > ### Name: drift_psi > ### Title: Population stability index and Jensen-Shannon divergence (C > ### backend) > ### Aliases: drift_psi > > ### ** Examples > > set.seed(2) > ref <- stats::rnorm(500) > > # Same distribution: both indices near zero. > drift_psi(ref, stats::rnorm(500)) psi js_divergence 0.022072326 0.002752915 > > # A shift both indices register. > drift_psi(ref, stats::rnorm(500, mean = 1)) psi js_divergence 0.9543324 0.1053174 > > # A sample compared with itself has moved nowhere at all. > drift_psi(ref, ref) psi js_divergence 0 0 > > # The Jensen-Shannon divergence is bounded by log(2), whatever the > # shift, which is what makes it comparable across columns. > drift_psi(c(1, 1, 1), c(9, 9, 9))[["js_divergence"]] <= log(2) [1] TRUE > > > > cleanEx() > nameEx("duplicate_rows") > ### * duplicate_rows > > flush(stderr()); flush(stdout()) > > ### Name: duplicate_rows > ### Title: Duplicated rows, with their groups > ### Aliases: duplicate_rows > > ### ** Examples > > df <- data.frame(id = c(1, 2, 2, 3, 3, 3), + value = c("a", "b", "b", "c", "d", "c"), + stringsAsFactors = FALSE) > > # Duplicated on every column. > duplicate_rows(df) id value dupe_count 1 2 b 2 2 2 b 2 3 3 c 2 4 3 c 2 > > # Duplicated on the identifier alone, which catches more. > duplicate_rows(df, "id") id value dupe_count 1 2 b 2 2 2 b 2 3 3 c 3 4 3 d 3 5 3 c 3 > > # No duplicates gives zero rows, not an error. > duplicate_rows(data.frame(x = 1:3)) [1] x dupe_count <0 rows> (or 0-length row.names) > > > > cleanEx() > nameEx("eb_rates") > ### * eb_rates > > flush(stderr()); flush(stdout()) > > ### Name: eb_rates > ### Title: Empirical Bayes rates, shrunk toward the overall experience > ### Aliases: eb_rates > > ### ** Examples > > # Three areas, one of them tiny. The tiny area's raw ratio is > # extreme; its shrunk one is not. > eb_rates(observed = c(30, 45, 2), expected = c(25, 50, 0.5), + area = c("North", "South", "Tiny")) area observed expected sir eb shrinkage nu alpha 1 North 30 25.0 1.2 1.1073869 0.5141392 26.98066 26.45506 2 South 45 50.0 0.9 0.9414767 0.3460211 26.98066 26.45506 3 Tiny 2 0.5 4.0 1.0751472 0.9814506 26.98066 26.45506 > > > > cleanEx() > nameEx("environment_diff") > ### * environment_diff > > flush(stderr()); flush(stdout()) > > ### Name: environment_diff > ### Title: Compare two captured environments > ### Aliases: environment_diff > > ### ** Examples > > a <- capture_environment() > b <- a > > # An environment matches itself. > environment_diff(a, b)$identical [1] TRUE > > # Stage a moved dependency and a removed one. > if (length(b$packages)) { + nm <- names(b$packages)[1] + b$packages[[nm]] <- "0.0.0" + environment_diff(a, b)$packages + } package a b change 1 base 4.7.0 0.0.0 changed > > # Whole manifests are accepted, not just the environment block. > m <- make_manifest(list(run = "demo")) > environment_diff(m, m)$identical [1] TRUE > > > > cleanEx() > nameEx("evalue_rr") > ### * evalue_rr > > flush(stderr()); flush(stdout()) > > ### Name: evalue_rr > ### Title: How strong would an unmeasured confounder have to be > ### Aliases: evalue_rr > > ### ** Examples > > # a risk ratio of 2 needs a confounder associated by 3.41 with both > evalue_rr(2) evalue_point 3.414214 > > # a protective effect is inverted, so 0.5 gives the same answer > evalue_rr(0.5) evalue_point 3.414214 > > # an interval that already includes the null needs nothing > evalue_rr(2, lo = 0.9, hi = 4.4) evalue_point evalue_limit 3.414214 1.000000 > > # and a strong result with a limit well above the null is harder to > # explain away > evalue_rr(3, lo = 2.1, hi = 4.3) evalue_point evalue_limit 5.449490 3.619868 > > > > cleanEx() > nameEx("expand_bands") > ### * expand_bands > > flush(stderr()); flush(stdout()) > > ### Name: expand_bands > ### Title: Expand a banded frequency table into per-unit values > ### Aliases: expand_bands > > ### ** Examples > > x <- expand_bands(c("1", "2 to 5", "Greater than 5"), + counts = c(10, 4, 2), open_upper_cap = 12) > table(x) x 1 3.5 9 10 4 2 > > gini(x) [1] 0.452381 > > > > cleanEx() > nameEx("expected_counts") > ### * expected_counts > > flush(stderr()); flush(stdout()) > > ### Name: expected_counts > ### Title: Expected counts under indirect standardisation > ### Aliases: expected_counts > > ### ** Examples > > d <- data.frame( + region = rep(c("North", "South", "East"), each = 2), + age = rep(c("18 to 24", "25 to 49"), 3), + n = c(30, 45, 12, 60, 8, 20), + pop = c(1000, 6000, 900, 9000, 400, 3500) + ) > > # Adjusting for size only. > expected_counts(d$n, d$pop, d$region) area observed population expected 1 East 28 3900 32.81250 2 North 75 7000 58.89423 3 South 72 9900 83.29327 > > # Adjusting for size AND age composition, which is the comparison > # that says something about the region. > expected_counts(d$n, d$pop, d$region, strata = d$age) area observed population expected 1 East 28 3900 32.34430 2 North 75 7000 62.27967 3 South 72 9900 80.37603 > > > > cleanEx() > nameEx("falsify_family") > ### * falsify_family > > flush(stderr()); flush(stdout()) > > ### Name: falsify_family > ### Title: Correct a family of falsification results for multiple testing > ### Aliases: falsify_family > > ### ** Examples > > # four statistics, one of which is real > set.seed(1) > d <- data.frame(x = rnorm(150)) > d$y <- 0.6 * d$x + rnorm(150) > d$a <- rnorm(150) > d$b <- rnorm(150) > fam <- list( + real = capsule_falsify(d, function(z) cor(z$x, z$y), + treatment = "x", n = 199, seed = 1), + noise_a = capsule_falsify(d, function(z) cor(z$a, z$y), + treatment = "a", n = 199, seed = 2), + noise_b = capsule_falsify(d, function(z) cor(z$b, z$y), + treatment = "b", n = 199, seed = 3)) > falsify_family(fam) ── Family of 3, corrected by holm at alpha 0.05 ────────────────── real p 0.005 adjusted 0.015 survives noise_a p 0.955 adjusted 1 noise_b p 0.995 adjusted 1 ────────────────────────────────────────────────────────────────── at the permutation floor (more permutations would be needed to say more): real ────────────────────────────────────────────────────────────────── > > # the correction is what stops the smallest of several from being > # read as the finding > falsify_family(c(a = 0.01, b = 0.04, c = 0.2, d = 0.5))$results name p adjusted survives 1 a 0.01 0.04 TRUE 2 b 0.04 0.12 FALSE 3 c 0.20 0.40 FALSE 4 d 0.50 0.50 FALSE > > > > cleanEx() > nameEx("fips_key") > ### * fips_key > > flush(stderr()); flush(stdout()) > > ### Name: fips_key > ### Title: Assemble a standardised key from raw key material > ### Aliases: fips_key > > ### ** Examples > > key <- fips_keygen("ML-DSA-44") > # the round trip through raw material changes nothing > again <- fips_key("ML-DSA-44", key$public, key$secret) > identical(again$secret, key$secret) [1] TRUE > > sig <- capsule_sign("m", again) > capsule_verify("m", sig, fips_key("ML-DSA-44", key$public)) [1] TRUE > > # material of the wrong length is refused > try(fips_key("ML-DSA-65", key$public, key$secret)) Error : `public` must be 1952 bytes of key material for ML-DSA-65 > > > > cleanEx() > nameEx("fips_keygen") > ### * fips_keygen > > flush(stderr()); flush(stdout()) > > ### Name: fips_keygen > ### Title: Generate a standardised post-quantum signing key > ### Aliases: fips_keygen fips_public_key > > ### ** Examples > > key <- fips_keygen("ML-DSA-65") > key$scheme [1] "ML-DSA-65" > > sig <- capsule_sign("a manifest digest", key) > capsule_verify("a manifest digest", sig, fips_public_key(key)) [1] TRUE > > # A context string binds the signature to its purpose: the same > # message signed for one context does not verify under another. > sig2 <- capsule_sign("a manifest digest", key, context = "release") > capsule_verify("a manifest digest", sig2, key, context = "release") [1] TRUE > capsule_verify("a manifest digest", sig2, key, context = "staging") [1] FALSE > > > > cleanEx() > nameEx("fips_mu") > ### * fips_mu > > flush(stderr()); flush(stdout()) > > ### Name: fips_mu > ### Title: Sign an ML-DSA message digest computed elsewhere > ### Aliases: fips_mu fips_sign_mu fips_verify_mu > > ### ** Examples > > key <- fips_keygen("ML-DSA-65") > mu <- fips_mu(key, "a manifest digest", context = "release") > length(mu) [1] 64 > > sig <- fips_sign_mu(key, mu) > fips_verify_mu(key, mu, sig) [1] TRUE > > # the same signature verifies the ordinary way, from the message > capsule_verify("a manifest digest", sig, key, context = "release") [1] TRUE > > # mu is computable from the PUBLIC key alone, which is what lets the > # message stay on the machine that has it > identical(fips_mu(fips_public_key(key), "a manifest digest", + context = "release"), mu) [1] TRUE > > > > cleanEx() > nameEx("fips_sizes") > ### * fips_sizes > > flush(stderr()); flush(stdout()) > > ### Name: fips_sizes > ### Title: Byte lengths of a standardised signature scheme > ### Aliases: fips_sizes > > ### ** Examples > > fips_sizes("ML-DSA-65") public_key secret_key signature seed opt_rand 1952 4032 3309 32 32 > fips_sizes("SLH-DSA-SHAKE-128s") public_key secret_key signature seed opt_rand 32 64 7856 48 16 > > # An SLH-DSA signature is far larger than an ML-DSA one at the same > # security level, which is the price of dropping the lattice > # assumption. > fips_sizes("SLH-DSA-SHAKE-128s")[["signature"]] > + fips_sizes("ML-DSA-44")[["signature"]] [1] TRUE > > > > cleanEx() > nameEx("fiscal_year_label") > ### * fiscal_year_label > > flush(stderr()); flush(stdout()) > > ### Name: fiscal_year_label > ### Title: Name a fiscal year by the years it spans > ### Aliases: fiscal_year_label > > ### ** Examples > > fiscal_year_label(2019:2023) [1] "2018/19" "2019/20" "2020/21" "2021/22" "2022/23" > > fiscal_year_label(2023, short = FALSE) [1] "2022/2023" > > fiscal_year_label(2023, sep = "-") [1] "2022-23" > > > > cleanEx() > nameEx("frequency_table") > ### * frequency_table > > flush(stderr()); flush(stdout()) > > ### Name: frequency_table > ### Title: Frequency table for one column > ### Aliases: frequency_table > > ### ** Examples > > df <- data.frame(grade = c("a", "b", "b", "c", NA, "b"), + stringsAsFactors = FALSE) > frequency_table(df, "grade") ── Frequency table ─────────────────────────────────────────────── value n pct pct_valid bar b 3 50.0 60.0 #################### a 1 16.7 20.0 ####### c 1 16.7 20.0 ####### – (missing) 1 16.7 – ####### ────────────────────────────────────────────────────────────────── > > # The two percentage columns differ exactly by the missingness. > frequency_table(df, "grade")[, c("pct", "pct_valid")] pct pct_valid 1 50.00000 60 2 16.66667 20 3 16.66667 20 4 16.66667 NA > > # A vector works directly. > frequency_table(c(1, 1, 2, 3, 3, 3)) ── Frequency table ─────────────────────────────────────────────── value n pct pct_valid bar 3 3 50.0 50.0 #################### 1 2 33.3 33.3 ############# 2 1 16.7 16.7 ####### ────────────────────────────────────────────────────────────────── > > # Natural order rather than frequency order. > frequency_table(c("c", "a", "b", "a"), sort = FALSE) ── Frequency table ─────────────────────────────────────────────── value n pct pct_valid bar a 2 50.0 50.0 #################### b 1 25.0 25.0 ########## c 1 25.0 25.0 ########## ────────────────────────────────────────────────────────────────── > > # Long tails are folded so the percentages still total 100. > set.seed(1) > ft <- frequency_table(sample(letters, 500, TRUE), max_levels = 5) > ft ── Frequency table ─────────────────────────────────────────────── value n pct pct_valid bar y 25 5.0 5.0 # e 24 4.8 4.8 # t 24 4.8 4.8 # a 23 4.6 4.6 # f 23 4.6 4.6 # (other) 381 76.2 76.2 #################### ────────────────────────────────────────────────────────────────── > sum(ft$pct) [1] 100 > > > > cleanEx() > nameEx("friendly_download") > ### * friendly_download > > flush(stderr()); flush(stdout()) > > ### Name: friendly_download > ### Title: Download a File With Diagnostic Error Messages > ### Aliases: friendly_download > > ### ** Examples > > > > > cleanEx() > nameEx("funnel_limits") > ### * funnel_limits > > flush(stderr()); flush(stdout()) > > ### Name: funnel_limits > ### Title: Funnel-plot control limits > ### Aliases: funnel_limits > > ### ** Examples > > # The funnel narrows as the expected count grows, which is the whole > # point: a ratio of 2 means nothing at an expected count of 2 and a > # great deal at an expected count of 200. > funnel_limits(c(2, 20, 200)) expected level lower upper 1 2 0.950 0.000 2.500 2 20 0.950 0.600 1.450 3 200 0.950 0.865 1.140 4 2 0.998 0.000 4.000 5 20 0.998 0.400 1.750 6 200 0.998 0.790 1.225 > > > > cleanEx() > nameEx("hill_tail_index") > ### * hill_tail_index > > flush(stderr()); flush(stdout()) > > ### Name: hill_tail_index > ### Title: Tail index of a heavy-tailed count > ### Aliases: hill_tail_index > > ### ** Examples > > # A continuous Pareto tail with exponent 2.5. > set.seed(1) > x <- (1 - stats::runif(5000))^(-1 / 1.5) > round(hill_tail_index(x, x_min = 1, discrete = FALSE)$alpha, 2) [1] 2.49 > > # A discrete power law, where the exact likelihood is needed: the > # closed-form correction is badly biased at a threshold of one. > k <- 1:10000 > p <- k^(-2.5) / sum(k^(-2.5)) > set.seed(2) > z <- sample(k, 5000, replace = TRUE, prob = p) > c(exact = round(hill_tail_index(z, x_min = 1)$alpha, 2), + approx = round(hill_tail_index(z, x_min = 1, approx = TRUE)$alpha, 2)) exact approx 2.46 2.00 > > # A short tail still returns an estimate, marked as not to be leaned > # on, and with a standard error that says the same thing. > short <- hill_tail_index(c(3, 4, 5, 9), x_min = 3) > c(alpha = round(short$alpha, 2), n = short$n_tail, + reliable = short$reliable) alpha n reliable 2.59 4.00 0.00 > > # Below `min_tail` there is nothing to estimate from. > hill_tail_index(c(3, 4), x_min = 3)$alpha [1] NA > > > > cleanEx() > nameEx("hurwitz_zeta") > ### * hurwitz_zeta > > flush(stderr()); flush(stdout()) > > ### Name: hurwitz_zeta > ### Title: Hurwitz zeta function > ### Aliases: hurwitz_zeta > > ### ** Examples > > # The Riemann zeta at even integers has a closed form. > c(hurwitz_zeta(2), pi^2 / 6) [1] 1.644934 1.644934 > c(hurwitz_zeta(4), pi^4 / 90) [1] 1.082323 1.082323 > > # Apery's constant. > hurwitz_zeta(3) [1] 1.202057 > > # Shifting the lower limit removes exactly the leading term. > hurwitz_zeta(2.5, 3) - hurwitz_zeta(2.5, 4) [1] 0.06415003 > 3^-2.5 [1] 0.06415003 > > # Outside the domain of convergence there is no value to return. > hurwitz_zeta(1) [1] NA > > > > cleanEx() > nameEx("infer_schema") > ### * infer_schema > > flush(stderr()); flush(stdout()) > > ### Name: infer_schema > ### Title: Infer a pinnable schema from a data frame > ### Aliases: infer_schema > > ### ** Examples > > set.seed(1) > df <- data.frame( + id = 1:100, + score = stats::runif(100, 0, 10), + grade = sample(c("a", "b", "c"), 100, TRUE), + note = paste0("free text ", 1:100), + stringsAsFactors = FALSE + ) > > sch <- infer_schema(df) > sch ── Inferred schema ─────────────────────────────────────────────── columns 4 rows 90 to 111 value sets 1 numeric ranges 2 id integer max NA 10.0% [ -8.9, 109.9] score numeric max NA 10.0% [-0.8446, 10.9] grade character max NA 10.0% a, b, c note character max NA 10.0% – free ────────────────────────────────────────────────────────────────── > > # The categorical column has its levels pinned; the free-text one does > # not, because it exceeds max_levels. > sch$expected_value_sets $grade [1] "a" "b" "c" > > # It validates the data it was learned from. > length(validate_schema(df, list(schema = sch))) [1] 0 > > # And catches a column that has gone missing, or a new category. > length(validate_schema(df[, -3], list(schema = sch))) > 0 [1] TRUE > bad <- df; bad$grade[1] <- "z" > length(validate_schema(bad, list(schema = sch))) > 0 [1] TRUE > > > > cleanEx() > nameEx("inline_hist") > ### * inline_hist > > flush(stderr()); flush(stdout()) > > ### Name: inline_hist > ### Title: Inline histogram for a numeric vector > ### Aliases: inline_hist > > ### ** Examples > > set.seed(1) > # A symmetric distribution peaks in the middle. > inline_hist(stats::rnorm(1000)) [1] "▁▂▄██▇▄▂▁▁" > > # A skewed one leans left. > inline_hist(stats::rexp(1000)) [1] "█▄▂▁▁▁▁▁▁▁" > > # Bimodality is visible here and in no single summary number. > inline_hist(c(stats::rnorm(500, -3), stats::rnorm(500, 3))) [1] "▁▅█▄▁▁▃█▆▁" > > # A constant column has no spread to show. > inline_hist(rep(5, 10)) [1] " █ " > > > > cleanEx() > nameEx("kem_decapsulate") > ### * kem_decapsulate > > flush(stderr()); flush(stdout()) > > ### Name: kem_decapsulate > ### Title: Recover a shared secret from an ML-KEM ciphertext > ### Aliases: kem_decapsulate > > ### ** Examples > > key <- kem_keygen(512) rmbl_mlkem_core.h:63:34: runtime error: signed integer overflow: 64778 * 62209 cannot be represented in type 'int' #0 0x7bcfe88ba0bc in rmbl_mlkem_core::montgomery_reduce(int) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:63 #1 0x7bcfe88ba0bc in rmbl_mlkem_core::ntt(short*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:136 #2 0x7bcfe88c6abb in rmbl_mlkem512::pke_keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:256 #3 0x7bcfe88c91ca in rmbl_mlkem512::keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:367 #4 0x7bcfe88d9a0c in C_rmbl_mlkem_keygen /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem.cpp:126 #5 0x00000075cd66 in R_doDotCall /data/localhost/ripley/R/svn/R-devel/src/main/dotcode.c:757 #6 0x000000900c47 in bcEval_loop /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:8704 #7 0x0000008d7ffb in bcEval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:7533 #8 0x00000087822a in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1167 #9 0x00000088ea3a in R_execClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2398 #10 0x00000089273d in applyClosure_core /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2314 #11 0x0000008788d8 in Rf_applyClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2333 #12 0x0000008788d8 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1278 #13 0x0000008a727e in do_set /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:3585 #14 0x000000878d06 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1230 #15 0x000000a211f8 in Rf_ReplIteration /data/localhost/ripley/R/svn/R-devel/src/main/main.c:264 #16 0x000000a211f8 in R_ReplConsole /data/localhost/ripley/R/svn/R-devel/src/main/main.c:319 #17 0x000000a3eeba in run_Rmainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1239 #18 0x000000a3ef52 in Rf_mainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1246 #19 0x0000004120af in main /data/localhost/ripley/R/svn/R-devel/src/main/Rmain.c:29 #20 0x7fcff4a0a680 in __libc_start_call_main (/lib64/libc.so.6+0x3680) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #21 0x7fcff4a0a797 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3797) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #22 0x000000412a74 in _start (/data/localhost/ripley/R/gcc-SAN3/bin/exec/R+0x412a74) (BuildId: 9dff11dcd6e3f76486b274cbe4864e0a7249b59b) rmbl_mlkem_core.h:63:34: runtime error: signed integer overflow: 40196 * 62209 cannot be represented in type 'int' #0 0x7bcfe88b698e in rmbl_mlkem_core::montgomery_reduce(int) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:63 #1 0x7bcfe88b698e in rmbl_mlkem_core::basemul(short*, short const*, short const*, short) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:170 #2 0x7bcfe88c6f59 in rmbl_mlkem_core::poly_basemul(short*, short const*, short const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:183 #3 0x7bcfe88c6f59 in rmbl_mlkem512::vec_dot(short*, rmbl_mlkem512::PolyVec const*, rmbl_mlkem512::PolyVec const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:184 #4 0x7bcfe88c6f59 in rmbl_mlkem512::pke_keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:260 #5 0x7bcfe88c91ca in rmbl_mlkem512::keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:367 #6 0x7bcfe88d9a0c in C_rmbl_mlkem_keygen /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem.cpp:126 #7 0x00000075cd66 in R_doDotCall /data/localhost/ripley/R/svn/R-devel/src/main/dotcode.c:757 #8 0x000000900c47 in bcEval_loop /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:8704 #9 0x0000008d7ffb in bcEval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:7533 #10 0x00000087822a in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1167 #11 0x00000088ea3a in R_execClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2398 #12 0x00000089273d in applyClosure_core /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2314 #13 0x0000008788d8 in Rf_applyClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2333 #14 0x0000008788d8 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1278 #15 0x0000008a727e in do_set /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:3585 #16 0x000000878d06 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1230 #17 0x000000a211f8 in Rf_ReplIteration /data/localhost/ripley/R/svn/R-devel/src/main/main.c:264 #18 0x000000a211f8 in R_ReplConsole /data/localhost/ripley/R/svn/R-devel/src/main/main.c:319 #19 0x000000a3eeba in run_Rmainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1239 #20 0x000000a3ef52 in Rf_mainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1246 #21 0x0000004120af in main /data/localhost/ripley/R/svn/R-devel/src/main/Rmain.c:29 #22 0x7fcff4a0a680 in __libc_start_call_main (/lib64/libc.so.6+0x3680) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #23 0x7fcff4a0a797 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3797) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #24 0x000000412a74 in _start (/data/localhost/ripley/R/gcc-SAN3/bin/exec/R+0x412a74) (BuildId: 9dff11dcd6e3f76486b274cbe4864e0a7249b59b) rmbl_mlkem_core.h:63:34: runtime error: signed integer overflow: 55498 * 62209 cannot be represented in type 'int' #0 0x7bcfe88b6c30 in rmbl_mlkem_core::montgomery_reduce(int) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:63 #1 0x7bcfe88b6c30 in rmbl_mlkem_core::basemul(short*, short const*, short const*, short) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:173 #2 0x7bcfe88c6f59 in rmbl_mlkem_core::poly_basemul(short*, short const*, short const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:183 #3 0x7bcfe88c6f59 in rmbl_mlkem512::vec_dot(short*, rmbl_mlkem512::PolyVec const*, rmbl_mlkem512::PolyVec const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:184 #4 0x7bcfe88c6f59 in rmbl_mlkem512::pke_keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:260 #5 0x7bcfe88c91ca in rmbl_mlkem512::keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:367 #6 0x7bcfe88d9a0c in C_rmbl_mlkem_keygen /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem.cpp:126 #7 0x00000075cd66 in R_doDotCall /data/localhost/ripley/R/svn/R-devel/src/main/dotcode.c:757 #8 0x000000900c47 in bcEval_loop /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:8704 #9 0x0000008d7ffb in bcEval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:7533 #10 0x00000087822a in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1167 #11 0x00000088ea3a in R_execClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2398 #12 0x00000089273d in applyClosure_core /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2314 #13 0x0000008788d8 in Rf_applyClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2333 #14 0x0000008788d8 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1278 #15 0x0000008a727e in do_set /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:3585 #16 0x000000878d06 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1230 #17 0x000000a211f8 in Rf_ReplIteration /data/localhost/ripley/R/svn/R-devel/src/main/main.c:264 #18 0x000000a211f8 in R_ReplConsole /data/localhost/ripley/R/svn/R-devel/src/main/main.c:319 #19 0x000000a3eeba in run_Rmainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1239 #20 0x000000a3ef52 in Rf_mainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1246 #21 0x0000004120af in main /data/localhost/ripley/R/svn/R-devel/src/main/Rmain.c:29 #22 0x7fcff4a0a680 in __libc_start_call_main (/lib64/libc.so.6+0x3680) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #23 0x7fcff4a0a797 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3797) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #24 0x000000412a74 in _start (/data/localhost/ripley/R/gcc-SAN3/bin/exec/R+0x412a74) (BuildId: 9dff11dcd6e3f76486b274cbe4864e0a7249b59b) rmbl_mlkem_core.h:63:34: runtime error: signed integer overflow: 62520 * 62209 cannot be represented in type 'int' #0 0x7bcfe88b6abb in rmbl_mlkem_core::montgomery_reduce(int) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:63 #1 0x7bcfe88b6abb in rmbl_mlkem_core::basemul(short*, short const*, short const*, short) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:174 #2 0x7bcfe88c6f59 in rmbl_mlkem_core::poly_basemul(short*, short const*, short const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:183 #3 0x7bcfe88c6f59 in rmbl_mlkem512::vec_dot(short*, rmbl_mlkem512::PolyVec const*, rmbl_mlkem512::PolyVec const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:184 #4 0x7bcfe88c6f59 in rmbl_mlkem512::pke_keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:260 #5 0x7bcfe88c91ca in rmbl_mlkem512::keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:367 #6 0x7bcfe88d9a0c in C_rmbl_mlkem_keygen /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem.cpp:126 #7 0x00000075cd66 in R_doDotCall /data/localhost/ripley/R/svn/R-devel/src/main/dotcode.c:757 #8 0x000000900c47 in bcEval_loop /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:8704 #9 0x0000008d7ffb in bcEval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:7533 #10 0x00000087822a in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1167 #11 0x00000088ea3a in R_execClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2398 #12 0x00000089273d in applyClosure_core /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2314 #13 0x0000008788d8 in Rf_applyClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2333 #14 0x0000008788d8 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1278 #15 0x0000008a727e in do_set /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:3585 #16 0x000000878d06 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1230 #17 0x000000a211f8 in Rf_ReplIteration /data/localhost/ripley/R/svn/R-devel/src/main/main.c:264 #18 0x000000a211f8 in R_ReplConsole /data/localhost/ripley/R/svn/R-devel/src/main/main.c:319 #19 0x000000a3eeba in run_Rmainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1239 #20 0x000000a3ef52 in Rf_mainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1246 #21 0x0000004120af in main /data/localhost/ripley/R/svn/R-devel/src/main/Rmain.c:29 #22 0x7fcff4a0a680 in __libc_start_call_main (/lib64/libc.so.6+0x3680) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #23 0x7fcff4a0a797 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3797) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #24 0x000000412a74 in _start (/data/localhost/ripley/R/gcc-SAN3/bin/exec/R+0x412a74) (BuildId: 9dff11dcd6e3f76486b274cbe4864e0a7249b59b) rmbl_mlkem_core.h:63:34: runtime error: signed integer overflow: 48755 * 62209 cannot be represented in type 'int' #0 0x7bcfe88b6e26 in rmbl_mlkem_core::montgomery_reduce(int) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:63 #1 0x7bcfe88b6e26 in rmbl_mlkem_core::basemul(short*, short const*, short const*, short) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:176 #2 0x7bcfe88c6f59 in rmbl_mlkem_core::poly_basemul(short*, short const*, short const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:183 #3 0x7bcfe88c6f59 in rmbl_mlkem512::vec_dot(short*, rmbl_mlkem512::PolyVec const*, rmbl_mlkem512::PolyVec const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:184 #4 0x7bcfe88c6f59 in rmbl_mlkem512::pke_keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:260 #5 0x7bcfe88c91ca in rmbl_mlkem512::keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:367 #6 0x7bcfe88d9a0c in C_rmbl_mlkem_keygen /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem.cpp:126 #7 0x00000075cd66 in R_doDotCall /data/localhost/ripley/R/svn/R-devel/src/main/dotcode.c:757 #8 0x000000900c47 in bcEval_loop /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:8704 #9 0x0000008d7ffb in bcEval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:7533 #10 0x00000087822a in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1167 #11 0x00000088ea3a in R_execClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2398 #12 0x00000089273d in applyClosure_core /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2314 #13 0x0000008788d8 in Rf_applyClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2333 #14 0x0000008788d8 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1278 #15 0x0000008a727e in do_set /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:3585 #16 0x000000878d06 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1230 #17 0x000000a211f8 in Rf_ReplIteration /data/localhost/ripley/R/svn/R-devel/src/main/main.c:264 #18 0x000000a211f8 in R_ReplConsole /data/localhost/ripley/R/svn/R-devel/src/main/main.c:319 #19 0x000000a3eeba in run_Rmainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1239 #20 0x000000a3ef52 in Rf_mainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1246 #21 0x0000004120af in main /data/localhost/ripley/R/svn/R-devel/src/main/Rmain.c:29 #22 0x7fcff4a0a680 in __libc_start_call_main (/lib64/libc.so.6+0x3680) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #23 0x7fcff4a0a797 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3797) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #24 0x000000412a74 in _start (/data/localhost/ripley/R/gcc-SAN3/bin/exec/R+0x412a74) (BuildId: 9dff11dcd6e3f76486b274cbe4864e0a7249b59b) rmbl_mlkem_core.h:63:34: runtime error: signed integer overflow: 55196 * 62209 cannot be represented in type 'int' #0 0x7bcfe88b6dd0 in rmbl_mlkem_core::montgomery_reduce(int) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:63 #1 0x7bcfe88b6dd0 in rmbl_mlkem_core::basemul(short*, short const*, short const*, short) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:171 #2 0x7bcfe88c6f59 in rmbl_mlkem_core::poly_basemul(short*, short const*, short const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:183 #3 0x7bcfe88c6f59 in rmbl_mlkem512::vec_dot(short*, rmbl_mlkem512::PolyVec const*, rmbl_mlkem512::PolyVec const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:184 #4 0x7bcfe88c6f59 in rmbl_mlkem512::pke_keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:260 #5 0x7bcfe88c91ca in rmbl_mlkem512::keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:367 #6 0x7bcfe88d9a0c in C_rmbl_mlkem_keygen /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem.cpp:126 #7 0x00000075cd66 in R_doDotCall /data/localhost/ripley/R/svn/R-devel/src/main/dotcode.c:757 #8 0x000000900c47 in bcEval_loop /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:8704 #9 0x0000008d7ffb in bcEval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:7533 #10 0x00000087822a in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1167 #11 0x00000088ea3a in R_execClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2398 #12 0x00000089273d in applyClosure_core /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2314 #13 0x0000008788d8 in Rf_applyClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2333 #14 0x0000008788d8 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1278 #15 0x0000008a727e in do_set /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:3585 #16 0x000000878d06 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1230 #17 0x000000a211f8 in Rf_ReplIteration /data/localhost/ripley/R/svn/R-devel/src/main/main.c:264 #18 0x000000a211f8 in R_ReplConsole /data/localhost/ripley/R/svn/R-devel/src/main/main.c:319 #19 0x000000a3eeba in run_Rmainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1239 #20 0x000000a3ef52 in Rf_mainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1246 #21 0x0000004120af in main /data/localhost/ripley/R/svn/R-devel/src/main/Rmain.c:29 #22 0x7fcff4a0a680 in __libc_start_call_main (/lib64/libc.so.6+0x3680) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #23 0x7fcff4a0a797 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3797) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #24 0x000000412a74 in _start (/data/localhost/ripley/R/gcc-SAN3/bin/exec/R+0x412a74) (BuildId: 9dff11dcd6e3f76486b274cbe4864e0a7249b59b) rmbl_mlkem_core.h:63:34: runtime error: signed integer overflow: 49808 * 62209 cannot be represented in type 'int' #0 0x7bcfe88c8588 in rmbl_mlkem_core::montgomery_reduce(int) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:63 #1 0x7bcfe88c8588 in rmbl_mlkem512::pke_keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:263 #2 0x7bcfe88c91ca in rmbl_mlkem512::keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:367 #3 0x7bcfe88d9a0c in C_rmbl_mlkem_keygen /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem.cpp:126 #4 0x00000075cd66 in R_doDotCall /data/localhost/ripley/R/svn/R-devel/src/main/dotcode.c:757 #5 0x000000900c47 in bcEval_loop /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:8704 #6 0x0000008d7ffb in bcEval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:7533 #7 0x00000087822a in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1167 #8 0x00000088ea3a in R_execClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2398 #9 0x00000089273d in applyClosure_core /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2314 #10 0x0000008788d8 in Rf_applyClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2333 #11 0x0000008788d8 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1278 #12 0x0000008a727e in do_set /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:3585 #13 0x000000878d06 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1230 #14 0x000000a211f8 in Rf_ReplIteration /data/localhost/ripley/R/svn/R-devel/src/main/main.c:264 #15 0x000000a211f8 in R_ReplConsole /data/localhost/ripley/R/svn/R-devel/src/main/main.c:319 #16 0x000000a3eeba in run_Rmainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1239 #17 0x000000a3ef52 in Rf_mainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1246 #18 0x0000004120af in main /data/localhost/ripley/R/svn/R-devel/src/main/Rmain.c:29 #19 0x7fcff4a0a680 in __libc_start_call_main (/lib64/libc.so.6+0x3680) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #20 0x7fcff4a0a797 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3797) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #21 0x000000412a74 in _start (/data/localhost/ripley/R/gcc-SAN3/bin/exec/R+0x412a74) (BuildId: 9dff11dcd6e3f76486b274cbe4864e0a7249b59b) > sent <- kem_encapsulate(kem_public_key(key)) rmbl_mlkem_core.h:63:34: runtime error: signed integer overflow: 56564 * 62209 cannot be represented in type 'int' #0 0x7bcfe88ba5cb in rmbl_mlkem_core::montgomery_reduce(int) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:63 #1 0x7bcfe88ba5cb in rmbl_mlkem_core::invntt(short*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:157 #2 0x7bcfe88ca17a in rmbl_mlkem512::pke_encrypt(unsigned char*, unsigned char const*, unsigned char const*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:304 #3 0x7bcfe88cbc65 in rmbl_mlkem512::encaps(unsigned char*, unsigned char*, unsigned char const*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:383 #4 0x7bcfe88ded78 in C_rmbl_mlkem_encaps /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem.cpp:149 #5 0x00000075cd1a in R_doDotCall /data/localhost/ripley/R/svn/R-devel/src/main/dotcode.c:760 #6 0x000000900c47 in bcEval_loop /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:8704 #7 0x0000008d7ffb in bcEval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:7533 #8 0x00000087822a in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1167 #9 0x00000088ea3a in R_execClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2398 #10 0x00000089273d in applyClosure_core /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2314 #11 0x0000008788d8 in Rf_applyClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2333 #12 0x0000008788d8 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1278 #13 0x0000008a727e in do_set /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:3585 #14 0x000000878d06 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1230 #15 0x000000a211f8 in Rf_ReplIteration /data/localhost/ripley/R/svn/R-devel/src/main/main.c:264 #16 0x000000a211f8 in R_ReplConsole /data/localhost/ripley/R/svn/R-devel/src/main/main.c:319 #17 0x000000a3eeba in run_Rmainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1239 #18 0x000000a3ef52 in Rf_mainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1246 #19 0x0000004120af in main /data/localhost/ripley/R/svn/R-devel/src/main/Rmain.c:29 #20 0x7fcff4a0a680 in __libc_start_call_main (/lib64/libc.so.6+0x3680) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #21 0x7fcff4a0a797 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3797) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #22 0x000000412a74 in _start (/data/localhost/ripley/R/gcc-SAN3/bin/exec/R+0x412a74) (BuildId: 9dff11dcd6e3f76486b274cbe4864e0a7249b59b) rmbl_mlkem_core.h:63:34: runtime error: signed integer overflow: 43904 * 62209 cannot be represented in type 'int' #0 0x7bcfe88baac5 in rmbl_mlkem_core::montgomery_reduce(int) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:63 #1 0x7bcfe88baac5 in rmbl_mlkem_core::invntt(short*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:163 #2 0x7bcfe88ca17a in rmbl_mlkem512::pke_encrypt(unsigned char*, unsigned char const*, unsigned char const*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:304 #3 0x7bcfe88cbc65 in rmbl_mlkem512::encaps(unsigned char*, unsigned char*, unsigned char const*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:383 #4 0x7bcfe88ded78 in C_rmbl_mlkem_encaps /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem.cpp:149 #5 0x00000075cd1a in R_doDotCall /data/localhost/ripley/R/svn/R-devel/src/main/dotcode.c:760 #6 0x000000900c47 in bcEval_loop /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:8704 #7 0x0000008d7ffb in bcEval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:7533 #8 0x00000087822a in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1167 #9 0x00000088ea3a in R_execClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2398 #10 0x00000089273d in applyClosure_core /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2314 #11 0x0000008788d8 in Rf_applyClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2333 #12 0x0000008788d8 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1278 #13 0x0000008a727e in do_set /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:3585 #14 0x000000878d06 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1230 #15 0x000000a211f8 in Rf_ReplIteration /data/localhost/ripley/R/svn/R-devel/src/main/main.c:264 #16 0x000000a211f8 in R_ReplConsole /data/localhost/ripley/R/svn/R-devel/src/main/main.c:319 #17 0x000000a3eeba in run_Rmainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1239 #18 0x000000a3ef52 in Rf_mainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1246 #19 0x0000004120af in main /data/localhost/ripley/R/svn/R-devel/src/main/Rmain.c:29 #20 0x7fcff4a0a680 in __libc_start_call_main (/lib64/libc.so.6+0x3680) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #21 0x7fcff4a0a797 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3797) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #22 0x000000412a74 in _start (/data/localhost/ripley/R/gcc-SAN3/bin/exec/R+0x412a74) (BuildId: 9dff11dcd6e3f76486b274cbe4864e0a7249b59b) > identical(kem_decapsulate(key, sent$ciphertext), sent$shared) [1] TRUE > > # a tampered ciphertext returns a secret, and it is the wrong one > bad <- sent$ciphertext > substring(bad, 3L, 4L) <- "ff" > other <- kem_decapsulate(key, bad) > nchar(other) == 64L [1] TRUE > identical(other, sent$shared) [1] FALSE > > > > cleanEx() > nameEx("kem_encapsulate") > ### * kem_encapsulate > > flush(stderr()); flush(stdout()) > > ### Name: kem_encapsulate > ### Title: Encapsulate a shared secret under an ML-KEM key > ### Aliases: kem_encapsulate > > ### ** Examples > > key <- kem_keygen(512) > a <- kem_encapsulate(key) > nchar(a$ciphertext) / 2 == kem_sizes(512)[["ciphertext"]] [1] TRUE > > # two encapsulations to one key give different secrets > b <- kem_encapsulate(key) > identical(a$shared, b$shared) [1] FALSE > > # both decapsulate correctly > identical(kem_decapsulate(key, a$ciphertext), a$shared) [1] TRUE > identical(kem_decapsulate(key, b$ciphertext), b$shared) [1] TRUE > > > > cleanEx() > nameEx("kem_keygen") > ### * kem_keygen > > flush(stderr()); flush(stdout()) > > ### Name: kem_keygen > ### Title: Generate an ML-KEM key pair > ### Aliases: kem_keygen kem_public_key > > ### ** Examples > > key <- kem_keygen(768) rmbl_mlkem_core.h:63:34: runtime error: signed integer overflow: 41860 * 62209 cannot be represented in type 'int' #0 0x7bcfe88d01eb in rmbl_mlkem_core::montgomery_reduce(int) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_core.h:63 #1 0x7bcfe88d01eb in rmbl_mlkem768::pke_keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:263 #2 0x7bcfe88d0e5a in rmbl_mlkem768::keygen(unsigned char*, unsigned char*, unsigned char const*) /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem_body.h:367 #3 0x7bcfe88d9c3f in C_rmbl_mlkem_keygen /data/localhost/ripley/R/packages/tests-gcc-SAN/rmoriebricklayer/src/rmbl_mlkem.cpp:126 #4 0x00000075cd66 in R_doDotCall /data/localhost/ripley/R/svn/R-devel/src/main/dotcode.c:757 #5 0x000000900c47 in bcEval_loop /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:8704 #6 0x0000008d7ffb in bcEval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:7533 #7 0x00000087822a in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1167 #8 0x00000088ea3a in R_execClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2398 #9 0x00000089273d in applyClosure_core /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2314 #10 0x0000008788d8 in Rf_applyClosure /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:2333 #11 0x0000008788d8 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1278 #12 0x0000008a727e in do_set /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:3585 #13 0x000000878d06 in Rf_eval /data/localhost/ripley/R/svn/R-devel/src/main/eval.c:1230 #14 0x000000a211f8 in Rf_ReplIteration /data/localhost/ripley/R/svn/R-devel/src/main/main.c:264 #15 0x000000a211f8 in R_ReplConsole /data/localhost/ripley/R/svn/R-devel/src/main/main.c:319 #16 0x000000a3eeba in run_Rmainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1239 #17 0x000000a3ef52 in Rf_mainloop /data/localhost/ripley/R/svn/R-devel/src/main/main.c:1246 #18 0x0000004120af in main /data/localhost/ripley/R/svn/R-devel/src/main/Rmain.c:29 #19 0x7fcff4a0a680 in __libc_start_call_main (/lib64/libc.so.6+0x3680) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #20 0x7fcff4a0a797 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x3797) (BuildId: 5bd941be836f538fe5e10eff508f7f5dd94905a6) #21 0x000000412a74 in _start (/data/localhost/ripley/R/gcc-SAN3/bin/exec/R+0x412a74) (BuildId: 9dff11dcd6e3f76486b274cbe4864e0a7249b59b) > pub <- kem_public_key(key) > > # the sender holds only the public key > sent <- kem_encapsulate(pub) > # the recipient recovers the same secret from the ciphertext > got <- kem_decapsulate(key, sent$ciphertext) > identical(sent$shared, got) [1] TRUE > > # a corrupted ciphertext yields a DIFFERENT secret, not an error > bad <- sent$ciphertext > substring(bad, 1L, 2L) <- "00" > identical(kem_decapsulate(key, bad), got) [1] FALSE > > > > cleanEx() > nameEx("kem_sizes") > ### * kem_sizes > > flush(stderr()); flush(stdout()) > > ### Name: kem_sizes > ### Title: Byte lengths of an ML-KEM parameter set > ### Aliases: kem_sizes > > ### ** Examples > > kem_sizes(768) encapsulation_key decapsulation_key ciphertext seed 1184 2400 1088 64 shared_secret 32 > > # the shared secret is 32 bytes at every level: the level buys > # security margin, not a longer secret > vapply(c(512, 768, 1024), + function(l) kem_sizes(l)[["shared_secret"]], integer(1)) [1] 32 32 32 > > > > cleanEx() > nameEx("load_provenance") > ### * load_provenance > > flush(stderr()); flush(stdout()) > > ### Name: load_provenance > ### Title: Load a Pinned Data-Provenance Record > ### Aliases: load_provenance > > ### ** Examples > > prov_file <- tempfile(fileext = ".json") > writeLines('{"dataset": {"title": "demo"}, "sha256": "abc"}', prov_file) > prov <- load_provenance(prov_file) > prov$dataset$title [1] "demo" > load_provenance(file.path(tempdir(), "no-such-file.json")) # NULL NULL > > > > cleanEx() > nameEx("mahalanobis_outliers") > ### * mahalanobis_outliers > > flush(stderr()); flush(stdout()) > > ### Name: mahalanobis_outliers > ### Title: Multivariate outliers by Mahalanobis distance > ### Aliases: mahalanobis_outliers > > ### ** Examples > > set.seed(1) > n <- 200 > df <- data.frame(height = stats::rnorm(n, 170, 10)) > df$weight <- df$height * 0.5 + stats::rnorm(n, 0, 5) > > # A row that is ordinary on each variable but impossible jointly. > df[1, ] <- list(height = 150, weight = 140) > > out <- mahalanobis_outliers(df) > head(out, 3) ── Mahalanobis outliers (robust) ───────────────────────────────── ! 1 of 3 rows beyond alpha = 0.001 row distance p_value outlier 1 9.45 <2e-16 TRUE 61 2.76 0.0224 FALSE 14 2.70 0.0258 FALSE ────────────────────────────────────────────────────────────────── > > # It is flagged, even though neither value is a marginal outlier. > out$row[1] == 1 [1] TRUE > range(df$height) [1] 147.8530 194.0162 > range(df$weight) [1] 67.07546 140.00000 > > # The classical version can be fooled by the outliers it should find. > mahalanobis_outliers(df, robust = FALSE)$distance[1] < + mahalanobis_outliers(df, robust = TRUE)$distance[1] [1] FALSE > > # A duplicated column has no distance defined, and is refused. > dup <- df > dup$height2 <- dup$height > try(mahalanobis_outliers(dup)) Error : the columns are collinear, so no Mahalanobis distance is defined. Drop the redundant column(s) -- drop_constant() and top_correlations() will find them. > > > > cleanEx() > nameEx("make_manifest") > ### * make_manifest > > flush(stderr()); flush(stdout()) > > ### Name: make_manifest > ### Title: Construct a Reproducibility Manifest > ### Aliases: make_manifest > > ### ** Examples > > # Minimal manifest, no environment capture. > man <- make_manifest(list(project = "demo-study", author = "A. Author"), + environment = FALSE) > names(man) # "meta" "results" [1] "meta" "results" > man$meta$project [1] "demo-study" > > # With environment = TRUE it also records R version / platform / packages. > full <- make_manifest(list(project = "demo"), environment = TRUE) > names(full) # adds "environment" [1] "meta" "results" "environment" > full$environment$r_version [1] "4.7.0" > > > > cleanEx() > nameEx("make_synthetic_column") > ### * make_synthetic_column > > flush(stderr()); flush(stdout()) > > ### Name: make_synthetic_column > ### Title: Generate One Synthetic Column From a Spec > ### Aliases: make_synthetic_column > > ### ** Examples > > set.seed(1) > # "sample": categorical draw, optionally weighted. > make_synthetic_column(list(type = "sample", values = list("a", "b"), + weights = list(0.7, 0.3)), 5) [1] "a" "a" "a" "b" "a" > > # "bernoulli": two-label draw at probability p. > make_synthetic_column(list(type = "bernoulli", p = 0.5, + labels = list("Yes", "No")), 5) [1] "No" "No" "No" "No" "Yes" > > # "poisson": counts with a floor via `min`. > make_synthetic_column(list(type = "poisson", lambda = 3, min = 1), 5) [1] 2 1 4 2 4 > > # "id_pattern": templated IDs (the {seq:05d} token is zero-padded). > make_synthetic_column(list(type = "id_pattern", + pattern = "case-{seq:05d}"), 3) [1] "case-00001" "case-00002" "case-00003" > > # "sequence": a running integer sequence from `from`. > make_synthetic_column(list(type = "sequence", from = 100), 4) [1] 100 101 102 103 > > # An unknown type errors. > try(make_synthetic_column(list(type = "nope"), 3)) Error in make_synthetic_column(list(type = "nope"), 3) : Unknown synthetic column type: nope > > > > cleanEx() > nameEx("make_synthetic_csv") > ### * make_synthetic_csv > > flush(stderr()); flush(stdout()) > > ### Name: make_synthetic_csv > ### Title: Generate a Synthetic CSV From a Schema Recipe > ### Aliases: make_synthetic_csv > > ### ** Examples > > recipe <- list( + n_rows = 20, seed = 42, + columns = list( + year = list(type = "sample", values = list(2024, 2025)), + alert = list(type = "bernoulli", p = 0.2), + visits = list(type = "poisson", lambda = 3, min = 1), + id = list(type = "id_pattern", pattern = "p-{seq:05d}") + ) + ) > out <- tempfile(fileext = ".csv") > res <- make_synthetic_csv(recipe, out) > res$rows # 20 [1] 20 > res$seed # 42 (reproducible) [1] 42 > > # The written CSV round-trips and has the declared columns. > df <- utils::read.csv(out) > dim(df) [1] 20 4 > names(df) [1] "year" "alert" "visits" "id" > > # `n_rows` overrides the recipe's own row count. > make_synthetic_csv(recipe, tempfile(fileext = ".csv"), n_rows = 5)$rows [1] 5 > > > > cleanEx() > nameEx("manifest_canonical") > ### * manifest_canonical > > flush(stderr()); flush(stdout()) > > ### Name: manifest_canonical > ### Title: The canonical serialisation of a manifest, and its digest > ### Aliases: manifest_canonical manifest_digest > > ### ** Examples > > a <- make_manifest(list(b = 2, a = 1), environment = FALSE) > b <- make_manifest(list(a = 1, b = 2), environment = FALSE) > # the same content in a different order has the same digest > identical(manifest_digest(a), manifest_digest(b)) [1] TRUE > > # full precision, so a recorded number can be checked later > m <- make_manifest(list(x = 1/3), environment = FALSE) > grepl("0.33333333333333331", manifest_canonical(m), fixed = TRUE) [1] TRUE > > > > cleanEx() > nameEx("manifest_recompute") > ### * manifest_recompute > > flush(stderr()); flush(stdout()) > > ### Name: manifest_recompute > ### Title: Recompute a manifest's recorded statistics against the data > ### Aliases: manifest_recompute > > ### ** Examples > > d <- data.frame(x = 1:10) > m <- make_manifest(list(dataset = "demo"), environment = FALSE) > m <- record(m, "mean_x", observed = mean(d$x), expected = 5.5) mean_x observed = 5.5000 expected = 5.5000 [PASS] > m <- record(m, "n", observed = nrow(d), expected = 10) n observed = 10.0000 expected = 10.0000 [PASS] > > # recomputing both reproduces them > res <- manifest_recompute(m, d, list(mean_x = function(z) mean(z$x), + n = function(z) nrow(z))) > res$ok [1] TRUE > res$results[, c("name", "recorded", "recomputed", "status")] name recorded recomputed status 1 mean_x 5.5 5.5 MATCH 2 n 10.0 10.0 MATCH > > # recomputing one leaves the other reported as unchecked > manifest_recompute(m, d, list(n = function(z) nrow(z)))$unchecked [1] "mean_x" > > # and data that no longer matches the record is caught > manifest_recompute(m, data.frame(x = 1:11), + list(n = function(z) nrow(z)))$ok [1] FALSE > > > > cleanEx() > nameEx("manifest_record_seed") > ### * manifest_record_seed > > flush(stderr()); flush(stdout()) > > ### Name: manifest_record_seed > ### Title: Record and restore the random number generator state > ### Aliases: manifest_record_seed manifest_restore_seed > > ### ** Examples > > set.seed(42) > m <- manifest_record_seed(make_manifest(list(a = 1), + environment = FALSE)) > first <- runif(3) > > # any amount of other work can happen in between > invisible(runif(1000)) > > manifest_restore_seed(m) > identical(runif(3), first) [1] TRUE > > > > cleanEx() > nameEx("mcar_test") > ### * mcar_test > > flush(stderr()); flush(stdout()) > > ### Name: mcar_test > ### Title: Little's test for data missing completely at random > ### Aliases: mcar_test > > ### ** Examples > > set.seed(1) > n <- 300 > x <- stats::rnorm(n) > y <- x + stats::rnorm(n) > > # Missing completely at random: a coin flip decides, so the test > # should not reject. > mcar <- data.frame(x = x, y = y) > mcar$y[sample(n, 90)] <- NA > mcar_test(mcar) ── Little's MCAR test ──────────────────────────────────────────── ✓ no departure from MCAR detected statistic 1.094 df 1 p-value 0.296 patterns 2 variables 2 rows used 300 EM iterations 13 Not evidence OF MCAR: a large p-value is a failure to detect a departure, and this test has little power on small samples. ────────────────────────────────────────────────────────────────── > > # Missing depending on the OTHER, observed variable: not MCAR, and > # detectable, because the pattern's mean of x is shifted. > mar <- data.frame(x = x, y = y) > mar$y[x > 0.4] <- NA > mcar_test(mar) ── Little's MCAR test ──────────────────────────────────────────── ✗ MCAR rejected: the missingness is related to the data statistic 180.118 df 1 p-value <2e-16 patterns 2 variables 2 rows used 300 EM iterations 69 ────────────────────────────────────────────────────────────────── > > # Complete data has one pattern and nothing to test. > mcar_test(data.frame(a = x, b = y))$df [1] 0 > > # A duplicated column makes the likelihood degenerate, and is refused. > dup <- mcar > dup$x2 <- dup$x > try(mcar_test(dup)) Error : the columns are collinear (or one is constant), so the multivariate normal likelihood Little's test is built on is degenerate. Drop the redundant column(s) first -- top_correlations() and drop_constant() will find them. > > # The EM estimates are the ML ones: with no missingness they are the > # column means and the ML (1/n) covariance. > fit <- mcar_test(data.frame(a = x, b = y)) > all.equal(fit$mu, c(mean(x), mean(y)), check.attributes = FALSE) [1] TRUE > > > > cleanEx() > nameEx("missing_runs") > ### * missing_runs > > flush(stderr()); flush(stdout()) > > ### Name: missing_runs > ### Title: Runs of consecutive missing values > ### Aliases: missing_runs > > ### ** Examples > > # One long outage and two isolated gaps, with the same total count. > df <- data.frame( + outage = c(1, 2, NA, NA, NA, NA, 7, 8), + scattered = c(1, NA, 3, 4, NA, 6, NA, NA) + ) > sum(is.na(df$outage)) == sum(is.na(df$scattered)) [1] TRUE > > missing_runs(df) ── Runs of consecutive missing values ──────────────────────────── column start end length outage 3 6 4 scattered 7 8 2 ────────────────────────────────────────────────────────────────── > > # Isolated gaps too, by lowering the threshold. > missing_runs(df, min_run = 1) ── Runs of consecutive missing values ──────────────────────────── column start end length outage 3 6 4 scattered 7 8 2 scattered 2 2 1 scattered 5 5 1 ────────────────────────────────────────────────────────────────── > > # A complete column has no runs. > missing_runs(data.frame(x = 1:5)) ── Runs of consecutive missing values ──────────────────────────── (none) ────────────────────────────────────────────────────────────────── > > > > cleanEx() > nameEx("missingness_map") > ### * missingness_map > > flush(stderr()); flush(stdout()) > > ### Name: missingness_map > ### Title: Text map of where the missing values are > ### Aliases: missingness_map > > ### ** Examples > > set.seed(1) > df <- data.frame( + complete = 1:100, + block = c(rep(NA, 30), 31:100), + scattered = ifelse(stats::runif(100) < 0.3, NA, 1), + mostly_gone = c(1:10, rep(NA, 90)) + ) > missingness_map(df) ── Missingness map ─────────────────────────────────────────────── cbsm olco moas pctt lktl eey tr_ eeg do n e 1 █▒ 6 █░ 11 █▒█ 16 █ █ 21 █▒█ 26 █░█ 31 ░█ 36 ░█ 41 █ 46 ░█ 51 ▒█ 56 ░█ 61 ░█ 66 ▒█ 71 █ 76 █ 81 █ 86 ▓█ 91 ▒█ 96 █ legend: ' ' none '█' all missing ────────────────────────────────────────────────────────────────── > > > > cleanEx() > nameEx("missingness_pattern") > ### * missingness_pattern > > flush(stderr()); flush(stdout()) > > ### Name: missingness_pattern > ### Title: Which columns are missing together > ### Aliases: missingness_pattern > > ### ** Examples > > # Two columns missing in the SAME rows: one structural gap. > structural <- data.frame( + id = 1:10, + a = c(rep(NA, 3), 4:10), + b = c(rep(NA, 3), 4:10) + ) > missingness_pattern(structural) ── Missingness patterns ────────────────────────────────────────── columns, in pattern order: id, a, b pattern n_rows pct_rows n_missing columns ... 7 70.0 0 .XX 3 30.0 2 a, b ────────────────────────────────────────────────────────────────── > > # The same per-column rates, but missing independently. > scattered <- data.frame( + id = 1:10, + a = c(rep(NA, 3), 4:10), + b = c(1:7, rep(NA, 3)) + ) > missingness_pattern(scattered) ── Missingness patterns ────────────────────────────────────────── columns, in pattern order: id, a, b pattern n_rows pct_rows n_missing columns ... 4 40.0 0 ..X 3 30.0 1 b .X. 3 30.0 1 a ────────────────────────────────────────────────────────────────── > > # A complete frame has exactly one pattern. > missingness_pattern(data.frame(x = 1:3, y = 4:6)) ── Missingness patterns ────────────────────────────────────────── columns, in pattern order: x, y pattern n_rows pct_rows n_missing columns .. 3 100.0 0 ────────────────────────────────────────────────────────────────── > > > > cleanEx() > nameEx("missingness_summary") > ### * missingness_summary > > flush(stderr()); flush(stdout()) > > ### Name: missingness_summary > ### Title: Missingness in one line per question > ### Aliases: missingness_summary > > ### ** Examples > > df <- data.frame(a = c(1, NA, 3), b = c(NA, NA, 3), c = 1:3) > missingness_summary(df) n_rows n_cols n_missing pct_missing 3.00000 3.00000 3.00000 33.33333 n_complete_rows pct_complete_rows n_cols_any_missing n_cols_all_missing 1.00000 33.33333 2.00000 0.00000 > > # A complete table is all zeros but for its dimensions. > missingness_summary(data.frame(x = 1:3, y = 4:6)) n_rows n_cols n_missing pct_missing 3 2 0 0 n_complete_rows pct_complete_rows n_cols_any_missing n_cols_all_missing 3 100 0 0 > > > > cleanEx() > nameEx("morans_i") > ### * morans_i > > flush(stderr()); flush(stdout()) > > ### Name: morans_i > ### Title: Global Moran's I over a neighbour list > ### Aliases: morans_i > > ### ** Examples > > # Six areas in a line, each adjacent to the next. > nb <- list(2L, c(1L, 3L), c(2L, 4L), c(3L, 5L), c(4L, 6L), 5L) > > # A smooth gradient is strongly positively autocorrelated. > set.seed(1) > morans_i(c(1, 2, 3, 4, 5, 6), nb, n_perm = 999L)[c("I", "p_value")] $I [1] 0.7142857 $p_value [1] 0.011 > > # An alternating pattern is negatively autocorrelated. > set.seed(1) > morans_i(c(1, 6, 1, 6, 1, 6), nb, n_perm = 999L)[c("I", "p_value")] $I [1] -1 $p_value [1] 0.199 > > # And the null expectation is not zero. > -1 / (6 - 1) [1] -0.2 > > > > cleanEx() > nameEx("oqs_keygen") > ### * oqs_keygen > > flush(stderr()); flush(stdout()) > > ### Name: oqs_keygen > ### Title: Generate a standardised post-quantum signing key (deprecated > ### name) > ### Aliases: oqs_keygen oqs_public_key > > ### ** Examples > > # Deprecated: use fips_keygen(). > key <- suppressWarnings(oqs_keygen("ML-DSA-65")) > key$scheme [1] "ML-DSA-65" > > > > cleanEx() > nameEx("parse_bands") > ### * parse_bands > > flush(stderr()); flush(stdout()) > > ### Name: parse_bands > ### Title: Parse banded category labels into numeric bounds > ### Aliases: parse_bands > > ### ** Examples > > parse_bands(c("1", "2 to 5", "6 to 10", "Greater than 10")) label lower upper open_lower open_upper 1 1 1 1 FALSE FALSE 2 2 to 5 2 5 FALSE FALSE 3 6 to 10 6 10 FALSE FALSE 4 Greater than 10 11 NA FALSE TRUE > > parse_bands(c("18 to 24", "25 to 49", "50+")) label lower upper open_lower open_upper 1 18 to 24 18 24 FALSE FALSE 2 25 to 49 25 49 FALSE FALSE 3 50+ 50 NA FALSE TRUE > > # An unrecognised label is reported as unparsed, not guessed at. > parse_bands(c("3", "unknown", "not stated")) label lower upper open_lower open_upper 1 3 3 3 FALSE FALSE 2 unknown NA NA FALSE FALSE 3 not stated NA NA FALSE FALSE > > > > cleanEx() > nameEx("period_days") > ### * period_days > > flush(stderr()); flush(stdout()) > > ### Name: period_days > ### Title: Period length in days, from dates > ### Aliases: period_days > > ### ** Examples > > period_days("2024-01-01", "2024-12-31") # a leap year [1] 366 > period_days("2023-01-01", "2023-12-31") [1] 365 > period_days("2025-04-01", "2026-03-31") # a fiscal year [1] 365 > > > > cleanEx() > nameEx("pqc_backends") > ### * pqc_backends > > flush(stderr()); flush(stdout()) > > ### Name: pqc_backends > ### Title: Available post-quantum signature schemes > ### Aliases: pqc_backends > > ### ** Examples > > pqc_backends() [1] "xmss-sha256" "ML-DSA-44" "ML-DSA-65" [4] "ML-DSA-87" "SLH-DSA-SHA2-128s" "SLH-DSA-SHA2-128f" [7] "SLH-DSA-SHA2-192s" "SLH-DSA-SHA2-192f" "SLH-DSA-SHA2-256s" [10] "SLH-DSA-SHA2-256f" "SLH-DSA-SHAKE-128s" "SLH-DSA-SHAKE-128f" [13] "SLH-DSA-SHAKE-192s" "SLH-DSA-SHAKE-192f" "SLH-DSA-SHAKE-256s" [16] "SLH-DSA-SHAKE-256f" > > # Every scheme is present in every build. > all(c("xmss-sha256", "ML-DSA-65", "SLH-DSA-SHAKE-128s") %in% + pqc_backends()) [1] TRUE > > > > cleanEx() > nameEx("pqc_keygen") > ### * pqc_keygen > > flush(stderr()); flush(stdout()) > > ### Name: pqc_keygen > ### Title: Generate a post-quantum signing key for capsule provenance > ### Aliases: pqc_keygen > > ### ** Examples > > # A small key, to keep the example quick. > key <- pqc_keygen(height = 3) > key$capacity # 8 signatures [1] 8 > key$next_index # none used yet [1] 0 > > # The public half is what a verifier needs; it carries no secret. > pub <- signing_public_key(key) > names(pub) [1] "root" "pub_seed" "height" "scheme" > > # Deterministic seeds reproduce the same key -- for tests only. > s1 <- paste(rep("11", 32), collapse = "") > s2 <- paste(rep("22", 32), collapse = "") > identical(pqc_keygen(3, s1, s2)$root, pqc_keygen(3, s1, s2)$root) [1] TRUE > > > > cleanEx() > nameEx("prereg_declare") > ### * prereg_declare > > flush(stderr()); flush(stdout()) > > ### Name: prereg_declare > ### Title: Declare an analysis before running it > ### Aliases: prereg_declare prereg_check > > ### ** Examples > > plan <- prereg_declare(c( + ate = "use of force is higher in the exposed division", + n_rows = "the extract has the row count the source publishes"), + note = "OTIS 2019-2024, division-level, pre-specified") > > # afterwards, against what was reported > prereg_check(plan, c("ate", "n_rows"))$ok [1] TRUE > > # dropping a declared outcome is outcome switching > prereg_check(plan, "n_rows")$declared_not_reported [1] "ate" > > # and adding undeclared ones is what makes a nominal p meaningless > prereg_check(plan, c("ate", "n_rows", "ate_by_year", + "ate_by_precinct"))$reported_not_declared [1] "ate_by_year" "ate_by_precinct" > > > > cleanEx() > nameEx("profile_columns") > ### * profile_columns > > flush(stderr()); flush(stdout()) > > ### Name: profile_columns > ### Title: Column report for a data frame > ### Aliases: profile_columns > > ### ** Examples > > set.seed(9) > df <- data.frame( + clean = stats::rnorm(100), + skewed = c(stats::rnorm(99), 500), + grade = sample(c("a", "b", "c"), 100, TRUE), + gappy = c(rep(NA, 10), stats::runif(90)) + ) > > profile_columns(df) ── Column profile ──────────────────────────────────────────────── column type n n_missing pct_missing n_distinct n_zero n_negative clean numeric 100 0 0 100 0 54 skewed numeric 100 0 0 100 0 48 grade character 100 0 0 3 – – gappy numeric 100 10 10 90 0 0 n_infinite mean sd median mad min max skewness n_outliers 0 -0.05351 0.9588 -0.1708 0.8777 -2.618 2.682 0.3145 3 0 4.874 50.02 0.04449 0.9517 -2.738 500 9.844 1 – – – – – – – – – 0 0.5019 0.2917 0.5243 0.3714 0.007639 0.9953 -0.04396 0 top q25 q50 q75 hist – -0.7457 -0.1708 0.422 ▁▁▃█▇█▃▃▂▁ – -0.7947 0.04449 0.6215 █ ▁ c – – – – – 0.2545 0.5243 0.7339 █▆▆█▆▇█▆█▆ ────────────────────────────────────────────────────────────────── > > # The mean and the median agree on `clean` and disagree sharply on > # `skewed`, which is the outlier announcing itself. > p <- profile_columns(df) > p[p$column %in% c("clean", "skewed"), c("column", "mean", "median")] column mean median 1 clean -0.05351488 -0.17078983 2 skewed 4.87405667 0.04448896 > > # The histogram column shows shape no summary number carries. > p[, c("column", "hist")] column hist 1 clean ▁▁▃█▇█▃▃▂▁ 2 skewed █ ▁ 3 grade 4 gappy █▆▆█▆▇█▆█▆ > > # Zeros, negatives and infinities are counted separately, because > # each breaks a different downstream computation (a log, a square > # root, an average). > p[, c("column", "n_zero", "n_negative", "n_infinite")] column n_zero n_negative n_infinite 1 clean 0 54 0 2 skewed 0 48 0 3 grade NA NA NA 4 gappy 0 0 0 > > > > cleanEx() > nameEx("random_bytes") > ### * random_bytes > > flush(stderr()); flush(stdout()) > > ### Name: random_bytes > ### Title: Cryptographically strong random bytes > ### Aliases: random_bytes > > ### ** Examples > > random_bytes(8) [1] 5a 7a 94 6f ce 4f 6b 89 > > # Independent between calls, unlike a seeded generator. > identical(random_bytes(16), random_bytes(16)) [1] FALSE > > # R's own stream is not consumed, so a seeded analysis is unaffected. > set.seed(1) > a <- stats::runif(1) > set.seed(1) > invisible(random_bytes(32)) > identical(stats::runif(1), a) [1] TRUE > > # As hex, for a seed argument. > paste(format(random_bytes(4)), collapse = "") [1] "f8f15fc6" > > > > cleanEx() > nameEx("rate") > ### * rate > > flush(stderr()); flush(stdout()) > > ### Name: rate > ### Title: Event rates per unit of population > ### Aliases: rate rate.data.frame rate.default > > ### ** Examples > > stops <- data.frame( + division = c("North", "South", "East"), + stops = c(412, 77, 3), + residents = c(120000, 41000, 9500)) > > # per 1,000 residents, the default > rate(stops, stops, residents, by = "division") ── Rate per 1,000, 95% exact Poisson interval ──────────────────── division count population rate lower upper flag East 3 9500 0.3157895 0.06512338 0.9228708 North 412 120000 3.4333333 3.10977110 3.7814142 South 77 41000 1.8780488 1.48212673 2.3472387 ────────────────────────────────────────────────────────────────── > > # the denominator published guidance usually asks for > rate(stops, stops, residents, by = "division", per = "100k") ── Rate per 100,000, 95% exact Poisson interval ────────────────── division count population rate lower upper flag East 3 9500 31.57895 6.512338 92.28708 North 412 120000 343.33333 310.977110 378.14142 South 77 41000 187.80488 148.212673 234.72387 ────────────────────────────────────────────────────────────────── > > # East's three events: the interval is wider than the estimate, and > # flagging it is the point of min_count > rate(stops, stops, residents, by = "division", per = "100k", + min_count = 5) ── Rate per 100,000, 95% exact Poisson interval ────────────────── division count population rate lower upper flag East 3 9500 31.57895 6.512338 92.28708 count at or below 5 North 412 120000 343.33333 310.977110 378.14142 South 77 41000 187.80488 148.212673 234.72387 ────────────────────────────────────────────────────────────────── > > # vectors work too, for a single figure > rate(3, 9500, per = "100k") ── Rate per 100,000, 95% exact Poisson interval ────────────────── count population rate lower upper flag 3 9500 31.57895 6.512338 92.28708 ────────────────────────────────────────────────────────────────── > > > > cleanEx() > nameEx("rate_change") > ### * rate_change > > flush(stderr()); flush(stdout()) > > ### Name: rate_change > ### Title: Change in a rate between periods > ### Aliases: rate_change rate_change.data.frame > > ### ** Examples > > d <- data.frame( + year = rep(2021:2023, each = 2), + division = rep(c("North", "South"), 3), + stops = c(400, 70, 430, 66, 455, 61), + residents = c(120000, 41000, 122000, 41500, 125000, 42000)) > > # North's count rose while its population rose too: the rate change > # is smaller than the count change, which is the reason to use it > rate_change(d, stops, residents, year, by = "division", per = "100k") ── Change in rate per 100,000, lag 1, 95% exact conditional interval division year count population rate previous_rate rate_ratio pct_change North 2021 400 120000 333.3333 NA NA NA North 2022 430 122000 352.4590 333.3333 1.0573770 5.737705 North 2023 455 125000 364.0000 352.4590 1.0327442 3.274419 South 2021 70 41000 170.7317 NA NA NA South 2022 66 41500 159.0361 170.7317 0.9314974 -6.850258 South 2023 61 42000 145.2381 159.0361 0.9132395 -8.676046 pct_lower pct_upper flag NA NA no comparison period -7.937165 21.46533 -9.679876 18.10199 NA NA no comparison period -34.473784 32.29053 -36.596300 31.35600 ────────────────────────────────────────────────────────────────── > > > > cleanEx() > nameEx("record") > ### * record > > flush(stderr()); flush(stdout()) > > ### Name: record > ### Title: Record a Cross-Check Result in a Manifest > ### Aliases: record > > ### ** Examples > > man <- make_manifest(list(project = "demo"), environment = FALSE) > > # Within tolerance -> PASS. > man <- record(man, "mean_matches", observed = 1.0001, expected = 1, + tol = 0.001) mean_matches observed = 1.0001 expected = 1.0000 [PASS] > man$results$mean_matches$status # "PASS" [1] "PASS" > > # Outside tolerance -> DIFFER. > man <- record(man, "sd_matches", observed = 2.5, expected = 2.0, tol = 0.01) sd_matches observed = 2.5000 expected = 2.0000 [DIFFER] > man$results$sd_matches$status # "DIFFER" [1] "DIFFER" > > # Synthetic data -> INFO (comparison not meaningful). > man <- record(man, "synthetic_row", observed = 5, expected = 5, + synthetic = TRUE) synthetic_row observed = 5.0000 expected = 5.0000 [INFO] > man$results$synthetic_row$status # "INFO" [1] "INFO" > > # Calls chain: record() returns the mutated manifest. > length(man$results) # 3 [1] 3 > > > > cleanEx() > nameEx("region_coverage") > ### * region_coverage > > flush(stderr()); flush(stdout()) > > ### Name: region_coverage > ### Title: Population of the regions that contain a unit, and of those that > ### do not > ### Aliases: region_coverage > > ### ** Examples > > # Four regions, two of which hold a facility. > cov <- region_coverage(region = c("A", "B", "C", "D"), + population = c(1200000, 800000, 450000, 90000), + units = c(3, 0, 1, 0)) > cov ── 4 units in 2 of 4 regions ───────────────────────────────────── those regions hold 1,650,000 of 2,540,000 residents (65.0%) 2 regions hold none; 890,000 residents (35.0%) live there region population units has_unit pop_share A 1200000 3 TRUE 47.244094 C 450000 1 TRUE 17.716535 B 800000 0 FALSE 31.496063 D 90000 0 FALSE 3.543307 The covered share is context, not a denominator: units serve catchments, so a rate over these regions alone would take its numerator from the whole territory and is inflated. ────────────────────────────────────────────────────────────────── > > # The covered share is reported, and is not a rate denominator. > attr(cov, "coverage")$covered_share [1] 64.96063 > > > > cleanEx() > nameEx("region_map_compare") > ### * region_map_compare > > flush(stderr()); flush(stdout()) > > ### Name: region_map_compare > ### Title: Compare a recomputed region map against a published one > ### Aliases: region_map_compare > > ### ** Examples > > pub <- data.frame(inst = c("North Jail", "South Jail"), + cd = c("3557", "3520"), stringsAsFactors = FALSE) > obs <- pub > region_map_compare(pub, obs, "inst") column cells mismatched first 1 rows 2 0 2 cd 2 0 > > # a changed assignment is reported with the unit that moved > obs$cd[2] <- "3521" > region_map_compare(pub, obs, "inst") column cells mismatched first 1 rows 2 0 2 cd 2 1 South Jail: published 3520, recomputed 3521 > > > > cleanEx() > nameEx("region_map_from_points") > ### * region_map_from_points > > flush(stderr()); flush(stdout()) > > ### Name: region_map_from_points > ### Title: Recompute a region map by point in polygon > ### Aliases: region_map_from_points > > ### ** Examples > > # Needs sf and a boundary file, so this is the shape of the call > # rather than a run of it. > ## Not run: > ##D obs <- region_map_from_points( > ##D x = inst$Longitude, y = inst$Latitude, unit = inst$Institution, > ##D boundaries = "lcd_000b21a_e.shp", fields = c("CDUID", "CDNAME")) > ##D stopifnot(all(obs$n_regions == 1)) > ## End(Not run) > > > > cleanEx() > nameEx("region_map_integrity") > ### * region_map_integrity > > flush(stderr()); flush(stdout()) > > ### Name: region_map_integrity > ### Title: Internal soundness of a region map > ### Aliases: region_map_integrity > > ### ** Examples > > cw <- data.frame(inst = c("North Jail", "South Jail", "East Jail"), + cd = c("3557", "3520", "3506"), + stringsAsFactors = FALSE) > region_map_integrity(cw, "inst", "cd", regions = c("3557", "3520", "3506")) check observed expected pass 1 units assigned more than one region 0 0 TRUE 2 units assigned no region 0 0 TRUE 3 region codes not in the reference geography 0 0 TRUE > > # a region code the geography does not know fails the third check > cw$cd[3] <- "2406" > region_map_integrity(cw, "inst", "cd", regions = c("3557", "3520", "3506")) check observed expected pass 1 units assigned more than one region 0 0 TRUE 2 units assigned no region 0 0 TRUE 3 region codes not in the reference geography 1 0 FALSE > > > > cleanEx() > nameEx("region_map_second_route") > ### * region_map_second_route > > flush(stderr()); flush(stdout()) > > ### Name: region_map_second_route > ### Title: Check a region map against an independently derived assignment > ### Aliases: region_map_second_route > > ### ** Examples > > cw <- data.frame(inst = c("North Jail", "South Jail", "Hill Jail"), + cd = c("3557", "3520", "3506"), + stringsAsFactors = FALSE) > > # a name-based route that is known to mis-place one unit > route <- c("North Jail" = "3557", "South Jail" = "3520", + "Hill Jail" = "3519") > region_map_second_route(cw, "inst", "cd", route, known = "Hill Jail") unit primary second known 1 Hill Jail 3506 3519 TRUE > > # an undocumented disagreement is what the check is for > route["South Jail"] <- "3521" > d <- region_map_second_route(cw, "inst", "cd", route, known = "Hill Jail") > sum(!d$known) [1] 1 > > > > cleanEx() > nameEx("report_markdown") > ### * report_markdown > > flush(stderr()); flush(stdout()) > > ### Name: report_markdown > ### Title: Write a capsule report as Markdown > ### Aliases: report_markdown > > ### ** Examples > > set.seed(1) > df <- data.frame(v = stats::rnorm(100), g = rep("x", 100), + stringsAsFactors = FALSE) > r <- capsule_report(df) > > md <- report_markdown(r) > cat(head(md, 8), sep = "\n") # Capsule report Notes only -- worth a look, nothing blocking. | | | |---|---| | rows | 100 | | columns | 2 | > > # Written beside the capsule it describes. > p <- tempfile(fileext = ".md") > report_markdown(r, p) > file.exists(p) [1] TRUE > unlink(p) > > > > cleanEx() > nameEx("resolve_via_arcgis") > ### * resolve_via_arcgis > > flush(stderr()); flush(stdout()) > > ### Name: resolve_via_arcgis > ### Title: Resolve a Query URL via ArcGIS FeatureServer Metadata > ### Aliases: resolve_via_arcgis > > ### ** Examples > > # Missing fields return NULL rather than erroring: > resolve_via_arcgis(list()) NULL > > > > cleanEx() > nameEx("resolve_via_ckan") > ### * resolve_via_ckan > > flush(stderr()); flush(stdout()) > > ### Name: resolve_via_ckan > ### Title: Resolve a Download URL via CKAN package_show > ### Aliases: resolve_via_ckan > > ### ** Examples > > # Missing fields return NULL rather than erroring: > resolve_via_ckan(list()) NULL > > > > cleanEx() > nameEx("resolve_via_ckan_search") > ### * resolve_via_ckan_search > > flush(stderr()); flush(stdout()) > > ### Name: resolve_via_ckan_search > ### Title: Resolve a Download URL via CKAN package_search > ### Aliases: resolve_via_ckan_search > > ### ** Examples > > # Missing fields return NULL rather than erroring: > resolve_via_ckan_search(list()) NULL > > > > cleanEx() > nameEx("resolve_via_socrata") > ### * resolve_via_socrata > > flush(stderr()); flush(stdout()) > > ### Name: resolve_via_socrata > ### Title: Resolve a Download URL via the Socrata Metadata API > ### Aliases: resolve_via_socrata > > ### ** Examples > > # Missing fields return NULL rather than erroring: > resolve_via_socrata(list()) NULL > > > > cleanEx() > nameEx("revocation_fetch") > ### * revocation_fetch > > flush(stderr()); flush(stdout()) > > ### Name: revocation_fetch > ### Title: Fetch revocation data for a certificate path > ### Aliases: revocation_fetch > > ### ** Examples > > # Reaches the network, so it is not run here. > ## Not run: > ##D res <- cert_chain_verify("leaf.crt", trust = "ca.crt", > ##D revocation = "fetch") > ##D res$checks > ## End(Not run) > > > > cleanEx() > nameEx("rmbl_base64") > ### * rmbl_base64 > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_base64 > ### Title: Base64 encoding > ### Aliases: rmbl_base64 bricklayer_json_base64_enc > ### bricklayer_json_base64_dec bricklayer_json_base64url_enc > ### bricklayer_json_base64url_dec > > ### ** Examples > > # Round trip through the standard alphabet. > b <- bricklayer_json_base64_enc("hello capsule") > b [1] "aGVsbG8gY2Fwc3VsZQ==" > rawToChar(bricklayer_json_base64_dec(b)) [1] "hello capsule" > > # Raw input works the same way. > bricklayer_json_base64_enc(charToRaw("abc")) [1] "YWJj" > bricklayer_json_base64_dec(bricklayer_json_base64_enc(charToRaw("abc"))) [1] 61 62 63 > > # Padding appears when the length is not a multiple of three. > bricklayer_json_base64_enc("a") [1] "YQ==" > bricklayer_json_base64_enc("ab") [1] "YWI=" > bricklayer_json_base64_enc("abc") [1] "YWJj" > > # The URL-safe variant has no "+", "/" or "=" to escape. > bricklayer_json_base64url_enc(as.raw(c(255, 224, 63))) [1] "_-A_" > bricklayer_json_base64_enc(as.raw(c(255, 224, 63))) [1] "/+A/" > bricklayer_json_base64url_dec( + bricklayer_json_base64url_enc("path/safe?yes") + ) [1] 70 61 74 68 2f 73 61 66 65 3f 79 65 73 > > # Long input is wrapped, and the decoder ignores the breaks. > long <- bricklayer_json_base64_enc(strrep("x", 200)) > grepl("\n", long) [1] TRUE > rawToChar(bricklayer_json_base64_dec(long)) == strrep("x", 200) [1] TRUE > > > > cleanEx() > nameEx("rmbl_chain") > ### * rmbl_chain > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_chain > ### Title: Tamper-evident chain of capsule manifests > ### Aliases: rmbl_chain chain_new chain_append chain_head chain_seal > ### chain_verify > > ### ** Examples > > ch <- chain_new() > ch <- chain_append(ch, "manifest for run 1", label = "run-1") > ch <- chain_append(ch, "manifest for run 2", label = "run-2") > ch <- chain_append(ch, "manifest for run 3", label = "run-3") > ch ── Manifest chain ──────────────────────────────────────────────── ✓ chain intact entries 3 head 2afe0e270d2b1fbbc080dd4624540c181e5b8458aaecf247ccb8c38dc4c387da seal de28f9277b3f9f4cb3b1a7dd80e556d0c6e1568723f1395732f9d087ee7f7353 1 run-1 7947c9201969a6793f9daf05 2 run-2 9dbaa6d33259f974f30ff33e 3 run-3 2afe0e270d2b1fbbc080dd46 ────────────────────────────────────────────────────────────────── > > # An intact chain verifies. > chain_verify(ch)$valid [1] TRUE > > # Editing an entry breaks it, and names where. > edited <- ch > edited$entries[[2]]$digest <- core_sha256("something else") > chain_verify(edited)$valid [1] FALSE > chain_verify(edited)$broken_at [1] 2 > > # So does deleting one, which a per-manifest digest would not catch. > dropped <- ch > dropped$entries[[2]] <- NULL > chain_verify(dropped)$valid [1] FALSE > > # Sign the SEAL, which covers the links and the length together. > key <- pqc_keygen(height = 2) > sig <- capsule_sign(chain_seal(ch), key) > capsule_verify(chain_seal(ch), sig, signing_public_key(key)) [1] TRUE > > # Truncating the chain still seals, but to a different value, so the > # signature no longer verifies. > truncated <- ch > truncated$entries[[3]] <- NULL > capsule_verify(chain_seal(truncated), sig, signing_public_key(key)) [1] FALSE > > # A chain whose links disagree has no seal to present at all. > chain_seal(dropped) [1] NA > > > > cleanEx() > nameEx("rmbl_core_rank") > ### * rmbl_core_rank > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_core_rank > ### Title: Rank correlation and midranks (C backend) > ### Aliases: rmbl_core_rank core_cor_spearman core_midranks > > ### ** Examples > > x <- c(1, 2, 3, 4, 5) > y <- c(2, 4, 9, 16, 25) > > # Perfectly monotone but not linear: rho is 1 where Pearson is not. > core_cor_spearman(x, y) [1] 1 > core_cor(x, y) [1] 0.9737247 > > # Agrees with stats::cor(), ties included. > xt <- c(1, 2, 2, 2, 5, 5, 7) > yt <- c(3, 1, 1, 4, 4, 9, 2) > all.equal(core_cor_spearman(xt, yt), stats::cor(xt, yt, method = "spearman")) [1] TRUE > > # Tied values share the average of the ranks they cover. > core_midranks(xt) [1] 1.0 3.0 3.0 3.0 5.5 5.5 7.0 > all.equal(core_midranks(xt), rank(xt)) [1] TRUE > > # Invariant to any monotone rescaling. > all.equal(core_cor_spearman(x, y), core_cor_spearman(exp(x), log(y))) [1] TRUE > > > > cleanEx() > nameEx("rmbl_core_robust") > ### * rmbl_core_robust > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_core_robust > ### Title: Quantiles, median and robust spread (C backend) > ### Aliases: rmbl_core_robust core_quantile core_median core_mad core_iqr > ### core_tukey_fences > > ### ** Examples > > x <- c(2, 4, 4, 4, 5, 5, 7, 9) > core_quantile(x, c(0.25, 0.5, 0.75)) 25% 50% 75% 4.0 4.5 5.5 > all.equal(core_quantile(x, c(0.1, 0.9)), + as.numeric(stats::quantile(x, c(0.1, 0.9)))) [1] "names for target but not for current" > > core_median(x) [1] 4.5 > core_mad(x) [1] 0.7413 > all.equal(core_mad(x), stats::mad(x)) [1] TRUE > core_mad(x, constant = 1) # unscaled median deviation [1] 0.5 > core_mad(x, constant = 1 / stats::qnorm(3/4)) # unrounded constant [1] 0.7413011 > > core_iqr(x) [1] 1.5 > core_tukey_fences(x) lower upper 1.75 7.75 > > # Robustness: one wild value barely moves the median, but moves the > # mean a long way. > wild <- c(x, 1000) > c(mean = mean(wild), median = core_median(wild)) mean median 115.5556 5.0000 > > # Values outside the fences are the candidates to inspect. > f <- core_tukey_fences(wild) > wild[wild < f[["lower"]] | wild > f[["upper"]]] [1] 1000 > > > > cleanEx() > nameEx("rmbl_core_spread") > ### * rmbl_core_spread > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_core_spread > ### Title: Standard deviation and Euclidean distance (C backend) > ### Aliases: rmbl_core_spread core_sd core_dist > > ### ** Examples > > # Sample standard deviation, matching stats::sd(). > core_sd(c(2, 4, 4, 4, 5, 5, 7, 9)) [1] 2.13809 > all.equal(core_sd(1:10), stats::sd(1:10)) [1] TRUE > > # ddof = 0 divides by n instead of n - 1. > core_sd(1:10, ddof = 0) [1] 2.872281 > all.equal(core_sd(1:10, ddof = 0), sqrt(mean((1:10 - mean(1:10))^2))) [1] TRUE > > # Euclidean distance between two points. > core_dist(c(0, 0), c(3, 4)) # 5 [1] 5 > core_dist(1:5, 1:5) # 0 -- a point is zero from itself [1] 0 > > > > cleanEx() > nameEx("rmbl_core_stats") > ### * rmbl_core_stats > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_core_stats > ### Title: Fast summary statistics (C backend) > ### Aliases: rmbl_core_stats core_mean core_var core_cor > > ### ** Examples > > ## core_mean(): sample mean (NA/NaN propagate; no na.rm) > core_mean(1:10) # 5.5 [1] 5.5 > core_mean(c(2.5, 3.5)) # 3 [1] 3 > core_mean(c(1, 2, NA)) # NA -- call stats::na.omit() first if needed [1] NA > core_mean(stats::na.omit(c(1, 2, NA))) [1] 1.5 > > ## core_var(): n-1 (sample) variance, matching stats::var() > core_var(c(2, 4, 4, 4, 5, 5, 7, 9)) [1] 4.571429 > all.equal(core_var(1:10), stats::var(1:10)) # agrees with base R [1] TRUE > > ## core_cor(): Pearson correlation of two equal-length vectors > core_cor(1:10, (1:10)^2) # strong positive, near 0.97 [1] 0.9745586 > core_cor(1:10, 10:1) # perfect negative: -1 [1] -1 > > > > cleanEx() > nameEx("rmbl_core_trimmed") > ### * rmbl_core_trimmed > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_core_trimmed > ### Title: Trimmed and winsorized means (C backend) > ### Aliases: rmbl_core_trimmed core_trimmed_mean core_winsorized_mean > > ### ** Examples > > x <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 100) > > mean(x) # dragged up by the 100 [1] 14.5 > core_trimmed_mean(x, 0.1) # the 100 and the 1 dropped [1] 5.5 > core_winsorized_mean(x, 0.1) # the 100 pulled back to 9 [1] 5.5 > > # Agrees with base R's own trimming. > all.equal(core_trimmed_mean(x, 0.2), mean(x, trim = 0.2)) [1] TRUE > > # trim = 0 is the plain mean; trim = 0.5 is the median. > all.equal(core_trimmed_mean(x, 0), mean(x)) [1] TRUE > all.equal(core_trimmed_mean(x, 0.5), core_median(x)) [1] TRUE > > > > cleanEx() > nameEx("rmbl_distinct") > ### * rmbl_distinct > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_distinct > ### Title: Distinct-value count in fixed memory > ### Aliases: rmbl_distinct distinct_sketch distinct_count sketch_merge > > ### ** Examples > > set.seed(1) > x <- sample(1:5000, 200000, replace = TRUE) > > # Close to the true 5000 distinct values, in fixed memory. > distinct_count(distinct_sketch(x)) [1] 5039.269 > length(unique(x)) [1] 5000 > > # Small cardinalities are near-exact, via linear counting. > distinct_count(distinct_sketch(c("a", "b", "c", "a", "b"))) [1] 3.000275 > > # Chunks fold into one sketch, so a file can be counted block by > # block, and two independent sketches can be merged. > s <- distinct_sketch(x[1:100000]) > s <- distinct_sketch(x[100001:200000], registers = s) > distinct_count(s) [1] 5039.269 > > a <- distinct_sketch(x[1:100000]) > b <- distinct_sketch(x[100001:200000]) > distinct_count(sketch_merge(a, b)) [1] 5039.269 > > # An empty input has no distinct values. > distinct_count(distinct_sketch(character(0))) [1] 0 > > > > cleanEx() > nameEx("rmbl_drop") > ### * rmbl_drop > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_drop > ### Title: Drop empty or constant columns and rows > ### Aliases: rmbl_drop drop_empty drop_constant > > ### ** Examples > > df <- data.frame( + keep = c(1, 2, NA), + all_na = c(NA, NA, NA), + constant = c(7, 7, 7), + stringsAsFactors = FALSE + ) > > drop_empty(df) keep constant 1 1 7 2 2 7 3 NA 7 > attr(drop_empty(df), "dropped") [1] "all_na" > > drop_constant(df) keep 1 1 2 2 3 NA > > # Rows only. > drop_empty(data.frame(a = c(1, NA), b = c(2, NA)), which = "rows") a b 1 1 2 > > # A column of NAs plus one value is constant by default, and not when > # NA is treated as a value of its own. > x <- data.frame(v = c(NA, NA, 5)) > ncol(drop_constant(x)) [1] 0 > ncol(drop_constant(x, na_as_value = TRUE)) [1] 1 > > > > cleanEx() > nameEx("rmbl_file_digest") > ### * rmbl_file_digest > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_file_digest > ### Title: SHA-512 and CRC-32 of a file > ### Aliases: rmbl_file_digest sha512_file crc32_file > > ### ** Examples > > p <- tempfile() > writeLines("capsule payload", p) > > sha512_file(p) [1] "5d0664a30f586585aca8896c34269ca62f2eba708d5d7983a80925d50eaee5535116f104f245649f33054880810b4f88c542d70fd86ba95111f80342fa9bf9ba" > crc32_file(p) [1] 2211766739 > > # The block size is a speed knob and cannot change the digest. > identical(sha512_file(p, 16), sha512_file(p, 1048576)) [1] TRUE > > unlink(p) > > > > cleanEx() > nameEx("rmbl_json_gzip") > ### * rmbl_json_gzip > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_json_gzip > ### Title: Compressed, base64-encoded JSON > ### Aliases: rmbl_json_gzip json_gzip_encode json_gzip_decode > > ### ** Examples > > x <- list(rows = data.frame(id = 1:50, value = stats::runif(50))) > > enc <- json_gzip_encode(x) > substring(enc, 1, 40) [1] "H4sIAAAAAAAA/1WTy0oEQQxF/6XXg1Qelcf8irgQ" > > # Smaller than the JSON it came from, because the keys repeat. > c(json = nchar(bricklayer_json_to_json(x)), gzip_b64 = nchar(enc)) json gzip_b64 1246 437 > > # Round trips. > identical(json_gzip_decode(enc)$rows$id, 1:50) [1] TRUE > > # Raw gzip bytes, for writing to a file. > bytes <- json_gzip_encode(x, raw = TRUE) > class(bytes) [1] "raw" > identical(json_gzip_decode(bytes, raw = TRUE)$rows$id, 1:50) [1] TRUE > > > > cleanEx() > nameEx("rmbl_json_serialize") > ### * rmbl_json_serialize > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_json_serialize > ### Title: Lossless JSON serialisation of an R object > ### Aliases: rmbl_json_serialize bricklayer_json_serialize > ### bricklayer_json_unserialize > > ### ** Examples > > # A factor survives the round trip with its levels intact. > f <- factor(c("b", "a", "b"), levels = c("a", "b", "c")) > back <- bricklayer_json_unserialize(bricklayer_json_serialize(f)) > identical(back, f) [1] TRUE > > # So does a matrix, with its dimensions. > m <- matrix(1:6, nrow = 2) > identical(bricklayer_json_unserialize(bricklayer_json_serialize(m)), m) [1] TRUE > > # Plain data JSON does not keep either, which is the trade-off. > bricklayer_json_to_json(f) [1] "[\"b\",\"a\",\"b\"]" attr(,"class") [1] "json" > > # Nested lists, names and NULLs round trip too. > x <- list(a = 1:3, b = list(c = "x", d = NULL), e = TRUE) > identical(bricklayer_json_unserialize(bricklayer_json_serialize(x)), x) [1] TRUE > > # The serialised form is JSON, so it can be pinned like any other text. > nchar(core_sha256(bricklayer_json_serialize(m))) [1] 64 > > > > cleanEx() > nameEx("rmbl_keyed_digest") > ### * rmbl_keyed_digest > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_keyed_digest > ### Title: Keyed digest and constant-time comparison (C backend) > ### Aliases: rmbl_keyed_digest core_hmac_sha256 core_digest_equal > > ### ** Examples > > # RFC 4231 test case 2. > core_hmac_sha256("Jefe", "what do ya want for nothing?") [1] "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843" > > # The key changes the digest, so a manifest cannot be re-signed > # without it. > core_hmac_sha256("key-a", "manifest") [1] "463b8b2c47caadd6334c53e4d9492fdac6fcaca185f56229043e1a025138ceae" > core_hmac_sha256("key-b", "manifest") [1] "f3ebaf1b8fad504c57fd4cf82b163e30eac6eabd31b7c41a2a6e268ec445b134" > > # Raw keys and messages are accepted. > core_hmac_sha256(as.raw(rep(0x0b, 20)), "Hi There") [1] "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7" > > # Compare tags in constant time, never with ==. > tag <- core_hmac_sha256("k", "m") > core_digest_equal(tag, core_hmac_sha256("k", "m")) [1] TRUE > core_digest_equal(tag, core_hmac_sha256("k", "tampered")) [1] FALSE > core_digest_equal(tag, "too-short") [1] FALSE > > > > cleanEx() > nameEx("rmbl_merkle") > ### * rmbl_merkle > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_merkle > ### Title: Merkle tree over capsule chunks (C backend) > ### Aliases: rmbl_merkle merkle_root merkle_leaves merkle_proof > ### merkle_verify > > ### ** Examples > > chunks <- c("row1,row2", "row3,row4", "row5,row6", "row7,row8") > > root <- merkle_root(chunks) > root [1] "d2197affda886ecc49807b28c90a8c4ff7a07f122225ecc64788d08df5a312f3" > > # A single chunk's root is just its own digest. > merkle_root("only") == core_sha256("only") [1] TRUE > > # The leaves are the per-chunk digests, so a diff names the culprit. > before <- merkle_leaves(chunks) > after <- merkle_leaves(c(chunks[1:2], "row5,row6-EDITED", chunks[4])) > which(before != after) [1] 3 > > # Prove chunk 3 belongs, without holding chunks 1, 2 or 4. > pr <- merkle_proof(chunks, 3) > pr $sibling [1] "a9199c29a2bc724e33e3dd4ad9bffd41e9bc0f187d998b46676980240fe16bce" [2] "797f2302a18a964bc609952c054c5ed815d371dc71428cade513006202d05a9c" $side [1] "right" "left" > merkle_verify(chunks[3], pr, root) [1] TRUE > > # The proof fails for a chunk that was not in the tree. > merkle_verify("row5,row6-EDITED", pr, root) [1] FALSE > > # Any change to any chunk changes the root. > merkle_root(chunks) == merkle_root(c(chunks[1:3], "row7,row8 ")) [1] FALSE > > > > cleanEx() > nameEx("rmbl_online") > ### * rmbl_online > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_online > ### Title: Exact summary statistics accumulated in blocks > ### Aliases: rmbl_online online_summary summary_update summary_merge > ### summary_stats > > ### ** Examples > > set.seed(1) > x <- stats::rnorm(1000) > > # Accumulate in blocks of 100. > acc <- online_summary() > for (i in seq(1, 1000, by = 100)) { + acc <- summary_update(acc, x[i:(i + 99)]) + } > summary_stats(acc) n mean variance sd skewness 1.000000e+03 -1.164814e-02 1.071051e+00 1.034916e+00 -1.916710e-02 kurtosis -1.775465e-03 > > # Which is exactly the batch answer, not an approximation to it. > all.equal(summary_stats(acc)[["variance"]], stats::var(x)) [1] TRUE > all.equal(summary_stats(acc)[["mean"]], mean(x)) [1] TRUE > > # Two accumulators built independently can be merged, so blocks can be > # processed in any order or on different machines. > a <- summary_update(online_summary(), x[1:400]) > b <- summary_update(online_summary(), x[401:1000]) > all.equal(summary_stats(summary_merge(a, b)), summary_stats(acc)) [1] TRUE > > # An empty accumulator reports nothing rather than zero. > summary_stats(online_summary()) n mean variance sd skewness kurtosis 0 NaN NaN NaN NaN NaN > > > > cleanEx() > nameEx("rmbl_print_methods") > ### * rmbl_print_methods > > flush(stderr()); flush(stdout()) > > ### Name: print.bricklayer_attestation > ### Title: Printed reports for bricklayer objects > ### Aliases: print.bricklayer_attestation > ### print.bricklayer_attestation_check print.bricklayer_bundle > ### print.bricklayer_bundle_check print.bricklayer_chain > ### print.bricklayer_falsification print.bricklayer_kem_key > ### print.bricklayer_kem_public_key print.bricklayer_kem_capsule > ### print.bricklayer_mcar print.bricklayer_power print.bricklayer_prereg > ### print.bricklayer_prereg_check print.bricklayer_falsify_family > ### rmbl_print_methods print.bricklayer_drift summary.bricklayer_drift > ### print.bricklayer_benford print.bricklayer_signing_key > ### print.bricklayer_public_key print.bricklayer_signature > ### summary.bricklayer_benford print.bricklayer_env_diff > ### print.bricklayer_report summary.bricklayer_report > ### print.bricklayer_recompute print.bricklayer_schema > ### print.bricklayer_oqs_key print.bricklayer_oqs_public_key > ### print.bricklayer_timestamp print.bricklayer_certificate > ### print.bricklayer_certpath_check > > ### ** Examples > > set.seed(7) > ref <- data.frame(v = stats::rnorm(200), + g = sample(c("a", "b"), 200, TRUE)) > cur <- data.frame(v = stats::rnorm(200, mean = 1), + g = sample(c("a", "b"), 200, TRUE)) > > # The drift report leads with its verdict. > capsule_drift(ref, cur) ── Capsule drift report ────────────────────────────────────────── ✗ DRIFT DETECTED reference rows 200 current rows 200 columns tested 2 alpha 0.01 ── Per-column tests ────────────────────────────────────────────── column type stat p psi ✗ v numeric 0.36 1.11e-11 0.814 ✓ g categorical 1.44 0.23 – ────────────────────────────────────────────────────────────────── > > # format() gives the same lines for a log file. > head(format(capsule_drift(ref, cur)), 3) [1] "── Capsule drift report ──────────────────────────────────────────" [2] " ✗ DRIFT DETECTED" [3] "" > > # A Benford screen. > benford_test(10^stats::runif(500, 0, 5)) ── Benford first-digit screen ──────────────────────────────────── ✓ consistent with Benford's law values used 500 chi-square 5.919 df 8 p-value 0.656 digit observed expected shape 1 0.300 0.301 #################### 2 0.184 0.176 ############ 3 0.124 0.125 ######## 4 0.112 0.097 ####### 5 0.078 0.079 ##### 6 0.066 0.067 #### 7 0.062 0.058 #### 8 0.030 0.051 ## 9 0.044 0.046 ### ────────────────────────────────────────────────────────────────── > > # Keys and signatures print without ever showing the secret seed. > key <- pqc_keygen(height = 2) > key ── Signing key (post-quantum) ──────────────────────────────────── scheme xmss-sha256 root e39fa7ac75aa584f7ec7919b4e4a1e9163ad864a0c54d3cedc36d2dc0a1a6caa height 2 used 0 of 4 signatures remaining 4 secret ! one signature per index; never sign twice at one index ────────────────────────────────────────────────────────────────── > capsule_sign("a-manifest", key) ── Capsule signature ───────────────────────────────────────────── scheme xmss-sha256 index 0 root e39fa7ac75aa584f7ec7919b4e4a1e9163ad864a0c54d3cedc36d2dc0a1a6caa signature ed2a8ac003d177ab6385701196d3861f... (2144 bytes) auth path 2 nodes ────────────────────────────────────────────────────────────────── > > > > cleanEx() > nameEx("rmbl_reservoir") > ### * rmbl_reservoir > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_reservoir > ### Title: Uniform sample of a stream in one pass > ### Aliases: rmbl_reservoir reservoir_indices reservoir_sample > > ### ** Examples > > # A reproducible sample of 5 from 1000. > reservoir_indices(1000, 5, seed = 1) [1] 33 67 304 630 638 > reservoir_sample(letters, 4, seed = 2) [1] "m" "r" "s" "z" > > # Reproducible, and independent of R's own RNG. > identical(reservoir_indices(1000, 5, seed = 1), + reservoir_indices(1000, 5, seed = 1)) [1] TRUE > > # Asking for more than the stream holds returns the whole stream. > reservoir_indices(3, 10) [1] 1 2 3 > > # Every item is equally likely: over many seeds the retained positions > # are spread uniformly rather than favouring the start or the end. > hits <- unlist(lapply(1:400, function(s) reservoir_indices(50, 5, s))) > round(mean(hits)) # near the midpoint, 25.5 [1] 26 > > > > cleanEx() > nameEx("rmbl_rule_library") > ### * rmbl_rule_library > > flush(stderr()); flush(stdout()) > > ### Name: rmbl_rule_library > ### Title: Ready-made validation rules > ### Aliases: rmbl_rule_library rule_in_set rule_between rule_not_null > ### rule_unique rule_regex rule_increasing rule_within_n_mads > ### rule_complete_rows rule_distinct_rows rule_col_count > > ### ** Examples > > df <- data.frame( + id = c(1, 2, 2), + grade = c("a", "b", "z"), + score = c(5, 200, 7), + email = c("a@b.com", "nope", "c@d.org"), + day = c(3, 1, 2), + stringsAsFactors = FALSE + ) > > rules <- list( + rule_unique("id", severity = "fatal"), + rule_in_set("grade", c("a", "b", "c")), + rule_between("score", 0, 100), + rule_regex("email", "^[^@]+@[^@]+\\\\.[a-z]+$"), + rule_increasing("day") + ) > names(validate_rules(df, rules)) [1] "id_unique" "grade_in_set" "score_between" "email_regex" [5] "day_increasing" > > # Each names the rows that failed. > validate_rules(df, rules)$grade_in_set$rows [1] 3 > > # Clean data passes every one of them. > ok <- data.frame(id = 1:3, grade = c("a", "b", "c"), + score = c(5, 50, 7), + email = c("a@b.com", "c@d.org", "e@f.net"), + day = 1:3, stringsAsFactors = FALSE) > length(validate_rules(ok, rules)) [1] 1 > > # A robust outlier rule: MADs from the median, not standard > # deviations from the mean, so one wild value cannot hide the others. > validate_rules(data.frame(v = c(1, 2, 3, 2, 1, 900)), + rule_within_n_mads("v", 5))$v_within_mads$rows [1] 6 > > # Whole-table rules. > validate_rules(df, rule_distinct_rows()) list() > validate_rules(df, rule_col_count(5)) list() > validate_rules(df, rule_complete_rows()) list() > > > > cleanEx() > nameEx("rule") > ### * rule > > flush(stderr()); flush(stdout()) > > ### Name: rule > ### Title: Declare a validation rule > ### Aliases: rule > > ### ** Examples > > # A column predicate, applied row-wise. > rule("age_non_negative", function(v) v >= 0, column = "age") age_non_negative [warning] on `age` > > # A whole-column property. > rule("id_unique", function(v) !anyDuplicated(v), column = "id", + severity = "fatal") id_unique [fatal] on `id` > > # A table-level rule spanning two columns. > rule("dates_ordered", function(df) all(df$start <= df$end)) dates_ordered [warning] table-level > > > > cleanEx() > nameEx("sha256_file") > ### * sha256_file > > flush(stderr()); flush(stdout()) > > ### Name: sha256_file > ### Title: Compute a File's SHA256 Digest > ### Aliases: sha256_file > > ### ** Examples > > f <- tempfile() > writeLines("hello capsule", f) > sha256_file(f) [1] "55d6110230c260319d580bb6274db530b7e751c4f687fc00d0736ec531260a02" > > # Deterministic: the same bytes always yield the same digest. > identical(sha256_file(f), sha256_file(f)) [1] TRUE > > # Any change to the file changes the digest (tamper-evidence). > before <- sha256_file(f) > writeLines("hello capsule (edited)", f) > after <- sha256_file(f) > before == after # FALSE [1] FALSE > > # Provenance pin: record a digest, verify it later. > pinned <- sha256_file(f) > stopifnot(sha256_file(f) == pinned) > > > > cleanEx() > nameEx("share") > ### * share > > flush(stderr()); flush(stdout()) > > ### Name: share > ### Title: Share of a total, in percent > ### Aliases: share share.data.frame share.default > > ### ** Examples > > stops <- data.frame( + division = c("North", "South", "East"), + stops = c(412, 77, 3)) > > # shares of the table's own total, summing to 100 > share(stops, stops, by = "division") ── Share of 492, 95% Wilson interval ───────────────────────────── division count total share lower upper East 3 492 0.6097561 0.2075843 1.777215 North 412 492 83.7398374 80.2200225 86.736863 South 77 492 15.6504065 12.7074531 19.125597 ────────────────────────────────────────────────────────────────── > > # East is 0.6% of stops, and the interval does not run below zero > # the way a normal approximation would > share(stops, stops, by = "division")$lower [1] 0.2075843 80.2200225 12.7074531 > > # a denominator from outside the table > share(stops, stops, by = "division", total = 10000) ── Share of 10,000, 95% Wilson interval ────────────────────────── division count total share lower upper East 3 10000 0.03 0.01020322 0.08817358 North 412 10000 4.12 3.74774662 4.52748907 South 77 10000 0.77 0.61657440 0.96123408 ────────────────────────────────────────────────────────────────── > > > > cleanEx() > nameEx("signing_public_key") > ### * signing_public_key > > flush(stderr()); flush(stdout()) > > ### Name: signing_public_key > ### Title: Public half of a signing key > ### Aliases: signing_public_key > > ### ** Examples > > key <- pqc_keygen(height = 2) > pub <- signing_public_key(key) > > # The secret seed is gone. > is.null(pub$sk_seed) [1] TRUE > > # And verification works from the public half alone. > sig <- capsule_sign("manifest-digest", key) > capsule_verify("manifest-digest", sig, pub) [1] TRUE > > > > cleanEx() > nameEx("sir") > ### * sir > > flush(stderr()); flush(stdout()) > > ### Name: sir > ### Title: Standardised incidence ratio, with an exact interval > ### Aliases: sir > > ### ** Examples > > sir(observed = c(30, 12, 3), expected = c(20, 14, 5), + area = c("North", "South", "East")) area observed expected sir lower upper excess 1 North 30 20 1.5000000 1.0120437 2.141343 TRUE 2 South 12 14 0.8571429 0.4428982 1.497256 FALSE 3 East 3 5 0.6000000 0.1237344 1.753455 FALSE > > # An observed count of three carries almost no information, and the > # interval says so rather than hiding it. > sir(3, 5) observed expected sir lower upper excess 1 3 5 0.6 0.1237344 1.753455 FALSE > > > > cleanEx() > nameEx("stay_summary") > ### * stay_summary > > flush(stderr()); flush(stdout()) > > ### Name: stay_summary > ### Title: Length of stay with its distribution and interval > ### Aliases: stay_summary > > ### ** Examples > > # a skewed distribution: most stays short, a few long > stays <- c(rep(1, 40), rep(3, 30), rep(10, 20), 60, 90, 120) > stay_summary(stays) n total_days mean sd median iqr max se lower upper 1 93 600 6.451613 16.33183 3 2 120 1.693532 3.088113 9.815113 > > # the mean is pulled well above the median by the long tail > stay_summary(stays)[, c("mean", "median", "max")] mean median max 1 6.451613 3 120 > > > > cleanEx() > nameEx("step_change") > ### * step_change > > flush(stderr()); flush(stdout()) > > ### Name: step_change > ### Title: A single step change, with the scan's own null distribution > ### Aliases: step_change > > ### ** Examples > > # A clear step down after the third period. > step_change(c(100, 104, 98, 60, 63, 58)) $break_after [1] 3 $index [1] 3 $before [1] 100.6667 $after [1] 60.33333 $difference [1] -40.33333 $statistic [1] 2440.167 $p_value [1] 0.1012483 $n_perm [1] 720 $method [1] "exact over all 720 orderings" > > # Pure noise: the best split is still found, and is not significant. > set.seed(2) > step_change(stats::rnorm(12))$p_value [1] 0.6223 > > > > cleanEx() > nameEx("stock_flow") > ### * stock_flow > > flush(stderr()); flush(stdout()) > > ### Name: stock_flow > ### Title: Stock and flow side by side, with the decomposition > ### Aliases: stock_flow > > ### ** Examples > > # Fewer people, held longer: the flow falls while the stock rises. > stock_flow(days = c(115674, 126121), people = c(12647, 9608), + period = c("2023", "2025"), + exposure = c(15495050, 16256538)) ── Stock and flow over 2 periods ───────────────────────────────── period people days alos adp flow_rate stock_rate 2023 12647 115674 9.146359 316.9151 81.61961 2.045267 2025 9608 126121 13.126665 345.5370 59.10237 2.125526 2023 to 2025: people -24.0%, stay +43.5%, days +9.0% flow rate -27.6%, stock rate +3.9% <- opposite signs: quote both ────────────────────────────────────────────────────────────────── > > > > cleanEx() > nameEx("timestamp_verify") > ### * timestamp_verify > > flush(stderr()); flush(stdout()) > > ### Name: timestamp_verify > ### Title: Verify an RFC 3161 timestamp token > ### Aliases: timestamp_verify timestamp_info > > ### ** Examples > > # Tokens come from a timestamping authority, so there is nothing to > # demonstrate offline; this is the shape of the call. > ## Not run: > ##D res <- timestamp_verify("response.tsr", data = "manifest.json") > ##D res$ok > ##D res$time > ## End(Not run) > > > > cleanEx() > nameEx("to_ascii") > ### * to_ascii > > flush(stderr()); flush(stdout()) > > ### Name: to_ascii > ### Title: Transliterate Text to Plain ASCII > ### Aliases: to_ascii > > ### ** Examples > > # Latin accents fold to their nearest ASCII letter. > to_ascii("Prof. \u00c1ngela Zorro Medina") # "Prof. Angela Zorro Medina" [1] "Prof. Angela Zorro Medina" > > # Vectorised over the input. > to_ascii(c("Se\u00e1n", "Zo\u00eb", "na\u00efve")) [1] "Sean" "Zoe" "naive" > > # Non-Latin scripts are romanised when stringi is available. > if (requireNamespace("stringi", quietly = TRUE)) + to_ascii("\u041c\u043e\u0441\u043a\u0432\u0430") # "Moskva" (Cyrillic) [1] "Moskva" > > # Either way the result is guaranteed pure 7-bit ASCII (never "?"). > all(charToRaw(to_ascii("caf\u00e9")) < 128) [1] TRUE > > > > cleanEx() > nameEx("top_correlations") > ### * top_correlations > > flush(stderr()); flush(stdout()) > > ### Name: top_correlations > ### Title: Strongest pairwise correlations in a data frame > ### Aliases: top_correlations > > ### ** Examples > > set.seed(1) > n <- 200 > df <- data.frame( + a = stats::rnorm(n), + b = stats::rnorm(n), + grade = sample(letters[1:3], n, TRUE) + ) > df$c <- df$a * 2 + stats::rnorm(n, sd = 0.1) # strongly related to a > df$d <- exp(df$a) # monotone but curved > > top_correlations(df) ── Top correlations (spearman) ─────────────────────────────────── x y correlation plot a d 1.000 |########## a c 0.998 |########## c d 0.998 |########## a b -0.062 #| b d -0.062 #| b c -0.060 #| ────────────────────────────────────────────────────────────────── > > # The curved pair is ranked correctly by Spearman and understated by > # Pearson, which is why Spearman is the default. > tc <- top_correlations(df, method = "spearman") > tc[tc$x == "a" & tc$y == "d", "correlation"] [1] 1 > tp <- top_correlations(df, method = "pearson") > tp[tp$x == "a" & tp$y == "d", "correlation"] [1] 0.8496382 > > # Filter to the pairs worth looking at. > top_correlations(df, min_abs = 0.5) ── Top correlations (spearman) ─────────────────────────────────── x y correlation plot a d 1.000 |########## a c 0.998 |########## c d 0.998 |########## ────────────────────────────────────────────────────────────────── > > > > cleanEx() > nameEx("trend_test") > ### * trend_test > > flush(stderr()); flush(stdout()) > > ### Name: trend_test > ### Title: Trend in a short series > ### Aliases: trend_test > > ### ** Examples > > # Five years of placements. > y <- c(402, 377, 190, 268, 331) > trend_test(y) $S [1] -4 $tau [1] -0.4 $p_value [1] 0.4833333 $slope [1] -21.375 $intercept [1] 419.75 $slope_lower [1] -187 $slope_upper [1] 78 $n [1] 5 $var_S [1] 16.66667 $alternative [1] "two.sided" $conf_level [1] 0.95 $method [1] "Mann-Kendall, exact over all 120 orderings" > > # A monotone series is detected even at n = 5, where a regression's > # standard error would be nearly uninformative. > trend_test(c(1, 2, 3, 4, 5)) $S [1] 10 $tau [1] 1 $p_value [1] 0.01666667 $slope [1] 1 $intercept [1] 0 $slope_lower [1] 1 $slope_upper [1] 1 $n [1] 5 $var_S [1] 16.66667 $alternative [1] "two.sided" $conf_level [1] 0.95 $method [1] "Mann-Kendall, exact over all 120 orderings" > > # One aberrant period does not create a trend. > trend_test(c(100, 100, 100, 100, 900))$p_value [1] 0.4833333 > > # From a data frame. > d <- data.frame(year = 2019:2023, n = y) > trend_test(d, value = "n", period = "year")$slope [1] -21.375 > > > > cleanEx() > nameEx("validate_rules") > ### * validate_rules > > flush(stderr()); flush(stdout()) > > ### Name: validate_rules > ### Title: Apply declared rules to a data frame > ### Aliases: validate_rules > > ### ** Examples > > df <- data.frame(id = c(1, 2, 2), age = c(30, -5, 40), + start = c(1, 5, 3), end = c(2, 4, 9)) > > rules <- list( + rule("age_non_negative", function(v) v >= 0, column = "age"), + rule("id_unique", function(v) !anyDuplicated(v), column = "id", + severity = "fatal"), + rule("dates_ordered", function(d) all(d$start <= d$end)) + ) > > issues <- validate_rules(df, rules) > names(issues) [1] "age_non_negative" "id_unique" "dates_ordered" > > # A row-wise failure reports how many rows and which. > issues$age_non_negative$n_failed [1] 1 > issues$age_non_negative$rows [1] 2 > > # Clean data produces nothing. > clean <- data.frame(id = 1:3, age = c(30, 31, 40), start = 1:3, end = 4:6) > length(validate_rules(clean, rules)) [1] 0 > > # A rule for an absent column is skipped, not failed -- a missing > # column is validate_schema()'s finding to report, not this one's. > length(validate_rules(data.frame(id = 1:3), rules[1:2])) [1] 0 > > # A rule that errors is a failure, not a silent pass. > broken <- list(rule("bad", function(v) stop("boom"), column = "age")) > validate_rules(clean, broken)$bad$message [1] "Rule 'bad' failed (rule could not be evaluated: boom)" > > > > cleanEx() > nameEx("validate_schema") > ### * validate_schema > > flush(stderr()); flush(stdout()) > > ### Name: validate_schema > ### Title: Validate a Data Frame Against a Provenance Schema > ### Aliases: validate_schema > > ### ** Examples > > prov <- list(schema = list( + expected_columns = c("id", "year"), + structural_invariants = list(min_data_rows = 1), + expected_value_sets = list(year = 2020:2025) + )) > df <- data.frame(id = 1:3, year = c(2020, 2021, 2030)) > issues <- validate_schema(df, prov) > names(issues) # flags the out-of-set year value [1] "unexpected_year" > > # A column that silently changed type is caught. > typed <- list(schema = list(expected_types = c(id = "integer"))) > validate_schema(data.frame(id = c("1", "2")), typed)[[1]]$message [1] "Column 'id' is character, expected integer" > > # So is a value outside its pinned range, and excess missingness. > ranged <- list(schema = list(numeric_ranges = list(v = c(min = 0, max = 1)))) > validate_schema(data.frame(v = c(0.5, 9)), ranged)[[1]]$message [1] "Column 'v' has 1 value(s) outside [0, 1]" > > gappy <- list(schema = list(max_missing_fraction = c(v = 0.1))) > validate_schema(data.frame(v = c(1, NA, NA, 4)), gappy)[[1]]$message [1] "Column 'v' is 50.0% missing, above the expected 10.0%" > > # A clean frame produces nothing. > length(validate_schema(data.frame(id = 1:3, year = 2021), prov)) [1] 0 > > > > cleanEx() > nameEx("verify_capsule") > ### * verify_capsule > > flush(stderr()); flush(stdout()) > > ### Name: verify_capsule > ### Title: Re-Verify an Entire Reproducible Data Capsule > ### Aliases: verify_capsule > > ### ** Examples > > dir <- file.path(tempdir(), "capsule-example") > dir.create(dir, showWarnings = FALSE) > write.csv(data.frame(id = 1:3), file.path(dir, "d.csv"), row.names = FALSE) > prov <- list(resource = list(filename = "d.csv", + sha256 = sha256_file(file.path(dir, "d.csv")))) > writeLines(bricklayer_json_to_json(prov, auto_unbox = TRUE), + file.path(dir, "data_provenance.json")) > verify_capsule(dir)$ok [1] TRUE > > > > cleanEx() > nameEx("verify_sha256") > ### * verify_sha256 > > flush(stderr()); flush(stdout()) > > ### Name: verify_sha256 > ### Title: Verify a File's SHA256 Against an Expected Digest > ### Aliases: verify_sha256 > > ### ** Examples > > f <- tempfile() > writeLines("hello capsule", f) > > # Matching digest -> match TRUE. > chk <- verify_sha256(f, sha256_file(f)) > chk$match # TRUE [1] TRUE > > # A wrong expected digest -> match FALSE, with both values reported. > bad <- verify_sha256(f, strrep("0", 64L)) > bad$match # FALSE [1] FALSE > bad$actual # the real digest [1] "55d6110230c260319d580bb6274db530b7e751c4f687fc00d0736ec531260a02" > > > > cleanEx() > nameEx("wayback_snapshot_url") > ### * wayback_snapshot_url > > flush(stderr()); flush(stdout()) > > ### Name: wayback_snapshot_url > ### Title: Resolve a Wayback Machine snapshot URL > ### Aliases: wayback_snapshot_url > > ### ** Examples > > > > > cleanEx() > nameEx("wayback_snapshot_url_native") > ### * wayback_snapshot_url_native > > flush(stderr()); flush(stdout()) > > ### Name: wayback_snapshot_url_native > ### Title: Resolve a Wayback Machine snapshot URL (C++/libcurl) > ### Aliases: wayback_snapshot_url_native > > ### ** Examples > > # Input is validated before any network call: > try(wayback_snapshot_url_native("")) # empty url -> error Error in wayback_snapshot_url_native("") : nzchar(url) is not TRUE > > > > > cleanEx() > nameEx("write_manifest_json") > ### * write_manifest_json > > flush(stderr()); flush(stdout()) > > ### Name: write_manifest_json > ### Title: Write a Manifest to JSON > ### Aliases: write_manifest_json > > ### ** Examples > > man <- make_manifest(list(project = "demo"), environment = FALSE) > man <- record(man, "row_count", observed = 20, expected = 20) row_count observed = 20.0000 expected = 20.0000 [PASS] > path <- write_manifest_json(man, tempfile(fileext = ".json")) > file.exists(path) [1] TRUE > > # Round-trips back through the package's own codec. > back <- bricklayer_json_from_json(path, simplifyVector = FALSE) > back$results$row_count$status # "PASS" [1] "PASS" > > > > cleanEx() > nameEx("write_summary_txt") > ### * write_summary_txt > > flush(stderr()); flush(stdout()) > > ### Name: write_summary_txt > ### Title: Write a Plain-Language Run Summary > ### Aliases: write_summary_txt > > ### ** Examples > > man <- make_manifest(list(project = "demo", author = "A. Author"), + environment = FALSE) > man <- record(man, "row_count", observed = 20, expected = 20) row_count observed = 20.0000 expected = 20.0000 [PASS] > out <- file.path(tempdir(), "demo-run") > dir.create(out, showWarnings = FALSE) > s <- write_summary_txt(man, out, paths = list(results = out)) > readLines(s)[7:8] [1] "Project: demo" "Author: A. Author" > > > > cleanEx() > nameEx("write_text_fallback") > ### * write_text_fallback > > flush(stderr()); flush(stdout()) > > ### Name: write_text_fallback > ### Title: Write Text as UTF-8, Falling Back to ASCII on an Encoding Error > ### Aliases: write_text_fallback > > ### ** Examples > > p <- write_text_fallback(c("line one", "line two"), + tempfile(fileext = ".txt")) > readLines(p) [1] "line one" "line two" > > > > cleanEx() > nameEx("yoy") > ### * yoy > > flush(stderr()); flush(stdout()) > > ### Name: yoy > ### Title: Year-over-year (and period-over-period) change > ### Aliases: yoy yoy.data.frame yoy.numeric yoy.integer yoy.ts > ### print.rmbl_yoy > > ### ** Examples > > seg <- data.frame( + EndFiscalYear = rep(2019:2023, each = 2), + Gender = rep(c("Female", "Male"), 5), + Number_Of_Placements = c(31, 402, 28, 377, 12, 190, 19, 268, 24, 331) + ) > > y <- yoy(seg, value = "Number_Of_Placements", period = "EndFiscalYear", + by = "Gender", direction = "lower_is_better") > y Gender EndFiscalYear Number_Of_Placements previous change change % interval ────── ───────────── ──────────────────── ──────── ────── ──────── ──────────── Female 2019 31 — — — — ↳ percent withheld: no comparison period Female 2020 28 31 -3 ▼ -9.7% [-48%, +56%] Female 2021 12 28 -16 ▼ -57.1% [-80%, -13%] Female 2022 19 12 7 — — ↳ percent withheld: base below 20 Female 2023 24 19 5 — — ↳ percent withheld: base below 20 Male 2019 402 — — — — ↳ percent withheld: no comparison period Male 2020 377 402 -25 ▼ -6.2% [-19%, +8%] Male 2021 190 377 -187 ▼ -49.6% [-58%, -40%] Male 2022 268 190 78 ▲ +41.1% [+17%, +71%] Male 2023 331 268 63 ▲ +23.5% [+5%, +46%] lag 1 period · units: count · 95% exact rate-ratio interval · percent withheld below a base of 20 · lower is better > > # The interval is exact, so a small group does not get a confident > # percent it has not earned. > subset(as.data.frame(y), Gender == "Female") Gender EndFiscalYear value previous change pct_change flag 1 Female 2019 31 NA NA NA no comparison period 2 Female 2020 28 31 -3 -9.677419 3 Female 2021 12 28 -16 -57.142857 4 Female 2022 19 12 7 NA base below 20 5 Female 2023 24 19 5 NA base below 20 pct_lower pct_upper verdict 1 NA NA 2 -47.79679 55.62836 better 3 -80.14950 -12.97354 better 4 NA NA worse 5 NA NA worse > > # A percentage is handled as percentage points, not as a percent of a > # percent. > rate <- data.frame(year = 2019:2023, share = c(4.1, 4.6, 5.2, 5.0, 5.4)) > yoy(rate, value = "share", period = "year", units = "percent") year share previous change points ──── ───── ──────── ────── ──────── 2019 4.1 — — — ↳ percent withheld: no comparison period 2020 4.6 4.1 0.5 ▲ +0.5pp 2021 5.2 4.6 0.6 ▲ +0.6pp 2022 5.0 5.2 -0.2 ▼ -0.2pp 2023 5.4 5.0 0.4 ▲ +0.4pp lag 1 period · units: percent · percentage-point change, not percent of a percent > > > > cleanEx() > nameEx("yoy_delim") > ### * yoy_delim > > flush(stderr()); flush(stdout()) > > ### Name: yoy_delim > ### Title: Write a change table as delimited text, JSON or Markdown > ### Aliases: yoy_delim yoy_csv yoy_tsv yoy_json yoy_markdown > > ### ** Examples > > d <- data.frame(year = 2019:2023, n = c(402, 377, 190, 268, 331)) > y <- yoy(d, value = "n", period = "year") > > # Straight to text, for inspection. > cat(yoy_csv(y, NULL)) # value: n; period: year; lag: 1; units: count; interval: 95% exact rate ratio; percent withheld below a base of 20 year,value,previous,change,pct_change,flag,pct_lower,pct_upper,verdict 2019,402,,,,no comparison period,,, 2020,377,402,-25,-6.21890547263682,,-18.7301481792582,8.20024314312362,down 2021,190,377,-187,-49.6021220159151,,-57.8921768223217,-39.8426144902702,down 2022,268,190,78,41.0526315789474,,16.6890230584617,70.7750209773721,up 2023,331,268,63,23.5074626865672,,4.81624015357676,45.6380333585367,up > > # Markdown, for a report. > cat(yoy_markdown(y, NULL)) | year | n | previous | change | change % | interval | note | | ---- | --- | -------- | -----: | -------: | -----------: | -------------------- | | 2019 | 402 | — | — | — | | no comparison period | | 2020 | 377 | 402 | -25 | -6.2% | [-19%, +8%] | | | 2021 | 190 | 377 | -187 | -49.6% | [-58%, -40%] | | | 2022 | 268 | 190 | 78 | +41.1% | [+17%, +71%] | | | 2023 | 331 | 268 | 63 | +23.5% | [+5%, +46%] | | _value: n; period: year; lag: 1; units: count; interval: 95% exact rate ratio; percent withheld below a base of 20_ > > # JSON keeps the settings as fields rather than as comments. > substr(yoy_json(y, NULL), 1, 80) [1] "{\n \"settings\": {\n \"value\": \"n\",\n \"period\": \"year\",\n \"lag\": 1,\n \"uni" > > > > cleanEx() > nameEx("yoy_label") > ### * yoy_label > > flush(stderr()); flush(stdout()) > > ### Name: yoy_label > ### Title: Label a period without changing it > ### Aliases: yoy_label > > ### ** Examples > > seg <- data.frame(EndFiscalYear = 2019:2023, + n = c(402, 377, 190, 268, 331)) > y <- yoy(seg, value = n, period = EndFiscalYear) > > # 2023 means the fiscal year 2022/23, so say so. > yoy_label(y, fiscal_year_label) EndFiscalYear n previous change change % interval ───────────── ─── ──────── ────── ──────── ──────────── 2018/19 402 — — — — ↳ percent withheld: no comparison period 2019/20 377 402 -25 ▼ -6.2% [-19%, +8%] 2020/21 190 377 -187 ▼ -49.6% [-58%, -40%] 2021/22 268 190 78 ▲ +41.1% [+17%, +71%] 2022/23 331 268 63 ▲ +23.5% [+5%, +46%] lag 1 period · units: count · 95% exact rate-ratio interval · percent withheld below a base of 20 > > # Any function will do. > yoy_label(y, function(p) paste0("FY", substr(p, 3, 4))) EndFiscalYear n previous change change % interval ───────────── ─── ──────── ────── ──────── ──────────── FY19 402 — — — — ↳ percent withheld: no comparison period FY20 377 402 -25 ▼ -6.2% [-19%, +8%] FY21 190 377 -187 ▼ -49.6% [-58%, -40%] FY22 268 190 78 ▲ +41.1% [+17%, +71%] FY23 331 268 63 ▲ +23.5% [+5%, +46%] lag 1 period · units: count · 95% exact rate-ratio interval · percent withheld below a base of 20 > > # Or an explicit mapping, for the periods that need one. > yoy_label(y, c("2020" = "2019/20 (COVID)")) EndFiscalYear n previous change change % interval ─────────────── ─── ──────── ────── ──────── ──────────── 2019 402 — — — — ↳ percent withheld: no comparison period 2019/20 (COVID) 377 402 -25 ▼ -6.2% [-19%, +8%] 2021 190 377 -187 ▼ -49.6% [-58%, -40%] 2022 268 190 78 ▲ +41.1% [+17%, +71%] 2023 331 268 63 ▲ +23.5% [+5%, +46%] lag 1 period · units: count · 95% exact rate-ratio interval · percent withheld below a base of 20 > > > > cleanEx() > nameEx("yoy_palettes") > ### * yoy_palettes > > flush(stderr()); flush(stdout()) > > ### Name: yoy_palettes > ### Title: Colour palettes for change tables > ### Aliases: yoy_palettes > > ### ** Examples > > yoy_palettes() [1] "diverging" "safe" "mono" > > > > cleanEx() > nameEx("yoy_render") > ### * yoy_render > > flush(stderr()); flush(stdout()) > > ### Name: yoy_render > ### Title: Render a change table to HTML or PDF > ### Aliases: yoy_render yoy_html yoy_pdf > > ### ** Examples > > d <- data.frame(year = rep(2019:2023, each = 2), + region = rep(c("North", "South"), 5), + n = c(31, 402, 28, 377, 12, 190, 19, 268, 24, 331)) > y <- yoy(d, value = "n", period = "year", by = "region", + direction = "lower_is_better") > > h <- file.path(tempdir(), "change.html") > yoy_html(y, h, title = "Placements by region") > file.exists(h) [1] TRUE > > p <- file.path(tempdir(), "change.pdf") > yoy_pdf(y, p, title = "Placements by region") > file.exists(p) [1] TRUE > > unlink(c(h, p)) > > > > cleanEx() > nameEx("yoy_summary") > ### * yoy_summary > > flush(stderr()); flush(stdout()) > > ### Name: yoy_summary > ### Title: Summarise a change table > ### Aliases: yoy_summary yoy_summary.rmbl_yoy > > ### ** Examples > > d <- data.frame(year = 2018:2023, n = c(120, 131, 98, 140, 155, 149)) > yoy_summary(yoy(d, value = "n", period = "year")) from to first last total_pct cagr_pct periods up down flat 1 2018 2023 120 149 24.16667 4.424163 6 3 2 0 > > > > cleanEx() > nameEx("yoy_write") > ### * yoy_write > > flush(stderr()); flush(stdout()) > > ### Name: yoy_write > ### Title: Write a change table to a file, in whatever format the name > ### implies > ### Aliases: yoy_write > > ### ** Examples > > d <- data.frame(year = 2019:2023, n = c(402, 377, 190, 268, 331)) > y <- yoy(d, value = "n", period = "year") > > for (ext in c("csv", "tsv", "json", "md", "html")) { + f <- file.path(tempdir(), paste0("change.", ext)) + yoy_write(y, f) + cat(ext, file.size(f), "bytes\n") + unlink(f) + } csv 519 bytes tsv 519 bytes json 1553 bytes md 712 bytes html 4872 bytes > > > > ### *