PROJET AUTOBLOG


Sam et Max

source: Sam et Max

⇐ retour index

Petit exercice en Python

lundi 16 décembre 2013 à 08:27

Nouveau concept, de temps en temps, je vais proposer un exercice à faire en Python, vous postez vos solutions, et j’en posterai une le lendemain.

Pas de pression, c’est pour le fun.

Les solutions dans un autre langage sont bienvenues, mais privilégiez Python si vous avez le choix, c’est quand même le but.

Postez votre code sur un pastebin ou ailleurs avec un lien en commentaire, pas le code directement dans les commentaires.

Exercice du jour :

Un script qui attend un fichier en paramètre, l’ouvre, et trouve toutes les positions de chaque mot.

Le script doit prendre en compte les apostrophes, supprimer la ponctuation, et normaliser la casse et les caractères spéciaux des mots.

Le résultat doit afficher une liste à de mots avec leurs positions ordonnée par le nombre d’apparition, ou en cas d’égalité, par ordre naturel des positions.

Aucune gestion d’erreur n’est demandée.

Par exemple si j’ai un fichier contenant :

« La marche des vertueux est semée d’obstacles qui sont les entreprises égoïstes que fait sans fin surgir l’œuvre du Malin. Béni soit-il l’homme de bonne volonté qui, au nom de la charité, se fait le berger des faibles qu’il guide dans la vallée d’ombre, de la mort et des larmes, car il est le gardien de son frère et la providence des enfants égarés. J’abattrai alors le bras d’une terrible colère, d’une vengeance furieuse et effrayante sur les hordes impies qui pourchassent et réduisent à néant les brebis de Dieu. Et tu connaîtras pourquoi mon nom est l’éternel quand sur toi s’abattra la vengeance du Tout-Puissant ! »

Ça fait des années que je répète ça. L’enfoiré qui l’entend, il meurt aussitôt. J’avais jamais cherché à comprendre, je trouvais seulement que ça en jetait de dire ça avant de flinguer un mec. Et puis ce matin, j’ai vu quelque chose qui m’a fait réfléchir. D’un seul coup, je me dis, ça pourrait bien vouloir dire que tu es l’œuvre du malin, et que l’homme vertueux c’est moi, et que mon joli 9 mm ce serait mon protecteur, mon berger dans la vallée de l’angoisse et des larmes. Ou encore mieux, c’est moi le berger et toi l’homme vertueux, et c’est le monde qui est l’œuvre de Lucifer. Qu’est-ce que tu dis de ça ? Mais rien de tout ça n’est juste. Ce qui est vrai, c’est que tu es le faible et que je suis la tyrannie des méchants. Et moi j’essaie, Ringo, au prix d’un effort harassant, de protéger les faibles.

On appelle le script ainsi :

python ton_script.py ton_fichier.txt

Et il affiche ceci :

