Algèbre

15 minutes de Python

numpy.linalg : propriétés de matrices (inversibilité, rang, valeurs propres, …)

Thème : Algèbre

Niveau : ECG1–ECG2

Année : Maths appliquées, Maths approfondies

Objectif : maîtriser les commandes de numpy.linalg pour inverser une matrice, résoudre un système linéaire, calculer le rang, les valeurs propres et des puissances de matrices

Commandes essentielles de numpy.linalg

Les commandes du module numpy.linalg permettent d’étudier les principales propriétés des matrices : calcul du rang, recherche d’un inverse, résolution de systèmes linéaires, détermination des valeurs propres, calcul de puissances de matrices, etc.

Dans cette page, on travaille avec des matrices numpy, c’est-à-dire des objets np.array à deux dimensions. On importera systématiquement les bibliothèques numpy et numpy.linalg de la façon suivante :

import numpy as np
import numpy.linalg as al
import numpy as np
import numpy.linalg as al

Les commandes du module numpy.linalg permettent d’effectuer rapidement les calculs fondamentaux d’algèbre linéaire : inverse, résolution de systèmes, valeurs propres, rang, puissances de matrices.


Inverse d’une matrice : al.inv

Si \(A\in\mathcal{M}_n(\mathbb{R})\) est inversible, la commande

al.inv(A)

renvoie l’inverse de la matrice \(A\), ou plus précisément une approximation numérique de la matrice \(A^{-1}\). En effet, les calculs sont effectués par l’ordinateur avec un nombre fini de décimales : les coefficients affichés ne sont donc pas exacts, mais approchés.

Par exemple, si l’on définit

A = np.array([[1,1],[1,2]])

alors la commande

al.inv(A)

renvoie

array([[ 2., -1.],  [-1.,  1.]])

ce qui correspond bien à la matrice \[ A^{-1}=\begin{pmatrix}2 & -1 \\ -1 & 1\end{pmatrix}. \]

En pratique, on peut vérifier le résultat par exemple avec :

np.dot(A, al.inv(A))

qui doit renvoyer un résultat proche de la matrice identité.


Résolution de système : al.solve

Si \(A\in\mathcal{M}_n(\mathbb{R})\) est inversible et \(B\in\mathcal{M}_{n,p}(\mathbb{R})\), la commande

al.solve(A, B)

renvoie la matrice \(X\) solution du système linéaire \[ AX = B. \]

Autrement dit, al.solve s’applique exactement au cas où le système admet une solution unique.

En particulier, si \(B\) est un vecteur colonne, on obtient la solution d’un système linéaire classique.

Mathématiquement, on a \(X=A^{-1}B\), mais l’algorithme utilisé n’explicite pas l’inverse.

⚠️ Remarque importante. Si la matrice \(A\) n’est pas inversible, le système n’admet pas de solution unique (absence de solution ou infinité de solutions). Dans ce cas, la commande al.solve provoque une erreur.


Exemple (système avec solution unique).

A = np.array([[2,1],[1,2]])
b = np.array([3,3])

al.solve(A, b)

Python renvoie alors :

array([1., 1.])

ce qui correspond à la solution \((x,y)=(1,1)\).


Exemple (matrice non inversible).

A = np.array([[1,2],[2,4]])
b = np.array([3,6])

al.solve(A, b)

Ici, la matrice \(A\) n’est pas inversible. La commande al.solve provoque une erreur (indiquant que la matrice est singulière) et ne renvoie aucun résultat.

Cela correspond au fait que le système n’admet pas de solution unique.


Valeurs propres et vecteurs propres : al.eig


Exemple 1 : matrice diagonalisable.

A = np.array([[2,0], [0,1]])

al.eig(A)

Python renvoie :

EigResult(eigenvalues=array([2., 1.]),
          eigenvectors=array([[1., 0.], [0., 1.]]))

Les valeurs propres sont 2 et 1. Les colonnes de la matrice eigenvectors sont des vecteurs propres associés. Ici, on reconnaît deux vecteurs propres non colinéaires : \((1,0)\) et \((0,1)\).

Ils sont linéairement indépendants, donc ils forment une base de \(\mathbb{R}^2\). On en déduit que la matrice est diagonalisable.


Exemple 2 : matrice non diagonalisable.

A = np.array([[1,1], [0,1]])

al.eig(A)

Python renvoie :

EigResult(eigenvalues=array([1., 1.]),
          eigenvectors=array([[ 1.00000000e+00, -1.00000000e+00],
                               [ 0.00000000e+00,  2.22044605e-16]]))

La seule valeur propre est 1, de multiplicité 2. Python fournit deux vecteurs propres. Cependant, le deuxième vecteur est numériquement très proche de \((-1,0)\), car \(2.22044605\times10^{-16}\approx 0\).

Les deux colonnes sont donc pratiquement colinéaires. Elles engendrent une droite et non \(\mathbb{R}^2\). La matrice eigenvectors n’est pas inversible.

On en déduit que la matrice n’est pas diagonalisable : elle n’admet qu’une seule direction propre.

Dans ce cas, on peut retrouver facilement un vecteur propre en résolvant \begin{align*} (A-I)v=0 &\Leftrightarrow\; \begin{pmatrix}0&1\\0&0\end{pmatrix} \begin{pmatrix}x\\y\end{pmatrix} =\begin{pmatrix}0\\0\end{pmatrix}\\ &\Longleftrightarrow\; y=0. \end{align*} Un vecteur propre simple est donc par exemple \((1,0)\).


Rang d’une matrice : al.matrix_rank

La commande

al.matrix_rank(A)

renvoie le rang de la matrice \(A\), c’est-à-dire la dimension du sous-espace engendré par ses colonnes (ou, ce qui revient au même, par ses lignes).

