diff options
| -rw-r--r-- | experiments/plot_digital_additive_transfer.py | 325 | ||||
| -rw-r--r-- | results/digital_additive_transfer.csv | 19 | ||||
| -rw-r--r-- | results/digital_additive_transfer.json | 194 | ||||
| -rw-r--r-- | results/figs/figure_digital_additive_transfer.pdf | bin | 0 -> 17919 bytes | |||
| -rw-r--r-- | results/figs/figure_digital_additive_transfer.png | bin | 0 -> 157768 bytes | |||
| -rw-r--r-- | results/figs/figure_digital_additive_transfer.svg | 964 | ||||
| -rw-r--r-- | visual-composer/digital-additive-transfer.md | 33 | ||||
| -rw-r--r-- | visual-composer/qa-ledger.md | 14 |
8 files changed, 1549 insertions, 0 deletions
diff --git a/experiments/plot_digital_additive_transfer.py b/experiments/plot_digital_additive_transfer.py new file mode 100644 index 0000000..5e12a11 --- /dev/null +++ b/experiments/plot_digital_additive_transfer.py @@ -0,0 +1,325 @@ +#!/usr/bin/env python3 +"""Plot SDIL as an additive correction across four digital learners.""" + +from __future__ import annotations + +import argparse +import csv +import json +from pathlib import Path + +import matplotlib as mpl +import matplotlib.pyplot as plt +import numpy as np + + +COLORS = { + "clean": "#222222", + "noise": "#CC79A7", + "raw": "#D55E00", + "constant": "#777777", + "sdil": "#0072B2", + "oracle": "#009E73", +} + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument( + "--dualprop", type=Path, + default=Path("results/contrastive_bias/c1_gate.json")) + parser.add_argument( + "--ep", type=Path, + default=Path("results/ep_bias/c1_gate.json")) + parser.add_argument( + "--clln", type=Path, + default=Path("results/coupled_ladder/p2_confirm_side4.json")) + parser.add_argument( + "--overclamp", type=Path, + default=Path("results/coupled_ladder/p3_overclamp_side4.json")) + parser.add_argument( + "--output-analysis", type=Path, + default=Path("results/digital_additive_transfer.json")) + parser.add_argument( + "--output-csv", type=Path, + default=Path("results/digital_additive_transfer.csv")) + parser.add_argument( + "--output-figure", type=Path, + default=Path("results/figs/figure_digital_additive_transfer")) + parser.add_argument("--bootstrap-replicates", type=int, default=20000) + parser.add_argument("--bootstrap-seed", type=int, default=20260829) + return parser.parse_args() + + +def summarize_values( + values: np.ndarray, + rng: np.random.Generator, + replicates: int, +) -> dict: + values = np.asarray(values, dtype=float) + samples = rng.integers(0, len(values), size=(replicates, len(values))) + means = np.mean(values[samples], axis=1) + return { + "mean_accuracy_percent": float(np.mean(values)), + "bootstrap_95ci_percent": [ + float(value) for value in np.percentile(means, (2.5, 97.5)) + ], + "independent_units": len(values), + } + + +def task_cluster_accuracies(report: dict, method: str) -> np.ndarray: + tasks = sorted({record["task_index"] for record in report["records"]}) + return np.asarray([ + 100.0 * np.mean([ + 1.0 - record["methods"][method]["classification_error"] + for record in report["records"] + if record["task_index"] == task + ]) + for task in tasks + ]) + + +def gap_recovered(methods: dict) -> float: + clean = methods["clean"]["mean_accuracy_percent"] + raw = methods["raw"]["mean_accuracy_percent"] + sdil = methods["sdil"]["mean_accuracy_percent"] + return float(100.0 * (sdil - raw) / (clean - raw)) + + +def build_analysis( + dualprop: dict, + ep: dict, + clln: dict, + overclamp: dict, + *, + replicates: int, + seed: int, +) -> dict: + rng = np.random.default_rng(seed) + dp_rows = dualprop["rows"] + ep_rows = ep["rows"] + panels = { + "dualprop": { + "title": "Dual Propagation · CIFAR-10", + "unit": "seed", + "methods": { + "clean": summarize_values(np.asarray([ + row["same_path_clean"] for row in dp_rows]), rng, replicates), + "raw": summarize_values(np.asarray([ + row["raw"] for row in dp_rows]), rng, replicates), + "sdil": summarize_values(np.asarray([ + row["innovation"] for row in dp_rows]), rng, replicates), + "oracle": summarize_values(np.asarray([ + row["oracle"] for row in dp_rows]), rng, replicates), + }, + }, + "ep": { + "title": "Equilibrium Propagation · FashionMNIST", + "unit": "seed", + "methods": { + "clean": summarize_values(100.0 * np.asarray([ + row["clean"] for row in ep_rows]), rng, replicates), + "noise": summarize_values(100.0 * np.asarray([ + row["same_rms_noise"] for row in ep_rows]), rng, replicates), + "raw": summarize_values(100.0 * np.asarray([ + row["raw"] for row in ep_rows]), rng, replicates), + "constant": summarize_values(100.0 * np.asarray([ + row["constant"] for row in ep_rows]), rng, replicates), + "sdil": summarize_values(100.0 * np.asarray([ + row["innovation"] for row in ep_rows]), rng, replicates), + "oracle": summarize_values(100.0 * np.asarray([ + row["oracle"] for row in ep_rows]), rng, replicates), + }, + }, + "clln": { + "title": "Coupled learning · 32 edges", + "unit": "task; device draws averaged within task", + "methods": { + method: summarize_values( + task_cluster_accuracies(clln, source), rng, replicates) + for method, source in ( + ("clean", "clean"), + ("noise", "matched_noise"), + ("raw", "raw"), + ("constant", "constant"), + ("sdil", "sdil"), + ) + }, + }, + "overclamp": { + "title": "Overclamped coupled learning · 32 edges", + "unit": "task; device draws averaged within task", + "methods": { + method: summarize_values( + task_cluster_accuracies(overclamp, source), rng, replicates) + for method, source in ( + ("clean", "overclamp_clean"), + ("raw", "overclamp"), + ("sdil", "overclamp_sdil"), + ) + }, + }, + } + for panel in panels.values(): + panel["raw_to_clean_gap_recovered_percent"] = gap_recovered( + panel["methods"]) + return { + "analysis": "digital_additive_sdil_transfer", + "confirmatory_sources": { + "dualprop": dualprop["gate"] == "pass", + "ep": ep["gate"] == "pass", + "clln": bool(clln["confirmatory"]), + "overclamp": bool(overclamp["confirmatory"]), + }, + "bootstrap": { + "replicates": replicates, + "seed": seed, + "interval": "percentile 95%", + }, + "panels": panels, + } + + +def write_csv(path: Path, analysis: dict) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", newline="") as stream: + writer = csv.writer(stream) + writer.writerow(( + "panel", "method", "mean_accuracy_percent", "ci_low", "ci_high", + "independent_unit", "independent_units", "gap_recovered_percent", + )) + for panel_name, panel in analysis["panels"].items(): + for method, summary in panel["methods"].items(): + writer.writerow(( + panel_name, + method, + summary["mean_accuracy_percent"], + *summary["bootstrap_95ci_percent"], + panel["unit"], + summary["independent_units"], + panel["raw_to_clean_gap_recovered_percent"], + )) + + +def plot(path: Path, analysis: dict) -> None: + mpl.rcParams.update({ + "font.family": "DejaVu Sans", + "font.size": 8.5, + "axes.labelsize": 9, + "axes.titlesize": 9.5, + "xtick.labelsize": 7.8, + "ytick.labelsize": 8, + "axes.spines.top": False, + "axes.spines.right": False, + "svg.fonttype": "none", + "pdf.fonttype": 42, + "figure.facecolor": "white", + "axes.facecolor": "white", + }) + order = ("dualprop", "ep", "clln", "overclamp") + figure, axes = plt.subplots(2, 2, figsize=(8.0, 5.8), sharey=True) + for index, (axis, panel_name) in enumerate(zip(axes.ravel(), order)): + panel = analysis["panels"][panel_name] + methods = list(panel["methods"]) + summaries = [panel["methods"][method] for method in methods] + means = np.asarray([ + summary["mean_accuracy_percent"] for summary in summaries]) + intervals = np.asarray([ + summary["bootstrap_95ci_percent"] for summary in summaries]) + positions = np.arange(len(methods)) + axis.bar( + positions, + means, + color=[COLORS[method] for method in methods], + width=0.72, + edgecolor="white", + linewidth=0.4, + ) + axis.errorbar( + positions, + means, + yerr=np.vstack(( + means - intervals[:, 0], intervals[:, 1] - means, + )), + fmt="none", + ecolor="#222222", + elinewidth=0.8, + capsize=2.2, + ) + labels = { + "clean": "Clean", "noise": "Same-RMS\nnoise", "raw": "Raw", + "constant": "Static\ncalibration", "sdil": "SDIL", + "oracle": "Oracle", + } + axis.set_xticks(positions, [labels[method] for method in methods]) + axis.set_ylim(0.0, 106.0) + axis.grid(axis="y", color="#D9D9D9", linewidth=0.55, alpha=0.8) + axis.tick_params(length=3) + letter = chr(ord("a") + index) + recovery = panel["raw_to_clean_gap_recovered_percent"] + axis.set_title( + f"({letter}) {panel['title']}\n{recovery:.0f}% of clean gap recovered") + if index % 2 == 0: + axis.set_ylabel("Task accuracy (%)") + figure.text( + 0.995, + 0.005, + "Dual Prop/EP: 5 seeds; coupled learners: 40 tasks × 3 device draws", + ha="right", + va="bottom", + fontsize=7, + color="#666666", + ) + figure.tight_layout(rect=(0.0, 0.035, 1.0, 1.0), h_pad=2.1, w_pad=1.8) + path.parent.mkdir(parents=True, exist_ok=True) + figure.savefig(path.with_suffix(".svg"), bbox_inches="tight") + figure.savefig(path.with_suffix(".pdf"), bbox_inches="tight") + figure.savefig(path.with_suffix(".png"), dpi=240, bbox_inches="tight") + plt.close(figure) + + +def main() -> None: + args = parse_args() + reports = { + name: json.loads(path.read_text()) + for name, path in ( + ("dualprop", args.dualprop), + ("ep", args.ep), + ("clln", args.clln), + ("overclamp", args.overclamp), + ) + } + analysis = build_analysis( + **reports, + replicates=args.bootstrap_replicates, + seed=args.bootstrap_seed, + ) + analysis["sources"] = { + "dualprop": str(args.dualprop), + "ep": str(args.ep), + "clln": str(args.clln), + "overclamp": str(args.overclamp), + } + args.output_analysis.parent.mkdir(parents=True, exist_ok=True) + args.output_analysis.write_text(json.dumps(analysis, indent=2) + "\n") + write_csv(args.output_csv, analysis) + plot(args.output_figure, analysis) + print(json.dumps({ + name: { + "gap_recovered_percent": panel[ + "raw_to_clean_gap_recovered_percent"], + "methods": { + method: summary["mean_accuracy_percent"] + for method, summary in panel["methods"].items() + }, + } + for name, panel in analysis["panels"].items() + }, indent=2)) + print(f"wrote {args.output_analysis}") + print(f"wrote {args.output_csv}") + print(f"wrote {args.output_figure}.svg/.pdf/.png") + + +if __name__ == "__main__": + main() diff --git a/results/digital_additive_transfer.csv b/results/digital_additive_transfer.csv new file mode 100644 index 0000000..92b019c --- /dev/null +++ b/results/digital_additive_transfer.csv @@ -0,0 +1,19 @@ +panel,method,mean_accuracy_percent,ci_low,ci_high,independent_unit,independent_units,gap_recovered_percent
+dualprop,clean,82.85999908447266,82.56399993896484,83.07999725341797,seed,5,100.08168001179783
+dualprop,raw,9.399999618530273,9.399999618530273,9.399999618530273,seed,5,100.08168001179783
+dualprop,sdil,82.92000122070313,82.6280014038086,83.23600158691406,seed,5,100.08168001179783
+dualprop,oracle,82.96000061035156,82.52799682617187,83.34400329589843,seed,5,100.08168001179783
+ep,clean,76.26,73.55,78.53,seed,5,96.12299465240643
+ep,noise,75.44,71.01,78.76,seed,5,96.12299465240643
+ep,raw,31.379999999999995,18.059999999999995,46.08,seed,5,96.12299465240643
+ep,constant,67.9,60.42,74.46674999999942,seed,5,96.12299465240643
+ep,sdil,74.52000000000001,72.51,76.25999999999999,seed,5,96.12299465240643
+ep,oracle,75.55999999999999,70.6,78.66999999999999,seed,5,96.12299465240643
+clln,clean,100.0,100.0,100.0,task; device draws averaged within task,40,100.0
+clln,noise,99.27083333333334,98.4375,99.89583333333334,task; device draws averaged within task,40,100.0
+clln,raw,65.3125,61.14583333333333,69.375,task; device draws averaged within task,40,100.0
+clln,constant,93.85416666666666,90.41666666666667,96.875,task; device draws averaged within task,40,100.0
+clln,sdil,100.0,100.0,100.0,task; device draws averaged within task,40,100.0
+overclamp,clean,91.875,87.8125,95.3125,task; device draws averaged within task,40,100.41666666666663
+overclamp,raw,66.875,61.25,72.70833333333333,task; device draws averaged within task,40,100.41666666666663
+overclamp,sdil,91.97916666666666,88.125,95.3125,task; device draws averaged within task,40,100.41666666666663
diff --git a/results/digital_additive_transfer.json b/results/digital_additive_transfer.json new file mode 100644 index 0000000..ccb06f8 --- /dev/null +++ b/results/digital_additive_transfer.json @@ -0,0 +1,194 @@ +{ + "analysis": "digital_additive_sdil_transfer", + "confirmatory_sources": { + "dualprop": true, + "ep": false, + "clln": true, + "overclamp": true + }, + "bootstrap": { + "replicates": 20000, + "seed": 20260829, + "interval": "percentile 95%" + }, + "panels": { + "dualprop": { + "title": "Dual Propagation \u00b7 CIFAR-10", + "unit": "seed", + "methods": { + "clean": { + "mean_accuracy_percent": 82.85999908447266, + "bootstrap_95ci_percent": [ + 82.56399993896484, + 83.07999725341797 + ], + "independent_units": 5 + }, + "raw": { + "mean_accuracy_percent": 9.399999618530273, + "bootstrap_95ci_percent": [ + 9.399999618530273, + 9.399999618530273 + ], + "independent_units": 5 + }, + "sdil": { + "mean_accuracy_percent": 82.92000122070313, + "bootstrap_95ci_percent": [ + 82.6280014038086, + 83.23600158691406 + ], + "independent_units": 5 + }, + "oracle": { + "mean_accuracy_percent": 82.96000061035156, + "bootstrap_95ci_percent": [ + 82.52799682617187, + 83.34400329589843 + ], + "independent_units": 5 + } + }, + "raw_to_clean_gap_recovered_percent": 100.08168001179783 + }, + "ep": { + "title": "Equilibrium Propagation \u00b7 FashionMNIST", + "unit": "seed", + "methods": { + "clean": { + "mean_accuracy_percent": 76.26, + "bootstrap_95ci_percent": [ + 73.55, + 78.53 + ], + "independent_units": 5 + }, + "noise": { + "mean_accuracy_percent": 75.44, + "bootstrap_95ci_percent": [ + 71.01, + 78.76 + ], + "independent_units": 5 + }, + "raw": { + "mean_accuracy_percent": 31.379999999999995, + "bootstrap_95ci_percent": [ + 18.059999999999995, + 46.08 + ], + "independent_units": 5 + }, + "constant": { + "mean_accuracy_percent": 67.9, + "bootstrap_95ci_percent": [ + 60.42, + 74.46674999999942 + ], + "independent_units": 5 + }, + "sdil": { + "mean_accuracy_percent": 74.52000000000001, + "bootstrap_95ci_percent": [ + 72.51, + 76.25999999999999 + ], + "independent_units": 5 + }, + "oracle": { + "mean_accuracy_percent": 75.55999999999999, + "bootstrap_95ci_percent": [ + 70.6, + 78.66999999999999 + ], + "independent_units": 5 + } + }, + "raw_to_clean_gap_recovered_percent": 96.12299465240643 + }, + "clln": { + "title": "Coupled learning \u00b7 32 edges", + "unit": "task; device draws averaged within task", + "methods": { + "clean": { + "mean_accuracy_percent": 100.0, + "bootstrap_95ci_percent": [ + 100.0, + 100.0 + ], + "independent_units": 40 + }, + "noise": { + "mean_accuracy_percent": 99.27083333333334, + "bootstrap_95ci_percent": [ + 98.4375, + 99.89583333333334 + ], + "independent_units": 40 + }, + "raw": { + "mean_accuracy_percent": 65.3125, + "bootstrap_95ci_percent": [ + 61.14583333333333, + 69.375 + ], + "independent_units": 40 + }, + "constant": { + "mean_accuracy_percent": 93.85416666666666, + "bootstrap_95ci_percent": [ + 90.41666666666667, + 96.875 + ], + "independent_units": 40 + }, + "sdil": { + "mean_accuracy_percent": 100.0, + "bootstrap_95ci_percent": [ + 100.0, + 100.0 + ], + "independent_units": 40 + } + }, + "raw_to_clean_gap_recovered_percent": 100.0 + }, + "overclamp": { + "title": "Overclamped coupled learning \u00b7 32 edges", + "unit": "task; device draws averaged within task", + "methods": { + "clean": { + "mean_accuracy_percent": 91.875, + "bootstrap_95ci_percent": [ + 87.8125, + 95.3125 + ], + "independent_units": 40 + }, + "raw": { + "mean_accuracy_percent": 66.875, + "bootstrap_95ci_percent": [ + 61.25, + 72.70833333333333 + ], + "independent_units": 40 + }, + "sdil": { + "mean_accuracy_percent": 91.97916666666666, + "bootstrap_95ci_percent": [ + 88.125, + 95.3125 + ], + "independent_units": 40 + } + }, + "raw_to_clean_gap_recovered_percent": 100.41666666666663 + } + }, + "sources": { + "dualprop": "results/contrastive_bias/c1_gate.json", + "ep": "results/ep_bias/c1_gate.json", + "clln": "results/coupled_ladder/p2_confirm_side4.json", + "overclamp": "results/coupled_ladder/p3_overclamp_side4.json" + } +} diff --git a/results/figs/figure_digital_additive_transfer.pdf b/results/figs/figure_digital_additive_transfer.pdf Binary files differnew file mode 100644 index 0000000..4070813 --- /dev/null +++ b/results/figs/figure_digital_additive_transfer.pdf diff --git a/results/figs/figure_digital_additive_transfer.png b/results/figs/figure_digital_additive_transfer.png Binary files differnew file mode 100644 index 0000000..78046ca --- /dev/null +++ b/results/figs/figure_digital_additive_transfer.png diff --git a/results/figs/figure_digital_additive_transfer.svg b/results/figs/figure_digital_additive_transfer.svg new file mode 100644 index 0000000..014aeb9 --- /dev/null +++ b/results/figs/figure_digital_additive_transfer.svg @@ -0,0 +1,964 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="577.840313pt" height="420.588437pt" viewBox="0 0 577.840313 420.588437" xmlns="http://www.w3.org/2000/svg" version="1.1"> + <metadata> + <rdf:RDF xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> + <cc:Work> + <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> + <dc:date>2026-08-29T18:42:31.692423</dc:date> + <dc:format>image/svg+xml</dc:format> + <dc:creator> + <cc:Agent> + <dc:title>Matplotlib v3.10.8, https://matplotlib.org/</dc:title> + </cc:Agent> + </dc:creator> + </cc:Work> + </rdf:RDF> + </metadata> + <defs> + <style type="text/css">*{stroke-linejoin: round; stroke-linecap: butt}</style> + </defs> + <g id="figure_1"> + <g id="patch_1"> + <path d="M 0 420.588437 +L 577.840313 420.588437 +L 577.840313 -0 +L 0 -0 +z +" style="fill: #ffffff"/> + </g> + <g id="axes_1"> + <g id="patch_2"> + <path d="M 41.680312 168.391437 +L 293.860312 168.391437 +L 293.860312 31.056437 +L 41.680312 31.056437 +z +" style="fill: #ffffff"/> + </g> + <g id="patch_3"> + <path d="M 53.14304 168.391437 +L 97.514887 168.391437 +L 97.514887 61.036928 +L 53.14304 61.036928 +z +" clip-path="url(#p7944c5556f)" style="fill: #222222; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_4"> + <path d="M 114.770606 168.391437 +L 159.142453 168.391437 +L 159.142453 156.212674 +L 114.770606 156.212674 +z +" clip-path="url(#p7944c5556f)" style="fill: #d55e00; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_5"> + <path d="M 176.398172 168.391437 +L 220.770019 168.391437 +L 220.770019 60.959189 +L 176.398172 60.959189 +z +" clip-path="url(#p7944c5556f)" style="fill: #0072b2; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_6"> + <path d="M 238.025738 168.391437 +L 282.397585 168.391437 +L 282.397585 60.907365 +L 238.025738 60.907365 +z +" clip-path="url(#p7944c5556f)" style="fill: #009e73; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="matplotlib.axis_1"> + <g id="xtick_1"> + <g id="line2d_1"> + <defs> + <path id="m278102d266" d="M 0 0 +L 0 3 +" style="stroke: #000000; stroke-width: 0.8"/> + </defs> + <g> + <use xlink:href="#m278102d266" x="75.328964" y="168.391437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_1"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="75.328964" y="180.818219" transform="rotate(-0 75.328964 180.818219)">Clean</text> + </g> + </g> + <g id="xtick_2"> + <g id="line2d_2"> + <g> + <use xlink:href="#m278102d266" x="136.95653" y="168.391437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_2"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="136.95653" y="180.818219" transform="rotate(-0 136.95653 180.818219)">Raw</text> + </g> + </g> + <g id="xtick_3"> + <g id="line2d_3"> + <g> + <use xlink:href="#m278102d266" x="198.584095" y="168.391437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_3"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="198.584095" y="180.818219" transform="rotate(-0 198.584095 180.818219)">SDIL</text> + </g> + </g> + <g id="xtick_4"> + <g id="line2d_4"> + <g> + <use xlink:href="#m278102d266" x="260.211661" y="168.391437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_4"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="260.211661" y="180.818219" transform="rotate(-0 260.211661 180.818219)">Oracle</text> + </g> + </g> + </g> + <g id="matplotlib.axis_2"> + <g id="ytick_1"> + <g id="line2d_5"> + <path d="M 41.680312 168.391437 +L 293.860312 168.391437 +" clip-path="url(#p7944c5556f)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_6"> + <defs> + <path id="m33223f5472" d="M 0 0 +L -3 0 +" style="stroke: #000000; stroke-width: 0.8"/> + </defs> + <g> + <use xlink:href="#m33223f5472" x="41.680312" y="168.391437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_5"> + <text style="font-size: 8px; font-family: 'DejaVu Sans'; text-anchor: end" x="35.180312" y="171.430812" transform="rotate(-0 35.180312 171.430812)">0</text> + </g> + </g> + <g id="ytick_2"> + <g id="line2d_7"> + <path d="M 41.680312 142.479173 +L 293.860312 142.479173 +" clip-path="url(#p7944c5556f)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_8"> + <g> + <use xlink:href="#m33223f5472" x="41.680312" y="142.479173" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_6"> + <text style="font-size: 8px; font-family: 'DejaVu Sans'; text-anchor: end" x="35.180312" y="145.518548" transform="rotate(-0 35.180312 145.518548)">20</text> + </g> + </g> + <g id="ytick_3"> + <g id="line2d_9"> + <path d="M 41.680312 116.566909 +L 293.860312 116.566909 +" clip-path="url(#p7944c5556f)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_10"> + <g> + <use xlink:href="#m33223f5472" x="41.680312" y="116.566909" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_7"> + <text style="font-size: 8px; font-family: 'DejaVu Sans'; text-anchor: end" x="35.180312" y="119.606284" transform="rotate(-0 35.180312 119.606284)">40</text> + </g> + </g> + <g id="ytick_4"> + <g id="line2d_11"> + <path d="M 41.680312 90.654645 +L 293.860312 90.654645 +" clip-path="url(#p7944c5556f)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_12"> + <g> + <use xlink:href="#m33223f5472" x="41.680312" y="90.654645" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_8"> + <text style="font-size: 8px; font-family: 'DejaVu Sans'; text-anchor: end" x="35.180312" y="93.69402" transform="rotate(-0 35.180312 93.69402)">60</text> + </g> + </g> + <g id="ytick_5"> + <g id="line2d_13"> + <path d="M 41.680312 64.742381 +L 293.860312 64.742381 +" clip-path="url(#p7944c5556f)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_14"> + <g> + <use xlink:href="#m33223f5472" x="41.680312" y="64.742381" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_9"> + <text style="font-size: 8px; font-family: 'DejaVu Sans'; text-anchor: end" x="35.180312" y="67.781756" transform="rotate(-0 35.180312 67.781756)">80</text> + </g> + </g> + <g id="ytick_6"> + <g id="line2d_15"> + <path d="M 41.680312 38.830117 +L 293.860312 38.830117 +" clip-path="url(#p7944c5556f)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_16"> + <g> + <use xlink:href="#m33223f5472" x="41.680312" y="38.830117" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_10"> + <text style="font-size: 8px; font-family: 'DejaVu Sans'; text-anchor: end" x="35.180312" y="41.869492" transform="rotate(-0 35.180312 41.869492)">100</text> + </g> + </g> + <g id="text_11"> + <text style="font-size: 9px; font-family: 'DejaVu Sans'; text-anchor: middle" x="14.038594" y="99.723937" transform="rotate(-90 14.038594 99.723937)">Task accuracy (%)</text> + </g> + </g> + <g id="LineCollection_1"> + <path d="M 75.328964 61.420429 +L 75.328964 60.751896 +" clip-path="url(#p7944c5556f)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 136.95653 156.212674 +L 136.95653 156.212674 +" clip-path="url(#p7944c5556f)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 198.584095 61.337508 +L 198.584095 60.549775 +" clip-path="url(#p7944c5556f)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 260.211661 61.467075 +L 260.211661 60.409846 +" clip-path="url(#p7944c5556f)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + </g> + <g id="line2d_17"> + <defs> + <path id="m23b9465fd3" d="M 2.2 0 +L -2.2 -0 +" style="stroke: #222222"/> + </defs> + <g clip-path="url(#p7944c5556f)"> + <use xlink:href="#m23b9465fd3" x="75.328964" y="61.420429" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="136.95653" y="156.212674" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="198.584095" y="61.337508" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="260.211661" y="61.467075" style="fill: #1f77b4; stroke: #222222"/> + </g> + </g> + <g id="line2d_18"> + <g clip-path="url(#p7944c5556f)"> + <use xlink:href="#m23b9465fd3" x="75.328964" y="60.751896" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="136.95653" y="156.212674" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="198.584095" y="60.549775" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="260.211661" y="60.409846" style="fill: #1f77b4; stroke: #222222"/> + </g> + </g> + <g id="patch_7"> + <path d="M 41.680312 168.391437 +L 41.680312 31.056437 +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> + </g> + <g id="patch_8"> + <path d="M 41.680312 168.391437 +L 293.860312 168.391437 +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> + </g> + <g id="text_12"> + <text style="font-size: 9.5px; font-family: 'DejaVu Sans'" transform="translate(93.087695 14.418516)">(a) Dual Propagation · CIFAR-10</text> + <text style="font-size: 9.5px; font-family: 'DejaVu Sans'" transform="translate(98.051445 25.056437)">100% of clean gap recovered</text> + </g> + </g> + <g id="axes_2"> + <g id="patch_9"> + <path d="M 312.160312 168.391437 +L 564.340312 168.391437 +L 564.340312 31.056437 +L 312.160312 31.056437 +z +" style="fill: #ffffff"/> + </g> + <g id="patch_10"> + <path d="M 323.62304 168.391437 +L 352.480255 168.391437 +L 352.480255 69.587974 +L 323.62304 69.587974 +z +" clip-path="url(#p23da3bf74f)" style="fill: #222222; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_11"> + <path d="M 363.702506 168.391437 +L 392.559721 168.391437 +L 392.559721 70.650377 +L 363.702506 70.650377 +z +" clip-path="url(#p23da3bf74f)" style="fill: #cc79a7; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_12"> + <path d="M 403.781972 168.391437 +L 432.639187 168.391437 +L 432.639187 127.735095 +L 403.781972 127.735095 +z +" clip-path="url(#p23da3bf74f)" style="fill: #d55e00; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_13"> + <path d="M 443.861438 168.391437 +L 472.718653 168.391437 +L 472.718653 80.419301 +L 443.861438 80.419301 +z +" clip-path="url(#p23da3bf74f)" style="fill: #777777; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_14"> + <path d="M 483.940904 168.391437 +L 512.798119 168.391437 +L 512.798119 71.842341 +L 483.940904 71.842341 +z +" clip-path="url(#p23da3bf74f)" style="fill: #0072b2; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_15"> + <path d="M 524.02037 168.391437 +L 552.877585 168.391437 +L 552.877585 70.494904 +L 524.02037 70.494904 +z +" clip-path="url(#p23da3bf74f)" style="fill: #009e73; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="matplotlib.axis_3"> + <g id="xtick_5"> + <g id="line2d_19"> + <g> + <use xlink:href="#m278102d266" x="338.051648" y="168.391437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_13"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="338.051648" y="180.818219" transform="rotate(-0 338.051648 180.818219)">Clean</text> + </g> + </g> + <g id="xtick_6"> + <g id="line2d_20"> + <g> + <use xlink:href="#m278102d266" x="378.131114" y="168.391437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_14"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'" transform="translate(357.108895 180.818219)">Same-RMS</text> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'" transform="translate(367.758332 189.552512)">noise</text> + </g> + </g> + <g id="xtick_7"> + <g id="line2d_21"> + <g> + <use xlink:href="#m278102d266" x="418.21058" y="168.391437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_15"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="418.21058" y="180.818219" transform="rotate(-0 418.21058 180.818219)">Raw</text> + </g> + </g> + <g id="xtick_8"> + <g id="line2d_22"> + <g> + <use xlink:href="#m278102d266" x="458.290045" y="168.391437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_16"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'" transform="translate(447.138483 180.818219)">Static</text> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'" transform="translate(437.649295 189.552512)">calibration</text> + </g> + </g> + <g id="xtick_9"> + <g id="line2d_23"> + <g> + <use xlink:href="#m278102d266" x="498.369511" y="168.391437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_17"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="498.369511" y="180.818219" transform="rotate(-0 498.369511 180.818219)">SDIL</text> + </g> + </g> + <g id="xtick_10"> + <g id="line2d_24"> + <g> + <use xlink:href="#m278102d266" x="538.448977" y="168.391437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_18"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="538.448977" y="180.818219" transform="rotate(-0 538.448977 180.818219)">Oracle</text> + </g> + </g> + </g> + <g id="matplotlib.axis_4"> + <g id="ytick_7"> + <g id="line2d_25"> + <path d="M 312.160312 168.391437 +L 564.340312 168.391437 +" clip-path="url(#p23da3bf74f)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_26"> + <g> + <use xlink:href="#m33223f5472" x="312.160312" y="168.391437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + </g> + <g id="ytick_8"> + <g id="line2d_27"> + <path d="M 312.160312 142.479173 +L 564.340312 142.479173 +" clip-path="url(#p23da3bf74f)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_28"> + <g> + <use xlink:href="#m33223f5472" x="312.160312" y="142.479173" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + </g> + <g id="ytick_9"> + <g id="line2d_29"> + <path d="M 312.160312 116.566909 +L 564.340312 116.566909 +" clip-path="url(#p23da3bf74f)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_30"> + <g> + <use xlink:href="#m33223f5472" x="312.160312" y="116.566909" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + </g> + <g id="ytick_10"> + <g id="line2d_31"> + <path d="M 312.160312 90.654645 +L 564.340312 90.654645 +" clip-path="url(#p23da3bf74f)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_32"> + <g> + <use xlink:href="#m33223f5472" x="312.160312" y="90.654645" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + </g> + <g id="ytick_11"> + <g id="line2d_33"> + <path d="M 312.160312 64.742381 +L 564.340312 64.742381 +" clip-path="url(#p23da3bf74f)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_34"> + <g> + <use xlink:href="#m33223f5472" x="312.160312" y="64.742381" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + </g> + <g id="ytick_12"> + <g id="line2d_35"> + <path d="M 312.160312 38.830117 +L 564.340312 38.830117 +" clip-path="url(#p23da3bf74f)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_36"> + <g> + <use xlink:href="#m33223f5472" x="312.160312" y="38.830117" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + </g> + </g> + <g id="LineCollection_2"> + <path d="M 338.051648 73.099086 +L 338.051648 66.646932 +" clip-path="url(#p23da3bf74f)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 378.131114 76.389944 +L 378.131114 66.348941 +" clip-path="url(#p23da3bf74f)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 418.21058 144.992663 +L 418.21058 108.689581 +" clip-path="url(#p23da3bf74f)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 458.290045 90.110487 +L 458.290045 71.911333 +" clip-path="url(#p23da3bf74f)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 498.369511 74.446524 +L 498.369511 69.587974 +" clip-path="url(#p23da3bf74f)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 538.448977 76.921145 +L 538.448977 66.465546 +" clip-path="url(#p23da3bf74f)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + </g> + <g id="line2d_37"> + <g clip-path="url(#p23da3bf74f)"> + <use xlink:href="#m23b9465fd3" x="338.051648" y="73.099086" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="378.131114" y="76.389944" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="418.21058" y="144.992663" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="458.290045" y="90.110487" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="498.369511" y="74.446524" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="538.448977" y="76.921145" style="fill: #1f77b4; stroke: #222222"/> + </g> + </g> + <g id="line2d_38"> + <g clip-path="url(#p23da3bf74f)"> + <use xlink:href="#m23b9465fd3" x="338.051648" y="66.646932" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="378.131114" y="66.348941" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="418.21058" y="108.689581" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="458.290045" y="71.911333" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="498.369511" y="69.587974" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="538.448977" y="66.465546" style="fill: #1f77b4; stroke: #222222"/> + </g> + </g> + <g id="patch_16"> + <path d="M 312.160312 168.391437 +L 312.160312 31.056437 +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> + </g> + <g id="patch_17"> + <path d="M 312.160312 168.391437 +L 564.340312 168.391437 +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> + </g> + <g id="text_19"> + <text style="font-size: 9.5px; font-family: 'DejaVu Sans'" transform="translate(335.684453 14.418516)">(b) Equilibrium Propagation · FashionMNIST</text> + <text style="font-size: 9.5px; font-family: 'DejaVu Sans'" transform="translate(371.553633 25.056437)">96% of clean gap recovered</text> + </g> + </g> + <g id="axes_3"> + <g id="patch_18"> + <path d="M 41.680312 369.628437 +L 293.860312 369.628437 +L 293.860312 232.293437 +L 41.680312 232.293437 +z +" style="fill: #ffffff"/> + </g> + <g id="patch_19"> + <path d="M 53.14304 369.628437 +L 88.114072 369.628437 +L 88.114072 240.067117 +L 53.14304 240.067117 +z +" clip-path="url(#p8d4a35fc37)" style="fill: #222222; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_20"> + <path d="M 101.713918 369.628437 +L 136.68495 369.628437 +L 136.68495 241.011835 +L 101.713918 241.011835 +z +" clip-path="url(#p8d4a35fc37)" style="fill: #cc79a7; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_21"> + <path d="M 150.284796 369.628437 +L 185.255829 369.628437 +L 185.255829 285.0087 +L 150.284796 285.0087 +z +" clip-path="url(#p8d4a35fc37)" style="fill: #d55e00; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_22"> + <path d="M 198.855675 369.628437 +L 233.826707 369.628437 +L 233.826707 248.02974 +L 198.855675 248.02974 +z +" clip-path="url(#p8d4a35fc37)" style="fill: #777777; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_23"> + <path d="M 247.426553 369.628437 +L 282.397585 369.628437 +L 282.397585 240.067117 +L 247.426553 240.067117 +z +" clip-path="url(#p8d4a35fc37)" style="fill: #0072b2; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="matplotlib.axis_5"> + <g id="xtick_11"> + <g id="line2d_39"> + <g> + <use xlink:href="#m278102d266" x="70.628556" y="369.628437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_20"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="70.628556" y="382.055219" transform="rotate(-0 70.628556 382.055219)">Clean</text> + </g> + </g> + <g id="xtick_12"> + <g id="line2d_40"> + <g> + <use xlink:href="#m278102d266" x="119.199434" y="369.628437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_21"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'" transform="translate(98.177215 382.055219)">Same-RMS</text> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'" transform="translate(108.826653 390.789512)">noise</text> + </g> + </g> + <g id="xtick_13"> + <g id="line2d_41"> + <g> + <use xlink:href="#m278102d266" x="167.770312" y="369.628437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_22"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="167.770312" y="382.055219" transform="rotate(-0 167.770312 382.055219)">Raw</text> + </g> + </g> + <g id="xtick_14"> + <g id="line2d_42"> + <g> + <use xlink:href="#m278102d266" x="216.341191" y="369.628437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_23"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'" transform="translate(205.189628 382.055219)">Static</text> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'" transform="translate(195.700441 390.789512)">calibration</text> + </g> + </g> + <g id="xtick_15"> + <g id="line2d_43"> + <g> + <use xlink:href="#m278102d266" x="264.912069" y="369.628437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_24"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="264.912069" y="382.055219" transform="rotate(-0 264.912069 382.055219)">SDIL</text> + </g> + </g> + </g> + <g id="matplotlib.axis_6"> + <g id="ytick_13"> + <g id="line2d_44"> + <path d="M 41.680312 369.628437 +L 293.860312 369.628437 +" clip-path="url(#p8d4a35fc37)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_45"> + <g> + <use xlink:href="#m33223f5472" x="41.680312" y="369.628437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_25"> + <text style="font-size: 8px; font-family: 'DejaVu Sans'; text-anchor: end" x="35.180312" y="372.667812" transform="rotate(-0 35.180312 372.667812)">0</text> + </g> + </g> + <g id="ytick_14"> + <g id="line2d_46"> + <path d="M 41.680312 343.716173 +L 293.860312 343.716173 +" clip-path="url(#p8d4a35fc37)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_47"> + <g> + <use xlink:href="#m33223f5472" x="41.680312" y="343.716173" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_26"> + <text style="font-size: 8px; font-family: 'DejaVu Sans'; text-anchor: end" x="35.180312" y="346.755548" transform="rotate(-0 35.180312 346.755548)">20</text> + </g> + </g> + <g id="ytick_15"> + <g id="line2d_48"> + <path d="M 41.680312 317.803909 +L 293.860312 317.803909 +" clip-path="url(#p8d4a35fc37)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_49"> + <g> + <use xlink:href="#m33223f5472" x="41.680312" y="317.803909" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_27"> + <text style="font-size: 8px; font-family: 'DejaVu Sans'; text-anchor: end" x="35.180312" y="320.843284" transform="rotate(-0 35.180312 320.843284)">40</text> + </g> + </g> + <g id="ytick_16"> + <g id="line2d_50"> + <path d="M 41.680312 291.891645 +L 293.860312 291.891645 +" clip-path="url(#p8d4a35fc37)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_51"> + <g> + <use xlink:href="#m33223f5472" x="41.680312" y="291.891645" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_28"> + <text style="font-size: 8px; font-family: 'DejaVu Sans'; text-anchor: end" x="35.180312" y="294.93102" transform="rotate(-0 35.180312 294.93102)">60</text> + </g> + </g> + <g id="ytick_17"> + <g id="line2d_52"> + <path d="M 41.680312 265.979381 +L 293.860312 265.979381 +" clip-path="url(#p8d4a35fc37)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_53"> + <g> + <use xlink:href="#m33223f5472" x="41.680312" y="265.979381" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_29"> + <text style="font-size: 8px; font-family: 'DejaVu Sans'; text-anchor: end" x="35.180312" y="269.018756" transform="rotate(-0 35.180312 269.018756)">80</text> + </g> + </g> + <g id="ytick_18"> + <g id="line2d_54"> + <path d="M 41.680312 240.067117 +L 293.860312 240.067117 +" clip-path="url(#p8d4a35fc37)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_55"> + <g> + <use xlink:href="#m33223f5472" x="41.680312" y="240.067117" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_30"> + <text style="font-size: 8px; font-family: 'DejaVu Sans'; text-anchor: end" x="35.180312" y="243.106492" transform="rotate(-0 35.180312 243.106492)">100</text> + </g> + </g> + <g id="text_31"> + <text style="font-size: 9px; font-family: 'DejaVu Sans'; text-anchor: middle" x="14.038594" y="300.960937" transform="rotate(-90 14.038594 300.960937)">Task accuracy (%)</text> + </g> + </g> + <g id="LineCollection_3"> + <path d="M 70.628556 240.067117 +L 70.628556 240.067117 +" clip-path="url(#p8d4a35fc37)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 119.199434 242.091512 +L 119.199434 240.202076 +" clip-path="url(#p8d4a35fc37)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 167.770312 290.407088 +L 167.770312 279.745271 +" clip-path="url(#p8d4a35fc37)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 216.341191 252.48341 +L 216.341191 244.115908 +" clip-path="url(#p8d4a35fc37)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 264.912069 240.067117 +L 264.912069 240.067117 +" clip-path="url(#p8d4a35fc37)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + </g> + <g id="line2d_56"> + <g clip-path="url(#p8d4a35fc37)"> + <use xlink:href="#m23b9465fd3" x="70.628556" y="240.067117" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="119.199434" y="242.091512" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="167.770312" y="290.407088" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="216.341191" y="252.48341" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="264.912069" y="240.067117" style="fill: #1f77b4; stroke: #222222"/> + </g> + </g> + <g id="line2d_57"> + <g clip-path="url(#p8d4a35fc37)"> + <use xlink:href="#m23b9465fd3" x="70.628556" y="240.067117" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="119.199434" y="240.202076" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="167.770312" y="279.745271" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="216.341191" y="244.115908" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="264.912069" y="240.067117" style="fill: #1f77b4; stroke: #222222"/> + </g> + </g> + <g id="patch_24"> + <path d="M 41.680312 369.628437 +L 41.680312 232.293437 +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> + </g> + <g id="patch_25"> + <path d="M 41.680313 369.628437 +L 293.860312 369.628437 +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> + </g> + <g id="text_32"> + <text style="font-size: 9.5px; font-family: 'DejaVu Sans'" transform="translate(93.113672 215.655516)">(c) Coupled learning · 32 edges</text> + <text style="font-size: 9.5px; font-family: 'DejaVu Sans'" transform="translate(98.051445 226.293437)">100% of clean gap recovered</text> + </g> + </g> + <g id="axes_4"> + <g id="patch_26"> + <path d="M 312.160312 369.628437 +L 564.340312 369.628437 +L 564.340312 232.293437 +L 312.160312 232.293437 +z +" style="fill: #ffffff"/> + </g> + <g id="patch_27"> + <path d="M 323.62304 369.628437 +L 384.308067 369.628437 +L 384.308067 250.593974 +L 323.62304 250.593974 +z +" clip-path="url(#p91f9cd916a)" style="fill: #222222; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_28"> + <path d="M 407.907799 369.628437 +L 468.592826 369.628437 +L 468.592826 282.984304 +L 407.907799 282.984304 +z +" clip-path="url(#p91f9cd916a)" style="fill: #d55e00; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="patch_29"> + <path d="M 492.192558 369.628437 +L 552.877585 369.628437 +L 552.877585 250.459014 +L 492.192558 250.459014 +z +" clip-path="url(#p91f9cd916a)" style="fill: #0072b2; stroke: #ffffff; stroke-width: 0.4; stroke-linejoin: miter"/> + </g> + <g id="matplotlib.axis_7"> + <g id="xtick_16"> + <g id="line2d_58"> + <g> + <use xlink:href="#m278102d266" x="353.965553" y="369.628437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_33"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="353.965553" y="382.055219" transform="rotate(-0 353.965553 382.055219)">Clean</text> + </g> + </g> + <g id="xtick_17"> + <g id="line2d_59"> + <g> + <use xlink:href="#m278102d266" x="438.250312" y="369.628437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_34"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="438.250312" y="382.055219" transform="rotate(-0 438.250312 382.055219)">Raw</text> + </g> + </g> + <g id="xtick_18"> + <g id="line2d_60"> + <g> + <use xlink:href="#m278102d266" x="522.535072" y="369.628437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + <g id="text_35"> + <text style="font-size: 7.8px; font-family: 'DejaVu Sans'; text-anchor: middle" x="522.535072" y="382.055219" transform="rotate(-0 522.535072 382.055219)">SDIL</text> + </g> + </g> + </g> + <g id="matplotlib.axis_8"> + <g id="ytick_19"> + <g id="line2d_61"> + <path d="M 312.160312 369.628437 +L 564.340312 369.628437 +" clip-path="url(#p91f9cd916a)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_62"> + <g> + <use xlink:href="#m33223f5472" x="312.160312" y="369.628437" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + </g> + <g id="ytick_20"> + <g id="line2d_63"> + <path d="M 312.160312 343.716173 +L 564.340312 343.716173 +" clip-path="url(#p91f9cd916a)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_64"> + <g> + <use xlink:href="#m33223f5472" x="312.160312" y="343.716173" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + </g> + <g id="ytick_21"> + <g id="line2d_65"> + <path d="M 312.160312 317.803909 +L 564.340312 317.803909 +" clip-path="url(#p91f9cd916a)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_66"> + <g> + <use xlink:href="#m33223f5472" x="312.160312" y="317.803909" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + </g> + <g id="ytick_22"> + <g id="line2d_67"> + <path d="M 312.160312 291.891645 +L 564.340312 291.891645 +" clip-path="url(#p91f9cd916a)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_68"> + <g> + <use xlink:href="#m33223f5472" x="312.160312" y="291.891645" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + </g> + <g id="ytick_23"> + <g id="line2d_69"> + <path d="M 312.160312 265.979381 +L 564.340312 265.979381 +" clip-path="url(#p91f9cd916a)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_70"> + <g> + <use xlink:href="#m33223f5472" x="312.160312" y="265.979381" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + </g> + <g id="ytick_24"> + <g id="line2d_71"> + <path d="M 312.160312 240.067117 +L 564.340312 240.067117 +" clip-path="url(#p91f9cd916a)" style="fill: none; stroke: #d9d9d9; stroke-opacity: 0.8; stroke-width: 0.55; stroke-linecap: square"/> + </g> + <g id="line2d_72"> + <g> + <use xlink:href="#m33223f5472" x="312.160312" y="240.067117" style="stroke: #000000; stroke-width: 0.8"/> + </g> + </g> + </g> + </g> + <g id="LineCollection_4"> + <path d="M 353.965553 255.857403 +L 353.965553 246.140304 +" clip-path="url(#p91f9cd916a)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 438.250312 290.272129 +L 438.250312 275.426561 +" clip-path="url(#p91f9cd916a)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + <path d="M 522.535072 255.452524 +L 522.535072 246.140304 +" clip-path="url(#p91f9cd916a)" style="fill: none; stroke: #222222; stroke-width: 0.8"/> + </g> + <g id="line2d_73"> + <g clip-path="url(#p91f9cd916a)"> + <use xlink:href="#m23b9465fd3" x="353.965553" y="255.857403" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="438.250312" y="290.272129" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="522.535072" y="255.452524" style="fill: #1f77b4; stroke: #222222"/> + </g> + </g> + <g id="line2d_74"> + <g clip-path="url(#p91f9cd916a)"> + <use xlink:href="#m23b9465fd3" x="353.965553" y="246.140304" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="438.250312" y="275.426561" style="fill: #1f77b4; stroke: #222222"/> + <use xlink:href="#m23b9465fd3" x="522.535072" y="246.140304" style="fill: #1f77b4; stroke: #222222"/> + </g> + </g> + <g id="patch_30"> + <path d="M 312.160312 369.628437 +L 312.160312 232.293437 +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> + </g> + <g id="patch_31"> + <path d="M 312.160312 369.628437 +L 564.340312 369.628437 +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> + </g> + <g id="text_36"> + <text style="font-size: 9.5px; font-family: 'DejaVu Sans'" transform="translate(330.643516 215.655516)">(d) Overclamped coupled learning · 32 edges</text> + <text style="font-size: 9.5px; font-family: 'DejaVu Sans'" transform="translate(368.531445 226.293437)">100% of clean gap recovered</text> + </g> + </g> + <g id="text_37"> + <text style="font-size: 7px; font-family: 'DejaVu Sans'; text-anchor: end; fill: #666666" x="570.640313" y="411.932656" transform="rotate(-0 570.640313 411.932656)">Dual Prop/EP: 5 seeds; coupled learners: 40 tasks × 3 device draws</text> + </g> + </g> + <defs> + <clipPath id="p7944c5556f"> + <rect x="41.680312" y="31.056437" width="252.18" height="137.335"/> + </clipPath> + <clipPath id="p23da3bf74f"> + <rect x="312.160312" y="31.056437" width="252.18" height="137.335"/> + </clipPath> + <clipPath id="p8d4a35fc37"> + <rect x="41.680312" y="232.293437" width="252.18" height="137.335"/> + </clipPath> + <clipPath id="p91f9cd916a"> + <rect x="312.160312" y="232.293437" width="252.18" height="137.335"/> + </clipPath> + </defs> +</svg> diff --git a/visual-composer/digital-additive-transfer.md b/visual-composer/digital-additive-transfer.md new file mode 100644 index 0000000..74867f8 --- /dev/null +++ b/visual-composer/digital-additive-transfer.md @@ -0,0 +1,33 @@ +# Visual contract: additive digital transfer + +- **Artifact:** four-panel quantitative result figure. +- **Target venue / format:** ICLR two-column paper, full-width figure. +- **Core claim:** the same local instruction-off subtraction improves four + digital local-learning backbones under matched teaching-channel + imperfection. +- **Reviewer question:** is SDIL a correction that transfers across learning + rules, or does it work only in one custom network? +- **Evidence layer:** main digital transfer result. +- **Source data:** + `results/contrastive_bias/c1_gate.json`, + `results/ep_bias/c1_gate.json`, + `results/coupled_ladder/p2_confirm_side4.json`, and + `results/coupled_ladder/p3_overclamp_side4.json`. +- **Statistics / uncertainty:** Dual Propagation and EP resample five seeds; + CLLN panels average three device draws within each of 40 tasks and resample + tasks. Error bars are percentile 95% bootstrap intervals. +- **Figure prototype:** coordinated 2-by-2 bar-chart small multiples. +- **Panel map:** author-code Dual Propagation, author-code EP, digital coupled + learning, and digital overclamped coupled learning. +- **Exact label inventory:** clean, same-RMS noise, raw, static calibration, + SDIL, oracle, task accuracy, clean gap recovered. +- **Caption role:** define raw-to-clean gap recovery within each panel and + state that datasets and absolute clean levels differ across panels. +- **Manuscript placement:** Part 1, after the algorithm definition. +- **Output formats:** editable SVG, vector PDF, PNG preview, analysis JSON, and + source CSV. +- **Traceability:** every bar is regenerated by + `experiments/plot_digital_additive_transfer.py` from the four JSON sources. +- **Constraint:** the EP five-seed result beats raw in every seed and recovers + 96% of the mean clean gap, while its stricter preregistered gate failed. The + manuscript and caption must retain that distinction. diff --git a/visual-composer/qa-ledger.md b/visual-composer/qa-ledger.md index c9e66e5..f601f93 100644 --- a/visual-composer/qa-ledger.md +++ b/visual-composer/qa-ledger.md @@ -26,3 +26,17 @@ changing the plot grammar. Rendered inspection: no clipped labels, tick-label collision, legend overlap, or panel overlap at 2,560-by-765 PNG resolution. SVG text remains editable and the PDF uses embedded TrueType fonts. + +## Additive digital transfer figure + +| Issue | Artifact | Severity | Fix | Status | +|:--|:--|:--|:--|:--| +| Different datasets invite invalid absolute comparisons | All panels | High | Used separate titled panels and defined recovery relative to each panel's own raw and clean endpoints | Resolved | +| CLLN device draws are not independent tasks | Panels (c) and (d) | High | Averaged device draws within task before task-level bootstrap | Resolved | +| EP result could be mistaken for a passed strict gate | Panel (b) | High | Stored gate status in analysis and required the caption/manifest to report the partial-gate boundary | Resolved | +| Long calibration labels could collide | Panels (b) and (c) | Medium | Used two-line labels and inspected the full-resolution render | Resolved | +| Color-only distinctions could fail in print | All panels | Low | Every bar has a direct method label | Resolved | + +Rendered inspection: no clipped labels, title collision, error-bar clipping, +or panel overlap at 1,920-by-1,392 PNG resolution. SVG text remains editable +and the PDF uses embedded TrueType fonts. |