- marche: 1
- semee: 5
- obstacles: 7
- sont: 9
- entreprises: 11
- egoistes: 12
- sans: 15
- fin: 16
- surgir: 17
- beni: 22
- soit: 23
- bonne: 28
- volonte: 29
- charite: 35
- se: 36
- guide: 44
- ombre: 49
- mort: 52
- car: 56
- gardien: 60
- son: 62
- frere: 63
- providence: 66
- enfants: 68
- egares: 69
- abattrai: 71
- alors: 72
- bras: 74
- terrible: 77
- colere: 78
- furieuse: 82
- effrayante: 84
- hordes: 87
- impies: 88
- pourchassent: 90
- reduisent: 92
- neant: 94
- brebis: 96
- dieu: 98
- connaitras: 101
- pourquoi: 102
- eternel: 107
- quand: 108
- s: 111
- abattra: 112
- puissant: 117
- annees: 121
- repete: 124
- enfoire: 127
- entend: 130
- meurt: 132
- aussitot: 133
- avais: 135
- jamais: 136
- cherche: 137
- comprendre: 139
- trouvais: 141
- seulement: 142
- en: 145
- jetait: 146
- avant: 150
- flinguer: 152
- mec: 154
- puis: 156
- matin: 158
- ai: 160
- vu: 161
- quelque: 162
- chose: 163
- m: 165
- reflechir: 168
- seul: 171
- coup: 172
- me: 174
- pourrait: 177
- bien: 178
- vouloir: 179
- joli: 199
- mm: 200
- serait: 202
- protecteur: 204
- angoisse: 212
- ou: 216
- encore: 217
- mieux: 218
- monde: 233
- lucifer: 239
- mais: 248
- rien: 249
- n: 253
- juste: 255
- vrai: 259
- faible: 266
- suis: 270
- tyrannie: 272
- mechants: 274
- essaie: 278
- ringo: 279
- prix: 281
- effort: 284
- harassant: 285
- proteger: 287
- malin: 21, 187
- au: 31, 280
- nom: 32, 104
- faibles: 41, 289
- qu: 42, 240
- dans: 45, 207
- vallee: 47, 209
- larmes: 55, 215
- une: 76, 80
- vengeance: 81, 114
- sur: 85, 109
- toi: 110, 225
- tout: 116, 251
- dire: 148, 180
- dis: 175, 245
- es: 183, 264
- vertueux: 3, 192, 228
- oeuvre: 19, 185, 237
- du: 20, 115, 186
- homme: 26, 191, 227
- berger: 39, 206, 223
- a: 93, 138, 166
- un: 153, 170, 283
- moi: 195, 221, 276
- les: 10, 86, 95, 288
- fait: 14, 37, 119, 167
- il: 24, 43, 57, 131
- j: 70, 134, 159, 277
- tu: 100, 182, 244, 263
- mon: 103, 198, 203, 205
- je: 123, 140, 173, 269
- ce: 157, 201, 242, 256
- c: 193, 219, 230, 260
- d: 6, 48, 75, 79, 169, 282
- le: 38, 59, 73, 222, 232, 265
- des: 2, 40, 54, 67, 120, 214, 273
- qui: 8, 30, 89, 128, 164, 234, 257
- ca: 118, 125, 144, 149, 176, 247, 252
- la: 0, 34, 46, 51, 65, 113, 208, 271
- que: 13, 122, 143, 181, 189, 197, 243, 262, 268
- l: 18, 25, 106, 126, 129, 184, 190, 211, 226, 236
- est: 4, 58, 105, 194, 220, 231, 235, 241, 254, 258, 261
- de: 27, 33, 50, 61, 97, 147, 151, 210, 238, 246, 250, 286
- et: 53, 64, 83, 91, 99, 155, 188, 196, 213, 224, 229, 267, 275

Solution

flattr this!

Les mensonges des DSL

dimanche 15 décembre 2013 à 02:36

Un DSL, ou Domaine Specific Language, est un langage qui est dédié à un usage très pointu, et pour lequel il est donc particulièrement efficace.

Par exemple, le langage de Matlab est un DSL, dédié à l’expression mathématique. SQL est un DSL, orienté requête. PHP a commencé comme un DSL, optimisé pour le Web.

En théorie, un DSL doit vous rendre plus productif. En théorie. En pratique, une fois qu’un DSL sort de son domaine de prédilection, il est extrêmement inéficace. C’est le prix de la spécialisation.

Or, dernièrement, on a fait beaucoup l’apanage des DSL dans le cadre d’autres langages. Car oui, certains langages permettent de créer des DSL. Les macros du C et les capacités de meta programmations de Lisp permettent par exemple de créer des langages complets, avec des dialectes spécialisés.

Vient alors le premier problème : on créé un nouveau langage. Récent. Supporté et donc débuggé et (mal) documenté par l’auteur. Ensuite, on se rajoute un niveau d’indirection. Car du coup ça nous fait une abstraction supplémentaire, et il faut savoir ce que ça fait sous le capot. En prime, on freine l’entrée de nouveaux venus dans le projet, puisqu’il faut qu’ils apprenent à faire avec le DSL en plus, là où une simple lib aurait pu faire l’affaire.

