diff options
| author | YurenHao0426 <Blackhao0426@gmail.com> | 2026-07-23 08:17:56 -0500 |
|---|---|---|
| committer | YurenHao0426 <Blackhao0426@gmail.com> | 2026-07-23 08:17:56 -0500 |
| commit | 75a64888cb3e117ee6d232adc7b48974647fbc1e (patch) | |
| tree | 4a79340ec2f2f41b267152180f14a5e696b5fca6 | |
| parent | 9a8c0570f8d96cc3bca200ed872323e44e60f55f (diff) | |
figures: add audited oral-B-v2 confirmation panel
| -rw-r--r-- | experiments/plot_bci_v2_confirmation.py | 533 | ||||
| -rw-r--r-- | results/figs/figure5_bci_v2.pdf | bin | 0 -> 30918 bytes | |||
| -rw-r--r-- | results/figs/figure5_bci_v2.png | bin | 0 -> 572434 bytes | |||
| -rw-r--r-- | results/figs/figure5_bci_v2_caption.md | 20 | ||||
| -rw-r--r-- | results/figs/figure5_bci_v2_manifest.json | 78 |
5 files changed, 631 insertions, 0 deletions
diff --git a/experiments/plot_bci_v2_confirmation.py b/experiments/plot_bci_v2_confirmation.py new file mode 100644 index 0000000..6f08ea7 --- /dev/null +++ b/experiments/plot_bci_v2_confirmation.py @@ -0,0 +1,533 @@ +#!/usr/bin/env python3 +"""Render the audited oral-B-v2 confirmation figure from all 30 records.""" +import argparse +import hashlib +import json +import math +import os +import statistics + +import matplotlib + +matplotlib.use("Agg") +import matplotlib.pyplot as plt +import numpy as np + + +TASK_SEEDS = tuple(range(30, 36)) +MODEL_SEEDS = tuple(range(5)) +PROTOCOL = "oral_b_v2_calibrated_recovery_confirmation_v1" +BLUE = "#0072B2" +LIGHT_BLUE = "#56B4E9" +GREEN = "#009E73" +ORANGE = "#E69F00" +RED = "#D55E00" +GRAY = "#5A5A5A" +LIGHT_GRAY = "#B7B7B7" +PDF_METADATA = { + "Creator": "SDIL audited oral-B-v2 figure pipeline", + "Producer": "Matplotlib", + "CreationDate": None, + "ModDate": None, +} + + +def load_json(path): + with open(path) as handle: + return json.load(handle) + + +def sha256(path): + digest = hashlib.sha256() + with open(path, "rb") as handle: + for chunk in iter(lambda: handle.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def require(condition, message): + if not condition: + raise RuntimeError(message) + + +def finite_leaves(value): + if isinstance(value, bool) or value is None: + return True + if isinstance(value, (int, float)): + return math.isfinite(float(value)) + if isinstance(value, dict): + return all(finite_leaves(child) for child in value.values()) + if isinstance(value, (list, tuple)): + return all(finite_leaves(child) for child in value) + return True + + +def all_true(value): + if isinstance(value, dict): + return all(all_true(child) for child in value.values()) + return value is True + + +def load_panel(input_dir, gate_path): + gate = load_json(gate_path) + require(gate.get("protocol") == PROTOCOL, "oral-B-v2 protocol drift") + require(gate.get("status") == "passed", "oral-B-v2 gate is not passed") + require(gate.get("review_score_after") == 8, "oral-B-v2 score drift") + require(all_true(gate.get("checks", {})), "oral-B-v2 has false checks") + records = {} + paths = [] + for task_seed in TASK_SEEDS: + for model_seed in MODEL_SEEDS: + name = ( + f"bci_v2_calibrated_confirm_t{task_seed}" + f"_m{model_seed}.json" + ) + path = os.path.join(input_dir, name) + require(os.path.isfile(path), f"missing oral-B-v2 record: {path}") + row = load_json(path) + paths.append(path) + require(row.get("schema_version") == 4, f"{path}: schema") + require( + row.get("protocol", {}).get("name") == PROTOCOL + and row["protocol"].get("split") + == "untouched_confirmation" + and row.get("split") == "untouched_confirmation", + f"{path}: split/protocol", + ) + require( + row.get("args", {}).get("task_seed") == task_seed + and row["args"].get("model_seed") == model_seed, + f"{path}: seed", + ) + require( + row.get("provenance", {}).get("git_tracked_dirty") is False + and row["provenance"].get("git_commit") + == gate.get("source_commit"), + f"{path}: provenance", + ) + require( + row.get("finite") is True and finite_leaves(row), + f"{path}: finite", + ) + records[(task_seed, model_seed)] = row + observed = sorted( + name for name in os.listdir(input_dir) if name.endswith(".json") + ) + expected = sorted( + ( + f"bci_v2_calibrated_confirm_t{task_seed}" + f"_m{model_seed}.json" + ) + for task_seed in TASK_SEEDS + for model_seed in MODEL_SEEDS + ) + require(observed == expected, "oral-B-v2 record-set drift") + return gate, records, paths + + +def task_cluster_array(records, getter): + return np.asarray([ + np.mean([ + getter(records[(task_seed, model_seed)]) + for model_seed in MODEL_SEEDS + ], axis=0) + for task_seed in TASK_SEEDS + ], dtype=float) + + +def style_axis(axis): + axis.spines["top"].set_visible(False) + axis.spines["right"].set_visible(False) + axis.tick_params(width=1.0, length=4) + axis.grid(axis="y", color="#E7E7E7", linewidth=0.8, zorder=0) + + +def panel_label(axis, label): + axis.text( + -0.14, + 1.08, + label, + transform=axis.transAxes, + fontsize=15, + fontweight="bold", + va="top", + ) + + +def plot_learning(axis, records): + conditions = ( + ("intact", "SDIL + TD critic", BLUE), + ("critic_training_lesion", "critic lesion", ORANGE), + ("outcome_training_lesion", "outcome lesion", GREEN), + ("fixed_role", "fixed role", LIGHT_GRAY), + ) + days = np.arange(1, 15) + for condition, label, color in conditions: + clustered = task_cluster_array( + records, + lambda row: np.asarray( + row["conditions"][condition]["daily_success"] + ) * 100, + ) + mean = clustered.mean(0) + interval = 1.96 * clustered.std(0, ddof=1) / np.sqrt(len(TASK_SEEDS)) + axis.plot(days, mean, color=color, linewidth=2.0, label=label) + axis.fill_between( + days, mean - interval, mean + interval, + color=color, alpha=0.12, linewidth=0, + ) + axis.set_xlim(1, 14) + axis.set_ylim(-3, 104) + axis.set_xticks([1, 4, 7, 10, 14]) + axis.set_xlabel("Training day") + axis.set_ylabel("Successful episodes (%)") + axis.set_title( + "Local actor–critic learns", + loc="left", + fontsize=11.5, + fontweight="bold", + pad=10, + ) + axis.legend(frameon=False, fontsize=8, loc="upper left") + style_axis(axis) + panel_label(axis, "a") + + +def plot_residualization(axis, records): + raw = task_cluster_array( + records, + lambda row: row["signatures"]["mean_abs_raw_soma_corr"], + ) + residual = task_cluster_array( + records, + lambda row: row["signatures"]["mean_abs_residual_soma_corr"], + ) + for index in range(len(TASK_SEEDS)): + axis.plot( + [0, 1], + [raw[index], residual[index]], + color=LIGHT_GRAY, + linewidth=1.3, + zorder=1, + ) + axis.scatter( + np.zeros_like(raw), raw, s=32, facecolor="white", + edgecolor=GRAY, zorder=2, + ) + axis.scatter( + np.ones_like(residual), residual, s=34, facecolor=BLUE, + edgecolor="white", zorder=3, + ) + axis.scatter( + [0, 1], [raw.mean(), residual.mean()], + marker="D", s=65, c=[GRAY, BLUE], edgecolor="#111111", + linewidth=0.7, zorder=4, + ) + axis.axhline(0.10, color=RED, linestyle="--", linewidth=1.0) + axis.text( + 0.98, 0.115, "frozen residual ceiling", + ha="right", va="bottom", color=RED, fontsize=8, + ) + axis.set_xlim(-0.35, 1.35) + axis.set_ylim(0, 1.06) + axis.set_xticks([0, 1], ["Raw apical", "Innovation"]) + axis.set_ylabel("Mean |soma correlation|") + axis.set_title( + "Prediction removes ordinary traffic", + loc="left", + fontsize=11.5, + fontweight="bold", + pad=10, + ) + axis.text( + 0.05, + 0.48, + f"raw $-$ residual = {raw.mean() - residual.mean():.3f}\n" + f"surrounding decoder = " + f"{100 * task_cluster_array(records, lambda row: row['signatures']['surrounding_event_decoder_balanced_acc']).mean():.2f}%", + transform=axis.transAxes, + fontsize=8.5, + bbox={ + "boxstyle": "round,pad=0.35", + "facecolor": "white", + "edgecolor": "#D6D6D6", + }, + ) + style_axis(axis) + panel_label(axis, "b") + + +def plot_psychometric(axis, records): + quantiles = np.asarray([0.20, 0.35, 0.50, 0.65, 0.80]) + + def success_curve(row): + targets = row["assays"]["challenge"]["targets"] + values = row["signatures"]["target_success_fraction"] + return np.asarray([values[str(target)] for target in targets]) * 100 + + clustered = task_cluster_array(records, success_curve) + mean = clustered.mean(0) + interval = 1.96 * clustered.std(0, ddof=1) / np.sqrt(len(TASK_SEEDS)) + expected = (1.0 - quantiles) * 100 + axis.plot( + quantiles, expected, color=LIGHT_GRAY, linestyle="--", + linewidth=1.5, label="calibration expectation", + ) + axis.plot( + quantiles, mean, color=GREEN, marker="o", linewidth=2.0, + label="independent assay", + ) + axis.fill_between( + quantiles, mean - interval, mean + interval, + color=GREEN, alpha=0.15, linewidth=0, + ) + axis.axhline(50, color="#DDDDDD", linewidth=0.9) + axis.set_xlim(0.16, 0.84) + axis.set_ylim(10, 90) + axis.set_xticks(quantiles) + axis.set_xlabel("Calibration quantile used as target") + axis.set_ylabel("Rewarded trials (%)") + axis.set_title( + "Label-free calibration generalizes", + loc="left", + fontsize=11.5, + fontweight="bold", + pad=10, + ) + axis.legend(frameon=False, fontsize=8, loc="upper right") + axis.text( + 0.04, + 0.05, + f"pooled success = " + f"{100 * task_cluster_array(records, lambda row: row['signatures']['challenge_success_fraction']).mean():.2f}%", + transform=axis.transAxes, + fontsize=8.6, + ) + style_axis(axis) + panel_label(axis, "c") + + +def plot_outcome(axis, records, gate): + keys = ( + ( + "terminal_previous_soma_outcome_balanced_acc", + "Pre-outcome\nsoma", + LIGHT_GRAY, + ), + ( + "acute_outcome_lesion_outcome_balanced_acc", + "Innovation\noutcome lesion", + ORANGE, + ), + ( + "terminal_residual_outcome_balanced_acc", + "Innovation\nintact", + BLUE, + ), + ) + values = [ + task_cluster_array( + records, lambda row, key=key: row["signatures"][key] + ) * 100 + for key, _, _ in keys + ] + for index, ((_, _, color), clustered) in enumerate(zip(keys, values)): + axis.bar( + index, clustered.mean(), color=color, width=0.66, + edgecolor="white", zorder=2, + ) + jitter = np.linspace(-0.13, 0.13, len(clustered)) + axis.scatter( + index + jitter, clustered, s=22, facecolor="white", + edgecolor="#333333", linewidth=0.7, zorder=3, + ) + axis.axhline(50, color=RED, linestyle="--", linewidth=1.0) + axis.set_ylim(45, 103) + axis.set_xticks(range(len(keys)), [item[1] for item in keys]) + axis.set_ylabel("Outcome balanced accuracy (%)") + axis.set_title( + "Residual carries outcome surprise", + loc="left", + fontsize=11.5, + fontweight="bold", + pad=10, + ) + drop = gate["metrics"]["outcome_lesion_drop"] + critic = gate["metrics"]["critic_expectedness"] + axis.text( + 0.04, + 0.95, + "role separation lesion\n" + f"$\\Delta$ = {drop['mean']:.3f} " + f"(LCB {drop['one_sided_95pct_lower']:.3f})\n" + "critic expectedness\n" + f"{critic['mean']:.3f} " + f"(LCB {critic['one_sided_95pct_lower']:.3f})", + transform=axis.transAxes, + va="top", + fontsize=8.3, + bbox={ + "boxstyle": "round,pad=0.35", + "facecolor": "white", + "edgecolor": "#D6D6D6", + "alpha": 0.96, + }, + ) + style_axis(axis) + panel_label(axis, "d") + + +def write_caption(path): + caption = """# Oral-B-v2 confirmation figure caption + +**Figure 5 | Role-vectorized somato-dendritic innovation carries +temporal-difference outcome surprise.** All summaries use the complete +untouched six-task by five-model confirmation; uncertainty is computed after +averaging models within each task seed. **a,** Mean episode success over +training. The learned causal-role vector is necessary, the forward-plasticity +lesion (omitted for visual overlap with zero) does not learn, and critic or +terminal-outcome training lesions are reported rather than hidden. Bands are +95% normal intervals over six task clusters. **b,** Ordinary apical traffic is +almost perfectly soma-correlated before subtraction; the innovation is below +the frozen correlation ceiling in every task cluster. **c,** Five targets are +chosen from fixed quantiles of 512 outcome-free cursor-max calibration trials. +The displayed rewarded fractions come from independent assay trajectories; +no evaluation label selects or reweights a target. **d,** Terminal innovation +decodes rewarded versus timeout outcomes, while the acute terminal-outcome +lesion removes role-aligned separation. The critic contribution tracks the +stored value prediction and attenuates expected outcomes. Exact role maps, +outcome labels, and gradients are diagnostic-only and never used by the +learner's updates. +""" + with open(path, "w") as handle: + handle.write(caption) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--input-dir", + default="results/bci_v2_calibrated_confirmation", + ) + parser.add_argument( + "--gate", + default="results/bci_v2_calibrated_confirmation_gate.json", + ) + parser.add_argument("--outdir", default="results/figs") + args = parser.parse_args() + gate, records, paths = load_panel(args.input_dir, args.gate) + os.makedirs(args.outdir, exist_ok=True) + plt.rcParams.update({ + "font.family": "DejaVu Sans", + "font.size": 9.5, + "axes.linewidth": 1.0, + "xtick.major.width": 1.0, + "ytick.major.width": 1.0, + "pdf.fonttype": 42, + "ps.fonttype": 42, + }) + figure, axes = plt.subplots(2, 2, figsize=(10.5, 7.8)) + plot_learning(axes[0, 0], records) + plot_residualization(axes[0, 1], records) + plot_psychometric(axes[1, 0], records) + plot_outcome(axes[1, 1], records, gate) + figure.subplots_adjust( + left=0.09, right=0.98, bottom=0.10, top=0.93, + hspace=0.42, wspace=0.30, + ) + pdf_path = os.path.join(args.outdir, "figure5_bci_v2.pdf") + png_path = os.path.join(args.outdir, "figure5_bci_v2.png") + caption_path = os.path.join( + args.outdir, "figure5_bci_v2_caption.md" + ) + manifest_path = os.path.join( + args.outdir, "figure5_bci_v2_manifest.json" + ) + figure.savefig(pdf_path, metadata=PDF_METADATA) + figure.savefig(png_path, dpi=320) + plt.close(figure) + write_caption(caption_path) + + def mean_metric(key): + return float(task_cluster_array( + records, lambda row: row["signatures"][key] + ).mean()) + + terminal_previous_soma = mean_metric( + "terminal_previous_soma_outcome_balanced_acc" + ) + terminal_outcome_lesion = mean_metric( + "acute_outcome_lesion_outcome_balanced_acc" + ) + manifest = { + "strict": True, + "protocol": PROTOCOL, + "gate_status": gate["status"], + "task_seeds": list(TASK_SEEDS), + "model_seeds": list(MODEL_SEEDS), + "record_count": len(records), + "statistics": { + "intact_final_mean": gate["metrics"]["intact_final"]["mean"], + "learning_gain_mean": gate["metrics"]["intact_gain"]["mean"], + "fixed_role_gap_mean": gate["metrics"]["fixed_role_gap"]["mean"], + "role_cosine_mean": gate["metrics"]["role_cosine"]["mean"], + "residual_soma_corr_mean": + gate["metrics"]["residual_soma_corr"]["mean"], + "raw_residual_corr_gap_mean": + gate["metrics"]["raw_residual_corr_gap"]["mean"], + "surrounding_accuracy_mean": + gate["metrics"]["surrounding_accuracy"]["mean"], + "surrounding_accuracy_lower": + gate["metrics"]["surrounding_accuracy"][ + "one_sided_95pct_lower" + ], + "decoder_corr_mean": gate["metrics"]["decoder_corr"]["mean"], + "sign_inversion_mean": + gate["metrics"]["sign_inversion"]["mean"], + "positive_sign_count": gate["positive_sign_count"], + "velocity_advantage_mean": + gate["metrics"]["velocity_advantage"]["mean"], + "challenge_fraction_mean": + gate["metrics"]["challenge_fraction"]["mean"], + "terminal_accuracy_mean": + gate["metrics"]["terminal_accuracy"]["mean"], + "terminal_accuracy_lower": + gate["metrics"]["terminal_accuracy"][ + "one_sided_95pct_lower" + ], + "terminal_previous_soma_accuracy_mean": + terminal_previous_soma, + "terminal_outcome_lesion_accuracy_mean": + terminal_outcome_lesion, + "terminal_separation_mean": + gate["metrics"]["terminal_separation"]["mean"], + "outcome_lesion_drop_mean": + gate["metrics"]["outcome_lesion_drop"]["mean"], + "outcome_lesion_drop_lower": + gate["metrics"]["outcome_lesion_drop"][ + "one_sided_95pct_lower" + ], + "critic_expectedness_mean": + gate["metrics"]["critic_expectedness"]["mean"], + "critic_expectedness_lower": + gate["metrics"]["critic_expectedness"][ + "one_sided_95pct_lower" + ], + }, + "source_sha256": { + os.path.relpath(path): sha256(path) + for path in sorted(paths + [args.gate]) + }, + } + with open(manifest_path, "w") as handle: + json.dump(manifest, handle, indent=2, sort_keys=True) + handle.write("\n") + print(json.dumps({ + "manifest": manifest_path, + "png": png_path, + "status": "passed", + }, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/results/figs/figure5_bci_v2.pdf b/results/figs/figure5_bci_v2.pdf Binary files differnew file mode 100644 index 0000000..deff043 --- /dev/null +++ b/results/figs/figure5_bci_v2.pdf diff --git a/results/figs/figure5_bci_v2.png b/results/figs/figure5_bci_v2.png Binary files differnew file mode 100644 index 0000000..f1eb506 --- /dev/null +++ b/results/figs/figure5_bci_v2.png diff --git a/results/figs/figure5_bci_v2_caption.md b/results/figs/figure5_bci_v2_caption.md new file mode 100644 index 0000000..41e0dbd --- /dev/null +++ b/results/figs/figure5_bci_v2_caption.md @@ -0,0 +1,20 @@ +# Oral-B-v2 confirmation figure caption + +**Figure 5 | Role-vectorized somato-dendritic innovation carries +temporal-difference outcome surprise.** All summaries use the complete +untouched six-task by five-model confirmation; uncertainty is computed after +averaging models within each task seed. **a,** Mean episode success over +training. The learned causal-role vector is necessary, the forward-plasticity +lesion (omitted for visual overlap with zero) does not learn, and critic or +terminal-outcome training lesions are reported rather than hidden. Bands are +95% normal intervals over six task clusters. **b,** Ordinary apical traffic is +almost perfectly soma-correlated before subtraction; the innovation is below +the frozen correlation ceiling in every task cluster. **c,** Five targets are +chosen from fixed quantiles of 512 outcome-free cursor-max calibration trials. +The displayed rewarded fractions come from independent assay trajectories; +no evaluation label selects or reweights a target. **d,** Terminal innovation +decodes rewarded versus timeout outcomes, while the acute terminal-outcome +lesion removes role-aligned separation. The critic contribution tracks the +stored value prediction and attenuates expected outcomes. Exact role maps, +outcome labels, and gradients are diagnostic-only and never used by the +learner's updates. diff --git a/results/figs/figure5_bci_v2_manifest.json b/results/figs/figure5_bci_v2_manifest.json new file mode 100644 index 0000000..ae5a6ea --- /dev/null +++ b/results/figs/figure5_bci_v2_manifest.json @@ -0,0 +1,78 @@ +{ + "gate_status": "passed", + "model_seeds": [ + 0, + 1, + 2, + 3, + 4 + ], + "protocol": "oral_b_v2_calibrated_recovery_confirmation_v1", + "record_count": 30, + "source_sha256": { + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t30_m0.json": "2909c54021e9d451ef54ae5de6b521478119b9bffaca06f58f711b24431c4d06", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t30_m1.json": "775b835a8d48f6d8dea2cb0078446552fb7cfab2d3e437aa9631c311cd6f40e2", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t30_m2.json": "0f95bdeb1a156ef4a97a59748453dfa1f872b490e68e13df926e37057a42eb36", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t30_m3.json": "fec845763b8402c8abf021000041d3b0790b5b50979ef381c1e2b016a9c5fee1", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t30_m4.json": "110fa43b9b0fcbcef89ed8a2332e871777c116690024ed2fa4bedea155fbb246", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t31_m0.json": "1f1c1fa49dd56743081d6420193b56ecba5f11cb7b2a40300f26e666bc4fb821", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t31_m1.json": "4efde69c884057c73d68a712625f5d940fb152e0ad7f5e301ffbecf9c9b8379a", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t31_m2.json": "10e16869c8b23007b840bec177378abe18c26f3fbabaa9dc09d112d4655b140e", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t31_m3.json": "a8be20d34915f95f7c278c4a4a3c2eaaf775d280b42614dfad8256cd877fe789", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t31_m4.json": "38e58907ad43ab06361a2946935855ea9d059a0ffd51d3cbd0ad596e1b923271", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t32_m0.json": "0254fc9d1945d11c5f178b9267ecbf8fe7f7ac2af8099b84095b4e931e1bb719", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t32_m1.json": "359c7a46d1f3bdde2e9394b5f7dceea01511b4a1714688976be3d69b4312a370", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t32_m2.json": "b2e1228d511fffd9753aacfd2b8f534652612d348900d44584f3c8f7e9ce7c05", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t32_m3.json": "e34d2a5e285184c6e60d088b67d8658d6dc78c62b2fc42c06acdb78f55bd6803", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t32_m4.json": "033dd12ed1e2efacc07ae14297bb0cc8fc74dc9114cd57431de9794bee7c7695", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t33_m0.json": "fba80b70c40169efcb60144e8315b5837184463601c86f3e3bda21361b3318ed", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t33_m1.json": "be952f8068e07612ef469dab0c495788d5b5b9dbc1c198b84ef5f9a17be3f62e", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t33_m2.json": "1d144e27aff463aacbc2e418bb5567016690477ba6f1e9e0e84f241cc8f24105", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t33_m3.json": "f81a7942503b1768c5819aff76e4525c1f0425c70b5a9f1ba397a30b0d5b31f2", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t33_m4.json": "42cc8ca59a3239c351bd3436bd8662e08c706f0861fce07266958e8e55d6dcd4", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t34_m0.json": "b798f59f61ff25c1f6d8e06b35727492a901ee87d8798700d2d7ff111cff0ecb", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t34_m1.json": "f5d4d84beeefd5c2e46187ccb61ef4432b0193c4c7f053c40252740a939ee651", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t34_m2.json": "7b8a5e144f71c5c6476be92612b8924dcdf1ba1d8f3083ce80618099b756adc1", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t34_m3.json": "c75f0c42a28ee1b764a7181e5fb7f449fecf84a3a63f69bf0663ed29f4dd1846", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t34_m4.json": "eb3de9a7edb8d3283a8762c1202310775d634af9a8ea5a25f90f314412f8f615", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t35_m0.json": "c026bcf06003c4129fe2d444f30331187b872ea2d28d55e41e5752cf2e3acb15", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t35_m1.json": "42452e471e10d9b17916f906b6b205632aa1f1de8335b1ffe962e855c53ee4e1", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t35_m2.json": "37ecff67bc1f7899b95f81c5587eb826602c1053b6777d76076bb891742161df", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t35_m3.json": "e53a422eff2bb2961ea396f071ea040a71d921e348a35bcb2d7e54d0952b3c23", + "results/bci_v2_calibrated_confirmation/bci_v2_calibrated_confirm_t35_m4.json": "4d9d35cb6d9bc30d240c85a0a5887c7d983e81acdb4a94b613bc633a11ea3178", + "results/bci_v2_calibrated_confirmation_gate.json": "3b161c32727a2a7c4b50ca696dafff20a023d23e8cd008a0b8dddd662516b084" + }, + "statistics": { + "challenge_fraction_mean": 0.5009375, + "critic_expectedness_lower": 0.2813635909438583, + "critic_expectedness_mean": 0.3187244219033087, + "decoder_corr_mean": 0.1208991158963185, + "fixed_role_gap_mean": 0.9997395833333333, + "intact_final_mean": 1.0, + "learning_gain_mean": 0.9880208333333333, + "outcome_lesion_drop_lower": 0.3886365638440749, + "outcome_lesion_drop_mean": 0.40001482185266496, + "positive_sign_count": 30, + "raw_residual_corr_gap_mean": 0.935791327739437, + "residual_soma_corr_mean": 0.06308767535907349, + "role_cosine_mean": 0.9761252363522848, + "sign_inversion_mean": 0.04271187342053094, + "surrounding_accuracy_lower": 0.5425667337998379, + "surrounding_accuracy_mean": 0.5436850460987417, + "terminal_accuracy_lower": 0.9968020433207192, + "terminal_accuracy_mean": 0.9983265604220595, + "terminal_outcome_lesion_accuracy_mean": 0.583741356708507, + "terminal_previous_soma_accuracy_mean": 0.7350079225783795, + "terminal_separation_mean": 0.4116997088030089, + "velocity_advantage_mean": 0.6383611285557892 + }, + "strict": true, + "task_seeds": [ + 30, + 31, + 32, + 33, + 34, + 35 + ] +} |
