Promedios de las distancias

Johann Carl Friedrich Gauss
Johann Carl Friedrich Gauss

En las entradas anteriores generamos un archivo con los primeros números primos que se encuentran entre 1 y mil millones y construimos un pequeño programa en Python que genera las distancias entre ellos y las grafica por rangos. Observamos algo que hace unos añitos (220 mas o menos) Carl Friedrich Gauss había observado sin contar con nuestras sofisticadas herramientas.

En esta entrada vamos a intentar cuantificar qué tanto cambian las distancias entre los números primos a medida que tomamos rangos mas alejados de cero. Esto es, las distancias en los primeros 1000 primos, frente a las distancias en los siguientes mil y los siguientes. Vamos a hacer uso de un concepto estadístico muy sencillo que es el promedio. Esto no es nada diferente que una suma dividida por el número de elementos que sumamos. Miraremos el promedio de las distancias entre números primos, en cada uno de los rangos, tratando de encontrar un patrón en ello.

Para la estadística usaremos un módoulo de Python llamado Pandas. Respecto al uso de la libreria Pandas sugiero leer la excelente página de José Ricardo Zapata. Es una librería muy poderosa, tanto para calcular estadísticas como para gráficarlas. Pero nosotros sólo usaremos algunas mínimas funciones.

Intentemos calcular el promedio de las distancias entre números primos para los primeros 1000, los segundos mil, etc.

Comenzamos importando la libreria y asignándola al identificador pd:

import pandas as pd

Pandas reconoce dos tipos de entradas de datos: Series y DataFrame. La primera es un listado de valores como el que venimos usando. El segundo tipo es una tabla con varias columnas. Para calcular el promedio de nuestra lista de distancias basta con la instrucción:

print( pd.Series(sucesion).mean() )

pd. indica que estamos llamando a la libreria Pandas. Series. por que usaremos como datos de entrada una serie, esta es sucesion que creamos en la entrada anterior y finalmente usamos el metodo mean().

Para calcular el promedio de as distancias de los primeros mil números primos, usando algunas de las funciones creadas en la entrada anterior, hariamos:

#---------------------------------------------------------------
#--------------------PROGRAMA PRINCIPAL-------------------------
# Parametros
consecutivo_inicial = 1   # Desde cuál consecutivo comienza
cantidad = 1000    # Cuantos primos 

primos = lee_primos(cantidad, inicio=consecutivo_inicial)
sucesion = sucesion_distancias(primos)
promedio = pd.Series(sucesion).mean()
print( 'Promedio de distancias entre '+str(consecutivo_inicial)+' y '+str(consecutivo_inicial+cantidad)+': ',promedio )

y obtendremos como resultado:

Un número: 7.9. El promedio de la distancia entre los primeros mil primos. Pero lo realmente interesante sería tener varios promedios de distancias Hagamos un ciclo for para calcular tantos promedios como queramos:

#---------------------------------------------------------------
#--------------------PROGRAMA PRINCIPAL-------------------------
# Parametros
consecutivo_inicial = 1   # Desde cuál consecutivo comienza
cantidad = 1000    # Cuantos primos 
intervalo = 1000    # Espacio entre el comienzo de cada rango
numero_iteraciones = 10

final = consecutivo_inicial +(intervalo * numero_iteraciones)
for desde in range(consecutivo_inicial, final, intervalo):
    primos = lee_primos(cantidad, inicio=desde)
    sucesion = sucesion_distancias(primos)
    promedio = pd.Series(sucesion).mean()
    print( 'Promedio de distancias entre '+str(desde)+' y '+str(desde+intervalo)+': ',promedio )

En este ejemplo calcularemos los promedios de las distancias para los números primos entre 1 y 1001, entre 1001 y 2001, entre 2001 y 3001 y así hasta completar 10 promedios:

Parecería que la distancia entre primos tiene una tendencia a ir creciendo a medida que los examinamos en números mas grandes. Aprovechemos la función de graficar y dibujemos los promedios de las distancias. Para ello tan sólo almacenamos las distancias en una lista y luego llamamos a nuestra función grafica. El programa principal quedaría así:

#--------------------PROGRAMA PRINCIPAL-------------------------
# Parametros
consecutivo_inicial = 1   # Desde cuál consecutivo comienza
cantidad = 1000    # Cuantos primos promediará
intervalo = 1000    # Espacio entre el comienzo de cada rango
numero_iteraciones = 10
promedios = []      # Lista que almacenará los promedio

