返回首页

Wolfram Language 中的萤火虫同步

文章描述了 Wolfram Language 中萤火虫同步模型的实现。从基于代理的模型过渡到使用卷积 ListConvolve 的向量化细胞自动机。通过 NumericArray 和视频生成进行渲染优化。在 2–200 个代理和 50×50 字段的示例中演示涌现行为。

萤火虫同步:细胞自动机代码
Advertisement 728x90

萤火虫同步:从代理模型到沃尔弗拉姆语言中的细胞自动机

萤火虫通过局部互动实现闪光同步。每个代理拥有一个在 [0,1] 范围内的内部计时器,每步衰减 0.01。当计时器归零时,触发一次闪光(状态为 1),影响指定半径内的邻近个体。

核心机制是自适应相位校正:若邻近个体闪光,则当前计时器根据其在周期中的位置向前或向后调整。方向由 Sign[2 Round[state] - 1] 决定:靠近 0 的状态为负,靠近 1 的状态为正。

代理模型:生成与连接关系

首先,在区域内放置 n 个代理,并赋予随机初始状态:

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

每个萤火虫是一个 {位置, 状态} 对。连接矩阵通过欧几里得距离计算:

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

每步的核心操作包括:

  • 衰减Clip[state - 0.01, {0,1}]
  • 闪光:当 state == 0 → 1
  • 校正:若邻居处于状态 1,则 state + Sign[2 Round[state] - 1] * 0.0001

更新逻辑:fireFlies = MapIndexed[adjust, decay /@ flash /@ fireFlies];

Google AdInline article slot

小规模测试

对于两个代理,同步约需 10 个周期。状态图显示收敛过程:

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

通过 EventHandler[AnimationFrameListener[...]] 实现动画可视化,清晰展示相位对齐效果。

当使用 200 个代理时,采用彩色圆盘表示:

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]

叠加模糊层可营造出发光视觉效果。

过渡到细胞自动机

该逻辑类似于《生命游戏》,但支持连续状态。初始化一个 25×25 网格,值域为 RandomReal[{0,1.01}, {25,25}]

闪光检测通过 Floor[field] 实现。邻域影响使用 3×3 卷积核:

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

校正公式:(2.0 Round[field] - 1.0) * Clip[convolution, {0, 0.001}]。衰减与闪光合并处理:Map[Clip[# - 0.01, {0.0,1.0}, {1.0,1.0}], f, {2}]

完整循环在 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]]

迭代过程中逐渐形成波状图案。

性能优化

ArrayPlotRefresh 中适用于原型验证,但面对更大规模时,建议改用 NumericArrayImage

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]

在 50×50 网格上,雷达状结构开始显现。

视频生成

用于导出视频:

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

该模型从基于代理的系统成功演进至适合 GPU 加速的卷积架构,生动展现了自组织行为的涌现过程。

核心启示

  • 局部规则(衰减 + 自适应校正)可驱动全局同步。
  • 代理模型 → 细胞自动机:卷积取代了邻域遍历。
  • Sign[2 Round[state] - 1] 实现双向相位调节。
  • NumericArray + Image 显著提升大场域渲染效率。
  • 矩形卷积核产生方形图案;追求真实感时,推荐使用高斯核。

— Editorial Team

Advertisement 728x90

继续阅读