Retour à l'accueil

Synchronisation des Lucioles en Wolfram Language

L'article décrit l'implémentation du modèle de synchronisation des lucioles en Wolfram Language. Transition du modèle basé sur des agents à l'automate cellulaire vectorisé à l'aide des convolutions ListConvolve. Optimisation du rendu via NumericArray et génération de vidéo. Démontre le comportement émergent sur des exemples de 2–200 agents et des champs 50×50.

Les Lucioles se Synchronisent : Code d'Automate Cellulaire
Advertisement 728x90

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 :

Google AdInline article slot
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];

Google AdInline article slot

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 :

Google AdInline article slot
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 + Image optimisent 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

Advertisement 728x90

Lire ensuite