Informatique : Leçon 8. Matrices

  |   Source

Comment représenter les matrices ?

Rappel. Une matrice est un tableau bi-dimensionnel de nombres. Il existe un module dédié au calcul matriciel, mais pour le moment on va construire artisanalement nos matrices. ça fera un bon exercice de programmation.

Exemple. \(A =\begin{pmatrix} 1&1&1\\ 1&1&0\\ 1&0&1 \end{pmatrix}\) ou \(M =\begin{pmatrix} 1&2&3\\ 4&5&6 \end{pmatrix}\)

Vous pouvez considérer ainsi qu'une matrice est une liste de lignes, chaque ligne étant elle-même une liste de flottants. Ainsi, on peut définir des matrices comme des listes de listes.

A = [[1,1,1],[1,1,0],[1,0,1]] # les séparateurs des items sont
                              # des virgules
M = [[1,2,3],[4,5,6]]

Accéder à un coefficient

Si vous vous voulez récupérer le coefficient \(m_{i,j}\) dans \(M\), par exemple \(m_{2,3} = 6\), vous taperez :

M[1][2] # En Python, la numération commence à  0 ...
6

Fonction cousue main : taille d'une matrice

Exercice.

  1. Construire une fonction \(\texttt{taille(A)}\) qui prend en entrée une matrice \(\texttt{A}\) et retourne en sortie le tuple \(\texttt{(n,p)}\) donnant son format. Par exemple, pour la matrice \(\texttt{M}\) précédente, \(\texttt{taille(M)}\) doit vous retourner le tuple \(\texttt{(2,3)}\).
  2. Testez votre fonction sur les matrices \(A\),\(M\) précédentes.
  3. Pourquoi cela ne marche pas pour L = [1,2,3,4] ?
  4. Testez alors sur la matrice ligne \(L=\begin{pmatrix} 1&12&-1&0 \end{pmatrix} \)

Réponse à la question 1.

def taille(M):
    """ fonction qui prend en entrée une matrice vue comme
        une liste de listes, et qui retourne en sortie son format.
        Exemple : M = 1 2 3
                      4 5 6
        taille(M) vaut (2,3)
    """
    return  len(M), len(M[0]) # C'est bien un tuple !

Réponse à la question 2.

taille(M)
(2, 3)
taille(A)
(3, 3)

Réponse à la question 3. l'objet \(\texttt{L}\) ainsi défini est une liste d'entiers et pas uen liste de listes : en tant que telle, ce n'est pas une matrice.

Réponse à la question 4.

L =  [[1,12,-1,0]]       # Ne pas oublier que chaque ligne de
C =  [[1],[2],[-1],[0]] # toute matrice est une liste !
                         # D'où les (nombreux) crochets
taille(L)
(1, 4)
taille(C)
(4, 1)

Opérations matricielles cousues main

Multiplication par une constante

Exercice. Programmer une fonction \(\texttt{mult(mu,A)}\) qui prend en entrée un scalaire \(\mu\) et une matrice \(A\) et qui retourne en sortie la matrice \(\mu A\).

Indications

  1. Si on appelle \(\texttt{resultat}\) la matrice qu'on veut calculer, intialisez votre liste \(\texttt{reusltat}\) à une liste vide.
  2. Remplissez \(\texttt{resultat}\) ligne par ligne : boucle sur les lignes.
  3. Pour chaque ligne : remplissez \(\texttt{resultat}\) colonne par colonne : boucle sur les colonnes.

Vous aurez besoin de regarder dans l'aide-mémoire comment ajouter un élément à une liste pour remplir vos lignes et votre matrice.

Votre fonction contient donc une double boucle.

def mult(mu,A):
    """ Fonction qui calcule le produit mu X A où mu est un scalaire
    et A une matrice.
    """
    (n,p) = taille(A)
    resultat = []
    for i in range(n):     # je prends les lignes de A une par une
                           # range(k) signifie range(0,k)
        ligne=[]           # je remplis la ligne qui est vide
        for j in range(p):
            ligne.append(mu*A[i][j])# j'ajoute à la ligne le coeff mu a_ij
        resultat.append(ligne)      # j'ajoute la ligne calculée à la matrice
    return resultat
mult(-1,A)
[[-1, -1, -1], [-1, -1, 0], [-1, 0, -1]]

Version améliorée : les listes en compréhension c'est super

Remarque. Il y a une façon plus pythonique de faire cela. Je pars de la liste suivante :

liste1 = [ 1, -9 ,5, 4]

Comme en maths !

Je créé la liste qui s'écrirait ainsi en maths : \(\texttt{liste2} = [ 3x, \quad x \in \texttt{liste1}]\). En Python, cela s'écrit de la même façon :