Et on touche ici à une seconde problématique, les faux DSL : des libs ordinnaires qui se déguisent en DSL. Typiquement, je pense à Ruby, ici.

Les rubistes prétendent partout qu’ils peuvent créer des DSL avec leur langage. Encore un mensonge, puisque tout ce qu’ils font c’est utiliser le chaînage de méthode, le namespacing, la surcharge des opérateurs et les parenthèses/virgules facultatives pour donner l’impression qu’un nouveau langage est créé.

Tout comme on donne l’illusion de retourner deux paramètres dans une fonction en Python en retournant un tuple et en faisant de l’unpacking. C’est du sucre syntaxique, mais on est très loin de ce que ça prétend être.

Pourquoi c’est important ? Parce que cela laisse à croire qu’il y a quelque chose de spéciale là dedans, alors qu’il s’agit ni plus ni moins que d’une bête lib avec une API fluide. Ce qu’on peut faire dans tout autre langage (excepté l’absence de parenthèses, sur lequel il faudra que j’écrive un article tellement c’est une FBI).

Donc plutôt que de faire du bruit et du hype autour de cela, et amener les gens à se concentrer sur l’aspect “comment obtenir une syntaxe exotique”, il serait plus intéressant de dire tout simplement : voilà comment on peut faire une belle API, voici les bonnes pratiques, appliquez les.

Et aussi écrire une doc…

J’ai horreur en informatique quand on donne 40 noms différents à la même chose. Comme par exemple pour les promises, les futures, les deferred, etc. Merde, non seulement ça n’aide personne, mais en plus ça rend la comprehension de principes plus difficile. Déjà que c’est rarement bien expliqué…

Au final, un DSL est rarement une bonne idée, que ce soit un vrai ou un faux. SQL nous aura bien servi, il faut le reconnaitre, même si on aurait pu faire mieux. Mais la plupart du temps, ce sont quelques heures de gagnées en redaction de code, et des jours de formation et maintenance perdus, ou alors juste une masquarade cachant simplement derrière le hype des principes sains de programmation.

Languages are more than just languages, they are a form of culture, and by being culture they tend to enforce (indirecty or directly) a certain way of doing things, i.e. standards or conventions. This means that if you know the language and its culture, there are less surprises and a longer learning or adaptation curve

(Extrait de Is Lisp Too Powerful ?)

flattr this!

Remplacer sed, awk, cut et Perl par Python (= orgasme pour sysadmin)

samedi 14 décembre 2013 à 09:28

La force de Perl c’est qu’il permettait de piper des données directement via la ligne de commande pour faire des manipulations rapides.

C’est pour cela que c’était devenu les choix des sysadmins. Parce que jusqu’ici, le choix c’était soit de faire un truc simple en connaissant par coeur la tool box GNU, soit ouvrir un fichier et faire un script.

Python ne permet pas de piper des données directement dans la commande, mais des projets ont vu le jour pour le faire.

Il y a le projet pyp, que l’on doit à Sony Pictures Imageworks qui avait besoin de se simplifier l’automatisation des tâches de build pour ses films.

Et il y a pyped, dont j’avais brièvement parlé ici (article qui mérite d’être mis à jour vu que j’ai remplace dateutils par arrow).

Les deux étaient sympas, mais avait des syntaxes alambiquées. Cependant, pyped est récemment passé en v1.0, donc stable, et a une toute nouvelle approche de syntaxe qui rend la bestiole super agréable à utiliser.

Présentation.

Stdin, ligne à ligne

L’installation est bateau, c’est du pip :

pip install --user pyped

Et derrirère, on obtient la commande py. Elle s’utilise essentiellement à la suite d’une autre commande. Typiquement :

