rapport.tex (124163B)
1 \documentclass{article} 2 3 \usepackage[utf8]{inputenc} 4 \usepackage[T1]{fontenc} 5 \usepackage[frenchb]{babel} 6 \usepackage{tikz} 7 \usepackage{amsmath} 8 \usepackage{listings} 9 \usepackage{amssymb} 10 \usepackage{pdfpages} 11 \usetikzlibrary{chains,positioning,matrix,arrows,decorations,calc,fit} 12 %\usepackage{hyperref} 13 \usetikzlibrary{chains,positioning,matrix,arrows,decorations,calc} 14 \title{Rapport de projet : FMIN105\\ Cours algorithmique / complexité / calculabilité} 15 \author{\textsc{Bonavero} Yoann \\ \textsc{Brun} Bertrand \\ \textsc{Charron} John \\ \textsc{Dupéron} Georges} 16 \date{} 17 18 \lstset{ 19 language=C, %% Preload 20 language=Lisp, %% Preload + default 21 showspaces=false, 22 showstringspaces=false, 23 showtabs=false, 24 tabsize=4, 25 columns=flexible% if this is not enough, use columns=fullflexible. 26 } 27 28 \setlength{\parindent}{0pt} 29 \setlength{\parskip}{2ex} 30 31 \newcounter{exocount} 32 \setcounter{exocount}{0} 33 34 \newcounter{enoncecount} 35 \setcounter{enoncecount}{0} 36 37 \newenvironment{enonce} 38 { 39 \stepcounter{enoncecount} 40 \bf\small \arabic{enoncecount}. 41 \begin{bf} 42 } 43 { 44 \end{bf} 45 } 46 47 48 \newcounter{sousenoncecount} 49 \setcounter{sousenoncecount}{0} 50 \newenvironment{sousenonce} 51 { 52 \stepcounter{sousenoncecount} 53 \bf\small (\alph{sousenoncecount}) 54 \begin{bf} 55 } 56 { 57 \end{bf} 58 } 59 60 \begin{document} 61 \includepdf{couverture.pdf} 62 \setcounter{page}{0} 63 \pagestyle{empty} 64 \thispagestyle{empty} 65 \tableofcontents 66 \pagestyle{empty} 67 \thispagestyle{empty} 68 \newpage 69 \pagestyle{plain} 70 71 72 \section{Descriptif des tâches} 73 Vos résultats seront présentés en procédant à la rédaction d'un mémoire dont la qualité influencera la note finale. Ce manuscrit sera rendu le jour de la soutenance. La soutenance consiste à présenter résultats pratiques (choix du langage, choix des structures de données, résultats obtenus, tests sur un grand jeu de données, analyse de ceux-ci ...). Vous aurez 15 minutes au maximum, questions comprises. Vous avez la possibilité d'utiliser des transparents. 74 75 76 \section{Partie théorique} 77 \subsection{Partie algorithmique} 78 79 \subsubsection*{Exercice \stepcounter{exocount}\bf\small \arabic{exocount} -- Modélisation et résolution d'un problème d'ordonnancement par un problème de flot maximum : ordonnancement avec coûts dépendants des dates de début} 80 \addcontentsline{toc}{subsubsection}{Exercice \arabic{exocount} -- Modélisation et résolution d'un problème d'ordonnancement par un problème de flot maximum : ordonnancement avec coûts dépendants des dates de début} 81 82 83 84 \begin{figure}[h!] 85 \centering 86 \begin{tikzpicture}[node distance=3cm] 87 \node (J1) {$J_{1}$}; 88 \node (J2) [above of=J1] {$J_{2}$}; 89 \node (J3) [right of=J1] {$J_{3}$}; 90 \draw[->] (J1) -- (J2); 91 \draw[->] (J1) -- (J3); 92 \draw[->] (J3) -- (J2); 93 \end{tikzpicture} 94 \caption{Graphe G} 95 \label{fig:graphe-g} 96 \end{figure} 97 98 \begin{enonce} 99 Construire le graphe $G^*$ pour $n = 3$, $T = 5$, $p_1 = 1$, $p_2 = 2$, $p_3 = 1$, 100 $E = \{(1,2), (1,3), (3,2)\}$ et les coûts suivants : 101 \end{enonce} 102 103 \begin{figure}[ht!] 104 \centering 105 \begin{tabular}{cccccc} 106 \hline 107 $i,t$ & 0 & 1 & 2 & 3 & 4\\ 108 \hline 109 1 & 0 & 2 & 5 & 0 & 1\\ 110 2 & 1 & 1 & 2 & 4 & -\\ 111 3 & 1 & 10 & 2 & 3 & 3\\ 112 \hline 113 \end{tabular} 114 \end{figure} 115 116 \begin{figure}[ht!] 117 \centering 118 \colorlet{affectation}{green!75!black} 119 \colorlet{auxiliaire}{black} 120 \colorlet{précédence}{blue} 121 \begin{tikzpicture}[ 122 affectation/.style = { 123 draw=affectation, 124 -> 125 }, 126 auxiliaire/.style = { 127 draw=auxiliaire, 128 -> 129 }, 130 précédence/.style = { 131 draw=précédence, 132 -> 133 }, 134 capacité/.style = { 135 fill=white, 136 font=\footnotesize 137 }, 138 capacité affectation/.style = { 139 text=affectation, 140 capacité 141 }, 142 capacité auxiliaire/.style = { 143 text=auxiliaire, 144 capacité 145 }, 146 capacité précédence/.style = { 147 text=précédence, 148 capacité 149 } 150 ] 151 152 \matrix[matrix of math nodes, nodes in empty cells, row sep=1cm, column sep=0.9cm] (m) { 153 & v_{1,0} & v_{1,1} & v_{1,2} & v_{1,3} & v_{1,4} & v_{1,5} & \\ 154 s & v_{3,0} & v_{3,1} & v_{3,2} & v_{3,3} & v_{3,4} & v_{3,5} & t \\ 155 & v_{2,0} & v_{2,1} & v_{2,2} & v_{2,3} & v_{2,4} & & \\ 156 }; 157 158 %% Penser a rajouter les J1, J2 et J3 a gauche du graphe. 159 160 \draw[affectation] (m-1-2)-- node[capacité affectation]{0} (m-1-3); 161 \draw[affectation] (m-1-3)-- node[capacité affectation]{2} (m-1-4); 162 \draw[affectation] (m-1-4)-- node[capacité affectation]{5} (m-1-5); 163 \draw[affectation] (m-1-5)-- node[capacité affectation]{0} (m-1-6); 164 \draw[affectation] (m-1-6)-- node[capacité affectation]{1} (m-1-7); 165 166 \draw[affectation] (m-2-2)-- node[capacité affectation]{1} (m-2-3); 167 \draw[affectation] (m-2-3)-- node[capacité affectation]{10} (m-2-4); 168 \draw[affectation] (m-2-4)-- node[capacité affectation]{2} (m-2-5); 169 \draw[affectation] (m-2-5)-- node[capacité affectation]{3} (m-2-6); 170 \draw[affectation] (m-2-6)-- node[capacité affectation]{3} (m-2-7); 171 172 \draw[affectation] (m-3-2)-- node[capacité affectation]{1} (m-3-3); 173 \draw[affectation] (m-3-3)-- node[capacité affectation]{1} (m-3-4); 174 \draw[affectation] (m-3-4)-- node[capacité affectation]{2} (m-3-5); 175 \draw[affectation] (m-3-5)-- node[capacité affectation]{4} (m-3-6); 176 177 \draw[auxiliaire] (m-2-1)-- node[capacité auxiliaire]{$\infty$} (m-1-2); 178 \draw[auxiliaire] (m-2-1)-- node[capacité auxiliaire]{$\infty$} (m-2-2); 179 \draw[auxiliaire] (m-2-1)-- node[capacité auxiliaire]{$\infty$} (m-3-2); 180 \draw[auxiliaire] (m-1-7)-- node[capacité auxiliaire]{$\infty$} (m-2-8); 181 \draw[auxiliaire] (m-2-7)-- node[capacité auxiliaire]{$\infty$} (m-2-8); 182 \draw[auxiliaire] (m-3-6)--(m-3-7.center)-- node[capacité auxiliaire]{$\infty$} (m-2-8); 183 184 \draw[précédence] (m-1-2)-- node[capacité précédence]{$\infty$} (m-2-3); 185 \draw[précédence] (m-1-3)-- node[capacité précédence]{$\infty$} (m-2-4); 186 \draw[précédence] (m-1-4)-- node[capacité précédence]{$\infty$} (m-2-5); 187 \draw[précédence] (m-1-5)-- node[capacité précédence]{$\infty$} (m-2-6); 188 \draw[précédence] (m-1-6)-- node[capacité précédence]{$\infty$} (m-2-7); 189 190 \draw[précédence] (m-2-2)-- node[capacité précédence]{$\infty$} (m-3-3); 191 \draw[précédence] (m-2-3)-- node[capacité précédence]{$\infty$} (m-3-4); 192 \draw[précédence] (m-2-4)-- node[capacité précédence]{$\infty$} (m-3-5); 193 \draw[précédence] (m-2-5)-- node[capacité précédence]{$\infty$} (m-3-6); 194 195 \draw[précédence] (m-1-2)-- node[capacité précédence,pos=0.3]{$\infty$} (m-3-3); 196 \draw[précédence] (m-1-3)-- node[capacité précédence,pos=0.3]{$\infty$} (m-3-4); 197 \draw[précédence] (m-1-4)-- node[capacité précédence,pos=0.3]{$\infty$} (m-3-5); 198 \draw[précédence] (m-1-5)-- node[capacité précédence,pos=0.3]{$\infty$} (m-3-6); 199 \end{tikzpicture} 200 \caption{Graphe $G^*(X^*, E^*)$} 201 \label{fig:graphe-g*} 202 \end{figure} 203 204 205 206 \begin{enonce} 207 Montrer qu'il existe une coupe dans $G^*$ de capacité minimale de laquelle sort un et un seul arc d'affectation par job. 208 \end{enonce} 209 210 Démonstration par construction~: 211 On effectue un tri topologique sur le graphe des contraintes de précédence $G(\{J_1, \dots, J_n\}, E)$. Ce tri topologique nous donne un 212 ensemble ordonné de n\oe uds $(J_{a1}, \dots, J_{an})$. On a donc~: 213 $$\forall j < i \quad (J_{aj}, J_{ai}) \not\in E$$ 214 On transforme ensuite $G$ en un graphe de flots $G^*(X^*,E^*)$ à l'aide de l'algorithme fourni dans le sujet. 215 Considérons les arcs entre les $v_{ai,t}$~: 216 \begin{itemize} 217 \item Arcs d'affectation~: ces arcs sont entre des sommets $v_{ai,t}$ et $v_{aj,t'}$ avec $ai = aj$ 218 \item Arcs de précédences~: ces arcs sont entre des sommets $v_{ai,t}$ et $v_{aj,t'}$ avec $ai < aj$, car grâce au tri topologique, il 219 n'existe pas d'arcs entre des sommets $J_{ai}$ et $J_{aj}$ avec $aj < ai$, et de plus il n'y a pas de boucle (donc pas d'arc 220 $(J_{ai},J_{ai})$ dans $E$, donc pas d'arc $(v_{ai,t}, v_{ai,t'})$ dans $E^*$). 221 \item Arcs auxiliaires~: ces arcs ne sont pas entre des sommets $v_{ai,t}$. 222 \end{itemize} 223 224 Soit un $(s-t)-\mathrm{coupe}$ minimale, entre les ensembles de noeuds $S$ et $T$. Etant donné que cette coupe est minimale, aucun arc de 225 capacité infinie n'a son origine dans $S$ et son extremité dans $\overline{S}$. Autrement dit, en fonction des noeuds présents dans S, on 226 est donc \og obligé\fg{} d'inclure dans $S$ toutes les extrémités des arcs de capacité infinie et dont l'origine est dans $S$. On va donc 227 construire $S$ itérativement en suivant cette règle. 228 229 \begin{itemize} 230 \item $s \in S$ et tous les arcs sortants de $s$ sont les arcs auxiliaires de capacité infinie qui pointent sur tous les $v_{ai,0}$. On 231 les inclut donc dans $S$. 232 \item Pour chaque $v_{ai,t}$ dans $S$ on n'a pas besoin de suivre les arcs d'affectation car ils sont de capacité finie. Comme ces arcs 233 d'affectation \og restent sur la même ligne\fg, à partir du moment où un $v_{ai,t}$ est présent dans $S$, les arcs d'affectation ne nous 234 obligent pas à inclure les $v_{ai,t'}$ avec $t' > t$. 235 \item Par contre les arcs de précédence nous obligent, lorsqu'on inclut un $v_{ai,t}$, d'inclure tous les $v_{aj,t'}$ qui sont à l'extrêmité 236 d'un arc de précédence partant de ce $v_{ai,t}$. 237 \end{itemize} 238 239 Puisque la coupe est minimale et que tous les $v_{ai,0}$ font partie de $S$, lorsqu'un $v_{ai,t}$ fait partie de S, alors tous les 240 $v_{ai,t'}$ avec $0 \leq t' \leq t$ font aussi partie de $S$ (car sinon on ajoute le coût des arcs d'affectation intermédiaires). 241 242 On a donc $s \in S$ et 243 \begin{equation} 244 \forall ai \quad \exists t \quad (0 <= t' <= t) \Leftrightarrow (v_{ai,t} \in S) 245 \label{eq:tous-t-debut-ligne} 246 \end{equation} 247 248 Il ne sort donc qu'un et un seul arc d'affectation par job dans toute coupe minimale. 249 250 Évidemment, cette coupe minimale ne peut exister que s'il y a «suffisemment de temps pour tout faire», autrement dit, si la somme des durées 251 d'exécution des tâches est supérieure au temps disponible, on ne pourra pas effectuer toutes les tâches. 252 253 \begin{enonce} 254 Montrer que l'on peut associer un ordonnancement réalisable (qui respecte toutes les contraintes) à toute 255 coupe de capacité finie minimale dans le graphe. Quel est le coût de cet ordonnancement ? 256 \end{enonce} 257 258 Dans l'exercice précédent, on a montré que de toute coupe minimale sort un et un seul arc d'affectation par job. 259 260 On cherche à associer un ordonancement réalisable à toute coupe minimale. 261 262 On va construire cet ordonancement de la manière suivante~: à chaque 263 fois qu'un arc d'affectation $v_{ai,t}, v_{ai,t+1}$ traverse la coupe, 264 on exécute le job $ai$ à l'instant $t$ dans l'ordonancement. 265 266 \textbf{Cherchons un ordonancement}, un ensemble de paires $(\text{tâche},\text{date de début})$ respectant les dépendances. 267 Autrement dit, chaque tâche apparaît après ses dépendances dans la suite. 268 269 Soit $te(ai) = t$ la fonction qui à un job $ai$ associe son temps de début d'exécution $t$. 270 Nous allons montrer que~: 271 $$(\exists ai,t,aj,t' \quad (v_{ai,t},v_{aj,t'}) \in E^*) \qquad \Rightarrow \qquad (te(ai) > te(aj) \quad \Leftrightarrow \quad ai > aj)$$ 272 Cela signifie que s'il existe un arc de précédence entre deux noeuds, alors le job qui 273 correspond au noeud «le plus haut» s'exécute avant le job qui correspond au 274 noeud «le plus bas». 275 276 En effet, si $t = te(ai)$ est le temps de début d'exécution du job $ai$, alors c'est que $v_{ai,t}, v_{ai,t+1}$ 277 traverse la coupe, et donc : 278 \begin{equation} 279 \forall tt \quad v_{ai,tt} \in S \Leftrightarrow tt <= t 280 \label{eq:tous-t-avant-exec} 281 \end{equation} 282 283 Il en va de même pour $\forall tt' <= t' \quad v_{aj,tt'} \in S$. 284 285 Comme il y a un arc d'affectation du job $ai$ vers le job $aj$, 286 $$\exists\ {} tdest > t \quad (v_{ai,t},v_{aj,tdest}) \in E^*$$ 287 et vu que la capacité de cet arc de précédence est infinie, $tdest \in S$. En utilisant les équations \ref{eq:tous-t-debut-ligne} et 288 \ref{eq:tous-t-avant-exec}, on peut affirmer que $tdest <= t$. Nous avons donc bien montré que l'arc d'affectation entre la tâche $ai$ et la 289 tâche $aj$ «forçait» $aj$ à s'exécuter après $ai$. 290 291 Grâce au tri topoligique, nous pouvons affirmer que tous les arcs de précédence entrants dans le noeud $v_{ai,te(ai)}$ viennent d'une ligne 292 «plus haute», autrement dit d'un noeud $v_{aj,t'}$ avec $aj < ai$. Et grâce à ce que nous avons prouvé précédemment, 293 on sait que $te(aj) < te(ai)$. 294 295 \textbf{On cherche un ordonancement réalisable}, c'est-à-dire pour lequel 296 toutes les tâches peuvent être menées à bout durant le temps 297 imparti. 298 299 300 La propriété énoncée dans la question 2 de l'exercice 1 nous indique que de toute coupe minimale sort un et un seul arc d'affectation par 301 job. Cela signifie que chaque job a commencé à être exécuté. Comme il exite un noeud pour le job $aj$ à l'instant $t$ si et seulement s'il y 302 a le temps de l'exécuter (\ogà chaque date de début possible\fg), cela signifie que tous les jobs commencés ont eu le temps d'être terminés 303 et, comme nous venons de voir, que tous les jobs ont pu être commencés -- ils ont tous pu être terminés -- et, par conséquent, 304 l'ordonancement est réalisable. 305 306 \begin{enonce} 307 Montrer qu'à tout ordonnancement réalisable correspond une coupe dont la capacité est égale au coût de l'ordonnancement. 308 \end{enonce} 309 310 On construit la coupe à partir de l'ordonancement de la même manière 311 qu'on a construit l'ordonancement à partir de la coupe dans l'exercice 312 précédent, mais en suivant l'algorithme dans l'autre sens. 313 314 Si on exécute le job $ai$ à l'instant $t$ dans l'ordonancement, alors 315 tous les noeuds $v_{ai,t'}$ avec $t' \leq t$ sont dans la partie \og 316 gauche\fg{} de la coupe. De plus, $s$ appartient lui aussi à la partie 317 gauche de la coupe et aucun arc de précédence ne sort de la coupe. 318 319 La capacité de cette coupe est la somme de la capacité de tous les 320 arcs qui sortent de la coupe, c'est-à-dire la somme des capacités des 321 arcs $v_{ai,t}, v_{ai,t+1}$. Comme la capacité de ces arcs est égale au 322 coût d'exécution de la tâche $ai$ à l'instant $t$, on a bien égalité entre 323 la somme des capacités et la somme des coûts de démarrage des jobs, 324 donc la capacité de la coupe est égale au coût de l'ordonancement. 325 326 327 \subsubsection*{Exercice \stepcounter{exocount}\bf\small \arabic{exocount} -- Coupes et chemins arc-disjoints} 328 \addcontentsline{toc}{subsubsection}{Exercice \arabic{exocount} -- Coupes et chemins arc-disjoints} 329 \setcounter{enoncecount}{0} 330 331 \begin{enonce} 332 Calculer le nombre maximum des chemins d'arcs disjoints à partir de la source jusqu'au puits dans le réseau donné par la figure 1. 333 \end{enonce} 334 335 Il existe un ensemble de chemins d'arcs disjoints de cardinal 3~: 336 337 $$ 338 \begin{array}{ccccccc} 339 1 & \rightarrow & 2 & \rightarrow & 3 & \rightarrow & 6 \\ 340 1 & \rightarrow & 3 & \rightarrow & 4 & \rightarrow & 6 \\ 341 1 & \rightarrow & 4 & \rightarrow & 5 & \rightarrow & 6 \\ 342 \end{array} 343 $$ 344 345 Cherchons s'il en existe un de cardinal 4. Voici la liste des chemins 346 obtenue par un parcours en profondeur (en prennant toujours en premier 347 les sommets voisins avec le numéro le plus petit possible)~: 348 349 %% TODO~: numéroter les "équations" «proprement». Mais il semble que LaTeX ne permette pas de numéroter les lignes d'une matrice sans se casser la tête :-( 350 %% Ou sinon, il faut utilise \begin{align}/\end{align}, mais On ne peut pas choisir l'espacement des colonnes (et il est beaucoup trop gros à ce moment-là. 351 $$ 352 \begin{array}{cccccccccccr} 353 1 & \rightarrow & 2 & \rightarrow & 3 & \rightarrow & 4 & \rightarrow & 5 & \rightarrow & 6 & \quad (A) \\ 354 1 & \rightarrow & 2 & \rightarrow & 3 & \rightarrow & 4 & \rightarrow & 6 & & & \quad (B) \\ 355 1 & \rightarrow & 2 & \rightarrow & 3 & \rightarrow & 6 & & & & & \quad (C) \\ 356 1 & \rightarrow & 3 & \rightarrow & 4 & \rightarrow & 5 & \rightarrow & 6 & & & \quad (D) \\ 357 1 & \rightarrow & 3 & \rightarrow & 4 & \rightarrow & 6 & & & & & \quad (E) \\ 358 1 & \rightarrow & 3 & \rightarrow & 6 & & & & & & & \quad (F) \\ 359 1 & \rightarrow & 4 & \rightarrow & 5 & \rightarrow & 6 & & & & & \quad (G) \\ 360 1 & \rightarrow & 4 & \rightarrow & 6 & & & & & & & \quad (H) \\ 361 \end{array} 362 $$ 363 364 Voyons les ensembles qui contiennent le chemin $A$~: On ne peut pas 365 prendre les chemins $B$ et $C$ car ils ont l'arc $(1,2)$ en commun 366 avec $A$. On ne peut pas prendre non plus les chemin $D$ et $G$ car 367 ils ont l'arc $(5,6)$ en commun avec $A$ ni le chemin $E$ à cause de 368 l'arc $(3,4)$. Il ne reste plus que les chemins $F$ et $H$ qu'on 369 pourrait peut-être prendre si on prend $A$, mais le cardinal de 370 l'ensemble serait alors 3, donc on n'améliorerait pas le résultat 371 existant. En conséquence, ce n'est pas la peine de chercher si ces chemins 372 sont \og compatibles\fg{} avec $A$. 373 374 Procédons de la même manière pour $B$ (sachant que $A$ ne peut pas 375 faire partie de l'ensemble). Si on a le chemin $B$, alors on ne peut 376 pas avoir~: 377 \begin{itemize} 378 \item $C$ (arc $(2,3)$), 379 \item $D$ (arc $(3,4)$), 380 \item $E$ (arc $(3,4)$), 381 \item $H$ (arc $(4,6)$). 382 \end{itemize} 383 À partir de ce moment, il ne reste plus que $F$ et $G$, l'ensemble 384 serait de cardinal 3, donc $B$ ne peut pas être dans un ensemble de 385 cardinal 4. 386 387 Passons à $D$ avec $A$ et $B$ exclus. On ne peut pas avoir~: 388 \begin{itemize} 389 \item $E$ (arc $(3,4)$), 390 \item $F$ (arc $(1,3)$), 391 \item $G$ (arc $(4,5)$). 392 \end{itemize} 393 Donc $D$ n'est pas dans l'ensemble. 394 395 Passons à $F$ avec $A,B,D$ exclus. On ne peut pas avoir~: 396 \begin{itemize} 397 \item $C$ (arc $(3,6)$), 398 \item $E$ (arc $(1,3)$). 399 \end{itemize} 400 Donc $F$ n'est pas dans l'ensemble. 401 402 Comme $A,B,D,F$ ne sont pas dans l'ensemble et que nous avons 403 seulement 8 candidats, la seule possibilité qui reste pour un ensemble 404 de cardinal 4 est $C,E,G,H$. Or, dans cet ensemble, l'arête $(1,4)$ 405 est commune à $G$ et $H$, donc on ne peut pas construire un ensemble 406 de chemins d'arcs disjoints de taille 4 ni de taille supérieure 407 à 4. 408 409 Conclusion~: Le nombre maximum de chemins d'arcs disjoints est 3. 410 411 \begin{enonce} 412 Enumérer tous les s-t-coupes dans le réseau donnés par la figure 1. Pour chaque s-t-coupe $[S,\overline{S}]$, énumérer les sommets, les arcs avants et les arcs arrières. 413 \end{enonce} 414 415 % Code LISP pour générer le tableau ci-après : 416 417 % (defun S (n p) 418 % (if p 419 % (format t " ~a " n) 420 % (format t "\\phantom{~a} " n))) 421 422 % (defun Sbar (n p) 423 % (S-n-p n (not p))) 424 425 % (defun print-arcs (arcs) 426 % (when arcs 427 % (when (car arcs) 428 % (format t "(~a,~a)" (caar arcs) (cdar arcs)) 429 % (unless (endp (cdr arcs)) 430 % (format t ", "))) 431 % (print-arcs (cdr arcs)))) 432 433 % (defun print-arcs-if-not-nil (arcs) 434 % (print-arcs (remove-if-not #'identity arcs))) 435 436 % (defun print-line (l nodes edges) 437 % (let ((num-and-pred (pairlis nodes (mapcar #'list l)))) 438 % ;; (cdr (butlast)) pour ne pas imprimer les 1ers et derniers qui sont fixes. 439 % (format t "~a " (car nodes)) 440 % (mapcar #'S (cdr (butlast nodes)) (cdr (butlast l))) 441 % (format t "& ") 442 % (mapcar #'Sbar (cdr (butlast nodes)) (cdr (butlast l))) 443 % (format t "~a " (car (last nodes))) 444 % (format t "& ${") 445 % (print-arcs-if-not-nil 446 % (mapcar (lambda (arc) 447 % (and (cadr (assoc (car arc) num-and-pred)) 448 % (not (cadr (assoc (cdr arc) num-and-pred))) 449 % arc)) 450 % edges)) 451 % (format t "}$ & ${") 452 % (print-arcs-if-not-nil 453 % (mapcar (lambda (arc) 454 % (and (cadr (assoc (cdr arc) num-and-pred)) 455 % (not (cadr (assoc (car arc) num-and-pred))) 456 % arc)) 457 % edges)) 458 % (format t "}$ \\\\~%"))) 459 460 % (defun range (n) 461 % (loop for i from 0 below n collect i)) 462 463 % (defun print-s-t-cuts (nodes edges) 464 % (loop 465 % for i from 0 below (expt 2 (- (length nodes) 2)) 466 % do (print-line (append 467 % '(t) ;; Source : toujours t 468 % (mapcar (lambda (n) 469 % (/= 0 (logand i (expt 2 n)))) 470 % (range (- (length nodes) 2))) 471 % '(nil)) ;; Target : toujours nil 472 % nodes 473 % edges))) 474 475 % (print-s-t-cuts 476 % '(1 2 3 4 5 6) 477 % '((1 . 2) 478 % (1 . 3) 479 % (1 . 4) 480 % (2 . 3) 481 % (3 . 4) 482 % (3 . 6) 483 % (4 . 5) 484 % (4 . 6) 485 % (5 . 6))) 486 487 \begin{tabular}{|l|l|l|l|} 488 \hline 489 $S$ & $\overline{S}$ & Arcs avants & Arcs arrières \\ 490 \hline 491 \hline 492 1 \phantom{2} \phantom{3} \phantom{4} \phantom{5} & 2 3 4 5 6 & ${(1,2), (1,3), (1,4)}$ & ${}$ \\ 493 1 2 \phantom{3} \phantom{4} \phantom{5} & \phantom{2} 3 4 5 6 & ${(1,3), (1,4), (2,3)}$ & ${}$ \\ 494 1 \phantom{2} 3 \phantom{4} \phantom{5} & 2 \phantom{3} 4 5 6 & ${(1,2), (1,4), (3,4), (3,6)}$ & ${(2,3)}$ \\ 495 1 2 3 \phantom{4} \phantom{5} & \phantom{2} \phantom{3} 4 5 6 & ${(1,4), (3,4), (3,6)}$ & ${}$ \\ 496 1 \phantom{2} \phantom{3} 4 \phantom{5} & 2 3 \phantom{4} 5 6 & ${(1,2), (1,3), (4,5), (4,6)}$ & ${(3,4)}$ \\ 497 1 2 \phantom{3} 4 \phantom{5} & \phantom{2} 3 \phantom{4} 5 6 & ${(1,3), (2,3), (4,5), (4,6)}$ & ${(3,4)}$ \\ 498 1 \phantom{2} 3 4 \phantom{5} & 2 \phantom{3} \phantom{4} 5 6 & ${(1,2), (3,6), (4,5), (4,6)}$ & ${(2,3)}$ \\ 499 1 2 3 4 \phantom{5} & \phantom{2} \phantom{3} \phantom{4} 5 6 & ${(3,6), (4,5), (4,6)}$ & ${}$ \\ 500 1 \phantom{2} \phantom{3} \phantom{4} 5 & 2 3 4 \phantom{5} 6 & ${(1,2), (1,3), (1,4), (5,6)}$ & ${(4,5)}$ \\ 501 1 2 \phantom{3} \phantom{4} 5 & \phantom{2} 3 4 \phantom{5} 6 & ${(1,3), (1,4), (2,3), (5,6)}$ & ${(4,5)}$ \\ 502 1 \phantom{2} 3 \phantom{4} 5 & 2 \phantom{3} 4 \phantom{5} 6 & ${(1,2), (1,4), (3,4), (3,6), (5,6)}$ & ${(2,3), (4,5)}$ \\ 503 1 2 3 \phantom{4} 5 & \phantom{2} \phantom{3} 4 \phantom{5} 6 & ${(1,4), (3,4), (3,6), (5,6)}$ & ${(4,5)}$ \\ 504 1 \phantom{2} \phantom{3} 4 5 & 2 3 \phantom{4} \phantom{5} 6 & ${(1,2), (1,3), (4,6), (5,6)}$ & ${(3,4)}$ \\ 505 1 2 \phantom{3} 4 5 & \phantom{2} 3 \phantom{4} \phantom{5} 6 & ${(1,3), (2,3), (4,6), (5,6)}$ & ${(3,4)}$ \\ 506 1 \phantom{2} 3 4 5 & 2 \phantom{3} \phantom{4} \phantom{5} 6 & ${(1,2), (3,6), (4,6), (5,6)}$ & ${(2,3)}$ \\ 507 1 2 3 4 5 & \phantom{2} \phantom{3} \phantom{4} \phantom{5} 6 & ${(3,6), (4,6), (5,6)}$ & ${}$ \\ 508 \hline 509 \end{tabular} 510 511 \begin{enonce} 512 Vérifier que le nombre maximum de chemins d'arcs disjoints à partir du sommet source jusqu'au puits est égal au nombre minimum d'arcs avant dans une s-t-coupe. 513 \end{enonce} 514 515 D'après notre conclusion de la question 1, on a uniquement trois chemins d'arcs disjoints et d'après le tableau de la question 2, on constate que le nombre minimum d'arcs avant est de 3. On peut donc vérifier que le nombre maximum d'arcs disjoints est égal au nombre minimum d'arcs avants. 516 517 \subsection{Partie complexité} 518 519 \subsubsection*{Exercice \stepcounter{exocount}\bf\small \arabic{exocount} -- Sur quelques réductions} 520 \addcontentsline{toc}{subsubsection}{Exercice \arabic{exocount} -- Sur quelques réductions} 521 \setcounter{enoncecount}{0} 522 523 \begin{enonce} 524 On vous demande de rappeler la réduction de SAT à 3-SAT. 525 \end{enonce} 526 527 \begin{sousenonce} 528 Enoncer SAT et 3-SAT. 529 \end{sousenonce} 530 531 SAT est une abbrévation pour 'problème de satisfiabilité'. En logique propositionnelle, résoudre un problème SAT consiste à déterminer s'il existe une assignation des variables booléennes telle qu'une formule logique sous forme normale conjonctive s'évalue à vrai. Si tel est le cas, la formule est dite 'satisfiable', sinon elle est 'insatisfiable'. Etant donné le résultat booléen ('satisfiable' ou 'insatisfiable') de ce genre de problème, il s'agit bien d'un problème de décision. 532 533 On appelle 2-sat un problème dont chaque clause de la formule logique en question contient au plus 2 littéraux, 3-sat un problème SAT dans lequel chaque clause de la formule logique en question contient au plus 3 littéraux. Un problème 2-sat est polynomial et NL-complet alors qu'un problème 3-sat est NP-complet. 534 535 Un exemple d'un problème 3-SAT est le suivant : 536 537 $(v_{1} \vee v_{2} \vee v_{3}) \wedge (v_{4} \vee v_{5} \vee v_{6}) \wedge (v_{7} \vee v_{8} \vee v_{9}) \wedge$ ... 538 539 où chaque v est une variable ou la négation d'une variable, chaque variable pouvant figurer plusieurs fois dans l'expression. 540 541 \begin{sousenonce} 542 Définir la réduction. 543 \end{sousenonce} 544 545 En théorie de complexité, une 'réduction' est la transformation d'un problème en un autre problème. Selon la transformation utilisée, la réduction peut être utilisée afin de définir une classe de complexité à un ensemble de problèmes. Problème A est réductible à Problème B si les solutions au Problème B existent et donnent des solutions au Problème A à chaque fois que A a des solutions. Par conséquent, la solution de A ne peut pas être plus difficile que la solution de B. 546 547 Il peut être utile de résoudre un problème qui est similaire à un problème que l'on a déjà résolu. Dans ce cas, une méthode efficace de résoudre le nouveau problème est de transformer chaque instance du nouveau problème en une instance d'un problème que l'on sait résoudre et puis de résoudre chaque instance à l'aide de solutions existantes afin d'obtenir une solution finale. Une autre stratégie est de subdiviser un problème en plusieurs sous-problèmes que l'on sait résoudre, d'où le terme 'réduction'. 548 549 Une autre application des 'réductions' est son application aux problèmes qui sont difficiles à résoudre. Lorsque l'on a un problème qui a été prouvé difficile à résoudre et que nous avons un nouveau problème similaire, nous pouvons faire l'hypothèse que le nouveau problème, lui aussi, est difficile à résoudre. Le raisonnement est l'inverse de celui des problèmes qui peuvent être résolu aisément. 550 551 Un exemple simple est de passer de la multiplication à la quadrature. Supposons que nous ne sommes capable que d'effectuer l'addition, la soustraction la quadrature et la division. Avec ces quatre opérations, nous pouvons trouver le produit de deux nombres quelconques : 552 553 554 $$(a \times b) = \dfrac{(a + b)^2 - a^2 - b^2}{2}$$ 555 556 557 Lorsqu'il est possible de réduire un problème difficile en un problème que l'on sait résoudre, la difficulté demeure souvent dans la réduction elle-même. 558 559 Pour la réduction de SAT à 3-SAT, on prend chaque clause de littéraux du problème SAT et on la transforme en une ou plusieurs clauses de la manière suivante~: 560 561 \begin{itemize} 562 \item Si la clause possède 3 littéraux ou moins, on la laisse telle quelle. Elle est déjà sous forme 3-SAT. 563 \item Sinon, soient $l_1, \dots, l_n$ les littéraux de la clause, on construit plusieurs clauses ainsi~: 564 $$ 565 (l_1, l_2, z_1), (\lnot z_1, l_3, z_2), (\lnot z_2, l_4, z_3), \dots, (\lnot z_{i-2}, l_{i}, z_{i-1}), \dots, (\lnot z_{n-3}, l_{n-1}, l_{n}) 566 $$ 567 \end{itemize} 568 569 Les littéraux $z_i$, qui n'était pas présents dans la clause d'origine, sont ajoutés afin de pouvoir subdiviser une clause en deux ou 570 plusieurs clauses et afin de les relier. Par exemple, la clause $(a \vee \lnot b \vee c \vee d)$ sera transformée en deux clauses~: $(a 571 \vee \lnot b \vee z_1) \wedge (\lnot z_1 \vee c \vee d)$ ; la clause ${\lnot a \vee b \vee \lnot c \vee d \vee e}$ sera transformée en trois 572 clauses, à savoir $(\lnot a \vee b \vee z_1) \wedge (\lnot z_1 \vee \lnot c \vee z_2) \wedge (\lnot z_2 \vee d \vee e)$. 573 574 L'ensemble des clauses ainsi créées sont équivalentes à l'ensemble des clauses d'origines correspondant car, à chaque fois, soit un des littéraux d'origine vérifie la clause et $z_i$ peut être faux, ce qui permet à $\lnot z_i$ de valider la clause suivante, de proche en proche, soit aucun des littéraux d'origine ne vérifie la clause, auquel cas, si on prend un $z_i$ faux, la clause est fausse, et si on prend un $z_i$ vrai, la clause suivante 575 contiendra $\lnot z_i$ qui sera faux, et le résultat dépendra des littéraux de la ou des clause(s) suivante(s). 576 577 Si l'on souhaite que le résultat soit strictement 3-SAT (toutes les clauses contenant exactement 3 littéraux, on applique les transformations suivantes~: 578 \begin{itemize} 579 \item Les clauses qui contiennent un seul littéral, ${l_1}$, sont transformées en ${l_1, l_1, l_1}$. 580 \item Les clauses qui contiennent exactement deux littéraux, ${l_1, l_2}$ sont transformées en ${l_1, l_2, l_1}$. 581 \end{itemize} 582 583 Cette transformation est linéaire en complexité. En effet, on ne considère chaque littéral qu'une fois et on ajoute $n-3$ littéraux pour chaque clause. Il s'agit de complexité polynomiale. 584 585 \begin{sousenonce} 586 Justifier alors que 3-SAT est NP-complet (sachant que SAT est NP-complet). 587 \end{sousenonce} 588 589 Vu que SAT est np-complet et que 3-SAT sait faire ce que sait faire SAT, avec une transformation polynomiale, 3-SAT (y compris la transformation) est au moins aussi dur que SAT. La difficulté peut résider dans la transformation 3-SAT ou les deux. 590 591 Vu que la difficulté ne s'est pas cachée dans la transformation, qui est polynomiale alors que SAT est np-complet, 3-SAT est np-complet lui aussi. 592 593 \begin{sousenonce} 594 Application : si un ensemble de clauses contient $n_v$ variables, $n_1$ clauses à un littéral, $n_2$ clauses à 2 littéraux, $n_3$ clauses 595 à 3 littéraux, $n_4$ clauses à 4 littéraux, $n_5$ clauses à 5 littéraux (et pas d'autres clauses), combien le système obtenu par votre 596 réduction contient-il de variables et de clauses ? Vous devrez bien sûr justifier votre réponse. 597 \end{sousenonce} 598 599 Le système obtenu par la réduction contient : 600 \begin{itemize} 601 \item Une variable supplémentaire pour chaque clause à 4 littéraux. 602 \item Deux variables supplémentaires pour chaque clause à 5 littéraux. 603 \item Soit au total $n_v + n_4 + 2n_5$ variables. 604 \end{itemize} 605 606 De plus, les expansions sont les suivantes : 607 \begin{itemize} 608 \item Un littéral : 1 clause 609 \item Deux littéraux : 1 clause 610 \item Trois littéraux : 1 clause 611 \item Quatre littéraux : 2 clauses 612 \item Cinq littéraux : 3 clause 613 \item Soit au total $n_1 + n_2 + n_3 + 2n_4 + 3n_5$ clauses. 614 \end{itemize} 615 616 617 618 \begin{enonce} 619 Pourquoi le principe de la réduction ne permet-il pas de réduire 3-SAT à 2-SAT et de prouver que 2-SAT est NP-complet ? (Il ne s'agit pas 620 d'expliquer pourquoi 2-SAT n'est pas NP-complet, mais pourquoi cette réduction ne marche pas). 621 \end{enonce} 622 623 Tentons de réduire la clause $(a \vee b \vee c)$ de manière similaire à l'algorithme donné pour la réduction de SAT à 3-SAT~. 624 625 On a $(a \vee z_1) \wedge (\lnot z_1 \vee b)$. A partir de là, on ne peut insérer de variable permettant de faire la liaison entre la clause 626 qui contient $b$ et celle qui contient $c$, donc on ne peut pas appliquer cette réduction. 627 628 \begin{enonce} 629 Il s'agit de prouver que 2-SAT est un problème polynomial. Vous avez un article en français expliquant cette preuve à \\ http://philippe.gambette.free.fr/SCOL/Graphes 630 \end{enonce} 631 \setcounter{sousenoncecount}{0} 632 633 \begin{sousenonce} 634 Vous commencerez par fabriquer trois ensembles de deux clauses, le premier valide, le deuxième insatisfiable et le troisième contingent, 635 et pour chacun de ces ensembles de clauses vous construirez le graphe correspondant. Vous expliquerez comment apparaît sur chacun des 636 trois graphes la validité de l'ensemble de clauses corresponsdantes. 637 \end{sousenonce} 638 639 Philippe Gambette, dans son article intitulé 'Un graphe pour résoudre 2-SAT', donne une explication succincte de l'agorithme d'Aspvall, Plass et Tarjan. 640 641 Une formule logique en forme normale conjonctive contenant des clauses à deux littéraux est transformé en un problème de graphe orienté. On 642 doit tout d'abord établir si la formule admet un modèle, et ensuite, si tel est le cas, donner un modèle quelconque. 643 644 \begin{enumerate} 645 \item L'algorithme de construction de graphe : 646 \begin{enumerate} 647 \item On crée un graphe avec $2n$ sommets ($n$ étant ici le nombre littéraux distincts de la formule) contenant tous les littéraux de la 648 formule ainsi que les négations de ces littéraux. 649 \item On prend chaque clause de la formule que l'on traduit en implications dans les deux sens : $(a \vee b)$ 650 se transforme en deux clauses : $(\neg a \Rightarrow b)$ et ($\neg b \Rightarrow a)$. 651 \item On crée des arcs correspondant aux implications créées à l'étape précédente (arc ($\neg a 652 \rightarrow b$) et ($\neg b \rightarrow a$)) 653 \end{enumerate} 654 \item On effectue un tri topologique en numérotant les sommets de $1$ à $n$. 655 \item En ordre inverse, du sommet $n$ au sommet $1$ du graphe, on affecte à tout noeud $x$ la valeur VRAI et au noeud $\neg x$ la valeur 656 FAUX, c'est-à-dire dans l'ordre inverse du tri topologique. 657 \end{enumerate} 658 659 S'il existe une composante fortement connexe contenant un littéral et sa négation, la formule est insatisfiable étant donné qu'on a $x_{i} 660 \Leftrightarrow \neg x_{i}$ sinon, la formule est satisfiable, c'est-à-dire soit contingente soit valide. L'algorithme ne nous donne aucune 661 information pour distinguer une formule contingente et une formule valide, il nous donne une ou deux informations : (1) il nous dit si la 662 formule admet un modèle, et (2) si oui, il nous donne un modèle~: le modèle est assuré car le graphe en question ne contient aucun arc $VRAI 663 \rightarrow FAUX$. 664 665 Prenons trois exemples~: une formule insatisfiable, une formule contingente et une formule valide. 666 667 \begin{figure}[ht!] 668 \centering 669 \begin{tikzpicture}[ 670 node distance=2.5cm, 671 lettre/.style={ 672 draw, 673 circle, 674 minimum size=1cm 675 } 676 ] 677 \node[lettre] (nx1) {$\lnot x_1$} ; 678 \node[lettre, below of=nx1] (x1) {$x_1$} ; 679 \node[coordinate,xshift=0.1cm] (x1r) at (x1.north) {}; 680 \node[coordinate,xshift=-0.1cm] (x1l) at (x1.north) {}; 681 \node[coordinate,xshift=0.1cm] (nx1r) at (nx1.south) {}; 682 \node[coordinate,xshift=-0.1cm] (nx1l) at (nx1.south) {}; 683 \draw[->] (x1r) -- (nx1r); 684 \draw[->] (nx1l) -- (x1l); 685 686 \end{tikzpicture} 687 \caption{Clause insatisfiable : $(x_{1} \vee x_{1}) \wedge (\neg x_{1} \vee \neg x_{1})$} 688 \label{fig:clause-insat} 689 \end{figure} 690 691 \paragraph*{Clause insatisfiable $(x_{1} \vee x_{1}) \wedge (\neg x_{1} \vee \neg x_{1})$~:} 692 693 Le résultat de l'application de l'algorithme décrit ci-dessus est un graphe orienté cyclique. Il est impossible d'effectuer un tri 694 topologique étant donné qu'un tri topologique ne peut être effectué que sur un graphe acyclique orienté. Ce graphe contient un composant 695 fortement connexe contenant un littéral et sa négation, et la formule associée est, par conséquent, insatisfiable. Il est impossible 696 d'attribuer un ordre aux sommets pour ensuite affecter des valeurs aux littéraux correspondant aux sommets car la formule admet aucun 697 modèle. Pour cette raison, les arcs de ce graphe n'ont pas été numérotés ni affectés des valeurs $VRAI$ ou $FAUX$. En somme, l'algorithme 698 nous dit simplement que ce graphe n'admet aucun modèle. 699 700 \begin{figure}[ht!] 701 \centering 702 \begin{tikzpicture}[ 703 start chain=circle placed {at=(\tikzchaincount*-45+22.5+90:2.5)}, 704 lettre/.style={ 705 on chain, 706 draw, 707 circle, 708 minimum size=1cm 709 }, 710 chiffre/.style={ 711 node distance = 0.75cm 712 }, 713 arr/.style={ 714 ->, 715 >=triangle 90 716 } 717 ] 718 \node[lettre] (1) {$\lnot x1$} ; 719 \node[lettre] (5) {$x2$} ; 720 \node[lettre] (3) {$\lnot x2$} ; 721 \node[lettre] (6) {$x3$} ; 722 \node[lettre] (4) {$\lnot x3$} ; 723 \node[lettre] (7) {$x4$} ; 724 \node[lettre] (2) {$\lnot x4$} ; 725 \node[lettre] (8) {$x1$} ; 726 727 \node[right of=1] {\textcolor{red}{faux}} ; 728 \node[right of=5] {\textcolor{green!75!black}{vrai}} ; 729 \node[right of=3] {\textcolor{red}{faux}} ; 730 \node[right of=6] {\textcolor{green!75!black}{vrai}} ; 731 \node[left of=4] {\textcolor{red}{faux}} ; 732 \node[left of=7] {\textcolor{green!75!black}{vrai}} ; 733 \node[left of=2] {\textcolor{red}{faux}} ; 734 \node[left of=8] {\textcolor{green!75!black}{vrai}} ; 735 736 \node[chiffre, above right of=1] {1} ; 737 \node[chiffre, above right of=5] {5} ; 738 \node[chiffre, below right of=3] {3} ; 739 \node[chiffre, below right of=6] {6} ; 740 \node[chiffre, below left of=4] {4} ; 741 \node[chiffre, below left of=7] {7} ; 742 \node[chiffre, above left of=2] {2} ; 743 \node[chiffre, above left of=8] {8} ; 744 745 \draw[arr] (1) -- (5) ; 746 \draw[arr] (3) -- (8) ; 747 \draw[arr] (2) -- (6) ; 748 \draw[arr] (4) -- (7) ; 749 \end{tikzpicture} 750 \caption{Clause contingente : $(x_{1} \vee x_{2}) \wedge (x_{3} \vee x_{4})$} 751 \label{fig:clause-conting} 752 \end{figure} 753 754 % \includegraphics[height=2in, width = 3in]{img/contingente.png 755 756 \paragraph*{Clause contingente $(x_{1} \vee x_{2}) \wedge (x_{3} \vee x_{4})$~:} 757 Le graphe de la figure \ref{fig:clause-conting} ne contient aucune composante fortement connexe contenant un littéral et sa négation, donc 758 la formule associée admet bien un modèle. Ce modèle est le résultat du tri topologique effectué et les valeurs $VRAI$ et $FAUX$ affectées à 759 des sommets par notre algorithme. Il existe aucun arc qui part d'un sommet étiqueté $VRAI$ vers un sommet étiqueté $FAUX$ et, en effet, les 760 valeurs attribuées aux arcs donnent bien un modèle. 761 762 763 764 \begin{figure}[ht!] 765 \centering 766 \begin{tikzpicture}[ 767 start chain=circle placed {at=(\tikzchaincount*-90+180:1.6)}, 768 lettre/.style={ 769 on chain, 770 draw, 771 circle, 772 minimum size=1cm 773 }, 774 chiffre/.style={ 775 node distance = 0.75cm 776 }, 777 arr/.style={ 778 ->, 779 >=triangle 90 780 } 781 ] 782 \node[lettre] (1) {$\lnot x1$} ; 783 \node[lettre] (2) {$x1$} ; 784 \node[lettre] (3) {$\lnot x2$} ; 785 \node[lettre] (4) {$x2$} ; 786 787 \node[right of=1] {\textcolor{green!75!black}{vrai}} ; 788 \node[right of=2] {\textcolor{red}{faux}} ; 789 \node[right of=3] {\textcolor{green!75!black}{vrai}} ; 790 \node[left of=4] {\textcolor{red}{faux}} ; 791 792 \node[chiffre, above right of=1] {1} ; 793 \node[chiffre, below right of=2] {2} ; 794 \node[chiffre, below right of=3] {3} ; 795 \node[chiffre, below left of=4] {4} ; 796 797 \path 798 (1) edge[loop above] (1) 799 (2) edge[loop above] (2) 800 (3) edge[loop below] (3) 801 (4) edge[loop above] (4) ; 802 \end{tikzpicture} 803 \caption{Clause valide : $(x_{1} \vee \neg x_{1}) \wedge (x_{2} \vee \neg x_{2})$} 804 \label{fig:clause-valide} 805 \end{figure} 806 807 % \includegraphics[height=2in, width = 3in]{img/valide.png} 808 809 \paragraph*{Clause valide $(x_{1} \vee \neg x_{1}) \wedge (x_{2} \vee \neg x_{2})$~:} 810 L'application de l'algorithme de transformation en graphe d'une formule valide nous donne un graphe ne contenant que des boucles à chaque 811 sommet. Nous pouvons donc numéroter les arcs de n'importe quel façon. Ce étant, nous pouvous aussi affecter n'importe quelles valeurs aux 812 sommets (hormis la même valeur à un littéral et sa négation, bien entendu) et la formule sera toujours vraie. 813 814 L'objectif de cet algorithme n'est pas de dire si une formule satisfiable est contingente ou valide. Toutefois, si le résultat de 815 l'algorithme est un graphe ne comportant que des boucles à chaque sommet, la formule associée est satisfiable et valide. Autrement, et si le 816 graphe ne contient aucune composante fortement connexe contenant un littéral et sa négation, la formule est contingente. 817 818 819 \begin{sousenonce} 820 Vous expliciterez ensuite l'algorithme de transformation et vous évaluerez sa complexité. 821 \end{sousenonce} 822 823 L'algorithme de transformation est expliqué plus haut, sous le nom \og L'algorithme de construction de graphe\fg{} 824 825 On pose~: 826 827 c = nb clauses \\ 828 l = nb littéraux 829 830 En triant la liste des sommets du graphe (coût $n \log n$ pour le tri), on peut effectuer les opérations de recherche d'un littéral (ou de sa négation) par dichotomie (coût $\log n$), donc les $c \times l$ et $O(l \times l)$ (1.a, 1.c, 3.) ci-dessous deviennent respectivement $O(c \log l)$ et $O(l \log l)$ 831 832 833 \begin{itemize} 834 \item 1.a : $O(c \times l)$ car pour chaque littéral qu'on insère, il faut chercher s'il existe déjà. 835 \item 1.b : $O(c)$ une opération pour chaque clause 836 \item 1.c : $O(c \times l)$ pour chaque clause, on cherche ses 2 littéraux et leur négation dans le graphe 837 \item 2. : $O(card(V) + card(E))$, comme $card(V) = 2l$ et $card(E) <= 2c$ (inférieur ou égal à cause des doublons potentiels qui n'ajoutent rien au graphe)., on a $O(l+c)$ 838 \item 3. : $O(l \times l)$ car pour chaque littéral qu'on rencontre on devra chercher sa négation dans tout le graphe. 839 \end{itemize} 840 841 Comme $l <= 2c$, tous les l ci-dessus peuvent être transformés en c. 842 843 Donc, on prend le coût le plus élevé~: 844 $$ 845 O(c^2 + c + c^2 + 2c + c^2) = O(c^2) 846 $$ 847 848 On a donc bien un coût polynomial. 849 850 De plus, si on trie le graphe, on a (le premier $c \log c$ est la création du graphe en maintenant sa liste de sommets triés (tri par insertion)): 851 $$ 852 O(c \log c + c + c \log c + 2c + c \log c) = O(c \log c) 853 $$ 854 855 856 \begin{sousenonce} 857 Vous expliciterez ensuite l'algorithme d'exploration du graphe et vous évaluerez sa complexité 858 en fonction de la taille de l'ensemble de clauses initial. 859 \end{sousenonce} 860 861 L'algorithme a déjà été expliqué plus haut à la question 3(a). 862 863 Pour la partie «trouver un modèle» de l'algorithme, le tri topologique se fait en $O(V + E)$ en faisant un parcours en profondeur. Ensuite, on parcourt chaque littéral auquel on n'a pas encore affecté de valeur~; on lui affecte VRAI et on affecte FAUX à sa négation. Cela coûte 864 $O(V^2)$ car pour chaque littéral, il faudra chercher sa négation dans $V$ et le coût total est donc $O(V + E + V^2) = O(V^2 + E)$. 865 866 On peut toutefois trier les noeuds de $V$ et faire une recherche par dichotomie, ce qui coûte alors $O(V \log V)$ pour le tri et la 867 recherche coûte alors $O(\log V)$, soit $O(V \log V)$ pour toute la phase d'affectation des valeurs. Le coût total de cette partie est donc 868 $O(V + E + V \log V + V \log V)$, soit $O(E + V \log V)$. 869 870 Pour la partie «déterminer si la formule est invalide», il faut parcourir le graphe pour voir si une composante fortement connexe contient 871 un littéral et sa négation. On fera encore un parcours en profondeur $O(V + E)$ et pour chaque noeud (littéral) rencontré lors du parcours, 872 il faudra voir si on a déjà rencontré la négation de ce littéral dans la même composante, ce qui coûte $O(\text{taille composante})$. Dans 873 le pire des cas, la composante fortement connexe fait tout le graphe et le coût de la recherche sera alors $O(V)$. Comme cette recherche 874 est effectuée pour chaque noeud, le coût total sera $O(V+E)$ pour le parcours en profondeur et $O(V^2)$ pour l'ensemble des recherches, 875 soit $O(V+E+V^2) = O(V^2+E)$ au total. 876 877 On peut améliorer le coût de la recherche en maintenant une structure de données permettant un accès rapide aux littéraux déjà rencontrés, par exemple, un arbre binaire de recherche balancé (AVL). Le coût de la recherche descend alors à $O(\log V)$ dans le pire des cas, pour un coût total de $O(E + V \log V)$. 878 879 L'algorithme d'exploration du graphe (y compris la partie qui trouve un modèle) coûte donc $O(E + V^2)$ sans les tris supplémentaires et $O(E + V \log V)$ avec. 880 881 \begin{sousenonce} 882 Enfin, vous justifierez l'équivalence de la réponse au problème 2-SAT et au problème qui est posé dans le graphe. 883 \end{sousenonce} 884 885 Un problème 2-SAT est une conjonction de disjonctions de deux littéraux (ou de leur négation). Pour que la formule soit satisfiable, il faut 886 qu'il existe une affectation des littéraux telle que chaque clause soit vraie (car les clauses sont reliées par des $\wedge$ et il suffit 887 donc qu'une seule d'entre elles soit fausse pour que toute la formule devienne fausse). 888 889 Pour qu'une clause soit valide, il faut qu'au moins un de ses deux membres soit vrai. Cela signifie que si le premier membre est forcément 890 faux, alors le deuxième doit être vrai pour que la formule entière soit vraie. 891 892 On peut donc ré-écrire la formule 893 $$(a_1 \vee a_2) \wedge (a_3 \vee a_4) \wedge \dots \wedge (a_{n-1} \vee a_n)$$ 894 (les $a_i$ étant des littéraux ou leur négation) de la manière suivante : 895 $$(\lnot a_1 \rightarrow a_2) \wedge (\lnot a_3 \rightarrow a_4) \wedge \dots \wedge (\lnot a_{n-1} \rightarrow a_n)$$ 896 897 Le graphe que l'on constuit explicite ces implications en faisant un arc entre le littéral à gauche et le littéral à droite. 898 899 Pour chercher une contradiction dans la formule, qui la rend insatisfiable, il faut trouver un ensemble d'implications présentes dans la 900 formules telles que~: 901 $$ 902 \begin{array}{rrcl} 903 & (a_{i1} & \Rightarrow & a_{i2}) \\ 904 \wedge & (a_{i3} & \Rightarrow & a_{i4}) \\ 905 \wedge & & \dots & \\ 906 \wedge & (a_{i5} & \Rightarrow & \lnot a_{i1}) \\ 907 \wedge & (\lnot a_{i1} & \Rightarrow & a_{i6}) \\ 908 \wedge & (a_{i7} & \Rightarrow & a_{i8}) \\ 909 \wedge & & \dots & \\ 910 \wedge & (a_{i9} & \Rightarrow & a_{i1}) \\ 911 \end{array} 912 $$ 913 Ce qui peut se réduire à $a_{i1} \Rightarrow \lnot a_{i1} \Rightarrow a_{i1}$ autrement dit $a_{i1} \Leftrightarrow \lnot a_{i1}$, ce qui 914 est bien évidemment insatisfiable. 915 916 Cet ensemble d'implication se traduit dans le graphe par un chemin de $a_{i1}$ jusqu'à $\lnot a_{i1}$, et un chemin de $\lnot a_{i1}$ 917 jusqu'à $\lnot a_{i1}$, autrement dit, $a_{i1}$ et $\lnot a_{i1}$ sont dans la même composante connexe. 918 919 L'algorithme utilise cette même transformation en implications pour déterminer un modèle~: le graphe étant trié topologiquement, on part du 920 terme «le plus à droite» d'une chaîne d'implications et on lui affecte vrai si c'est un littéral sans négation en affectant faux à sa 921 négation et vice versa si c'est un littéral avec négation. Lorsque l'on remonte ainsi de droite à gauche, on s'assure qu'il n'y aura jamais un 922 $\text{VRAI} \Rightarrow \text{FAUX}$ (puisqu'on vient de la droite et qu'on n'affecte que des valeurs qui rendent le membre vrai), à moins 923 qu'il y ait une boucle (qui aurait été détectée à l'étape précédente). Cette combinaison de valeurs nous donne donc un modèle. 924 925 \subsection{Partie Calculabilité} 926 927 \subsubsection*{Exercice \stepcounter{exocount}\bf\small \arabic{exocount} -- Sur le problème de codage} 928 \addcontentsline{toc}{subsubsection}{Exercice \arabic{exocount} -- Sur le problème de codage} 929 \setcounter{enoncecount}{0} 930 931 \begin{enonce} 932 Comment énumérer les couples d'entiers ? 933 \end{enonce} 934 935 936 L'énumération des couples de manière relativement homogène nous donnerait un codage qui nous permettrait d'identifier chaque couple par un nombre unique. 937 938 Il ne serait pas du tout utile de commencer par tous les couples $(0,y_{i})$ tel que $i \in \mathbb{Z}$ car il s'agirait, là, d'un ensemble infini de couples et on ne passerait jamais aux couples $(1, y_{i})$. 939 940 Une solution, pour tous les nombres naturels, serait de parcourir un graphe comme suit: 941 942 \begin{figure}[ht!] 943 %% «Paramètres» 944 \xdef\maxdots{23} 945 \xdef\maxdotsX{5} 946 \xdef\maxdotsY{5} 947 \xdef\maxnums{20} 948 \xdef\maxcoordsX{3} 949 \xdef\maxcoordsY{3} 950 951 %% ===== Code is below ===== 952 953 %% Macros crades 954 \makeatletter 955 \def\myadv#1#2{% 956 \xdef\incr@backup{\the\@tempcnta}% 957 \@tempcnta=#1{}% 958 \advance\@tempcnta by #2{}% 959 \xdef#1{\the\@tempcnta}% 960 \@tempcnta=\incr@backup{}% 961 } 962 \def\incr#1{% 963 \myadv#1{1}% 964 } 965 \def\decr#1{% 966 \myadv#1{-1}% 967 } 968 \makeatother 969 \centering 970 \begin{tikzpicture}[ 971 scale=1.4, 972 dot/.style={ 973 circle, 974 inner sep=0.7pt, 975 fill=black 976 }, 977 dotphantom/.style={ 978 circle, 979 inner sep=3pt, 980 fill=none, 981 draw=none 982 }, 983 numero/.style={rectangle, fill=white, inner sep=2pt, text=red!50!black}, 984 coord/.style={darkgray, scale=.8}, 985 % 986 bigarrow/.style={ 987 ->, 988 thick, 989 draw=green!50!black 990 }, 991 constatation1/.style={ 992 circle, 993 inner sep=1.5pt, 994 outer sep=0.8pt, 995 fill=white, 996 text=red, 997 anchor=south, 998 rotate around={45:(0,0)} 999 }, 1000 constatation2/.style={ 1001 text=green!50!black, 1002 node distance=0.6cm 1003 } 1004 ] 1005 1006 % %% Digonale 1007 % \draw[bigarrow,red] (0,0) -- (.5*7.5,-.5*7.5); 1008 1009 % Définitions pour le code ci-dessous. 1010 \xdef\i{0} 1011 \xdef\x{0} 1012 \xdef\y{0} 1013 \xdef\corner{3} 1014 \xdef\sidelen{0} 1015 \xdef\nextsidelen{1} 1016 \xdef\direction{3} 1017 \incr\maxnums 1018 \incr\maxcoordsX 1019 \incr\maxcoordsY 1020 1021 \foreach \x in {0,...,\maxcoordsX} { 1022 \foreach \y in {1,...,\maxcoordsY} { 1023 \expandafter\xdef\csname dotxypresent-\x-\y\endcsname{0} 1024 } 1025 } 1026 1027 \def\reallysmallcheat#1{% 1028 \ensuremath{\hphantom{\vphantom{X}}_{\hphantom{\vphantom{X}}_{#1}}} 1029 } 1030 \def\drawnode{% 1031 \node[dot] (dot-\x-\y) at (\x,-\y) {}; 1032 \node[dotphantom] (phantom-\x-\y) at (\x,-\y) {}; 1033 \ifnum\maxnums>\i 1034 % \ifnum\corner=0 \node[numero,anchor=south] at (dot-\x-\y.north) {\i}; \else 1035 % \ifnum\corner=1 \node[numero,anchor=east] at (dot-\x-\y.west) {\i}; \else 1036 % \ifnum\corner=2 \node[numero,anchor=east] at (dot-\x-\y.west) {\i}; \else 1037 % \ifnum\corner=3 \node[numero,anchor=south] at (dot-\x-\y.north) {\i}; \else 1038 % \ifnum\direction=0 \node[numero,anchor=north west] at (dot-\x-\y.south east) {\i}; \else 1039 % \ifnum\direction=2 \node[numero,anchor=north west] at (dot-\x-\y.south east) {\i}; \fi\fi\fi\fi\fi\fi 1040 \node[numero,anchor=north west] at (dot-\x-\y.south east) {\i}; 1041 \fi 1042 \ifnum\maxcoordsX>\x 1043 \ifnum\maxcoordsY>\y 1044 % \ifnum\corner=0 \node[coord,anchor=south east] at (dot-\x-\y.north west) {\reallysmallcheat{(\x, \y)}}; \else 1045 % \ifnum\corner=1 \node[coord,anchor=north east] at (dot-\x-\y.south west) {\reallysmallcheat{(\x, \y)}}; \else 1046 % \ifnum\corner=2 \node[coord,anchor=north west] at (dot-\x-\y.south east) {\reallysmallcheat{(\x, \y)}}; \else 1047 % \ifnum\corner=3 \node[coord,anchor=south west] at (dot-\x-\y.north east) {\reallysmallcheat{(\x, \y)}}; \else 1048 % \ifnum\direction=0 \node[coord,anchor=east] at (dot-\x-\y.west) {\reallysmallcheat{(\x, \y)}}; \else 1049 % \ifnum\direction=1 \node[coord,anchor=north] at (dot-\x-\y.south) {\reallysmallcheat{(\x, \y)}}; \else 1050 % \ifnum\direction=2 \node[coord,anchor=west] at (dot-\x-\y.east) {\reallysmallcheat{(\x, \y)}}; \else 1051 % \ifnum\direction=3 \node[coord,anchor=south] at (dot-\x-\y.north) {\reallysmallcheat{(\x, \y)}}; \fi\fi\fi\fi\fi\fi\fi\fi 1052 \expandafter\xdef\csname dotxypresent-\x-\y\endcsname{1} 1053 \ifnum\y=0 1054 \node[coord,anchor=south west] at (dot-\x-\y.north east) {\reallysmallcheat{(\x, \y)}}; 1055 \else 1056 \node[coord,anchor=west,xshift=0.2] at (dot-\x-\y.east) {\reallysmallcheat{(\x, \y)}}; 1057 \fi 1058 \fi 1059 \fi 1060 } 1061 \def\drawlinknode{% 1062 \drawnode% 1063 \draw[->] (phantom-\oldx-\oldy) -- (phantom-\x-\y);% 1064 } 1065 \def\mystep{% 1066 \incr\i% 1067 \xdef\oldx{\x}% 1068 \xdef\oldy{\y}% 1069 } 1070 \def\changedir#1{% 1071 \xdef\direction{#1}% 1072 \xdef\corner{#1}% 1073 } 1074 1075 \drawnode 1076 \mystep \incr\x 1077 \xdef\cornerc{0} 1078 1079 \foreach \pos in {1,...,\maxdots} { 1080 % Detect when we are at the end of this edge. 1081 \ifnum\sidelen=0 1082 \ifnum\direction=0 \changedir{1} \incr\nextsidelen \xdef\sidelen{1} \else 1083 \ifnum\direction=1 \changedir{2} \xdef\sidelen{\nextsidelen} \else 1084 \ifnum\direction=2 \changedir{3} \incr\nextsidelen \xdef\sidelen{1} \else 1085 \ifnum\direction=3 \changedir{0} \xdef\sidelen{\nextsidelen} \fi\fi\fi\fi% Brin d'acier 1086 1087 \fi 1088 % Draw node and link to previous, step counters 1089 \drawlinknode \mystep 1090 %% Se déplacer vers ↙↓↗→ 1091 \ifnum\direction=0 \incr\y \decr\x \fi 1092 \ifnum\direction=1 \incr\y \fi 1093 \ifnum\direction=2 \decr\y \incr\x \fi 1094 \ifnum\direction=3 \incr\x \fi 1095 \decr\sidelen 1096 \xdef\corner{4}%% 4 == pas de coin-coin. 1097 } 1098 1099 \foreach \x in {0,...,\maxdotsX} { 1100 \foreach \y in {1,...,\maxdotsY} { 1101 \node[dot] (dot-\x-\y) at (\x,-\y) {}; 1102 } 1103 } 1104 \decr\maxcoordsX 1105 \decr\maxcoordsY 1106 \foreach \x in {0,...,\maxcoordsX} { 1107 \foreach \y in {0,...,\maxcoordsY} { 1108 \node[dot,fill=none] (fakedot-\x-\y) at (\x,-\y) {}; 1109 \expandafter\ifnum\csname dotxypresent-\x-\y\endcsname=0 1110 \ifnum\y=0 1111 \node[coord,anchor=south west] at (fakedot-\x-\y.north east) {\reallysmallcheat{(\x, \y)}}; 1112 \else 1113 \node[coord,anchor=west,xshift=0.2] at (fakedot-\x-\y.east) {\reallysmallcheat{(\x, \y)}}; 1114 \fi 1115 \fi 1116 } 1117 } 1118 1119 % \foreach \i in {1, ...,6}{ 1120 % \node[constatation1] at (.5*\i,-.5*\i) {\i}; 1121 % } 1122 % \node[constatation1] at (.5*7,-.5*7) {\vdots}; 1123 1124 % \node[coordinate] (fake0-0) at (0,0) {}; 1125 % \node[coordinate] (fake1-0) at (1,0) {}; 1126 % \node[coordinate] (fake3-0) at (3,0) {}; 1127 % \node[coordinate] (fake5-0) at (5,0) {}; 1128 % \node[coordinate] (fake0-2) at (0,-2) {}; 1129 % \node[coordinate] (fake0-4) at (0,-4) {}; 1130 % \node[coordinate] (fake0-6) at (0,-6) {}; 1131 % \node[constatation2, above left of=fake0-0] {0}; 1132 % \node[constatation2, above of=fake1-0] {1}; 1133 % \node[constatation2, above of=fake3-0] {6}; 1134 % \node[constatation2, above of=fake5-0] {15}; 1135 % \node[constatation2, left of=fake0-2] {3}; 1136 % \node[constatation2, left of=fake0-4] {10}; 1137 % \node[constatation2, left of=fake0-6] {21}; 1138 \end{tikzpicture} 1139 \caption{Codage d'un couple d'entiers relatifs}%% TODO : caption 1140 \label{fig:codage-zigzag} 1141 \end{figure} 1142 1143 %% TODO: Il faudrait ajouter les coordonnées (0,0), (1,0), (0,1), et les codes correspondants au graphe ci-dessus, etc. VOIR LES DIAGRAMMES QUE J'AI DONNE A BERTRAND 1144 %% TODO : Réponse georges : c'est fait. 1145 1146 Dans la figure \ref{fig:codage-zigzag}, on commence par le couple $(0,0)$, puis on procède aux couples $(1,0)$, $(0,1)$, $(0,2)$, $(1,1)$, $(2,0)$, $(3,0)$, $(2,1)$, $(1,2)$, $(0,3)$, $(0,4)$\ldots L'algorithme pour simplement parcourir les couples de cette façon consisterait tout d'abord de déclarer et d'intialiser trois variables globales~: le point de départ, \lstinline!*current*!, et les valeurs maximales courantes de $x$ et de $y$, c'est-à-dire \lstinline!*max-x*! et \lstinline!*max-y*!. En LISP, ceci pourrait être codé comme suit~: 1147 1148 \begin{lstlisting}[language=Lisp] 1149 (defvar *current* (list 0 0 0)) ;; liste courante (code x y) 1150 (setf *current* (list 0 0 0)) 1151 (defvar *max-x* 0) ;; valeur maximal courante de x 1152 (setf *max-x* 0) 1153 (defvar *max-y* 0) ;; valeur maximal courante de y 1154 (setf *max-y* 0) 1155 \end{lstlisting} 1156 1157 On pourrait stocker toutes les valeurs de \lstinline!*current*! dans un tableau \lstinline!*db*! (base de données) comme suit~: 1158 1159 \begin{lstlisting}[language=Lisp] 1160 (defvar *db* nil) 1161 (setf *db* nil) 1162 (push *current* *db*) 1163 \end{lstlisting} 1164 1165 Puis, les conditions pour déterminer la direction à prendre afin de parcourir le graphe pourrait être implémentées comme suit (toujours en LISP)~: 1166 1167 \begin{lstlisting}[language=Lisp] 1168 (defun move (L) 1169 (cond 1170 ((and (zerop (third L)) (= *max-x* *max-y*)) 1171 ;; RIGHT takes precedence over LEFT becuase it occurs first 1172 (print "in RIGHT") ;; 1173 (right L)) 1174 ((and (zerop (second L)) (= *max-x* *max-y*)) ;; DOWN 1175 (print "in DOWN") 1176 (down L)) 1177 ((> *max-x* *max-y*) ;; DOWN-LEFT 1178 (print "in DOWN-LEFT") 1179 (down-left L)) 1180 ((< *max-x* *max-y*) ;; UP-RIGHT 1181 (print "in UP-RIGHT") 1182 (up-right L)))) 1183 \end{lstlisting} 1184 1185 La liste \lstinline!*current*! est passée en paramètre lorsque l'on appelle ces fonctions~: L correspond toujours à *current*. Les fonctions 'right', 'down', 'down-left' et 'up-right', qui correspondent au parcours dans la figure \ref{fig:codage-zigzag}, incrémente la première valeur de L (le codage), qui est une liste de la forme \lstinline!(code x y)!. Par ailleurs, la fonction 'right' incrémente la valeur courante de $x$ (le deuxième élément de la liste), la fonction 'down' incrémente la valeur courante de $y$ (la troisième élément de la liste), la fonction 'down-left' décrémente la valeur de $x$ et incrémente la valeur $y$ et la fonction 'up-right', elle, fait le contraire, elle incrémente la valeur de $x$ et décrémente la valeur de $y$. 1186 1187 On peut parcourir le graphe à l'aide de la fonction 'zig-zag' qui, elle, se sert de la fonction move-and-update afin de mettre à jour les variables globales *max-x* et *max-y*. 'move-and-update' se sert de 'move' qui choisit la bonne direction à prendre pour parcourir le graphe, c'est-à-dire 'right', 'down', 'down-left' ou 'up-right'~: 1188 1189 \begin{lstlisting}[language=Lisp] 1190 (defun move-and-update (L) 1191 (progn 1192 (setf L (move L)) 1193 (update-max-x-y L) 1194 *db*)) 1195 1196 (defun zig-zag (L n) 1197 (if (zerop n) 1198 (move-and-update *current*) 1199 (progn 1200 (move-and-update *current*) 1201 (zig-zag L (- n 1))))) 1202 \end{lstlisting} 1203 1204 1205 %% TODO : JOHN : 1206 %% Pour définir un label pour une section / sous-section / …, il faut mettre ceci juste après le \section{…} 1207 %% \label{foobar} 1208 %% 1209 %% Pour avoir le numéro de page correspondant : 1210 %% \pageref{foobar} 1211 %% 1212 %% Pour le numéro de section / sous-section / … : 1213 %% \ref{foobar} 1214 %% 1215 %% Tu changes foobar par un nom de ton choix. 1216 1217 %% TODO TODO TODO !!!!!!!! 1218 L'intégralité du programme est en annexe à la page \pageref{coupleslisp}. 1219 1220 Voici une trace de cette fonction en passant \lstinline!*current*! égal à \lstinline!(0 0 0)! et $n = 100$ en paramètres~: 1221 1222 \begin{lstlisting}[language=Lisp] 1223 > (zig-zag *current* 100) 1224 "in RIGHT" 1225 "in DOWN-LEFT" 1226 "in DOWN" 1227 "in UP-RIGHT" 1228 "in UP-RIGHT" 1229 "in RIGHT" 1230 (etc.) 1231 "in DOWN-LEFT" 1232 "in DOWN-LEFT" 1233 ((101 3 10) (100 4 9) (99 5 8) (98 6 7) (97 7 6) (96 8 5) 1234 (95 9 4) (94 10 3) (93 11 2) (92 12 1) (91 13 0) (90 12 0) 1235 (89 11 1) (88 10 2) (87 9 3) (86 8 4) (85 7 5) (84 6 6) 1236 (83 5 7) (82 4 8) (81 3 9) (80 2 10) (79 1 11) (78 0 12) 1237 (77 0 11) (76 1 10) (75 2 9) (74 3 8) (73 4 7) (72 5 6) 1238 (71 6 5) (70 7 4) (69 8 3) (68 9 2) (67 10 1) (66 11 0) 1239 (65 10 0) (64 9 1) (63 8 2) (62 7 3) (61 6 4) (60 5 5) 1240 (59 4 6) (58 3 7) (57 2 8) (56 1 9) (55 0 10) (54 0 9) 1241 (53 1 8) (52 2 7) (51 3 6) (50 4 5) (49 5 4) (48 6 3) 1242 (47 7 2) (46 8 1) (45 9 0) (44 8 0) (43 7 1) (42 6 2) 1243 (41 5 3) (40 4 4) (39 3 5) (38 2 6) (37 1 7) (36 0 8) 1244 (35 0 7) (34 1 6) (33 2 5) (32 3 4) (31 4 3) (30 5 2) 1245 (29 6 1) (28 7 0) (27 6 0) (26 5 1) (25 4 2) (24 3 3) 1246 (23 2 4) (22 1 5) (21 0 6) (20 0 5) (19 1 4) (18 2 3) 1247 (17 3 2) (16 4 1) (15 5 0) (14 4 0) (13 3 1) (12 2 2) 1248 (11 1 3) (10 0 4) (9 0 3) (8 1 2) (7 2 1) (6 3 0) (5 2 0) 1249 (4 1 1) (3 0 2) (2 0 1) (1 1 0) (0 0 0)) 1250 \end{lstlisting} 1251 1252 1253 \begin{enonce} 1254 Donner les fonctions de codage et de décodage $f_1(z)\rightarrow x$ et $f_2(z)\rightarrow y$. 1255 \end{enonce} 1256 1257 \begin{figure}[ht!] 1258 %% «Paramètres» 1259 \xdef\maxdots{23} 1260 \xdef\maxdotsX{5} 1261 \xdef\maxdotsY{5} 1262 \xdef\maxnums{20} 1263 \xdef\maxcoordsX{3} 1264 \xdef\maxcoordsY{3} 1265 1266 %% ===== Code is below ===== 1267 1268 %% Macros crades 1269 \makeatletter 1270 \def\myadv#1#2{% 1271 \xdef\incr@backup{\the\@tempcnta}% 1272 \@tempcnta=#1{}% 1273 \advance\@tempcnta by #2{}% 1274 \xdef#1{\the\@tempcnta}% 1275 \@tempcnta=\incr@backup{}% 1276 } 1277 \def\incr#1{% 1278 \myadv#1{1}% 1279 } 1280 \def\decr#1{% 1281 \myadv#1{-1}% 1282 } 1283 \makeatother 1284 \centering 1285 \begin{tikzpicture}[ 1286 scale=1.4, 1287 dot/.style={ 1288 circle, 1289 inner sep=0.7pt, 1290 fill=black 1291 }, 1292 dotphantom/.style={ 1293 circle, 1294 inner sep=3pt, 1295 fill=none, 1296 draw=none 1297 }, 1298 numero/.style={rectangle, fill=white, inner sep=2pt, text=red!50!black}, 1299 coord/.style={darkgray, scale=.8}, 1300 % 1301 bigarrow/.style={ 1302 ->, 1303 thick, 1304 draw=green!50!black 1305 }, 1306 constatation1/.style={ 1307 circle, 1308 inner sep=1.5pt, 1309 outer sep=0.8pt, 1310 fill=white, 1311 text=red, 1312 anchor=south, 1313 rotate around={45:(0,0)} 1314 }, 1315 constatation2/.style={ 1316 text=green!50!black, 1317 node distance=0.6cm 1318 } 1319 ] 1320 1321 %% Digonale 1322 \draw[bigarrow,red] (0,0) -- (.5*7.5,-.5*7.5); 1323 1324 % Définitions pour le code ci-dessous. 1325 \xdef\i{0} 1326 \xdef\x{0} 1327 \xdef\y{0} 1328 \xdef\corner{3} 1329 \xdef\sidelen{0} 1330 \xdef\nextsidelen{1} 1331 \xdef\direction{3} 1332 \incr\maxnums 1333 \incr\maxcoordsX 1334 \incr\maxcoordsY 1335 1336 \foreach \x in {0,...,\maxcoordsX} { 1337 \foreach \y in {1,...,\maxcoordsY} { 1338 \expandafter\xdef\csname dotxypresent-\x-\y\endcsname{0} 1339 } 1340 } 1341 1342 \def\reallysmallcheat#1{% 1343 \ensuremath{\hphantom{\vphantom{X}}_{\hphantom{\vphantom{X}}_{#1}}} 1344 } 1345 \def\drawnode{% 1346 \node[dot] (dot-\x-\y) at (\x,-\y) {}; 1347 \node[dotphantom] (phantom-\x-\y) at (\x,-\y) {}; 1348 \ifnum\maxnums>\i 1349 % \ifnum\corner=0 \node[numero,anchor=south] at (dot-\x-\y.north) {\i}; \else 1350 % \ifnum\corner=1 \node[numero,anchor=east] at (dot-\x-\y.west) {\i}; \else 1351 % \ifnum\corner=2 \node[numero,anchor=east] at (dot-\x-\y.west) {\i}; \else 1352 % \ifnum\corner=3 \node[numero,anchor=south] at (dot-\x-\y.north) {\i}; \else 1353 % \ifnum\direction=0 \node[numero,anchor=north west] at (dot-\x-\y.south east) {\i}; \else 1354 % \ifnum\direction=2 \node[numero,anchor=north west] at (dot-\x-\y.south east) {\i}; \fi\fi\fi\fi\fi\fi 1355 \node[numero,anchor=north west] at (dot-\x-\y.south east) {\i}; 1356 \fi 1357 \ifnum\maxcoordsX>\x 1358 \ifnum\maxcoordsY>\y 1359 % \ifnum\corner=0 \node[coord,anchor=south east] at (dot-\x-\y.north west) {\reallysmallcheat{(\x, \y)}}; \else 1360 % \ifnum\corner=1 \node[coord,anchor=north east] at (dot-\x-\y.south west) {\reallysmallcheat{(\x, \y)}}; \else 1361 % \ifnum\corner=2 \node[coord,anchor=north west] at (dot-\x-\y.south east) {\reallysmallcheat{(\x, \y)}}; \else 1362 % \ifnum\corner=3 \node[coord,anchor=south west] at (dot-\x-\y.north east) {\reallysmallcheat{(\x, \y)}}; \else 1363 % \ifnum\direction=0 \node[coord,anchor=east] at (dot-\x-\y.west) {\reallysmallcheat{(\x, \y)}}; \else 1364 % \ifnum\direction=1 \node[coord,anchor=north] at (dot-\x-\y.south) {\reallysmallcheat{(\x, \y)}}; \else 1365 % \ifnum\direction=2 \node[coord,anchor=west] at (dot-\x-\y.east) {\reallysmallcheat{(\x, \y)}}; \else 1366 % \ifnum\direction=3 \node[coord,anchor=south] at (dot-\x-\y.north) {\reallysmallcheat{(\x, \y)}}; \fi\fi\fi\fi\fi\fi\fi\fi 1367 \expandafter\xdef\csname dotxypresent-\x-\y\endcsname{1} 1368 \ifnum\y=0 1369 \node[coord,anchor=south west] at (dot-\x-\y.north east) {\reallysmallcheat{(\x, \y)}}; 1370 \else 1371 \node[coord,anchor=west,xshift=0.2] at (dot-\x-\y.east) {\reallysmallcheat{(\x, \y)}}; 1372 \fi 1373 \fi 1374 \fi 1375 } 1376 \def\drawlinknode{% 1377 \drawnode% 1378 \draw[->] (phantom-\oldx-\oldy) -- (phantom-\x-\y);% 1379 } 1380 \def\mystep{% 1381 \incr\i% 1382 \xdef\oldx{\x}% 1383 \xdef\oldy{\y}% 1384 } 1385 \def\changedir#1{% 1386 \xdef\direction{#1}% 1387 \xdef\corner{#1}% 1388 } 1389 1390 \drawnode 1391 \mystep \incr\x 1392 \xdef\cornerc{0} 1393 1394 \foreach \pos in {1,...,\maxdots} { 1395 % Detect when we are at the end of this edge. 1396 \ifnum\sidelen=0 1397 \ifnum\direction=0 \changedir{1} \incr\nextsidelen \xdef\sidelen{1} \else 1398 \ifnum\direction=1 \changedir{2} \xdef\sidelen{\nextsidelen} \else 1399 \ifnum\direction=2 \changedir{3} \incr\nextsidelen \xdef\sidelen{1} \else 1400 \ifnum\direction=3 \changedir{0} \xdef\sidelen{\nextsidelen} \fi\fi\fi\fi% Brin d'acier 1401 1402 \fi 1403 % Draw node and link to previous, step counters 1404 \drawlinknode \mystep 1405 %% Se déplacer vers ↙↓↗→ 1406 \ifnum\direction=0 \incr\y \decr\x \fi 1407 \ifnum\direction=1 \incr\y \fi 1408 \ifnum\direction=2 \decr\y \incr\x \fi 1409 \ifnum\direction=3 \incr\x \fi 1410 \decr\sidelen 1411 \xdef\corner{4}%% 4 == pas de coin-coin. 1412 } 1413 1414 \foreach \x in {0,...,\maxdotsX} { 1415 \foreach \y in {1,...,\maxdotsY} { 1416 \node[dot] (dot-\x-\y) at (\x,-\y) {}; 1417 } 1418 } 1419 \decr\maxcoordsX 1420 \decr\maxcoordsY 1421 \foreach \x in {0,...,\maxcoordsX} { 1422 \foreach \y in {0,...,\maxcoordsY} { 1423 \node[dot,fill=none] (fakedot-\x-\y) at (\x,-\y) {}; 1424 \expandafter\ifnum\csname dotxypresent-\x-\y\endcsname=0 1425 \ifnum\y=0 1426 \node[coord,anchor=south west] at (fakedot-\x-\y.north east) {\reallysmallcheat{(\x, \y)}}; 1427 \else 1428 \node[coord,anchor=west,xshift=0.2] at (fakedot-\x-\y.east) {\reallysmallcheat{(\x, \y)}}; 1429 \fi 1430 \fi 1431 } 1432 } 1433 1434 \foreach \i in {1, ...,6}{ 1435 \node[constatation1] at (.5*\i,-.5*\i) {\i}; 1436 } 1437 \node[constatation1] at (.5*7,-.5*7) {\vdots}; 1438 1439 \node[coordinate] (fake0-0) at (0,0) {}; 1440 \node[constatation2, coordinate, above of=fake0-0] (fake0-0-bis) {}; 1441 \node[coordinate] (fake1-0) at (1,0) {}; 1442 \node[coordinate] (fake3-0) at (3,0) {}; 1443 \node[coordinate] (fake5-0) at (5,0) {}; 1444 \node[coordinate] (fake0-2) at (0,-2) {}; 1445 \node[coordinate] (fake0-4) at (0,-4) {}; 1446 \node[coordinate] (fake0-6) at (0,-6) {}; 1447 \node[constatation2, left of=fake0-0-bis] {0}; 1448 \node[constatation2, above of=fake1-0] {1}; 1449 \node[constatation2, above of=fake3-0] {6}; 1450 \node[constatation2, above of=fake5-0] {15}; 1451 \node[constatation2, left of=fake0-2] {3}; 1452 \node[constatation2, left of=fake0-4] {10}; 1453 \node[constatation2, left of=fake0-6] {21}; 1454 \end{tikzpicture} 1455 \caption{Codage d'un couple d'entiers relatifs}%% TODO : caption 1456 \label{fig:codage-nat-avec-constatation} 1457 \end{figure} 1458 1459 1460 En reprenant la figure \ref{fig:codage-nat-avec-constatation} ci-dessus, on peut faire plusieurs constatations~: 1461 1462 \begin{itemize} 1463 \item La somme de $x$ et $y$ de chaque sommet du graphe d'une diagonale dans le sens du parcours est toujours la même. 1464 \item La longueur de chaque diagonale successive s'incrémente à chaque fois et nous donne par conséquent toujours une longueur impaire suivie d'une longueur paire. 1465 \item Le point à partir duquel on commence à incrémenter le code au long d'une diagonale correspond aux codes $1$, $3$, $6$, $10$, $15$, $21$\ldots (voir la figure \ref{fig:codage-nat-avec-constatation}), ce qui correspond à la formule de Gauss, à savoir~: 1466 1467 $$\dfrac{(n \times (n + 1))}{2}$$ 1468 \end{itemize} 1469 1470 Ces trois informations nous permettront de coder un couple de nombres naturels sans parcourir le graphe. En voici l'algorithme en C~: 1471 1472 \begin{lstlisting}[language=C] 1473 long int orderedPairToCodeNat(int x, int y){ 1474 long code; 1475 int sumxy; 1476 sumxy = x + y; 1477 code = ((sumxy)*(sumxy + 1))/2; 1478 1479 if(even(sumxy)){ 1480 code = code + x; 1481 } 1482 else{ 1483 code = code + y; 1484 } 1485 return code; 1486 } 1487 \end{lstlisting} 1488 1489 1490 En reprenant les trois informations constatées à partir du figure \ref{fig:codage-nat-avec-constatation} et les algorithmes décrits ci-dessus, il est également relativement facile de calculer n'importe quel couple d'entiers naturels à partir d'un code. En voici l'algorithme en C~: 1491 1492 \begin{lstlisting}[language=C] 1493 int* codeToOrderedPairNat(long int code){ 1494 int *couple = malloc(2*sizeof(int)); 1495 int n = sqrt(code * 2); 1496 long int axis = (n * (n + 1))/2; 1497 int diff = 0; 1498 if(axis > code){ 1499 n = n - 1; 1500 axis = (n * (n + 1))/2; 1501 } 1502 diff = code - axis; 1503 if(even(n)){ 1504 couple[0] = diff; 1505 couple[1] = n - diff; 1506 } 1507 else{ 1508 couple[0] = n - diff; 1509 couple[1] = diff; 1510 } 1511 return couple; 1512 } 1513 \end{lstlisting} 1514 1515 On trouve d'abord une valeur approximative du code correspondant aux valeurs de la formule de Gauss (la variable \lstinline!axis! dans la fonction ci-dessus), puis on modifie cette valeur afin qu'elle soit une valeur plus petite que le vrai code passé en paramètre. La valeur \lstinline!n! est égale soit à la valeur de \lstinline!x! soit à la valeur de \lstinline!y! d'un point extrêmal de la ligne diagonale en question (selon le point en question). On modifie les valeurs de \lstinline!x! et de \lstinline!y! en calculant la différence entre le code et le code approximatif (la variable $axis$), ce qui nous donne les valeurs de \lstinline!x! et de \lstinline!y! correspondant au code passé en paramètre. 1516 1517 Prenons un simple example. Mettons qu'on voulait connaitre le couple correspondant au code $19$. La valeur entière correspondant au point extrêmal de la diagonale est $15$ ($axis = 15$, $n = 5$). La différence entre ces deux points est $19 - 15 = 4$ ($diff = code - axis$). On soustrait $4$ à $5$ ($couple[0] = n - diff$) pour avoir la valeur de $x$ (ce qui nous donne $1$) et $4$ ($diff$) est la valeur de $y$. On retourne $x$ et $y$ (à savoir ($(1,4)$). 1518 1519 On peut étendre ce codage pour comprendre tous les nombres entiers en réutilisant la fonction ci-dessus. Voici l'algorithme implémenté en C de la fonction du codage des entiers~: 1520 1521 \begin{lstlisting}[language=C] 1522 long int orderedPairToCodeInt(int x, int y){ 1523 long int code = 0; 1524 1525 if (x < 0){ 1526 x = (2 * (abs (x))) - 1; 1527 } 1528 else{ 1529 x = 2 * x; 1530 } 1531 1532 if (y < 0){ 1533 y = (2 * (abs(y))) - 1; 1534 } 1535 else{ 1536 y = 2 * y; 1537 } 1538 1539 code = orderedPairToCodeNat(x, y); 1540 return code; 1541 } 1542 \end{lstlisting} 1543 1544 1545 On n'utilise que des valeurs positive pour ce codage. Si x est négative, on l'attribut une valeur impaire. Si \lstinline!x! est positif, on 1546 l'attribut une valeur paire, et il en va de même des valeurs de y. Ensuite, on passe le nouveau couple ainsi créé en paramètre en se servant 1547 de la fonction initialement créée pour coder les nombres naturels. 1548 1549 1550 Pour trouver un couple à partir d'un code, on fait l'inverse~: 1551 1552 \begin{lstlisting}[language=C] 1553 int* codeToOrderedPairInt(long int code){ 1554 int *pair = codeToOrderedPairNat(code); 1555 1556 if (even(pair[0])){ 1557 pair[0] = pair[0] / 2; 1558 } 1559 else{ 1560 pair[0] = (pair[0] / 2)*(-1) - 1; 1561 } 1562 1563 if (even (pair[1])){ 1564 pair[1] = pair[1] / 2; 1565 } 1566 else{ 1567 pair[1] = (pair[1] / 2)*(-1) - 1; 1568 } 1569 1570 return pair; 1571 } 1572 \end{lstlisting} 1573 1574 1575 Un autre système de codage pourrait être utilisé en parcourant un graphe comme montré dans la figure \ref{fig:codage-rel}. 1576 1577 \begin{figure}[ht!] 1578 %% «Paramètres» 1579 \xdef\maxdots{81} 1580 \xdef\maxnums{56} 1581 \xdef\maxcoords{20} 1582 1583 %% ===== Code is below ===== 1584 1585 %% Macros crades 1586 \makeatletter 1587 \def\myadv#1#2{% 1588 \xdef\incr@backup{\the\@tempcnta}% 1589 \@tempcnta=#1{}% 1590 \advance\@tempcnta by #2{}% 1591 \xdef#1{\the\@tempcnta}% 1592 \@tempcnta=\incr@backup{}% 1593 } 1594 \def\incr#1{% 1595 \myadv#1{1}% 1596 } 1597 \def\decr#1{% 1598 \myadv#1{-1}% 1599 } 1600 \makeatother 1601 % \centering 1602 \hskip -21mm%% Hack-o-matic to get the picture more or less centered… 1603 \begin{tikzpicture}[ 1604 dot/.style={ 1605 circle, 1606 inner sep=0.7pt, 1607 fill=black 1608 }, 1609 dotphantom/.style={ 1610 circle, 1611 inner sep=3pt, 1612 fill=none, 1613 draw=none 1614 }, 1615 numero/.style={circle, fill=white, inner sep=0.2pt, text=red, scale=.75}, 1616 coord/.style={darkgray, scale=.6}, 1617 % 1618 bigarrow/.style={ 1619 ->, 1620 thick, 1621 draw=green!50!black 1622 } 1623 ] 1624 1625 % Diagonales 1626 \node[dotphantom] (pre-phantom-0-0) at (0,0) {}; 1627 \node[dotphantom] (pre-phantom-1-0) at (1,0) {}; 1628 1629 % Top right 1630 \node[inner sep=0.1pt] (tr-start) at (4,4) {}; 1631 \xdef\previous{tr-start} 1632 \foreach \pos/\content in {0/$1\times 2=2$,1/$3\times 4=12$,2/$5\times 6=30$,3/$7\times 8=56$,4/$\vphantom{X}\dots$}{ 1633 \node[anchor=south] (tr-temp-\pos) at (intersection cs: first line={(\previous.north west)--(\previous.north east)}, second line={(0,0)--(6,6)}) {\phantom{\content}}; 1634 \node[anchor=north west] (tr-\pos) at (intersection cs: first line={(tr-temp-\pos.north west)--(tr-temp-\pos.north east)}, second line={(0,0)--(6,6)}) {\content}; 1635 \xdef\previous{tr-\pos} 1636 } 1637 \draw[bigarrow] (pre-phantom-0-0) -- (intersection cs: first line={(\previous.north west)--(\previous.south west)}, second line={(0,0)--(6,6)}); 1638 1639 % Top left 1640 \node[inner sep=0.1pt] (tl-start) at (-4,4) {}; 1641 \xdef\previous{tl-start} 1642 \foreach \pos/\content in {0/$0^2=0$,1/$2^2=4$,2/$6^2=36$,3/$8^2=64$,4/$\vphantom{X}\dots$}{ 1643 \node[anchor=south] (tl-temp-\pos) at (intersection cs: first line={(\previous.north west)--(\previous.north east)}, second line={(0,0)--(-6,6)}) {\phantom{\content}}; 1644 \node[anchor=north east] (tl-\pos) at (intersection cs: first line={(tl-temp-\pos.north west)--(tl-temp-\pos.north east)}, second line={(0,0)--(-6,6)}) {\content}; 1645 \xdef\previous{tl-\pos} 1646 } 1647 \draw[bigarrow] (pre-phantom-0-0) -- (intersection cs: first line={(\previous.north east)--(\previous.south east)}, second line={(0,0)--(-6,6)}); 1648 1649 % Bottom left 1650 \node[inner sep=0.1pt] (bl-start) at (-4,-4) {}; 1651 \xdef\previous{bl-start} 1652 \foreach \pos/\content in {0/$0\times 1=0$,1/$2\times 3=6$,2/$4\times 5=20$,3/$6\times 7=42$,4/$\vphantom{X}\dots$}{ 1653 \node[anchor=north] (bl-temp-\pos) at (intersection cs: first line={(\previous.south west)--(\previous.south east)}, second line={(0,0)--(-6,-6)}) {\phantom{\content}}; 1654 \node[anchor=south east] (bl-\pos) at (intersection cs: first line={(bl-temp-\pos.south west)--(bl-temp-\pos.south east)}, second line={(0,0)--(-6,-6)}) {\content}; 1655 \xdef\previous{bl-\pos} 1656 } 1657 \draw[bigarrow] (pre-phantom-0-0) -- (intersection cs: first line={(\previous.north east)--(\previous.south east)}, second line={(0,0)--(-6,-6)}); 1658 1659 % Bottom right 1660 \node[inner sep=0.1pt] (br-start) at (5,-4) {}; 1661 \xdef\previous{br-start} 1662 \foreach \pos/\content in {0/$1^2=1$,1/$3^2=9$,2/$5^2=25$,3/$7^2=49$,4/$\vphantom{X}\dots$}{ 1663 \node[anchor=north] (br-temp-\pos) at (intersection cs: first line={(\previous.south west)--(\previous.south east)}, second line={(1,0)--(6,-5)}) {\phantom{\content}}; 1664 \node[anchor=south west] (br-\pos) at (intersection cs: first line={(br-temp-\pos.south west)--(br-temp-\pos.south east)}, second line={(1,0)--(6,-5)}) {\content}; 1665 \xdef\previous{br-\pos} 1666 } 1667 \draw[bigarrow] (pre-phantom-1-0) -- (intersection cs: first line={(\previous.north west)--(\previous.south west)}, second line={(1,0)--(6,-5)}); 1668 % Fin diagonales 1669 1670 % Définitions pour le code ci-dessous. 1671 \xdef\i{0} 1672 \xdef\x{0} 1673 \xdef\y{0} 1674 \xdef\corner{4} 1675 \xdef\sidelen{0} 1676 \xdef\nextsidelen{1} 1677 \xdef\direction{3} 1678 \incr\maxnums 1679 \incr\maxcoords 1680 1681 \def\reallysmallcheat#1{% 1682 \ensuremath{\hphantom{\vphantom{X}}_{\hphantom{\vphantom{X}}_{#1}}} 1683 } 1684 \def\drawnode{% 1685 \node[dot] (dot-\x-\y) at (\x,\y) {}; 1686 \node[dotphantom] (phantom-\x-\y) at (\x,\y) {}; 1687 \ifnum\maxnums>\i 1688 \ifnum\corner=0 \node[numero,anchor=north west] at (dot-\x-\y.south east) {\i}; \else 1689 \ifnum\corner=1 \node[numero,anchor=south west] at (dot-\x-\y.north east) {\i}; \else 1690 \ifnum\corner=2 \node[numero,anchor=south east] at (dot-\x-\y.north west) {\i}; \else 1691 \ifnum\corner=3 \node[numero,anchor=north east] at (dot-\x-\y.south west) {\i}; \else 1692 \ifnum\direction=0 \node[numero,anchor=west] at (dot-\x-\y.east) {\i}; \else 1693 \ifnum\direction=1 \node[numero,anchor=south] at (dot-\x-\y.north) {\i}; \else 1694 \ifnum\direction=2 \node[numero,anchor=east] at (dot-\x-\y.west) {\i}; \else 1695 \ifnum\direction=3 \node[numero,anchor=north] at (dot-\x-\y.south) {\i}; \fi\fi\fi\fi\fi\fi\fi\fi 1696 \fi 1697 \ifnum\maxcoords>\i 1698 \ifnum\corner=0 \node[coord,anchor=south east] at (dot-\x-\y.north west) {\reallysmallcheat{(\x, \y)}}; \else 1699 \ifnum\corner=1 \node[coord,anchor=north east] at (dot-\x-\y.south west) {\reallysmallcheat{(\x, \y)}}; \else 1700 \ifnum\corner=2 \node[coord,anchor=north west] at (dot-\x-\y.south east) {\reallysmallcheat{(\x, \y)}}; \else 1701 \ifnum\corner=3 \node[coord,anchor=south west] at (dot-\x-\y.north east) {\reallysmallcheat{(\x, \y)}}; \else 1702 \ifnum\direction=0 \node[coord,anchor=east] at (dot-\x-\y.west) {\reallysmallcheat{(\x, \y)}}; \else 1703 \ifnum\direction=1 \node[coord,anchor=north] at (dot-\x-\y.south) {\reallysmallcheat{(\x, \y)}}; \else 1704 \ifnum\direction=2 \node[coord,anchor=west] at (dot-\x-\y.east) {\reallysmallcheat{(\x, \y)}}; \else 1705 \ifnum\direction=3 \node[coord,anchor=south] at (dot-\x-\y.north) {\reallysmallcheat{(\x, \y)}}; \fi\fi\fi\fi\fi\fi\fi\fi 1706 \fi 1707 } 1708 \def\drawlinknode{% 1709 \drawnode% 1710 \draw[->] (phantom-\oldx-\oldy) -- (phantom-\x-\y);% 1711 } 1712 \def\mystep{% 1713 \incr\i% 1714 \xdef\oldx{\x}% 1715 \xdef\oldy{\y}% 1716 } 1717 \def\changedir#1{% 1718 \xdef\direction{#1}% 1719 \xdef\corner{#1}% 1720 } 1721 1722 \drawnode 1723 \mystep \incr\x 1724 \xdef\cornerc{0} 1725 1726 \foreach \pos in {1,...,\maxdots} { 1727 % Detect when we are at the end of this edge. 1728 \ifnum\sidelen=0 1729 \ifnum\direction=0 \changedir{1} \incr\nextsidelen \else 1730 \ifnum\direction=1 \changedir{2} \else 1731 \ifnum\direction=2 \changedir{3} \incr\nextsidelen \else 1732 \ifnum\direction=3 \changedir{0} \fi\fi\fi\fi% Brin d'acier 1733 \xdef\sidelen{\nextsidelen} 1734 \fi 1735 % Draw node and link to previous, step counters 1736 \drawlinknode \mystep 1737 %% Se déplacer vers ↑←↓→ 1738 \ifnum\direction=0 \incr\y \fi 1739 \ifnum\direction=1 \decr\x \fi 1740 \ifnum\direction=2 \decr\y \fi 1741 \ifnum\direction=3 \incr\x \fi 1742 \decr\sidelen 1743 \xdef\corner{4}%% 4 == pas de coin-coin. 1744 } 1745 \end{tikzpicture} 1746 \caption{Codage d'un couple d'entiers relatifs} 1747 \label{fig:codage-rel} 1748 \end{figure} 1749 1750 Bien que les algorithmes d'encodage et de décodage ne soient pas les mêmes, le principe reste identique. 1751 1752 On peut faire plusieurs constations~: 1753 1754 \begin{itemize} 1755 \item Le code correspondant aux couples (1,1), (2,2), (3,3), (4,4)\ldots sont respectivement 1, 2, 12, 30\ldots, ce qui correspond à $(1 \times 2)$, $(3 \times 4)$, $(5 \times 6)$, $(7 \times 8)$\ldots 1756 \item Le code correspondant aux couples (0,0), (-1,-1), (-2,-2), (-3,-3)\ldots sont respectivement 0, 6, 20, 42\ldots, ce qui correspond à $(0 \times 1)$, $(2 \times 3)$, $(4 \times 5)$, $(6 \times 7)$\ldots 1757 \item Le code des couples $(1,0)$, $(2,-1)$, $(3,-2)$, $(4,-3)$ sont respectivement $1$, $9$, $25$, $49$\ldots ce qui correspond à la valeur de $(x + |y|))^{2}$, ce sont les carrés des entiers impairs. 1758 \item Le code des couples $(-1,-1)$, $(-2,-2)$, $(-3,-3)$, $(-4,-4)$ sont respectivement $4$, $16$, $36$, $64$\ldots, ce qui correspond à la valeur de $(|x| + |y|))^{2}$, ce sont les carrés des entiers pairs. 1759 \end{itemize} 1760 1761 1762 A l'aide de ces constations, on peut coder n'importe quel couple d'entiers. En voici un exemple en C~: 1763 1764 1765 \begin{lstlisting}[language=C] 1766 long int orderedPairToCodeIntAlgo2(int x, int y){ 1767 long int code = 0; 1768 int _x, _y, diff; 1769 _x = _y = diff = 0; 1770 int temp; 1771 int absmax; 1772 absmax = max(abs(x), abs(y)); 1773 1774 if(absmax == abs(x)){ // _x == x 1775 _x = _y = x; 1776 temp = abs(x) * 2; 1777 if(x < 0){ // x negative 1778 code = temp * (temp + 1); 1779 if(y < 0){ // x negative, y negative 1780 diff = abs(_y) - abs(y); 1781 } 1782 else{ // x negative, y positive 1783 diff = abs(_y) + abs(y); 1784 } 1785 } 1786 else{ // x positive 1787 code = (temp - 1) * temp; 1788 if(y > 0){ // x positive, y positive 1789 diff = abs(_y) - abs(y); 1790 } 1791 else{ // x positive, y negative 1792 diff = abs(_y) + abs(y); 1793 } 1794 } 1795 code = code - diff; 1796 } 1797 else{ // _y = y 1798 _x = _y = y; 1799 temp = abs(y) * 2; 1800 if(y < 0){ // y negative 1801 code = temp * (temp + 1); 1802 if(x < 0){ // y negative, x negative 1803 diff = abs(_x) - abs(x); 1804 } 1805 else{ // y negative, x positive 1806 diff = abs(_x) + abs (x); 1807 } 1808 } 1809 else{ // y positive 1810 code = (temp - 1) * temp; 1811 if(x > 0){ // y positive, x positive 1812 diff = abs(_x) - abs(x); 1813 } 1814 else{ // y positive, x negative 1815 diff = abs(_x) + abs(x); 1816 } 1817 } 1818 code = code + diff; 1819 } 1820 return code; 1821 } 1822 \end{lstlisting} 1823 1824 1825 On commence par trouver le max de $|x|$ et $|y|$~: $(-3,1)$ nous donnerait comme $absmax$ la valeur $3$. Ensuite on détermine si cette valeur correspond à la valeur de $x$ ou la valeur de $y$. Si cette valeur correspond à la valeur de $x$ (resp. $y$), on affecte la valeur de $x$ (resp. $y$) aux variables temporaires $\_x$ et $\_y$. Ensuite, on se sert de la propriété des multiplications décrite précédemment selon les quatre cas de figures possibles, à savoir, le cas où $x$ et $y$ sont positives, le cas où $x$ et $y$ sont négatives, celui où $x$ est positive et $y$ est négative, et inversement. On affecte une valeur provisoire à la variable $code$, qui est soit $temp$ (la valeur absolue de la max des deux coordonnées) multiplié par $temp + 1$ ou bien $temp$ multiplié par $temp - 1$ selon que la valeur de la coordonnée $absmax$ est négative ou positive respectivement. Nous avons à ce point un code approximatif. On peut facilement trouver la coordonnée correspondant à $absmax$, et pour trouver l'autre coordonnée on calcule la différence entre la valeur absolue de la coordonnée qu'on connaît et l'autre coordonnée afin d'ajuster le code. Puis, enfin, on retourne le code exact. 1826 1827 Le décodage utilise le même principe mais dans le sens inverse~: 1828 1829 \begin{lstlisting}[language=C] 1830 int* codeToOrderedPairIntAlgo2(long int code){ 1831 int* pair = malloc(2*sizeof(int)); 1832 int isqrtcode = (int) sqrt(code); 1833 long int pivotcode = isqrtcode * (isqrtcode + 1); 1834 int x, y; 1835 x = y = 0; 1836 1837 if(even(isqrtcode)){ 1838 x = y = -(isqrtcode / 2); 1839 if(code > pivotcode){ 1840 x = x + (code - pivotcode); 1841 } 1842 else{ 1843 y = y + (pivotcode - code); 1844 } 1845 } 1846 else{ 1847 x = y = (isqrtcode / 2) + 1; 1848 if(code > pivotcode){ 1849 x = x - (code - pivotcode); 1850 } 1851 else{ 1852 y = y - (pivotcode - code); 1853 } 1854 } 1855 pair[0] = x; 1856 pair[1] = y; 1857 return pair; 1858 } 1859 \end{lstlisting} 1860 1861 Plusieurs programmes complets pour le codage des entiers naturels et le codage des entiers se trouve annexe~: couples-2.lisp (page \pageref{couples2lisp}), couples-3.lisp (page \pageref{couples3lisp}), couples.c (page \pageref{couplesc}) et couple\_entiers.c (page \pageref{coupleentiersc}). 1862 1863 1864 1865 \begin{enonce} 1866 Montrer que l'on peut coder les triplets. Généraliser aux k-uplets, puis aux listes de longueurs quelconques. 1867 \end{enonce} 1868 1869 Pour coder un triplet $(x_1, x_2, x_3)$, on code d'abord le couple $(x_1, x_2)$, puis, soit $x^*$ le résultat intermédiaire, on code le couple $(x^*, x_3)$. 1870 1871 \begin{figure}[ht!] 1872 \centering 1873 \begin{tikzpicture} 1874 \node (x11) {$x_1$}; 1875 \node[right of=x11] (x21) {$x_2$}; 1876 \node[right of=x21] (x31) {$x_3$}; 1877 \node[coordinate] (xmark) at ($ .5*(x11) + .5*(x21) $) {}; 1878 \node[below of=xmark] (x*2) {$x^*$}; 1879 \node[coordinate] (xmark2) at ($ .5*(xmark) + .5*(x*2) $) {}; 1880 1881 \node[anchor=base] (x32) at (x*2.base -| x31) {$x_3$}; 1882 1883 \node[coordinate] (xmark4) at ($ .5*(x*2) + .5*(x32) $) {}; 1884 \node[below of=xmark4] (x*3) {résultat}; 1885 \node[coordinate] (xmark5) at ($ .5*(xmark4) + .5*(x*3) $) {}; 1886 1887 \draw (x11) -- (xmark2); 1888 \draw[->] (x21) -- (xmark2) -- (x*2); 1889 \draw[->] (x31) -- (x32 |- x*2.north); 1890 \draw (x*2) -- (xmark5); 1891 \draw[->] (x32) -- (xmark5) -- (x*3); 1892 \end{tikzpicture} 1893 \caption{Codage d'un triplet d'entiers naturels} 1894 \label{fig:codage-couple} 1895 \end{figure} 1896 1897 Le décodage suit tout simplement le chemin inverse (on décode ne nombre en $(x^*, x_3)$, puis on décode $x^*$ en $(x_1, x_2)$ et on recompose en $(x_1, x_2, x_3)$. 1898 1899 La généralisation aux k-uplets suit le même principe : On code les deux premiers nombres de la paire en nommant le résultat $x^*$, puis, on 1900 code successivement chaque paire $(x^*, x_i)$, avec $x_i$ qui vaut successivement chaque élément du k-uplet, et $x^*$ qui vaut à chaque fois 1901 le résultat précédent. 1902 1903 Le décodage d'un k-uplet de longueur k décodera le nombre en une paire $(x^*, x_i)$ $k-1$ fois, et la dernière paire ainsi générée sera 1904 $(x_1, x_2)$. Il suffira alors de recomposer le k-uplet à partir de $x_1$, $x_2$ et tous les $x_i$. 1905 1906 Le codage et le décodage d'un singleton sont triviaux : $(x_1) \leftrightarrow x_1$. 1907 1908 Pour les listes de longueur quelconque, le problème est de savoir combien de fois faudra-t-il décoder le résultat. En effet, $(0)$, $(0,0)$ 1909 et $(0,0,0)$ ont le même code, $0$, donc il n'y a plus de bijection entre la liste et les entiers naturels, donc ambiguïté lors du décodage. 1910 1911 Étant donné que pour un k donné, il y a une bijection entre les k-uplets et les entiers naturels, il nous suffit d'ajouter une information 1912 permettant de déterminer de manière unique la valeur de k. On code donc d'abbord le k-uplet correspondant à la liste, en nommant le résultat 1913 $x^*$, puis on code le couple $(x^*, k)$. Au décodage, on décodera le nombre pour obtenir $x^*$ et $k$, et on décodera $x^*$ avec la méthode 1914 de décodage des k-uplets donnés ci-dessus. 1915 1916 Reste un dernier problème, celui de pouvoir encoder des listes d'entiers relatifs (et non pas juste des entiers naturels). Pour cela, on 1917 fera une transformation préalable sur chaque élément des k-uplets : 1918 1919 Soit $n$ le $i$-ième élément du k-uplet, si $n$ est positif, on le transforme en le $n$-ième nombre pair, sinon, il est strictement négatif et on le transforme en le $|n|-1$ ième nombre impair. Ainsi, $0 \mapsto 0$, $1 \mapsto 2$, $2 \mapsto 4$, $-1 \mapsto 1$, $-2 \mapsto 3$, \dots 1920 1921 \begin{equation} 1922 \begin{array}{r l} 1923 \mathrm{transformation} : Z & \longrightarrow N \\ 1924 n & \mapsto 1925 \left \{ 1926 \begin{array}{r l} 1927 2n & \text{si $n$ est pair} \\ 1928 2(|n|-1) & \text{si $n$ est impair} 1929 \end{array} 1930 \right . 1931 \end{array} 1932 \end{equation} 1933 1934 Le codage d'une liste d'entiers relatifs peut donc être résumé par la figure \ref{fig:codage-all} 1935 1936 \begin{figure}[ht!] 1937 \centering 1938 \begin{tikzpicture}[ 1939 level distance=0.7cm, 1940 circle, 1941 inner sep=0.1pt, 1942 ] 1943 \node[rectangle, inner sep=1pt] (res) {$\text{résultat}$} [grow=up] 1944 child[draw=red] { 1945 node[coordinate] (catch-k) {} edge from parent[<-] 1946 } 1947 child { 1948 node {x*} 1949 child { 1950 child { 1951 child { 1952 child { 1953 child { 1954 child { 1955 node (xk) {$x_{\phantom{k}}$} 1956 % node[anchor=base] at (xk.base) {$\vphantom{x}_{k}$} 1957 % node[anchor=east] at (xk.east) {$\hphantom{x}_{k}$} 1958 node[anchor=base] (get-k-v) at (xk.base) {$\vphantom{x}_{\phantom{k}}$} 1959 node[anchor=east] (get-k-h) at (xk.east) {$\hphantom{x}_{\phantom{k}}$} 1960 node[coordinate] (get-k-se) at (get-k-v.south -| get-k-h.east) {} 1961 node[coordinate] (get-k-nw) at (get-k-v.north -| get-k-h.west) {} 1962 node[anchor=base east, draw=red, inner sep=0.15pt] (the-k) 1963 at (get-k-v.base -| get-k-h.east) {$\vphantom{.}_{k}$} 1964 } 1965 } 1966 } 1967 } 1968 } edge from parent[<-] 1969 } 1970 child { 1971 node {x*} 1972 child { 1973 child { 1974 child { 1975 child { 1976 child {node {...} edge from parent[dashed]} 1977 edge from parent[dashed] 1978 } 1979 edge from parent[dashed] 1980 } 1981 edge from parent[dashed] 1982 } 1983 edge from parent[dashed,<-] 1984 } 1985 child { 1986 node{x*} 1987 child { 1988 child { 1989 child { 1990 child {node {$x_5$}} 1991 } 1992 } edge from parent[<-] 1993 } 1994 child { 1995 node{x*} 1996 child { 1997 child { 1998 child {node {$x_4$}} 1999 } edge from parent[<-] 2000 } 2001 child { 2002 node{x*} 2003 child { 2004 child {node {$x_3$}} edge from parent[<-] 2005 } 2006 child { 2007 node{x*} [sibling distance=7.5mm] edge from parent[<-] 2008 child {node {$x_2$} edge from parent[<-]} 2009 child {node {$x_1$} edge from parent[<-]} 2010 child[missing] {} 2011 } edge from parent[<-] 2012 } edge from parent[<-] 2013 } edge from parent[<-] 2014 } edge from parent[<-] 2015 } edge from parent[<-] 2016 }; 2017 2018 \draw[red] (the-k) -| (catch-k); 2019 2020 \node[xshift=0cm, anchor=base west] at (res.base east) {$\vphantom{\text{résultat}} = \operatorname{code}(x^*,k)$}; 2021 2022 % \node (e11) {$x_1$}; 2023 % \node[right of=e11] (e21) {$x_2$}; 2024 % \node[right of=e21] (e31) {$x_3$}; 2025 % \node[right of=e31] (e41) {$x_4$}; 2026 % \node[right of=e41] (e51) {$x_5$}; 2027 % \node[right of=e51] (ed1) {\dots}; 2028 % \node[right of=ed1] (ek1) {$x_k$}; 2029 2030 2031 % \matrix[column sep=2mm, row sep=7mm]{ 2032 % \node (e11) {$x_1$}; & \node[coordinate] (o11) {}; & 2033 % \node (e21) {$x_2$}; & \node[coordinate] (o21) {}; & 2034 % \node (e31) {$x_3$}; & \node[coordinate] (o31) {}; & 2035 % \node (e41) {$x_4$}; & \node[coordinate] (o41) {}; & 2036 % \node (e51) {$x_5$}; & \node[coordinate] (o51) {}; & 2037 % \node (ed1) {\dots}; & \node[coordinate] (o61) {}; & 2038 % \node (ek1) {$x_k$}; & \node[coordinate] (o71) {}; \\ 2039 2040 % \node[coordinate] (e12) {}; & \node (o11) {$x^*$}; & 2041 % \node (e22) {$x_2$}; & \node[coordinate] (o22) {}; & 2042 % \node (e32) {$x_3$}; & \node[coordinate] (o32) {}; & 2043 % \node (e42) {$x_4$}; & \node[coordinate] (o42) {}; & 2044 % \node (e52) {$x_5$}; & \node[coordinate] (o52) {}; & 2045 % \node (ed2) {\dots}; & \node[coordinate] (o62) {}; & 2046 % \node (ek2) {$x_k$}; & \node[coordinate] (o72) {}; \\ 2047 2048 % \node[coordinate] (e12) {}; & \node[coordinate] (o12) {}; & 2049 % \node[coordinate] (e22) {}; & \node (o22) {$x^*$}; & 2050 % \node (e32) {$x_3$}; & \node[coordinate] (o32) {}; & 2051 % \node (e42) {$x_4$}; & \node[coordinate] (o42) {}; & 2052 % \node (e52) {$x_5$}; & \node[coordinate] (o52) {}; & 2053 % \node (ed2) {\dots}; & \node[coordinate] (o62) {}; & 2054 % \node (ek2) {$x_k$}; & \node[coordinate] (o72) {}; \\ 2055 2056 % \node[coordinate] (e12) {}; & \node[coordinate] (o12) {}; & 2057 % \node[coordinate] (e22) {}; & \node[coordinate] (o22) {}; & 2058 % \node[coordinate] (e32) {}; & \node (o32) {$x^*$}; & 2059 % \node (e42) {$x_4$}; & \node[coordinate] (o42) {}; & 2060 % \node (e52) {$x_5$}; & \node[coordinate] (o52) {}; & 2061 % \node (ed2) {\dots}; & \node[coordinate] (o62) {}; & 2062 % \node (ek2) {$x_k$}; & \node[coordinate] (o72) {}; \\ 2063 2064 % \node[coordinate] (e12) {}; & \node[coordinate] (o12) {}; & 2065 % \node[coordinate] (e22) {}; & \node[coordinate] (o22) {}; & 2066 % \node[coordinate] (e32) {}; & \node[coordinate] (o32) {}; & 2067 % \node[coordinate] (e42) {}; & \node (o42) {$x^*$}; & 2068 % \node (e52) {$x_5$}; & \node[coordinate] (o52) {}; & 2069 % \node (ed2) {\dots}; & \node[coordinate] (o62) {}; & 2070 % \node (ek2) {$x_k$}; & \node[coordinate] (o72) {}; \\ 2071 % }; 2072 2073 % \node[coordinate] (x11-21) at ($ .5*(x11) + .5*(x21) $) {}; 2074 % \node[coordinate] (x21-31) at ($ .5*(x11) + .5*(x21) $) {}; 2075 % \node[coordinate] (x31-41) at ($ .5*(x11) + .5*(x21) $) {}; 2076 % \node[coordinate] (x41-51) at ($ .5*(x11) + .5*(x21) $) {}; 2077 % \node[coordinate] (x51-d1) at ($ .5*(x11) + .5*(x21) $) {}; 2078 % \node[coordinate] (xd1-k1) at ($ .5*(x11) + .5*(x21) $) {}; 2079 2080 % \node[below of=xmark] (x*2) {$x^*$}; 2081 % \node[coordinate] (xmark2) at ($ .5*(xmark) + .5*(x*2) $) {}; 2082 2083 % \node[anchor=base] (x32) at (x*2.base -| x31) {$x_3$}; 2084 2085 % \node[coordinate] (xmark4) at ($ .5*(x*2) + .5*(x32) $) {}; 2086 % \node[below of=xmark4] (x*3) {résultat}; 2087 % \node[coordinate] (xmark5) at ($ .5*(xmark4) + .5*(x*3) $) {}; 2088 2089 % \draw (x11) -- (xmark2); 2090 % \draw[->] (x21) -- (xmark2) -- (x*2); 2091 % \draw[->] (x31) -- (x32 |- x*2.north); 2092 % \draw (x*2) -- (xmark5); 2093 % \draw[->] (x32) -- (xmark5) -- (x*3); 2094 \end{tikzpicture} 2095 \caption{Codage d'un $n$-uplet d'entiers} 2096 \label{fig:codage-all} 2097 \end{figure} 2098 2099 %% TODO : ce qui suit est un doublon du début de l'exercice !?! 2100 2101 Pour coder les triplets, on considère un triplet, (3,1,2) par exemple, comme un couple (3,(1,2)). On calcule le code du couple imbriqué, 2102 c'est-à-dire du couple (1,2), ce qui nous donne 8. On refait le même codage en substituant 8 à (1,2), ce qui nous donne (3,8). On code 2103 ensuite (3,8) et notre résultat est 74. L'algorithme est récursif, tant qu'on n'a pas un couple à deux éléments atomiques, on continue à 2104 coder les \og{}sous-couples\fg{}, ce qui nous permet non seulement de coder les triplets, mais de coder n'importe quel k-uplet. Donc, pour 2105 ce faire, il nous faut deux informations, le code et la taille du k-uplet, qui est implicite lorsque l'on code, mais qui doit être 2106 explicitée lorsque l'on doit trouver le k-uplet à partir d'un code. 2107 2108 Voici le code en C pour coder et décoder respectivement n'importe quel k-uplet de nombres entiers en reprenant les fonctions déjà décrites 2109 dans la réponse de la question précédente~: 2110 2111 \begin{lstlisting}[language=C] 2112 2113 long int orderedMultipleToCodeInt(int *arr, int size){ 2114 long int code; 2115 if(size > 1){ 2116 code = orderedPairToCodeInt(arr[size - 2], arr[size - 1]); 2117 arr[size - 2] = code; 2118 arr = realloc(arr, (size - 1)); 2119 if(size > 2){ 2120 code = orderedMultipleToCodeInt(&arr[0], (size - 1)); 2121 } 2122 } 2123 return code; 2124 } 2125 2126 int* codeToOrderedMultipleInt(long int code, int size){ 2127 int *multiple = malloc(size*sizeof(int)); 2128 int *pair; 2129 int i = 0; 2130 for(i = 0; i < (size - 1); i++){ 2131 pair = codeToOrderedPairInt(code); 2132 code = pair[1]; 2133 multiple[i] = pair[0]; 2134 multiple[i + 1] = pair[1]; 2135 } 2136 return multiple; 2137 } 2138 2139 \end{lstlisting} 2140 2141 2142 Plusieurs programmes permettant de coder et de décoder des couples et des k-uplets en LISP et en C sont fournis en annexe de ce document, y 2143 compris les fonctions 'int* codeToOrderedMultipleIntAlgo2(long int code, int size)' et 'long int orderedMultipleToCodeIntAlgo2(int *arr, int 2144 size)' qui se servent du deuxième algorithme pour coder et pour décoder les k-uplets de nombres entiers. 2145 2146 2147 \begin{enonce} 2148 Peut-on énumérer les fonctions C syntaxiquements correctes ? Et les fonctions C qui ne bouclent jamais ? Justifier vos réponses le plus 2149 clairement et le plus synthétiquement possible. 2150 \end{enonce} 2151 2152 On sait énumérer récursivement toutes les séquences d'octets~: 2153 2154 Pour passer d'une séquence à la suivante, on commence par le dernier octet. S'il est inférieur à 255, on incrémente sa valeur de 1, sinon on passe à l'octet d'avant, et continue la même démarche. Si on arrive au premier octet de la séquence sans avoir pu en incrémenter de 1, on crée une séquence d'octets de longueur $n + 1$ (où $n$ est la longueur de la séquence courante) dans laquelle chaque octet vaut zéro. 2155 2156 Pour énumérer les fonctions C syntaxiquement correctes, on passe successivement chaque séquence d'octets et on vérifie si elle correspond à une fonction C syntaxiquement correcte (La reconaissance de la syntaxe C peut être faite grâce à un automate, qui se termine toujours dans un temps fini). S'il s'agit d'une fonction C syntaxiquement correcte, on l'affiche, et dans tous les cas on passe à la suivante et on recommence. 2157 2158 Énumérer les fonctions consiste à fournir un algorithme (donc un programme) permettant de donner l'élément suivant à partir de l'élément courant (ou de les donner un à un, ce qui revient à la même chose). 2159 2160 Dans ce cas-ci, il faudrait donc faire un programme (algorithme) qui énumère toutes les fonctions C (ce qu'on sait faire), et soit capable de ne pas lister celles qui bouclent indéfiniment. 2161 2162 Or, cela signifierait que ce programme (algorithme) serait capable de résoudre le problème de l'arrêt, ce qui n'est pas possible. 2163 2164 % TODO : faire un titre de la ligne suivante 2165 \textbf{Démonstration de l'impossibilité de résoudre algorithmiquement le problème de l'arrêt.} 2166 2167 Supposons qu'il existe un programme $h(p, x)$ prennant en paramètre un programme et une donnée tel que : 2168 \[ 2169 h(p, x) = \left\{ 2170 \begin{array}{ll} 2171 1 & \qquad \text{si $p(x)$ se termine} \\ 2172 0 & \qquad \text{sinon $p(x)$ boucle indéfiniment} \\ 2173 \end{array} 2174 \right. 2175 \] 2176 2177 \ldots on pourrait alors construire le programme $gamma(n)$ suivant~: 2178 \begin{lstlisting}[language=C] 2179 int gamma(int n) { 2180 if (h(gamma, n)) 2181 while (1); 2182 else 2183 return (0); 2184 } 2185 \end{lstlisting} 2186 Si $gamma(n)$ se termine, alors $gamma(n)$ boucle et donc ne se termine pas. Si $gamma(n)$ ne se termine pas, alors $gamma(n)$ retourne 0, 2187 donc $gamma(n)$ se termine. 2188 2189 Dans les deux cas, il y a contradiction. Par conséquent, il n'est pas possible de déterminer algorithmiquement si un programme s'arrête ou 2190 boucle indéfiniment, et donc il est impossible d'énumerer toutes les fonctions C qui ne bouclent jamais (puisqu'on ne peut pas savoir si la 2191 fonction en question boucle ou non, on ne peut pas savoir si elle fait partie de l'énumération ou non). 2192 2193 \section{Partie pratique sur les algorithmes de flots} 2194 2195 2196 \subsubsection*{Exercice \stepcounter{exocount}\bf\small \arabic{exocount} -- La méthode de Edmonds-Karp et celle de Dinic} 2197 \addcontentsline{toc}{subsubsection}{Exercice \arabic{exocount} -- La méthode de Edmonds-Karp et celle de Dinic} 2198 \setcounter{enoncecount}{0} 2199 2200 \begin{enonce} 2201 Programmer une procédure qui construit à partir d'un graphe orienté valué (les valuations représentent les capacités) et deux sommets $s$ et $p$ du graphe, le graphe d'écart associé (correspondant à un flot nul sur chaque arc). 2202 \end{enonce} 2203 2204 (Voir Annexe B, page \pageref{annexeexo5}) 2205 2206 \begin{enonce} 2207 Programmer un procédure qui à partir d'un graphe orienté et deux sommets $s$ et $p$ donne un plus court chemin en nombre d'arcs de $s$ à $p$ ou qui signale s'il n'y en a pas. 2208 \end{enonce} 2209 2210 (Voir Annexe B, page \pageref{annexeexo5}) 2211 2212 \begin{enonce} 2213 Etant donnés un graphe G orienté et valué et un chemin de G, écrire une fonction uqi calcule l'arc de plus petite valuation sur le chemin. 2214 \end{enonce} 2215 2216 (Voir Annexe B, page \pageref{annexeexo5}) 2217 2218 \begin{enonce} 2219 Etant donnés un graphe d'écard, un chemin et un entier $k$, donner une procédure qui met à jour le graphe d'écard si on augmente le flot de $k$ le long de la chaîne augmentante correspondant au chemin. 2220 \end{enonce} 2221 2222 (Voir Annexe B, page \pageref{annexeexo5}) 2223 2224 \begin{enonce} 2225 Ecrire une procédure qui à partir du graphe initial et du graphe d'écard final (plus de chemins entre $s$ et $p$ donne la valeur du flot maximum ainsi que la valeur deu flot sur chaque arc lorsque le flot maximum est atteint. 2226 \end{enonce} 2227 2228 (Voir Annexe B, page \pageref{annexeexo5}) 2229 2230 \begin{enonce} 2231 En utilisant les procédures et les fonctions précédentes, programmer l'algorithme de Edmond-Karp. 2232 \end{enonce} 2233 2234 (Voir Annexe B, page \pageref{annexeexo5}) 2235 2236 \begin{enonce} 2237 Ecrire une procédure qui prend en compte l'ensemble des plus cours chemins en nombres d'arcs. 2238 \end{enonce} 2239 2240 (Voir Annexe B, page \pageref{annexeexo5}) 2241 2242 \begin{enonce} 2243 Ecrire une procédure qui calcule la plus petite valeur du flot dans le graphe de couche. 2244 \end{enonce} 2245 2246 (Voir Annexe B, page \pageref{annexeexo5}) 2247 2248 \begin{enonce} 2249 Ecrire une procédure qui met à jour le flot dans le graphe G. 2250 \end{enonce} 2251 2252 (Voir Annexe B, page \pageref{annexeexo5}) 2253 2254 \begin{enonce} 2255 En déduire l'algorithme de Dinic. 2256 \end{enonce} 2257 2258 (Voir Annexe B, page \pageref{annexeexo5}) 2259 2260 \begin{enonce} 2261 Comparer les résultats (temps d'exécution, taux d'occupation mémoire) entre les deux méthodes. Vous apporterez un soin tout particulier à la génération de vos résultats et à leur présentation. 2262 \end{enonce} 2263 2264 Les graphiques ci-dessous représentent le temps d'exécution et l'espace mémoire utilisé par nos implémentations de l'algorithme de Dinic et d'Elmonds-Karp. Notre implémentation de l'algorithme de Dinic fonctionne, mais les résultats montrés dans les graphiques ne reflète pas la réalité car nous avons mal implémenté la gestion de la structure de couche dans cet algorithme, ce qui rend notre implémentation très gourmand en mémoire. 2265 2266 \newpage 2267 \input{temps} 2268 \newpage 2269 \input{espace} 2270 \newpage 2271 \input{espace2} 2272 \newpage 2273 2274 \appendix 2275 \section{Annexe~: Exercice 4} 2276 \label{annexe-deb} 2277 \newpage 2278 \subsection{couples.lisp} 2279 \label{coupleslisp} 2280 \begin{lstlisting}[language=Lisp, basicstyle=\footnotesize] 2281 2282 ;;COUPLES.LISP 2283 2284 ;; definition des variables globales (toujours entre asterisques) 2285 (defvar *current* (list 0 0 0)) ;; liste courante "(code x y)" 2286 (setf *current* (list 0 0 0)) 2287 (defvar *db* nil) ;; base de donnees qui stocke tous les "(code x y)" 2288 (setf *db* nil) 2289 (push *current* *db*) 2290 2291 (defvar *max-x* 0) ;; valeur maximal courante de x 2292 (setf *max-x* 0) 2293 (defvar *max-y* 0) ;; valeur maximal courante de y 2294 (setf *max-y* 0) 2295 2296 #| pour remettre toutes les variables globales a leur valeurs par defaut 2297 afin de tester, de refaire un 'zig-zag', etc. 2298 |# 2299 (defun reset () 2300 (progn 2301 (defvar *current* (list 0 0 0)) ;; liste courante (cle x y) 2302 (setf *current* (list 0 0 0)) 2303 (defvar *db* nil) ;; base de donnees qui stocke tous les "(cle x y)" 2304 (setf *db* nil) 2305 (push *current* *db*) 2306 (defvar *max-x* 0) ;; valeur maximal de x jusque "la" 2307 (setf *max-x* 0) 2308 (defvar *max-y* 0) ;; valeur maximal de y jusque "la" 2309 (setf *max-y* 0) 2310 *current*)) 2311 2312 #| Les fonctions "right" "down-left", "down", "up-right" imitent le movement des 2313 coordonnees sur un graphe mais au les coordonnees "y" positifs sont en DESSOUS du graphe 2314 |# 2315 (defun right (L) 2316 (progn 2317 (push 2318 (setf *current* 2319 (cons (+ 1 (first L)) (cons (+ 1 (second L)) (last L)))) *db*) 2320 *current*)) 2321 2322 (defun down (L) 2323 (progn 2324 (push 2325 (setf *current* 2326 (cons (+ 1 (first L)) (cons (second L) (cons (+ 1 (third L)) ())))) *db*) 2327 *current*)) 2328 2329 (defun up-right (L) 2330 (progn 2331 (push 2332 (setf *current* 2333 (cons (+ 1 (first L)) (cons (+ 1 (second L)) (cons (- (third L) 1) ())))) *db*) 2334 *current*)) 2335 2336 (defun down-left (L) 2337 (progn 2338 (push 2339 (setf *current* 2340 (cons (+ 1 (first L)) (cons (- (second L) 1) (cons (+ 1 (third L)) ())))) *db*) 2341 *current*)) 2342 2343 (defun update-max-x (L) 2344 (if (> (second L) *max-x*) 2345 (setf *max-x* (second L)) 2346 nil)) 2347 2348 (defun update-max-y (L) 2349 (if (> (third L) *max-y*) 2350 (setf *max-y* (third L)) 2351 nil)) 2352 2353 (defun update-max-x-y (L) 2354 (cond 2355 ((> (second L) *max-x*) 2356 (setf *max-x* (second L))) 2357 ((> (third L) *max-y*) 2358 (setf *max-y* (third L))) 2359 (t ()))) 2360 2361 ;; "move" s'occupe de choisir "right", "down-left" etc. selon les valeurs dans *current* 2362 (defun move (L) 2363 (cond 2364 ((and (zerop (third L)) (= *max-x* *max-y*)) ;; RIGHT takes precedence over LEFT becuase it occurs first 2365 (print "in RIGHT") ;; 2366 (right L)) 2367 ((and (zerop (second L)) (= *max-x* *max-y*)) ;; DOWN 2368 (print "in DOWN") 2369 (down L)) 2370 ((> *max-x* *max-y*) ;; DOWN-LEFT 2371 (print "in DOWN-LEFT") 2372 (down-left L)) 2373 ((< *max-x* *max-y*) ;; UP-RIGHT 2374 (print "in UP-RIGHT") 2375 (up-right L)))) 2376 2377 #| 2378 On fait un "move" et puis un "update-max-x-y" 2379 Attention : il faut bien faire un setf L, sinon, le parametre L de "update-max-x-y utilise la valeur 2380 de L inchange ! 2381 |# 2382 (defun move-and-update (L) 2383 (progn 2384 (setf L (move L)) 2385 (update-max-x-y L) 2386 *db*)) 2387 2388 ;; "zig-zag" fait n "move-and-update" en un seul coup et affiche le contenu de *db* (toutes les couples) 2389 (defun zig-zag (L n) 2390 (if (zerop n) 2391 (move-and-update *current*) 2392 (progn 2393 (move-and-update *current*) 2394 (zig-zag L (- n 1))))) 2395 2396 ;;END COUPLES.LISP 2397 2398 \end{lstlisting} 2399 2400 \subsection{couples-2.lisp} 2401 \label{couples2lisp} 2402 \begin{lstlisting}[language=Lisp, basicstyle=\footnotesize] 2403 2404 ;;COUPLES-2.LISP 2405 2406 (defun gauss-formula (n) 2407 (/ (* n (+ n 1)) 2)) 2408 2409 (defun get-n (code) 2410 (isqrt (* code 2))) 2411 2412 (defun get-axis (code) 2413 (gauss-formula (isqrt (* code 2)))) 2414 2415 (defun get-axis-from-n (n) 2416 (gauss-formula n)) 2417 2418 (defun axis-code-compare (code) 2419 (format t "~d ~d~%" code (get-axis code))) 2420 2421 (defun axis-code-compare-n (startcode n) 2422 (let ((i 0)) 2423 (loop 2424 (when (> i n) (return)) 2425 (axis-code-compare (+ startcode i)) 2426 (incf i)))) 2427 2428 (defun ord-pr-to-code (x y) 2429 (let ((sumxy (+ x y))) 2430 (if (evenp sumxy) 2431 (+ (gauss-formula sumxy) x) 2432 (+ (gauss-formula sumxy) y)))) 2433 2434 (defun code-to-ord-pr (code) 2435 (let ((n (get-n code)) 2436 (axis (get-axis code)) 2437 (diff 0)) 2438 (progn 2439 (when (> (get-axis code) code) 2440 (progn 2441 (setf n (- n 1)) 2442 (setf axis (get-axis-from-n n)))) 2443 (setf diff (- code axis)) 2444 (if (evenp n) 2445 (cons diff (cons (- n diff) ())) 2446 (cons (- n diff) (cons diff ())))))) 2447 2448 (defun ord-mult-to-code (L) 2449 (if (= (list-length L) 1) 2450 (car L) 2451 (ord-mult-to-code (append (butlast (butlast L)) 2452 (cons (ord-pr-to-code (car (last (butlast L))) (car (last L))) ()))))) 2453 2454 (defun code-to-ord-mult (L-or-code size) 2455 (if (atom L-or-code) 2456 (code-to-ord-mult (code-to-ord-pr L-or-code) (- size 1)) 2457 (if (not (= size 1)) 2458 (code-to-ord-mult (append (butlast L-or-code) (code-to-ord-pr (car (last L-or-code)))) 2459 (- size 1)) 2460 L-or-code))) 2461 2462 #| Les codes generes par cette fonction ne correspondent pas au code genere par le 2463 diagramme du rapport ni des fonctions ord-mult-to-code et code-to-ord-mult. 2464 Toutefois, la fonction ci-dessous a ete creees ici car son ecriture et beaucoup plus idiomatique 2465 en LISP (d'ou le nom 'ord-mult-to-code-lisp'). En effet, si on avait a coder les nombres naturels en LISP, on ajouterait 2466 (resp. supprimerait) des elements de la liste en partant du debut de la liste afin de creer 2467 une paire ou un n-uplet (resp. pour trouver le code correspondant a une paire ou un n-uplet 2468 |# 2469 (defun ord-mult-to-code-lisp (L) 2470 (if (= (list-length L) 1) 2471 (car L) 2472 (ord-mult-to-code-lisp (cons (ord-pr-to-code (first L) (second L)) (cddr L))))) 2473 2474 #| voir le commentaire precedent concernant la fonction ord-mult-to-code-lisp |# 2475 (defun code-to-ord-mult-lisp (L-or-code size) 2476 (if (atom L-or-code) 2477 (code-to-ord-mult-lisp (code-to-ord-pr L-or-code) (- size 1)) 2478 (if (not (= size 1)) 2479 (code-to-ord-mult-lisp (append (code-to-ord-pr (car L-or-code)) (cdr L-or-code)) (- size 1)) 2480 L-or-code))) 2481 2482 #| 2483 (defun code-to-ord-pr (code) 2484 (;let* ((code*2 (* code 2)) 2485 (n (isqrt code*2)) 2486 (axis (gauss-formula n)) 2487 (diff 0)) 2488 (cond 2489 ((> axis code) 2490 (loop while (> axis code) 2491 ((setf n (- n 1)) 2492 (setf axis (gauss-formula n)))) 2493 (< axis code) 2494 ((loop while (< axis code) 2495 ((setf n (- n 1)) 2496 (setf axis (gauss-formula n)))) 2497 (when (> axis code) 2498 ((setf n (- n 1)) 2499 (setf axis (gauss-formula n)))))) 2500 (t 5)))) 2501 |# 2502 2503 2504 (defun loop-test (n) 2505 (let ((n 0)) 2506 (loop 2507 (when (> n 10) (return)) 2508 (format t "~d ~d ~d~%" n (isqrt n) (gauss-formula n)) 2509 ;(print n) (write (* n n)) (write n) 2510 (incf n)))) 2511 2512 ;;END COUPLES-2.LISP 2513 2514 \end{lstlisting} 2515 2516 \subsection{couples-3.lisp} 2517 \label{couples3lisp} 2518 \begin{lstlisting}[language=Lisp, basicstyle=\footnotesize] 2519 2520 ;;COUPLES-3.LISP 2521 2522 (defun gauss-formula (n) 2523 (/ (* n (+ n 1)) 2)) 2524 2525 (defun get-n (code) 2526 (isqrt (* code 2))) 2527 2528 (defun get-axis (code) 2529 (gauss-formula (isqrt (* code 2)))) 2530 2531 (defun get-axis-from-n (n) 2532 (gauss-formula n)) 2533 2534 (defun axis-code-compare (code) 2535 (format t "~d ~d~%" code (get-axis code))) 2536 2537 (defun axis-code-compare-n (startcode n) 2538 (let ((i 0)) 2539 (loop 2540 (when (> i n) (return)) 2541 (axis-code-compare (+ startcode i)) 2542 (incf i)))) 2543 2544 (defun ord-pr-to-code-nat (x y) 2545 (let ((sumxy (+ x y))) 2546 (if (evenp sumxy) 2547 (+ (gauss-formula sumxy) x) 2548 (+ (gauss-formula sumxy) y)))) 2549 2550 (defun code-to-ord-pr-nat (code) 2551 (let ((n (get-n code)) 2552 (axis (get-axis code)) 2553 (diff 0)) 2554 (progn 2555 (when (> (get-axis code) code) 2556 (progn 2557 (setf n (- n 1)) 2558 (setf axis (get-axis-from-n n)))) 2559 (setf diff (- code axis)) 2560 (if (evenp n) 2561 (cons diff (cons (- n diff) ())) 2562 (cons (- n diff) (cons diff ())))))) 2563 2564 (defun nat-to-int (nat) 2565 (if (< nat 0) 2566 (- (* 2 (abs nat)) 1) 2567 (* 2 (abs nat)))) 2568 2569 (defun int-to-nat (int) 2570 (if (evenp int) 2571 (/ int 2) 2572 (ceiling (- (- (/ int 2)) 1)))) 2573 2574 2575 (defun ord-pr-to-code-int (x y) 2576 (setf x (nat-to-int x)) 2577 (setf y (nat-to-int y)) 2578 (ord-pr-to-code-nat x y)) 2579 2580 (defun code-to-ord-pr-int (code) 2581 (let ((L (code-to-ord-pr-nat code))) 2582 (progn 2583 (setf L (cons (int-to-nat (first L)) (cdr L))) 2584 (setf L (cons (car L) (cons (int-to-nat (second L)) ()))) 2585 L))) 2586 2587 (defun ord-mult-to-code-nat (L) 2588 (if (= (list-length L) 1) 2589 (car L) 2590 (ord-mult-to-code-nat (append (butlast (butlast L)) 2591 (cons (ord-pr-to-code-nat (car (last (butlast L))) (car (last L))) ()))))) 2592 2593 (defun code-to-ord-mult-nat (L-or-code size) 2594 (if (atom L-or-code) 2595 (code-to-ord-mult-nat (code-to-ord-pr L-or-code) (- size 1)) 2596 (if (not (= size 1)) 2597 (code-to-ord-mult-nat (append (butlast L-or-code) (code-to-ord-pr (car (last L-or-code)))) 2598 (- size 1)) 2599 L-or-code))) 2600 2601 #| Les codes generes par cette fonction ne correspondent pas au code genere par le 2602 diagramme du rapport ni des fonctions ord-mult-to-code et code-to-ord-mult. 2603 Toutefois, la fonction ci-dessous a ete creees ici car son ecriture et beaucoup plus idiomatique 2604 en LISP (d'ou le nom 'ord-mult-to-code-lisp'). En effet, si on avait a coder les nombres naturels en LISP, on ajouterait 2605 (resp. supprimerait) des elements de la liste en partant du debut de la liste afin de creer 2606 une paire ou un n-uplet (resp. pour trouver le code correspondant a une paire ou un n-uplet. 2607 On aurait pu faire pareil pour les fonctions concernant tous les entiers 2608 |# 2609 (defun ord-mult-to-code-nat-lisp (L) 2610 (if (= (list-length L) 1) 2611 (car L) 2612 (ord-mult-to-code-lisp (cons (ord-pr-to-code (first L) (second L)) (cddr L))))) 2613 2614 #| voir le commentaire precedent concernant la fonction ord-mult-to-code-lisp |# 2615 (defun code-to-ord-mult-nat-lisp (L-or-code size) 2616 (if (atom L-or-code) 2617 (code-to-ord-mult-lisp (code-to-ord-pr L-or-code) (- size 1)) 2618 (if (not (= size 1)) 2619 (code-to-ord-mult-lisp (append (code-to-ord-pr (car L-or-code)) (cdr L-or-code)) (- size 1)) 2620 L-or-code))) 2621 2622 (defun loop-test (n) 2623 (let ((n 0)) 2624 (loop 2625 (when (> n 10) (return)) 2626 (format t "~d ~d ~d~%" n (isqrt n) (gauss-formula n)) 2627 ;(print n) (write (* n n)) (write n) 2628 (incf n)))) 2629 2630 ;;END COUPLES-3.LISP 2631 2632 \end{lstlisting} 2633 2634 \subsection{couples.c} 2635 \label{couplesc} 2636 \begin{lstlisting}[language=C, basicstyle=\footnotesize] 2637 2638 //COUPLES.C 2639 2640 #include <stdio.h> 2641 #include <stdlib.h> 2642 #include <math.h> 2643 2644 int even(int x){ 2645 return (!(x % 2)); 2646 } 2647 2648 int max(int a, int b){ 2649 if(a > b) 2650 return a; 2651 return b; 2652 } 2653 2654 long int orderedPairToCodeNat(int x, int y){ 2655 long code; 2656 int sumxy; 2657 sumxy = x + y; 2658 code = ((sumxy)*(sumxy + 1))/2; 2659 2660 if(even(sumxy)){ 2661 code = code + x; 2662 } 2663 else{ 2664 code = code + y; 2665 } 2666 return code; 2667 } 2668 2669 int* codeToOrderedPairNat(long int code){ 2670 int *couple = malloc(2*sizeof(int)); 2671 int n = sqrt(code * 2); 2672 long int axis = (n * (n + 1))/2; 2673 int diff = 0; 2674 if(axis > code){ 2675 n = n - 1; 2676 axis = (n * (n + 1))/2; 2677 } 2678 diff = code - axis; 2679 if(even(n)){ 2680 couple[0] = diff; 2681 couple[1] = n - diff; 2682 } 2683 else{ 2684 couple[0] = n - diff; 2685 couple[1] = diff; 2686 } 2687 return couple; 2688 } 2689 2690 long int orderedPairToCodeInt(int x, int y){ 2691 long int code = 0; 2692 2693 if (x < 0){ 2694 x = (2 * (abs (x))) - 1; 2695 } 2696 else{ 2697 x = 2 * x; 2698 } 2699 2700 if (y < 0){ 2701 y = (2 * (abs(y))) - 1; 2702 } 2703 else{ 2704 y = 2 * y; 2705 } 2706 2707 code = orderedPairToCodeNat(x, y); 2708 return code; 2709 } 2710 2711 int* codeToOrderedPairInt(long int code){ 2712 int *pair = codeToOrderedPairNat(code); 2713 2714 if (even(pair[0])){ 2715 pair[0] = pair[0] / 2; 2716 } 2717 else{ 2718 pair[0] = (pair[0] / 2)*(-1) - 1; 2719 } 2720 2721 if (even (pair[1])){ 2722 pair[1] = pair[1] / 2; 2723 } 2724 else{ 2725 pair[1] = (pair[1] / 2)*(-1) - 1; 2726 } 2727 2728 return pair; 2729 } 2730 2731 long int orderedPairToCodeIntAlgo2(int x, int y){ 2732 long int code = 0; 2733 int _x, _y, diff; 2734 _x = _y = diff = 0; 2735 int temp; 2736 int absmax; 2737 absmax = max(abs(x), abs(y)); 2738 2739 if(absmax == abs(x)){ // _x == x 2740 _x = _y = x; 2741 temp = abs(x) * 2; 2742 if(x < 0){ // x negative 2743 code = temp * (temp + 1); 2744 if(y < 0){ // x negative, y negative 2745 diff = abs(_y) - abs(y); 2746 } 2747 else{ // x negative, y positive 2748 diff = abs(_y) + abs(y); 2749 } 2750 } 2751 else{ // x positive 2752 code = (temp - 1) * temp; 2753 if(y > 0){ // x positive, y positive 2754 diff = abs(_y) - abs(y); 2755 } 2756 else{ // x positive, y negative 2757 diff = abs(_y) + abs(y); 2758 } 2759 } 2760 code = code - diff; 2761 } 2762 else{ // _y = y 2763 _x = _y = y; 2764 temp = abs(y) * 2; 2765 if(y < 0){ // y negative 2766 code = temp * (temp + 1); 2767 if(x < 0){ // y negative, x negative 2768 diff = abs(_x) - abs(x); 2769 } 2770 else{ // y negative, x positive 2771 diff = abs(_x) + abs (x); 2772 } 2773 } 2774 else{ // y positive 2775 code = (temp - 1) * temp; 2776 if(x > 0){ // y positive, x positive 2777 diff = abs(_x) - abs(x); 2778 } 2779 else{ // y positive, x negative 2780 diff = abs(_x) + abs(x); 2781 } 2782 } 2783 code = code + diff; 2784 } 2785 return code; 2786 } 2787 2788 int* codeToOrderedPairIntAlgo2(long int code){ 2789 int* pair = malloc(2*sizeof(int)); 2790 int isqrtcode = (int) sqrt(code); 2791 long int pivotcode = isqrtcode * (isqrtcode + 1); 2792 int x, y; 2793 x = y = 0; 2794 2795 if(even(isqrtcode)){ 2796 x = y = -(isqrtcode / 2); 2797 if(code > pivotcode){ 2798 x = x + (code - pivotcode); 2799 } 2800 else{ 2801 y = y + (pivotcode - code); 2802 } 2803 } 2804 else{ 2805 x = y = (isqrtcode / 2) + 1; 2806 if(code > pivotcode){ 2807 x = x - (code - pivotcode); 2808 } 2809 else{ 2810 y = y - (pivotcode - code); 2811 } 2812 } 2813 pair[0] = x; 2814 pair[1] = y; 2815 return pair; 2816 } 2817 2818 long int orderedMultipleToCodeNat(int *arr, int size){ 2819 long int code; 2820 if(size > 1){ 2821 code = orderedPairToCodeNat(arr[size - 2], arr[size - 1]); 2822 arr[size - 2] = code; 2823 arr = realloc(arr, (size - 1)); 2824 if(size > 2){ 2825 code = orderedMultipleToCodeNat(&arr[0], (size - 1)); 2826 } 2827 } 2828 return code; 2829 } 2830 2831 int* codeToOrderedMultipleNat(long int code, int size){ 2832 int *multiple = malloc(size*sizeof(int)); 2833 int *pair; 2834 int i = 0; 2835 for(i = 0; i < (size - 1); i++){ 2836 pair = codeToOrderedPairNat(code); 2837 code = pair[1]; 2838 multiple[i] = pair[0]; 2839 multiple[i + 1] = pair[1]; 2840 } 2841 return multiple; 2842 } 2843 2844 2845 long int orderedMultipleToCodeInt(int *arr, int size){ 2846 long int code; 2847 if(size > 1){ 2848 code = orderedPairToCodeInt(arr[size - 2], arr[size - 1]); 2849 arr[size - 2] = code; 2850 arr = realloc(arr, (size - 1)); 2851 if(size > 2){ 2852 code = orderedMultipleToCodeInt(&arr[0], (size - 1)); 2853 } 2854 } 2855 return code; 2856 } 2857 2858 int* codeToOrderedMultipleInt(long int code, int size){ 2859 int *multiple = malloc(size*sizeof(int)); 2860 int *pair; 2861 int i = 0; 2862 for(i = 0; i < (size - 1); i++){ 2863 pair = codeToOrderedPairInt(code); 2864 code = pair[1]; 2865 multiple[i] = pair[0]; 2866 multiple[i + 1] = pair[1]; 2867 } 2868 return multiple; 2869 } 2870 2871 2872 long int orderedMultipleToCodeIntAlgo2(int *arr, int size){ 2873 long int code = 0; 2874 if(size > 1){ 2875 code = orderedPairToCodeIntAlgo2(arr[size - 2], arr[size - 1]); 2876 arr[size - 2] = code; 2877 arr = realloc(arr, (size - 1)); 2878 if(size > 2){ 2879 code = orderedMultipleToCodeIntAlgo2(&arr[0], (size - 1)); 2880 } 2881 } 2882 return code; 2883 } 2884 2885 int* codeToOrderedMultipleIntAlgo2(long int code, int size){ 2886 int *multiple = malloc(size*sizeof(int)); 2887 int *pair; 2888 int i = 0; 2889 for(i = 0; i < (size - 1); i++){ 2890 pair = codeToOrderedPairIntAlgo2(code); 2891 code = pair[1]; 2892 multiple[i] = pair[0]; 2893 multiple[i + 1] = pair[1]; 2894 } 2895 return multiple; 2896 } 2897 2898 2899 void testMultiNat(){ 2900 2901 int x = 0; 2902 int y = 0; 2903 long int code = 0; 2904 int *p; 2905 int size = 0; 2906 2907 do{ 2908 printf("\n(NATURAL NUMBERS) testPairInt();Enter a size of a multidimensional array representing a 'ordered multiple': "); 2909 scanf("%d",&size); 2910 p = malloc(size * sizeof(int)); 2911 int i; 2912 for(i = 0; i < size; i++){ 2913 printf("Enter value number %d: ", i); 2914 scanf("%d", &p[i]); 2915 } 2916 2917 code = orderedMultipleToCodeNat(p, size); 2918 printf("\n... The code is %ld", code); 2919 printf ("\ncode = "); 2920 scanf("%ld",&code); 2921 printf ("\nnumber of ordered elements = "); 2922 scanf("%d",&size); 2923 p = codeToOrderedMultipleNat(code, size); 2924 printf("The ordered multiple identified by code %ld contains the following elements: ", code); 2925 printf("("); 2926 2927 for(i = 0; i < (size - 1); i++){ 2928 printf("%d, ", p[i]); 2929 } 2930 printf("%d)", p[size-1]); 2931 } 2932 while(1); 2933 } 2934 2935 void testPairInt(){ 2936 2937 int x = 0; 2938 int y = 0; 2939 long int code = 0; 2940 int *p; 2941 2942 do{ 2943 p = malloc(2 * sizeof(int)); 2944 int i; 2945 for(i = 0; i < 2; i++){ 2946 printf("(ORDERED PAIRS INT) Enter value number %d: ", i); 2947 scanf("%d", &p[i]); 2948 } 2949 2950 code = orderedPairToCodeInt(p[0], p[1]); 2951 printf("\n... The code is %ld", code); 2952 printf ("\ncode = "); 2953 scanf("%ld",&code); 2954 p = codeToOrderedPairInt(code); 2955 printf("The ordered pair identified by code %ld contains the following elements: ", code); 2956 printf("("); 2957 2958 for(i = 0; i < 1; i++){ 2959 printf("%d, ", p[i]); 2960 } 2961 printf("%d)\n", p[1]); 2962 } 2963 while(1); 2964 } 2965 2966 void testMultiInt(){ 2967 2968 int x = 0; 2969 int y = 0; 2970 long int code = 0; 2971 int *p; 2972 int size = 0; 2973 2974 do{ 2975 printf("\n(INTEGERS) Enter a size of a multidimensional array representing a 'ordered multiple': "); 2976 scanf("%d",&size); 2977 p = malloc(size * sizeof(int)); 2978 int i; 2979 for(i = 0; i < size; i++){ 2980 printf("Enter value number %d: ", i); 2981 scanf("%d", &p[i]); 2982 } 2983 2984 code = orderedMultipleToCodeInt(p, size); 2985 printf("\n... The code is %ld", code); 2986 printf ("\ncode = "); 2987 scanf("%ld",&code); 2988 printf ("\nnumber of ordered elements = "); 2989 scanf("%d",&size); 2990 p = codeToOrderedMultipleInt(code, size); 2991 printf("The ordered multiple identified by code %ld contains the following elements: ", code); 2992 printf("("); 2993 2994 for(i = 0; i < (size - 1); i++){ 2995 printf("%d, ", p[i]); 2996 } 2997 printf("%d)", p[size-1]); 2998 } 2999 while(1); 3000 } 3001 3002 void testPairIntAlgo2(){ 3003 3004 int x = 0; 3005 int y = 0; 3006 long int code = 0; 3007 int *p; 3008 3009 do{ 3010 p = malloc(2 * sizeof(int)); 3011 int i; 3012 3013 for(i = 0; i < 2; i++){ 3014 printf("(ORDERED PAIRS INT) Enter value number %d: ", i); 3015 scanf("%d", &p[i]); 3016 } 3017 3018 code = orderedPairToCodeIntAlgo2(p[0], p[1]); 3019 printf("\n... The code is %ld", code); 3020 3021 printf ("\ncode = "); 3022 scanf("%ld",&code); 3023 p = codeToOrderedPairIntAlgo2(code); 3024 printf("The ordered pair identified by code %ld contains the following elements: ", code); 3025 printf("("); 3026 3027 for(i = 0; i < 1; i++){ 3028 printf("%d, ", p[i]); 3029 } 3030 printf("%d)\n", p[1]); 3031 } 3032 while(1); 3033 } 3034 3035 3036 void testMultiIntAlgo2(){ 3037 3038 int x = 0; 3039 int y = 0; 3040 long int code = 0; 3041 int *p; 3042 int size = 0; 3043 3044 do{ 3045 printf("\n(INTEGERS) Enter a size of a multidimensional array representing a 'ordered multiple': "); 3046 scanf("%d",&size); 3047 p = malloc(size * sizeof(int)); 3048 int i; 3049 for(i = 0; i < size; i++){ 3050 printf("Enter value number %d: ", i); 3051 scanf("%d", &p[i]); 3052 } 3053 3054 code = orderedMultipleToCodeIntAlgo2(p, size); 3055 printf("\n... The code is %ld", code); 3056 printf ("\ncode = "); 3057 scanf("%ld",&code); 3058 printf ("\nnumber of ordered elements = "); 3059 scanf("%d",&size); 3060 p = codeToOrderedMultipleIntAlgo2(code, size); 3061 printf("The ordered multiple identified by code %ld contains the following elements: ", code); 3062 printf("("); 3063 3064 for(i = 0; i < (size - 1); i++){ 3065 printf("%d, ", p[i]); 3066 } 3067 printf("%d)", p[size-1]); 3068 } 3069 while(1); 3070 } 3071 3072 3073 3074 3075 int main(int argc, char **argv, char **envp){ 3076 // testMultiNat(); 3077 // testPairInt(); 3078 // testMultiInt(); 3079 // testPairIntAlgo2(); 3080 testMultiIntAlgo2(); 3081 } 3082 3083 3084 //END COUPLES.C 3085 3086 \end{lstlisting} 3087 3088 \subsection{couple\_entiers.c} 3089 \label{coupleentiersc} 3090 \begin{lstlisting}[language=C, basicstyle=\footnotesize] 3091 3092 3093 //COUPLES_ENTIERS.C 3094 3095 #include <stdio.h> 3096 #include <stdlib.h> 3097 #include <math.h> 3098 3099 int pair(int x){ 3100 return (!(x % 2)); 3101 } 3102 3103 int orderedPairToCode(int x, int y){ 3104 int sumxy, code; 3105 sumxy = x + y; 3106 code = ((sumxy)*(sumxy + 1))/2; 3107 3108 if(pair(sumxy)){ 3109 code = code + x; 3110 } 3111 else{ 3112 code = code + y; 3113 } 3114 return code; 3115 } 3116 3117 3118 int* codeToOrderedPair(int code){ 3119 int *couple = malloc(2*sizeof(int)); 3120 int n = sqrt(code * 2); 3121 int axis = (n * (n + 1))/2; 3122 int diff = 0; 3123 if(axis > code){ 3124 while(axis > code){ 3125 n = n - 1; 3126 axis = (n * (n + 1))/2; 3127 } 3128 } 3129 else if(axis < code){ 3130 while(axis < code){ 3131 n = n + 1; 3132 axis = (n * (n + 1))/2; 3133 } 3134 if(axis > code){ 3135 n = n - 1; 3136 axis = (n * (n + 1))/2; 3137 } 3138 } 3139 3140 if(axis == code){ // je pense que je peux me dispenser de cet "if", ca revient au meme car diff serait = 0 3141 if(pair(n)){ 3142 couple[0] = 0; 3143 couple[1] = n; 3144 } 3145 else{ 3146 couple[0] = n; 3147 couple[1] = 0; 3148 } 3149 } 3150 if(axis != code){ // idem 3151 diff = code - axis; 3152 if(pair(n)){ 3153 couple[0] = diff; 3154 couple[1] = n - diff; 3155 } 3156 else{ 3157 couple[0] = n - diff; 3158 couple[1] = diff; 3159 } 3160 } 3161 return couple; 3162 } 3163 3164 int orderedMultipleToCode(int *arr, int size){ 3165 int code; 3166 if(size > 1){ 3167 code = orderedPairToCode(arr[size - 2], arr[size - 1]); 3168 arr[size - 2] = code; 3169 arr = realloc(arr, (size - 1)); 3170 if(size > 2){ 3171 code = orderedMultipleToCode(&arr[0], (size - 1)); 3172 } 3173 } 3174 return code; 3175 } 3176 3177 int* codeToOrderedMultiple(int code, int size){ 3178 int *multiple = malloc(size*sizeof(int)); 3179 int *pair; 3180 int i = 0; 3181 for(i = 0; i < (size - 1); i++){ 3182 pair = codeToOrderedPair(code); 3183 code = pair[1]; 3184 multiple[i] = pair[0]; 3185 multiple[i + 1] = pair[1]; 3186 } 3187 return multiple; 3188 } 3189 3190 3191 int main(int argc, char **argv, char **envp){ 3192 3193 int x = 0; 3194 int y = 0; 3195 int code = 0; 3196 int *p; 3197 int size = 0; 3198 3199 do{ 3200 /* 3201 printf ("\nx = "); 3202 scanf("%d",&x); 3203 printf ("y = "); 3204 scanf("%d",&y); 3205 code = orderedPairToCode(x, y); 3206 printf("Le code du couple (%d, %d) est %d\n", x, y, code); 3207 3208 printf ("\ncode = "); 3209 scanf("%d",&code); 3210 p = codeToOrderedPair(code); 3211 printf("The ordered pair identified by code %d is (%d, %d)", code, p[0], p[1]); 3212 3213 */ 3214 printf("\nEnter a size of a multidimensional array representing a 'ordered multiple': "); 3215 scanf("%d",&size); 3216 p = malloc(size * sizeof(int)); 3217 int i; 3218 for(i = 0; i < size; i++){ 3219 printf("Enter value number %d: ", i); 3220 scanf("%d", &p[i]); 3221 } 3222 3223 code = orderedMultipleToCode(p, size); 3224 printf("\n... The code is %d", code); 3225 3226 3227 3228 printf ("\ncode = "); 3229 scanf("%d",&code); 3230 printf ("\nnumber of ordered elements = "); 3231 scanf("%d",&size); 3232 p = codeToOrderedMultiple(code, size); 3233 printf("The ordered multiple identified by code %d contains the following elements: ", code); 3234 printf("("); 3235 for(i = 0; i < (size - 1); i++){ 3236 printf("%d, ", p[i]); 3237 } 3238 printf("%d)", p[size-1]); 3239 3240 3241 } 3242 while(code != -1); 3243 } 3244 3245 //END COUPLES_ENTIERS.C 3246 \end{lstlisting} 3247 \newpage 3248 \section{Annexe~: Exercice 5} 3249 \label{annexeexo5} 3250 \includepdf[pages=-]{exo5} 3251 3252 \end{document}