Projet 1 - Pavages de Penrose & Tours de Hanoï Raphaël Berthon & Xuedong Shang ENS Rennes 5 octobre 2014 Table des matières 1 Pavages de Penrose 2 1.1 Histoire et une petite introduction........................... 2 1.2 Dessiner des pavages................................... 2 1.2.1 Pavages de Penrose avec triangles d or.................... 2 1.2.2 Pavages de Penrose avec losanges....................... 3 1.2.3 Pavages de Penrose avec cerf-volants et fléchettes.............. 4 1.3 Mise en oeuvre...................................... 5 2 Tours de Hanoi 6 2.1 Tours de Hanoi à n anneaux et 3 piquets........................ 6 2.1.1 Présentation du jeu................................ 6 2.1.2 Programmation d une méthode de résolution................ 6 2.1.3 Complexité et optimalité............................. 6 2.2 Généralisation à n anneaux et k piquets........................ 6 2.2.1 Présentation.................................... 6 2.2.2 Premier algorithme................................ 7 2.2.3 Second algorithme................................ 7 2.3 Résultats et commentaires................................ 7 3 Conclusion 8 A Annexe : auto-évaluation 9 Résumé Ceci est un rapport pour le premier projet du cours Programmation 1. Il s agit, d une part, de dessiner des pavages de Penrose, et d autre part, de résoudre le problème des tours de Hanoï. Les deux parties ont été faites indépendemment. Le rapport est donc lui aussi divisé deux parties : la première porte sur les pavages de Penrose, la seconde sur les tours de Hanoï. Mots-clés. Pavages non périodiques, jeu de Hanoï, récursivité. 1
1 Pavages de Penrose 1.1 Histoire et une petite introduction En mathématiques, les pavages de Penrose sont des pavages du plan découverts par le mathématicien et physicien britannique Roger Penrose dans les années 1970. Les pavages de Penrose sont des pavages non périodiques caractérisables par des règles locales. Les 17 pavages périodiques du plan étaient connus de longue date quand Roger Penrose s est intéressé aux pavages non périodiques. Son intention initiale n était pas d ouvrir un nouveau champ des mathématiques et de la physique mais seulement de créer un divertissement mathématique. Les pavages de Penrose ne seraient restés qu un joli divertissement mathématique si, en 1984, n avaient été découverts des matériaux présentant une structure fortement ordonnée (comme celle des cristaux) mais non périodique : les quasi-cristaux. Les pavages non périodiques, en particulier ceux de Penrose, s avérèrent alors un modèle utilisable de ces étranges matériaux. 1.2 Dessiner des pavages 1.2.1 Pavages de Penrose avec triangles d or Il existe de nombreuses façons de définir un triangle d or, voici une définition simple : Définition 1. Un triangle d or est un triangle isocèle possédant la propriété (P) suivante : pouvoir être découpé en 2 triangles isocèles inégaux et possédant à leur tour la propriété (P). Il n existe que deux types de triangles d or, le type aigu (A) et le type obtus (O). Le type aigu a pour l angle de sommet 36 tandis que le type obtus a pour l angle de sommet 108. Le pavage se fait en décomposant des triangles d or d une manière ou l autre. L idée de l algorithme est de générer une liste de triangles de la forme (color, A, B, C) dont color représente la couleur du triangle, et A, B, C sont les trois coordonnées (représenées par les nombres Complex dans mon code). A chaque découpage d un triangle (A), on va générer un triangle (A) et un triangle (O). Après le découpage, un nouveau point P s introduit, il se situe sur le côté AB et satisfait le nombre d or : FIGURE 1 Le découpage d un triangle aigu. D une manière analogue, on découpe un triangle (O) en deux triangles (O) et un triangle (A). Après le découpage, deux nouveaux points s introduisent dont Q se trouve sur AB tandis que R se trouve sur BC : 2
FIGURE 2 Le découpage d un triangle obtus. Le découpage se fait en OCaml avec quelques lignes de codes. Il s agit d une fonction subdivide qui prend comme argument une liste de triangles, les découpe un par un, puis retourne la nouvelle liste de triangles. let subdivide triangles = let result = ref [] in let aux (color, a, b, c) = if color = 0 then let p = Complex.add a (Complex.div (Complex.sub b a) phi) in result := (0, c, p, b) :: (1, p, c, a) :: (!result) else let q = Complex.add b (Complex.div (Complex.sub a b) phi) and r = Complex.add b (Complex.div (Complex.sub c b) phi) in result := (1, r, c, a) :: (1, q, r, b) :: (0, r, q, a) :: (!result) in List.iter aux triangles;!result La construction du pavage avec triangles d or n est pas unique : en effet, chaque découpage peut s effectuer d au moins deux façons différentes, ce qui conduit assez souvent à des pavages peu élégants. 1.2.2 Pavages de Penrose avec losanges On cherche maintenant à paver le plan à l aide des figures géométriques simples comme par exemple les deux losanges suivants : FIGURE 3 Les deux types de losanges. Il s agit ici aussi d une construction par découpage : il suffit de découper chaque gros losange en un gros losange, deux fins demi-losanges et deux gros demis-losanges, et chaque fin losange en deux fins demi-losanges et deux gros demi-losanges. 3
Pour construire un pavage de losanges, on peut par exemple initialiser la liste de triangles avec 10 triangles (A) autour de l origine. Il faut faire bien attention lors de l initialisation, chaque couple de voisins doit être symétrique par rapport à leur côté commun. La cohérence d un tel procédé est assuré par le fait que les triangles ainsi générés s associent toujours avec leur voisin pour former un losange complet en adaptant le découpage présenté dans la section précédente. Voici un bout de code pour réaliser cette démarche, on échange donc b et c lorsque i est pair : for i = 0 to 9 do let b = ref (Complex.polar 400. ((2..(float_of_int i)+.1.).pi/.10.)) and c = ref (Complex.polar 400. ((2..(float_of_int i).1.).pi/.10.)) in let tmp = ref Complex.zero in if i mod 2 = 0 then begin tmp :=!b; b :=!c; c :=!tmp end; rhombus := (0, Complex.zero,!b,!c) :: (!rhombus) done On obtient finalement un pavage comme montré ci-dessous : FIGURE 4 Le pavage avec losanges. 1.2.3 Pavages de Penrose avec cerf-volants et fléchettes On peut concevoir un autre type de pavage aussi. En réunissant deux triangles d or (A) ayant pour sommet commun le sommet dont la bissectrice est un axe de symétrie pour les deux autres sommets, on obtient un pavé en forme de cerf-volant. De même, si on fait la construction avec deux triangles (O), on obtient un pavé en forme de fléchette. On peut toujours définir un algorithme de construction par découpage. A chaque étape, on découpe chaque cerf-volant en deux cerfs-volants et deux demi-fléchettes, et on découpe une fléchette en un cerf-volant et deux demi-fléchettes. 4
FIGURE 5 Cerf-volant et fléchette. FIGURE 6 Cerf-volant et fléchette découpés. Ainsi, afin de former un pavage bien cohérent, il faut donc changer la stratégie du découpage. Voici un bout de code associé, on voit une différence claire entre celui-ci et celui décrit en première section : if color = 1 then let p = Complex.add b (Complex.div (Complex.sub c b) phi) in result := (1, p, c, a) :: (0, b, a, p) :: (!result) else let q = Complex.add a (Complex.div (Complex.sub b a) phi) in let r = Complex.add c (Complex.div (Complex.sub a c) phi) in result := (0, c, q, b) :: (0, c, q, r) :: (1, r, a, q) :: (!result) La cohérence du procédé est assurée par le fait que les demi-fléchettes ainsi générées s associent toujours avec leur voisine pour reconstituer une fléchette complète. 1.3 Mise en oeuvre Dans mon programme, j ai aussi réaliséune petite interface utilisateurs permettant de choisir le type de découpage, les couleurs et le nombre de générations. Cependant, l animation est encore loin d être esthétique. J ai aussi pensé à réaliser un "step back", un coloriage plus varié, etc., mais sans avoir le temps de finir. 5
2 Tours de Hanoi 2.1 Tours de Hanoi à n anneaux et 3 piquets 2.1.1 Présentation du jeu Le jeu de Hanoi est constitué de n anneaux et de 3 piquets. Les anneaux sont placés initialement par ordre de taille décroissante sur le premier piquet, et le but est de déplacer tous les anneaux jusqu au troisième piquet en ne déplaçant qu un anneau à la fois, et en ne déplaçant jamais un anneau sur un autre aneau plus petit. 2.1.2 Programmation d une méthode de résolution On appellera piquet de départ le piquet où les anneaux sont initialement, piquet d arrivée celui où on doit les emmener, et piquet intermédiaire le piquet restant. Si on sait déplacer (n-1) anneaux d un piquet à une autre, il suffit de déplacer ces (n-1) anneaux sur le piquet n étant ni celui de départ ni celui d arrivée, de déplacer le dernier anneau à l arrivée, puis les (n-1) autres à l arrivée. Par conséquent, un moyen pour obtenir un algorithme résolvant les tours de Hanoi est d appliquer ce processus récursivement ; puisque l algorithme s appelle récursivement deux fois, mais avec un nombre d anneaux déplacés récursivement diminue strictement, et que l on sait déplacer un anneaux d une pique à une autre, le procesus terminera, et sera correct. 2.1.3 Complexité et optimalité La complexité de l algorithme vérifie donc pour tout n entier positif : C(1) = 1 C(n) = 2 C(n 1) + 1 On obtient une complexité en O(2 n ). De plus, cet algorithme est optimal : n = 1, l algorithme est optimal. n 2, en supposant que l algorithme est optimal pour les valeurs inférieures, l unique moyen optimal de déplacer le dernier anneau est d avoir déplacé les (n-1) précédents sur le piquet du milieu optimalement, de déplacer le dernier anneau, puis de redéplacer optimalement les (n-1) anneaux. C est ce que fait l algorithme, qui est donc optimal. 2.2 Généralisation à n anneaux et k piquets 2.2.1 Présentation Le jeu de Hanoi peut être généralisé en utilisant non plus 3 mais k piquets. L existence d une solution avec 3 piquets assure l existence d une solution avec k piquets quel que soit le nombre d anneaux. On en vient ainsi à chercher une solution optimale (demandant le moins de coups) pour k piquets et n anneaux. 6
2.2.2 Premier algorithme Pour rechercher cette solution, la première idée a été non plus d utiliser une résolution directe, mais de lister toutes les suites de coups autorisées (le programme ne déplace pas un anneau sur un anneau plus petit) demandant moins de 2 n 1 mouvements (qui correspond à une solution n utilisant que trois piquets), et de retenir celle (ou une de celles) qui avait nécessité le moins de déplacements d anneaux. Cette méthode est cependant trop longue pour être efficace (le programme essaie les n(n 1) possibilités, et cela sur 2 n 1 coups ; on obtient une complexité en O((n 2 ) 2n ). De plus, on peut noter que lorsque le nombre de piquets augmente, le nombre de coups diminue ; la complexité de l algorithme ne correspond pas à la complexité réelle du problème. 2.2.3 Second algorithme La seconde solution fut de continuer à énumérer tous les coups possibles, mais non plus en allant jusqu au maximum de coups possible, mais en augmentant progressivement le nombre de coups autorisés. La complexité étant plus qu exponentielle, la complexité du programme sur n coups est négligeable par rapport à celle sur (n+1) coups. De plus, cela rend les solutions avec peu de piquets et d anneaux plus accessibles (dans les faits, ce sont d ailleurs les seuls accessibles). A ce programme, quelques modifications mineures ont été apportées ; ainsi, le coup précédent est enregistré, pour éviter de faire faire des allers-retour inutiles (et coûteux en temps) aux des anneaux. Il a aussi fallu faire un choix sur l ordre des piquets testés pour chaque coups, lorsqu un anneau est déplacé depuis un départ jusqu à une arrivée. Le but est de sortir les anneaux du premier piquet pour les mettre sur le dernier ; par conséquent, le programme essaie comme départ d abord depuis le premier piquet, puis le deuxième... jusqu au dernier. Pour ce qui était de déterminer où ils étaient déplacés, on peut remarquer que tous les piquets du milieu sont équivalents ; de plus, le dernier piquet étant là où on cherche à déplacer les anneaux, il a donc été décidé que le programme commencerait par déplacer les anneaux vers ce dernier piquet. 2.3 Résultats et commentaires Le programme a permis d accéder à des coups optimaux pour de petites valeurs de n (de 3 à 5). On observe alors qu à part pour k = 3 et k n + 1, le nombre de coups en fonction du nombre d anneaux semble être affine, de pente 2. On a alors envie de supposer l existence d un algorithme optimal qui résolve les tours de Hanoi en O(n) Cela n est cependant pas le cas ; le problème n est pas linéaire, mais au mieux linéaire par morceaux. Il est aisé de voir que si k n + 1, les solutions optimales déplaceront les (n-1) premiers aneaux sur (n-1) piquets intermédiaires, déplaceront le dernier anneau sur le piquet final, puis replaceront le (n-1) autres anneaux sur les piquets final ; cela se fait en 2n 1 coups quel que soit le nombre de piquets vérifiant l inégalité. Si on obtient une courbe linéaire pour certaines valeurs, c est que l on peut appliquer 7
une technique avec k piquets, n k 2n 1. En effet, on peut appliquer la méthode précédente, puis lorsqu il n y aura plus assez de piquets, on pourra alors poser le plus petit anneau sur l anneau juste plus grand, le troisième plus petit sur le quatrième... Une fois cela fait, on recommencera à déplacer un anneau par piquet, puis à la grouper par deux si nécessaire, et enfin on déplacera le grand anneau sur l arrivée. Ensuite, on appliquera les opérations inverses sur les autres anneaux pour les mettre sur l arrivée. On aura alors besoin de (2n 1) + (2n (2k 1)) = (2n 1) + 2(n k + 1) = 4n 2k + 1 coups. Mais cette méthode ne fonctionne pas avec par exemple 6 anneaux et 4 piquets! Je n ai cependant pas eu le temps de généraliser la complexité d une telle méthode, qui semble pourtant se révéler efficace. 3 Conclusion Ce projet nous a permis d apprendre à manipuler les outils graphiques OCaml, créer une petite interface utilisateurs, mais aussi utiliser des résultats d un programme pour essayer d améliorer ce même programme, en lui faisant plus rapidement essayer les bonnes méthodes. Le travail de groupes a cependant été peu présent, et quelques points n ont pas été poussés à leur plein potentiel. 8
A Annexe : auto-évaluation Points forts Contenu du rendu bien organisé, codes sources, Makefile, README, etc. Bonne prévention des problèmes cités ci-après, avec un partage des documents efficace. Division des parties qui s est avérée efficace. Capacité à changer de méthode et de structure de données lorsque l approche d un problème change (que ce soit comment calculer les découpages de Penrose, ou les mouvements de Hanoi) Points faibles Mauvaise communication entre partenaires (suite à divers problèmes d internet notamment). La présentation mal organisée au niveau de la gestion du temps. Des difficultés à rendre la présentation compréhensible dûe à une difficulté en français soutenu d un coté, une difficulté à gérer le stress de l autre. Plusieurs idées qui n ont pas été menées à bout, que ce soit pour les pavages ou les tours. Améliorations possibles Ne pas terminer le projet la veille du rendu. Préparer la présentation pour être plus à l aise lors des soutenances. Discuter plus avec son partenaire. Difficultés à anticiper Difficulté à s exprimer dans une ambiance formelle. Peu habitués à travailler en groupe. 9