import numpy as np
import seaborn as sns
import scipy.stats as stats
%matplotlib inline

"""
Explanation: Clase 6:  Generación de números aleatorios y simulación Montecarlo
Juan Diego Sánchez Torres, 
Profesor, MAF ITESO

Departamento de Matemáticas y Física
dsanchez@iteso.mx
Tel. 3669-34-34 Ext. 3069
Oficina: Cubículo 4, Edificio J, 2do piso

1. Motivación
Presentar los métodos básicos para la generación de números aleatorios uniformes y normales.
End of explanation
"""


def lcg(n, m=2**31-1, a=16807, c=0, seed=2**30):
    x = np.zeros(n+1)
    x[0]=seed
    for i in range(1,n+1):
        x[i] = (a * x[i-1]+c)%m
    return x[1:]/m

"""
Explanation: 2. Generador congruencial lineal
End of explanation
"""


lcg(10, m=31, a=13, c=0, seed=3)

"""
Explanation: Ejemplo
End of explanation
"""


x=lcg(10000)
sns.distplot(x, color="b", fit=stats.uniform);

"""
Explanation: Generador mínimo estándar
End of explanation
"""


x=lcg(10000, m=2**31, a=2**16+3, c=0, seed=3)
sns.distplot(x, color="b", fit=stats.uniform);

"""
Explanation: Generado Randu (Usado por IBM)
End of explanation
"""


def bm(n):
    m=2**31-1
    a=16807
    c=0
    seed=2**30
    x = np.zeros(n+1)
    x[0]=seed
    for i in range(1,n+1):
        x[i] = (a * x[i-1]+c)%m
    u=x[1:]/m
    u1=u[:int((n/2))]
    u2=u[int(n/2):]
    nn=np.concatenate((np.sqrt(-2*np.log(1-u1))*np.cos(2*np.pi*u2), np.sqrt(-2*np.log(1-u1))*np.sin(2*np.pi*u2)),axis=0)
    return nn

y=bm(100000)
sns.distplot(y, color="b", fit=stats.norm);

"""
Explanation: 3. Método de Box-Muller
End of explanation
"""


