📖 第11课:Langton蚂蚁

Langton 蚂蚁 图灵完备 涌现

🐜 Langton蚂蚁——最简单的图灵完备系统?

1986年,Chris Langton提出了一个极其简单的二维CA:一个"蚂蚁"在网格上行走,规则只有两条:

Langton蚂蚁规则

  1. 在白色格子上 → 右转90°,将格子涂黑,前进一格
  2. 在黑色格子上 → 左转90°,将格子涂白,前进一格

就这么简单!但它的行为令人震惊——前500步左右看似混沌,然后突然开始构建一条"高速公路",永远向一个方向延伸...

蚂蚁的三个阶段

阶段步数范围行为特征
混沌期0~500看似随机的对称图案中心区域呈近似对称
过渡期500~10000偶尔出现短暂的"准高速公路"局部有序结构出现又消失
高速公路>10000稳定的对角线高速公路每104步重复一次,向对角线方向无限延伸
💡 为什么是104步?:高速公路的一个完整周期是104步——蚂蚁走一段对角线后回到与之前相同的状态(只是位置偏移了)。这种"自组织临界"行为从两条极其简单的规则中涌现,是复杂系统科学的经典范例。

⚡ Langton蚂蚁的Verilog实现

Langton蚂蚁引擎

// ============================================================================
// langton_ant.v - Langton蚂蚁硬件引擎
// 支持多色扩展( generalized Langton's ant)
// ============================================================================
module langton_ant #(
    parameter WIDTH  = 128,           // 网格宽度
    parameter HEIGHT = 128,           // 网格高度
    parameter COLORS = 2              // 颜色数(2=经典版)
)(
    input  wire             clk,
    input  wire             rst_n,
    input  wire             enable,
    input  wire             init,
    output wire [1:0]       ant_dir,      // 蚂蚁方向(0=N,1=E,2=S,3=W)
    output wire [7:0]       ant_x,        // 蚂蚁X坐标
    output wire [7:0]       ant_y,        // 蚂蚁Y坐标
    output wire [31:0]      step_count,
    output wire [WIDTH*HEIGHT-1:0] grid   // 网格状态
);

    // ---- 网格状态(每格1位,2色版本) ----
    reg [WIDTH*HEIGHT-1:0] grid_reg;

    // ---- 蚂蚁状态 ----
    reg [7:0]  ax, ay;       // 位置
    reg [1:0]  dir;          // 方向: 00=北 01=东 10=南 11=西
    reg [31:0] steps;

    // ---- 当前格子颜色 ----
    wire [WIDTH*HEIGHT-1:0] idx = ay * WIDTH + ax;
    wire current_color = grid_reg[idx];

    // ---- 下一方向计算 ----
    // 白色(0)→右转: dir+1; 黑色(1)→左转: dir-1
    wire [1:0] next_dir = current_color ? (dir - 2'd1) : (dir + 2'd1);

    // ---- 下一位置计算 ----
    reg [7:0] next_x, next_y;
    always @(*) begin
        next_x = ax;
        next_y = ay;
        case (next_dir)
            2'd0: next_y = (ay == 0) ? HEIGHT - 1 : ay - 1;  // 北
            2'd1: next_x = (ax == WIDTH - 1) ? 0 : ax + 1;   // 东
            2'd2: next_y = (ay == HEIGHT - 1) ? 0 : ay + 1;  // 南
            2'd3: next_x = (ax == 0) ? WIDTH - 1 : ax - 1;   // 西
        endcase
    end

    // ---- 状态更新 ----
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            grid_reg <= {WIDTH*HEIGHT{1'b0}};
            ax    <= WIDTH / 2;
            ay    <= HEIGHT / 2;
            dir   <= 2'd0;
            steps <= 32'd0;
        end else if (init) begin
            grid_reg <= {WIDTH*HEIGHT{1'b0}};
            ax    <= WIDTH / 2;
            ay    <= HEIGHT / 2;
            dir   <= 2'd0;
            steps <= 32'd0;
        end else if (enable) begin
            // 翻转当前格子颜色
            grid_reg[idx] <= ~current_color;
            // 更新蚂蚁位置和方向
            ax  <= next_x;
            ay  <= next_y;
            dir <= next_dir;
            steps <= steps + 32'd1;
        end
    end

    assign ant_dir    = dir;
    assign ant_x     = ax;
    assign ant_y     = ay;
    assign step_count = steps;
    assign grid       = grid_reg;

endmodule

多色扩展:广义Langton蚂蚁

广义Langton蚂蚁:将2色扩展为k色,规则字符串指定每种颜色时的转向:

规则 R = r_0 r_1 ... r_{k-1},其中 r_i ∈ {L, R}

经典版:k=2, R="RL"(白→右转,黑→左转)

有趣扩展:

广义Langton蚂蚁

// ============================================================================
// langton_ant_general.v - 广义Langton蚂蚁
// 支持任意颜色数和转向规则
// ============================================================================
module langton_ant_general #(
    parameter WIDTH  = 128,
    parameter HEIGHT = 128,
    parameter COLORS = 4,              // 颜色数
    parameter [COLORS*2-1:0] RULE = 8'b01_00_01_00  // R=01,L=00
)(
    input  wire             clk,
    input  wire             rst_n,
    input  wire             enable,
    input  wire             init,
    output wire [1:0]       ant_dir,
    output wire [7:0]       ant_x,
    output wire [7:0]       ant_y,
    output wire [31:0]      step_count
);

    // 每格存储颜色索引(log2(COLORS)位)
    localparam CW = $clog2(COLORS);
    reg [CW-1:0] grid [0:WIDTH*HEIGHT-1];

    reg [7:0]  ax, ay;
    reg [1:0]  dir;
    reg [31:0] steps;

    wire [CW-1:0] idx = ay * WIDTH + ax;
    wire [CW-1:0] current_color = grid[idx];

    // 规则查找:获取转向
    wire turn_right = RULE[current_color * 2 +: 2] == 2'b01;

    // 方向更新
    wire [1:0] next_dir = turn_right ? (dir + 2'd1) : (dir - 2'd1);

    // 下一颜色
    wire [CW-1:0] next_color = (current_color == COLORS - 1) ? {CW{1'b0}} : current_color + 1'd1;

    // 位置更新
    reg [7:0] next_x, next_y;
    always @(*) begin
        next_x = ax; next_y = ay;
        case (next_dir)
            2'd0: next_y = (ay == 0) ? HEIGHT - 1 : ay - 1;
            2'd1: next_x = (ax == WIDTH - 1) ? 0 : ax + 1;
            2'd2: next_y = (ay == HEIGHT - 1) ? 0 : ay + 1;
            2'd3: next_x = (ax == 0) ? WIDTH - 1 : ax - 1;
        endcase
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            ax <= WIDTH/2; ay <= HEIGHT/2;
            dir <= 2'd0; steps <= 32'd0;
        end else if (init) begin
            ax <= WIDTH/2; ay <= HEIGHT/2;
            dir <= 2'd0; steps <= 32'd0;
            for (integer i = 0; i < WIDTH*HEIGHT; i = i + 1)
                grid[i] <= {CW{1'b0}};
        end else if (enable) begin
            grid[idx] <= next_color;
            ax <= next_x; ay <= next_y;
            dir <= next_dir;
            steps <= steps + 32'd1;
        end
    end

    assign ant_dir    = dir;
    assign ant_x     = ax;
    assign ant_y     = ay;
    assign step_count = steps;

endmodule

📐 Langton蚂蚁的数学性质

图灵完备性:Langton蚂蚁(以及其多色扩展)已被证明是图灵完备的!

证明方法:在蚂蚁的行为中编码图灵机的纸带读写头

这意味着即使是最简单的蚂蚁,理论上也可以执行任意计算

高速公路猜想:对于经典2色蚂蚁,从任意有限初始配置出发,是否总会构建高速公路?

这个猜想仍未被证明!但大量实验证据支持它

注意:在非空初始配置上,蚂蚁可能不会建造高速公路——这取决于初始图案

🏋️ 练习

练习11.1:模拟Langton蚂蚁的前10000步。确认在约10000步时出现高速公路。测量高速公路的周期和方向。
练习11.2:在网格中预设一些黑色方块("障碍物"),观察蚂蚁如何处理这些障碍。是否会破坏高速公路的构建?
练习11.3:实现"双蚂蚁"版本——两只蚂蚁同时行走,共享同一网格。它们如何交互?
练习11.4:测试至少5种不同的多色规则(k=3到k=9),分类它们的行为(填充型、高速公路型、混沌型)。
练习11.5(挑战):在FPGA上实现高速Langton蚂蚁引擎——每时钟周期执行N步(N=10或更多),支持VGA实时显示。

🏆 成就解锁

🏅 蚂蚁牧羊人

你已经进入人工生命领域!Langton蚂蚁展示了极端简单的规则如何产生令人惊讶的复杂行为。

📐 深入分析:Langton蚂蚁的计算复杂性

计算复杂性分析

Langton蚂蚁的每步计算量:

总计算量:O(1)/步——与网格大小无关!

这使得Langton蚂蚁成为O(N)时间复杂度的系统,N=步数

高速公路的渐近行为

高速公路每104步重复一次,偏移量(2,2)

渐近速度:v = (2,2)/104 = (1/52, 1/52)

这是Langton蚂蚁的"终态"——无论初始条件如何(有限非空),最终都会进入这个状态

多蚂蚁的交互

当N只蚂蚁共享同一网格时,它们的交互极其复杂

两只蚂蚁的交互可能:破坏对方的高速公路、创造新的高速公路、形成周期性结构

N只蚂蚁的宏观行为目前没有理论预测

补充实现

// 多蚂蚁引擎 - 支持N只蚂蚁同时运行
module multi_ant #(
    parameter WIDTH  = 128,
    parameter HEIGHT = 128,
    parameter NUM_ANTS = 4
)(
    input  wire             clk,
    input  wire             rst_n,
    input  wire             enable,
    output wire [7:0]       ant_x [0:NUM_ANTS-1],
    output wire [7:0]       ant_y [0:NUM_ANTS-1],
    output wire [1:0]       ant_dir [0:NUM_ANTS-1],
    output wire [WIDTH*HEIGHT-1:0] grid
);
    reg [WIDTH*HEIGHT-1:0] grid_r;
    reg [7:0]  ax [0:NUM_ANTS-1];
    reg [7:0]  ay [0:NUM_ANTS-1];
    reg [1:0]  adir [0:NUM_ANTS-1];
    reg [31:0] steps;
    
    integer a;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            grid_r <= {WIDTH*HEIGHT{1'b0}};
            for (a = 0; a < NUM_ANTS; a = a + 1) begin
                ax[a]   <= WIDTH/2 + a*8;
                ay[a]   <= HEIGHT/2;
                adir[a] <= a[1:0];
            end
        end else if (enable) begin
            for (a = 0; a < NUM_ANTS; a = a + 1) begin
                reg [15:0] idx_a;
                reg cur_color;
                reg [1:0] ndir;
                idx_a = ay[a] * WIDTH + ax[a];
                cur_color = grid_r[idx_a];
                ndir = cur_color ? (adir[a] - 2'd1) : (adir[a] + 2'd1);
                grid_r[idx_a] <= ~cur_color;
                adir[a] <= ndir;
                case (ndir)
                    2'd0: ay[a] <= (ay[a]==0) ? HEIGHT-1 : ay[a]-1;
                    2'd1: ax[a] <= (ax[a]==WIDTH-1) ? 0 : ax[a]+1;
                    2'd2: ay[a] <= (ay[a]==HEIGHT-1) ? 0 : ay[a]+1;
                    2'd3: ax[a] <= (ax[a]==0) ? WIDTH-1 : ax[a]-1;
                endcase
            end
            steps <= steps + 32'd1;
        end
    end
    genvar gi;
    generate
        for (gi = 0; gi < NUM_ANTS; gi = gi + 1) begin
            assign ant_x[gi] = ax[gi];
            assign ant_y[gi] = ay[gi];
            assign ant_dir[gi] = adir[gi];
        end
    endgenerate
    assign grid = grid_r;
endmodule

性能与优化分析

多蚂蚁的资源开销

每只蚂蚁:8位x + 8位y + 2位方向 = 18位寄存器

4只蚂蚁:72位额外寄存器 + 4组位置更新逻辑

网格存储不变:WIDTH×HEIGHT位

注意:多蚂蚁每步需要顺序更新(蚂蚁a的写入影响蚂蚁b的读取)

解决方案:所有蚂蚁同时读取,同时计算,同时写入。如果两只蚂蚁写同一格,后者优先。

📖 扩展阅读

元胞自动机课程 · 从Conway到Langton到Lattice Gas