cat /etc/fsta | py "un truc"

L’astuce, c’est que “un truc” peut être n’importe quelle expression Python. Généralement une expression qui print() quelque chose.

Or, Pyped met automatiquement à disposition de cette expression deux variables :

L’expression Python est appelée une fois pour chaque ligne.

Par exemple, supposons que j’ai un fichier “fortune.txt” contenant :

bitcoin (btc) : 5
euros () : 100
dollars ($) : 80

Si je veut tout mettre en majuscule, je fais :

$ cat fortune.txt | py "print(x.upper())"
BITCOIN (BTC) : 5
EUROS () : 100
DOLLARS ($) : 80

On peut mettre plusieurs expressions d’affilé. Ainsi, si je veux récupérer la somme et le symbole uniquement :

$ cat fortune.txt | py "devise, sign, _, value = x.split()" "sign = sign.strip('()')" "print('%s%s' % (value, sign))"
5btc
10080$

Ok, c’est plus long que perl, mais vachement plus facile à écrire et à relire. Et j’utilise un langage que je connais déjà. Et pas besoin de faire un mix incompréhensible de sed, awk et autre cut.

Si j’ai vraiment besoin de lisibilité, je peux même le mettre sur plusieurs lignes :

$ cat fortune.txt | py "                                                                                                 
devise, sign, _, value = x.split() 
sign = sign.strip('()') 
print('%s%s' % (value, sign))  
"
5btc
10080$

Vous aurez noté que j’utilise print() et que je semble ne pas me soucier de l’unicode. C’est parceque pyped fait ça au début du script :

from __future__ import print_function, unicode_literals, division, absolute_imports

Du coup, on est bien en Python 2.7, mais on bénéficie de la division améliorée, de la fonction pour printer, des imports absolus et surtout, de l’unicode partout. D’ailleurs pyped vous transforme x pour que ce soit un objet unicode.

Tout traiter d’un coup

Parfois, on a besoin d’avoir accès à toutes les lignes, pas juste les lignes une à une. pyped permet cela avec l’option -i. Les variables x et i disparaissent au profit de la variable l, qui contient un itérable sur toutes les lignes.

Par exemple, envie de trier tout ça ?

cat fortune.txt | py -i "
lignes = (x.split() for x in l)
lignes = sorted((v, s.strip('()')) for d, s, _, v in lignes)
for ligne in lignes: print('%s%s' % ligne)
"
100€
5btc
80$

Moar options

Lisez la doc, car il y a d’autres options du genre éviter que pyped vous strip automatiquement le ligne break, forcer l’encoding, etc.

Parmi les trucs les plus utiles, il y a l’option -b qui permet de lancer un code avant la boucle. Pratique pour importer des trucs genre le module tarfile pour extraire une archive avant d’utiliser son contenu.

Néanmoins la plupart du temps on a rien besoin d’importer car pyped importe déjà automatiquement les modules les plus utiles : maths, datetime, re, json, hashlib, uuid, etc.

flattr this!

Pourquoi j’ai horreur d’acheter

vendredi 13 décembre 2013 à 09:20

J’achète rarement des trucs neufs. Déjà, il faut que ça soit utile, que ça prenne pas trop de place, et que ça se déplace facilement vu que je bouge tout le temps.

Mais en plus, le problème d’un achat, c’est que ça bouffe énormément de temps, surtout si on l’achète pas en ligne.

Exemple, je vais à la fnac pour acheter un bidule à 150 euros. Je dois prendre la voiture (j’ai horreur de conduire) pour aller en centre ville, ce qui prend une bonne demi-heure. Il faut se garer, puis se taper la foule de mongoliens dans le magasin, en arpentant les étages pour trouver le bon rayon.

Là, je prends le produit dont j’ai fait le choix préalablement sur le net (encore du temps… pour un putain d’objet !) car les vendeurs n’y connaissent que dalle. Il faut se farcir la queue, payer en caisse, retourner chez soit. Une bonne heure et demi de perdue que j’aurais pu passer à faire des choses plus importantes, comme jouer à Don’t Starve, et encore, si on sait exactement ce qu’on fait.

