import numpy as np

## 1) matrices circulantes

def matriceCirculante(L):
    """
    L est une liste ou un vecteur.
    Renvoie la matrice circulante dont la premiere ligne est donnee par L
    en utilisant le produit matriciel.
    """
    n = len(L)
    J = np.eye(n, n, k=1)
    J[n - 1, 0] = 1
    Jk = np.eye(n, n)
    C = 0
    for k in range(n):
        C = C + L[k]*Jk
        Jk = Jk.dot(J)
    return C


def matriceCirculante_v2(L):
    """
    L est une liste.
    Renvoie la matrice circulante dont la premiere ligne est donnee par L
    sans utiliser le produit matriciel.
    """
    n = len(L)
    R = L.copy()
    C = np.zeros((n, n))
    for k in range(n):
        C[k, :] = R
        R = [R[-1]] + R[0:-1]
    return C

L = [-1, 1, 2, 4]
print(f"matrice circulante a partir de {L}, \n{matriceCirculante_v2(L)}\n")


## 2) matrice de Vandermond

def matriceVandermond(L):
    """
    L est une liste ou un vecteur.
    Renvoie la matrice Vandermond dont la deuxieme ligne est donnee par L.
    """
    n = len(L)
    if type(L)=='list':
        R = np.array(L)
    else:
        R = np.array(list(L))
    V = np.ones((n, n))
    for k in range(1, n):
        V[k, :] = V[k - 1, :] * R
    return V


def determinantVandermond(L):
    """
    L est une liste ou un vecteur.
    Renvoie une valeur conjecturee du determinant de la matrice Vandermond
    dont la deuxieme ligne est donnee par L.
    """
    D = 1
    for i in range(len(L)):
        for j in range(i + 1, len(L)):
            D = D * (L[i] - L[j])
    return D

L = [-1, 1, 2, 4]
V = matriceVandermond([-1, 1, 2, 4])
print('V =', V, '\n')
print('det de V =', np.linalg.det(V))
print('det de V conjecture =', determinantVandermond(L))
