N ◦ d’ordre : 303
N ◦ attribu´ e par la biblioth` eque : 04ENSL303
ECOLE NORMALE SUP´ ´ ERIEURE DE LYON Laboratoire de l’Informatique du Parall´ elisme
TH` ESE
pour obtenir le grade de
Docteur de l’ ´ Ecole Normale Sup´ erieure de Lyon sp´ ecialit´ e : Informatique
au titre de l’´ ecole doctorale MathIf
pr´ esent´ ee et soutenue publiquement le 20 d´ ecembre 2004 par Pascal Giorgi
ARITHM´ ETIQUE ET ALGORITHMIQUE EN ALG` EBRE LIN´ EAIRE EXACTE POUR LA BIBLIOTH` EQUE LINBOX
Apr` es avis de : M. Bernard Mourrain M. Jean-Louis Roch
Devant la commission d’examen form´ ee de :
M. Bernard Mourrain Membre/Rapporteur
M. Yves Robert Membre
M. Jean-Louis Roch Membre/Rapporteur
M. Bruno Salvy Membre/Pr´ esident du jury
M. Gilles Villard Membre/Directeur de th` ese
N ◦ d’ordre : 303
N ◦ attribu´ e par la biblioth` eque : 04ENSL303
ECOLE NORMALE SUP´ ´ ERIEURE DE LYON Laboratoire de l’Informatique du Parall´ elisme
TH` ESE
pour obtenir le grade de
Docteur de l’ ´ Ecole Normale Sup´ erieure de Lyon sp´ ecialit´ e : Informatique
au titre de l’´ ecole doctorale MathIf
pr´ esent´ ee et soutenue publiquement le 20 d´ ecembre 2004 par Pascal Giorgi
ARITHM´ ETIQUE ET ALGORITHMIQUE EN ALG` EBRE LIN´ EAIRE EXACTE POUR LA BIBLIOTH` EQUE LINBOX
Apr` es avis de : M. Bernard Mourrain M. Jean-Louis Roch
Devant la commission d’examen form´ ee de :
M. Bernard Mourrain Membre/Rapporteur
M. Yves Robert Membre
M. Jean-Louis Roch Membre/Rapporteur
M. Bruno Salvy Membre/Pr´ esident du jury
M. Gilles Villard Membre/Directeur de th` ese
Remerciements
En premier lieu, je tiens ` a remercier mon directeur de th` ese Gilles Villard sans qui cette th` ese n’aurait jamais pu voir le jour. Je le remercie pour son encadrement, sa disponibilit´ e, ses conseils, sa clairvoyance et pour sa g´ en´ erosit´ e aussi bien dans le travail que dans la vie de tous les jours.
Je remercie Jean-Michel Muller et Jean-Claude Bajard qui sont ` a l’origine de ma candidature pour une th` ese ` a l’ENS Lyon et qui m’ont permis de m’int´ eresser ` a la recherche scientifique.
Je remercie ´ egalement Jean-Louis Roch et Bernard Mourrain qui ont accept´ e la lourde tˆ ache de rapporter sur ce manuscrit et qui m’ont fortement encourag´ e pour son accomplissement ainsi que pour la poursuite de mes travaux de recherche. Un grand merci ` a tout les membres du jury pour l’attention port´ ee ` a mon travail et pour avoir accepter une date de soutenance aussi proche de no¨ el.
Je remercie fortement Claude-Pierre Jeannerod, Arnaud Tisserand et Nathalie Revol pour leur soutien au quotidien, leur encouragement et pour toutes les discussions s´ erieuses et moins s´ erieuses que nous avons pu partager autour d’un bon caf´ e.
Merci aux autres personnes de l’´ equipe Ar´ enaire de m’avoir aussi bien acceuilli et sup- port´ e pendant ces trois ann´ ees : David, Nicolas W, Marc, Florent, Jean-Luc, Catherine, J´ eremy, Guillaume, Saurhab, Romain, Sylvie et Nicolas.
Je tiens ´ egalement ` a remercier l’ensemble des membres du projet LinBox sans qui je n’aurai pu d´ evelopper l’ensemble des codes disponibles ` a l’heure actuelle dans la biblioth` eque. Plus particuli` erement, merci ` a Jean-Guillaume et Cl´ ement pour notre collaboration autour du projet fflas - ffpack ainsi que pour l’enthousiasme et la bonne humeur que vous m’avez apport´ e.
Merci aussi ` a Erich Kaltofen, Dave Saunders et Mark Giesbrecht pour l’ensemble des visites en Am´ erique du nord et un grand merci a Zhendong pour l’ensemble des corrections de bugs.
Je remercie ma famille pour leur comprehension et leur soutien sans faille tout au long de ces trois ann´ es. Je remercie ´ egalement tous mes amis Alex, Mehdi, Chass, Cissou, Bruno, S´ ev pour les moment de d´ etente que nous avons pass´ e ensemble. Enfin, je remercie S´ everine pour la patience et la gentillesse dont elle a fait preuve pendant tout ce temps pass´ e loin d’elle.
i
Table des mati` eres
Introduction 1
1 Organisation et motivation du projet LinBox 7
1.1 Choix du langage C++ . . . . 9
1.1.1 Classes : abstraction, acc` es et hi´ erarchisation . . . . 10
1.1.2 Polymorphisme et g´ en´ ericit´ e . . . . 13
1.1.3 Sp´ ecialisations et caract´ erisations . . . . 16
1.2 Utilisation de biblioth` eques sp´ ecialis´ ees . . . . 18
1.2.1 GMP . . . . 18
1.2.2 Givaro . . . . 19
1.2.3 NTL . . . . 19
1.2.4 LiDIA . . . . 20
1.2.5 blas . . . . 20
1.3 Interfaces utilisateurs . . . . 21
1.3.1 Maple . . . . 21
1.3.2 GAP . . . . 22
1.3.3 Serveurs web . . . . 23
1.4 Organisation des codes . . . . 23
iii
2.1 Arch´ etype de donn´ ees . . . . 28
2.1.1 Mod` ele de base des corps finis . . . . 29
2.1.2 Interface compilable . . . . 31
2.1.3 Implantation . . . . 34
2.1.4 Performances vs g´ en´ ericit´ es . . . . 38
2.2 Corps finis premiers . . . . 45
2.2.1 Modular . . . . 45
2.2.2 GivaroZpz standard . . . . 48
2.2.3 GivaroZpz : base logarithmique (Zech’s log) . . . . 48
2.2.4 GivaroZpz : base de Montgomery . . . . 50
2.2.5 NTL . . . . 51
2.2.6 Performances et surcoˆ ut des wrappers . . . . 53
2.3 Extension alg´ ebrique GF (p k ) . . . . 59
2.3.1 Givaro . . . . 59
2.3.2 NTL . . . . 60
2.3.3 LiDIA . . . . 61
2.3.4 Performances et surcoˆ ut des wrappers . . . . 63
2.4 Conclusion . . . . 65
3 Alg` ebre lin´ eaire dense sur un corps fini 67 3.1 Syst` emes lin´ eaires triangulaires . . . . 69
3.1.1 Algorithme r´ ecursif par blocs . . . . 70
3.1.2 Utilisation de la routine ”dtrsm” des blas . . . . 71
3.1.3 Utilisation de r´ eductions modulaires retard´ ees . . . . 74
3.1.4 Comparaison des implantations . . . . 75
3.2 Triangularisations de matrices . . . . 78
3.2.1 Factorisation LSP . . . . 78
3.2.2 LUdivine . . . . 80
3.2.3 LQUP . . . . 81
3.2.4 Performances et comparaisons . . . . 81
3.3 Applications des triangularisations . . . . 83
3.3.1 Rang et d´ eterminant . . . . 83
3.3.2 Inverse . . . . 84
3.3.3 Base du noyau . . . . 85
3.3.4 Alternative ` a la factorisation LQUP : Gauss-Jordan . . . . 85
3.4 Interfaces pour le calcul ”exact/num´ erique” . . . . 89
iv
v
3.4.1 Interface avec les blas . . . . 90
3.4.2 Connections avec Maple . . . . 95
3.4.3 Int´ egration et utilisation dans LinBox . . . 100
4 Syst` emes lin´ eaires entiers 119 4.1 Solutions rationnelles . . . 122
4.1.1 D´ eveloppement p-adique de la solution rationnelle . . . 122
4.1.2 Reconstruction de la solution rationnelle . . . 123
4.1.3 Algorithme complet . . . 124
4.2 Interface pour la r´ esolution des syst` emes lin´ eaires entiers . . . 125
4.2.1 RationalSolver . . . 126
4.2.2 LiftingContainer et LiftingIterator . . . 128
4.2.3 RationalReconstruction . . . 130
4.3 Algorithme de Dixon . . . 135
4.3.1 Cas non singulier . . . 137
4.3.2 Cas singulier et certificat d’inconsistance . . . 139
4.3.3 Solutions al´ eatoires . . . 144
4.3.4 Optimisations et performances . . . 145
4.4 Solutions diophantiennes . . . 150
4.4.1 Approche propos´ ee par Giesbrecht . . . 151
4.4.2 Certificat de minimalit´ e . . . 153
4.4.3 Implantations et performances . . . 156
Conclusion et perspectives 161 Annexes 173 A Code LinBox 173 A.1 D´ eveloppements p-adiques de syst` emes lin´ eaires entiers . . . 173
A.2 Reconstruction de la solution rationnelle . . . 175
A.3 R´ esolution de syst` emes lin´ eaires entiers singuliers avec l’algorithme de Dixon 178 A.4 Produits matrice-vecteur et matrice-matrice en repr´ esentation q-adique . . . 183
Table des figures 189
Liste des tableaux 191
Introduction
3 A la diff´ ` erence du calcul num´ erique qui s’attache ` a calculer les meilleures approximations possibles d’un r´ esultat, le calcul formel ou symbolique consiste ` a calculer les solutions de ma- ni` ere exacte. Dans le cadre de l’alg` ebre lin´ eaire, le calcul num´ erique b´ en´ eficie de plusieurs ann´ ees d’exp´ erience, tant au niveau math´ ematique qu’informatique. Le d´ eveloppement de routines de calcul exploitant au maximum les caract´ eristiques des processeurs et des unit´ es de calcul flot- tantes a permis de fournir une puissance de calcul incomparable pour les op´ erations de base en alg` ebre lin´ eaire. On connaˆıt notamment la hi´ erarchie des blas (Basic Linear Algebra Subrou- tines) qui propose, en particulier, des routines de multiplication de matrices permettant d’obtenir les meilleures performances pour cette op´ eration. On s’efforce donc d’exprimer l’ensemble des algorithmes pour les probl` emes majeurs en alg` ebre lin´ eaire ` a partir de ces routines. C’est exacte- ment ce qui est fait par la biblioth` eque lapack 1 qui fournit aujourd’hui un v´ eritable standard pour le calcul en alg` ebre lin´ eaire num´ erique. La r´ eutilisation de cette biblioth` eque est devenue indispensable pour r´ esoudre certains probl` emes provenant d’applications concr` etes.
Actuellement, il n’existe aucun ´ equivalent de ces biblioth` eques pour le calcul en alg` ebre li- n´ eaire exacte. La difficult´ e de conception d’un tel outil de calcul se situe ` a deux niveaux, d’abord sur un plan th´ eorique, o` u certains gains en complexit´ e ne sont que tr` es r´ ecents dans le domaine.
En effet, le probl` eme central, qui est le grossissement de la taille des donn´ ees durant les calculs, est encore difficile ` a maˆıtriser et entraˆıne un lourd tribut sur le nombre d’op´ erations arithm´ e- tiques n´ ecessit´ ees par les algorithmes. Ensuite, sur un plan pratique, la diversit´ e des calculs et des arithm´ etiques utilis´ ees ne permet pas de d´ efinir un v´ eritable standard. Les calculs peuvent, par exemple, n´ ecessiter l’utilisation d’arithm´ etiques bas´ ees sur des entiers, des polynˆ omes, des corps de fractions, des corps finis ou des extensions alg´ ebriques.
L’une des cl´ es pour proposer des solutions performantes en calcul exact r´ eside donc dans la conception de supports logiciels portables et efficaces pour l’ensemble des arithm´ etiques n´ e- cessaires. Ces supports arithm´ etiques sont aujourd’hui disponibles ` a partir de biblioth` eques de calcul sp´ ecialis´ ees. Par exemple, la biblioth` eque GMP 2 s’impose depuis quelques ann´ ees comme le standard pour l’arithm´ etique des grands entiers. De mˆ eme, des biblioth` eques comme NTL 3 ou Givaro 4 proposent des ensembles d’arithm´ etiques diverses tr` es convaincantes. Du fait de l’´ emer- gence de ces biblioth` eques sp´ ecialis´ ees tr` es performantes, portables et facilement r´ eutilisables, le logiciel en calcul formel n’est plus domin´ e par des syst` emes g´ en´ eralistes comme Maple ou Mathematica qui proposent des codes propri´ etaires peu r´ eutilisables et peu satisfaisants pour des calculs qui demandent de tr` es hautes performances.
La conception de logiciels f´ ed´ erant l’ensemble des codes d´ efinis par des biblioth` eques sp´ ecia- lis´ ees au sein d’un environnement de calcul commun devient un r´ eel besoin pour la r´ esolution de probl` emes en calcul formel qui n´ ecessitent de plus en plus de puissance de calcul. Cette th` ese s’inspire de cette tendance r´ ecente pour proposer une biblioth` eque de calcul g´ en´ erique en alg` ebre lin´ eaire exacte. L’un des int´ erˆ ets de la g´ en´ ericit´ e est de faciliter l’int´ egration de composants ex- ternes et d’offrir une r´ eutilisation des codes simplifi´ ee. Cette biblioth` eque est la concr´ etisation logicielle du projet LinBox, issu d’une collaboration internationale sur le th` eme de l’alg` ebre li- n´ eaire exacte.
Contrairement au calcul num´ erique, o` u la pr´ ecision des calculs est fix´ ee par les types flottants des processeurs, la pr´ ecision utilis´ ee pour des calculs exacts sur des nombre entiers est poten-
1 http://www.netlib.org/lapack/
2 http://www.swox.com/gmp
3 http://www.shoup.net/ntl
4 http://www-lmc.imag.fr/Logiciels/givaro/
tiellement infinie. Toutefois, certaines approches classiques du calcul formel comme le th´ eor` eme des restes chinois ou les d´ eveloppements p-adiques permettent d’effectuer l’essentiel des calculs en pr´ ecision finie et d’utiliser une pr´ ecision infinie uniquement pour la reconstruction de la solu- tion exacte. L’utilisation des corps finis est alors un bon moyen pour fournir des implantations efficaces pour ces approches, en particulier, du fait que la th´ eorie algorithmique sur ces objets math´ ematiques se rapproche fortement de celle d´ evelopp´ ee pour le calcul num´ erique.
Les probl` emes que nous ´ etudions dans cette th` ese concernent la conception et la validation de boˆıtes ` a outils g´ en´ eriques performantes pour l’implantation d’algorithmes de l’alg` ebre lin´ eaire exacte et l’int´ egration de codes externes. En premier lieu, notre objectif est de d´ evelopper et de valider une approche permettant le branchement ` a la demande (plug and play) de composants externes (plugins) ; pour cela, nous nous appuyons sur la notion d’interfaces abstraites et de fonctions virtuelles du langage C++. Dans ce cadre pr´ ecis, et dans le but de fournir des implan- tations algorithmiques b´ en´ eficiant des meilleures arithm´ etiques de corps finis, nous ´ etudions la faisabilit´ e et l’efficacit´ e de la r´ eutilisation de biblioth` eques sp´ ecialis´ ees pour d´ efinir un noyau de corps finis facilement interchangeable dans la biblioth` eque LinBox.
Un des probl` emes majeurs que nous consid´ erons concerne la possibilit´ e du d´ eveloppement de routines de calcul sur les corps finis similaires ` a celles propos´ ees par les biblioth` eques num´ e- riques blas / lapack , ` a savoir des routines portables, optimis´ ees en fonction des caract´ eristiques des processeurs et facilement r´ eutilisables. Notre d´ emarche pour aborder ce vaste probl` eme, a consist´ e ` a utiliser des calculs hybrides ”exact/num´ erique” permettant la r´ eutilisation des rou- tines num´ eriques blas pour le calcul sur les corps finis. Cette approche se base sur l’utilisation d’algorithmes par blocs se r´ eduisant au produit de matrices et permettant ainsi de b´ en´ eficier des tr` es bonnes performances du niveau trois des blas . De cette fa¸ con, nous proposons une brique de base pour les probl` emes fondamentaux d’alg` ebre lin´ eaire sur les corps finis permettant d’approcher l’efficacit´ e obtenue par la biblioth` eque lapack .
Afin de valider l’ensemble des fonctionnalit´ es que nous proposons au sein de la biblioth` eque LinBox, nous ´ etudions l’implantation d’une application d’alg` ebre lin´ eaire sur les entiers permet- tant de solliciter une multitude de caract´ eristiques de calcul sur les corps finis et les entiers, ainsi que diff´ erentes m´ ethodes algorithmiques selon que les matrices sont denses, creuses ou structu- r´ ees ; nous nous int´ eressons ` a la r´ esolution de syst` emes lin´ eaires diophantiens. L’utilisation de m´ ecanismes d’abstraction de calcul et d’optimisations en fonction des instances trait´ ees nous permettent de r´ eutiliser efficacement les fonctionnalit´ es de la biblioth` eque LinBox. La concep- tion d’une interface de calcul pour ces r´ esolutions qui est facilement param´ etrable et r´ eutilisable nous permet de proposer un outil de calcul de haut niveau tr` es performant.
Le premier chapitre de cette th` ese pr´ esente le projet LinBox et ses objectifs. Nous introdui- sons en particulier les diff´ erents concepts du langage C++ que nous utilisons pour permettre l’interop´ erabilit´ e de la biblioth` eque avec des composants externes. De plus, nous faisons un tour d’horizon des diff´ erentes biblioth` eques sp´ ecialis´ ees et des plates-formes g´ en´ eralistes qu’utilise le projet LinBox. Enfin, nous donnons une description exhaustive des fonctionnalit´ es d´ ej` a dispo- nibles dans la biblioth` eque LinBox.
Dans le deuxi` eme chapitre, nous proposons d’´ etudier un concept de branchement ` a la de-
mande propos´ e dans LinBox pour fournir une arithm´ etique de corps finis facilement interchan-
geable dans les codes et pouvant provenir de biblioth` eques externes. Pour cela, nous d´ efinissons
la notion d’arch´ etype de donn´ ees qui fixe un mod` ele de base permettant une d´ efinition pure-
ment abstraite de l’arithm´ etique utilis´ ee dans les codes g´ en´ eriques. En particulier, nous montrons
que grˆ ace ` a cet arch´ etype on peut facilement int´ egrer des codes externes ` a partir d’adaptateurs
5 (wrapper) qui permettent d’harmoniser les diff´ erentes implantations avec le formalisme d´ efini par le mod` ele de base. La pr´ esentation de ces adaptateurs est l’occasion de faire un ´ etat de l’art des diff´ erentes implantations de corps finis actuellement disponibles et d’en ´ evaluer les performances.
Le chapitre 3 d´ eveloppe l’approche de calcul hybride ”exact/num´ erique” que nous utilisons pour int´ egrer les routines de multiplication de matrices num´ eriques blas ` a l’int´ erieur de calculs d’alg` ebre lin´ eaire sur les corps finis. En particulier, nous d´ eveloppons les diff´ erents algorithmes employ´ es pour obtenir une r´ eduction au produit de matrices. Grˆ ace ` a ces algorithmes et ` a l’utilisation des routines num´ eriques blas , nous proposons des implantations pour les probl` emes classiques de l’alg` ebre lin´ eaire sur un corps fini qui ont des performances tr` es proches de celles ob- tenues pour le produit de matrice ; ` a savoir, le calcul de certaines triangularisations de matrices, le calcul du d´ eterminant, le calcul du rang, la r´ esolution de syst` emes triangulaires matriciels et le calcul d’une base du noyau. En plus de ce travail g´ en´ eral, nous avons eu l’occasion de tra- vailler sur le probl` eme particulier du calcul d’une base du noyau qui nous a permis de proposer une adaptation de l’algorithme de Gauss-Jordan par blocs am´ eliorant le nombre d’op´ erations n´ ecessaires par rapport au produit de matrices d’un facteur 1/6. La derni` ere partie de ce cha- pitre est consacr´ ee ` a la d´ efinition d’une interface standard pour l’utilisation de ces approches hybrides ”exact/num´ erique”; en outre, nous montrons comment r´ eutiliser ces approches ` a plus haut niveau, dans le logiciel Maple et la biblioth` eque LinBox.
Enfin, la chapitre 4 concerne la validation des diff´ erentes briques de base d´ evelopp´ ees dans
la biblioth` eque LinBox autour du probl` eme de la r´ esolution de syst` emes lin´ eaires diophantiens ;
nous d´ emontrons alors l’int´ erˆ et de la biblioth` eque. Ce travail s’appuie sur les d´ eveloppements
p-adiques des solutions rationnelles pour fournir une interface de r´ esolution g´ en´ erique qui est
facilement param´ etrable en fonction des caract´ eristiques du syst` eme et du type de solution que
l’on souhaite calculer. Nous montrons en particulier que la r´ eutilisation des calculs ”exacts/nu-
m´ eriques” nous permet de proposer l’une des meilleures implantations actuelles pour les syst` emes
lin´ eaires diophantiens denses.
Chapitre 1
Organisation et motivation du projet LinBox
Sommaire
1.1 Choix du langage C++ . . . . 9
1.1.1 Classes : abstraction, acc` es et hi´ erarchisation . . . . 10
1.1.2 Polymorphisme et g´ en´ ericit´ e . . . . 13
1.1.3 Sp´ ecialisations et caract´ erisations . . . . 16
1.2 Utilisation de biblioth` eques sp´ ecialis´ ees . . . . 18
1.2.1 GMP . . . . 18
1.2.2 Givaro . . . . 19
1.2.3 NTL . . . . 19
1.2.4 LiDIA . . . . 20
1.2.5 blas . . . . 20
1.3 Interfaces utilisateurs . . . . 21
1.3.1 Maple . . . . 21
1.3.2 GAP . . . . 22
1.3.3 Serveurs web . . . . 23
1.4 Organisation des codes . . . . 23
Le projet LinBox est un projet international (Canada, France, USA) http://www.linalg.org autour du calcul exact et plus particuli` erement de l’alg` ebre lin´ eaire exacte. Le but de ce pro- jet est le d´ eveloppement d’un outil logiciel g´ en´ erique pour les probl` emes classiques de l’alg` ebre lin´ eaire tels que la r´ esolution de syst` emes lin´ eaires, le calcul du d´ eterminant, le calcul du rang et le calcul des formes normales de matrices. L’ambition du projet s’ins` ere dans une tendance r´ ecente de d´ eveloppement logiciel qui vise ` a f´ ed´ erer des ensembles de codes sp´ ecifiques au sein d’un environnement de calcul commun. L’id´ ee est de proposer un logiciel ´ evolutif et configurable en autorisant le branchement ` a la demande de composants externes sp´ ecifiques. Cette approche est relativement nouvelle dans le calcul scientifique et trouve son int´ erˆ et dans l’existence d’outils de calcul symbolique d´ ej` a tr` es performants et d’am´ elioration croissante des techniques algorith- miques du domaine. Cette approche commence ` a ´ emerger de plus en plus dans le d´ eveloppement de logiciels scientifiques. On peut citer par exemple la biblioth` eque SYNAPS [68] pour le calcul symbolique-num´ erique et la biblioth` eque MTL (Matrix Template Library) [74] pour l’alg` ebre lin´ eaire num´ erique.
La mise en place d’un tel logiciel doit permettre de b´ en´ eficier des performances de logiciels tr` es sp´ ecialis´ es comme par exemple la biblioth` eque GMP [41] pour l’arithm´ etique multipr´ ecision ou la biblioth` eque NTL [73] pour l’arithm´ etique des polynˆ omes. ` A un plus haut niveau, ce lo- giciel doit aussi permettre de servir de middleware pour une mise en place de calculs efficaces dans des environnements conviviaux comme par exemple le logiciel Maple [58] ou GAP [81]
ainsi que certains serveurs web.
modules GMP NTL
LinBox GAP
solutions de calcul algorithmes et
branchements
spécifiques middleware
interface utilisateurs MAPLE
bibliothèques spécifiques
Serveurs web
Fig. 1.1 – Physionomie du projet LinBox
La figure 1.1 illustre la philosophie du projet LinBox. Afin de d´ evelopper ce logiciel, le pro-
1.1. Choix du langage C++ 9 jet LinBox s’est orient´ e vers la conception d’une biblioth` eque C++ g´ en´ erique appel´ ee LinBox.
L’int´ erˆ et d’un langage orient´ e objet provient du fait que le calcul scientifique, et particuli` ere- ment l’alg` ebre lin´ eaire, s’illustre parfaitement au travers des concepts d´ efinis par le mod` ele objet.
L’objectif de ce chapitre est de pr´ esenter les diff´ erents niveaux d’organisation de la biblio- th` eque LinBox illustr´ es par la figure 1.1. Avant de d´ efinir chacun de ces niveaux, nous pr´ esentons dans la partie 1.1 quelques concepts du langage C++ que nous utilisons pour d´ efinir la struc- ture de middleware de la biblioth` eque LinBox. Ensuite, dans la partie 1.2, nous d´ ecrivons les diff´ erentes biblioth` eques de calcul sp´ ecialis´ ees sur lesquelles nous nous appuyons pour effectuer des calculs sp´ ecifiques performants. Nous pr´ esentons dans la partie 1.3 quelques applications existantes permettant d’utiliser la biblioth` eque LinBox. Enfin, nous terminerons ce chapitre en dressant le bilan de l’organisation des codes ` a l’int´ erieur de la biblioth` eque LinBox ainsi que les diff´ erentes implantations algorithmiques disponibles.
1.1 Choix du langage C++
Depuis sa cr´ eation dans les ann´ ees 80, C++ est devenu un langage tr` es utilis´ e dans le d´ evelop- pement d’applications logicielles performantes. Au d´ epart, C++ n’est qu’une simple surcouche orient´ ee objet pour le langage C. A cette ´ epoque, ce langage s’appelait encore ” C with classes”.
Apr` es plusieurs changements de nom et une ´ evolution des fonctionnalit´ es, le langage C++ ´ emerge enfin en 1984. Bjarne Stroustrup, le concepteur de ce langage [80], explique le choix de C comme langage de base pour d´ efinir C++ du fait que C ´ etait massivement utilis´ e et qu’il permettait la mise en œuvre de tout type de programme. Grˆ ace ` a sa s´ emantique bas niveau ce langage
´ etait d’ailleurs l’un des plus performants ` a l’´ epoque. Il figure toujours parmi les langages de programmation les plus performants ` a l’heure actuelle. Encore aujourd’hui, certain compilateurs C++ continuent de g´ en´ erer leurs codes r´ esultats au travers de compilation C. L’apport majeur de C++ par rapport au langage C est l’organisation des programmes ` a l’aide de classes. Depuis 1991 et l’ajout de mod` eles param´ etrables (i.e. template), le langage C++ suscite un int´ erˆ et par- ticulier pour le d´ eveloppement d’applications g´ en´ eriques performantes.
Le choix du langage C++ pour d´ evelopper la biblioth` eque LinBox se justifie ` a la fois par les
bonnes performances des programmes compil´ es et par les facilit´ es de d´ eveloppement apport´ ees
par les m´ ecanismes de g´ en´ ericit´ e et de conception objet. De plus, ce langage autorise une bonne
portabilit´ e du fait qu’il existe des compilateurs C++ pour la plupart des architectures mat´ e-
rielles. L’utilisation d’autres langages orient´ es objet, comme Java par exemple, semble ne pas ˆ etre
encore assez comp´ etitive au niveau des calculs pour s’int´ eresser au d´ eveloppement d’applications
en calcul formel [5]. L’autre point important de notre choix pour C++ est la r´ eutilisation de
biblioth` eques sp´ ecialis´ ees. D’une part, ce langage autorise l’int´ egration d’autres langages comme
Fortran qui est le langage de programmation utilis´ e g´ en´ eralement par les biblioth` eques num´ e-
riques. D’autre part, la majeure partie des biblioth` eques faisant r´ ef´ erence en calcul symbolique
ont ´ et´ e d´ evelopp´ ees en C ou en C++. La biblioth` eque GMP [41], qui est d´ ej` a consid´ er´ ee comme
un standard pour l’arithm´ etique multipr´ ecision, est d´ evelopp´ ee en C et propose mˆ eme une in-
terface C++ depuis sa version 4. De mˆ eme, la biblioth` eque NTL [73], qui propose les meilleures
implantations d’arithm´ etique polynomiale, est aussi d´ evelopp´ ee en C++. L’interaction entre ces
biblioth` eques et LinBox est donc grandement facilit´ ee par l’utilisation d’un langage de program-
mation commun.
La notion de classe permet de regrouper les structures de donn´ ees et les diff´ erentes fonctions aff´ erentes ` a un objet ` a l’int´ erieur d’un unique mod` ele de donn´ ees. Ce mod` ele sert d’interface aussi bien pour la d´ efinition que pour la manipulation des objets. Ainsi, la structure de donn´ ees sous-jacentes ` a un objet est totalement d´ ecorr´ el´ ee de l’objet. Seules les fonctions de manipulation de l’objet permettent d’acc´ eder ` a sa structure. Ce n’est pas le cas dans un langage fonctionnel classique comme C. Nous pr´ esentons dans les paragraphes suivants les diff´ erents m´ ecanismes de C++ permettant de d´ efinir et d’organiser les objets au travers de classes. Plus pr´ ecis´ ement, nous aborderons les diff´ erents concepts de programmation g´ en´ erique disponibles en C++ en pr´ esentant leur int´ erˆ et pour le d´ eveloppement de la biblioth` eque LinBox.
1.1.1 Classes : abstraction, acc` es et hi´ erarchisation
Le principal but des classes est de pouvoir sp´ ecifier un concept ou un objet au travers d’une d´ efinition structurelle et fonctionnelle. La classe d´ efinie alors un mod` ele de donn´ ees qui encapsule la structure de donn´ ees de l’objet et les fonctionnalit´ es qui lui sont aff´ erentes. L’int´ erˆ et d’utiliser les classes est que l’on peut abstraire la structure d’un objet de sa manipulation. Par exemple, la manipulation d’un vecteur ne n´ ecessite pas de connaˆıtre sa structure de donn´ ees. Il suffit simplement de pouvoir acc´ eder ` a ces ´ el´ ements et ` a sa dimension. Le but de la conception d’une classe consiste ` a d´ efinir l’ensemble des donn´ ees repr´ esentant l’objet (appel´ ees attributs) et l’ensemble des fonctions permettant d’utiliser l’objet (appel´ ees m´ ethodes).
Le code 1.1 d´ ecrit un mod` ele de classe C++ permettant de d´ efinir un vecteur d’entiers.
Les attributs de cet objet sont ses coefficients et sa dimension et les m´ ethodes sont l’acc` es aux
´
el´ ements, l’acc` es ` a la dimension et la lecture de coefficients. La cr´ eation d’un vecteur est ici bas´ ee sur un constructeur en fonction de la dimension.
Code 1.1 – Exemple de classe
c l a s s V e c t e u r I n t {
// p r i v a t e d a t a private :
i n t ∗ Rep ; // s t o r a g e o f v e c t o r i n t s i z e ; // s i z e o f v e c t o r void r e a d ( i n t n ) // u n s a f e r e a d f u n c t i o n { f o r ( i n t i =0; i <n;++ i )
c i n>> Rep [ i ] ; }
// p u b l i c d a t a public :
V e c t e u r I n t ( i n t n ) : s i z e ( n ) { Rep = new i n t [ n ] ; } // v e c t o r c o n s t r u c t o r
˜ V e c t e u r I n t ( ) { d e le t e [ ] Rep ; } // v e c t o r d e s t r u c t o r i n t g e t C o e f f ( i n t i ) { return Rep [ i ] ; } // e l e m e n t s a c c e s s o r i n t s i z e ( ) {return s i z e ; } // s i z e a c c e s s o r void r e a d C o e f f ( ) { r e a d ( s i z e ) ; } // s a f e r e a d f u n c t i o n
. . .
};
1.1. Choix du langage C++ 11
Une notion importante dans la mise en place de classes C++ est le contrˆ ole d’acc` es. Ce m´ e- canisme permet de prot´ eger les attributs et les m´ ethodes d’un objet des erreurs de manipulation.
Par exemple, notre code 1.1 d´ efinit les attributs _Rep, _size et la m´ ethode read de fa¸ con priv´ ee afin d’empˆ echer leur acc` es depuis une instance de l’objet VecteurInt. En effet, un acc` es public
`
a ces donn´ ees permettrait ` a un utilisateur de modifier l’objet de fa¸ con non maˆıtris´ ee. Toujours dans notre exemple, la fonction read permet la lecture d’un nombre de coefficients potentiel- lement sup´ erieur ` a la zone m´ emoire allou´ ee au vecteur. Voila pourquoi cette fonction doit ˆ etre d´ efinie de fa¸ con priv´ ee. En contrepartie, il faut fournir des m´ ethodes publiques garantissant qu’il n’y aura aucun effet de bord sur l’objet. La fonction readCoeff de notre mod` ele est d´ efinie de fa¸ con publique car elle permet d’´ eviter les effets de bord de la fonction read. Il existe trois niveaux de contrˆ ole d’acc` es en C++ :
- acc` es priv´ e (private) - acc` es prot´ eg´ e (protected) - acc` es public (public)
L’acc` es priv´ e est le plus restrictif et n’autorise que l’acc` es ` a l’int´ erieur du mod` ele (par exemple read dans le code 1.1). L’acc` es public autorise l’acc` es ` a tous les niveaux. Enfin, l’acc` es prot´ eg´ e propose le mˆ eme niveau de restriction que l’acc` es priv´ e sauf pour les mod` eles et les fonctions qui sont d´ eclar´ es explicitement comme amis (friend) dans la d´ eclaration du mod` ele de l’objet.
Une autre caract´ eristique importante du C++ est la hi´ erarchisation de classes. Cette hi´ e- rarchisation s’exprime grˆ ace au concept d’h´ eritage, qui permet de mod´ eliser l’inclusion des en- sembles des objets. L’utilisation de cette notion permet donc d’organiser le code de fa¸ con plus intuitive en sp´ ecialisant les objets ` a partir d’un graphe de relation.
Vecteur
Vecteur − int Vecteur − dbl
int size()
double operator[](int) int operator[] (int)
public:
public:
public:
Fig. 1.2 – Exemple d’h´ eritage : mod` ele de vecteur ` a deux niveaux
Les caract´ eristiques communes de plusieurs objets peuvent ainsi ˆ etre d´ efinies dans un mˆ eme mod` ele de base. La figure 1.2 illustre cette notion de mod` ele de base pour des vecteurs dont les coefficients ne sont pas d´ efinis pour le mˆ eme type de donn´ ees. La notion de dimension ´ etant une caract´ eristique commune ` a nos deux mod` eles de vecteurs, on peut donc mod´ eliser cette caract´ eristique ` a l’aide d’une classe de base vecteur.
Le contrˆ ole d’acc` es aux classes de base joue ici un rˆ ole tr` es important. En effet, ce type
de contrˆ ole se propage dans les relations d’h´ eritage. Le m´ ecanisme d’h´ eritage s’accompagne lui
aussi d’une gestion de contrˆ ole d’acc` es qui permet de modifier le contrˆ ole d’acc` es des donn´ ees
d’une classe de base pour ses classes d´ eriv´ ees.
H´ eritage
private protected public Contrˆ ole
d’acc´ es
private inaccessible inaccessible inaccessible protected private protected protected public private protected public
Tab. 1.1 – Contrˆ ole d’acc` es des classes de base via l’h´ eritage
A l’instar du contrˆ ` ole d’acc` es des caract´ eristiques d’une classe (attributs+m´ ethodes), il existe trois types d’h´ eritage possibles : private, protected, public. La combinaison du contrˆ ole d’h´ eritage et du contrˆ ole d’acc` es de la classe de base permet de g´ en´ erer un contrˆ ole d’acc` es dans les classes d´ eriv´ ees. Par exemple, une caract´ eristique d´ eclar´ ee priv´ ee (private) dans une classe de base sera inaccessible dans une classe d´ eriv´ ee quel que soit le type d’h´ eritage. De mˆ eme, l’h´ eritage priv´ e rend toutes les caract´ eristiques h´ erit´ ees inaccessibles dans les classes d´ eriv´ ees.
Le choix du type de contrˆ ole d’acc` es et du type d’h´ eritage est donc un facteur pr´ epond´ erant pour la mise en place d’une hi´ erarchisation de classe coh´ erente. Nous r´ esumons dans le tableau 1.1 les types de contrˆ oles obtenus en fonction du type d’h´ eritage et du type de contrˆ ole d’acc` es initial. Le code 1.2 illustre la notion d’h´ eritage ` a partir du sch´ ema de d´ ependance ´ etabli dans la figure 1.2. La syntaxe du C++ pour d´ efinir une relation d’h´ eritage entre une classe A et une classe B est :
class A : public B ... ; o` u public pr´ ecise le type d’h´ eritage.
Code 1.2 – Exemple d’h´ eritage
c l a s s V e c t e u r { private :
i n t s i z e ; public :
i n t s i z e ( ) {return s i z e ; } };
c l a s s V e c t e u r I n t : public V e c t e u r { private :
i n t ∗ Rep ; public :
V e c t e u r I n t ( i n t n ) : V e c t e u r ( n ) { Rep = new i n t [ n ] ; }
˜ V e c t e u r I n t ( ) { d e le t e [ ] Rep ; }
i n t g e t C o e f f ( i n t i ) { return Rep [ i ] ; } . . .
};
c l a s s V e c t e u r D b l : public V e c t e u r { private :
double ∗ Rep ; public :
V e c t e u r D b l ( i n t n ) : V e c t e u r ( n ) { Rep = new double [ n ] ; }
˜ V e c t e u r D b l ( ) { d e le t e [ ] Rep ; }
i n t g e t C o e f f ( i n t i ) { return Rep [ i ] } ;
. . .
1.1. Choix du langage C++ 13
} ;
1.1.2 Polymorphisme et g´ en´ ericit´ e
La d´ efinition d’objets ` a partir de classes permet une description haut niveau facilitant l’´ ecri- ture de programmes. La notion d’h´ eritage permet d’organiser les codes par des relations d’inclu- sion comme nous avons vu dans le paragraphe pr´ ec´ edent. Un autre aspect int´ eressant du C++
est la d´ efinition de mod` eles de donn´ ees g´ en´ eriques. On parle de polymorphisme pour d´ efinir cette notion. On distingue deux types de polymorphisme en C++ : le polymorphisme statique et le polymorphisme dynamique. Ces deux polymorphismes diff` erent par leur gestion des param` etres g´ en´ eriques. Le polymorphisme statique fixe ces param` etres lors de la compilation (compile time) alors que le polymorphisme dynamique g` ere ces param` etres lors de l’ex´ ecution (run-time).
La notion de polymorphisme statique s’exprime en C++ par l’utilisation de la commande template [80, chap. 13]. Cette commande permet de sp´ ecifier qu’un ou plusieurs types de donn´ ees ne sont pas fix´ es dans le mod` ele. On dit alors que le mod` ele est g´ en´ erique en fonction des types de donn´ ees non sp´ ecifi´ es. Ces types sont sp´ ecifi´ es lors de l’instanciation d’un objet du mod` ele.
En particulier, il faut que l’ensemble des param` etres g´ en´ eriques soit connu au moment de la compilation afin que des sp´ ecialisations du mod` ele soient utilis´ ees. En reprenant notre exemple de classe vecteur du code 1.2, nous d´ efinissons un mod` ele de vecteur g´ en´ erique en fonction de la nature des coefficients. Le code 1.3 illustre cette mod´ elisation.
Code 1.3 – Exemple de polymorphisme statique
template <c l a s s C o e f f >
c l a s s V e c t e u r { private :
C o e f f ∗ Rep ; i n t s i z e ; public :
V e c t e u r ( i n t n ) : s i z e ( n ) { Rep= new C o e f f [ n ] ; }
˜ V e c t e u r ( ) { d e le t e [ ] Rep ; }
C o e f f g e t C o e f f ( i n t i ) {return Rep [ i ] } ; i n t s i z e ( ) {return s i z e ;}
. . . } ;
Le principe des mod` eles g´ en´ eriques est de fournir une conception type pour un ensemble d’ob- jets. Le code 1.3 nous permet par exemple de remplacer les classes VecteurInt et VecteurDbl donn´ ees dans le code 1.2 par un seul mod` ele de classe. L’utilisation des classes Vecteur<int>
et Vecteur<double> permet d’appr´ ehender exactement le mˆ eme type d’objets. C’est le compi- lateur qui se charge de dupliquer et de sp´ ecialiser le mod` ele g´ en´ erique sur les diff´ erents types d’instanciations.
En utilisant ce m´ ecanisme, on peut donc facilement d´ ecrire des objets concrets ` a partir de
mod` eles de donn´ ees abstraits. La seule obligation est que le type d’instanciation du mod` ele g´ en´ e-
rique respecte les pr´ erequis du mod` ele. Typiquement, il faut que ces types proposent l’ensemble
des op´ erations utilisables dans le mod` ele.
La biblioth` eque STL (Standard Template Library) [62, 35] utilise cette technique afin de fournir une biblioth` eque g´ en´ erique pour la manipulation de vecteurs, de listes, de tables de hachage et diff´ erentes structures de conteneurs [10, page 188] de donn´ ees. On peut ainsi utili- ser cette biblioth` eque pour d´ efinir des vecteurs pour n’importe quel type de coefficients (ex. : std::vector<int> et std::vector<double>). L’int´ erˆ et de la biblioth` eque STL est qu’elle permet de manipuler n’importe quel de ces conteneurs ` a l’aide d’une interface g´ en´ erique. Cette interface est d´ efinie par la notion d’it´ erateur de donn´ ees [10, page 193]. Chaque conteneur propose une structure d’it´ erateur permettant de parcourir l’ensemble des objets qu’il repr´ esente. Le nom des it´ erateurs ´ etant standard (iterator, const_iterator,...) on peut alors les utiliser pour d´ e- finir des codes g´ en´ eriques sur les conteneurs. On peut par exemple d´ efinir la fonction g´ en´ erique suivante qui affiche l’ensemble des ´ el´ ements d’un conteneur.
t e m p l a t e < c l a s s c o n t a i n e r >
p r i n t ( c o n s t c o n t a i n e r & c ){
t y p e n a m e c o n t a i n e r :: c o n s t _ i t e r a t o r it ; for ( it = c . b e g i n (); it != c . end (); ++ it )
cout < <* it < < end l }
Chaque conteneur doit fournir des fonctions de cr´ eation d’it´ erateur en d´ ebut et en fin de structure, les fonctions begin() et end() dans notre exemple. L’op´ erateur ++ permet de d´ epla- cer l’it´ erateur sur les donn´ ees du conteneur alors que l’op´ erateur * permet de r´ ecup´ erer l’´ el´ ement point´ e par l’it´ erateur. Cette approche par it´ erateur est standard en C++ pour des structures de donn´ ees ayant un stockage lin´ eaire. Nous r´ eutilisons cette approche dans la biblioth` eque Lin- Box pour la plupart des structures de donn´ ees lin´ eaires (vecteur, matrice, g´ en´ erateur al´ eatoire, d´ eveloppement p-adique, ...). Le but est de pouvoir fournir des implantations g´ en´ eriques pour l’ensemble des structures de donn´ ees qui proposent les bons it´ erateurs. Nous verrons dans la partie 4.2 de ce document un exemple d’utilisation de cette approche pour la r´ esolution de sys- t` emes lin´ eaires entiers.
Bien que le m´ ecanisme de polymorphisme statique soit int´ eressant pour d´ efinir des mod` eles g´ en´ eriques, son utilisation entraˆıne la g´ en´ eration et la compilation de code de taille cons´ equente.
En effet, d` es lors qu’un mod` ele g´ en´ erique est instanci´ e sur un nouveau type de donn´ ees, le compilateur g´ en` ere un mod` ele sp´ ecifique associ´ e ` a ce type de donn´ ees. La compilation de codes uniquement d´ efinis ` a partir de codes templates est donc susceptible de saturer la taille des codes compil´ es ou des ex´ ecutables g´ en´ er´ es. On parle alors d’explosion de code. Une alternative en C++ pour d´ efinir des fonctions g´ en´ eriques sans utiliser les m´ ecanismes templates consiste ` a uti- liser des classes abstraites. Le but d’une classe abstraite est de servir d’unique interface pour la manipulation d’objets d´ efinissant un concept commun. Par exemple, l’arithm´ etique d´ efinit un concept commun ` a l’ensemble des nombres. L’id´ ee est de proposer une interface pour mo- d´ eliser ce concept de fa¸con abstraite et de pouvoir l’utiliser pour manipuler des implantations d’arithm´ etiques concr` etes. Le principe des classes abstraites est de pouvoir d´ eterminer lors de l’ex´ ecution quelle est l’implantation concr` ete ` a utiliser en fonction du type dynamique de l’objet.
On parle alors de polymorphisme dynamique.
1.1. Choix du langage C++ 15 Ce polymorphisme dynamique est possible en pratique grˆ ace ` a l’utilisation des fonctions virtuelles [10, page 101]. Les fonctions virtuelles sont un moyen de sp´ ecifier au compilateur que la fonction est r´ esolue en fonction du type dynamique de l’objet et non pas en fonction de son type statique. Nous illustrons le principe des fonctions virtuelles avec l’exemple suivant.
c l a s s A { p u b l i c :
v i r t u a l voi d f () { cout < < " o b j e c t A " ;}
};
c l a s s B : p u b l i c A { p u b l i c :
v i r t u a l voi d f () { cout < < " o b j e c t B " ;}
};
int ma in () { A a ;
B b ; A & c = b ;
a . f (); // p r i n t o b j e c t A b . f (); // p r i n t o b j e c t B c . f (); // p r i n t o b j e c t B r e t u r n 0;
}
Cet exemple d´ efinit deux classes A et B dont l’une est d´ eriv´ ee de l’autre (B est d´ eriv´ ee de A). Ces deux classes encapsulent une fonction virtuelle f() qui affiche le type dynamique de l’objet. La syntaxe C++ pour d´ efinir une fonction virtuelle est virtual. Cet exemple illustre le fait que, mˆ eme si le type statique de l’objet c est la classe A, la fonction f() d´ epend du type dynamique, ici la classe B.
En pratique, ce m´ ecanisme est d´ efini grˆ ace ` a des tables de pointeurs encapsul´ ees dans la structure de l’objet. On comprend mieux ce m´ ecanisme en regardant ` a quoi ressemblent les objets en m´ emoire. La figure 1.3 illustre les objets a, b, c de notre exemple.
La classe A d´ efinit la fonction virtuelle f() ` a l’int´ erieur d’une table virtuelle. Cette table est associ´ ee ` a la structure de donn´ ees des objets de type A. Un objet de la classe B ´ etant aussi un objet de type A, il h´ erite dans sa structure de la table virtuelle de la classe A. En red´ efinissant la fonction f() dans la classe B, on red´ efinit en mˆ eme temps la table virtuelle de la classe A associ´ ee aux objets B. Le transtypage d’un objet de type B vers un objet de type A permet de conserver la table virtuelle associ´ ee. Cela signifie que l’on peut manipuler des objets B ` a partir d’objets A. Lorsque la classe de base est d´ efinie de fa¸ con totalement abstraite (fonctions virtuelles pures), on ne peut cr´ eer d’instance du type de base. La classe de base est juste une interface (` a partir des fonctions virtuelles).
Cette technique de classe abstraite est r´ eutilis´ ee dans LinBox pour d´ efinir des arch´ etypes de
donn´ ees. Ce type d’utilisation est dˆ u ` a Erich Kaltofen et s’applique particuli` erement au concept
de matrices boˆıtes noires. Ces matrices sont consid´ er´ ees uniquement comme des op´ erateurs
lin´ eaires o` u seule l’application de la matrice ` a un vecteur est disponible. Toutefois, l’utilisation
des classes abstraites ne permet pas de fournir d’instance d’objet compil´ e. En effet, ces classes