Files
egutierrez d76c831247 feat(cpp/datascience): CPU stats + MCMC primitives
Nuevo dominio cpp/functions/datascience con primitivas puras CPU para post-
proceso de samples Monte Carlo y diagnostico de cadenas MCMC. Diseñadas como
gemelas CPU de los kernels GPU (rng pareja con gpu_rng_glsl, MH 1D/ND con
mc_metropolis_hastings_gpu) para validar numericamente y para datasets
pequeños donde el dispatch GPU no compensa.

- rng: xoshiro256++ con uniform / normal (Box-Muller) / below (Lemire) /
  categorical. Determinista bit-exacto dado seed.
- stats_summary: sum (Kahan), mean, var/std (Welford one-pass), min, max,
  quantile / percentile (R type-7).
- autocorr: r(k), ACF, tau_int (Sokal) — diagnostico ACF y ESS.
- rhat_ess: Gelman-Rubin clasico y split + ESS basico (multi-chain).
- beta_dist: lgamma (Lanczos), beta_pdf, beta_cdf (continued fraction),
  beta_quantile, mean/var/std — para inferencia Beta-Binomial.
- drawdown: max_dd absoluto/pct + underwater series para sesiones
  simuladas y backtests.
- samples_to_grid_2d: binning 2D CPU para alimentar heatmap_cpp_viz /
  contour_cpp_viz desde samples (x[], y[]).
- metropolis_hastings: MH 1D y ND con target log-pdf como std::function
  (no normalizada).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 11:52:26 +02:00

64 lines
2.8 KiB
Markdown

---
name: rng
kind: function
lang: cpp
domain: datascience
version: "1.0.0"
purity: pure
signature: "void rng_seed(Rng&, uint64 seed); uint64 rng_u64(Rng&); double rng_uniform(Rng&); double rng_normal(Rng&); uint64 rng_below(Rng&, uint64 n); int rng_categorical(Rng&, const double* weights, int n)"
description: "Generador pseudoaleatorio xoshiro256++ con state inout (struct Rng). Helpers: uniform, normal (Box-Muller), below (Lemire sin sesgo), categorical (O(n) cumulative). Determinista dado seed — pareja CPU del gpu_rng_glsl."
tags: [rng, xoshiro, uniform, normal, categorical, montecarlo, datascience]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: [cstdint, cmath]
tested: false
tests: []
test_file_path: ""
file_path: "cpp/functions/datascience/rng.cpp"
params:
- name: seed
desc: "Semilla maestra. 0 se sustituye por la constante de Knuth para evitar arranque degenerado."
- name: r
desc: "Estado RNG (struct con 4 uint64). Se muta in-place en cada llamada."
- name: n
desc: "(rng_below) limite superior exclusivo. (rng_categorical) numero de pesos."
- name: weights
desc: "(rng_categorical) array de pesos NO necesariamente normalizados. Pesos negativos o cero se ignoran."
output: "Numeros pseudoaleatorios deterministas dado el state inicial. rng_seed inicializa los 4 lanes via SplitMix64. Mismo patron que glsl_rng_preamble (gpu) para reutilizar GLSL kernels en CPU."
---
# rng
Pareja CPU del `glsl_rng_preamble` (de `gpu_rng_glsl`). Misma semantica, mismas garantias.
## Calidad
xoshiro256++ (Vigna 2018): periodo 2^256 - 1, 1.2 ns/u64 en x86, supera PractRand 32 TB. Reemplaza al `std::mt19937_64` (mas lento y mayor estado, sin ventaja para Monte Carlo).
`rng_normal` usa Box-Muller polar (~30 ns por sample). Para volumen extremo (>10^9 normals CPU) considerar Ziggurat — no incluido aqui por complejidad.
`rng_below` usa el metodo de Lemire (2019): rejection sampling sin division en el caso comun, sesgo cero. Mejor que `rng_u64() % n` que tiene sesgo modular.
## Uso
```cpp
fn::ds::Rng r;
fn::ds::rng_seed(r, 0xC0FFEE);
double x = fn::ds::rng_normal(r); // ~ N(0, 1)
double u = fn::ds::rng_uniform(r); // [0, 1)
int k = fn::ds::rng_below(r, 100); // 0..99 sin sesgo
double weights[] = {0.5, 0.3, 0.2};
int idx = fn::ds::rng_categorical(r, weights, 3);
```
## Notas
- Determinista bit-exacto dado el seed. Util para tests numericos y para comparar contra el GLSL kernel (que usa PCG32 — distinto stream pero misma semantica de uniform/normal).
- No thread-safe en una unica Rng. Para Monte Carlo paralelo: una Rng por thread, sembrada con seeds derivados de un master via `rng_seed` con seeds distintos.
- Pure: la mutacion del state es referencialmente transparente (la misma secuencia de llamadas produce los mismos resultados). Sin I/O, sin globals.