#################################
########### AGRO 2022 ###########
#################################

## Importations

from math import exp

# # # # # # # # # # # # # # # #
# # # # # QUESTION 1a # # # # #
# # # # # # # # # # # # # # # #

def extraction_ch() :
    f = open("data.txt","r")
    L = []
    ligne1 = f.readline()
    ligne2 = f.readline()
    f.close()
    L.append(ligne1)
    L.append(ligne2)
    return L

# # # # # # # # # # # # # # # #
# # # # # QUESTION 1b # # # # #
# # # # # # # # # # # # # # # #

def ch_vers_liste(ch) :
    L = []
    n = len(ch)
    sh = ""
    for k in range(n) :
        if ch[k] != " " :
            sh = sh+ch[k]
        else :
            L.append(float(sh))
            sh = ""
    L.append(float(sh))
    return L

# # # # # # # # # # # # # # # #
# # # # # QUESTION 1c # # # # #
# # # # # # # # # # # # # # # #

def division(L1,L2) :
    n1 = len(L1)
    n2 = len(L2)
    if n1 != n2 :
        return False
    div = []
    for k in range(n1) :
        div.append(L1[k]/L2[k])
    return div

# # # # # # # # # # # # # # # #
# # # # # QUESTION 1d # # # # #
# # # # # # # # # # # # # # # #

L = extraction_ch()
L1 = ch_vers_liste(L[0])
L2 = ch_vers_liste(L[1])
Lnorm = division(L1,L2)

# # # # # # # # # # # # # # # #
# # # # # QUESTION 2ai# # # # #
# # # # # # # # # # # # # # # #

# Minimiser Mtilde par rapport à alpha et bêta revient
# à appliquer la méthode des moindres carrés pour
# obtenir un ajustement affine (y = alpha x + bêta)
# du nuage de points de coordonnées (lt,t).
# Ce choix n'est pas retenu car la forme du nuage
# de points ne suggère pas une dépendance linéaire
# entre lt et t.

# # # # # # # # # # # # # # # #
# # # # # QUESTION 2aii # # # #
# # # # # # # # # # # # # # # #

# En minimisant M par rapport à lambda, mu, gamma,
# on applique la méthode des moindres carrés à
# un ajustement exponentiel : y = lambda.exp(-mu.t)+gamma
# On cherche en effet à minimiser la somme des carrés
# des écarts d'ordonnées entre les points du nuage,
# et les points de même abscisse de la courbe représentative
# de t |---> lambda.exp(-mu.t)+gamma

# On exclut un ajustement polynomial car on observe
# que lt tend vers une constante quand t tend vers + l'infini,
# alors qu'un polynôme non constant tend vers + ou - l'infini
# en + l'infini.

# # # # # # # # # # # # # # # #
# # # # # QUESTION 2b # # # # #
# # # # # # # # # # # # # # # #

# Dans le modèle : lt = lambda.exp(-mu.t) + gamma,
# on a : lim(t->+inf) lt = gamma, car mu > 0
# Or, on observe que lt s'approche d'environ 0,015
# quand t augmente, donc on peut supposer :
# gamma0 = 0,015
# De plus, l0 = lambda+gamma au temps t = 0
# et on lit : l0 = 0,29
# donc lambda0+gamma0 = 0,29 avec gamma0 = 0,015
# donc lambda0 = 0,275

gamma0 = 0.015
lambda0 = 0.275

# # # # # # # # # # # # # # # #
# # # # # QUESTION 2c # # # # #
# # # # # # # # # # # # # # # #

def M_mu(mu) :
    lamb = lambda0
    gam = gamma0
    s = 0
    for k in range(len(Lnorm)) :
        s += (Lnorm[k]-lamb*exp(-mu*k)-gam)**2
    return s

# La fonction M_mu calcule la somme M(lambda,mu,gamma)
# pour lambda = lambda0, gamma = gamma0
# et pour une valeur de mu passée en argument.

# # # # # # # # # # # # # # # #
# # # # # QUESTION 2d # # # # #
# # # # # # # # # # # # # # # #

# La figure 2 permet d'estimer que la valeur de mu cherchée
# est proche de 0,75 : c'est la valeur de mu pour laquelle
# la somme M_mu(mu) est minimale.
# Néanmoins, il aurait été plus utile de représenter
# cette fonction M_mu entre, par exemple, 0.5 et 1
# pour avoir une meilleure précision.

mu0 = 0.75

# # # # # # # # # # # # # # # #
# # # # # QUESTION 3a # # # # #
# # # # # # # # # # # # # # # #

def argmin2(f,x,y) :
    if f(x) <= f(y) :
        return x
    else :
        return y

def argmin3(f,x,y,z) :
    if f(x) <= f(y) and f(x) <= f(z) :
        return x
    elif f(y) <= f(x) and f(y) <= f(z) :
        return y
    else :
        return z

# # # # # # # # # # # # # # # #
# # # # # QUESTION 3b # # # # #
# # # # # # # # # # # # # # # #

def minimum(f,A,B,eps) :
    g = A
    d = B
    while d-g > eps :
        xg = g + (d-g)/3
        xd = d - (d-g)/3
        if f(xg) < f(xd) :
            d = xd
        elif f(xg) > f(xd) :
            g = xg
        else :
            g = xg
            d = xd
    return argmin2(f,g,d)

# # # # # # # # # # # # # # # #
# # # # # QUESTION 4a # # # # #
# # # # # # # # # # # # # # # #

def test_croissant(L) :
    for k in range(len(L)-1) :
        if L[k] > L[k+1] :
            return False
    return True

# # # # # # # # # # # # # # # #
# # # # # QUESTION 4b # # # # #
# # # # # # # # # # # # # # # #

# Pour tester si M_mu est croissante entre 0,8 et 3,
# on crée une liste de valeurs de M_mu(mu) pour mu
# variant entre 0,8 et 3 avec un pas assez petit.
# On peut utiliser par exemple : X = np.linspace(0.8,3,10000)
# puis : Y = M_mu(X) ou Y = [M_mu(x) for x in X]
# On applique enfin la fonction "est_croissant"
# à cette liste Y.

# rq : il est plus rapide d'écrire le code que de l'expliquer...

# # # # # # # # # # # # # # # #
# # # # # QUESTION 4c # # # # #
# # # # # # # # # # # # # # # #

mu0 = minimum(M_mu,0,0.8,10**-3)

# # # # # # # # # # # # # # # #
# # # # # QUESTION 4d # # # # #
# # # # # # # # # # # # # # # #

# Le modèle donne donc lt = 0.275*exp(-0.7061 t) + 0.015
# ce qui est loin d'être une constante : selon ce modèle,
# le taux de mortalité est élevé pendant la petite enfance
# (mortalité infantile) et décroît tout au long de la vie.
# On peut s'interroger sur la pertinence du modèle aux âges
# avancés...


















