Adloun

É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 :

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.