File size: 5,486 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
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env python3
"""CUDA identity, gradient, DQ, and control checks for QH034."""

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.qh034_spectral_modulation_replacement import (  # noqa: E402
    DequantizedSpectralCore,
    EqualParameterClassicalSpectralCore,
    ExactQuantumSpectralCore,
    QH034Config,
    qh034_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("QH034 static validation requires CUDA")
    torch.manual_seed(20260856)
    device = torch.device("cuda:0")
    config = QH034Config(
        hidden_size=128, output_size=64, rank=64, layer_indices=(0, 1),
        num_qubits=6, depth=2, entangling_offsets=(1, 2, 3),
    )
    qh = ExactQuantumSpectralCore(config).to(device)
    dq = DequantizedSpectralCore(config).to(device)
    cc = EqualParameterClassicalSpectralCore(config).to(device)
    no_ent = ExactQuantumSpectralCore(config, use_entanglers=False).to(device)
    if {module.parameter_count for module in (qh, dq, cc, no_ent)} != {48}:
        raise AssertionError("small QH034 parameter counts differ")

    identity_input = torch.randn(3, 5, config.rank, device=device)
    identity_errors = {
        name: float((module(identity_input) - identity_input).float().abs().max())
        for name, module in (("qh", qh), ("dq", dq), ("cc", cc), ("no_ent", no_ent))
    }
    if max(identity_errors.values()) > 2.0e-7:
        raise AssertionError(f"zero-angle identity failed: {identity_errors}")

    with torch.no_grad():
        qh.theta.uniform_(-0.25, 0.25)
        dq.theta.copy_(qh.theta)
    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),
    }
    if checks["forward_max_abs"] > 2.0e-5:
        raise AssertionError(f"QH/DQ forward mismatch: {checks}")
    if checks["input_gradient_max_abs"] > 2.0e-5 or checks["theta_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)
        value = torch.randn(4, config.rank, device=device)
        module(value).float().square().mean().backward()
        gradient = module.theta.grad
        gradient_audit[name] = {
            "norm": float(gradient.norm()),
            "nonzero_elements": int((gradient != 0).sum()),
            "all_finite": bool(torch.isfinite(gradient).all()),
        }
        if gradient_audit[name]["norm"] == 0 or not gradient_audit[name]["all_finite"]:
            raise AssertionError(f"invalid {name} gradients")

    scale_audit = {}
    with torch.no_grad():
        for name, module in (("qh", qh), ("dq", dq), ("cc", cc), ("no_ent", no_ent)):
            output = module(torch.ones(1, config.rank, device=device)).float().squeeze(0)
            scale_audit[name] = {
                "minimum": float(output.min()),
                "mean": float(output.mean()),
                "maximum": float(output.max()),
            }
            if output.min() < 0 or abs(float(output.mean()) - 1.0) > 3.0e-6:
                raise AssertionError(f"invalid positive mean-one scale: {name}")

    cpu_rejected = False
    try:
        ExactQuantumSpectralCore(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 = qh034_parameter_audit(QH034Config())
    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-034 quantum shared-SVD spectral modulation",
        "small_config": config.__dict__,
        "small_parameter_count_per_core": qh.parameter_count,
        "zero_angle_identity_max_abs": identity_errors,
        "dequantization_checks": checks,
        "gradient_audit": gradient_audit,
        "positive_mean_one_scale_audit": scale_audit,
        "cpu_quantum_path_rejected": cpu_rejected,
        "full_parameter_audit": full_audit,
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    output = PROJECT / "artifacts/qh034-static-validation.json"
    output.write_text(json.dumps(payload, indent=2), encoding="utf-8")
    print(json.dumps(payload, indent=2))


if __name__ == "__main__":
    main()