Zpět na domů

Synchronizace světlušek v Wolfram Language

Článek popisuje implementaci modelu synchronizace světlušek v Wolfram Language. Přechod od agentního modelu k vektorizovanému buněčnému automatu s použitím konvolucí ListConvolve. Optimalizace vykreslování přes NumericArray a generování videa. Demonstruje emergent behavior na příkladech 2–200 agentů a polích 50×50.

Světlušky se synchronizují: kód buněčného automatu
Advertisement 728x90

Synchronizace světlušek: od agentního modelu k buněčným automatům v jazyce Wolfram

Světlušky se synchronizují blikáním prostřednictvím lokálních interakcí. Každý agent má vnitřní časovač v rozsahu [0,1], který klesá rychlostí 0,01 za krok. Když dosáhne hodnoty 0, dojde k bliknutí (stav 1), které ovlivňuje sousedy v určeném okolí.

Klíčový mechanismus je adaptivní fázová korekce: pokud soused blikne, aktuální časovač se posune vpřed nebo vzad v závislosti na pozici v cyklu. Směr určuje Sign[2 Round[state] - 1]: záporný pro stavy blíže k 0, kladný pro stavy blíže k 1.

Agentní model: generování a vazby

Nejprve umístíme n agentů do oblasti a přiřadíme jim náhodné stavy:

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]}]}]
 ];

Každý světlušek je dvojice {poloha, stav}. Matice vazeb se počítá podle euklidovské vzdálenosti:

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
);

Základní operace za krok:

  • Zatížení: Clip[state - 0.01, {0,1}]
  • Bliknutí: při state==0 → 1
  • Korekce: pokud soused je ve stavu 1, state + Sign[2 Round[state] - 1] * 0.0001

Aktualizace: fireFlies = MapIndexed[adjust, decay /@ flash /@ fireFlies];

Google AdInline article slot

Testování na malém měřítku

U dvou agentů trvá synchronizace přibližně 10 cyklů. Graf stavů ukazuje konvergenci:

generateFireFlies[2, Circle[{0,0},0.5]];
bakeConnections[2.0];

Vizuální prezentace s animací prostřednictvím EventHandler[AnimationFrameListener[...]] demonstruje fázové ladění.

Při 200 agentech použijeme barevné disky:

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], update]
}, Background->Black]

Rozmazání duplikované vrstvy vytváří efekt světla.

Přechod k buněčnému automatu

Logika je podobná hře Život, ale s kontinuálními stavy. Pole velikosti 25×25 se inicializuje jako RandomReal[{0,1.01}, {25,25}].

Bliknutí jsou definována pomocí Floor[field]. Vliv sousedů je vyjádřen konvolucí 3×3 jádra:

ListConvolve[
  {{1.0,1.0,1.0}, {1.0,0.0,1.0}, {1.0,1.0,1.0}},
  Floor[field],
  2, 0
]

Korekce: (2.0 Round[field] - 1.0) * Clip[convolution, {0, 0.001}]. Zatížení-bliknutí: Map[Clip[# - 0.01, {0.0,1.0}, {1.0,1.0}], f, {2}].

Plný cyklus v Refresh s frekvencí 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]]

Po iteracích se tvoří vlnové vzory.

Optimalizace výkonu

ArrayPlot v Refresh je vhodný pro prototypy, ale pro větší škály použijeme NumericArray a Image:

field = RandomReal[{0,1.0}, {50,50}];

render = Function[Null,
  Do[
    field = Map[Clip[# - 0.01, {0.0,1.0}, {1.0,1.0}]&, field, {2}];
    field = Clip[
      field + (2.0 Round[field] - 1.0)
        Clip[ListConvolve[{{1,1,1},{1,0,1},{1,1,1}}, Floor[field], 2, 0], {0,0.001}],
      {0.,1.0}
    ];
  , {2}];

  imageBuffer = NumericArray[255.0 field, "Byte", "ClipAndRound"];
];

Image[imageBuffer, "Byte", Epilog -> EventHandler[AnimationFrameListener[imageBuffer], render], Magnification -> 20]

Na poli 50×50 vznikají radarové struktury.

Generování videa

Pro export:

movie = Table[
  render[];
  ImageResize[Colorize[Image[imageBuffer]], Scaled[6], Method->"NearestNeighbor"],
  {600}
];
FrameListVideo[movie, FrameRate->60]

Model se škáluje od agentů ke GPU-přívětivým konvolucím, což ukazuje emergentní chování.

Co je důležité

  • Lokální pravidla (zatížení + adaptivní korekce) vedou ke globální synchronizaci.
  • Agentní model → buněčný automat: konvoluce nahrazuje cykly přes sousedy.
  • Sign[2 Round[state] - 1] zajišťuje bidirekční fázovou úpravu.
  • NumericArray + Image optimalizují vykreslování pro velká pole.
  • Obdélníkové jádro konvoluce vytváří čtvercové vzory; pro realistickost jsou potřeba Gaussianova jádra.

— Editorial Team

Advertisement 728x90

Číst dál