final = consecutivo_inicial +(intervalo * numero_iteraciones)
for desde in range(consecutivo_inicial, final, intervalo):
    primos = lee_primos(cantidad, inicio=desde)
    sucesion = sucesion_distancias(primos)
    promedio = pd.Series(sucesion).mean()
    print( 'Promedio de distancias entre '+str(desde)+' y '+str(desde+intervalo)+': ',promedio )
    promedios.append(promedio)
grafica(promedios)
plt.show()

Y el resultado sería como este:

Si, efectivamente la gráfica muestra que crece, pero parecería que se va aplanando en la parte alta. De nuevo no seamos tímidos e intentémoslo con muchos valores. ¿Que tal intervalos de a millón? ese es un buen promedio. Y dado que contamos con 50 millones de primos en nuestro archivo, hagamos la gráfica de 5 puntos con promedios cada diez millones de intervalos de un millón de primos. Los parámetros serían:

# Parametros
consecutivo_inicial = 1   # Desde cuál consecutivo comienza
cantidad = 1000000    # Cuantos primos graficará
intervalo = 10000000    # Espacio entre el comienzo de cada rango
numero_iteraciones = 5

Y el resultado nos da:

Efectivamente, crece y se aplana en la parte alta, parecería ser asintótica o sea que crece infinitamente pero acercándose siemre a un valor. Por supuesto esto no demuestra nada, sólo nos permite suponer. Si fuera asintótica, ¿a que valor tiende a hacercarse? ¿será a un valor primo?.

El programa completo queda de la siguiente manera:

import matplotlib.pyplot as plt
import math, time
import pandas as pd
import numpy as np

#------------ Funciones -----------------------------------
# Grafica
def grafica(sucesion,  desde=1):
    fig = plt.figure()
    ax = fig.add_subplot(211)
    ex = plt.subplot(1,1,1)
    plt.scatter(range(desde, len(sucesion)+desde), sucesion)
    plt.plot(range(desde, len(sucesion)+desde), sucesion, linewidth ='0.2')
    ex.set_title('Promedios de distancia entre primos') 
    
# Lee del archivo
def lee_primos(cantidad, inicio = 1):
    f_in = 'primos_hasta_1000000000.txt'
    f = open(f_in, 'r')
    contador = 0 # Numeros almacenados en la lista
    indice = 0 # Registros leídos del archivo
    primos = []
    
    for numero in f:
        if indice >= inicio:
            primos.append(int(numero))
            if contador == cantidad:
                break
            contador += 1
        indice += 1
    return primos

# Genera lista de distancias
def sucesion_distancias(lista_primos):
    sucesion = []
    anterior = lista_primos[0]
    for primo in lista_primos[1:len(primos)]:
        distancia = primo - anterior
        sucesion.append(distancia)
        anterior = primo
    return sucesion
#---------------------------------------------------------------
#--------------------PROGRAMA PRINCIPAL-------------------------
# Parametros
consecutivo_inicial = 1000000   # Desde cuál consecutivo comienza
cantidad = 2000    # Cuantos primos promediará
intervalo = 1000000    # Espacio entre el comienzo de cada rango
numero_iteraciones = 50
promedios = []      # Lista que almacenará los promedio

final = consecutivo_inicial +(intervalo * numero_iteraciones)
for desde in range(consecutivo_inicial, final, intervalo):
    primos = lee_primos(cantidad, inicio=desde)
    sucesion = sucesion_distancias(primos)
    promedio = pd.Series(sucesion).mean()
    print( 'Promedio de distancias entre '+str(desde)+' y '+str(desde+intervalo)+': ',promedio )
    promedios.append(promedio)
grafica(promedios)
plt.show()

Para terminar la entrada seamos más atrevidos y hagamos 50 puntos. Que tal los promedios de las distancias de millón de primos cada millón, desde 1 hasta 50 millones. Es una hermosa gráfica que se ve así:

Recordemos que el eje x representa el número del intervalo (o sea el primer intervalo, el segundo intervalo, el tercer intervalo y así sucesivamente) y el eje y es el promedio de las distancias en dicho intervalo. Para la gráfica anterior cada intervalo contenia un millón de números primos. Una más antes de cerrar, hasta 100 millones:

Cuál será la asíntota?


Buscando patrones Proximamente… Frecuecias de las distancias

Categorías: Python

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *