oelson/gajs
Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
== Domaines == Domaine flou = je peux m'approcher d'une bonne solution par plusieurs chemins Domaine strict = je ne peux m'approcher que par un chemin L'évolution des textes est un domaine strict, car on doit avoir tous les caractères dans l'ordre, strictement. Conjecture : un domaine strict engendre une courge logarithmique par définition car plus on s'approche, plus c'est difficile de s'approcher. En effet il faut à la fois changer le dernier caractère erroné, mais également conserver intact les N-1 qui sont corrects. Statistiquement on doit donc sacrifier une grosse partie de la population, qui subit uniformément les mutations, pour retirer les mutants qui perdent un bon caractère. Parmi le reste, il faut ensuite avoir suffisament d'individus restants pour que la probabilité de la bonne mutation sur le bon caractère arrive. Donc plus on sacrifie d'individus à chaque génération, plus on s'approchera (vite ?) du résultat. Ainsi le % de perte à chaque génération fait converger la courbe de survie vers l'asymtote de valeur y= le % On remarque qu'entre 50% et 84% la relation suit, mais au delà on piétinne, même en sacrifiant 97% de chaque génération. == TODO == - pouvoir appuyer sur "pause" et le worker s'arrête, on affiche tous les individus N-1 et N avec lien de parenté et un diff parent/enfant == Thèse == L'évolution du code est d'autant moins facile que la complexité du code augmente. Les mutations individuelles ne peuvent pas produire de séquences complexes de code, tandis la sélection ne peut qu'éliminer les codes en évolution mais non fonctionnels ou sous-fonctionnels. L'accumulation de mutations neutres, soudainement basculées dans le domaine fonctionnel par chance, ne tient pas la route car la complexité du code rend l'apparition de ces séquences impossible statistiquement. Dit autrement, l'activité de programmation requiert de l'intelligence dans la capacité à percevoir à l'avance le résultat escompté et à produire la séquence de code fonctionnelle d'un coup : on ne programme pas par erreurs et essais au sein d'une masse de code non fonctionnelle. Et même dans le scénario d'un code préexistant et fonctionnel, la complexité du langage et du code rendent impossible toute amélioration substentielle par des moyens progressifs. Le code fonctionnel est comme placé sur un îlot entouré par une mer de mutations délètres, c'est la nature fragile du code. La distance de Hamming entre deux codes fonctionnels de fonctionnalité similaire est toujours trop grande, dans le monde des programmes réels, pour envisager un chemin évolutif de l'un à l'autre. Car contrairement à l'activité de programmation, l'évolution requiert strictement que tout chainon dans la filiation soit fonctionnel et au moins aussi bon que son prédécesseur. == Courbe logarithme == La probabilité de se rapprocher d'une cible absolue est forte au début car toutes les positions de la chaînent peuvent contribuer à l'amélioration. Mais quand tous les caractères sauf un sont alignés, la probabilité que ce seul caractère passe d'un mauvais au bon est 1/a où a est la taille de l'alphabet. La formule générale donnant la probabilité de production d'un individu amélioré d'un seul caractère est n/a avec n la taille de la chaîne. C'est dans le cas où l'on remplace des caractères et non des bits. Ce scénario d'un début facile et d'une fin pénible se rencontre aussi dans le monde de l'élevage : il est facile de croiser certaines espèces de crevettes très différentes pour produire des individus radicalement différents, mais plus on sélectionne un trait précis, plus on a besoin de générations proprement sélectionnées : on affine à la fin. Pourquoi la courbe descend ? À cause des mutations délétaires, qui sont majoritaires dans ce scénario : il est plus facile de défaire un caractère que de le faire, donc en moyenne la courbe est tirée vers le bas par l'entropie génétique. La sélection artificielle tire la courbe vers le haut non pas en créant de bonne mutations mais en supprimant massivement les mauvaises. La courbe résultante est donc un rapport de force entre une dynamique vers le haut et vers le bas. Ainsi la phase stationnaire s'explique par le fait que lorsqu'il reste peu de caractères non optimaux, ils sont difficiles à faire basculer. En revanche l'entropie génétique continue d'opérer sur tous les autres et donc le "poids" de l'ensemble augmente, car il devient plus probable qu'une erreur apparaisse à la place d'une bonne réponse, qu'une bonne réponse disparaisse et cède la place à une erreur. On converge systématiquement vers un fitness de valeur = % de sélection. Exemple 1 : si à chaque génération on multiplie par 10 la population, en vue d'une stabilité on devra par la suite éliminer 90% de la population. Si la population est suffisament nombreuse (en pratique entre 100 et 300 individus suffisent) alors le fitness convergera vers 0.9. Exemple 2 : en parant de 150 individus, à chaque génération on en obtient 5950 c'est-à-dire 33 fois plus ; on devra en supprimer 4800 pour revenir à 150, soit 97%. Le fitness convergera alors vers 97%. Point important : on a donc une méthodologie pour atteindre un fitness désiré. En pratique cela revient à calibrer "la fusée" de la courbe logarithmique, pour que l'accélération compense la gravité : on vise le début de l'asymptote, car si on n'a pas assez d'énergie on sera bloqué sur un plateau à jamais. En ayant bien "visé" on arrive en quelque centaines de générations à obtenir notre individu évolué. Pour résumer on forge une espèce "évoluée" au prix exact du pourcentage de mort qu'on inflige à chaque génération. Plus on tue les inaptes, plus l'évolution converge. C'est une machine à gâcher. == Pourquoi ça descend à certaines générations ? == Car tous les mauvais ne sont pas ôtés. Si par hasard une génération à quasiment tous les individus dévalués, les quelques uns intacts pour améliorés seront conservés en vie avec d'autres qui fatalement seront inférieurs. Supposons que 95% soient faits mauvais et qu'on supprime 90% des pires : il reste donc 5% de bons et 5% de mauvais. À la génération suivantes, on a 50%-50%, ainsi l'erreur est amplifiée. Cela arrive statistiquement moins souvent, mais cela arrive. == Le rôle de la quantité de mutations == Plus les mutations sont nombreuses, plus le "poids" de la courbe est grand car l'entropie devient efficace à supprimer toutes les informations positives. On a donc deux paramètres antagonistes : le taux de fécondité, par lequel le grand nombre d'individus devient une sorte de "tampon" pour l'entropie et qui maintient la courbe en haut ; et le taux de mutations, qui tire vers le bas. Mais le taux de mutation ne contrebalance pas très fortement l'efficacité de la sélection. On constate un poids moyen d'environ 5% à 20 mutations par cycle. Et bien sûr, le nombre de mutations est lié à la taille de la chaîne à faire évoluer; si on a autant de mutations que de caractères, la probabilité qu'on mute une mutation augmente et l'effet s'annule si les mutations se font en respect du code. En revanche si l'on mute le génome brutalement, sans égard au code, la courbe s'effondre ! Il y a une limite à ce que le code peut supporter ! Même sans parler de catastrophe génétique, la courbe est tirée vers le bas de 10% pour un taux de mutation de 1/cycle ; de 30% pour 2/cycle; de 45% pour 3/cycle ; de 55% pour 4; de 60% pour 5. En moyenne : 5% par point de mutation par cycle. Plus on mute, plus les oscillations s'étalent, comme si la sélection avait du mal à se défaire des erreurs du passé. Ainsi alors que UTF-8 est auto-synchronisant, et donc résilient aux erreurs de communication, on voit qu'au delà de 2 ou 3 mutations par cycle, l'évolution s'effondre. == Pourquoi y a-t-il des phases descendantes ? == Une phase régressive est paradoxale car à chaque génération a a conservé les meilleurs. Si sur 40 générations successives, ne conserver que les meilleurs aboutit au final à une dégradation de l'adaptivité, cela veut dire que même parmi les meilleurs se cachait quelque chose de mauvais. Mystère difficile à expliquer ... la sélection doit alors se "purger" de ses mauvais éléments, mais elle ne peut pas les juger mauvais dans l'absolu, seulement mauvais relativent aux autres qui sont aussi mauvais. == idée == La sélection naturelle est meilleurs car ses contraintes sélectives sont multiples, donc les espèces s'adaptent simultanément à plusieurs contraintes. NON ! justement au contraire, le coût sélectif est déjà tellement elevé pour une contrainte que la population ne peut pas supporter un poid supplémentaire. On ne peut sélectionner qu'un petit nombre de caractéristiques, et éviter des caractéristiques incompatibles ou incohérentes. En effet alors la fonction de sélection est finalement réduite à un (A | B) et elle ne "sait" plus qui privilégier, de A ou de B; et si A et B sont constradictoires (se rapprocher de A signifie s'éloigner de B et réciproquement) alors on ne peut pas converger. => Il faut tester ce principe de la double sélection, par exemple en cherchant d'une part à se rapprocher exactement d'un texte cible, d'autre part en cherchant à se rapprocher d'une distribution de caractères (que des consonnes). Le résultat sera forcément incohérent et la pression sélective demandée insupportable. Soit on atteint l'impossible rapidement, en tuant tout le monde ; soit on "progresse" vers l'impossible sans jamais l'atteindre. Dit autrement, on ne peut pas optimiser un lézard à aquérir des ailes et des os creux en "même temps", il faut le faire séquentiellement. Car des os creux sans ailes, c'est un désavantage; et des ailes sans os creux, de même. Complexité irréductible, au niveau même du processus sélectif : on doit avoir un ordre d'aquisition des phénotypes.