def run(seed: int, steps: int | None, accelerator: str) -> tuple[dict, dict]:
source_budget = 512 if steps is None else min(steps, 512)
adapt_budget = 256 if steps is None else min(steps, 256)
lit.seed_everything(seed, workers=True)
train = list(records(rows=2048, seed=seed + 1))
test = list(records(rows=2048, seed=seed + 3))
mean = float(np.mean([row["y"] for row in train]))
tolerance = 1e-6 * float(np.std([row["y"] for row in train]))
oracle = scores(test, np.asarray([row["a"] for row in test]), mean)
source = build()
source_fit = fit(source, seed=seed, split=seed + 1, rows=2048, budget=source_budget, accelerator=accelerator)
reference = prediction(source, test)
initial = scores(test, reference, mean)
learned = initial["nrmse"] < 0.25
state = deepcopy(source.state_dict())
selected_state = deepcopy(source.nodes["record/b"].state_dict())
normalization = rf.Number.normalization(source, "record/b")
checks = {
"Source learns both-input relationship below 0.25 nRMSE": learned,
"Source optimizer covers current parameters": source_fit["optimizer_covers_current_parameters"],
}
arms = {}
selected = rf.where("address") == "record/b"
flipped = [{**row, "b": -row["b"]} for row in test]
with TemporaryDirectory(prefix="relflow-mutation-") as directory:
checkpoint = Path(directory) / "source.ckpt"
source.save(checkpoint)
for index, arm in enumerate(("deleted", "inactive", "scratch_restricted", "continuation")):
lit.seed_everything(seed + 100 + index, workers=True)
model = (
build(restricted=True).to(source.device)
if arm == "scratch_restricted"
else rf.Model.load(checkpoint).to(source.device)
)
if arm == "deleted":
model.delete(selected)
deleted_schema = model.schema.model_dump()
current = model.state_dict()
removed = [name for name in state if name.startswith("nodes.record/b.")]
changes = [
name
for name, value in state.items()
if not name.startswith("nodes.record/b.")
and (name not in current or not equal(value, current[name]))
]
checks["Deletion removes b from schema and runtime"] = (
"record/b" not in model.schema.requests and "record/b" not in model.nodes
)
checks["Deletion removes the selected state entries"] = bool(removed) and all(
name not in current for name in removed
)
checks["Deletion preserves all unselected state entries"] = not changes
elif arm == "inactive":
model.update(selected, active=False)
checks["Inactive control preserves all original state"] = equal(state, model.state_dict())
elif arm == "scratch_restricted":
checks["Scratch schema and field order match deletion"] = model.schema.model_dump() == deleted_schema
model.eval()
before = prediction(model, test)
immediate = scores(test, before, mean)
if arm == "deleted":
deleted_prediction = before.copy()
checks["Deletion immediately loses the selected information"] = (
immediate["nrmse"] > initial["nrmse"] + 0.35 and immediate["nrmse"] >= 0.9 * oracle["nrmse"]
)
elif arm == "inactive":
checks["Deletion and deactivation initially give the same predictions"] = bool(
np.allclose(deleted_prediction, before, rtol=1e-5, atol=tolerance)
)
elif arm == "continuation":
checks["Unchanged checkpoint restores source predictions"] = bool(
np.allclose(reference, before, rtol=1e-5, atol=tolerance)
)
if arm != "continuation":
checks[f"{arm} before: removed input values cannot affect predictions"] = bool(
np.allclose(before, prediction(model, test, include_b=False), rtol=1e-5, atol=tolerance)
and np.allclose(before, prediction(model, flipped), rtol=1e-5, atol=tolerance)
)
parameters = {name: p.detach().clone() for name, p in model.named_parameters()}
fitting = fit(
model, seed=seed + 200, split=seed + 11, rows=4096, budget=adapt_budget, accelerator=accelerator
)
after = prediction(model, test)
final = scores(test, after, mean)
updated = [name for name, p in model.named_parameters() if not torch.equal(parameters[name], p)]
arms[arm] = {
"before": immediate,
"after": final,
**fitting,
"updated_parameter_count": len(updated),
"pooling_capacity": model.nodes["record"].encoder.pool.mass_capacity,
}
checks[f"{arm}: optimizer covers current parameters"] = fitting["optimizer_covers_current_parameters"]
checks[f"{arm}: parameters actually learn"] = bool(updated)
checks[f"{arm}: hidden target values cannot affect predictions"] = bool(
np.allclose(after, prediction(model, test, corrupt=True), rtol=1e-5, atol=tolerance)
)
if arm == "continuation":
checks["Continuation retains full-information accuracy below 0.25 nRMSE"] = final["nrmse"] < 0.25
else:
checks[f"{arm}: adapts near the remaining-information limit"] = (
oracle["nrmse"] - 0.05 <= final["nrmse"] <= oracle["nrmse"] + 0.10
and final["only_a_distance_nrmse"] < 0.20
)
checks[f"{arm} after: removed input values cannot affect predictions"] = bool(
np.allclose(after, prediction(model, test, include_b=False), rtol=1e-5, atol=tolerance)
and np.allclose(after, prediction(model, flipped), rtol=1e-5, atol=tolerance)
)
if arm == "deleted":
arms[arm]["removed_state_entries"] = removed
arms[arm]["changed_unselected_state_entries"] = changes
path = Path(directory) / "deleted.ckpt"
model.save(path)
loaded = rf.Model.load(path).to(model.device).eval()
checks["Deleted checkpoint preserves schema and learned state"] = (
loaded.schema.model_dump() == model.schema.model_dump()
and equal(model.state_dict(), loaded.state_dict())
and "record/b" not in loaded.nodes
)
checks["Deleted checkpoint preserves adapted predictions"] = bool(
np.allclose(after, prediction(loaded, test), rtol=1e-5, atol=tolerance)
)
readded = rf.Model.load(checkpoint).to(source.device).eval()
readded.delete(selected)
lit.seed_everything(seed + 300, workers=True)
readded.extend(rf.where("address") == "record", b=rf.Number)
fresh_normalization = rf.Number.normalization(readded, "record/b")
checks["Re-adding the same name does not restore its learned state"] = not equal(
selected_state, readded.nodes["record/b"].state_dict()
)
fresh = build().to(source.device)
checks["Re-added input has fresh normalization"] = (
fresh_normalization == rf.Number.normalization(fresh, "record/b") and fresh_normalization != normalization
)
readdition = {
"scores": scores(test, prediction(readded, test), mean),
"source_normalization": normalization,
"fresh_normalization": fresh_normalization,
"source_field_order": [str(node.address) for node in source.schema.fields.fields],
"readded_field_order": [str(node.address) for node in readded.schema.fields.fields],
}
return {
"source": initial,
"source_fit": source_fit,
"source_prerequisite_met": learned,
"downstream_interpretable": learned,
"only_a_oracle": oracle,
"arms": arms,
"readdition": readdition,
"test_rows": len(test),
"optimizer_policy": "New AdamW factory and Trainer per phase; matched adaptation data and updates",
"mutation": "delete record/b; inactive control updates active=False; separate source fork deletes and re-adds b",
}, checks