summaryrefslogtreecommitdiff
path: root/experiments
diff options
context:
space:
mode:
authorYurenHao0426 <Blackhao0426@gmail.com>2026-08-29 12:56:47 -0500
committerYurenHao0426 <Blackhao0426@gmail.com>2026-08-29 12:56:47 -0500
commit6c1263a0e9db21ccc13547b4251909523c9c55d9 (patch)
tree646a3d294a61860ce81bce20c50e4350dbbfb4b0 /experiments
parentf3d1f73b3c2c7b52fc861ba02aa644505cb01015 (diff)
feat: model state-dependent physical learning bias
Diffstat (limited to 'experiments')
-rw-r--r--experiments/physical_imperfection_smoke.py98
1 files changed, 98 insertions, 0 deletions
diff --git a/experiments/physical_imperfection_smoke.py b/experiments/physical_imperfection_smoke.py
new file mode 100644
index 0000000..3722c4c
--- /dev/null
+++ b/experiments/physical_imperfection_smoke.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3
+"""Mechanics checks for the Appendix-C physical imperfection model."""
+
+from __future__ import annotations
+
+from pathlib import Path
+import sys
+
+import numpy as np
+
+ROOT = Path(__file__).resolve().parents[1]
+sys.path.insert(0, str(ROOT))
+
+from sdil.physical_coupled import Circuit, Task # noqa: E402
+from sdil.physical_imperfection import ( # noqa: E402
+ DifferentialSquareLawImperfection,
+ LocalPolynomialPredictor,
+ edge_voltage_drops,
+ fit_polynomial_predictor,
+ simulate_imperfect_alternating_tasks,
+)
+
+
+def main() -> None:
+ circuit = Circuit()
+ ideal = DifferentialSquareLawImperfection.ideal()
+ output_free = 0.23
+ output_clamped = 0.26
+ assert np.array_equal(
+ ideal.observed_rate(circuit, output_free, output_clamped),
+ ideal.ideal_rate(circuit, output_free, output_clamped),
+ )
+ assert np.array_equal(
+ ideal.neutral_bias(circuit, output_free), np.zeros(2))
+
+ hardware = DifferentialSquareLawImperfection.sample_appendix_c(20260829)
+ outputs = np.linspace(circuit.low + 0.01, circuit.high - 0.01, 81)
+ local_states = np.asarray([
+ edge_voltage_drops(circuit, output) for output in outputs])
+ neutral = np.asarray([
+ hardware.neutral_bias(circuit, output) for output in outputs])
+ center = np.mean(local_states, axis=0)
+ scale = np.ptp(local_states, axis=0)
+ constant = LocalPolynomialPredictor.zeros(center, scale, degree=0)
+ quadratic = LocalPolynomialPredictor.zeros(center, scale, degree=2)
+ constant_count = fit_polynomial_predictor(
+ constant,
+ local_states,
+ neutral,
+ )
+ quadratic_count = fit_polynomial_predictor(
+ quadratic,
+ local_states,
+ neutral,
+ )
+ assert constant_count == quadratic_count
+ constant_rmse = float(np.sqrt(np.mean([
+ np.square(measurement - constant.predict(state))
+ for state, measurement in zip(local_states, neutral)
+ ])))
+ quadratic_rmse = float(np.sqrt(np.mean([
+ np.square(measurement - quadratic.predict(state))
+ for state, measurement in zip(local_states, neutral)
+ ])))
+ assert quadratic_rmse < 1e-6
+ assert constant_rmse > 1e-3
+
+ tasks = (
+ Task("alpha", circuit.high, 0.31),
+ Task("beta", circuit.low, 0.14),
+ )
+ shared = {
+ "circuit": circuit,
+ "tasks": tasks,
+ "imperfection": hardware,
+ "period_seconds": 0.01,
+ "cycles": 12,
+ "initial_gates": np.asarray((4.0, 4.0)),
+ "overclamp_nudging": 0.05,
+ "overclamp_magnitude": circuit.high,
+ }
+ oracle = simulate_imperfect_alternating_tasks(
+ method="overclamp_oracle_neutral", **shared)
+ sdil = simulate_imperfect_alternating_tasks(
+ method="overclamp_sdil", predictor=quadratic, **shared)
+ assert np.allclose(
+ oracle["final_gates"], sdil["final_gates"], atol=1e-8, rtol=0.0)
+ print({
+ "constant_neutral_rmse_v_per_s": constant_rmse,
+ "quadratic_neutral_rmse_v_per_s": quadratic_rmse,
+ "neutral_observations_each": constant_count,
+ "sdil_matches_neutral_oracle": True,
+ "autodiff_used": False,
+ })
+
+
+if __name__ == "__main__":
+ main()