# -*- coding: utf-8 -*-
"""
Created on Tue Oct  1 09:03:24 2019

@author: Agnes Valladeau
"""


import random as rd


#%% exercice n°1


def infsup(L):
    x = rd.choice(L)
    Linf = []
    Lsup = []
    Leg = []
    for val in L:
        if w < val : # éléments de L inférieurs à x
            Linf.append(val)
        elif val == x:
            Leg.append(val)
        else:
            Lsup.append(val)
    return [x, Linf + Lid + Lsup]

# différence à expliquer
def infsup1(L):
    x = rd.choice(L)
    Linf = []
    Lsup = []
    Leg = []
    for k in range(len(L)):
        if L[k] < x : # éléments de L inférieurs à x
            Linf.append(L[k])
        elif L[k] == x:
            Leg.append(L[k])
        else:
            Lsup.append(L[k])
    return [x, Linf + Leg + Lsup]

#ou avec des listes en compréhension

def infsupbis(L):
    x = choice(L)
    Linf = [w for w in L if w < x]
    Lid = [w for w in L if w == x]
    Lsup = [w for w in L if w > x]
    return [x, Linf + Lid + Lsup]



#%% exercice n°2

def sansrep(L,k):
    " renvoie une k-liste sans répétition d'éléments de L"
    tirages = []
    for i in range(k):
        indice = rd.randint(0, len(L)-1) # choix d'un indice au hasard
        element = L.pop(indice)
        tirages.append(element)
    return tirages

def sansrep1(L,k):
    tirages = []
    for _ in range(k):
        x = rd.choice(L)
        L.remove(x)
        tirages.append(x)
    return tirages

# Attention L est modifiée. Si on veut récupérer la liste intiale, on doit faire une copie profonde de L

def sansrep2(L,k):
    T = L.copy()
    tirages = []
    for _ in range(k):
        x = rd.choice(T)
        T.remove(x)
        tirages.append(x)
    return tirages


#%% exerice n°3

def simul(n):
    "renvoie True si boule blanche et False sinon"
    urne =  rd.randint(1,n)
    return urne, rd.random()< urne**2/n**2

def simul1(n):
    "renvoie True si boule blanche et False sinon"
    urne =  rd.randint(1,n)
    if rd.random()< urne**2/n**2:
        return urne, 'B'
    else:
        return urne, 'N'


#%% Estimation de P(A) : fréquence de réalisation de A sur un grand nombre de répatétion d'une expérience aléatoire

def face(nbsim):
    cpt = 0
    for k in range(nbsim):
        if rd.random() < 1/2:
            cpt += 1
    return cpt, cpt / nbsim

# tester avec nbsim =100, 1000, 10000,1000000
#Quand nbsim augmente,  cpt / nbsim , la fréquence d'obtention de Face se rapproche de 1/2


#%% exercice n°4

def de():
    return rd.randint(1,6)

def Agagne():
    "renvoie 1 si A gagne et 0 sinon"
    n = 1
    while de() != 6:
        n += 1
    if n%2 == 1:
        return 1
    return 0

def estimA(nbsim):
    succes = 0
    for _ in range(nbsim):
        if Agagne() == 1:
            succes += 1
    return succes / nbsim

def estimB(nbsim):
    succes = 0
    for _ in range(nbsim):
        if Agagne() == 0 : # B gagne
            succes += 1
    return succes / nbsim

#%% exercice n°5 (exo 7 TD 3 dénombrement)

def permut(n):
    "création d'une permutation de {1,..,n}"
    L=[i for i in range(1,n+1)]
    P=[]
    for k in range(n):
        indice=randint(0,len(L)-1)
        element = L.pop(indice)
        P.append(element)
    return P

# on peut aussi créer une permutation avec choice et remove

def permut1(n):
    "création d'une permutation de {1,..,n}"
    L=[i for i in range(1,n+1)]
    P=[]
    for k in range(n):
        x=rd.choice(L)
        L.remove(x)
        P.append(x)
    return P



def derangement(L):
    "renvoie vrai si L est un dérangement de {1,..,n} et faux sinon"
    for i in range(len(L)):
        if L[i] == i+1:
            return False
    return True

