📖 第2课:一维初等CA——Wolfram规则

Wolfram规则 规则编码 硬件映射

🎯 本课目标

深入理解Wolfram的256种一维初等CA的编码体系,掌握规则号与状态转移表的数学关系,并用Verilog实现一个支持运行时规则切换的CA引擎。

🔢 Wolfram规则的数学结构

邻域与规则空间

一维初等CA的定义:

规则编码公式

将8种邻域模式按二进制值降序排列:

b₇b₆b₅b₄b₃b₂b₁b₀

其中 b_j = f(邻域模式j),j从7(111)到0(000)

规则号 R = Σ(j=0 to 7) b_j × 2^j

因此 R ∈ {0, 1, 2, ..., 255}

规则的完整解码表

邻域模式二进制值位位置规则30规则90规则110规则150
■■■111 = 7b₇0001
■■□110 = 6b₆0100
■□■101 = 5b₅0011
■□□100 = 4b₄1100
□■■011 = 3b₃1110
□■□010 = 2b₂1010
□□■001 = 1b₁1110
□□□000 = 0b₀0000
二进制输出00011110010110100110111010010100
十进制规则号3090110150

规则等价类

256种规则中,许多是等价的。等价变换有两种:

1. 左右反射(Mirror):

交换邻域中左右邻居的角色:111↔111, 110↔011, 101↔101, 100↔001, 010↔010, 000↔000

即交换b₆↔b₃,b₄↔b₁

2. 状态取反(Complement):

将0和1互换:将规则R的每一位取反,得到255-R

3. 组合变换:左右反射 + 状态取反

因此256种规则分为最多 256/4 = 64 个等价类

实际上有些规则是自对称的,等价类少于64个

💡 实际意义:硬件实现时,只需实现每个等价类的一个代表规则,通过输入变换即可覆盖所有256种规则。这节省了3/4的规则存储空间。

⚡ 运行时可配置的CA引擎

上一课的ca_core_1d使用编译时参数RULE,现在我们实现运行时可切换规则的版本。

可配置规则CA引擎

