¿El azar emerge de la estructura de los primos?
Un experimento con Niell sobre el tamiz de Eratóstenes
Doce fases sucesivas sobre un sencillo tamiz, escritas en Niell, el lenguaje que fuimos ajustando en paralelo.
1. El punto de partida
Hay preguntas que uno descarta como ingenuas y después vuelven, más tercas, en el momento menos esperado. Una de ellas fue la que motivó este proyecto. La formulo con torpeza a propósito: ¿el azar tiene que venir de afuera, o hay una forma de azar que emerge sola de la estructura de los números?
La intuición inicial venía de una observación bastante obvia sobre los números primos. Los primos son "los ladrillos" de la aritmética: cualquier número entero se puede descomponer de forma única como producto de ellos. Pero a la vez, los primos están distribuidos de una manera que a simple vista parece caótica. Están todos condicionados por una regla estricta — no ser divisibles por ningún primo anterior — pero la distancia entre uno y el siguiente, la posición donde aparecen, no obedece a ningún patrón periódico que sepamos identificar. Esa combinación de regla estricta y aparente desorden se sentía como el material justo para preguntar si el azar puede nacer de la estructura.
Para ir de la intuición a una pregunta operacional hay que construir algo concreto que se pueda medir. Lo que construimos es un tamiz, un procedimiento clásico que se usa para encontrar primos: eliges un rango de números, borras los múltiplos de cada primo pequeño en cascada, y lo que queda son primos. La variante que usamos se llama tamiz por rueda (o wheel sieve). En lugar de mirar todos los enteros de 1 a N, primero se elige una rueda — un número base que es producto de los primeros primos, como 2·3·5 = 30, o 2·3·5·7 = 210, o 2·3·5·7·11 = 2310. A esos números se les llama primoriales. Una vez fijada la rueda B, solo se miran los números cuyo resto al dividir por B es coprimo con B — es decir, aquellos restos que no comparten factores comunes con B. Ese subconjunto de números se llama la matriz coprima de B, y es el terreno donde el tamiz efectivamente busca primos.
De ese tamiz sale, entre otras cosas, un objeto muy simple: un bytestream, o secuencia de bits. Recorriendo la matriz coprima en orden, marcamos con un 1 los primos que encontramos y con un 0 los huecos entre ellos. Si empaquetamos esos bits en bytes, obtenemos una secuencia binaria que podemos tratar como salida candidata de un generador de números pseudoaleatorios (PRNG, por pseudo-random number generator). La pregunta se vuelve entonces cuantitativa: ¿es esa secuencia estadísticamente indistinguible del azar? Si lo fuera, tendríamos un pequeño ejemplo concreto del fenómeno intuido — azar emergido de la pura estructura de los primos, sin ninguna fuente externa de entropía.
A lo largo de doce fases sucesivas corrimos el experimento, medimos, refutamos hipótesis intermedias y refinamos la respuesta. La respuesta final es más matizada que "sí" o "no", pero tiene forma y tiene evidencia — y eso, más que cualquier otra cosa, es lo que el proyecto tenía como objetivo producir.
2. Cómo Niell creció con este proyecto
Antes de contar qué encontramos, hay que contar una cosa complementaria: el proyecto se escribió en Niell, el lenguaje de programación experimental que también desarrollamos en paralelo. Cada versión del tamiz ejercitó capacidades del lenguaje y expuso qué le faltaba. Esa es la función complementaria que el proyecto cumple mientras investiga el azar emergente: ser el forcing function que empuja al lenguaje a madurar, un caso de uso real que se rehúsa a esperar y exige soluciones estructurales.
Tres ejemplos concretos que nacieron durante el trabajo con el tamiz y volvieron al compilador como cambios permanentes:
Gap del bucle `while`. Al escalar el tamiz hicieron falta iteraciones donde no se conoce por adelantado cuántas veces habrá que dar vuelta — un tamiz avanza mientras queden candidatos por eliminar. Ese patrón lo captura de forma natural la instrucción while, tan básica en la mayoría de los lenguajes como respirar. En Niell, la primera versión solo tenía recursión y bucles con conteo fijo. Escribir un tamiz sin while era posible pero incómodo, forzando a envolver cada iteración en una función recursiva. La decisión fue agregar while como construcción de primer orden. Lección: incluso las construcciones más básicas necesitan un caso de uso concreto que justifique su diseño exacto.
Un desbordamiento de pila descubierto al escalar. Al llegar a rangos de un millón (N=10⁶) con múltiples ruedas simultáneas, el programa se caía con un error de segmentación (segfault). El diagnóstico llevó tiempo: el compilador estaba emitiendo una instrucción de reserva de memoria (alloca) dentro del cuerpo de cada iteración del bucle, sin declarar dónde terminaba su vida útil. La memoria se acumulaba iteración tras iteración hasta desbordar la pila. El arreglo fue mover esa reserva al bloque de entrada de la función — así se reutiliza el mismo espacio en todas las iteraciones. Un bug latente en el compilador que estuvo mucho tiempo sin manifestarse, hasta que un proyecto lo suficientemente exigente lo expuso.
El operador XOR bit a bit. En la última fase técnica del arco quisimos aplicar una operación estándar de mezcla al bytestream: un XOR ladder, que combina cada byte con el anterior aplicando la operación lógica XOR (o exclusivo) bit a bit. Es una técnica clásica para "lavar" estructura residual. Niell no tenía operador XOR bitwise; lo agregamos como palabra clave xor con la precedencia de la multiplicación, coherente con el resto de la aritmética explícita del lenguaje (ver la sección de tipos del lenguaje para la semántica formal de operadores como idiv y xor).
Además de estos tres, el arco cerró otros dos gaps que menciono al pasar: un error del recolector de basura al escalar y una construcción de filtro sobre listas con reutilización de memoria in-place (retain). El patrón se repite: cada versión del proyecto es un test de estrés del lenguaje. El compilador salió más robusto. El proyecto salió más honesto. Los dos lados ganaron.
3. El recorrido
El arco pasó por doce fases distinguibles. Contarlas rápido ayuda a entender por qué el resultado final combina un hallazgo positivo firme con un caveat honesto sobre las limitaciones que descubrimos al mirar de cerca.
Fases 1-3: el tamiz simple. Empezamos con la implementación mínima del tamiz de Eratóstenes clásico, sin rueda, sobre rangos chicos. Ya con esa versión emergió una observación importante: los "huecos" entre primos consecutivos, mirados como un bytestream, tenían más entropía por bit que los propios gaps entre primos. Esa diferencia no era artefacto del formato de codificación — la verificamos con dos empaquetados independientes que llegaron al mismo resultado.
Fase 4: el tamiz por rueda. Generalizamos el tamiz para aceptar una rueda arbitraria. Como primer experimento probamos cuatro ruedas que combinan bases numéricas comunes (B=10 decimal, B=16 hexadecimal) con primoriales chicos (B=6, B=30), justamente para ver si las bases del sistema numérico tenían algo especial. No lo tenían — la calidad del bytestream dependía fuertemente de la rueda elegida, pero de forma no monótona: aumentar la rueda ayudaba hasta cierto punto y después empeoraba. Una primera pista sobre lo que después llamaríamos el sweet spot.
Fases 6-8: la conjetura del sweet spot. Agregamos ruedas más grandes (B=210, B=2310) y una segunda métrica basada en la entropía de Shannon. El patrón se aclaró: la calidad del bytestream depende de la densidad de primos en la matriz coprima, y la calidad máxima aparece cuando esa densidad se acerca al 50%. Antes del 50%, los bits están sesgados hacia el 0 (matriz muy grande con pocos primos). Después del 50%, sesgados hacia el 1 (matriz muy chica donde casi todo lo que hay es primo). Y el 50% es el óptimo teórico de entropía por bit — la moneda justa. La conjetura era: el sweet spot se desplaza a ruedas más grandes cuando N crece, porque la densidad de primos decrece con N y hace falta una rueda mayor para compensar.
Fase 9: el barrido cross-N. Para validar la conjetura corrimos un barrido sistemático sobre cinco tamaños distintos de N (desde 5 000 hasta 100 000) por cada rueda. Por cada rueda, medimos en qué N alcanza su mejor calidad. El resultado confirmó la predicción: best_N crece monotónicamente con el tamaño de la rueda, y la densidad en ese best_N converge al 50%. El mínimo absoluto medido fue B=2310 @ N=60 000, con densidad 50.5% y una calidad indistinguible de una moneda justa a la resolución de nuestras muestras. Es el punto más cerca del ideal que el tamiz produjo con los parámetros explorados.

