File size: 5,211 Bytes
47709ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env python3
"""CUDA static, gradient, and dequantization checks for QH032."""

from __future__ import annotations

import json
import sys
from datetime import datetime, timezone
from pathlib import Path

import torch


PROJECT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(PROJECT / "code/src"))
from quantum_qwen38.qh032_pauli_observable_replacement import (  # noqa: E402
    DequantizedPauliObservableCore,
    EqualParameterClassicalObservableCore,
    ExactPauliObservableCore,
    QH032Config,
    qh032_parameter_audit,
)


def relative(a: torch.Tensor, b: torch.Tensor) -> float:
    return float((a - b).float().norm() / b.float().norm().clamp_min(1.0e-12))


def main() -> None:
    if not torch.cuda.is_available():
        raise RuntimeError("QH032 static validation requires CUDA")
    torch.manual_seed(20260849)
    device = torch.device("cuda:0")
    config = QH032Config(hidden_size=32, output_size=16, rank=16, layer_indices=(0, 1), num_qubits=4, observable_offsets=(1, 2))
    qh = ExactPauliObservableCore(config).to(device)
    dq = DequantizedPauliObservableCore(config).to(device)
    cc = EqualParameterClassicalObservableCore(config).to(device)
    no_ent = ExactPauliObservableCore(config, use_entanglers=False).to(device)
    if {module.parameter_count for module in (qh, dq, cc, no_ent)} != {32}:
        raise AssertionError("small-core parameter counts are not equal")

    identity_input = torch.randn(3, 5, config.rank, device=device, requires_grad=True)
    identity_error = float((qh(identity_input) - identity_input).float().abs().max())
    if identity_error > 1.0e-7:
        raise AssertionError(f"zero-alpha QH032 is not identity: {identity_error}")

    with torch.no_grad():
        qh.theta.uniform_(-0.25, 0.25)
        qh.alpha.uniform_(-0.08, 0.08)
        dq.theta.copy_(qh.theta)
        dq.alpha.copy_(qh.alpha)
    xq = torch.randn(2, 3, config.rank, device=device, requires_grad=True)
    xd = xq.detach().clone().requires_grad_(True)
    yq, yd = qh(xq), dq(xd)
    probe = torch.randn_like(yq)
    (yq * probe).sum().backward()
    (yd * probe).sum().backward()
    checks = {
        "forward_max_abs": float((yq - yd).float().abs().max()),
        "forward_relative_l2": relative(yq, yd),
        "input_gradient_max_abs": float((xq.grad - xd.grad).float().abs().max()),
        "input_gradient_relative_l2": relative(xq.grad, xd.grad),
        "theta_gradient_max_abs": float((qh.theta.grad - dq.theta.grad).abs().max()),
        "theta_gradient_relative_l2": relative(qh.theta.grad, dq.theta.grad),
        "alpha_gradient_max_abs": float((qh.alpha.grad - dq.alpha.grad).abs().max()),
        "alpha_gradient_relative_l2": relative(qh.alpha.grad, dq.alpha.grad),
    }
    if checks["forward_max_abs"] > 2.0e-5 or checks["input_gradient_max_abs"] > 2.0e-5:
        raise AssertionError(f"QH/DQ mismatch: {checks}")
    if checks["theta_gradient_max_abs"] > 3.0e-4 or checks["alpha_gradient_max_abs"] > 3.0e-4:
        raise AssertionError(f"QH/DQ gradient mismatch: {checks}")

    gradient_audit = {}
    for name, module in (("qh", qh), ("dq", dq), ("cc", cc), ("no_ent", no_ent)):
        module.zero_grad(set_to_none=True)
        with torch.no_grad():
            module.theta.uniform_(-0.2, 0.2)
            module.alpha.uniform_(-0.1, 0.1)
        value = torch.randn(4, config.rank, device=device)
        module(value).float().square().mean().backward()
        gradient_audit[name] = {
            "theta_norm": float(module.theta.grad.norm()),
            "alpha_norm": float(module.alpha.grad.norm()),
            "all_finite": bool(torch.isfinite(module.theta.grad).all() and torch.isfinite(module.alpha.grad).all()),
        }
        if gradient_audit[name]["theta_norm"] == 0 or gradient_audit[name]["alpha_norm"] == 0 or not gradient_audit[name]["all_finite"]:
            raise AssertionError(f"invalid {name} gradients")

    cpu_rejected = False
    try:
        ExactPauliObservableCore(config)(torch.randn(1, config.rank))
    except RuntimeError:
        cpu_rejected = True
    if not cpu_rejected:
        raise AssertionError("CPU exact-quantum path was not rejected")
    full_audit = qh032_parameter_audit(QH032Config())
    if full_audit["trainable_parameters"] != 82 or full_audit["net_parameter_reduction"] != 3145646:
        raise AssertionError(f"full parameter audit changed: {full_audit}")
    payload = {
        "status": "pass",
        "candidate": "QH-032 Pauli-observable nonlinear shared-basis replacement",
        "small_config": config.__dict__,
        "small_parameter_count_per_core": qh.parameter_count,
        "zero_alpha_identity_max_abs": identity_error,
        "dequantization_checks": checks,
        "gradient_audit": gradient_audit,
        "cpu_quantum_path_rejected": cpu_rejected,
        "full_parameter_audit": full_audit,
        "simulator_calls": int(qh.circuit_calls.item()),
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    output = PROJECT / "artifacts/qh032-static-validation.json"
    output.write_text(json.dumps(payload, indent=2), encoding="utf-8")
    print(json.dumps(payload, indent=2))


if __name__ == "__main__":
    main()