Maintenant ça s’arrête là si tout va bien, mais évidement, l’histoire ne mériterait pas un article si c’était le cas.

Il se trouve qu’arrivé chez moi, le produit ne me satisfait pas. Pour 150 euros, je vais donc faire l’effort de le rapporter. Je le remballe, et on reprend la caisse. Ai-je précisé que je déteste conduire ?

Je demande à un vigile à l’entrée où est l’accueil.

Je vais à l’accueil pour demander à ce qu’on me le change. Je fais donc la queue.

L’accueil me renvoie vers un autre accueil un étage au dessus, qui s’en occupe. Je fais donc la queue.

L’autre accueil me dit que pour l’électronique, ce sont les vendeurs qui s’en occupent. Je cherche un vendeur, et tombe sur un mec qui est en fait vendeur Microsoft, pas fnac. Donc je vais en trouver un autre, qui est entouré de personnes qui lui posent des questions essentielles comme la couleur des barrettes de RAM, si l’anti-virus le protège contre le terrorisme et où sont les toilettes. Je fais donc la queue.

Le vendeur me signale qu’il me faut un bon de circulation pour cela, qu’il faut demander au vigile. Je retourne voir mon vigile à l’entrée, qui fouille le sac d’un mec alors que bien entendu seule la police est autorisée à faire ça. J’attends, mon tour. Je fais donc la queue.

Je chope le bon, retourne voir le vendeur, qui entre temps a changé de place alors qu’il avait dit qu’il m’attendrait. Je le retrouve, traitant un autre client. Je fais donc la queue.

Il me fais mon retour produit et m’annonce la couleur : ce sera un avoir. Donc uniquement valable dans les magasins fnac, et à utiliser dans les 3 mois. La partie fun maintenant : on ne peut pas le diviser, il va falloir que je fasse un achat de 150 euros. Joie.

Je note mentalement que j’achèterai avec 150 euros de carte cadeau, utilisable un an et divisible. Quand on fait une coloscopie, on choisit son hôpital.

Mais l’avoir n’est pas valable tant qu’il n’est pas validé en caisse, donc j’y vais pour, vous l’avez deviné, faire la queue.

A ce stade, la magasin ferme. Si, si. Je suis parti de chez moi en fin début d’après midi, et je sors du magasin à la fermeture. Pour me faire faire fouiller mon sac par le vigile.

Je hais les magasins. Je hais acheter des trucs.

Parce que même quand tout se passe bien (en supposant que ça ne tombe pas en panne, parce que là, c’est reparti pour l’Iliade version longue avec bonus DVD et sous-titrage en russe), l’histoire ne s’arrête pas là. L’objet prend de la place. Il faut le ranger. Occasionnellement le nettoyer ou l’entretenir. Et le transporter quand on déménage. Puis en disposer quand il arrive en fin de vie, ce qui, si on est sensible à l’écologie, suppose l’amener au bon point de recyclage. En l’occurrence, la fnac.

Je ne comprends pas comment “faire du shopping” peut être considéré comme un passe temps.

flattr this!

Du Darwinisme pythonien

jeudi 12 décembre 2013 à 11:13

Ceci est un post invité de golgotha posté sous licence creative common 3.0 unported.

Qui n’a jamais rêvé de cloner des moutons clara morgane et de s’adonner à des expérimentations scientifiques de haut niveau ?

Bon ici, nous n’avons pas de clara morgane sous la main pour notre expérience mais, avec le python et les théories scientifiques de Darwin, on peut faire quelques trucs sympas : On va essayer de déterminer le plus court chemin à prendre pour relier plusieurs points entre eux, le truc cool c’est que pour solutionner le problème on va utiliser un algorithme génétique.

De la génétique dans du python ?!

