Algorithmique et Programmation TD n 9 : Fast Fourier Transform Ecole normale supérieure Département d informatique td-algo@di.ens.fr 2011-2012 1 Petits Rappels Convolution La convolution de deux vecteurs (a 0,..., a m 1 ) et (b 0,..., b n 1 ) est le vecteur c = a b de longueur n + m dont le k-ème coefficient est : c k = a i b j (0 i < m, 0 j < n) i+j=k Le théorème de convolution dit que c = DF T 1 n+m(df T m+n (a) DF T n+m (b)), où les vecteurs a et b sont complétés avec des zéros jusqu à atteindre la taille n + m. 2 Réinventez la FFT vous-même Exercice 1 : Forme normale algébrique d une fonction booléenne. On s intéresse à une fonction booléenne f(x 1,..., x n ) : (F 2 ) n F 2. Cette fonction peut être représentée par sa table de vérité (c està-dire par la liste des 2 n valeurs qu elle prend successivement), ou bien comme un polynôme multivarié de degré au plus n sur F 2 [x 1,..., x n ]. On rappelle que sur le corps à deux éléments F 2, l addition est le XOR et la multiplication est le AND. Il s ensuit qu on a toujours x 2 = x, et qu on peut donc se restreindre à considérer des monômes sans carré. Plus précisément, on affirme (et on va justifier) que f s écrit : f(x 1,..., x n ) = g(a 1,..., a n ) x a1 1... xan n a (F 2) n où g(a) est le coefficient du monôme x a. Cette représentation est la forme normale algébrique (ANF) de f. Il s ensuit que g : (F 2 ) n F 2 est elle-même une fonction booléenne. Le but de l exercice est de construire un algorithme involutif (auto-inverse) qui calcule g à partir de f et réciproquement. Bien sûr, il sera rapide. 1. Exprimez g dans le cas facile où n = 1. Montrez que la procédure qui calcule g est involutive. 2. On cherche à écrire f sous la forme : f(x 1,..., x n ) = f 0 (x 1,..., x n 1 ) + x n f 1 (x 1,..., x n 1 ) Exprimez f 0 et f 1 en fonction de f, démontrant par là-même qu elles sont bien définies et uniques. 3. On considère les ANF g 0 et g 1 de f 0 et f 1 respectivement. Exprimez g en fonction de g 0 et g 1. Concluez que l ANF existe et est unique. 4. Déduisez-en un algorithme de calcul de g. Donnez sa complexité. 5. Cet algorithme permet en fait de calculer la table de vérité d un polynôme multivarié de F 2 [x 1,..., x n ]. Comparez sa complexité avec la procédure naïve qui consisterait à évaluer le polynôme 2 n fois. Solution de l exercice 1 1. Si n = 1, alors on cherche à écrire f sous la forme f(x 1 ) = g(1) x 1 + g(0). En fixant x 1 = 0, on trouve g(0) = f(0). Ensuite, en fixant x 1 = 1, on trouve g(1) = f(0) + f(1). Le caractère involutif de l opération est trivial. 1
2. De la même manière que précédemment, on a : f 0 (x 1,..., x n 1 ) = f(x 1,..., x n 1, 0), f 1 (x 1,..., x n 1 ) = f(x 1,..., x n 1, 0) + f(x 1,..., x n 1, 1). 3. Supposons que : f 0 (x 1,..., x n 1 ) = f 1 (x 1,..., x n 1 ) = g 0 (a 1,..., a n 1 ) x a1 a (F 2) n 1 g 1 (a 1,..., a n 1 ) x a1 a (F 2) n 1 Vu la définition de f 0 et f 1, on trouve f(x 1,..., x n ) = f 0 (x 1,..., x n 1 ) + x n f 1 (x 1,..., x n 1 ) f(x 1,..., x n ) = g 0 (a 1,..., a n 1 ) x a1 + g 1(a 1,..., a n 1 ) x a1 x n a (F 2) n 1 Et il résulte que : g(x 1,..., x n 1, 0) = g 0 (x 1,..., x n 1 ) g(x 1,..., x n 1, 1) = g 1 (x 1,..., x n 1 ) 4. On a donc quasiment abouti à un algorithme récursif pour calculer g à partir de f. En se débrouillant bien, on peut s en tirer en place, c est-à-dire avec O (1) d espace supplémentaire. Pour accomplir ceci, la fonction dont le pseudo-code suit suppose qu il existe un tableau A de 2 N booléen donné en argument, et que la table de vérité de la fonction booléenne f en n variable est donnée par A[start], A[start + 1],..., A[start + 2 n ]. Si A représente la table de vérité de f, il suffit de poser start = 0. On utilise la notation pour désigner le XOR, et + pour désigner l addition sur Z. 1: procedure ANF(A, n, start) 2: s 0 start 3: s 1 start + 2 n 1 4: for i = 0 to 2 n 1 do 5: A[s 1 + i] A[s 0 + i] A[s 1 + i] 6: f 0 est dans A[start... start + 2 n 1 1] 7: f 1 dans A[start + 2 n 1... start + 2 n 1] 8: ANF(A, n 1, s 0 ) 9: ANF(A, n 1, s 1 ) 10: end procedure La complexité du processus obéit à la récurrence habituelle T N = 2T N/2 + N (où N = 2 n ), et donc la complexité totale est n 2 n opérations. 3 Applications (presque) directes de la FFT Exercice 2 : filtrage. Un dispositif physique quelconque (un microphone, un oscilloscope,...) est utilisé pour acquérir un signal, qui constitue une suite de réels x 0,..., x n assez longue. Seulement, le dispositif n est pas de très bonne qualité et les échantillons contiennent du bruit. Une mesure rudimentaire pour retirer ce bruit consiste à appliquer un lissage Gaussien, c est-à-dire à remplacer chaque échantillon par une moyenne pondérée de ses voisins : y i = 1 Z k j= k x i+j e j2 où k est un paramètre de largeur, et où Z est un facteur de normalisation choisi convenablement. Evidemment, il y a un problème sur les bords (x 1 et x n+1 ne sont pas définis), mais on s en tire en disant qu on jette les k premières et les k dernières valeurs de y. 1. Montrez comment on peut calculer y en temps O (n log n). 2
Solution de l exercice 2 1. Le truc consiste à voir ça comme une convolution. En effet, si on pose le masque w j = e j2 /Z, alors très clairement k y i = x i+j w j j= k Changeons de variable pour enlever l indice négatif : y i = 2k j=0 x i+j k w j k Le problème c est que ceci ne se présente pas vraiment comme une convolution, vu que la somme des indices de x et w est i + 2j 2k. La feinte consiste à poser w (j) = w( j). On a alors : y i = 2k j=0 x i+j k w k j Déjà, ça semble mieux, vu que la somme des indices de x et w est constante. Les indices négatifs restent un peu embêtant cependant, mais on peut s en débarrasser complètement en posant w (j) = w(k j), pour j = 0,..., 2k. Et là, ça apparaît vraiment comme une convolution : y i = 2k j=0 x i+k j w j = u+v=i+k x u w v (0 u n, 0 v 2k) En d autre terme, le signal lissé est la convolution du signal original avec les masques pris à l envers. Pour que tout ceci ait un sens, il faut se restreindre à y k,..., y n k. Et la convolution peut se calculer avec 3 FFT en temps O (n log n). Exercice 3 : FFT et matrices structurées. Une matrice de Toeplitz est une matrice n n (a i,j ) telle que a i,j = a i 1,j 1 pour tout 2 i, j n. La matrice se décrit par un vecteur de taille 2n 1, et vérifie a i,j = t i j. Une matrice de Vandermonde est une matrice où a ij = t j i. n 1 t 0... t 0. V n = 1.............. n 1 t n t n t n t n 1... t 0. T n = t..... n+1......... t 2n... t n+1 t n 1. Montrer comment calculer le produit d une matrice de Toeplitz par un vecteur en temps O (n log n). 2. Montrez qu évaluer un polynôme sur les racines n-èmes de l unité revient à calculer un produit par une certaine matrice de Vandermonde, qu on appelle la matrice de Fourier. 3. On admet qu il existe un algorithme qui calcule P (x 0 ),..., P (x n ) en temps O ( n log 2 n ) étant donné les coefficients de P et les x i (l exercice 4 est consacré à ce problème). Montrer comment comment calculer le produit d une matrice de Vandermonde par un vecteur en temps O ( n log 2 n ). 4. On admet qu il existe un algorithme capable de déterminer les coefficients de l unique polynôme de degré n qui interpole n+1 points arbitraires en temps O ( n log 2 n ). Montrer comment résoudre le système linéaire V n u = v en temps O ( n log 2 n ). Solution de l exercice 3 1. Notons u = (u 0,..., u n ) le vecteur qu on veut multiplier, et notons v n le produit. Il n est pas extraordinairement difficile de voir que le produit est : ( n ) (v j ) = u i t j i i=0 j=n...2n Si on calcule la convolution z = t u, on trouve : z k = u i t j (0 k 3n) 0 i n 0 j 2n i+j=k 3
Il en découle que le produit v est formé de z n,..., z 2n. La convolution, elle, peut se calculer par la FFT. Il est possible qu il existe une technique plus efficace d un facteur constant, mais je ne la connais pas. 2. La k-ème coordonnée du produit de V n par un vecteur u est en fait : n u i t i k, i=0 c est-à-dire le polynôme de degré n décrit par u évalué au point t k. En fixant t k = e 2ikπ n, alors les coordonnées du produit décrivent les valeurs du polynômes sur les racines (n + 1)-èmes de l unité, et c est effectivement ce que la FFT calcule. 3. C est immédiat vu les questions précédentes. 4. Là aussi... Exercice 4 : Évaluation multipoint rapide. On démontre qu étant donné n points x 0,..., x n, on peut calculer A(x 0 ),..., A(x n 1 ) en temps O ( n log 2 n ), où A est un polynôme de degré n 1. L application directe de la FFT ne fonctionne que si les x i sont les racines n-èmes de l unité. 1. Démontrez que pour tout point z quelconque, A(z) = A(X) mod (X z). j On pose P ij (X) = (X x k ) et Q ij (X) = A(X) mod Q ij (X). k=i 2. Montrez qu on peut calculer les coefficients de P 0,n 1 en temps O ( n log 2 n ). 3. Démontrez que Q kk (X) = A(x k ) et que Q 0,n 1 (X) = A(X). 4. Démontrez que, pour i k j, on a Q ik (X) = Q ij (X) mod P ik (X) et Q kj (X) = Q ij mod P kj (X). 5. On admet qu il est possible de calculer R(X) mod S(X) en temps O (n log n), quand R et S sont deux polynômes de degré au plus n (c est l objet de l exercice 5). Donnez un algorithme de complexité O ( n log 2 n ) pour calculer P (x 0 ),..., P (x n 1 ). Solution de l exercice 4 1. On pose la division euclidienne de A par X z : A(X) = A(X) (X z) + α où α est une constante (un polynôme de degré 0). Alors, il est évident que A(z) = α, puisque X z s annule (indépendamment de Q). 2. Ce qu il ne faut PAS faire c est calculer successivement P 0,1, P 0,2,..., P 0,n 1, car cela prendrait O ( n 2 log n ) [n multiplications coûtant chacune n log n]. La bonne technique consiste à faire ça en arbre : 1: function TheProduct(i,j) 2: if i = j then return X x i 3: k (i + j)/2 4: return ThePRoduct(i, k) ThePRoduct(k + 1, j) 5: end function La complexité de cette procédure obéit à la récurrence T (n) = 2T (n/2) + O (n log n). Je vous laisse vous convaincre que T (n) = O ( n log 2 n ). 3. Le fait que Q kk (X) = A(x k ) est une conséquence immédiate de la première question. Le fait que Q 0,n 1 = A découle de ce que que A est de degré n 1 tandis que Q 0,n 1 est de degré n. 4. On pose la division euclidienne de A par P ik et P ij : D où il résulte que : A = U 1 P ik + Q ik A = U 2 P ij + Q ij Q ik = U 2 P ij + Q ij U 1 P ik Or, il n échappera à personne, j espère, que P ik divise P ij. On peut donc écrire : ) Q ik = P ik (U 2 P k+1,j U 1 + Q ij D où le résultat annoncé : Q ik = Q ik mod P ik = Q ij mod P ik. L autre partie de la question est complètement symétrique. 4
5. La technique générale consiste à ramener le problème pour n points à deux problèmes à n/2 point en effectuant un calcul de coût O (n log n). L objectif est donc de calculer tous les Q kk,, pour 0 k < n. Ce que la question précédente nous apprend, c est qu on peut déduire Q kk de n importe quel Q ij avec i k j, par une suite de découpes successives (avec une division euclidienne à chaque fois). Au début, on connaît Q 0,n 1, dont on peut déduire tous les Q kk. L approche qu on va utiliser, la plus naturelle, va être de couper au milieu. On pose k = (n 1)/2 (partie entière sous-entendue), et on cherche à obtenir Q 0,k ainsi que Q k+1,n 1. Après, on pourra continuer récursivement sur ces deux polynômes séparément. Pour calculer Q 0,k et Q k+1,n 1, il faut les valeurs correspondantes des polynômes P. En fait, on peut les obtenir (toutes!) en calculant P 0,n 1 avec l algorithme donné ci-dessus, en temps O ( n log 2 n ), et en gardant les résultats intermédiaires. On peut ensuite continuer récursivement. Le précalcul (des P ij ) se fait en temps O ( n log 2 n ), et chaque appel récursif effectue deux divisions euclidiennes de complexité O (n log n). La complexité totale (sans compter le précalcul) obéit donc à la récurrence : T (n) = 2T (n/2) + O (n log n), et vous commencez à avoir l habitude. Exercice 5 : Division polynomiale rapide. On considère deux polynômes A(X) et B(X), de degrés m et n respectivement (m n), et donc on suppose que a m 1 0 et b n 1 0. On s intéresse à leur division euclidienne : A(X) = B(X) Q(X) + R(X), avec deg R(X) < n. (1) On construit un algorithme rapide qui, étant donné les coefficients de A et B produit ceux de Q et R. 1. Montrez qu il y a un moyen simple de calculer le quotient de la division de A(X) par B(X) quand R = 0. Pourquoi cela ne s étend-il pas au cas où le reste de la division est non-nul? 2. Soit P un polynôme de degré n. On pose rev(p, k) = X k P (1/X). Que peut-on dire de rev(p, n)? Comment recalculer P à partir de rev(p, k) si k n? 3. Démontrez que rev(a, m) rev(b, n) rev(q, m n) mod X m n+1. Pour calculer Q, on va argumenter que rev(b, n) est inversible, en un certain sens. On se place dans l anneau K[[X]] des séries formelles sur K, c est-à-dire des polynômes a i X i de degré infini, sans chercher à tenir compte des problèmes de convergence. Les polynômes ordinaires sont en particulier des séries formelles. Pour calculer avec des séries formelles, on construit des algorithmes en-ligne, c est-à-dire des algorithmes qui lisent une quantité finie de coefficients des séries en entrée, et qui produisent le N-ème coefficient de la série de sortie après une quantité de calculs finie. Une autre manière de voir ça consiste à dire que ces algorithmes travaillent modulo X N, pour une certaine borne N. 4. Démontrez qu il existe des algorithmes en-ligne pour l addition et la multiplication des séries formelles. Certaines séries formelles possèdent un inverse. Par exemple, l inverse de 1 + X est i 0 ( X)i. Cela signifie que l algorithme en-ligne qui calcule le produit d une série formelle et de son inverse (lorsque celui-ci existe) va produire 1,0,0,... quel que soit le nombre de termes supplémentaires demandé. 5. Démontrez que les séries formelles de la forme a + X S(X) sont inversibles, si a 0 et S(X) est une série formelle quelconque. Déduisez-en que rev(b, n) admet un inverse. 6. Donnez un algorithme en-ligne qui calcule l inverse d une série formelle, et donnez sa complexité. 7. On considère donc la série formelle rev(b, n) 1. Il est clair que rev(q, m n) = ( rev(a, m) mod X n+1) rev(b, n) 1 Combien de termes de rev(b, n) 1 sont-ils nécessaires pour déterminer entièrement Q? 8. Concluez. Solution de l exercice 5 1. Si A est un multiple de B, alors la fonction z A(z)/B(z) est un polynôme de degré m n. On peut calculer ses coefficients : a) évaluer A et B sur les racines de l unité, b) diviser les valeurs prises par A sur les racines de l unité par celles prises par B, c) interpoler le quotient sur les racines. La première et la troisième étape se font avec la FFT en temps O (n log n), et la deuxième étape est linéaire. Le problème quand le reste n est pas nulle c est que la fonction z A(z)/B(z) n a aucune raison d être un polynôme de degré m n (voire même, selon le corps sur lequel on travaille, d être un polynôme tout court). 5
2. On pose P (X) = n i=0 a ix i. Alors, on trouve : rev(p, n) = X n P (1/X) = n a i X n i = a 0 X n + a 1 X n 1 + + a n i=0 Ca mets à l envers les coefficients. Évidement, c est une involution (il suffit de recommencer pour retomber sur le point de départ). 3. On part de l équation (1), on pose X = 1/Z et on multiplie des deux côtés par Z m. On trouve : Z m A(1/Z) = Z m B(1/Z) Z m Q(1/Z) + Z m R(1/Z) rev(a, m) = rev(b, n) rev(q, m n) + Z m n+1 rev(r, n 1) Prendre le reste dans la division par Z m n+1 va tuer le dernier terme. Il découle que : rev(a, m) mod Z m n+1 = rev(b, n) rev(q, m n) mod Z m n+1 4. L addition de séries formelle est très facile. Pour produire le N-ème terme de la somme, il suffit de calculer la somme des N-èmes termes des deux séries à sommer. Calculer le produit peut se faire en regardant les deux séries modulo X N (c est-à-dire en les tronquant à N termes), puis en les considérant comme des polynômes normaux et en calculant leur produit. 5. 6
4 Solutions 7