Bonjour à tous,
Je souhaite écrire une implémentation de l’algorithme qui inverse une matrice en procédant à une succession d’opérations sur les lignes. C’est quelque chose que j’ai déjà vu une fois à la fac, mais la prof ne nous avait pas demandé d’en faire un programme et on a vu ça vite fait.
Pour ce faire, je me suis basé sur ce cours : https://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/matrix-inverse .
Résumons grossièrement
On dispose de trois opérations de base
-
Échanger deux lignes
-
Multiplier chaque coefficient d’une ligne par un nombre (différent de 0)
-
Remplacer une ligne par la somme d’elle-même et le multiple d’une autre ligne
Idée générale
L’idée est d’appliquer une succession de ces trois opérations de base sur notre matrice N°1 ; ces applications, comment dire, "personnalisées" pour cette matrice. En parallèle, on applique exactement ces mêmes opérations sur une matrice identité qu’on s’est préalablement donnée (matrice N°2). A la toute fin du processus, la matrice N°1 doit être devenue une matrice identité, et notre matrice d’identité (N°2) doit être devenue une matrice non-identité et il s’agit de la matrice inverse de la matrice N°1.
Le processus
Reste à spécifier comment sont utilisées ces opérations de base (j’ai déjà précisé que cela dépendait de la matrice (N°1) traitée, mais ce n’est bien sûr pas une indication suffisante pour savoir comment inverser une matrice). Le processus se déroule en trois étapes.
Les explications ci-dessous proviennent du cours mentionné ci-dessus, et nécessitent de connaître la notion de pivot de matrice (définie dans ce même cours).
Etape N°1
Opération de base utilisée : échanges de deux lignes successifs,
The first thing we will do is to examine the value for the pivot coefficient for the current column (the column being processed). In order for our technique to work, this value has to be different than zero. If it is different than zero then we can directly move to step two. If it is equal to zero, we will need to find another row in the matrix for this column which value is different than zero, and swap these two rows (operation 1). However more than one row may have values different than zero ? So which one should we select ? We will pickup the row which absolute value is the highest.
If we can’t find another value for the pivot coefficient (that is if all the other values in the column are zero) then the matrix can’t be inverted and is singular
Le code source est fourni sur le cours.
Etape 2 : j’ai besoin d’aide !
L’idée est apparemment, grâce à des opérations de base, de mettre à 0 toutes les valeurs de chaque colonne (excepté leur pivot) des matrices N°1 et identité (N°2).
SAUF QUE j’ai beau lire et relire le cours, je ne comprends absolument pas ce qu’ils expliquent. Je trouve ça très flou, et l’exemple qu’ils donnent semble être partiel donc ça n’aide pas…
If the current column we are processing has a valid pivot coefficient, then we can proceed to the next step. We will reduce each coefficient of the column (apart from the pivot coefficient which we won’t touch for now) to zero. In English that won’t make much sense but here it is. Lets call ’m’, the current cofficient (for the current column/row) that we want to reduce to zero. We will subtract m muliplied by each coefficient of the row which index is the same as the index of the current column, from each coefficients of the current row (operation 2 and 3). The technique will work if m itself is divided by the pivot coefficient value (line 4). This is illustrated for one coefficient in the following example. The second column is the current column. We want to reduce the first coefficient (row 0) from the current column (4.3) to zero. For each coefficient of the first row (say C0j), we take the corresponding coefficient (C1j) from the second row (because we are processing the second column), multiply this coefficient by the coefficient we want to reduce by zero (C02) divided by the pivot coefficient from the second column (C12) and subtract the resulting number from C0j.
Bon et ils donnent le code source mais voilà quoi… Il n’a pas l’air très compliqué mais… J’aimerais plutôt comprendre sans devoir le lire…
Notez que je ne demande pas d’explications du genre "Mais pourquoi cette succession précise d’opérations de base permet-elle de mettre toutes ces valeurs à 0 ? Ce n’est pas magique je suppose ?!". Cela fera effectivement l’objet d’un second topic (le cours ne l’explique en effet pas).
Etape N°3
Convertir tous les pivots à 1. Bon là je pense comprendre. Je n’ai pas cherché à lire plus que ça cette étape du cours, car j’aimerais déjà comprendre l’étape 2 mais ça semble parler de diviser la valeur de chaque colonne par le pivot de cette dernière, et sûrement d’arrondir donc ça va, ça me semble compréhensible et aisément réalisable.
Ce que j’ai actuellement écrit
Etape 1 qui fonctionne
Le code qui suit est une simple implémentation de ce que j’ai cité et expliqué précédemment (cf. partie "Etape 1").
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 | def getGaussJordanInvertedMatrix: (Matrix, Matrix) = { var identity_matrix : mutable.Seq[Seq[Double]] = getIdentityMatrix(content.length) // We get the identity matrix. It will be modified // as the original matrix will. var inverted_matrix_content : scala.collection.mutable.Seq[Seq[Double]] = scala.collection.mutable.Seq[Seq[Double]](content: _*) content.zipWithIndex.foreach({ case (sub_sequence, first_index) => sub_sequence.indices.foreach(last_index => { // These first three lines simply indicates if either or not the // current case is a pivot (i.e. if it belongs to the diagonal) if(getDiagonalValuesCoordinates(content.length).contains((first_index, last_index))) { if(inverted_matrix_content(first_index)(last_index) == 0) { // Swapping (on both original and identity // matrices) is done only if the pivot = 0 val next_row_index = (first_index until content.length).maxBy(content(_)(last_index).abs) inverted_matrix_content = inverted_matrix_content.updated(next_row_index, inverted_matrix_content(first_index)).updated(first_index, inverted_matrix_content(next_row_index)) identity_matrix = identity_matrix.updated(next_row_index, identity_matrix(first_index)).updated(first_index, identity_matrix(next_row_index)) } } }) }) (new Matrix(identity_matrix), new Matrix(inverted_matrix_content)) } |
Etape 2 : pouvez-vous me réexpliquer cela s’il vous plaît ?
Comme je l’ai déjà dit, le cours est pour moi assez incompréhensible au niveau de cette étape, qu’il présente en outre comme un truc magique et compliqué… Y a moyen de reformuler ça svp ?
J’en ferai une implémentation selon VOS explications (limitez-vous à l’étape 2 svp, car le cours me paraît compréhensible concernant l’étape 3) et je vous la montrerai !
Merci d’avance !