M1 TP ALGORITHMIQUE EN SAGE CHRISTOPHE RITZENTHALER 1. Complexité et tris Exercice 1. On propose le programme SAGE suivant de recherche d’un maximal dans une liste d’entiers. def plus_grand_element(liste): resultat = liste[0] for i in range(1, len(liste)): if liste[i] > resultat: resultat = liste[i] return resultat (1) Implémenter le. (2) À l’aide des fonctions ZZ.random_element(), créer des listes aléatoires de longueur croissante et donner le temps pour le calcul de la fonction avec cputime(). (3) Automatiser la procédure précédente et tracer le graphe du temps dans le pire des cas (en prenant le maximum pour 5 tirages à longueur donnée) pour des longueurs entre 104 et 106 (avec un pas de 104 ). On pourra avoir besoin de list_plot() et de stocker des éléments dans une liste avec la fonction append. (4) Qu’en pensez-vous ? Exercice 2. (1) Implémenter le tri rapide avec l’implémentation ci-dessous def quicksort(aList): theList = aList if len(theList)==1: return theList else: early = [] late = [] pivot=floor(random()*len(theList)) pivotValue=theList[pivot] del theList[pivot] for j in [0..len(theList)-1]: if theList[j]<pivotValue: early.append(theList[j]) else: late.append(theList[j]) if len(early)>=1: sortEarly = quicksort(early) else: sortEarly = [] if len(late)>=1: sortLate = quicksort(late) 1 else: sortLate = [] sortEarly.append(pivotValue) for j in [0..len(sortLate)-1]: sortEarly.append(sortLate[j]) return sortEarly (2) Comparer le temps de cette méthode avec l’implémentation où le pivot est choisi à la dernière place (le dernier élément d’une liste a l’indice −1). On fera les tests sur des listes aléatoires puis sur des listes triées de longueur 100 à 1000 avec un pas de 10. Pour afficher deux graphes p1 et p2 superposés, on utilisera la fonction show(p1+p2). Exercice 3. (1) Implémenter le tri par sélection et par insertion. (2) Comparer les temps de ces méthodes sur des listes de longueur croissante avec le temps du tri rapide. On pourra automatiser les tests comme précédemment. 2 2. Graphes Sage possède des fonctions pour gérer les graphes, comme suit • Initialiser un graphe orienté (resp. non orienté) vide avec le constructeur DiGraph() (resp. Graph()). • Ajouter les sommets avec la commande add_vertex ou add_vertices • Ajouter les arcs (resp. arêtes) avec la commande add_edge ou add_edges. Pour connaitre les fonctions implémentés sur les graphes, il suffit d’entrer le nom d’une instance de graphe (par exemple ici on a initialisé G=Graph()), suivi du point ’.’ et faire tab pour que s’affiche la liste des 257 fonctions prédéfinies dans la librairie. Par exemple la fonction G.topological_sort() retourne une liste topologique si le graphe est sans circuit. Exercice 4. On rappelle que la matrice d’incidence d’un graphe orienté G = (S, A) est la matrice ∆ tel que δxa = 1 si x est l’origine de l’arc a, −1 si x est l’extrémité de l’arc a et 0 sinon. (1) Construire et afficher le graphe 0 1 0 0 0 0 0 0 0 0 0 1 0 0 du TD donné par la matrice d’adjacence 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 1 1 0 0 0 0 On souhaite automatiser le passage de la matrice d’adjacence à la matrice d’incidence. (2) Comment lit-on le nombre d’arêtes sur la matrice d’adjacence ? (3) Donner un algorithme qui calcule la matrice d’adjacence à partir de la matrice d’incidence. Quel est son coût ? (4) Donner un algorithme qui calcule la matrice d’incidence à partir de la matrice d’adjacence. Quel est son coût ? On pourra utiliser les fonctions G.adjacency_matrix() ou G.incidence_matrix() déjà implémentées pour obtenir des exemples à partir d’un graphe aléatoire donné par la fonction digraphs.RandomDirectedGNM(10,20) (ici à 10 sommets et 20 arcs). On aura besoin des fonctions Matrix(n,n), nrows(), augment() et delete_columns(). (5) On cherche maintenant à passer du graphe à la matrice d’adjacence. On utilisera pour cela les fonctions neighbors_out(), stack() et delete_rows(). Soit n le nombre de sommets de G. (6) Montrer que pour tout 1 ≤ k ≤ n, le coefficient (i,j), noté mkij , de la matrice M k est égal au nombre de chemins de longueur k du sommet i au sommet j. (7) Essayer sur un exemple. Comparer avec la fonction adjacency_matrix(). Exercice 5. Implémenter les algorithmes de Roy-Warshall et Floyd. Exercice 6. Quelle est la taille du plus grand sous-ensemble S ⊂ {1, . . . , 100} qui ne contient pas i, j tel que |i − j| soit un carré parfait ? Une fois le problème modélisé par un graphe, on pourra utiliser la fonction independent_set() qui retourne un sous-ensemble maximum d’éléments deux à deux non adjacents. 3 3. Multiplication rapide Exercice 7. Implémenter la méthode de Karatsuba. Exercice 8. On cherche à implémenter l’algorithme de la FFT. Notre exemple test sera les polynômes F = x4 + 3x3 + 2x2 + 6x + 7, G = x2 + 2x + 6 sur F17 (pourquoi ce corps ?). Pour trouver une racine n-ième de l’unité, on pourra commencer par chercher un élément primitif avec primitive_element(). (1) Commencer par implémenter la procédure d’évaluation. (2) Implémenter l’algorithme complet avec un choix de racine n-ième. (3) Pour deux polynômes de degré quelconque sur un corps fini k, écrire un programme pour faire la FFT de ces deux polynômes. On pourra avoir besoin des fonctions parent(), (4) Comparer la multiplication usuelle, Karatsuba et la FFT sur F29·257 +1 pour des degrés croissants. 4. Séries formellles, division euclidienne Exercice 9. Implémenter l’algorithme de calcul de la division euclidienne pour les polynômes basé sur l’inversion des séries formelles. On utilisera PowerSeriesRing(QQ) pour définir les séries formelles. L’opération de troncature est truncate(). Exercice 10. Soit F une série formelle de terme constant nul. Écrire un programme qui calcule log(1 + F ) en utilisant l’expression Z F0 log(1 + F ) = . 1+F Exercice 11. Soient a > b deux entiers pour lesquels on veut effectuer la division euclidienne. On propose l’algorithme ci-dessous. Soit n le plus petit entier tel que 2n b > a. B := b; R := a; Q := 0; N := n; Aux := 2N B; while N > 0 do Aux := Aux/2; N := N − 1; if R < Aux then Q := 2 ∗ Q; else Q := 2Q + 1; R := R − Aux; end if; end while; (1) Vérifier qu’à chaque étape on a a = Aux · Q + R et 0 ≤ R < Aux et que si N = 0 on a Aux = B. (2) Donner la complexité de l’algorithme. (3) Écrire le programme correspondant en SAGE. 4 5. Évaluation, évaluation multi-points, interpolation Exercice 12. Dans la méthode de pré-processing pour l’évaluation d’un polynôme de degré 4 (1) a4 x 4 + = = + a3 x3 + a2 x2 + a1 x + a0 a4 ((x(x + α0 ) + α1 )(x(x + α0 ) + x + α2 ) + α3 ) a4 x4 + a4 (2α0 + 1)x3 + a4 (α1 + α2 + α0 (α0 + 1))x2 a4 ((α1 + α2 )α0 + α1 )x + a4 (α1 α2 + α3 ). trouver les αi en fonction des coefficients ai . Exercice 13. Implémenter l’interpolation de Lagrange. On ne cherchera pas à optimer le calcul des Ai . Exercice 14. Implémenter l’évaluation multi-points rapide ainsi que l’interpolation rapide. On pourra créer la structure arborescente de la manière suivante class Tree(object): def __init__(self): self.left = None self.right = None self.data = None Puis pour créer un arbre binaire A de racine un polynôme P et de sous-arbre gauche (resp. droit) A0 (resp. A1 ), on écrit A = Tree() A.data = P A.left = A0 A.right = A1 1 Exercice 15. On considère la fonction f (x) = 1+25x On cherche à interpoler cette 2. fonction aux points a0 = −1, a1 = −1 + h, . . . , ai+1 = ai + h, . . . , 1 avec h = 2/n et n = 2s − 1. Dessiner pour plusieurs valeurs de s le polynôme de Lagrange obtenu et comparer le dessin à celui de f . Qu’observe-t-on ? 6. PGCD - Résultant - Factorisation Exercice 16. Écrire un algorithme qui étant données des listes (m1 , . . . , mr ) d’entiers premiers entre eux deux à deux et une liste d’entiers (a1 , . . . , ar ) renvoie une solution x au système x ≡ a1 (mod m1 ) .. . x ≡ ar (mod mr ) Exercice 17. (1) Trouver les points d’intersection des ellipses d’équations P = 0 et Q = 0 avec P = X 2 − XY + Y 2 − 1 et Q = 2X 2 + Y 2 − Y − 2. Tracer les courbes. La fonction pour le résultant est P.resultant(Q,X). (2) Même exercice dans le cas P = XY − 1 et Q = XY . (3) Fabriquer l’équation implicite de la courbe paramétrée par x = t2 + t + 1, y = (t2 − 1)/(t2 + 1). √ √ √ √ Exercice 18. Calculer le polynôme minimal de 2 + 3 et de Q Q 2 · 3. Conclusion. Soit P (X) = X 4 + X + 1 = (X − αi ). Calculer le polynôme (X − αi5 ). 5 Exercice 19. Soit F une famille de courbes à un paramètre réel t. L’enveloppe de F est l’ensemble des points (x, y) qui vérifient les deux équations ∂F (x, y, t) =0 ∂t F (x, y, t) = 0, pour au moins un t. (1) Calculez l’enveloppe de la famille suivante, en faisant à chaque fois un graphique contenant quelques courbes de la famille et le tracé de l’enveloppe : F (x, y, t) = x2 + (y − t)2 − 1/2(t2 + 1). (2) En supposant que l’enveloppe est une courbe, justifiez cette définition. Exercice 20. On se propose de déterminer la formule donnant l’aire d’un triangle en fonction des longueurs de ses trois côtés a, b, c. Grâce à des calculs de résultants, montrer que 1 S 2 = (a + b − c)(b + a + c)(a − b + c)(−c + a − b). 16 7. Algèbre linéaire Une matrice M de taille (m, n) sur un anneau A peut se définir avec la commande matrix(A,m,n,L]) où L est une liste de coefficients dans A. On peut aussi définir l’espace des matrices qu’on considère par R=MatrixSpace(A,m,n) puis un éléments par R(L), une matrice aléatoire par R.random_matrix(), etc. On peut accéder à un coefficients (i, j) de M par M[i,j]. On peut accéder/modifier toute la colonne j par M[: , j] ou une partie (à partir de la ligne i) par M[i : , j]. Remark 7.1. Attention ! Comme pour les listes, les matrices sont indicées à partir de 0. Exercice 21. (1) En considérant le pivot de Gauss comme l’action de certaines matrices à gauche, effectuer celui-ci sur la matrice 6 2 2 5 4 4 M = 6 4 5 5 1 3 définie sur F7 . Pour échanger deux lignes, on pourra utiliser swap_rows. Exercice 22. La résolution d’un système linéaire Av = b se fait avec la commande solve_right. (1) résoudre un système linéaire aléatoire sur Q. (2) Calculer la décomposition de Dunford M = D + N (avec D diagonalisable, N nilpotente et DN = N D) de la matrice 2 3 2 M = −1 −2 −6 1 1 5 à l’aide d’une suite d’itérations de Newton P (Xn ) Xn+1 = Xn − 0 P (Xn ) où P est le radical du polynôme caractéristique de M en partant de M . Quand la suite devient stationnaire, on obtient D. 6 Exercice 23. Implémenter la multiplication des matrices (de taille une puissance de 2) par la méthode de Strassen. Implémenter ensuite l’inversion matricielle rapide. Exercice 24. Implémenter l’algorithme de Keller-Gehrig pour le calcul du polynôme caractéristique. 7