CleanstoneDevelopmental and independent evidence for machine minds.

exp04_rate_chimera.py

#!/usr/bin/env python3
"""Experiment 0.1b: rate-matched chimera.

All cells run the bubble rule; label-B cells attempt a move with probability p
per turn. If algotype clustering in 0.1 is a rate effect, clustering should be
absent at p = 1 and rise as p falls. Predictions in plan.md.

Usage: exp04_rate_chimera.py [--n 100] [--seeds 100] [--out results/exp04]
       exp04_rate_chimera.py --selftest
"""

import argparse
import csv
import os
import random
import sys

import exp01_sorting as s

PS = (1.0, 0.75, 0.5, 0.25, 0.1)


def run(n, seeds, out_dir):
    rows = []
    for p in PS:
        means, peaks, finals = [], [], []
        for seed in range(seeds):
            rng = random.Random(1000 * seed + 7)
            arr = s.make_array(n, rng, 0, "movable")
            labels = ["A"] * (n // 2) + ["B"] * (n - n // 2)
            rng.shuffle(labels)
            label = dict(enumerate(labels))
            algotype = dict.fromkeys(range(n), "bubble")
            p_move = {v: (p if label[v] == "B" else 1.0) for v in range(n)}
            series = [s.aggregation(arr, label)]
            for _ in s.run_cellview(arr, algotype, "roundrobin", rng, p_move=p_move):
                series.append(s.aggregation(arr, label))
            means.append(sum(series) / len(series))
            peaks.append(max(series))
            finals.append(series[-1])
        rng = random.Random(1)
        row = {"p": p, "n": n, "seeds": seeds}
        for key, xs in (("mean", means), ("peak", peaks), ("final", finals)):
            row[key], row[key + "_lo"], row[key + "_hi"] = s.mean_ci(xs, rng)
        rows.append(row)
        print(f"p={p:4} mean={row['mean']:.3f} [{row['mean_lo']:.3f},{row['mean_hi']:.3f}] "
              f"peak={row['peak']:.3f} final={row['final']:.3f}", file=sys.stderr)
    os.makedirs(out_dir, exist_ok=True)
    with open(os.path.join(out_dir, "rate_chimera.csv"), "w", newline="") as f:
        w = csv.DictWriter(f, fieldnames=list(rows[0].keys()))
        w.writeheader()
        w.writerows(rows)
    return rows


def selftest():
    rng = random.Random(0)
    arr = s.make_array(30, rng, 0, "movable")
    algotype = dict.fromkeys(range(30), "bubble")
    p_move = {v: 0.3 for v in range(30)}
    for _ in s.run_cellview(arr, algotype, "roundrobin", rng, p_move=p_move):
        pass
    assert arr.vals == list(range(30)), arr.vals
    print("selftest ok")


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--n", type=int, default=100)
    ap.add_argument("--seeds", type=int, default=100)
    ap.add_argument("--out", default=os.path.join(os.path.dirname(__file__), "results", "exp04"))
    ap.add_argument("--selftest", action="store_true")
    a = ap.parse_args()
    if a.selftest:
        selftest()
        return
    run(a.n, a.seeds, a.out)


if __name__ == "__main__":
    main()