Problème des multiplications matricielles enchaînées

De testwiki
Aller à la navigation Aller à la recherche

En informatique, un algorithme de multiplication de matrices enchaînées est un algorithme d'optimisation qui sert à trouver un ordre dans lequel calculer un produit de plusieurs matrices A1Ak de façon à minimiser le nombre de multiplications scalaires à effectuer.

Exemple élémentaire

On considère A=(a1a2a3), B=(b1b2b3) et C=(c1c2c3). Comme le produit matriciel est associatif on a (AB)C = A(BC) mais le calcul de (AB)C nécessite 6 multiplications scalaires tandis que celui de A(BC) en nécessite 18. Il est donc préférable de calculer d'abord AB puis (AB)C plutôt que d'abord BC puis A(BC).

Énoncé du problème

On se donne une suite de matrices rectangulaires A1,Ak et on souhaite en calculer le produit A1,k=A1Ak (on suppose que toutes les matrices ont une taille compatible, c'est-à-dire que le produit est bien défini). Le produit matriciel étant associatif, n'importe quel parenthésage du produit donnera le même résultat. On cherche à déterminer avant d'effectuer tout calcul quel parenthésage nécessitera le moins de multiplications scalaires.

Modèle:Refnec ; on supposera donc par la suite que le parenthésage à trouver concerne un produit matriciel classique.

Détermination du nombre d'opérations associées à un parenthésage particulier

Lorsque l'on multiplie deux matrices rectangulaires A et B ayant respectivement p lignes et q colonnes, et q lignes et r colonnes, la matrice AB obtenue a p lignes et r colonnes. Le calcul de chacun de ses pr coefficients nécessite q multiplications scalaires d'après la définition du produit matriciel ; le calcul de AB requiert donc pqr multiplications scalaires[1].

On peut donc calculer de proche en proche le nombre de multiplications scalaires associées à un parenthésage particulier. Cette détermination a une complexité O(k)k est le nombre de matrices à multiplier.

Algorithme naïf

Une solution possible est de procéder par force brute en énumérant tous les parenthésage possibles pour retenir le meilleur. Ce n'est pas envisageable car pour un produit de k facteurs, le nombre de parenthésages possibles est égal au k1-ième nombre de Catalan, dont la suite a une croissance exponentielle[1].

Algorithme utilisant la programmation dynamique

Le problème a une structure telle qu'un sous-parenthésage d'un parenthésage optimal est lui-même optimal. De plus un même sous-parenthésage peut intervenir dans plusieurs parenthésages différents. Ces deux conditions rendent possible la mise en œuvre de techniques de programmation dynamique.

Structure d'un parenthésage optimal

On remarque que pour un parenthésage optimal du produit Ai,j=AiAj (où on a 1i<jk), si le dernier produit matriciel calculé est (AiAl)(Al+1Aj) alors les parenthésages utilisés pour le calcul de AiAl et Al+1Aj sont eux aussi optimaux. En effet si ce n'était pas le cas on pourrait les remplacer par un meilleur parenthésage et donc avoir un meilleur parenthésage pour le produit AiAj, ce qui est contradictoire avec l'hypothèse d'optimalité que l'on a faite.

La même hypothèse d'optimalité peut être faite pour tous les parenthésages de tous les produits intermédiaires au calcul de Ai,j et donc pour tous ceux du calcul de A1,k. Cela permet une résolution grâce à la programmation dynamique[1].

Calcul du coût des sous-parenthésages

Pour tout i[1,k] on note pi1 le nombre de lignes de Ai et pi son nombre de colonnes[2].

On définit les tableaux à deux dimensions m[1k][1k] et l[1k][1k] tels que pour tout couple d'indices (i,j) tel que ij, la case m[i][j] contient le nombre minimal de multiplications scalaires nécessaire au calcul de Ai,j et l[i][j] contient un indice tel que le parenthésage optimal du produit soit Ai,j=Ai,lAl+1,j on obtient[1]:

m[i][j]={0 si i=j,minil<j{m[i][l]+m[l+1][j]+pi1plpj} si i<j,NIL si i>j.

et

l[i][j]={s tel que minil<j{m[i][l]+m[l+1][j]+pi1plpj}=m[i][s]+m[s+1][i]+pi1pspj si i<j,NIL sinon.

On peut calculer le contenu des cases de m et de s simultanément de proche en proche.

Reconstitution d'un parenthésage optimal

Étant donné le tableau l, on peut utiliser l'algorithme récursif suivant pour étant donnés deux indices i et j déterminer un parenthésage optimal du produit Ai,j[1]:

Affichage-Parenthésage-Minimal(l,i,j)
si i=j
  afficher "A_i"
sinon afficher "("
  Affichage-Parenthésage-Minimal(l,i,l[i][j])
  Affichage-Parenthésage-Minimal(l,l[i][j]+1,j)
  afficher ")"

On obtient alors un parenthésage optimal en exécutant :

Affichage-Parenthésage-Minimal(l,1,k)


Calcul de la complexité

Comme il y a O(k2) cases dans le tableau et que le coût d'un sous-parenthésage peut être calculé en O(k), il s'ensuit que l'on peut calculer les coûts de l'ensemble des sous-parenthésages optimaux en O(k3) avec une capacité de stockage mémoire Θ(k2)[1]. On peut également montrer que la complexité en temps du calcul de m est Ω(k3) : la complexité est cubique même dans le meilleur des cas[1].

Une fois déterminés m et s, l'algorithme affichant le parenthésage a une complexité O(k)[1].

Exemple d'exécution

Soit M5,10,M10,6,M6,30,M30,4,M4,12,M12,16 six matrices rectangulaires (pour chaque matrice, le premier indice indique son nombre de lignes et le second son nombre de colonnes). On cherche un parenthésage optimal pour calculer le produit M=M5,10M10,6M6,30M30,4M4,12M12,16. Si l'on souhaite procéder par recherche exhaustive il y a C5=42 parenthésages à tester, on opte donc pour l'algorithme par programmation dynamique.

On remplit les cases (i,j) des tableaux c[1..6][1..6] et l[1..6][1..6] en suivant l'ordre :

Première diagonale (1,2)(2,3)(3,4)(4,5)(5,6)
Deuxième diagonale (1,3)(2,4)(3,5)(4,6)
Troisième diagonale (1,4)(2,5)(3,6)
Quatrième diagonale (1,5)(2,6)
Cinquième diagonale (1,6)


On obtient alors les tableaux suivants :


Modèle:Col-début Modèle:Col-2

Tableau c des coûts des sous-parenthésages.
1 2 3 4 5 6
1 0 300 1 200 1 140 1 380 2 228
2 NIL 0 1 800 960 1 440 2 368
3 NIL NIL 0 720 1 008 1 872
4 NIL NIL NIL 0 1 440 2 688
5 NIL NIL NIL NIL 0 768
6 NIL NIL NIL NIL NIL 0

Modèle:Col-2

Tableau l d'indices de séparation optimaux.

1 2 3 4 5 6
1 NIL 1 2 2 4 4
2 NIL NIL 2 2 4 4
3 NIL NIL NIL 3 4 4
4 NIL NIL NIL NIL 4 4
5 NIL NIL NIL NIL NIL 5
6 NIL NIL NIL NIL NIL NIL

Modèle:Col-fin


D'où l'on déduit qu'un parenthésage optimal est M=((M5,10M10,6)(M6,30M30,4))(M4,12M12,16) qui permet un calcul de M avec 2 228 multiplications scalaires. À titre de comparaison, le tableau suivant présente les coûts de différents parenthésages.

Parenthésage Nombre de multiplications
M=((M5,10M10,6)(M6,30M30,4))(M4,12M12,16) 2 228
M=M5,10(M10,6(M6,30(M30,4(M4,12M12,16)))) 3 000
M=((((M5,10M10,6)M6,30)M30,4)M4,12)M12,16 7 328
M=(M5,10(M10,6M6,30))((M30,4M4,12)M12,16) 12 900

Algorithme quasi linéaire

Modèle:... Un algorithme a été proposé en 1981 dont la complexité est O(klogk)[3].

Applications

Dans la pratique, la taille des matrices à multiplier excède souvent le nombre de facteurs du produit matriciel. Ainsi même si la complexité de l'algorithme d'optimisation est O(k3), l'appliquer pour minimiser le nombre de multiplications scalaires à effectuer dans le produit proprement dit représente un gain de temps[1].

Bibliographie

Modèle:Lien web

Références

Modèle:Références

Modèle:Palette Modèle:Portail

  1. 1,0 1,1 1,2 1,3 1,4 1,5 1,6 1,7 et 1,8 Modèle:Ouvrage.
  2. La notation est cohérente car pour que le produit de deux matrices soit défini, le nombre de colonnes de celle de gauche doit être égal au nombre de lignes de celle de droite.
  3. Modèle:Article