Université Louis Pasteur
Strasbourg

U.F.R. de Mathématiques et d’Informatique

 

Mémoire de Maîtrise de Mathématiques Pures

 

Algorithme LLL

 

présenté par


Sébastien DIEUDONNÉ
et
Jean-Sébastien GOETSCHY

 

Direction du mémoire : M. Raymond SEROUL

 

 

Année 1997

 

  1. Remerciements
  2. Nous tenons à remercier tout particulièrement M. Raymond Seroul, qui a suivit l’élaboration de ce mémoire.

    Nous remercions également le personnel de la bibliothèque de l’Institut de Mathématiques de Strasbourg.

    Egalement, les salles C12, C15 du même Institut de Mathématiques dont les tableaux nous ont souvent éclairés !

  3. Sommaire
  4. Remerciements *

    Sommaire *

    Notations, Conventions *

    Introduction *

    I. Méthode de travail *

    II. Conventions *

    III. Langages utilisés *

    IV. Plan *

    Première Partie : Algèbre Linéaire *

    I. Bases Mathématiques *

    A. Introduction *

    B. Représentation matricielle *

    II. Algorithmes classiques *

    A. Introduction *

    B. Pivot de Gauss / Résolution de systèmes linéaires *

    C. Déterminant *

    D. Noyau et image *

    Deuxième Partie : Le vif du sujet *

    I. Contexte théorique *

    A. Matrices à coefficients entiers *

    B. Modules *

    1. Z-Modules *

    2. Z-Modules libres de rang fini *

    C. Algèbre bilinéaire *

    1. Forme bilinéaire, forme quadratique *

    2. Représentation matricielle *

    D. Réseaux *

    II. Algorithmes élémentaires *

    A. Forme Normale d’Hermite *

    B. Procédé d’orthogonalisation de Gram-Schmidt *

    III. Algorithme LLL *

    A. Réduction de réseaux *

    1. Algorithme LLL original *

    2. Algorithme LLL avec insertions profondes *

    3. Algorithme LLL intégral *

    B. Algorithme MLLL pour des vecteurs dépendants *

    Troisième Partie : Applications *

    I. Dépendance linéaire *

    II. Recherche de petits vecteurs d’un réseau *

    A. Recherche de petits vecteurs de n *

    B. Algorithme de Cholesky *

    C. Recherche de petits vecteurs d’un réseau *

    Conclusion *

    Bibliographie *

    Résumé *

    I. Mots Clefs *

    II. Condensé *

     

  5. Notations, Conventions

  1. Introduction
  2. Le travail que nous proposons est une étude détaillée de l’algorithme de réduction des réseaux proposé par A.K. Lenstra, H.W. Lenstra et L. Lovacz en 1982. Cette étude est essentiellement basée sur l’ouvrage de H. Cohen qui rassemble de nombreux algorithmes mathématiques.

    1. Méthode de travail
    2. La méthode de travail utilisée consiste en une description théorique des problèmes et objets, puis une mise en pratique au niveau algorithmique et programmation. La partie théorique tentera de pas être trop exhaustive : il n’est pas ici question d’un cours d’algèbre général. Quant à la partie pratique, elle se veut la plus claire et la plus simple possible.

    3. Conventions
    4. Les conventions et notations adoptées dans ce mémoire sont énumérées au fil du besoin, outre les signifiants relevés plus haut dans le lexique.

    5. Langages utilisés
    6. Le choix d’un langage de programmation des algorithmes est un problème délicat. Nous avons décidé de retenir le langage Pascal de par son universalité dans le milieu mathématique. La programmation restera simple, voire simpliste dans la plupart des cas. Il ne s’agit pas ici d’un mémoire d’informatique, mais de mathématiques.

      Ce choix se justifie également en opposition à celui de H. Cohen : celui-ci implémente en effet ses algorithmes en GP (programme de calcul), ce qui le conduit à une description " logique " (à la Knuth), faite de renvois enchevêtrés et inextricables. La lisibilité informatique de ces algorithmes s’avère très délicate.

      Pour des raisons de confort de programmation, les premiers tests sont faits avec Mathematica.

    7. Plan

    Le travail se décompose en trois grands axes. Dans un premier temps, nous donnerons quelques rappels d’algèbre linéaire : les bases théoriques nécessaires à une bonne compréhension du problème et quelques algorithmes classiques.

    Par la suite, nous entrerons dans le vif du sujet : la théorie, essentiellement algébrique, et la mise en pratique de quelques algorithmes qui servirons de base par la suite et une étude plus détaillée des algorithmes LLL.

    Enfin, nous envisagerons deux applications parmi les plus importantes de cet algorithme.

  3. Première Partie : Algèbre Linéaire
    1. Bases Mathématiques
      1. Introduction
      2. Nous aurons ici besoin des notions de corps, d’espace vectoriels et de base. Nous rappelons a ce propos, que tout espace vectoriel admet une base. Nous travaillerons exclusivement avec des espaces vectoriels de dimension finie.

        Nous nous intéresserons également à la structure d’espace euclidien, c’est-à-dire, d’espace vectoriel muni d’un produit scalaire. La plupart du temps, nous considérerons des espaces réels muni du produit scalaire usuel, bien que cette théorie s’étende à des espaces plus généraux.

      3. Représentation matricielle

      Un K espace vectoriel V étant un objet abstrait, on le modélise par la donnée d’une base sous forme de matrice à coefficients dans K. On peut alors également représenter un sous-espace (sous-ensemble stable) W de V par une matrice.

      Une fonction linéaire f d’un espace vectoriel V dans un espace vectoriel W est représentée par la donnée d’une matrice A dont les colonnes représentent les coordonnées des images des vecteurs de base de V dans W.

      Dans la pratique, nous ne manipulerons donc que des matrices, mais il ne faudra pas perdre de vue l’interprétation des calculs effectués.

      On notera M(V) la matrice représentant V dans la base canonique, Mn,m(K) l’ensemble des matrices n ´ m à coefficients dans K et GL(n,K) l’ensemble des matrices à coefficients dans K carrées de dimension n inversibles.

    2. Algorithmes classiques
      1. Introduction
      2. Les quelques algorithmes qui suivent donnent des outils de base sur les objets introduits plus haut.

      3. Pivot de Gauss / Résolution de systèmes linéaires
      4. On cherche à résoudre le problème :

        trouver x tel que Ax = b où A Î GL(n,K), x et b sont deux vecteurs colonnes.

        On recherche dans la première colonne un " pivot " non nul. On échange les lignes pour faire venir le pivot en première position et on normalise la ligne. Par combinaisons linéaires, on annule les coefficients de la ligne autres que le pivot qui vaut alors 1. On effectue les opérations simultanément sur une matrice identité. Et on passe à la ligne suivante. Finalement, on aura par des opérations élémentaires transformé la matrice A en identité et la matrice identité de départ en A-1. Ainsi, on a x = A-1.b .

        Ce qui donne un code pascal semblable à ce qui suit. Les fonctions asinitrotantes ne figurent pas ici.

         

        Function FirstPivot(Var A : Matrix; dA : Dimension; j : Byte) : Byte;
        (***********************************************************************)
        (* Cherche le 1er pivot dans la colonne j, renvoie 0 si il n'y en a pas *)
        (***********************************************************************)
        Var
        k,FP : Byte;
        Begin
        FP:=0;
        k:=j;
        While (FP=0) And (k<=dA) Do
        If A[k,j]<>0
        Then FP:=k
        Else k:=k+1;
        FirstPivot:=FP;
        End;
         
        Procedure Gauss(A : Matrix; dA : Dimension;
        Var InvA : Matrix; Var Inversible : Boolean);
        (***********************************************************************)
        (* Inverse la matrice A dans InvA. Inversible est True si A inversible *)
        (***********************************************************************)
        Const
        Introuvable = 0;
        Var
        j,LignePivot : Byte;
         
        Procedure WorkLine(i,j : Byte; Var A,InvA : Matrix; dA : Dimension);
        (*****************************)
        (* Travaille avec la ligne j *)
        (*****************************)
        Var
        Coef : Real;
         
        Procedure DoTheWash(c : Byte; Var A, InvA : Matrix; dA : Dimension);
        (************************************************)
        (* Elimine les coef de la colonne c sauf A[c,c] *)
        (************************************************)
        Var
        k : Byte;
        Coef : Real;
        Begin
        For k:=1 To dA Do
        If k<>c
        Then
        Begin
        Coef:=-A[k,c];
        LinearCombination(c,k,A,dA,Coef);
        LinearCombination(c,k,InvA,dA,Coef);
        End;
        End;
         
        Begin
        If i<>j
        Then
        Begin
        SwapLines(i,j,A,dA);
        SwapLines(i,j,InvA,dA);
        End;
        Coef:=1/A[j,j];
        ScalarLine(j,A,dA,Coef);
        ScalarLine(j,InvA,dA,Coef);
        DoTheWash(j,A,InvA,dA);
        End;
         
        Begin
        UnitMatrix(InvA,dA);
        j:=1;
        Inversible:=True;
        While Inversible And (j<=dA) Do
        Begin
        LignePivot:=FirstPivot(A,dA,j);
        If LignePivot=Introuvable
        Then Inversible:=False
        Else
        Begin
        WorkLine(LignePivot,j,A,InvA,dA);
        j:=j+1;
        End;
        End;
        End;

      5. Déterminant
      6. On peut toujours rendre triangulaire supérieure, une matrice A à coefficients dans un corps, par la méthode Gauss. Le déterminant est alors le produit des éléments diagonaux au signe près (on multiplie par –1 à chaque échange de colonnes).

      7. Noyau et image

    Etant donnée une matrice A, on définit son noyau par la donnée des vecteurs x tels que Ax=0.

    L’image est le supplémentaire du noyau dans l’espace (en dimension finie, toujours…).

  4. Deuxième Partie : Le vif du sujet
    1. Contexte théorique
      1. Matrices à coefficients entiers
      2. On note GL(n, Z) l’ensemble des matrices inversibles à coefficients entiers

        Théorème : GL(n, Z) = {A Î Mn,n(Z), Det(A)= ±1}

        Démonstration : On a A.A-1=1

        Comme la fonction Det est un morphisme, on a :

        Det(A.A-1)=Det(1)

        Û Det(A).Det(A-1)=1

        Û Det(A)=Det(A-1)-1

        Or, les seuls éléments inversibles de Z sont 1 et –1. þ

      3. Modules
        1. Z-Modules
        2. On appelle Z-Module de rang fini un groupe abélien isomorphe à un produit de quotients Z/niZ et de Zn.

        3. Z-Modules libres de rang fini

        On appelle Z-Module libre de rang fini n un groupe abélien isomorphe à Zn.

        On représente un Z-Module par la matrice de représentation d’une base dans la base canonique. On voudrait alors définir les mêmes notions que pour les corps : inversion, noyau, etc.

      4. Algèbre bilinéaire
        1. Forme bilinéaire, forme quadratique
        2. Définition : Une forme bilinéaire b est une application de V dans K, où V est un espace vectoriel de dimension 2, linéaire en les deux variables.

          Définition : Soit K un corps de caractéristique différente de 2, et soit V en K-espace vectoriel. On dit qu’un application q de V dans K est une forme quadratique si elle satisfait les conditions suivantes :

          " l Î K, " x Î V, q(l x)=l 2q(x)

          En posant b(x,y)= (q(x+y)-q(x)-q(y)) alors b est une forme bilinéaire (symétrique).

          On a alors q(x)=b(x,x).

          Remarque : Si K= , on dit que q est définie positive (strictement) si " x Î V, q(x)>0.

        3. Représentation matricielle

        On représente une forme bilinéaire par la donnée de la matrice b(ei,ej) où (ei)iÎ   une base de V.

      5. Réseaux

      On appellera réseau, un -module libre de rang fini muni d’une forme quadratique définie positive.

      Un cas particulier est de prendre un produit scalaire pour forme bilinéaire et donc la norme associée pour forme quadratique. C’est dans ce cadre essentiellement que nous poursuivrons.

    2. Algorithmes élémentaires
      1. Forme Normale d’Hermite
      2. Définition : on dit qu’une matrice M est en Forme Normal d’Hermite (ou HNF pour Hermite Normal Form) si elle est de la forme :

        Théorème : Soit A Î Mn,m(). Il existe une unique matrice H = (bi,j) Î Mn,m() en HNF telle que H = AU où U Î GL(n,).

        Remarque : U n’est pas forcément unique.

      3. Procédé d’orthogonalisation de Gram-Schmidt

      Théorème (Gram-Schmidt) : Un espace vectoriel euclidien admet une base orthogonale.

      Démonstration : On définit par récurrence la nouvelle base , avec les notations usuelles.

      La nouvelle base ainsi définie est trivialement orthogonale. þ

    3. Algorithme LLL
      1. Réduction de réseaux
      2. Il est évident que l’algorithme de Gram-Schmidt ne peut se généraliser aux -modules à cause de la division : on ne retombe généralement pas sur un point du réseau… Cependant, on peut espérer approcher une base qui soit le plus orthogonale possible, en un sens qu’il reste définir. C’est cette définition et un algorithme pour trouver cette base qui font l’objet central de ce mémoire.

        Définition : En gardant les notation plus haut, une base b1, b2, …, bn d’un réseau est dite LLL-réduite si :

        ½ m i,j ½   " 1 j < i n

        et b  + m i,i-12   b  2 " 1 < i n

        Remarque : la deuxième inégalité est équivalente à b 2 ( -m  )b  2

        Cette inégalité est appelée condition de Lovasz.

        1. Algorithme LLL original
        2. Une version Pascal de l’algorithme mettant en œuvre cette réduction est proposée ici.

          On suppose que (bk) est une base. On procède alors par récurrence : on suppose que les k-1 premiers vecteurs sont déjà LLL-réduits. On peut initialiser cette récurrence pour k=2. On cherche maintenant à réduire le k-ième vecteur, de sorte que ½ m i,j ½   "  1 j < i n. Ceci peut être fait en remplaçants bk par , aj Î  : on suppose ½ m i,j ½   "  l j <k (vrai pour l=k). En posant alors q comme l’arrondi de m k,l, bk=bk-q.bl, m k,j n’est pas modifié pour j>l (car b  est orthogonal à bl pour l<j). On remplace alors m k,l par m k,l-q et ½ m k,l-q½  . On a alors ½ m k,j½   pour l-1<j<k.

          Maintenant que la réduction a été effectuée, il faut aussi que bk vérifie la condition de Lovasz. Si (par miracle !) bk satisfaisait cette condition, on passe au vecteur suivant, s’il existe. Sinon, on échange les vecteurs bk et bk-1 et on décrémente k, considérant que seuls les k-2 premiers vecteurs sont LLL-réduits.

          Pour le calcul des coefficients de Gram (m i,j), la solution retenue est un calcul au fur et à mesure que les coefficients sont nécessaires.

          Remarques :

          ü l’échange des vecteurs bk et bk-1 induit des changements sur les coefficients de Gram.

          ü On calcule tout au long de l’algorithme la matrice de passage H.

          Ceci donne l’algorithme qui suit

          Procedure BasisLLL(b_in : Vector; Var b_out : Vector; Var H : Matrix);
          k, kmax : Integer;
          B : Vector;
          Lovasz : Boolean;
          Begin
          (* Begin of Reduction *)
          (* Variables Initialization *)
          k:=2;
          kmax:=1;
          SetVectors(b_out[1], b_int[1]);
          B[1]:=Dot(b_in[1], b_in[1]);
          IdentityMatrix(H, n);
          (* Main Loop *)
          Repeat
          If k>kmax Then Gram(k, kmax);
          (* Lovasz's Loop *)
          Repeat
          Red(k, k-1);
          Lovasz:=B[k]>=(0.75-Mu[k,k-1]^2)*B[k-1];
          If Not Lovasz
          Then Begin
          Swap(k);
          k:=max(2, k-1);
          End;
          Until Lovasz;
          (* End Lovasz's Loop *)
          For l:=k-2 DownTo 1 Do Red (k,l)
          k:=k+1;
          Until k>n;
          (* End Main Loop *)
          (* End of Reduction *)
          End;

          Procedure Red(k, l : Integer);
          Var i, q : Integer;
          Begin
          If Mu[k,l]>0.5 Then
          Begin
          q:=Round(Mu[k,l]);
          "b_in[k]:=b_in[k]-q*b_in[l]";
          "Hk:=Hk-q*Hl"; (* Hk est la K-ieme colonne de H *)
          Mu[k,l]:=Mu[k,l]-q;
          For i:=1 To n-1 Do
          Mu[k,i]:=Mu[k,i]-q*Mu[l,i];
          End;
          End;

          Procedure Swap(k : Integer);
          Var i,j : Integer;
          BT, Temp, Mu : Real;
          Begin
          ExchangeVectors(b_in[k],b_in[k-1]);
          ExchangeMatrixCol(H, k, k-1);
          If k>2 Then
          For j:=1 To k-2 Do
          Begin
          Temp:=Mu[k,j];
          Mu[k,j]:=Mu[k-1,j];
          Mu[k-1,j]:=Temp;
          End;
          Mu:=Mu[k,k-1];
          BT:=B[k]+Mu^2*B[k-1];
          Mu[k,k-1]:=Mu*B[k-1]/BT;
          B[k]:=B[k-1]*B[k]/BT;
          B[k-1]:=BT;
          For i:=k+1 To kmax Do
          Begin
          Temp:=Mu[i,k];
          Mu[i,k]:=Mu[i,k-1]-Mu*Temp;
          Mu[i,k-1]:=Temp+Mu[k,k-1]*Mu[i,k];
          End;
          End;

          Détails :

          La procédure Red : Si m k,l 0,5 , bk est déjà de norme minimale. Sinon, on va soustraire le multiple maximum de bl pour obtenir un m k,l 0,5. On fait les mêmes opérations sur H et il faut rectifier les m k,i pour i<l.

          La procédure Swap : En changeant les vecteurs bk et bk-1 (les colonnes k et k-1 de H), il faut modifier les relations de Gram-Schmidt. Pour j<k-2, il suffit d’échanger m k,j avec m k-1,j. Pour m k,k-1, …m k,kmax, il faut inverser le système :

          pour k-1 l kmax. (ce qui induit des changements sur Bk).

          C’est-à-dire, en échangeant bk et bk-1 dans ce système.

          Ce qui donne le code optimisé plus haut.

          Remarques :

          ü On peut modifier l’algorithme pour récupérer uniquement la base ou la matrice H.

          ü Cet algorithme faisant intervenir des quantités réelles, dans la pratique, il se peut que le résultat ne soit pas LLL-réduit, mais en général, ce sera le cas. On pourra se référer à l’algorithme LLL intégral plus loin pour contourner cette difficulté.

          Preuve de l’algorithme : On suppose pour la preuve les b  initialisés aux bj. Il est alors clair que (b ) est une base du réseau, tout au long de l’algorithme.

          Soit et . Il est évident que D est à valeurs entières.

          L’unique partie de l’algorithme ou les Bj sont modifiés (et donc D) est le sous-algorithme SWAP dans lequel on modifie un seul Bk que l’on diminue au moins d’un facteur   par la condition de Lovasz. Donc D est diminuée d’un facteur   également et reste bien entendu à valeurs entières (les Bj sont toujours des normes au carré de vecteurs à coordonnées entières). Ceci montre que la boucle centrale mettant en jeu l’algorithme SWAP est finie. Comme c’est le seul endroit où k est decrémenté, on a montré que l’algorithme se termine. Il est évident que la base obtenue est LLL-réduite.

          þ

        3. Algorithme LLL avec insertions profondes
        4. A la place d’échanger simplement bk et bk-1, on peut directement échanger bk avec bi, i<k tel que : . Ceci donne alors l’algorithme schématique qui suit, dont nous ne donnerons pas d’équivalent Pascal (il ne nous sera pas utile par la suite).

        5. Algorithme LLL intégral

        Le but de cet algorithme est de proposer une version de l’algotihme LLL original ne faisant intervenir que des calculs sur entiers, ce qui garantit la stabilité de l’algorithme.

        Théorème et Corollaire :

        On suppose que la matrice de Gram (<bi,bj>) est à coefficients entiers (c’est le cas ici).

        Soit di=det(<br, bs> 1 r, s i) = B1…Bi

        Alors pour tout i fixé et pour tout j < i, on a :

        di-1Bi Î ,

        dim i,j Î ,

        pour tout m tel que j < m i, Î .

        Soit l i,j = dj m i,j pour j < i et l i,i=di. Alors pour j i fixé, on a :

        Alors uk Î et uj-1=l i,j.

        Preuve : cf. Ouvrage H. Cohen p. 91-92.

        Avec ces notations, on aboutit à l’algorithme suivant :

        Procedure IntegralLLL(b_in : Vector; Var b_out : Vector; Var H : Matrix);
        Var k, kmax, l : Integer;
        Lovasz : Boolean;

        Begin
        (* Begin Of Reduction *)
        (* Gram-Schmidt(b_in, b_out, H); *)
        (* ou H=IdentityMatrix(n); b_our:=b_in; *)
        (* Variables Initialization *)
        k:=2; kmax:=1;
        B[0]:=1;
        d[1]:=Dot(b_out[1],b_out[1]);
        (* Main Loop *)
        Repeat
        If k>kmax Then
        IntegralGram(k, kmax);
        (* Lovasz's Loop *)
        Repeat
        RedI(k, k-1);
        Lovasz:=d[k]*d[k-2]>=(0.75*d[k]^2-Lambda[k,k-1]^2);
        If Not Lovasz Then
        Begin
        SwapI(k);
        k:=Max(2,k-1);
        End;
        Until Lovasz;
        (* End Of Lovasz's Loop *)
        For l:=k-2 DownTo> 1 Do
        RedI(k,l);
        k:=k+1;
        Until k>n;
        End;

        Procedure RedI(k, l : Integer);
        Var i,q : Integer;
        Begin
        If Abs(2*Lambda[k,l]>d[l]) Then
        Begin
        q:=Round(Lambda[k,l]/d[l]);
        (* Hk:=Hk-q*Hl; *)
        Lambda[k,l]:=Lambda[k,l]-q*d[l];
        For i:=1 To l-1 Do
        Lambda[k,i]:=Lambda[k,i]-q*Lambda[l,i];
        End;
        End;

        Procedure SwapI(k : Integer);
        Var i, j, Temp, LambdaT, BT : Integer;
        Begin
        ExchangeMatrixCol(H, k, k-1);
        If k>2 Then
        For j:=1 To k-2 Do
        Begin
        Temp:=Lambda[k,j];
        Lambda[k,j]:=Lambda[k-1,j];
        Lambda[k-1,j]:=Temp;
        End;
        LambdaT:=Lambda[k,k-1];
        BT:=(d[k-2]*d[k]+LambdaT^2)/d[k-1];
        For i:=k+1 To kmax Then
        Begin
        Temp:=Lambda[i,k];
        Lambda[i,k]:=(d[k]*Lambda[i,k-1]-LambdaT*Temp)/d[k-1];
        Lambda[i,k-1]:=Temp+LamdaT*Lambda[i,k]/BT;
        End;
        d[k-1]:=BT;
        End;

        Procedure IntegralGram(k : Integer; Var kmax : Integer);
        Var i,j : Integer;
        u : Integer;
        Begin
        kmax:=k;
        For j:=1 To k Do
        Begin
        u:=Dot(b_in[k],b_in[j]);
        For i:=1 To j-1 Do
        u:=(d[i]*u-Lambda[k,i]*Lambda[j,i])/d[i-1];
        If j<k Then Lambda[k,j]:=u;
        If j=k Then d[k]:=u;
        End;
        If d[k]=0 Then
        Begin
        Writeln('Les b_in ne forment pas une base.');
        Halt(0);
        End;
        End;

        Cet algorithme n’appelle pas de commentaire particulier. Sa preuve est identique à celle du précédent.

      3. Algorithme MLLL pour des vecteurs dépendants

    On peut légèrement modifier l’algorithme LLL pour que celui-ci fonctionne avec une famille de vecteurs ne formant pas nécessairement une base. L’algorithme devra à ce moment renvoyer la base LLL-réduite formée de p vecteurs indépendants et la matrice de passage, dont les n-p premières colonnes donnerons les relations entre les vecteurs, i.e. des vecteurs v tels que <v,bi> = 0.

    Ceci donne l’algorithme qui suit, très voisin du premier algorithme auquel on pourra se référer pour certains détails.

    Procedure MLLL(b_in : Vector; Var b_out : Vector; Var H : Matrix);
    Var k, kmax : Integer;
    B : Vector;
    Lovasz : Boolean;
    Begin
    (* Begin of Reduction *)
    (* Variables Initialization *)
    k:=2;
    kmax:=1;
    SetVecTors(b_out[1], b_int[1]);
    B[1]:=Dot(b_in[1], b_in[1]);
    IdentityMatrix(H, n);
    (* Main Loop *)
    Repeat
    If k>kmax Then GramM(k, kmax);
    (* Lovasz's Loop *)
    Repeat
    Red(k, k-1);
    Lovasz:=B[k]>=(0.75-Mu[k,k-1]^2)*B[k-1];
    If Not Lovasz
    Then Begin
    SwapG(k);
    k:=max(2, k-1);
    End;
    Until Lovasz;
    (* End Lovasz's Loop *)
    For l:=k-2 DownTo 1 Do Red (k,l)
    k:=k+1;
    Until k>n;
    (* End Main Loop *)
    (* End of Reduction *)
    End;

    Procedure SwapG(k : Integer);
    Var i,j : Integer;
    BT, Temp, Mu : Real;
    Begin
    ExchangeVectors(b_in[k],b_in[k-1]);
    ExchangeMatrixCol(H, k, k-1);
    If k>2 Then
    For j:=1 To k-2 Do
    Begin
    Temp:=Mu[k,j];
    Mu[k,j]:=Mu[k-1,j];
    Mu[k-1,j]:=Temp;
    End;
    Mu:=Mu[k,k-1];
    BT:=B[k]+Mu^2*B[k-1];
    If BT=0 Then
    Begin
    Temp:=B[k];
    B[k]:=B[k-1];
    B[k-1]:=Temp;
    For i:=k+1 To kmax Do
    Begin
    Temp:=Mu[i,k];
    Mu[i,k]:=Mu[i,k-1];
    Mu[i,k-1]:=Temp;
    End;
    End;
    If (B[k]=0) And (Mu<>0)
    Then Begin
    B[k-1]:=BT;
    Mu[k,k-1]:=1/Mu;
    For i:=k+1 To kmax Do Mu[i,k-1]:=Mu[i,k-1]/Mu;
    End;
    If B[k]<>0
    Then Begin
    Temp:=B[k-1]/BT;
    Mu[k,k-1]:=Mu*Temp;
    B[k]:=B[k]*Temp;
    B[k-1]:=BT;
    For i:=k+1 To kmax Do
    Begin
    Temp:=Mu[i,k];
    Mu[i,k]:=Mu[i,k-1]-Mu*Temp;
    Mu[i,k-1]:=Temp+Mu[k,k-1]*Mu[i,k];
    End;
    End;
    End;

    Procedure GramM(k : Integer; Var kmax : Integer);
    Var i,j : Integer;
    Begin
    kmax:=k;
    For j:=1 To k-1 Do
    Begin
    If B[j]<>0
    Then Mu[k,j]:=Dot(b_in[k],b_in[j])/B[j];
    Else Mu[k,j]:=0;
    End;
    For l:=1 To n Do b_out[k,l]:=b_in[k,l];
    For j:=1 To k-1 Do
    For l:=1 To n Do
    b_out[k,l]:=b_out[k,l]-Mu[k,j]*b_out[j,l];
    Bk:=Dot(b_out[k],b_out[k]);
    End;

    Les coefficients de Gram correspondant aux vecteurs nuls sont annulés. Les échanges conduisent à mettre les vecteurs nuls en première position.

  5. Troisième Partie : Applications
    1. Dépendance linéaire
    2. On cherche à découvrir une dépendance -linéaire entre les n nombres complexes (z1,… , zn), si il en existe une.

      Supposons tout d’abord que ces nombres soient réels. Pour un entier N assez grand, on considère la forme quadratique en les ai suivante :

      Cette forme est définie positive car elle est toujours positive (somme de carrés) et est nulles si et seulement si tous les carrés sont nuls, i.e. et donc a1 = 0 et a est nul. Q définit donc un produit scalaire euclidien sur  n si z1 ¹ 0.

      Soit a l’ordre des ai. On peut choisir a n < N < a 2n, par exemple : N = [a 1,5n].

      En petit vecteur pour Q vérifie alors : est petit ainsi que les ai pour i > 1. Si les zi sont effectivement -linéaire dépendants, alors on aura trouvé une relation si est nul.

      On va en fait appliquer l’algorithme LLL a la base canonique (ei) de n pour la forme quadratique Q. On a alors le lemme suivant :

      Lemme : Avec les notations introduites plus haut, si on exécute l’algorithme d’orthogonalisation de Gram-Schmidt (pour Q) sur la base (ei), on a :

      m i,1 = zi/z1, pour 2 i n

      m i,j = 0, pour 2 j < i n

      e  = ei - (zi/z1) e1

      B1 = Nz  et Bk = 1 pour 2 k n.

      Démonstration : soit b la forme bilinéaire définie par Q. On rappelle que

      b(x,y) =  (Q(x+y)-Q(x)-Q(y)) pour deux vecteurs x et y.

      soit k 2, on a :

      Or : Q(e1) = N z , Q(ek) = 1 + N z , Q(e1+ek) = 1 + N(z1+zk)2

      D’où : m k,1 = zk/z1.

      Soit 2 j < i n :

      Q(ei) = 1 + N z , Q(e ) = 1, Q(ei+e ) = 2 + N z 

      D’où m i,j = 0.

      B1 = Q(e1) = N z  et Bj = Q(e ) = 1. þ

       

      On peut facilement modifier ce procédé pour travailler avec des nombres complexes. Dans ce cas on prend la forme quadratique:

      Q est alors définie positive et définit un produit scalaire euclidien sur R2nn) si et seulement si z1/z2 Ï  . Si jamais z1/z2 est réel, on cherche un couple zi/zj qui n’est pas réel et on réordonne. Si il n’en existe pas, on utilise le processus pour les réels 1, z2/z1, …, zn/z1.

      On utilise l’algorithme LLL pour trouver la relation de dépendance entre les zi la plus " petite " possible, c’est-à-dire les coefficients ai les plus petits possibles.

      Ceci donne l’algorithme suivant :

      Procedure LinDep(z : TabComplex; BigN : Integer);
      Var b_in, b_out, B : Vector;
      k, kmax, i, j : Integer;
      H, Mu : Matrix;
      Begin
      IdentityMatrix(b_in);
      For i:=3 To n Do
      For j:=3 To i-1 Do
      Mu[i,j]:=0;
      B[1]:=Re(z[1])*Re(z[1])+Im(z[1])*Im(z[1]);
      B[2]:=Im(cprod(z[1],conj(z[2])));
      For i:=3 To n Do
      B[i]:=1;
      For i:=2 To n Do
      Mu[i,1]:=Re(cprod(z[1],conj(z[i])))/B[1];
      If B[2]<>0 Then
      Begin
      For i:=3 To n Do
      Mu[i,2]:=Im(cprod(z[1],conj(z[i])))/B[2];
      B[2]:=BigN*B[2]*B[2]/B[1];
      End
      Else Begin
      For i:=3 To n Do
      Mu[i,2]:=0;
      B[2]:=1;
      End;
      (* LLL *)
      SetVectors(b_out[1], b_int[1]);
      B[1]:=BigN*B[1];
      k:=2;
      kmax:=n;
      IdentityMatrix(H, n);
      Repeat
      Repeat
      Red(k, k-1);
      Lovasz:=B[k]>=(0.75-Mu[k,k-1]^2)*B[k-1];
      If Not Lovasz
      Then Begin
      Swap(k);
      k:=max(2, k-1);
      End;
      Until Lovasz;
      For l:=k-2 DownTo 1 Do Red (k,l)
      k:=k+1;
      Until k>n;
      (* End of LLL *)
      Output(b_out, z);
      End;

      Remarque :

      ü On n’a pas besoin ici de Gram, puisqu’on l’effectue d’un seul tenant au début de la procédure.

    3. Recherche de petits vecteurs d’un réseau
    4. On veut trouver les petits vecteurs d’un réseau, c’est-à-dire les vecteurs x tels que Q(x) C, où C est une constante positive entière et Q est la forme quadratique du réseau. On va résoudre ce problème en trois temps : grâce à l’algorithme LLL, on va se placer dans une base plus " sympathique ", chercher dans celle-ci les petits vecteurs et redonner les solutions dans la base originale. On a donc besoin de deux outils : l’un qui sache chercher les petits vecteurs de n et l’autre qui sache transformer la matrice associée à la forme quadratique sous une forme adéquate : c’est l’algorithme classique de Cholesky.

      1. Recherche de petits vecteurs de n
      2. Le but est de trouver tous les vecteurs x non nuls de n vérifiant Q(x) C, où C est une constante positive entière et Q est une forme quadratique du type :

        On va choisir (arbitrairement) une coordonnée du vecteur et lui affecter la plus grande valeur possible. On va ensuite la décrémenter et incrémenter successivement les coordonnées suivantes. C’est cette idée intuitive que l’on va formaliser…

        On va choisir et ensuite , et ainsi de suite jusqu’à obtenir le vecteur. On décrémente ensuite xn et on recommence. Jusqu’à avoir le vecteur nul…

        Ceci donne l’algorithme pascal suivant (complet) :

        Program ShortVectors;
        Uses WinCrt;
        Const n=5;
        Type Vecteur = Array[1..n] of Integer;
        Var
        C,i,j : Integer;
        q : Array[1..n,1..n] Of Integer;
        Function IsNul(x : Vecteur) : boolean;
        Var i : Integer;
        IsN : Boolean;
        Begin
        IsN:=True;
        For i:=1 To n Do
        If x[i]<>0 Then IsN:=False;
        IsNul:=IsN;
        End;

        Procedure SV(C : Integer);
        Var i,j : Integer;
        count : Integer;
        Z : Real;
        T,L,x,U : Vecteur;
        NewBounds : Boolean;
        Begin
        Count:=0;
        i:=n;
        T[i]:=C;
        U[i]:=0;
        NewBounds:=True;
        Repeat
        If NewBounds Then
        Begin
        Z:=Sqrt(T[i]/q[i,i]);
        L[i]:=Trunc(Z-U[i]);
        x[i]:=Trunc(-Z-U[i])-1;
        End;
        Repeat x[i]:=x[i]+1;
        i:=i+1;
        Until x[i-1]<=L[i-1];
        i:=i-1;
        If i>1 Then
        Begin
        T[i-1]:=T[i]-q[i,i]*(x[i]+U[i])*(x[i]+U[i]);
        i:=i-1;
        U[i]:=0;
        For j:=i+1 To n Do U[i]:=U[i]+q[i,j]*x[j];
        NewBounds:=True;
        End
        Else
        If Not IsNul(x) Then
        Begin
        Count:=Count+2;
        Write('x = (');
        For j:=1 To n-1 Do Write(x[j],', ');
        Writeln(x[n],')');
        Write('-x = (');
        For j:=1 To n-1 Do Write(-x[j],', ');
        Writeln(-x[n],')');
        Writeln('Q(x) = ',C-T[1]+q[1,1]*(x[1]+U[1])*(x[1]+U[1]));
        Writeln;
        NewBounds:=False;
        End;
        Until IsNul(x);
        Writeln('Nb de vecteurs trouves : ',Count);
        End;

        Begin
        For i:=1 To n Do
        For j:=1 To n Do
        If i=j Then q[i,j]:=1 Else q[i,j]:=0;
        C:=7;
        InitWinCrt;
        SV(C);
        Writeln('Appuyez sur Return...');
        Readln;
        DoneWinCrt;
        End.

         

        La preuve de cet algorithme est triviale : si celui-ci ce termine, par les calculs effectués, on est assuré que les vecteurs x sont solutions du problème. De plus, l’algorithme se termine car la norme (forme quadratique) des vecteurs x diminue dans la boucle principale en restant entière.

      3. Algorithme de Cholesky
      4. Le problème est le suivant : soit A une matrice réelle, symétrique définissant la forme quadratique Q. On va chercher une matrice R triangulaire supérieure telle que A= tR.R. En fait, on va mettre Q sous la forme

        L’algorithme est classique pour trouver R, on pourra se référer pour de plus amples détails (par exemple) au cours d’Analyse Numérique de Licence de M. Komornik (Strasbourg) p. 55 ou de DEUG de M. Akesby (Mulhouse) p. 34. La version qui calcule les coefficients de Q est moins usuelle : on pourra se référer à l’article de U. Fincke et M. Pohst paru dans Mathematics of Computation.

        Procedure Cholesky(A : Matrix; Var Q, R : Matrix);
        Var i,j,k,l : Integer;
        Begin
        For j:=1 To n Do
        For i:=1 To j Do
        Q[i,j]:=A[i,j];
        i:=0;
        Repeat
        i:=i+1;
        If i<n Then
        Begin
        For j:=i+1 To n Do
        Begin
        Q[j,i]:=Q[i,j];
        Q[i,j]:=Q[i,j]/Q[i,i];
        End;
        For l:=i+1 To n Do
        For k:=i+1 To l Do
        Q[k,l]:=Q[k,l]-Q[k,i]*Q[i,l];
        End;
        Until i=n;
        For i:=1 To n Do
        Begin
        R[i,i]:=Sqrt(Q[i,i]);
        For j:=1 To i-1 Do R[i,j]:=0;
        For j:=i+1 To n Do R[i,j]:=R[i,i]*Q[i,j];
        End;
        End;

         

      5. Recherche de petits vecteurs d’un réseau

    On rappelle que Q(x) = txAx. En décomposant A = tRR par la méthode de Cholesky, on obtient Q(x) = txtRRx. Donc résoudre le problème Q(x) C revient à résoudre :

    txtRRx C

    On introduit alors les notations : ri représente la i-ème colonne de R, ri’ représente la i-ème ligne de R-1.

    On observant que R-1Rx=x, on a tri’.Rx=xi. Donc par Cauchy-Schwarz :

    .

    Donc, en réduisant , on réduit l’ensemble des candidats pour les coordonnées de x. On va donc faire intervenir à cette étape l’algorithme LLL, qui va nous donner une matrice S-1=H-1R-1.

    On résoud alors le problème tytSSy C par la méthode du A, et on retrouve les solutions originales par x = Hy !

    Une amélioration substancielle de cet algorithme est de proceder à un ordonnement des colonnes de S, c’est-à-dire l’ordre des coefficients de Cholesky. Mais il se peut alors qu’une solution (xk+1, …, xn) de A ne puisse se prolonger en une solution (x1, …, xn) convenable. La probabilité de cet événement décroit avec la croissance de l’ordre des xi.

    Procedure FinckePohst(A : Matrix; C : Real);
    Var A1,Q,Q1,R,R1,RInv,TRInv,S,TS,SInv,TSInv,H,HInv,THInv,X,Y : Matrix;
    Sigma : Array[1..n,1..2] Of Integer;
    Begin
    Cholesky(A,Q,R);
    InverseMatrix(R,RInv);
    TransposeMatrix(RInv,TRInv);
    BasisLLL(TRInv,TSInv,THInv);
    TransposeMatrix(THInv,HInv);
    InverseMatrix(HInv,H);
    MultMatrix(HInv,RInv,SInv)
    MultMatrix(R,H,S);
    For i:=1 To n Do
    Begin
    Sigma[i,1]:=i;
    Sigma[i,2]:=0;
    For j:=1 To n Do
    Sigma[i,2]:=Sigma[i,2]+SInv[i,j]*SInv[i,j];
    End;
    SortTab(Sigma);
    PermuteColumns(S,Sigma);
    TransposeMatrix(S,TS);
    MultMatrix(TS,S,A1);
    Cholesky(A1,Q1,R1);
    SV2(C,Q1,Y);
    ApplyInvSigma(Y,Sigma);
    TransposeMatrix(Y,Y);
    MultMatrix(H,Y,X);
    OutputMatrix(X);
    End;

     

    Détails : Le tableau Sigma sert a calculer et stocker la permutation s qui réordonne la matrice S-1. On stocke donc dans la première ligne de Sigma les indices i et dans une deuxième ligne, les carrés des normes des lignes de S-1. On trie alors ce tableau par ordre décroissant de la deuxième ligne et ceci donne une représentation de la permutation dans la première ligne. Ce tri est effectué par la procédure SortTab.

    La procédure PermuteColumns applique alors la permutation s -1 aux colonnes de S. On calcule alors la nouvelle matrice A1 et les nouveaux coefficients de Q1 par la méthode de Cholesky.

    On cherche alors les petits vecteurs pour la forme Q1. Cette opération est prise en charge par la procédure SV2 qui est quasi-identique à SV, mais stocke les solutions dans une matrice Y.

    Il n’y a plus alors qu’à calculer X = H Y, et les colonnes de X sont alors des vecteurs solutions du problème général.

    Remarques :

    ü Notre algorithme contient un nombre important de matrices qui pourrait être optimisé. Nous avons préféré fourni cet algorithme sous cette forme afin d’accroître la lisibilité pour le lecteur.

    ü Dans le deuxième appel à Cholesky, il n’est pas utile de calculer R1.

    ü Le gain de temps de cette méthode par rapport à celles préexistantes est consistant : on pourra se reporter à l’article cité plus haut pour une analyse de complexité.

  6. Conclusion
  7. L’importance de ces algorithmes LLL est d’autant plus grande qu’ils sont très souvent à la base de nombreux problèmes mathématiques et informatiques. Les exemples d’applications que nous avons donnés ne reflètent qu’une partie des nombreux cas où il est nécessaire de faire appel à une " réduction de réseau ".

    Ceci est d’autant plus frappant que cet algorithme n’existe que depuis quelques années (1982) et a permis un essor ou une amélioration d’une bonne part des algorithmes sur entiers. Ainsi, certaines de ses applications entre en jeux dans la recherche de racines de polynômes…

     

    Ce travail fut l’occasion de nous replonger dans les mathématiques discrètes et nous a procuré - outre beaucoup d’heures d’intenses cogitations - un certain plaisir de retrouver un support concret et une réalisation logicielle.

    Nous espérons avoir été aussi complets que possible sans égarer le lecteur dans d’âpres détails…

  8. Bibliographie

 

  1. Résumé
    1. Mots Clefs
    2. ü Algorithme LLL

      ü Calculs sur Entiers

      ü Réseaux

      ü Formes Quadratiques

       

    3. Condensé

Ce mémoire aborde l’explication détaillée des algorithmes de Lenstra, Lenstra et Lovasz d’orthogonalisation d’une base d’un réseau.

Le niveau requis n’est pas très important puisque la plupart des notions utiles sont rappelées.