Fases 10-12: la prueba estadística y el cierre. Agregamos una prueba χ² (chi-cuadrado) — un contraste estadístico estándar que mide si una distribución observada se aparta significativamente de una distribución uniforme. Los resultados matizaron el hallazgo: para muestras grandes (N ≥ 60 000), todas las ruedas se apartan detectablemente de lo uniforme, incluso el sweet spot. La fuente del tamiz es estructuralmente no-uniforme; a suficientemente grande resolución, se detecta que no es azar puro. Para muestras moderadas (N ≤ 30 000) con la rueda correcta, en cambio, la prueba no puede rechazar la hipótesis de uniformidad. La interpretación operacional es: el tamiz produce una fuente "casi uniforme" cuya desviación detectable depende del tamaño de la muestra. Para aplicaciones que toleran un pequeño sesgo estructural, los sweet spots son un PRNG utilizable con evidencia estadística.
Con el hallazgo cross-N validado en tres puntos independientes (10⁴ → B=210, 10⁵ → B=2310, 10⁶ → B=30030), la progresión quedó cerrada empíricamente. Cada salto de N agrega un primo al primorial óptimo. La regla "la rueda óptima es el siguiente primorial cuando la densidad cruza el 50%" se validó con tres puntos distintos, no con uno solo.

4. Lo que encontramos y el caveat honesto
El hallazgo central se resume en dos afirmaciones concretas.
Primero: encontramos una regla precisa. La calidad estadística del bytestream depende de una sola propiedad — la densidad de primos en la matriz coprima — y es óptima cuando esa densidad se acerca al 50%. Para cada N existe una rueda óptima, que resulta ser siempre un primorial. En el sweet spot, y aún más con una mezcla trivial posterior, el bytestream es indistinguible del azar bajo pruebas estadísticas de resolución moderada. La regla es cuantitativa y reproducible, no una intuición.
Segundo: el hallazgo tiene un límite honesto. Pruebas estadísticas más finas siguen detectando estructura incluso en el mejor punto medido. No conseguimos "azar puro" desde los primos — conseguimos una fuente muy cercana al azar, con una firma de origen que la mezcla trivial no borra.
La evidencia concreta viene en dos partes.
El sweet spot (Fase 9): la medición cross-N mostró que la calidad óptima aparece exactamente donde la teoría anticipa — densidad ≈ 50% en la matriz coprima. Tres puntos independientes lo confirmaron: 10⁴ / B=210, 10⁵ / B=2310, 10⁶ / B=30030. La progresión natural de primoriales (2, 6, 30, 210, 2310, 30030, ...) corresponde a una progresión de óptimos para N crecientes.
El XOR ladder (v1.5.0): la mezcla trivial post-procesamiento reduce ~20 veces la desviación respecto a lo uniforme sobre todas las ruedas. En B=30030 @ N=10⁶, la prueba χ² sobre 16 buckets pasa de p ≈ 0.0000 (fuerte sesgo detectado) a p ≈ 0.9925 (extremadamente uniforme). Bajo esa prueba, el bytestream posterior al XOR es indistinguible del azar puro.