En fait c’est assez simple (encore des termes barbares pour épater les copains..), écoutez bien, je vous explique le concept : on va faire des individus, chaque individu va faire un parcours en fonction des points du tracé en paramètre. A la fin, on note chaque individu avec un score, le score étant la longueur du parcours de l’individu. Vous suivez toujours ? Bien. On prend les meilleurs (Normal) et on les accouple avec des moins bons (faut les pousser un peu, au début ils sont timides mais, après ça va tout seul, c’est même l’orgie parfois…) ce qui donne une nouvelle population, normalement un poil meilleure que l’ancienne qu’on va vite mettre à la poubelle. On recommence le processus n fois et à la fin, on devrait arriver à des super individus, genre blonds aux yeux bleus qui parlent 14 langues : ça c’est notre solution.

Passons aux travaux pratiques !

Je commence par déclarer deux variables globales, la population et la liste de points.

population = []
a_map = []

Ensuite on créer une classe Point standard :

class Point(object):
 
    COUNT = 0
 
    def __init__(self, x, y):
        self.X = x
        self.Y = y
 
    def __str__(self):
        return "Point(%s,%s)"%(self.X, self.Y) 
 
    def distance(self, other):
        dx = self.X - other.X
        dy = self.Y - other.Y
        return sqrt(dx**2 + dy**2)

Rien de particulier ici, l’objet nous sera utile plus tard.

class Individu(object):
 
    # le constructeur de l'objet.
    # on met le score à zéro.
    # on peut aussi lui passer la liste de points
    # pour qu'il initialise une route au hasard.
    def __init__(self, init = False, map_point = []):
        self.score = 0
        self.route = []
        if init :
            self.set_route(map_point)
 
    # ici on créé une route avec un mélange des points
    # on utilise shuffle pour mélanger les points.
    # ensuite on calcul le score, c'est à dire la longueur du trajet.
    def set_route(self, map_point) :
        shuffle(map_point)
        self.route = map_point
        for p in range(len(map_point) - 1) :
            self.score += map_point[p].distance(map_point[p+1])
 
    # ici on donne à l'objet la capacité de faire un enfant
    # ça prend comme paramètre l'objet (lui même), et un autre individu.
    # on prend la moitié du trajet de l'objet et on complète avec
    # les points de l'autre individu.
    # on retourne un enfant, qui est un individu.
    def croisement(self, other):
        child = Individu()
        # je prends la moitier de moi-même.
        wdth = len(self.route)/2
        first_segment = self.route[:wdth/2]
        last_segment  = []
        # je complète avec l'autre
        for i in range(len(self.route)) :
            if other.route[i] not in first_segment :
                last_segment.append(other.route[i])
        child.set_route(first_segment + last_segment)
        return child
 
    # ici on défini une fonction pour que l'objet puisse se dessiner.
    # pour cela on utilisera Turtle de python.
    def show_me(self):
        turtle.clearscreen()
        pen = turtle.Turtle()
        pen.speed(0)
        pen.up()
        pen.setpos(self.route[0].X, self.route[0].Y)
        for point in self.route :
            pen.goto(point.X, point.Y)
            pen.down()
            pen.dot()
 
        pen.goto(self.route[0].X, self.route[0].Y)

Voilà pour l’objet individu (pas très inspiré sur le nom j’avoue..) qui est donc capable maintenant de faire pas mal de choses qui sera utile: se montrer, faire un petit (capacité que beaucoup d’objet lui envie déjà) et choisir une route parmi une liste de points.

La suite, j’ai écris ça dans des fonctions, il y a surement plus propre mais bon, le but est de vous montrer comment fonctionne un algo génétique, je laisserai le soin aux pro du python d’améliorer le code en lui-même (je ne vais pas faire tout le boulot non plus !)

# initialisation des points de la carte.
# prend en paramètre un nombre de points.
def init_map(nb):
    global a_map
    del a_map[:]
    for i in range(nb):
        p = Point(randint(1, 300), randint(1, 300))
        a_map.append(p)
