ilusm.dev

det

Deterministic PRNG and sort utilities - seeded LCG integer mixing, bounded random integers, pick one element from a list, Fisher-Yates shuffle, FNV-1a string hashing, hash-keyed sort, deterministic sampling, and stable deduplication. All outputs are reproducible from the same seed.

Load with: use det

What this module does

det provides deterministic pseudo-randomness and ordering primitives. Unlike cry.cryrn or system randomness, every function in det produces the same output for the same seed - making it ideal for reproducible tests, procedural generation, stable test-data shuffling, and consistent sampling.

The core is a 32-bit LCG (linear congruential generator): x * 1664525 + 1013904223, the same constants as Numerical Recipes. String hashing uses FNV-1a (32-bit) for stable ordering keys. The det.mix alias is used by other stdlib modules (e.g. c2 for jitter) to produce deterministic offsets.

Quick example

use det

# Deterministic integer mix
prn(detmi(42))        # always the same value

# Seeded integer from seed + salt
prn(detin(1234, 7))

# Pick one element from a list
items = ["a", "b", "c", "d"]
prn(detpi(items, 99))  # reproducible choice

# Shuffle a list (Fisher-Yates, seeded)
shuffled = detsh(items, 42)

# Bounded random integer in [0, 10)
prn(detbe(42, 0, 10))

# Hash a string to a stable integer
prn(detha("hello"))   # always the same FNV-1a hash

# Sort a list in deterministic hash order
prn(detso(["banana", "apple", "cherry"]))

# Sample k elements in deterministic order
prn(detsa(items, 42, 2))

# Deduplicate (stable, hash-keyed)
prn(detun(["a", "b", "a", "c"]))

Functions

PRNG core

detmi(n)

LCG mix: applies x = x * 1664525 + 1013904223 to the integer n and returns the absolute value. This is the basic mixing step. Also exposed as det.mix.

detin(seed, salt)

Generates a deterministic integer from a seed and salt by mixing seed + salt * 374761393. Use different salt values to get independent streams from the same seed.

Selection and shuffling

detpi(list, seed)

Picks one element from a list deterministically using detin(seed, 0) % len(list). Errors if the list is empty.

detsh(list, seed)

Returns a shuffled copy of the list using the Fisher-Yates algorithm, deriving each swap index from detin(seed, j). The original list is not modified.

detbe(seed, salt, hi)

Returns a deterministic integer in [0, hi). Errors if hi ≤ 0.

detra(n)

Returns the list [0, 1, 2, …, n-1]. Useful as input to other det functions.

Hashing and sorting

detha(s)

FNV-1a 32-bit hash of string s. Produces a stable non-negative integer. Used internally for hash-keyed sorting and deduplication. Not cryptographically secure.

detso(list)

Sorts a copy of the list by the FNV-1a hash of each element's string representation. The output order is deterministic and independent of input order. Uses an internal bubble sort on keyed records.

Sampling and deduplication

detsa(list, seed, k)

Returns the first k elements of a seeded shuffle of the list. Effectively a deterministic sample without replacement. Returns all elements if k ≥ len(list).

detun(list)

Returns a deduplicated copy of the list. Equality is determined by the FNV-1a hash of each element's string form - so any two elements that produce the same string are considered duplicates. Preserves first-seen order.

Notes

  • All operations are deterministic - same seed and input always produce the same output.
  • Not suitable for cryptographic use. For secure randomness use cry.cryrn.
  • The det.mix alias is the only exported namespace value; all other functions are top-level.
  • Requires trl, txt, and eru.