Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1746 connectés 

  FORUM HardWare.fr
  Programmation
  Python

  [Python][WIP] Fractales Markus-Lyapunov (Avis et conseils demandés)

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[Python][WIP] Fractales Markus-Lyapunov (Avis et conseils demandés)

n°1267895
Tigriss
Orga gaming des Geek Faëries
Posté le 15-12-2005 à 19:00:14  profilanswer
 

Hello tout le monde
 
Voilà quelques temps que je m'amuse à créer des fractales Markus-Lyapunov avec deux ou trois logiciels. Il y a deux semaines, j'ai décidé d'apprendre le Python en créant mon propre programme à partir de zero.
Rien de tel qu'une bonne motivation pour apprendre !
 
Ayant de solides connaissances en PHP, l'entrée dans le monde Python n'a pas durée plus de deux jours :pt1cable:
 
Plus sérieusement, les fractales markus-lyapunov sont assez interessantes à étudier et à programmer, sans compter l'aspect inédit qu'elles offrent. Si vous ne connaissez pas, cherchez rapidement sur google, on trouve quelques sites qui en parlent.
Le calcul étant assez long, elles sont très peu connues :/
 
Voilà mon code actuel :

Code :
  1. #!/usr/bin/python
  2. # -*- coding:Utf-8 -*-
  3. # Fractales Lyapunov - Tig'Prod' - Tigriss - 2005
  4.  
  5. from math import *
  6. import Image
  7. import psyco
  8. psyco.full()
  9.  
  10. def exposant_lyapunov(a,b,init,itera):
  11.     "Calcul de l'exposant. a -> x, b -> y, init -> itérations d'ammorçage, itera -> itérations de calcul"
  12.     global log2
  13.     sequence=[a,b,b,a]
  14.     max_seque=3
  15.     x=0.5
  16.     total=0
  17.     i=0
  18.     seque_init=-1
  19.     while i < init:
  20.         i = i + 1
  21.         seque_init=seque_init + 1
  22.         if seque_init > max_seque:
  23.             seque_init = 0
  24.         x=sequence[seque_init]*x*(1.0-x)
  25.     i=0
  26.     seque_init = -1
  27.     while i < itera:
  28.         i = i + 1
  29.         seque_init=seque_init + 1
  30.         if seque_init > max_seque:
  31.             seque_init = 0
  32.         x=sequence[seque_init]*x*(1.0-x)
  33.         total=total+(log(abs(sequence[seque_init]-2.0*sequence[seque_init]*x))/log2)
  34.     exposant=total/itera
  35.     return exposant
  36.  
  37. def couleur(exposant):
  38.     "Calcul de la couleur d'un pixel selon la palette utilisée et son exposant"
  39.     global maxResult
  40.     global minResult
  41.     global iterations_used
  42.     global longueur_palette_plus
  43.     global longueur_palette_minus
  44.     global colpalplus
  45.     global colpalminus
  46.     if exposant > 0:
  47.         echelle=(maxResult/longueur_palette_plus)
  48.         cindex = abs(int(exposant/echelle))
  49.         if cindex > longueur_palette_plus - 1:
  50.             cindex = longueur_palette_plus - 1
  51.         if cindex < 0:
  52.             cindex = 0
  53.         final = colpalplus[cindex]
  54.     else:
  55.         echelle=(minResult/longueur_palette_minus)
  56.         cindex = abs(int(exposant/echelle))
  57.         if cindex > longueur_palette_minus - 1:
  58.             cindex = longueur_palette_minus - 1
  59.                if cindex < 0:
  60.             cindex = 0
  61.         final = colpalminus[cindex]
  62.     return final
  63.  
  64. # Parametres des palettes de couleur
  65. colpalplus=[]
  66. colpalminus=[]
  67.  
  68. ## Reglages de base
  69. maxResult=(sqrt(5)-1.0)/2.0
  70. minResult=(sqrt(5)+1.0)/2.0
  71. longueur_palette_plus=256
  72. longueur_palette_minus=511
  73.  
  74. ## Palette CHAOS
  75. # bleu -> noir
  76. #i=0
  77. #while i < 256:
  78. #    colpalplus.append((0, 0, 255 - i))
  79. #    i = i + 1
  80.  
  81. # blanc -> noir
  82. #i=0
  83. #while i < 256:
  84. #    colpalplus.append((255 - i, 255 - i, 255 - i))
  85. #    i = i + 1
  86.  
  87. # noir -> noir
  88. i=0
  89. while i < 256:
  90.     colpalplus.append((0, 0, 0))
  91.     i = i + 1
  92. maxResult=1.9333897126112
  93.  
  94. ## Palette STABLE
  95. # noir -> jaune -> blanc
  96. #i=0
  97. #while i < 256:
  98. #    colpalminus.append((i, i, 0))
  99. #    i = i + 1
  100. #while i < 511:
  101. #    colpalminus.append((255, 255, i - 255))
  102. #    i = i + 1
  103.  
  104. # blanc -> gris -> noir
  105. #i=0
  106. #while i < 256:
  107. #    colpalminus.append((255-i, 255-i, 255-i))
  108. #    i = i + 1
  109. #while i < 511:
  110. #    colpalminus.append((i - 255, i - 255, i - 255))
  111. #    i = i + 1
  112.  
  113. # noir -> jaune
  114. i=0
  115. while i < 256:
  116.     colpalminus.append((255-i, 255-i, 0))
  117.     i = i + 1
  118. longueur_palette_minus=256
  119. minResult=-10.462186805818
  120.  
  121. # Parametres de la fractale
  122. ## Tailles image
  123. largeur=400
  124. hauteur=400
  125. ## Itérations d'ammorçage
  126. iterations_unused=200
  127. ## Itérations de calcul
  128. iterations_used=400
  129. ## Coordonnées du point bas gauche
  130. ## MEMO : x = largeur, y = hauteur
  131. x=2.52
  132. y=2.87
  133. ## Pas de coordonnées pour chaque pixel
  134. steps=0.002825
  135.  
  136. ## NOTE IMPORTANTE
  137. ## Ne jamais atteindre 4 pour une coordonnée ((steps*taille)+x ou y)
  138. ## sous peine de math overflow
  139.  
  140. image_finale=[]
  141.  
  142. im = Image.new("RGB",(largeur,hauteur))
  143.  
  144. log2=log(2)
  145.  
  146. # Construction
  147. i=hauteur
  148. j=1
  149. while i > 0:
  150.     while j <= largeur:
  151.         image_finale.append(couleur(exposant_lyapunov(i*steps+y,j*steps+x,iterations_unused,iterations_used)))
  152.         j = j+1
  153.     j=1
  154.     print i,"(",hauteur," )"
  155.     i = i - 1
  156.  
  157. # Enregistrement
  158. im.putdata(image_finale)
  159. im.save("lyapunov.jpg" )
  160.  
  161. print "Terminé"


 
