The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
Ironseed is an R package that improves seeding for R’s built in random number generators. An ironseed is a finite-entropy (or fixed-entropy) hash digest that can be used to generate an unlimited sequence of seeds for initializing the state of a random number generator. It is inspired by the work of M.E. O’Neill and others [1, 2, 3].
An ironseed is a 256-bit hash digest constructed from a variable-length sequence of 32-bit inputs. Each ironseed consists of eight 32-bit sub-digests. The sub-digests are values of 32-bit multilinear hashes [4] that accumulate entropy from the input sequence. Each input is included in every sub-digest. The coefficients for the multilinear hashes are generated by a Weyl sequence.
Multilinear hashes are also used to generate an output seed sequence from an ironseed. Each 32-bit output value is generated by uniquely hashing the sub-digests. The coefficients for the output are generated by a second Weyl sequence.
To improve the observed randomness of each hash output, bits are mixed using a finalizer adapted from SplitMix64 [5]. With the additional mixing from the finalizer, the output seed sequence passes PractRand tests [6].
# Install the released version of the package from CRAN as usual:
install.packages("ironseed")
# Or the development version from GitHub:
# install.packages("pak")
pak::pak("reedacartwright/ironseed")Ironseed can be used at the top of a script to robustly initialize R’s builtin random number generator. The resulting ironseed is returned invisibly, and a message is generated notifying the user that initialization has occurred. This message can be logged and later used to reproduce the run.
#!/usr/bin/env -S Rscript --vanilla
ironseed::ironseed("Experiment", 20251031, 1)
#> ** Ironseed v0.3.0: SetSeed L1S8a59jKMV-MXX2GrS1hrQ-nYwzqL14Rb2-yiBwupsfZUf
runif(10)
#> [1] 0.20771860 0.05685812 0.46064640 0.03253283 0.21827857 0.23708437
#> [7] 0.09678753 0.93051076 0.68834723 0.70048683If your script is intended to be called multiple times as part of a large study, you can also seed based on the command line arguments.
#!/usr/bin/env -S Rscript --vanilla
args <- commandArgs(trailingOnly = TRUE)
ironseed::ironseed("A Simulation Script 1", args)
#> ** Ironseed v0.3.0: SetSeed aGTMGJZrmQb-MmRAwvmajQ1-pEAyRkyfSWR-XvjHyVajxJW
runif(10)
#> [1] 0.1990489 0.7884689 0.2698110 0.4761755 0.4127876 0.2025955 0.6249008
#> [8] 0.9778754 0.8534247 0.3009149Specific command line arguments can also be used. For large, nested studies, it is useful for scripts to support seeding using multiple seeds. Ironseed makes this easy to accomplish.
#!/usr/bin/env -S Rscript --vanilla
args <- commandArgs(trailingOnly = TRUE)
ironseed::ironseed("A Simulation Script 2", args[grepl("--seed=", args)])
#> ** Ironseed v0.3.0: SetSeed KnabwooccdH-Fr7UKEkKauC-MGJNQ4AjqDN-SnKkDqUT8Ch
runif(10)
#> [1] 0.03714270 0.58069848 0.86104299 0.01920254 0.71453447 0.95131078
#> [7] 0.42456432 0.68626742 0.58047906 0.87471196Ironseed can also automatically initialize the random number
generator using an ironseed constructed from multiple sources of
entropy. This occurs if no data is passed to
ironseed().
#!/usr/bin/env -S Rscript --vanilla
ironseed::ironseed()
#> ** Ironseed v0.3.0: SetSeed MMP7kaVgit3-fdj8mH2Yuvb-XP4HvV9Z11e-tMES5isR5we
runif(10)
#> [1] 0.1709656 0.9549136 0.9939423 0.7165402 0.9792717 0.5409108 0.4919766
#> [8] 0.9735896 0.2513371 0.2296586
# Access the ironseed that was used for RNG seeding.
fe <- ironseed::get_ironseed()
fe
#> Ironseed: MMP7kaVgit3-fdj8mH2Yuvb-XP4HvV9Z11e-tMES5isR5weOr achieving the same thing with one call. Note that the automatically generated seed is different from the previous run.
#!/usr/bin/env -S Rscript --vanilla
fe <- ironseed::ironseed()
#> ** Ironseed v0.3.0: SetSeed XHtfF9L8fZ5-363rX2NV41B-Gu2D9ba1eNX-aqmBpurYLje
runif(10)
#> [1] 0.48126361 0.86350382 0.62432849 0.58320541 0.02967282 0.21307074
#> [7] 0.03946363 0.57550078 0.85126966 0.99778787
fe
#> Ironseed: XHtfF9L8fZ5-363rX2NV41B-Gu2D9ba1eNX-aqmBpurYLjeAn ironseed can also be used directly to reproduce a previous initialization. This is most useful when automatic seeding has been used, and the previously generated seed has been logged.
#!/usr/bin/env -S Rscript --vanilla
ironseed::ironseed("RW7vjwjeiHF-QG7RYPvrntR-6tGPoi65sVc-N1n5SQi5RH4")
#> ** Ironseed v0.3.0: SetSeed RW7vjwjeiHF-QG7RYPvrntR-6tGPoi65sVc-N1n5SQi5RH4
runif(10)
#> [1] 0.89365116 0.02137079 0.95990727 0.17105063 0.59927593 0.98808313
#> [7] 0.97298012 0.62492468 0.28697049 0.14086705A good hash function has good avalanche properties. If we change one bit of information in the input, our goal is to change 50% of the bits in the output. To test this we, will first build a function to construct a random pair of ironseeds that differ by a single input bit.
rand_fe_pair <- function(w) {
x <- sample(0:1, w, replace=TRUE)
n <- sample(seq_along(x), 1)
y <- x
y[n] <- if(y[n] == 1) 0L else 1L
x <- packBits(x, "integer")
y <- packBits(y, "integer")
x <- ironseed::ironseed(x, set_seed = FALSE)
y <- ironseed::ironseed(y, set_seed = FALSE)
list(x = x, y = y)
}Next we will generate 100,000 pairs using 32-bit inputs. We will use R’s built-in seeding algorithm so that the results are independent of Ironseed’s seeding algorithm. We will also measure how many hash bits were flipped by flipping one input bit.
set.seed(20251220)
z <- replicate(100000, rand_fe_pair(32), simplify = FALSE)
dat <- sapply(z, \(a) sum(intToBits(a$x) != intToBits(a$y)))mean(dat) # expectation: 128
#> [1] 127.9878
sd(dat) # expectation: 8
#> [1] 8.025923
hist(dat, breaks = 86:170, main = NULL)
We will repeat the same analysis for 256-bit inputs.
set.seed(20251221)
z <- replicate(100000, rand_fe_pair(256), simplify = FALSE)
dat <- sapply(z, \(a) sum(intToBits(a$x) != intToBits(a$y)))
mean(dat) # expectation: 128
#> [1] 127.955
sd(dat) # expectation: 8
#> [1] 7.980782
hist(dat, breaks = 86:170, main = NULL)
As one can see, the avalanche behavior of the input hash is excellent.
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.