liste2=[3*x for x in liste1]
print liste2
[3, -27, 15, 12]

Et en cascade

Si je veux construire de la même façon la matrice \(3A\)\(A\) est la matrice précédemment définie : \(A =\begin{pmatrix} 1&1&1\\ 1&1&0\\ 1&0&1 \end{pmatrix}\)

[ [3*x for x in ligne] for ligne in A ]
[[3, 3, 3], [3, 3, 0], [3, 0, 3]]

Ce qui donne une façon plus simple de programmer \(\texttt{mult}\) :

def mult2(mu,A):
    """version améliorée de mult"""
    return [ [mu*x for x in toto] for toto in A ]
mult2(5,A)
[[5, 5, 5], [5, 5, 0], [5, 0, 5]]

Produit matriciel cousu main

Exercice. Ecrire une fonction \(\texttt{fois(A,B)}\) qui prend en entrée deux matrices \(\texttt{A}\) et \(\texttt{B}\) et qui :

  1. Retourne en sortie le produit matriciel \(\texttt{AB}\) si il est défini.
  2. Affiche un message d'erreur sinon.

Indication. Construire la matrice \(\texttt{AB}\) ligne par ligne (boucle !) et regarder dans l'aide-mémoire comment ajouter un élément à une liste.

def fois(A,B):
    """ Calcule le produit matriciel A x B si il existe, sinon
        affiche un message d'erreur.
    """
    (n,p) = taille(A)        # j'utilise ma fonction taille !
    (q,r) = taille(B)
    if p != q :
        print 'Matrices incompatibles'
    else:
        produit = []         # j'intialise AB à une matrice vide
        for i in range(0,n): # je calcule la ligne i
            ligne = []       # j'intialiste la ligne à une ligne vide
            for j in range(0,r):
                coeff = 0
                for k in range(0,p):
                    coeff += A[i][k]*B[k][j]
                ligne.append(coeff)
            produit.append(ligne)
    return produit
atilla=[[1,1,1],[1,1,1],[1,1,1]]
fois(atilla,atilla)
[[3, 3, 3], [3, 3, 3], [3, 3, 3]]
fois(A,A)
[[3, 2, 2], [2, 2, 1], [2, 1, 2]]
print A
[[1, 1, 1], [1, 1, 0], [1, 0, 1]]

Pour rigoler : se bricoler un bel affichage

On commence à faire du tuning là. On aimerait bien que :

print A
[[1, 1, 1], [1, 1, 0], [1, 0, 1]]

donne un affichage en tableau. Voici le principe :

  1. Déterminer dans la liste des coefficients de la matrice le coeff qui prend le plus de place dans la matrice.
  2. Réserver le même espace à chaque coeff.
  3. Afficher les lignes les unes au-dessus des autres.

Pour 1., je vais faire ça avec la puissance des listes en compréhension. Accrochez-vous, quand on a compris, c'est facile, mais à lire dans l'autre sens c'est plus dur :

def longueur_max(A):
    """ cherche la chaine de caractères la plus longue parmi les chaînes
        représentant les coeffs de la matrice A
    """
    return  max([len(str(coeff)) for ligne in A for coeff in ligne])

Par exemple : je prends la matrice

\begin{equation*} A = \begin{pmatrix} 1 & 2 & 4324\\ 333333&1&0 \end{pmatrix} \end{equation*}
A = [ [1,2,4324], [333333,1,0]]
longueur_max(A)  # la chaine '333333' est la plus longue, de longueur 6
6

C'est la magie de Python : une syntaxe très souple qui permet d'écrire en peu de mots des choses compliquées. Revers de la médaille : pour relire du code, c'est souvent compliqué quand on use des astuces pythoniques.

Pour 2., je crée une fonction qui étant donné une chaîne de caractères, la complète avec des espaces pour qu'elle atteigne une longueur \(\mathtt{r}\) donnée :

def ajoute_blancs(chaine,r):
    l = len(str(chaine)) # je mets un str en plus au cas où on
                         # veut rentrer un flottant.
    return   ' '*(r-l)+str(chaine)
ajoute_blancs(12,4)
'  12'

Avec ça, je peux faire ma fonction d'affichage

def affiche(A):
    p = longueur_max(A)
    for ligne in A:
        print ' '.join([ajoute_blancs(coeff,p) for coeff in ligne])

Si je reprends ma matrice :

\begin{equation*} A = \begin{pmatrix} 1 & 2 & 4324\\ 333333&1&0 \end{pmatrix} \end{equation*}
affiche(A)
     1      2   4324
333333      1      0
Comments powered by Disqus
Partager