Synchronisation des lucioles : du modèle d’agents à l’automate cellulaire en Wolfram Language
Les lucioles s’harmonisent grâce à des interactions locales. Chaque agent possède un minuteur interne compris entre [0,1], qui diminue de 0,01 par étape. Lorsqu’il atteint 0, une flash se produit (état 1), influençant les voisins dans un rayon prédéfini.
Le mécanisme clé est la correction adaptative de phase : si un voisin flash, le minuteur courant avance ou recule selon sa position dans le cycle. La direction est déterminée par Sign[2 Round[état] - 1] : négative pour les états proches de 0, positive pour ceux proches de 1.
Modèle d’agents : génération et connexions
Plaçons tout d’abord n agents dans une région et attribuons-leur des états initiaux aléatoires :
generateFireFlies[n_:200, region_:Rectangle[{-10,-10}, {10,10}]] := fireFlies = With[{
pos = RandomPoint[region, n]
},
Transpose[{pos, Table[RandomReal[{0,1.0}], {Length[pos]}]}]
];
Chaque luciole est une paire {position, état}. La matrice de connexion est calculée via la distance euclidienne :
bakeConnections[r_:3.7] := (
connectionMatrix = Table[
If[i == j, Infinity, Power[Norm[i[[1]] - j[[1]]], 2]]
, {i, fireFlies}, {j, fireFlies}];
connectionMatrix = MapIndexed[
Function[{value, index},
If[value < r, index[[1]], Nothing]
],
#
] & /@ connectionMatrix
);
Opérations principales par étape :
- Dégradation :
Clip[état - 0.01, {0,1}] - Flash : lorsque état == 0 → 1
- Correction : si un voisin est à l’état 1,
état + Sign[2 Round[état] - 1] * 0.0001
Mise à jour : fireFlies = MapIndexed[ajuster, décroissance /@ flash /@ fireFlies];
Test à petite échelle
Pour deux agents, la synchronisation prend environ 10 cycles. Les graphiques d’état montrent une convergence :
generateFireFlies[2, Circle[{0,0},0.5]];
bakeConnections[2.0];
Une visualisation animée via EventHandler[AnimationFrameListener[...]] illustre l’alignement de phase.
Avec 200 agents, on utilise des disques colorés :
cf = Blend[{Darker[Red], Yellow}, #] &;
Graphics[{
Table[
With[{i = i, xy = fireFlies[[i,1]]},
{RGBColor[colors[[i]]], Disk[xy, 0.3]}
], {i, Length[fireFlies]}
],
EventHandler[AnimationFrameListener[colors], miseÀJour]
}, Background->Black]
Un flou sur une couche dupliquée crée un effet lumineux.
Transition vers l’automate cellulaire
La logique ressemble au Jeu de la vie, mais avec des états continus. Un grille 25×25 est initialisée avec RandomReal[{0,1.01}, {25,25}].
Les flashes sont détectés via Floor[champ]. L’influence des voisins utilise un noyau de convolution 3×3 :
ListConvolve[
{{1.0,1.0,1.0}, {1.0,0.0,1.0}, {1.0,1.0,1.0}},
Floor[champ],
2, 0
]
Correction : (2.0 Round[champ] - 1.0) * Clip[convolution, {0, 0.001}]. Dégradation-flash : Map[Clip[# - 0.01, {0.0,1.0}, {1.0,1.0}], f, {2}].
Boucle complète dans Refresh à 30 FPS :
Module[{f = RandomReal[{0,1.01}, {25,25}]}, Refresh[
f = Map[Clip[# - 0.01, {0.0,1.0}, {1.0,1.0}]&, f, {2}];
f = Clip[
f + (2.0 Round[f] - 1.0)
Clip[
ListConvolve[
{{1.0,1.0,1.0}, {1.0,0.0,1.0}, {1.0,1.0,1.0}},
Floor[f],
2, 0
], {0, 0.001}
],
{0., 1.0}
];
ArrayPlot[f, Frame->True, ColorFunction->"PlumColors"]
, 1/30.0]]
Des motifs ondulatoires apparaissent progressivement.
Optimisation des performances
ArrayPlot dans Refresh fonctionne bien pour les prototypes, mais pour des échelles plus grandes, utiliser NumericArray et Image :
champ = RandomReal[{0,1.0}, {50,50}];
render = Function[Null,
Do[
champ = Map[Clip[# - 0.01, {0.0,1.0}, {1.0,1.0}]&, champ, {2}];
champ = Clip[
champ + (2.0 Round[champ] - 1.0)
Clip[ListConvolve[{{1,1,1},{1,0,1},{1,1,1}}, Floor[champ], 2, 0], {0,0.001}],
{0.,1.0}
];
, {2}];
bufferImage = NumericArray[255.0 champ, "Byte", "ClipAndRound"];
];
Image[bufferImage, "Byte", Epilog -> EventHandler[AnimationFrameListener[bufferImage], render], Magnification -> 20]
Sur une grille 50×50, des structures semblant des radars apparaissent.
Génération de vidéos
Pour l’exportation :
film = Table[
render[];
ImageResize[Colorize[Image[bufferImage]], Scaled[6], Method->"NearestNeighbor"],
{600}
];
FrameListVideo[film, FrameRate->60]
Le modèle passe du système d’agents à des convolutions compatibles GPU, illustrant des comportements émergents.
Points clés
- Des règles locales (dégradation + correction adaptative) mènent à une synchronisation globale.
- Modèle d’agents → automate cellulaire : la convolution remplace les boucles sur les voisins.
Sign[2 Round[état] - 1]permet un ajustement de phase bidirectionnel.NumericArray+Imageoptimisent le rendu pour de grands champs.- Le noyau rectangulaire produit des motifs carrés ; pour plus de réalisme, les noyaux gaussiens sont préférés.
— Editorial Team
Aucun commentaire pour le moment.