n=50

def estimDerangement(nbsim):
    nbdrgt = 0
    for i in range(nbsim):
        if derangement(permut(n)):
            nbdrgt += 1
    return nbdrgt / nbsim


# Comparaison avec la proba théorique de l'exercice 7 TD3 dénombrement

def probatheo():
    "proba théorique"
    som = 1
    fact = 1
    for i in range(1,n+1):
        fact *= i
        som = som + ((-1)**i) / fact
    return som

def fact(n):
    p = 1
    for i in range(1,n+1):
        p *= i
    return p

#%% exercice n°6:

def position(n,p):
    " renvoie une simulation de la variable Xn"
    pos = 0
    for k in range(n):
        if rd.random() < p:
            pos += 1
        else:
            pos -= 1
    return pos

def estimesp(nbsim,n,p):
    "moyenne des nbim simulations de la variable Xn, estimation de E(Xn)"
    som = 0
    for k in range(nbsim):
        som += position(n,p)
    return som / nbsim

## exercice n °7
import matplotlib.pyplot as plt


#Z(Omega)={2,3,4}

def simulZ():
    nbb,nbn = 2,3
    nbtirage = 0
    while nbb != 0 and nbn != 0 :
        if random() < nbb/(nbb+nbn):#tirage blanche
            nbb -=1
        else:
            nbn -= 1
        nbtirage += 1
    return nbtirage

def estimproba(nbsim):
    cpt = 0
    for _ in range(nbsim):
        if simulZ() == 2:
            cpt +=1
    return cpt /nbsim

def estimloi(nbsim):
    loi = [0]*3
    for k in range(nbsim):
        i = simulZ()
        loi[i-2] +=1
    return [loi[i]/nbsim for i in range(3)]

def histobar(nbsim):
    "avec bar"
    T = [2,3,4]
    Y = estimloi(nbsim)
    plt.bar(T,Y)
    plt.show()

def estimesp(nbsim):
    som = 0
    for _ in range(nbsim):
        som += simulZ()
    return som /nbsim

#%% exercice n°8

# question 1

def SimulPas(p):
    E = 0 # nombre d'étapes
    S = 0 # nombre de succes
    while S < 3:
        if random() < p: #succes, la bactérie est touchée
            S += 1
            #print('succes')
        #else: #echec
            #print('echec')
        E +=1
    return E

# question 2

def LST(p,nbsim):
  ''' nbsim simulations de loi de Pascal '''
    return [SimulX(p) for i in range(nbsim)]

# question 3

def histPascal(p,nbsim):
    S =  LST(p,nbsim)
    X = [k+0.5 for k in range(min(S), max(S))]
    plt.hist(S, bins = X, density = True,rwidth = 0.5)
    plt.show()

# question 4

def moyenne(p,n):
    moy = 0
    for x in range(n):
        moy += SimulX(p)
    return moy / n

# Conjecture, la variable aléatoire X admet une espérance égale 3*(1/p).

#%% exercice n°9

def simulX(Lunivers, Lloi):
    a = rd.random()
    print(a)
    i,fdr = 0,Lloi[0]
    while fdr <= a:
         i+=1
         fdr += Lloi[i]
    return Lunivers[i]

#%% exercice n°10

from math import exp

def fact(n):
    p = 1
    for k in range(1,n+1):
        p*= k
    return p

def poisson(lamb):
    a = rd.random()
    #print('a',a)
    #print(exp(-lamb))
    i,fdr,loi = 0,exp(-lamb), exp(-lamb)
    while fdr <= a:
        i+=1
        loi *= lamb/i #pour éviter les erreurs avec i!
        fdr += loi
        #print('i',i)
        #print('fdr',fdr)
    return i

def poisson1(lamb):
    a = rd.random()
    #print('a',a)
    #print(exp(-lamb))
    i,fdr = 0,exp(-lamb)
    while fdr <= a:
        i+=1
        fdr += exp(-lamb)*lamb**i/fact(i)
        #print('i',i)
        #print('fdr',fdr)
    return i






