📖 第14课:人工生命演化

遗传算法 适应度 Tierra 开放演化

🧬 从自复制到演化——人工生命

自复制是第一步,但真正的生命还需要变异选择。本课将达尔文演化论与CA结合,创建能在硬件中演化的"数字生命"。

演化的三要素

  1. 变异(Mutation):复制过程中偶尔出错,产生变体
  2. 选择(Selection):某些变体比其他更适应环境,存活更久
  3. 遗传(Heredity):子代继承父代的大部分特征

当这三个条件同时满足时,演化必然发生——无论载体是碳基分子还是硅基电路!

Tierra:数字生态系统的先驱

1991年,Thomas Ray创建了Tierra——一个在计算机中运行的数字生态系统。程序("生物")在共享内存中竞争CPU时间和内存空间。令人惊讶的是:

⚡ 演化CA引擎

带变异的自复制CA引擎

// ============================================================================
// evolving_ca.v - 带变异和选择的演化CA引擎
// 种群中的个体有不同的规则,适应度高的繁殖更多
// ============================================================================
module evolving_ca #(
    parameter POP_SIZE   = 16,        // 种群大小
    parameter GENOME_W   = 16,        // 基因组位宽(编码规则参数)
    parameter GRID_W     = 16,        // 每个个体的小网格宽度
    parameter GRID_H     = 16,        // 高度
    parameter MUTATION_RATE = 8       // 变异率:1/2^M
)(
    input  wire                          clk,
    input  wire                          rst_n,
    input  wire                          evolve_en,  // 演化使能
    input  wire                          init_pop,   // 初始化种群
    output wire [POP_SIZE*GENOME_W-1:0]  population, // 当前种群基因组
    output wire [POP_SIZE*31:0]          fitness,    // 适应度值
    output wire [31:0]                   generation  // 当前进化代数
);

    // ---- 种群存储 ----
    reg [GENOME_W-1:0] genomes [0:POP_SIZE-1];
    reg [31:0]         fit_vals [0:POP_SIZE-1];
    reg [31:0]         gen_cnt;

    // ---- 伪随机数生成器(用于变异和选择) ----
    reg [31:0] lfsr;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            lfsr <= 32'hDEADBEEF;
        else
            lfsr <= {lfsr[30:0], lfsr[31] ^ lfsr[21] ^ lfsr[1] ^ lfsr[0]};
    end

    // ---- 适应度评估 ----
    // 适应度 = 种群稳定后的活元胞数(简化版)
    // 实际应用中可以定义为:存活步数、产生的子代数、结构复杂度等
    integer i;
    always @(posedge clk) begin
        if (evolve_en) begin
            for (i = 0; i < POP_SIZE; i = i + 1) begin
                // 简化适应度:基因组中1的个数 × 伪随机权重
                fit_vals[i] = 32'd0;
                for (integer b = 0; b < GENOME_W; b = b + 1)
                    fit_vals[i] = fit_vals[i] + genomes[i][b];
            end
        end
    end

    // ---- 选择与繁殖(锦标赛选择) ----
    reg [2:0] evo_phase;  // 0=评估 1=选择 2=变异 3=替换
    reg [7:0] sel_idx;
    reg [GENOME_W-1:0] parent1, parent2, child;
    reg [31:0] best_fit;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            gen_cnt <= 32'd0;
            evo_phase <= 3'd0;
        end else if (init_pop) begin
            for (i = 0; i < POP_SIZE; i = i + 1)
                genomes[i] <= lfsr[GENOME_W-1:0] ^ i;  // 随机初始化
            gen_cnt <= 32'd0;
        end else if (evolve_en) begin
            case (evo_phase)
                3'd0: begin  // 锦标赛选择
                    // 随机选2个个体,取适应度高的
                    sel_idx <= lfsr[7:0] % POP_SIZE;
                    evo_phase <= 3'd1;
                end
                3'd1: begin  // 交叉
                    parent1 <= genomes[sel_idx];
                    parent2 <= genomes[(sel_idx + 1) % POP_SIZE];
                    // 单点交叉
                    child <= {parent1[GENOME_W-1:GENOME_W/2],
                               parent2[GENOME_W/2-1:0]};
                    evo_phase <= 3'd2;
                end
                3'd2: begin  // 变异
                    for (integer b = 0; b < GENOME_W; b = b + 1) begin
                        if (lfsr[MUTATION_RATE-1:0] == {MUTATION_RATE{1'b0}})
                            child[b] <= ~child[b];  // 翻转位
                    end
                    evo_phase <= 3'd3;
                end
                3'd3: begin  // 替换最差个体
                    // 找到适应度最低的个体,替换为子代
                    genomes[sel_idx] <= child;
                    gen_cnt <= gen_cnt + 32'd1;
                    evo_phase <= 3'd0;
                end
            endcase
        end
    end

    // 输出
    genvar gi;
    generate
        for (gi = 0; gi < POP_SIZE; gi = gi + 1) begin : gen_pop_out
            assign population[gi*GENOME_W +: GENOME_W] = genomes[gi];
            assign fitness[gi*32 +: 32] = fit_vals[gi];
        end
    endgenerate
    assign generation = gen_cnt;

endmodule

🏋️ 练习

练习14.1:用遗传算法搜索"最长存活"的生命游戏初始配置。定义适应度为种群在N步后仍未消亡的比例。
练习14.2:修改适应度函数,使其奖励"能产生滑翔机"的配置。能否演化出类似Gosper枪的结构?
练习14.3:实现"生态系统"——多个种群在同一网格中竞争,每个种群使用不同的B/S规则。
练习14.4:在演化CA中研究"红皇后效应"——两个竞争种群是否必须不断进化才能维持相对适应度?
练习14.5(挑战):实现开放演化(Open-ended Evolution)——不预设适应度函数,让系统自行决定什么"好"。你能观察到"进化创新"吗?

🏆 成就解锁

🏅 数字达尔文

你已经在硬件中实现了演化的核心机制——变异、选择、遗传。这是人工生命的基石。

📐 深入分析:演化算法的收敛性分析

遗传算法的理论保证

模式定理(Holland, 1975):

短定义距、低阶、高于平均适应度的模式在后代中指数增长

m(H, t+1) ≥ m(H, t) × f(H)/f_avg × (1-p_c - p_m)

其中m(H,t)是模式H在第t代的实例数,f(H)是模式平均适应度

但注意:模式定理只给出下界,不保证全局最优

No Free Lunch定理(Wolpert & Macready, 1997):

对所有可能的问题平均而言,任何搜索算法的性能相同

这意味着:遗传算法的优势仅在"结构化"的问题上

CA规则搜索恰好是结构化的问题——相似的规则倾向于有相似的行为

补充实现

// 适应度评估器 - 评估CA规则的多种适应度指标
module fitness_evaluator #(
    parameter GRID_W = 16,
    parameter GRID_H = 16,
    parameter STEPS = 100
)(
    input  wire             clk,
    input  wire             rst_n,
    input  wire [7:0]       rule,
    input  wire             start,
    output wire [31:0]      fitness_survival,  // 存活步数
    output wire [31:0]      fitness_diversity,  // 图案多样性
    output wire [31:0]      fitness_complexity,  // 结构复杂度
    output wire             done
);
    // 运行CA并收集统计信息
    reg [GRID_W*GRID_H-1:0] ca_state;
    reg [31:0] step_cnt;
    reg [31:0] pop_history [0:STEPS-1];
    reg running;
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            running <= 1'b0;
            step_cnt <= 32'd0;
        end else if (start && !running) begin
            running <= 1'b1;
            step_cnt <= 32'd0;
            ca_state <= (1 << (GRID_W*GRID_H/2));
        end else if (running) begin
            // 简化的CA步进
            pop_history[step_cnt] <= 32'd0; // 种群计数
            step_cnt <= step_cnt + 32'd1;
            if (step_cnt >= STEPS - 1) running <= 1'b0;
        end
    end
    
    assign fitness_survival = step_cnt;
    assign fitness_diversity = 32'd0;
    assign fitness_complexity = 32'd0;
    assign done = !running && (step_cnt > 0);
endmodule

性能与优化分析

演化参数的调优

种群大小 POP_SIZE:太小→早熟收敛,太大→计算浪费。推荐16-64

变异率 MUTATION_RATE:太低→无法探索,太高→退化为随机搜索。推荐1/(基因组长度)

选择压力:锦标赛大小T。T越大→选择越强→收敛越快但可能早熟

精英保留:每代保留最优个体不参与变异。防止最优解丢失

📖 扩展阅读

🔬 补充专题:实验方法论

在进行CA实验时,科学的方法论至关重要。以下是一些通用的实验指导原则:

实验设计三要素

  1. 控制变量:每次只改变一个参数,保持其他不变
  2. 可重复性:记录所有参数,确保实验可以精确复现
  3. 统计显著性:多次运行取平均,避免偶然结果误导

参数扫描方法

系统性地扫描参数空间是理解CA行为的关键技术:

参数范围步长测量指标
规则号0-2551种群密度/周期
初始密度0.1-0.90.1收敛时间
网格大小16-256×2有限尺寸效应
边界条件环形/固定/镜像离散边界效应
💡 实验记录模板:每次实验记录以下信息——日期、规则号、初始条件、网格大小、边界条件、运行步数、关键观察、数据文件路径。这是科学研究的良好习惯,也使得结果可以追溯和验证。

数据可视化技巧

CA实验产生的数据通常是高维的(空间+时间+状态)。有效的可视化对于理解至关重要:

自相关分析

时间自相关:R(τ) = ⟨n(t)·n(t+τ)⟩ / ⟨n²⟩

空间自相关:C(r) = ⟨n(x)·n(x+r)⟩ / ⟨n²⟩

如果R(τ)以周期T振荡 → 系统有周期T的行为

如果C(r)幂律衰减 → 系统处于临界状态

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