(J'espere que la présentation et les commentaires vous iront ^^)
 
Une fois lancé, ce code va prendre a peu pret une minute (Duron 2Ghz), et sortir une image 400*400 peinte en jaune/noir (vous pouvez jouer avec les quelques palettes déjà présentes, dans CHAOS et STABLE).
 
Comme dis plus haut, l'execution prend environs 1 minute 20 sur un Duron 2Ghz, sous Ubuntu, et en dirigant le flux de sortie vers /dev/null.
Le "problème", c'est qu'avec mon programme habituel, la même fractale se fait en 20/30 secondes à tout casser.
 
Aussi, j'ai cherché à optimiser le code (bon moyen d'apprendre :D), avec un certain succès (2 minutes, avec mon tout premier code fonctionnel). Psyco m'a aussi permit de gagner 10/15 secondes.
 
Mais maintenant, je ne sais pas quoi tenter d'autre, aussi, je fais appel à vous pour m'aider à améliorer la bête, si celà est possible :)
Et en passant, si qqun a déjà bossé sur les Lyapunov, qu'il se manifeste ! :jap:
 
Actuellement, j'ai deux voies possibles à étudier, en calcul pur :
- Améliorer l'algo de calcul en ligne 33. Après un tour exhaustif sur le net, j'ai récupéré deux ou trois programmes (en MatLab, Java, et C), chacun utilisait un algo légérement différent, comme par exemple deux cosinus et un sinus dans la formule. L'actuel est le seul que j'ai pu faire fonctionner correctement :/
- Limitation du calcul selon si on est en zone de chaos (noir), ou en zone de stabilité (jaune/marron/noir intérieur aux formes). Le programme que j'utilise fonctionne de cette maniere, c'est très net quand il passe dans une zone de chaos total. Idem, je n'ai pas réussi à trouver un systeme correct pour faire celà, sans pour autant perdre les couleurs (le chaos est noir dans cet exemple, mais on peux en faire ce qu'on veut).
 
Si qqun a une idée...
 
Reste ensuite le côté programmation pure, et là, il y a certainement tout un tas de subtilités que je n'ai, de fait, pas encore intégré (comme par exemple une différence notable entre while et for, ou des choses du genre). Hormit ce point, je ne pense pas avoir de probleme structurel.
 
Voilà ! Je fais donc appel à vos lumières éclairées ! :) Et merci d'avance de m'avoir lu jusqu'au bout :)

Message cité 1 fois
Message édité par Tigriss le 18-12-2005 à 23:40:52

---------------
Geek Faeries 2013 , du 20 au 22 septembre, à 1h20 de Paris : Des invités de marque, un château, du gaming... Le Joueur du Grenier, Nesblog, la série Noob, Pen of Chaos, Reflets d'Acide, et bien plus encore !
mood
Publicité
Posté le 15-12-2005 à 19:00:14  profilanswer
 

n°1267937
masklinn
í dag viðrar vel til loftárása
Posté le 15-12-2005 à 20:28:04  profilanswer
 

Tigriss a écrit :

Comme dis plus haut, l'execution prend environs 1 minute 20 sur un Duron 2Ghz, sous Ubuntu, et en dirigant le flux de sortie vers /dev/null.
Le "problème", c'est qu'avec mon programme habituel, la même fractale se fait en 20/30 secondes à tout casser.


Si ton programme "habituel" est dans un langage compilé rapide (C/C++) ou même en Java/C#, ça n'a strictement rien d'étonnant, le Python est un langage interprété relativement lent en termes de vitesse d'exécution.

Tigriss a écrit :

Mais maintenant, je ne sais pas quoi tenter d'autre, aussi, je fais appel à vous pour m'aider à améliorer la bête, si celà est possible :)
Et en passant, si qqun a déjà bossé sur les Lyapunov, qu'il se manifeste ! :jap:


Là je peux pas t'aider, à part à la limite te proposer de passer ton code au profiler

Tigriss a écrit :

Reste ensuite le côté programmation pure, et là, il y a certainement tout un tas de subtilités que je n'ai, de fait, pas encore intégré (comme par exemple une différence notable entre while et for, ou des choses du genre). Hormit ce point, je ne pense pas avoir de probleme structurel.


Sur le Python pur:
 

  • Les docstrings, ça s'écrit avec des triple-quotes, donc
Code :
  1. def exposant_lyapunov(a,b,init,itera):
  2.    "Calcul de l'exposant. a -> x, b -> y, init -> itérations d'ammorçage, itera -> itérations de calcul"


doit être transformé en

Code :
  1. def exposant_lyapunov(a,b,init,itera):
  2.    """Calcul de l'exposant. a -> x, b -> y, init -> itérations d'ammorçage, itera -> itérations de calcul"""


De plus il manque le prototype et ce docstring est franchement peu compréhensible, en tout cas à moi il ne me sert absolument à rien (a->x wtf? qu'est-ce que je peux en tirer?)
 

  • Trop de variables globales -_-
  • Tu pourrais placer les données de configuration dans un fichier à part importé au lancement
  • Dans l'idéal, utilise le module "logging" plutôt que des print pour logger le déroulement de ton bouzin
  • remplacer
Code :
  1. i=hauteur
  2. j=1
  3. while i > 0:
  4.    while j <= largeur:
  5.        image_finale.append(couleur(exposant_lyapunov(i*steps+y,j*steps+x,iterations_unused,iterations_used)))
  6.        j = j+1
  7.    j=1
  8.    print i,"(",hauteur," )"
  9.    i = i - 1


par

Code :
  1. for i in xrange(hauteur, 0, -1):
  2.    for j in range(1, largeur+1):
  3.        image_finale.append(couleur(exposant_lyapunov(i*steps+y,j*steps+x,iterations_unused,iterations_used)))


et tes

Code :
  1. i=0
  2. while i<value:
  3.    i+=1


par des

Code :
  1. for i in range(value):


  • Concatène les opérations similaires.

je vois un  

Code :
  1. i=0
  2. while i < 256:
  3.    colpalplus.append((0, 0, 0))
  4.    i = i + 1


et quelques lignes plus bas

Code :
  1. i=0
  2. while i < 256:
  3.    colpalminus.append((255-i, 255-i, 0))
  4.    i = i + 1


Le tout peut devenir

Code :
  1. for i in range(256):
  2.    colpalplus.append((0, 0, 0))
  3.    colpalminus.append((255-i, 255-1, 0))


Tu peux également utiliser les list comprehensions:

Code :
  1. colpalplus = [(0, 0, 0) for i in range(256)]
  2. colpalminus = [(255-i, 255-i, 0) for i in range(256)]


Mais ça résulte en deux itérations sur [0, 256[ au lieu d'une, donc les perfs sont probablement inférieures à la version précédente.

  • Tout fichier python est un module, il est donc d'usage de planquer le code "exécuté" ne servant pas à l'initialisation du module lui même derrière:
Code :
  1. if __name__ == "__main__":


De cette manière ce code n'est pas exécuté quand on importe le fichier.
 
Après, sur les calculs en tant que tels je peux pas t'aider, étant une quiche en maths.

Message cité 2 fois
Message édité par masklinn le 17-12-2005 à 22:51:33

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
n°1267940
Profil sup​primé
Posté le 15-12-2005 à 20:43:47  answer
 

masklinn a écrit :


  • Les docstrings, ça s'écrit avec des triple-quotes, donc



 
Source ? :o

n°1267942
masklinn
í dag viðrar vel til loftárása
Posté le 15-12-2005 à 20:49:49  profilanswer
 


http://www.python.org/doc/current/ [...] 0000000000
 http://membres.lycos.fr/angel2k/petrus/petrusfuck.gif
 
C'est pas un impératif (c'est une convention), mais un docstring monoligne ne correspond pas aux conventions et du multiline avec des single quotes c'est moche [:jagstang]  
 
 
Accessoirement, sur les perfs:
 
Sans Psyco
Code originel
>pythonw -u "frac.py"
>Exit code: 0    Time: 195.798
 
Code avec boucles modifiées
>pythonw -u "frac_modded.py"
>Exit code: 0    Time: 179.000
 
Donc gain de ~8%
 
Avec Psyco, les optimisations des boucles font que le gain est statistiquement inexistant
 
Code originel
>pythonw -u "frac.py"
>Exit code: 0    Time: 46.580
 
Code boucles modifiées
>pythonw -u "frac_modded.py"
>Exit code: 0    Time: 46.520
 
(runs fait sur un Athlon64/3000+)
 
Par contre tu peux peut-être voir du côté de Shed Skin, c'est un compilateur Python > Natif, il est en tout début de dev mais vu que ton code c'est principalement des maths ça passera peut-être (edit: marche pas, il comprend pas où trouver PIL)
(pas de bol, parce que si on dégage la gestion d'images ça compile, et ça va bien vite [:huit] )
 
Et dans un futur qui se rapproche, Pypy arrivera peut-être un jour à être plus rapide que CPython :o

Message cité 2 fois
Message édité par masklinn le 15-12-2005 à 20:59:47

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
n°1267944
Profil sup​primé
Posté le 15-12-2005 à 20:58:37  answer
 

masklinn a écrit :

http://www.python.org/doc/current/ [...] 0000000000
 http://membres.lycos.fr/angel2k/petrus/petrusfuck.gif
 
C'est pas un impératif (c'est une convention), mais un docstring monoligne ne correspond pas aux conventions et du multiline avec des single quotes c'est moche [:jagstang]  


 
Sur plusieurs lignes oui tout à fait c'est indispensable (à moins de trafiquer) mais là il s'agissait de lignes simples, donc pas besoin de s'encombrer avec des triple quotes. :o
 
Comment ça mes interventions sont sans intérêt ? [:pingouino]

n°1267947
masklinn
í dag viðrar vel til loftárása
Posté le 15-12-2005 à 21:00:14  profilanswer
 


Oui mais j'y ai dit que ses lignes simples elles puaient du bout :o


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
n°1268030
Tigriss
Orga gaming des Geek Faëries
Posté le 15-12-2005 à 23:25:50  profilanswer
 

masklinn a écrit :

Si ton programme "habituel" est dans un langage compilé rapide (C/C++) ou même en Java/C#, ça n'a strictement rien d'étonnant, le Python est un langage interprété relativement lent en termes de vitesse d'exécution.


C'est z-lyapunov (ICI) que j'utilise. Un peu ancien, mais il fonctionne, y comprit dans Wine.
En effet, c'est compilé, donc c'est plus rapide. Mais ça fait une sacré différence tout de même, presque tout ce que j'ai pu lire montre que Python réagit plus vite que ça, donc...
 

masklinn a écrit :


Là je peux pas t'aider, à part à la limite te proposer de passer ton code au profiler


 
Oui, c'est ce que je comptais faire sous peu, même si je suis certain des points chauds (ligne 33... :/)
 

masklinn a écrit :


  • Les docstrings, ça s'écrit avec des triple-quotes, donc

def exposant_lyapunov(a,b,init,itera):
    "Calcul de l'exposant. a -> x, b -> y, init -> itérations d'ammorçage, itera -> itérations de calcul"


doit être transformé en

def exposant_lyapunov(a,b,init,itera):
    """Calcul de l'exposant. a -> x, b -> y, init -> itérations d'ammorçage, itera -> itérations de calcul"""


De plus il manque le prototype et ce docstring est franchement peu compréhensible, en tout cas à moi il ne me sert absolument à rien (a->x wtf? qu'est-ce que je peux en tirer?)


 
A vrais dire, comme dis plus haut, j'apprend en direct, donc c'est pas évident de connaitre ce genre de conventions tordues :P Surtout que j'ai appris les docsstrings qq heures avant :D
Quand au contenu... j'en suis bien conscient. A terme, ça sera lisible. En attendant, ça remplit parfaitement sa tache de memo perso, et c'est plus propre que des commentaires.
 

masklinn a écrit :


  • Trop de variables globales -_-



Sauf que j'ai besoin de passer ces variables. Et tout rentrer en argument, c'est pas super propre non plus. Une autre subtilité que je ne connais pas ? ;)
 

masklinn a écrit :


  • Tu pourrais placer les données de configuration dans un fichier à part importé au lancement



Nop, dès que j'ai un code clean, j'attaque une interface graphique. L'idéal serait de pouvoir visionner la construction en temps réel. J'envisage wxPtyhon pour ça.
 

masklinn a écrit :


  • Dans l'idéal, utilise le module "logging" plutôt que des print pour logger le déroulement de ton bouzin



Ok, je vais aller voir ça

masklinn a écrit :


  • remplacer

i=hauteur
j=1
while i > 0:
    while j <= largeur:
        image_finale.append(couleur(exposant_lyapunov(i*steps+y,j*steps+x,iterations_unused,iterations_used)))
        j = j+1
    j=1
    print i,"(",hauteur," )"
    i = i - 1


par

for i in xrange(hauteur, 0, -1):
    for j in range(1, largeur+1):
        image_finale.append(couleur(exposant_lyapunov(i*steps+y,j*steps+x,iterations_unused,iterations_used)))


et tes

i=0
while i<value:
    i+=1


par des

for i in range(value):




Bon ben dès que j'ai fini de me battre avec les quote, j'applique, merci ;)
J'aurais du regarder les for de plus pret, ainsi que range, que j'ai déjà rencontré, en plus...
 

masklinn a écrit :


  • Concatène les opérations similaires.

je vois un  

i=0
while i < 256:
    colpalplus.append((0, 0, 0))
    i = i + 1


et quelques lignes plus bas

i=0
while i < 256:
    colpalminus.append((255-i, 255-i, 0))
    i = i + 1


Le tout peut devenir

for i in range(256):
    colpalplus.append((0, 0, 0))
    colpalminus.append((255-i, 255-1, 0))


Tu peux également utiliser les list comprehensions:

colpalplus = [(0, 0, 0) for i in range(256)]
colpalminus = [(255-i, 255-i, 0) for i in range(256)]


Mais ça résulte en deux itérations sur [0, 256[ au lieu d'une, donc les perfs sont probablement inférieures à la version précédente.


Là on touche un autre truc. Cette partie sera completement reconstruite sous peu. J'ai besoin de pouvoir générer des palettes plus facilement qu'a la main comme ça. Sans compter que les palettes peuvent avoir la longueur que l'on souhaite (cf la palette STABLE Noir/Jaune/Blanc), et non identique avec la palette opposée.
Mais je note tes améliorations, ça va reservir.
 

masklinn a écrit :


  • Tout fichier python est un module, il est donc d'usage de planquer le code "exécuté" ne servant pas à l'initialisation du module lui même derrière:

if __name__ == "__main__":


De cette manière ce code n'est pas exécuté quand on importe le fichier.


J'ai vu un truc du genre, en effet. J'ai passé, vu que pas vital sur le momment, mais je regarde ça plus sérieusement sous peu.
 

masklinn a écrit :

Accessoirement, sur les perfs:
 
Sans Psyco
Code originel
>pythonw -u "frac.py"
>Exit code: 0    Time: 195.798
 
Code avec boucles modifiées
>pythonw -u "frac_modded.py"
>Exit code: 0    Time: 179.000
 
Donc gain de ~8%
 
Avec Psyco, les optimisations des boucles font que le gain est statistiquement inexistant
 
Code originel
>pythonw -u "frac.py"
>Exit code: 0    Time: 46.580
 
Code boucles modifiées
>pythonw -u "frac_modded.py"
>Exit code: 0    Time: 46.520
 
(runs fait sur un Athlon64/3000+)
 
Par contre tu peux peut-être voir du côté de Shed Skin, c'est un compilateur Python > Natif, il est en tout début de dev mais vu que ton code c'est principalement des maths ça passera peut-être (edit: marche pas, il comprend pas où trouver PIL)
(pas de bol, parce que si on dégage la gestion d'images ça compile, et ça va bien vite [:huit]


Et ben vais pas me géner, on va sauver les infos dans un fichier, puis suffira d'executer la création de l'image dans un second script :D Je regarde ça aussi
 

masklinn a écrit :


Après, sur les calculs en tant que tels je peux pas t'aider, étant une quiche en maths.


On est tous une quiche de qqchose :P
 
Merci pour touts ces infos, j'ai de quoi bien m'occuper now !


---------------
Geek Faeries 2013 , du 20 au 22 septembre, à 1h20 de Paris : Des invités de marque, un château, du gaming... Le Joueur du Grenier, Nesblog, la série Noob, Pen of Chaos, Reflets d'Acide, et bien plus encore !
n°1268045
masklinn
í dag viðrar vel til loftárása
Posté le 15-12-2005 à 23:34:14  profilanswer
 

Tigriss a écrit :

En effet, c'est compilé, donc c'est plus rapide. Mais ça fait une sacré différence tout de même, presque tout ce que j'ai pu lire montre que Python réagit plus vite que ça, donc...


Bof

Citation :

Oui, c'est ce que je comptais faire sous peu, même si je suis certain des points chauds (ligne 33... :/)


J'ai passé un coup de profiler (sans avoir activé psyco), il a trouvé que... les fonctions abs() et log() sont appelées 64 millions de fois chacune (non non, pas blague, sur 160.000 appels d'exposant_machin) et bouffent à elles deux 44% des ressources (23 et 21, par contre je me souviens plus laquelle des deux prend 23 et laquelle prend 21).
 
Le reste, c'est le reste du code dans ta fonction de recherche de l'exposant, donc normal

Citation :

Nop, dès que j'ai un code clean, j'attaque une interface graphique. L'idéal serait de pouvoir visionner la construction en temps réel. J'envisage wxPtyhon pour ça.


Aucun rapport :o

Message cité 1 fois
Message édité par masklinn le 15-12-2005 à 23:35:50

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
n°1268063
Tigriss
Orga gaming des Geek Faëries
Posté le 15-12-2005 à 23:54:13  profilanswer
 

masklinn a écrit :

J'ai passé un coup de profiler (sans avoir activé psyco), il a trouvé que... les fonctions abs() et log() sont appelées 64 millions de fois chacune (non non, pas blague, sur 160.000 appels d'exposant_machin) et bouffent à elles deux 44% des ressources (23 et 21, par contre je me souviens plus laquelle des deux prend 23 et laquelle prend 21).


 
(merci pour le coup de profiler)
Assez impressionant. Mais assez normal en fait, ça fait 160.000*400 pour l'abs, plus 160.000 autres pour la couleur, idem pour log. Et encore, le log(2) est en variable :D
J'ai une piste pour un algo qui serait un poil plus léger, je suis en train d'essayer de le comprendre, lol
 

masklinn a écrit :


Aucun rapport :o


 
Ben... je n'ai plus besoin de stocker des variables en fichier à partir du momment où tout est défini à la main en interface. Sans compter que sauver les parametres spécifique à une seule image n'est pas très utile. Ou alors j'ai pas bien saisis ton idée :/


---------------
Geek Faeries 2013 , du 20 au 22 septembre, à 1h20 de Paris : Des invités de marque, un château, du gaming... Le Joueur du Grenier, Nesblog, la série Noob, Pen of Chaos, Reflets d'Acide, et bien plus encore !
n°1268078
Tigriss
Orga gaming des Geek Faëries
Posté le 16-12-2005 à 00:13:42  profilanswer
 

Hum, je viens de faire qq tests, et...
 
Original (w/psyco) : 1m20/25
Boucles optimisée (w/psyco) : 1m7/8 (Le gain correspond)
Mais :
Boucles optimées (wo/psyco) : 3m10 :heink:
 
Pour le coup, je comprend plus là :pt1cable: Sans compter que non optimisé et sans psyco, je fais plutot 2m10...
 
M'enfin, ça commence à faire une sacrée avancée !


---------------
Geek Faeries 2013 , du 20 au 22 septembre, à 1h20 de Paris : Des invités de marque, un château, du gaming... Le Joueur du Grenier, Nesblog, la série Noob, Pen of Chaos, Reflets d'Acide, et bien plus encore !
mood
Publicité
Posté le 16-12-2005 à 00:13:42  profilanswer
 

n°1268593
Tigriss
Orga gaming des Geek Faëries
Posté le 16-12-2005 à 16:46:49  profilanswer
 

Yes !
 
Je viens de trouver un nouvel algo bien plus performant ! Et même assez logique, si j'avais un peu mieux suivit mes maths (comme quoi... ;) )
 
Voilà la nouvelle fonction exposant_lyapunov :
 

Code :
  1. def exposant_lyapunov(a,b,init,itera):
  2.     "Calcul de l'exposant. a -> x, b -> y, init -> itérations d'ammorçage, itera -> itérations de calcul"
  3.     sequence=[a,b,b,a]
  4.     max_seque=3
  5.     x=0.5
  6.     total=1
  7.     seque_init=-1
  8.     for i in range(init):
  9.         seque_init=seque_init + 1
  10.         if seque_init > max_seque:
  11.             seque_init = 0
  12.         x=sequence[seque_init]*x*(1.0-x)
  13.     seque_init = -1
  14.     for i in range(itera):
  15.         seque_init=seque_init + 1
  16.         if seque_init > max_seque:
  17.             seque_init = 0
  18.         x=sequence[seque_init]*x*(1.0-x)
  19.         total=total*abs(sequence[seque_init]-2.0*sequence[seque_init]*x)
  20. # Cet if est là pour éviter qu'a un momment, "0.0" arrive dans la log, ce qui n'est mathématiquement pas possible
  21. # Je ne sais pas encore d'où il vient, ni si "1" est la bonne chose à faire. En attendant, le reste marche. Je ferais une comparaison par différence sous toshop avec ces deux techniques
  22.     if total <= 0:
  23.         exposant=log(1)/itera
  24.     else:
  25.         exposant=log(total)/itera
  26.     return exposant


 
Avec ce nouvel algo, je supprime 99% des log, et du coup, j'atteins les 30 secondes de calcul ! 55% de gain :D
Doit encore y avoir à gratter, sur l'if entre autres, et y'a ptet qqchose à faire avec l'abs.
 
Je vais me pencher sur la colorisation, qui doit bien bouffer aussi.
 
EDIT :
Bon, cet algo pose problème. Les parties noires/sombres des zones stables sont changés en jaune pur, et j'ai l'impression que ça morfle sur les.... "branches" sombres, le dégradé sombre n'est pas le même.
Hormit ça, le reste est ok.


Message édité par Tigriss le 18-12-2005 à 23:41:05

---------------
Geek Faeries 2013 , du 20 au 22 septembre, à 1h20 de Paris : Des invités de marque, un château, du gaming... Le Joueur du Grenier, Nesblog, la série Noob, Pen of Chaos, Reflets d'Acide, et bien plus encore !
n°1268675
Monsieur S​eb
Posté le 16-12-2005 à 18:09:42  profilanswer
 

Très interressant ton programme. Je viens de le faire tourner sous linux.
Voici les perfs avec psyco :  
 

#time python frac.py
real    0m13.422s
user    0m13.249s
sys     0m0.068s


 
sans psyco


real    2m34.012s
user    2m27.081s
sys     0m0.764s
 


 :ouch:  
 
c'est sans appel !
 
Mon proc

# cat /proc/cpuinfo
processor       : 0
vendor_id       : AuthenticAMD
cpu family      : 6
model           : 8
model name      : AMD Athlon(tm) XP 2600+
stepping        : 1
cpu MHz         : 2075.344
cache size      : 256 KB
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 1
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 mmx fxsr sse syscall mmxext 3dnowext 3dnow
bogomips        : 4154.57
 


 
 
Pourrais tu nous donner un petit lien pour l'algo et la formule j'ai la flemme de chercher

n°1268689
masklinn
í dag viðrar vel til loftárása
Posté le 16-12-2005 à 18:47:52  profilanswer
 

Monsieur Seb a écrit :

Très interressant ton programme. Je viens de le faire tourner sous linux.
Voici les perfs avec psyco :  
 

#time python frac.py
real    0m13.422s
user    0m13.249s
sys     0m0.068s


 
sans psyco


real    2m34.012s
user    2m27.081s
sys     0m0.764s
 


 :ouch:  
 
c'est sans appel !


Oui, psyco est un JIT ( http://en.wikipedia.org/wiki/Just-in-time_compilation ), il fonctionne extrèmement bien pour des programmes très répétitifs dans ce genre.
 
Pour des programmes avec très peu de répétitions, le gain est largement inférieur (il est inférieur à 50%), et la consommation en RAM prend un ordre de grandeur.


Message édité par masklinn le 16-12-2005 à 18:48:16

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
n°1268728
Tigriss
Orga gaming des Geek Faëries
Posté le 16-12-2005 à 19:45:14  profilanswer
 

Monsieur Seb a écrit :

Très interressant ton programme. Je viens de le faire tourner sous linux.
Voici les perfs avec psyco :  
 

#time python frac.py
real    0m13.422s
user    0m13.249s
sys     0m0.068s


 
sans psyco


real    2m34.012s
user    2m27.081s
sys     0m0.764s
 


 :ouch:  
 
c'est sans appel !
 
Mon proc

# cat /proc/cpuinfo
processor       : 0
vendor_id       : AuthenticAMD
cpu family      : 6
model           : 8
model name      : AMD Athlon(tm) XP 2600+
stepping        : 1
cpu MHz         : 2075.344
cache size      : 256 KB
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 1
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 mmx fxsr sse syscall mmxext 3dnowext 3dnow
bogomips        : 4154.57
 


 
 
Pourrais tu nous donner un petit lien pour l'algo et la formule j'ai la flemme de chercher


 
Hop ! :P
 
http://perso.wanadoo.fr/charles.vassallo/index.html -> Bon site, un des plus complet sur le thème
http://gjoly.free.fr/fractales-pro [...] osant.html -> Page plus mathématique, mais très intéressante aussi :)
http://www.chaospro.de/lyap.php -> Et vala là où j'ai déniché le dernier algo
 
En parlant d'algo, j'ai corrigé celui de tt à l'heure :
 

Code :
  1. def exposant_lyapunov(a,b,init,itera,ligne):
  2.     "Calcul de l'exposant. a -> x, b -> y, init -> itérations d'ammorçage, itera -> itérations de calcul"
  3.     global log2
  4.     sequence=[a,b,b,a]
  5.     max_seque=3
  6.     x=0.5
  7.     total=1
  8.     total2=0
  9.     seque_init=-1
  10.     for i in range(init):
  11.         seque_init=seque_init + 1
  12.         if seque_init > max_seque:
  13.             seque_init = 0
  14.         x=sequence[seque_init]*x*(1.0-x)
  15.     seque_init = -1
  16.     for i in range(itera):
  17.         seque_init=seque_init + 1
  18.         if seque_init > max_seque:
  19.             seque_init = 0
  20.         x=sequence[seque_init]*x*(1.0-x)
  21.         total=total*abs(sequence[seque_init]-2.0*sequence[seque_init]*x)
  22.     if total == 0:
  23.         exposant=(log(0.00000001)/log2)/itera
  24.         print "############### ", exposant, total2/itera
  25.     else:
  26.         exposant=(log(total)/log2)/itera
  27.     return exposant


 
Modif toute bête :D (ajout de /log2)
 
Mais il reste un problème, certains des points les plus sombres (croisement des "fils", voire dans les fils pour qq pixels) dans les zones stables sont "brulés" dans l'opération.
A un momment, total devient tellement petit que le résultat fait 0, et comme c'est une multiplication (l'algo précédent etait une addition), une fois total passé à 0 toute la suite est brulée. Je n'ai aucune idée pour contrer ça mathématiquement, par contre, on peut stocker les coordonnées à probleme, pour les recalculer avec l'algo précédent.
 
Si qqun voit une autre idée...
 
Voilà une version fiable :
http://img528.imageshack.us/img528/2180/lyapcopie9rw.th.jpg
 
Et voici une version brulée :
http://img528.imageshack.us/img528/7481/lyapunov5bd.th.jpg


Message édité par Tigriss le 18-12-2005 à 23:42:09

---------------
Geek Faeries 2013 , du 20 au 22 septembre, à 1h20 de Paris : Des invités de marque, un château, du gaming... Le Joueur du Grenier, Nesblog, la série Noob, Pen of Chaos, Reflets d'Acide, et bien plus encore !
n°1269227
Tigriss
Orga gaming des Geek Faëries
Posté le 17-12-2005 à 22:24:08  profilanswer
 

up
 
Je suis en train de mettre en place le système de "récupération" des pixels perdus. On va bien voir ce que ça donne ^^
 
Par  contre, il y a un probleme de math range quand on pousse trop des itérations. Ca, c'est vraiment pas génial, il faudrait passer outre, sinon on ne peut atteindre une précision suffisante pour une image "propre" (1000 itérations d'initialisation, et 5000 de calcul).
Enquête en route, et si jamais un spécialiste math sous python passe par ici...


---------------
Geek Faeries 2013 , du 20 au 22 septembre, à 1h20 de Paris : Des invités de marque, un château, du gaming... Le Joueur du Grenier, Nesblog, la série Noob, Pen of Chaos, Reflets d'Acide, et bien plus encore !
n°1269237
masklinn
í dag viðrar vel til loftárása
Posté le 17-12-2005 à 22:48:49  profilanswer
 

BTW édite tes posts et remplace tes [code] par des [code=python] :o


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
n°1269450
0x90
Posté le 18-12-2005 à 14:07:18  profilanswer
 

dans  

Code :
  1. exposant=(log(0.00000001)/log2)/itera


je pense que tu peut optimiser légèrement,
log(a)/log(b) = log(a-b)
donc tu dois pouvoir faire ( si jme trompe pas ) :

Code :
  1. exposant = log(0.000000001 - 2)/itera


et pareil a d'autres endroits du code ... ca te fait économiser une division, je sais pas si ca permet de gagner kkchose de sensible mais c'est toujours ca.
 
[edit pas édité mais après réflexion ...]
Un log d'un nombre négatif spa bon chuis con ^^
 
( plus bas si total est > 2 tu peut t'en  servir, mais le test sera plus lourd que le gain je suppose :/ )


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
n°1269651
Tigriss
Orga gaming des Geek Faëries
Posté le 19-12-2005 à 00:03:58  profilanswer
 

masklinn a écrit :

BTW édite tes posts et remplace tes  par des  :o


 
Fait. En fait, j'avais essayé au début, mais la preview ne m'avait rien donnée... J'ai du me gourrer en tapant "python" :/
Du coup, j'ai édité les posts précédents.
 

0x90 a écrit :

dans  
[code=python]
exposant=(log(0.00000001)/log2)/itera
 
je pense que tu peut optimiser légèrement,
log(a)/log(b) = log(a-b)
donc tu dois pouvoir faire ( si jme trompe pas ) :
[code=python]
exposant = log(0.000000001 - 2)/itera
 
et pareil a d'autres endroits du code ... ca te fait économiser une division, je sais pas si ca permet de gagner kkchose de sensible mais c'est toujours ca.
 
[edit pas édité mais après réflexion ...]
Un log d'un nombre négatif spa bon chuis con ^^
 
( plus bas si total est > 2 tu peut t'en  servir, mais le test sera plus lourd que le gain je suppose :/ )


 
En fait, cette partie du code était là pour éviter au programme de planter avec un log(0), ou pire, un log négatif ;)
Maintenant, je met la valeur minResult à la place. Ca résoud rien, mais c'est plus visible ;)
 
Oui, en effet, le gain est annulé :/ En plus, cette opération n'est pas executée un grand nombre de fois, comparé au calcul par itérations.
 
Sinon, hier, j'ai séparé la boucle principale du programme en deux, une pour remplir une liste avec les exposants, et une autre pour les couleurs. Je verais dans le futur si je dois refusionner ou pas, mais je garde cette fenetre ouverte pour pouvoir faire un traitement à la liste avant de passer à la couleur :
 
Remplacer la grande boucle finale par :
 

Code :
  1. for i in xrange(hauteur, 0, -1):
  2.     liste_exposants_ligne=[]
  3.     for j in range(1, largeur+1):
  4.         liste_exposants_ligne.append(exposant_lyapunov(i*steps+y,j*steps+x,iterations_unused,iterations_used))
  5.         #exposant=exposant_lyapunov(i*steps+y,j*steps+x,iterations_unused,iterations_used,i)
  6.         #image_finale.append(couleur(exposant))
  7.     liste_exposants.append(liste_exposants_ligne)
  8.     print i,"(",hauteur," )"
  9.  
  10. for i in range(0, hauteur):
  11.     for j in range(0, largeur):
  12.  
  13.         #liste_exposants_ligne.append(exposant_lyapunov(i*steps+y,j*steps+x,iterations_unused,iterations_used))
  14.         #exposant=exposant_lyapunov(i*steps+y,j*steps+x,iterations_unused,iterations_used,i)
  15.         image_finale.append(couleur(liste_exposants[i][j]))
  16.     print i,"(",hauteur," )"


 
Et

Code :
  1. image_finale=[]


 
Par

Code :
  1. liste_exposants=[]
  2. image_finale=[]


 
Bon, et faut que je trouve un moyen de me débarraser des problèmes de calcul trop poussé...


Message édité par Tigriss le 19-12-2005 à 00:05:50

---------------
Geek Faeries 2013 , du 20 au 22 septembre, à 1h20 de Paris : Des invités de marque, un château, du gaming... Le Joueur du Grenier, Nesblog, la série Noob, Pen of Chaos, Reflets d'Acide, et bien plus encore !
n°1273874
Tigriss
Orga gaming des Geek Faëries
Posté le 27-12-2005 à 19:22:21  profilanswer
 

up
 
Dispositif de récupération des parties perdues en place, et ça consomme presque rien en temps.
 
Maintenant, j'essaye de comprendre pourquoi quand on pousse trop les itérations, ça plante :P
 
Je posterais une version fonctionelle ce soir


---------------
Geek Faeries 2013 , du 20 au 22 septembre, à 1h20 de Paris : Des invités de marque, un château, du gaming... Le Joueur du Grenier, Nesblog, la série Noob, Pen of Chaos, Reflets d'Acide, et bien plus encore !

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  Python

  [Python][WIP] Fractales Markus-Lyapunov (Avis et conseils demandés)

 

Sujets relatifs
Avis sur un site + progsPython/unicode: écrire de gauche à droite/de droite à gauche [résolu]
Passage de Python à Visual BasicXml / ISO et python qui veut pas des caractères non ascii [Résolu]
MySQL + Python.. possible ?Ma réalisation, votre avis
quelques précisions sur Python (PyUnit et modules)Avis Web-vhosts
votre avis sur mon premier site webPython sur hébergement mutualisé.
Plus de sujets relatifs à : [Python][WIP] Fractales Markus-Lyapunov (Avis et conseils demandés)


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR