Volver al inicio

Sincronización de Luciérnagas en Wolfram Language

El artículo describe la implementación del modelo de sincronización de luciérnagas en Wolfram Language. Transición de modelo basado en agentes a autómata celular vectorizado usando convoluciones ListConvolve. Optimización de renderizado vía NumericArray y generación de video. Demuestra comportamiento emergente en ejemplos de 2–200 agentes y campos de 50×50.

Luciérnagas se Sincronizan: Código de Autómata Celular
Advertisement 728x90

Sincronización de luciérnagas: del modelo de agentes a autómatas celulares en Wolfram Language

Las luciérnagas sincronizan sus destellos mediante interacciones locales. Cada agente tiene un temporizador interno en el rango [0,1], que disminuye a una tasa de 0,01 por paso. Cuando alcanza 0, se produce un destello (estado 1), afectando a los vecinos dentro de un radio especificado.

El mecanismo clave es la corrección adaptativa de fase: si un vecino destella, el temporizador actual se ajusta hacia adelante o atrás según su posición en el ciclo. La dirección se determina mediante Sign[2 Round[state] - 1]: negativa para estados más cercanos a 0, positiva para los más cercanos a 1.

Modelo de agentes: generación y conexiones

Primero, coloque n agentes en una región y asigne estados iniciales aleatorios:

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

Cada luciérnaga es un par {posición, estado}. La matriz de conexiones se calcula usando distancia euclidiana:

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

Operaciones principales por paso:

  • Decaimiento: Clip[estado - 0.01, {0,1}]
  • Destello: cuando estado == 0 → 1
  • Corrección: si un vecino está en estado 1, estado + Sign[2 Round[estado] - 1] * 0.0001

Actualización: fireFlies = MapIndexed[adjust, decay /@ flash /@ fireFlies];

Google AdInline article slot

Prueba a pequeña escala

Para dos agentes, la sincronización toma unos 10 ciclos. Los gráficos de estado muestran convergencia:

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

La visualización con animación mediante EventHandler[AnimationFrameListener[...]] demuestra la alineación de fases.

Con 200 agentes, use discos coloreados:

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]

Desenfocar una capa duplicada crea un efecto brillante.

Transición a autómata celular

La lógica se asemeja al Juego de la Vida, pero con estados continuos. Se inicializa una cuadrícula de 25×25 con RandomReal[{0,1.01}, {25,25}].

Los destellos se detectan mediante Floor[campo]. La influencia de los vecinos usa un kernel de convolución 3×3:

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

Corrección: (2.0 Round[campo] - 1.0) * Clip[convolución, {0, 0.001}]. Decaimiento-destello: Map[Clip[# - 0.01, {0.0,1.0}, {1.0,1.0}], f, {2}].

Bucle completo en Refresh a 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]]

Aparecen patrones ondulantes con las iteraciones.

Optimización de rendimiento

ArrayPlot en Refresh funciona bien para prototipos, pero para escalas mayores, use NumericArray y 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]

En una cuadrícula de 50×50 aparecen estructuras tipo radar.

Generación de video

Para exportar:

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

El modelo escala desde sistemas basados en agentes hasta convoluciones amigables con GPU, mostrando comportamiento emergente.

Conclusiones clave

  • Reglas locales (decaimiento + corrección adaptativa) generan sincronización global.
  • Modelo de agente → autómata celular: la convolución reemplaza los bucles de vecinos.
  • Sign[2 Round[estado] - 1] permite ajuste bidireccional de fase.
  • NumericArray + Image optimizan la representación en campos grandes.
  • El kernel rectangular produce patrones cuadrados; para mayor realismo, se prefieren kernels gaussianos.

— Editorial Team

Advertisement 728x90

Leer después