##1

import numpy.random as rd
import numpy as np
import scipy.optimize as resol
import scipy.integrate as integr
import matplotlib.pyplot as plt
#1

def x(n,p):
    return rd.geometric(p, n)

def X(n,p):
    S=0
    for i in range(n):
        S+=x(n,p)[i]
    return S

def Y(n,p):
    return max(x(n,p))

#2

def EX(n,p):
    S=0
    for i in range(1000):
        S+=X(n,p)
    return S/1000

def EY(n,p):
    S=0
    for i in range(1000):
        S+=Y(n,p)
    return S/1000

##2


import numpy.linalg as alg

# premiere methode
def A2(n):
    Z=np.zeros((n,n))
    for i in range(n-1):
        Z[i+1,i]= 1
    Z[0][n-1]=1
    return Z
#   plus complique
def A1(n):
    A1 =np.eye(n)
    C1 = np.zeros((n,1))
    L1 = np.concatenate((np.zeros((1,n)),np.ones((1,1))), axis=1)
    A2 = np.concatenate((A1,C1),axis=1)
    return np.concatenate((L1,A2),axis=0)

def B(n):
    I = np.eye(n)
    Z = np.zeros((n,n))
    A = A2(n)
    L1 = np.concatenate((A,I), axis = 1)
    L2 = np.concatenate((Z,A), axis = 1)
    return np.concatenate((L1,L2), axis = 0)


for i in range(2,6):
    print(alg.matrix_power(B(3),i))

##3

#1

A = np.array([[1,2,3],[1,-1,1],[1,2,1]])
B = np.array([[1],[2],[5]])
I = np.eye(3)

print(alg.solve(A, B))

#2

def polcarac(A):
    return(np.poly(A))

#3

print (alg.eig(A))

##4

L=[[a,b,c,d] for a in [-1,1] for b in [-1,1] for c in [-1,1] for d in [-1,1]]
LA=[np.array([e,f,g,h]) for e in L for f in L for g in L for h in L]
res=[]
for A in LA:
    if np.array_equal(np.dot(A,np.transpose(A)),4*np.eye(4)):
        res.append(A)
print (len(res))

##5

from numpy.polynomial import Polynomial

def T(n):
    T0 = Polynomial([1])
    T1 =  Polynomial([0,1])
    t= [T0, T1]
    for i in range(2,n+1):
        T = 2*Polynomial([0,1])*t[i-1]-t[i-2]
        t.append(T)
    return t
# en affichant t[i].coeff, on remarque que deg(Ti)=i, c(Ti)=2**i
# Ti pair si i pair et Ti impair si i impair
def racines (n):
    t=[]
    for i in range (n):
        t.append(T(i).roots())
    return t
# Tn admet n racines reelles

def matrice(n):
    t = T(n)
    M = np.zeros((n,n))
    for i in range(n):
        for j in range(i+1):
            M[i][j] = t[i].coef[j]
    return np.transpose(M)