Élever une matrice à une puissance en produits
Exercice d'entraînement · niveau 3 (difficile) · mathématiques approfondies (ECG 1re année), chapitre 11 — Informatique et algorithmique · Boucles, arrêt et algorithmes
Énoncé
Écrire une fonction qui calcule en n'employant que np.dot, avec un nombre de produits matriciels de l'ordre de et non de . Justifier sa correction par un invariant, puis la contrôler avec al.matrix_power sur et .
Corrigé
Ce qu'on montre. Que l'écriture binaire de permet de n'effectuer que des carrés successifs, et qu'un invariant de boucle démontre la correction du procédé.
L'idée. Si est pair, : un seul produit divise l'exposant par deux. Si est impair, et l'on se ramène au cas pair. On accumule donc les facteurs « impairs » rencontrés dans une variable, pendant qu'on élève au carré la base.
Le programme.
import numpy as np
import numpy.linalg as al
def puissance_rapide(A, n):
"""A**n avec environ 2*log2(n) produits matriciels."""
taille = np.shape(A)[0]
P = np.eye(taille) # accumulateur, neutre du produit
B = A # vaut A**(2**etape)
while n > 0:
if n % 2 == 1:
P = np.dot(P, B)
B = np.dot(B, B)
n = n // 2
return P
A = np.array([[1., 1.], [1., 0.]])
print(puissance_rapide(A, 10))
print(al.matrix_power(A, 10))
L'invariant. Notons l'exposant initial, et considérons, à chaque passage en tête de boucle, la quantité Au départ, , et : la quantité vaut . Un tour de boucle la conserve :
- si est pair, ne change pas, devient et devient : la quantité devient ;
- si est impair, devient , devient , devient : la quantité devient .
Dans les deux cas la valeur est inchangée. À la sortie, donc et la valeur vaut : la fonction renvoie bien . (Le calcul ci-dessus n'exige aucune commutativité étrangère : et sont toutes deux des puissances de , donc elles commutent.)
La terminaison. À chaque tour devient , entier strictement plus petit tant que : la suite décroît strictement dans , elle atteint .
Le coût. Le nombre de tours est le nombre de chiffres binaires de , soit . Chaque tour fait un ou deux produits : au plus produits, contre pour la méthode naïve. Pour : environ produits au lieu de .
Le contrôle. Pour , une récurrence donne où est la suite de Fibonacci. Avec , , , les deux affichages donnent identiques à la matrice renvoyée par al.matrix_power.
Point délicat. np.eye produit des flottants : la comparaison avec al.matrix_power se fait avec np.allclose, jamais avec ==.
Les autres exercices de ce chapitre Le cours du chapitre
Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.