# initialisation de la population.
# prend en paramètre le nombre d'individus à créer.
def init_pop(nb, map_point):
    global population
    del population[:]
    for i in range(nb):
        i = Individu(True, map_point)
        population.append(i)
# fonction qui sert à trier les individus suivant leur score.
# utile pour trouver les meilleurs.
def selection(pop):
    pop.sort(key=lambda x: x.score, reverse=True)
# dans cette fonction, on sélectionne les 15 meilleurs individus de la population
# que l'on croise avec les autres individus.
# la nouvelle population est constituée des 15 meilleurs plus les enfants.
def croisement(pop):
    new_pop = []
    best_pop = population[85:]
    for i in range(len(pop)-15) :
        new_pop.append(choice(best_pop).croisement(choice(population[20:85])))
    return new_pop + best_pop
# la fonction principal.
# on passe en paramètre le nombre de générations que l'on souhaite faire
# et le nombre de points. 
# Ensuite, on itère selon un algorithme précis :
# Création d'une population initiale.
# Sélection puis croisement de la population
# à chaque génération on regarde si on a un meilleur score
# si oui, on l'affiche.
def play(nb_gene, nb_point) :
    init_map(nb_point)
    init_pop(100, a_map)
    best_score = 1000000
    for i in range(nb_gene) :
        global population
        population = croisement(population)
        selection(population)
        if best_score > population[99].score :
            best_score = population[99].score
            print 'meilleur score : ' + str(population[99].score)
            population[99].show_me()

Voilà le morceau, je pense que j’ai laissé assez de commentaires dans le code pour bien comprendre comment ça fonctionne et au niveau du python en lui-même il n’y a vraiment rien de spécial, ici ce qui compte c’est que vous voyez rapidement comment fonctionne l’algorithme.

Alors, maintenant : Pourquoi s’emmerder à accoupler des objets à 2,78 Ghz ?

Le problème ci-dessus, un problème dit np-complet, c’est-à-dire que c’est la merde pour trouver une solution dans un temps raisonnable si on l’a fait de façon traditionnelle : pour trouver le meilleur trajet sur 10 points, on sera obligé dans un premier temps de trouver tous les trajets possibles, avec N villes on a (N-1)!/2 trajet possible, le nombre de trajets explose littéralement si N augmente. Avec 100 points il est déjà pratiquement impossible de calculer tous les trajets possibles en un temps raisonnable.

C’est là que l’algorithme génétique est très fort, on arrive très vite à une solution approchée, il est tout de même à noter que le résultat obtenu par l’algorithme génétique n’est pas LA solution exact au problème, il donne une solution approchée.

Dernier point sur le code ci-dessus, ce n’est que les bases de l’algorithme génétique, avec ce code vous ne pourrez pas venir à bout d’un parcours de plus de 20 ou 30 villes, pour cela il faut améliorer l’algorithme, par exemple le croisement entre deux individus peut être fait de plusieurs façons différentes, dans mon exemple je prends la moitié du “code génétique” d’un individu que je colle à une autre moitié, on peut aussi faire du crossover : c’est-à-dire qu’on prend des bouts du code génétique des deux individus alternativement. Ensuite, il y a aussi des mutations génétiques à introduire dans le croisement, à un certain taux, par exemple 1% des croisements entre individus produira une mutation génétique, concrètement : on fait le croisement puis on change aléatoirement des données du code génétique, dans notre exemple on échangera deux points sur le parcours. Cela a pour effet de produire des individus potentiellement meilleurs que les autres, en terme mathématique ça permet aussi de ne pas s’enfermer dans une solution locale, ce qui est souvent le cas.

J’espère ne pas vous avoir complètement perdu avec mes explications et vous avoir donné envie de regarder de plus près cet algorithme que je trouve très élégant.

flattr this!

I'm richer than you! infinity loop