Espaces de matrices

Plan du chapitre "Calcul matriciel"

Matrices à {n} lignes et {p} colonnes

Définition (matrices à n lignes, à p colonnes, et à coefficients dans )
Soient {n} et {p} deux entiers strictement positifs.
Une matrice {A} de type {(n,p)} est une application de {\{1,\ldots,n\}\times\{1,\ldots,p\}} dans {\mathbb{K}}.
On note souvent {a_{i,j}} (« coefficient d’indice {i,j} ») l’image du couple {(i,j)} par l’application {A}.
On écrit alors {A=(a_{i,j})_{i=1..n\atop j=1..p}}, ou plus simplement {A=(a_{ij})}.

On note {\mathcal{M}_{n,p}(\mathbb{K})} l’ensemble des matrices de type {(n,p)} à coefficients dans {\mathbb{K}}.
Pour décrire un élément {A} de {\mathcal{M}_{n,p}(\mathbb{K})}, on dispose les coefficients dans un tableau à {n} lignes et {p} colonnes, le coefficient {a_{i,j}} venant se placer à l’intersection de la {i}-ème ligne et de la {j}-ème colonne.

Par exemple, {A\in\mathcal{M}_{2,3}(\mathbb{K})} définie par : {\left\{\begin{array}{ccc}a_{1,1}=5,& a_{1,2}=3,&a_{1,3}=2\\a_{2,1}=7,& a_{2,2}=4,&a_{2,3}=1\end{array}\right.} est {A=\begin{pmatrix}5&3&2\cr7&4&1\end{pmatrix}}.

Finalement, c’est ce tableau lui-même qu’on appelle une matrice. On note souvent {[A]_{i,j}=a_{i,j}}.

On dit donc qu’un élément {A} de {\mathcal{M}_{n,p}(\mathbb{K})} est une “matrice à {n} lignes et à {p} colonnes”.
Voici comment on peut former cette matrice dans Python, après avoir chargé le module numpy :

>>> import numpy as np                   # charge numpy et le renomme np
>>> A = np.array([[5,3,2],[7,4,1]]); # forme une matrice d’entiers
>>> A # affiche cette matrice
array([[5, 3, 2],
[7, 4, 1]])

On peut convertir les coefficients entiers de {A} au format 'float' ou 'complex' :

>>> A.astype(float)
array([[ 5., 3., 2.],
[ 7., 4., 1.]])
>>> A.astype(complex)
array([[ 5.+0.j, 3.+0.j, 2.+0.j],
[ 7.+0.j, 4.+0.j, 1.+0.j]])
Attention!! En Python, les indices de ligne et de colonne commencent à {0}.

>>> A[1,0]           # la ligne d’indice 1 est la deuxième ligne
7 # la colonne d’indice 0 est la première colonne

Important : dans tous les exemples de ce chapitre, on supposera que numpy a été importé.

Avec Python, on peut créer une matrice dont le terme général répond à une formule donnée, en format par exemple la liste des listes de ces valeurs (avec une syntaxe “en compréhension”) avant de convertir le résultat en un “array” :

>>> A = np.array([[10*i+j for j in range(10)]
for i in range(5)])
>>> print(A) # la matrice des 10i+j, avec 0≤i≤4, et 0≤j≤9
[[ 0 1 2 3 4 5 6 7 8 9] 
[10 11 12 13 14 15 16 17 18 19] 
[20 21 22 23 24 25 26 27 28 29] 
[30 31 32 33 34 35 36 37 38 39] 
[40 41 42 43 44 45 46 47 48 49]]

Voici une autre méthode pour former la matrice précédente. Ici les coefficients sont des flottants : si on veut des entiers, il suffit de rajouter l’option dtype='int'.

>>> B = np.fromfunction(lambda x,y : 10*x+y, (5,10))
>>> print(B)
[[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.] 
[ 10. 11. 12. 13. 14. 15. 16. 17. 18. 19.] 
[ 20. 21. 22. 23. 24. 25. 26. 27. 28. 29.] 
[ 30. 31. 32. 33. 34. 35. 36. 37. 38. 39.] 
[ 40. 41. 42. 43. 44. 45. 46. 47. 48. 49.]]

On peut aussi créer des matrices aléatoires. Ici on crée une matrice pseudo-aléatoire de quatre lignes, cinq colonnes, et à coefficients dans [0,1] :

>>> A = np.random.rand(4,5); print(A)
[[ 0.4672486 0.42452394 0.55652697 0.50122566 0.45039697] 
[ 0.10245706 0.39642783 0.18395313 0.43191611 0.59490124] 
[ 0.97133547 0.06577487 0.33274442 0.39404957 0.34601463] 
[ 0.60141568 0.01085386 0.69123586 0.33062893 0.68429281]]

Matrices constantes, matrice nulle

Une matrice constante {A=(a_{i,j})} de {\mathcal{M}_{n,p}(\mathbb{K})} est définie par {a_{i,j}=\lambda} pour tous {i,j}.
En particulier, la matrice nulle {A=(a_{i,j})} de {\mathcal{M}_{n,p}(\mathbb{K})} est définie par {a_{i,j}=0} pour tous {i,j}.
Voici quelques façons de créer des matrices constantes avec Python :

>>> np.zeros([3, 4])
array([[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 0., 0., 0.]])
>>> np.ones([3, 4])
array([[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.]])

Ici la somme (ou le produit) d’une matrice et d’une constante s’effectue terme à terme :

>>> np.zeros([3, 4]) + 8
array([[ 8., 8., 8., 8.],
[ 8., 8., 8., 8.],
[ 8., 8., 8., 8.]])>>> np.ones([3, 4]) * 8
array([[ 8., 8., 8., 8.],
[ 8., 8., 8., 8.],
[ 8., 8., 8., 8.]])

“Matrices-ligne” et “matrices-colonne”

Les éléments de {{\mathcal M}_{1,p}(\mathbb{K})} sont dits matrices-ligne. Ceux de {{\mathcal M}_{p,1}(\mathbb{K})} sont dits matrices-colonne.

On peut identifier (en restant prudent) :

  • le vecteur {(a_1,a_2,\ldots,a_p)} de {\mathbb{K}^p}
  • la matrice-ligne {(a_1\ a_2\ \ldots\ a_p)} de {{\mathcal M}_{1,p}(\mathbb{K})}
  • la matrice-colonne {\begin{pmatrix}a_1\\ a_2\\ \vdots\\ a_p\end{pmatrix}} de {{\mathcal M}_{p,1}(\mathbb{K})}

>>> np.array([1,3,5])         # on définit un vecteur
array([1, 3, 5])
>>> np.array([[1,3,5]]) # on définit une matrice-ligne
array([[1, 3, 5]])
>>> np.array([[1],[3],[5]]) # on définit une matrice-colonne
array([[1],
[3],
[5]])

Structure d’espace vectoriel de {\mathcal{M}_{n,p}(\mathbb{K})}

Définition (somme de deux matrices, produit par un scalaire)
Soit {A=(a_{ij})} et {B=(b_{ij})} deux matrices de {\mathcal{M}_{n,p}(\mathbb{K})}, et {\lambda} un scalaire.
On définit les matrices {C=A+B} et {D=\lambda A} dans {\mathcal{M}_{n,p}(\mathbb{K})}de la manière suivante :
Pour tous indices {i} et {j} : {c_{ij}=a_{ij}+b_{ij}} et {d_{ij}=\lambda a_{ij}}.
Proposition (structure d'espace vectoriel de M_{n,p}())
L’ensemble {\mathcal{M}_{n,p}(\mathbb{K})} est un espace vectoriel sur {\mathbb{K}}, de dimension {np}.

L’élément neutre est la matrice nulle, notée habituellement {0}.
L’opposé de la matrice {A=(a_{ij})} est la matrice notée {-A}, de terme général {-a_{ij}}.

Base canonique

On fixe {n} et {p} dans {\mathbb{N}^{*}}, et on se place dans l’espace vectoriel {\mathcal{M}_{n,p}(\mathbb{K})}.
Soit {i} dans {\{1,\ldots,n\}} et {j} dans {\{1,\ldots,p\}}.
On note {E_{i,j}} la matrice dont tous les coefficients sont nuls, sauf celui d’indice {(i,j)} qui vaut {1}.
La famille des {np} matrices {(E_{i,j})}, pour {1\le i\le n} et {1\le j\le p} est une base de {\mathcal{M}_{n,p}(\mathbb{K})}.
On l’appelle la “base canonique” de {\mathcal{M}_{n,p}(\mathbb{K})}.

Pour toute matrice {M=(a_{ij})} de {\mathcal{M}_{n,p}(\mathbb{K})}, on a {M=\displaystyle\sum_{i=1}^n\,\displaystyle\sum_{j=1}^p\,a_{ij}\,E_{ij}}.
Voici par exemple les six matrices de la base canonique de {M_{2,3}(\mathbb{K})} : {\begin{array}{ccc}E_{1,1}=\begin{pmatrix}1&0&0\\0&0&0\end{pmatrix}& E_{1,2}=\begin{pmatrix}0&1&0\\0&0&0\end{pmatrix}& E_{1,3}=\begin{pmatrix}0&0&1\\0&0&0\end{pmatrix}\\ E_{2,1}=\begin{pmatrix}0&0&0\\1&0&0\end{pmatrix}& E_{2,2}=\begin{pmatrix}0&0&0\\0&1&0\end{pmatrix}& E_{2,3}=\begin{pmatrix}0&0&0\\0&0&1\end{pmatrix}\\\end{array}}
Pour toute matrice {A=\begin{pmatrix}a&b&c\\d&e&f\end{pmatrix}} de {M_{2,3}(\mathbb{K})}, on a effectivement (et de façon unique) : {\begin{array}{rl}A=&a\begin{pmatrix}1&0&0\\0&0&0\end{pmatrix}+b\begin{pmatrix}0&1&0\\0&0&0\end{pmatrix}+c\begin{pmatrix}0&0&1\\0&0&0\end{pmatrix}\\\\&+d\begin{pmatrix}0&0&0\\1&0&0\end{pmatrix}+e\begin{pmatrix}0&0&0\\0&1&0\end{pmatrix}+f\begin{pmatrix}0&0&0\\0&0&1\end{pmatrix}\end{array}}
Voici une fonction Python qui renvoie une matrice de la base canonique de {\mathcal{M}_{n,p}(\mathbb{K})} (attention encore une fois à la numérotation des lignes et des colonnes qui commence à {0} dans les tableaux Python) :

def E(n, p, i, j, format=’int’):
a = np.zeros([n,p],format); a[i-1,j-1] = 1; return a

On calcule ici deux fois {E_{2,4}} dans {\mathcal{M}_{3,5}(\mathbb{K})} (d’abord en format 'int', puis en format 'float') :

>>> E(3, 5, 2, 4)
array([[0, 0, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 0]])
>>> E(3, 5, 2, 4, ‘float’)
array([[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 1., 0.],
[ 0., 0., 0., 0., 0.]])

Avec Python, l’addition des matrices et le produit par des scalaires s’effectuent de façon très naturelle :

>>> A = np.random.randint(10, size=(3,4))
>>> print(A)
[[1 3 4 2] 
[0 5 5 1] 
[2 1 9 7]]
>>> B = np.random.randint(10, size=(3,4))
>>> print(B)
[[3 5 4 7] 
[1 2 3 1] 
[3 8 8 0]] 
>>> print(A+B)
[[ 4 8 8 9] 
[ 1 7 8 2] 
[ 5 9 17 7]] 
>>> print(10*A+B)
[[13 35 44 27] 
[ 1 52 53 11] 
[23 18 98 70]

Matrices carrées

Définition (matrices carrées d'ordre n)
On appelle matrice carrée d’ordre {n} (ou de taille {n}) toute matrice de type {(n,n)}.
On note {\mathcal{M}_n(\mathbb{K})} (plutôt que {\mathcal{M}_{n,n}(\mathbb{K})}) l’ensemble des matrices carrées d’ordre {n} à coefficients dans {\mathbb{K}}.

Diagonale d’une matrice carrée

Soit {A=(a_{i,j})} une matrice carrée d’ordre {n}.
Les coefficients {a_{i,i}} (appelés coefficients diagonaux) de {A} forment la diagonale de {A}.
Les coefficients {a_{i,j}} tels que {j\lt i} sont donc en dessous de cette diagonale.
Les coefficients {a_{i,j}} tels que {i\lt j} sont au dessus de celle-ci.

On forme ci-dessous une matrice {A} de {\mathcal{M}_{5}(\mathbb{R})}, à coefficients entiers choisis aléatoirement dans {[0,9[}.
On voit que la fonction diagonal du module numpy permet de récupérer la diagonale de {A}.
Remarque : il y a une deuxième diagonale dans une matrice carrée, mais seule celle qui débute “en haut en gauche” et se termine “en bas à droite” est importante (on le verra plus loin).

>>> A = np.random.randint(10, size=(4,4)); print(A)
[[6 3 4 3] 
[4 1 3 9] 
[7 0 9 6] 
[4 8 6 4]] 
>>> A.diagonal() # ou encore np.diag(A)
array([6, 1, 9, 4])

Matrices diagonales

Une matrice {A=(a_{i,j})} de {\mathcal{M}_n(\mathbb{K})} est dite diagonale si on a {a_{i,j}=0} pour tous indices distincts {i} et {j}.
Ainsi {A} est diagonale si les seuls coefficients non nuls éventuels de {A} sont ses coefficients diagonaux.
La matrice nulle de {\mathcal{M}_n(\mathbb{K})} est donc un cas (très) particulier de matrice diagonale.

Matrice identité

La matrice identité d’ordre {n} est la matrice diagonale de {\mathcal{M}_{n}(\mathbb{K})} de coefficients diagonaux égaux à {1}.
Cette matrice est notée {\text{I}_n}.
On remarque que pour tous indices {i} et {j}, on a : {[\text{I}_n]_{i,j}=\delta_{i,j}} (notation de Kronecker).

>>> np.diag([1,4,7,2])
array([[1, 0, 0, 0],
[0, 4, 0, 0],
[0, 0, 7, 0],
[0, 0, 0, 2]])
>>> np.eye(4)
array([[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]])
>>> np.eye(4,dtype=’int’)
array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])

Matrices scalaires

Les matrices carrées de la forme {A=\lambda{I}_n}, c’est-à-dire les matrices diagonales
dont tous les coefficients diagonaux sont égaux, sont dites matrices scalaires.

>>> (5+2j)*np.eye(3)
array([[ 5.+2.j, 0.+0.j, 0.+0.j],
[ 0.+0.j, 5.+2.j, 0.+0.j],
[ 0.+0.j, 0.+0.j, 5.+2.j]])

Matrices triangulaires ou strictement triangulaires

Soit {A=(a_{i,j})} une matrice de {\mathcal{M}_n(\mathbb{K})}.
On dit que {A} est triangulaire supérieure si les coefficients sous la diagonale sont nuls.
On dit que {A} est triangulaire inférieure si les coefficients au-dessus de la diagonale sont nuls.

Ainsi {A} est triangulaire inférieure si {(i\lt j\Rightarrow a_{i,j}=0)}.
Elle est triangulaire supérieure si {(j\lt i\Rightarrow a_{i,j}=0)}.

La matrice {A} est dite strictement triangulaire si elle est triangulaire et si sa diagonale est nulle.

Avec Python, on forme ici une matrice aléatoire {A}, carrée d’ordre {4}, à coefficients dans {[[ 1,9]]}.
Les fonctions triu et tril (avec u pour “up” et l pour “low”) permettent d’extraire de {A} une matrice triangulaire supérieure ou (éventuellement strictement, avec un argument optionnel).

>>> A=np.random.randint(1,10,size=(4,4))
>>> print(A)
[[4 6 2 7] 
[9 7 2 7] 
[3 4 5 1] 
[9 8 7 7]] 
>>> np.triu(A) # Matrice triangulaire supérieure
array([[4, 6, 2, 7], 
[0, 7, 2, 7], 
[0, 0, 5, 1], 
[0, 0, 0, 7]])
>>> np.triu(A,1) # Matrice strictement triangulaire supérieure
array([[0, 6, 2, 7], 
[0, 0, 2, 7], 
[0, 0, 0, 1], 
[0, 0, 0, 0]])
>>> np.tril(A) # Matrice triangulaire inférieure
array([[4, 0, 0, 0], 
[9, 7, 0, 0], 
[3, 4, 5, 0], 
[9, 8, 7, 7]])
>>> np.tril(A,-1) # Matrice strictement triangulaire inférieure
array([[0, 0, 0, 0], 
[9, 0, 0, 0], 
[3, 4, 0, 0], 
[9, 8, 7, 0]])

Toujours en Python, la fonction tri permet de construire des matrices (strictement) triangulaires inférieures dont les coefficients sous-diagonaux valent {1} :

>>> np.tri(4,4,dtype=’int’)
array([[1, 0, 0, 0],
[1, 1, 0, 0],
[1, 1, 1, 0],
[1, 1, 1, 1]])
>>> np.tri(4,4,-1,dtype=’int’)
array([[0, 0, 0, 0],
[1, 0, 0, 0],
[1, 1, 0, 0],
[1, 1, 1, 0]])

Page suivante : produit matriciel