"""

THEME 9 -Module numpy

"""

## Importations
import numpy as np
import numpy.linalg as la


## I opérations de base

ligne1 = [1,2,3,4]
ligne2 = [5,6,7,8]
liste = [ligne1,ligne2]
A = np.array(liste)  # Martice : opérateur np.array qui s'applique à une
                     #           liste de lignes
## Q1
print(A.shape)

# Si A est dans Mnp(K), A.shape renvoie le tuple (n,p).
# Ici = Tuple de longueur : A est un tableau numpy 2-dimensionnel

##Q2

X = np.arange(0,10,1)
print(X)
print(X.shape) # tuple de longueur 1 : cela ne représente  pas une matrice

#L'OBJET PYTHON QUI REPRESENTE UNE MATRICE EST UN TABLEAU
# NUMPY 2-DIMENSIONNEL.

##Q3

L =X.reshape(1,10)  # ceci représente une matrice ligne (shape : 1,10)
print(L,L.shape)

 # ceci représente une matrice colonne (shape : 10,1)

# La commande reshape permet de redimensionner un tableau numpy en un
# tableau de format souhaité (pourvu qu'il y ait le bon nombre de coefficients)

## Q4

L1 = [1,0,-1,1,-1,1,0,-1,1,1,1,0,0,1,-1,0] # liste des coeffs de B
L2 = np.array(L1)
B=L2.reshape(4,4)   # évite la définition de la liste des 4 listes
# (= des 4 lignes de B).
print(B)

##Q5

# A est la tableau
#array([[1, 2, 3, 4],
#       [5, 6, 7, 8]])

# A[1,3] vaut 8
# A[0,0] vaut 1
# A[2,1] renvoie une erreur : coefficient non défini !

# CONTRAIREMENT AU CAS DES MATHS, LES INDICES DES COEFFICIENTS
# DES MATRICES COMMENCENT A ZERO !

# maths | python
#-------+-------
# a1,1  | A[0,0]



##Q6

L = np.array([1,0,0,0,1]).reshape(1,5)
C = np.array([-1,-2,-3]).reshape(3,1)

##Q7

def alterne(n):
    return np.array([1,0]*n).reshape(1,2*n)

##Q8

def c(i,j):
    return i**j

n,p= 3,3
C = np.array([[c(i,j) for j in range(p)] for i in range(n)])

# Analyse syntaxique de l'expression ligne 87 :
#1. C = np.array(liste)
#2.              liste = [ truc(i) for i in range(n)]
#3.                        truc(i) =[ c(i,j) for j in range(p)]

# De 1. On voit qu'on est en train de définir la liste des lignes
#       du tableau numpy C.
# De 2. On voit que cette liste est une liste en compréhension
#       et que cette liste contient n items
# De 3. On voit que chaque item truc(i) est lui-même une liste,
#       ce qui est syntaxiquement compatible avec la définition
#       d'un tableau numpy.
#       truc(i)  est une liste en compréhension de p flottants.

# on récupère donc une matrice C de taille (n,p) de coefficient
# général cij = (i-1)**(j-1) (dans la notation math. des indices
# pour les coefficients des matrices).
#   python   |    math
#   ---------+-----------
#    i,j   ----> i+1,j+1
#    i-1,j-1 <---- i,j



def Hilbert(n):
    return np.array([[1/(i+j+1) for j in range(n)] for i in range(n)])

##Q10

# Extrait une ligne ou une colonne au format tableau 1-dimensionnel

##Q11

D =np.array([1]*25).reshape(5,5)
D[0,:] = 0 # première ligne
D[:,-2] =0 # avant-dernière colonne

##Q12
Z = np.zeros((2,2))   # matrice nulle de taille 2x2

U = np.ones((4,2))    # matrice Attila (= remplie de 1) de taille 4x2

U.T                   # matrice transposée de U

I = np.eye(3)         # matrice identité de taille 3x3

Z1 = np.zeros_like(A) # matrice nulle de même taille que A
Z2 = np.ones_like(A)  # matrice Attila de même taille que A

##Q13
# il faut calculer C[i,j] pour chaque valeur de i et de j : 2 boucles
# De plus; à i,j fixé, C[i,j] est une somme : une boucle sur k
# Cela fait 3 boucles imbriquées dans le calcul A x B.
def promat(A,B):
    n,p = A.shape
    r,q = B.shape
    # je suppose que r=p sinon il y aura une erreur de toutes
    # manières au moment de l'appel de la fonction
    C = np.zeros((n,q))
    for i in range(n):
        for j in range(q):
            for k in range(p):
                C[i,j]+=A[i,k]*B[k,j]
    return C