// ============================================================================
// ca_configurable_1d.v - 运行时可配置规则的一维CA引擎
// 支持动态规则切换、多种边界条件、步数计数
// ============================================================================
module ca_configurable_1d #(
    parameter WIDTH = 64               // 网格宽度
)(
    input  wire             clk,
    input  wire             rst_n,
    input  wire             enable,     // 步进使能
    input  wire             init,       // 初始化脉冲
    input  wire [WIDTH-1:0] seed,       // 初始种子
    input  wire [7:0]       rule,       // Wolfram规则号(运行时可变)
    input  wire             wrap_en,    // 1=环形边界, 0=固定边界
    input  wire             fixed_val,  // 固定边界值(当wrap_en=0时)
    output wire [WIDTH-1:0] state,      // 当前状态
    output wire [31:0]      step_count  // 已运行步数
);

    // ---- 状态寄存器 ----
    reg [WIDTH-1:0] curr_state;
    reg [WIDTH-1:0] next_state;
    reg [31:0]      step_reg;

    // ---- 边界处理 ----
    wire left_boundary, right_boundary;

    // 左边界:环形 or 固定
    assign left_boundary  = wrap_en ? curr_state[WIDTH-1] : fixed_val;
    assign right_boundary = wrap_en ? curr_state[0]       : fixed_val;

    // ---- 邻域提取与规则应用 ----
    genvar i;
    generate
        for (i = 0; i < WIDTH; i = i + 1) begin : gen_cell
            wire left, self, right;

            // 提取左邻居
            assign left  = (i == 0)        ? left_boundary  : curr_state[i-1];
            // 自身
            assign self  = curr_state[i];
            // 提取右邻居
            assign right = (i == WIDTH-1)  ? right_boundary : curr_state[i+1];

            // 邻域编码
            wire [2:0] neighborhood = {left, self, right};

            // 规则查找:从8位规则中选取对应位
            assign next_state[i] = rule[neighborhood];
        end
    endgenerate

    // ---- 状态更新 ----
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            curr_state <= {WIDTH{1'b0}};
            step_reg    <= 32'd0;
        end else if (init) begin
            curr_state <= seed;
            step_reg    <= 32'd0;
        end else if (enable) begin
            curr_state <= next_state;
            step_reg    <= step_reg + 32'd1;
        end
    end

    assign state      = curr_state;
    assign step_count = step_reg;

endmodule

🔬 特殊规则的硬件优化

某些规则的结构允许大幅简化硬件。让我们分析几个关键规则:

规则90 — Sierpinski三角形生成器

规则90的LUT = 01011010

分析:next_i = left_i XOR right_i

证明:当 {left, self, right} = {1,0,1}→1, {1,1,0}→1, {0,1,1}→1, {0,0,1}→1

恰好是 left XOR right!中间元胞self被忽略。

规则90的优化实现

// ============================================================================
// ca_rule90_opt.v - 规则90的优化硬件实现
// 规则90等价于 XOR(left, right),无需查找表
// ============================================================================
module ca_rule90_opt #(
    parameter WIDTH = 128              // 支持更大宽度,因为逻辑极简
)(
    input  wire             clk,
    input  wire             rst_n,
    input  wire             enable,
    input  wire             init,
    input  wire [WIDTH-1:0] seed,
    output wire [WIDTH-1:0] state
);

    reg [WIDTH-1:0] curr_state;
    wire [WIDTH-1:0] next_state;

    // 规则90: next[i] = curr[i-1] XOR curr[i+1]
    // 环形边界
    assign next_state[0]        = curr_state[WIDTH-1] ^ curr_state[1];
    assign next_state[WIDTH-1]  = curr_state[WIDTH-2] ^ curr_state[0];

    genvar i;
    generate
        for (i = 1; i < WIDTH-1; i = i + 1) begin : gen_xor
            assign next_state[i] = curr_state[i-1] ^ curr_state[i+1];
        end
    endgenerate

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            curr_state <= {WIDTH{1'b0}};
        else if (init)
            curr_state <= seed;
        else if (enable)
            curr_state <= next_state;
    end

    assign state = curr_state;

endmodule
💡 优化效果:规则90的优化实现将每个元胞的8:1 MUX替换为单个XOR门,面积减少约75%,延迟减少约60%。这是算法级优化的典型例子——理解规则的本质结构,而非盲目使用通用框架。

规则150 — 另一个XOR规则

规则150的LUT = 10010100

分析:next_i = left_i XOR self_i XOR right_i

即三输入XOR(奇偶校验)

规则关系的代数结构

XOR型规则形成代数群:

规则90: f = L ⊕ R(左异或右)

规则150: f = L ⊕ C ⊕ R(左异或中异或右)

规则90 ⊕ 规则150 = ?

按位XOR两个规则的LUT:01011010 ⊕ 10010100 = 11001110 = 规则206

规则206: f = C ⊕ 1(中间取反),等价于 NOT(C)

这揭示了CA规则空间的代数结构

🧪 完整仿真验证

我们编写一个综合testbench,同时验证多个规则:

多规则验证Testbench

// ============================================================================
// ca_multi_rule_tb.v - 多规则验证
// ============================================================================
\`timescale 1ns/1ps

module ca_multi_rule_tb;

    parameter WIDTH = 16;
    reg clk, rst_n, enable, init;
    reg  [WIDTH-1:0] seed;
    reg  [7:0]       rule;
    wire [WIDTH-1:0] state;
    wire [31:0]      step_count;

    ca_configurable_1d #(.WIDTH(WIDTH)) dut (
        .clk(clk), .rst_n(rst_n), .enable(enable),
        .init(init), .seed(seed), .rule(rule),
        .wrap_en(1'b1), .fixed_val(1'b0),
        .state(state), .step_count(step_count)
    );

    // 时钟生成
    initial clk = 0;
    always #5 clk = ~clk;

    // 规则测试序列
    reg [7:0] rules_to_test [0:3];
    integer   r, step;

    initial begin
        rules_to_test[0] = 8'd30;    // 混沌
        rules_to_test[1] = 8'd90;    // Sierpinski
        rules_to_test[2] = 8'd110;   // 通用计算
        rules_to_test[3] = 8'd150;   // XOR

        $dumpfile("ca_multi_rule.vcd");
        $dumpvars(0, ca_multi_rule_tb);

        for (r = 0; r < 4; r = r + 1) begin
            // 复位
            rst_n = 0; enable = 0; init = 0;
            #20 rst_n = 1;

            // 加载初始状态:仅中心位为1
            rule = rules_to_test[r];
            seed = (WIDTH == 16) ? 16'h0080 : 64'h1;
            init = 1; #10; init = 0;

            $display("--- Rule %0d ---", rule);

            // 运行16步
            for (step = 0; step < 16; step = step + 1) begin
                // 打印状态
                $write("Step %2d: ", step);
                for (integer b = WIDTH-1; b >= 0; b = b - 1)
                    $write("%b", state[b]);
                $write("\n");

                enable = 1; #10; enable = 0; #10;
            end
        end

        $display("✅ All rules verified successfully!");
        $finish;
    end

endmodule

📊 Wolfram规则分类详解

Class I — 趋于稳定

规则0(全零)、规则255(全一)是最极端的例子。从任何初始状态出发,都在有限步内收敛到均匀态。

规则0:所有输出为0 → f(any) = 0,一步归零

规则255:所有输出为1 → f(any) = 1,一步归一

Class II — 周期结构

产生简单的静止或振荡结构,如规则4产生对角线,规则108产生条纹。

这些规则的信息传播距离有限——局部扰动不会影响远处。

Class III — 混沌

规则30是最著名的混沌CA。从单点种子出发,产生看似随机的模式。

规则30的混沌特性被Mathematica用作伪随机数生成器!

PRNG: x_{n+1} 的某些位 = Rule30演化序列

Class IV — 复杂/计算通用

规则110是Wolfram发现的通用计算CA。它产生局域的"粒子"结构,这些粒子可以交互、碰撞、传递信息——本质上构成了CA中的"信号"和"逻辑门"。

⚠️ 规则110的通用性证明:由Matthew Cook在2004年正式证明,这是第一个被证明图灵完备的一维初等CA。证明方法是在规则110中编码循环标签系统(cyclic tag system),而循环标签系统已知是图灵完备的。

🏋️ 练习

练习2.1:手动计算规则22(LUT=00010110)和规则54(LUT=00110110)从前8步的演化,初始状态为16位全零+中心1。比较两者行为,分别属于哪一类?
练习2.2:证明规则90(LUT=01011010)确实等价于 next_i = left_i ⊕ right_i,通过枚举所有8种邻域模式验证。
练习2.3:修改ca_configurable_1d,添加规则等价变换功能:给定规则号R,自动计算其镜像规则、补规则和镜像补规则。用Verilog实现这些变换逻辑。
练习2.4:实现规则30的优化版本。分析规则30的LUT=00011110,是否存在比8:1 MUX更简单的布尔表达式?
练习2.5(挑战):设计一个"规则扫描器"模块,自动遍历所有256种规则,对每种规则运行N步,统计输出中1的比例和分布方差,用于自动分类。

🏆 成就解锁

🏅 规则大师

你已掌握Wolfram规则的编码体系和分类法,能手工解码任意规则号,并理解规则空间的代数结构。

🔬 优化意识

你已认识到通用框架≠最优实现。理解规则的本质结构,可以进行算法级优化,大幅减少硬件开销。这是硬件设计者的核心素养。

📖 扩展阅读

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