Dos análisis complementarios extendieron el retrato. El sesgo de Chebyshev generalizado — el fenómeno conocido de que los primos no se distribuyen uniformemente entre las clases de residuo módulo una rueda pequeña — se promedia y desaparece cuando la rueda tiene muchas clases coprimas (480 para B=2310, 5760 para B=30030). La distribución de gaps dentro de la matriz coprima se comporta como uno espera de la teoría continua filtrada por la rueda, sin sorpresas contraintuitivas.

Los detalles del caveat. La prueba χ² sobre 16 buckets es un test grueso — solo mira la frecuencia marginal de cada valor por byte. Las suites estándar de calidad de PRNG cubren más dimensiones. Pasamos el bytestream por NIST STS (Statistical Test Suite, National Institute of Standards and Technology), una batería de 12 tests que cubren periodicidades espectrales, correlaciones de tripletas de bits, patrones de bloque, y otras propiedades ortogonales. A la escala más grande medida (B=30030 @ N=10⁶), 5 de los 12 tests siguen fallando aún después del XOR ladder. El χ² macro no ve la estructura fina que esos cinco tests detectan.
La interpretación operacional: el bytestream sieve+XOR es utilizable como PRNG si la aplicación tolera cinco formas específicas de estructura residual (frecuencia dentro de bloques, DFT, templates no-solapadas, correlación serial, entropía aproximada). Aplicaciones ok: visualización de ruido pseudoaleatorio, Monte Carlo grueso, identificadores no criptográficos. Aplicaciones no: criptografía, simulaciones sensibles a periodicidades, semillas de seguridad. Cerrar la brecha a "confianza NIST plena" requeriría una segunda etapa de mezcla — fuera de este arco.
Comunicar "descubrimos un PRNG completo desde los primos" habría sido una sobreventa fácil. La versión honesta — un patrón robusto de sweet spot y una fuente casi-uniforme con caveat cuantificado — es la que corresponde publicar.
5. Lo que queda
El arco cierra, pero varias líneas quedan vivas.
Forcing function para Niell. El rol continúa post-arco. Nuevas exploraciones sobre el tamiz — escalar a rangos aún mayores, aplicar segundas etapas de mezcla, extender a otras fuentes estructurales de entropía — probablemente refinarán capacidades del lenguaje. El proyecto es un banco de pruebas persistente.
Aplicaciones concretas del PRNG. Tenemos un bytestream con calidad casi-uniforme disponible. Direcciones candidatas: una demo de ruido en canvas que compare contra Math.random(); una integración como fuente de aleatoriedad en un motor de juego pequeño. Cada una con su costo estimado documentado en el roadmap.
Segunda etapa de mezcla para cerrar NIST. Los cinco tests que siguen fallando después del XOR ladder son un objetivo cuantificable. Una mezcla más agresiva — encadenamiento con un generador congruencial, hash criptográfico por bloques — probablemente cerraría la brecha, aunque a esa altura el proyecto se aleja del espíritu original de "azar emergido puramente de la estructura".
Indagación matemática extendida. Refinamientos a la aproximación de Cipolla para el n-ésimo primo considerando la corrección de la rueda; extensión de las mediciones de Chebyshev a ruedas todavía más grandes; observación sistemática de clases "ricas" y "pobres" en el tamiz. Todas con baja urgencia.
"Herramientas matemáticas nuevas." La intuición al cerrar el arco fue que valdría inventar notación o estructuras matemáticas nuevas que capturen algo sobre los primos que las herramientas existentes no pueden. Sin observación previa que la motive concretamente, forzar la invención sería decoración — pero queda anotada como posibilidad futura si aparece un patrón cuya descripción "queda fea" con las herramientas actuales.
Cierre
El código completo del proyecto está en github.com/niell-lang/emergent-order — libre de leer, clonar o replicar los resultados desde cero. Si te interesa probar Niell (o corregir alguno de los bugs que este proyecto todavía no descubrió), la instalación del compilador está documentada en niell.dev/install.
---
Apéndice — referencias técnicas
Documentos técnicos del arco, ordenados por profundidad decreciente:
- síntesis técnica del arco (`docs/active_context.md`) — síntesis técnica completa (Fases 1-12 + Phase 13.C XOR + M1/M2/M3), con tablas de resultados por fase y detalle del hallazgo del sweet spot.
- reporte NIST STS (`docs/v1.5-nist-report.md`) — detalle mecánico de las cuatro corridas NIST STS (dos escalas × pre/post XOR), con p-values por test y análisis de qué tests fallan en qué condiciones.
- roadmap post-v1.5.0 (`docs/roadmap.md`) — direcciones pendientes del arco, con costo estimado y "posible decepción" documentada para cada una.
El apéndice es opcional; el lector casual puede saltarlo.