Concrètement, elle permet de savoir combien de colonnes de \(A\) sont linéairement indépendantes. On l’utilise notamment pour tester l’inversibilité d’une matrice carrée.

Par exemple, si l’on définit

A = np.array([[1,2,3],
              [2,4,6],
              [1,1,1]])

alors la commande

al.matrix_rank(A)

renvoie 2, car la deuxième ligne est le double de la première. La matrice n’est donc pas inversible.

Par ailleurs, si \(A\in\mathcal{M}_n(\mathbb{R})\), la condition

al.matrix_rank(A) == n

est vraie si et seulement si la matrice \(A\) est inversible.


Puissance d’une matrice : al.matrix_power

Si \(A\in\mathcal{M}_n(\mathbb{R})\) et \(k\in\mathbb{N}\), la commande

al.matrix_power(A, k)

renvoie la matrice \(A^k\), c’est-à-dire le produit de \(k\) matrices \(A\) : \[ A^k = \underbrace{A \times A \times \cdots \times A}_{k\ \text{facteurs}}. \]

Cette fonction est particulièrement utile pour étudier des suites de matrices, des systèmes dynamiques discrets, ou des chaînes de Markov (dans un cadre probabiliste).

En pratique, le calcul est effectué par exponentiation rapide, bien plus efficace qu’une boucle naïve.

Exemple

import numpy as np
import numpy.linalg as al

A = np.array([[2, 1],
              [1, 2]])

b = np.array([3, 3])

print("rang(A) =", al.matrix_rank(A))
print("A^{-1} =", al.inv(A))
print("solution de AX=b :", al.solve(A, b))

res = al.eig(A)
print(res)

print("A^3 =", al.matrix_power(A, 3))

Explication

On travaille avec \[ A=\begin{pmatrix}2&1\\1&2\end{pmatrix} \qquad\text{et}\qquad b=\begin{pmatrix}3\\3\end{pmatrix}. \]

  • al.matrix_rank(A) renvoie 2. En effet, \(\det(A)=4-1=3\neq0\), donc \(A\) est inversible et son rang vaut 2.
  • al.inv(A) renvoie une approximation de \[ A^{-1}=\frac{1}{3}\begin{pmatrix}2&-1\\-1&2\end{pmatrix}. \] Les coefficients sont affichés sous forme décimale approchée.
  • al.solve(A,b) résout le système \(AX=b\). Ici, \[ \begin{cases} 2x+y=3\\ x+2y=3 \end{cases} \Longrightarrow (x,y)=(1,1). \] Python renvoie donc array([1., 1.]).
  • al.eig(A) renvoie les valeurs propres et des vecteurs propres. On peut remarquer que : \[ \det(A-\lambda I)=(2-\lambda)^2-1=(\lambda-1)(\lambda-3), \] donc les valeurs propres sont \(1\) et \(3\). Comme \( A\) est une matrice carrée d’ordre \( 2 \) possédant deux valeurs propres distinctes, la matrice est diagonalisable.
  • al.matrix_power(A,3) renvoie la matrice \(A^3\). On peut la calculer à la main : \[ A^2=\begin{pmatrix}5&4\\4&5\end{pmatrix} \qquad\Rightarrow\qquad A^3=A^2A=\begin{pmatrix}14&13\\13&14\end{pmatrix}. \] Python renvoie donc une matrice égale (à l’écriture près) à celle-ci.

Trois commandes utiles aujourd’hui

Clique sur une carte pour voir l’instruction utile.

Créer une matrice en compréhension
Changer une colonne d'un tableau numpy
Créer une matrice dont tous les coefficients sont égaux à 1

Un exercice pour vérifier ta maîtrise

On considère les matrices

\[ A=\begin{pmatrix}2&1\\1&2\end{pmatrix} \qquad\text{et}\qquad b=\begin{pmatrix}3\\3\end{pmatrix} \]

Compléter le code pour afficher : le rang de \(A\), l’inverse de \(A\), la solution du système \(AX=b\), les valeurs propres de \(A\) et la matrice \(A^3\).

Et pour quelques minutes de plus…

Prendre en main la programmation, pas à pas.

Ces exercices sont conçus pour t’aider à maîtriser progressivement la programmation en Python, en partant de la lecture et de la compréhension du code, jusqu’à l’écriture autonome de scripts complets.

L’objectif n’est pas d’aller vite, mais de construire des automatismes solides, en comprenant ce que fait chaque instruction, puis en apprenant à les utiliser par toi-même.

L’ordre des exercices est volontaire : on lit, on comprend, on complète, puis on écrit seul. Prends le temps de chaque étape : c’est la clé pour progresser durablement.

Niveau 1 Analyser un code

Comprendre avant d’écrire.
Dans cette première série, tu observes et analyses des scripts Python déjà écrits. L’objectif est de comprendre la logique du programme, le rôle des variables, des boucles et des conditions, et d’être capable de prévoir ce que le code affiche ou calcule.

Niveau 2 Compléter un code

Écrire, mais avec un cadre.
Ici, tu passes à l’écriture sans partir de zéro. Le squelette du programme est fourni : il te reste à compléter certaines instructions pour que le code fonctionne correctement. Ce format permet de se concentrer sur l’essentiel, sans se perdre dans la structure générale.

Niveau 3 Écrire un code complet

Passer à l’autonomie.
Dans cette dernière série, tu écris un programme complet à partir d’une consigne. Tu dois organiser ton code, choisir les bonnes instructions et construire la logique globale du script. C’est ici que tu mets en pratique tout ce que tu as appris dans les niveaux précédents.

error: Ce contenu est protégé !