qaiji.core.program.validation 源代码

# Copyright 2026 Qaiji-IR core developer: Ye Jun <yjmaxpayne@hotmail.com>
# SPDX-License-Identifier: Apache-2.0
"""L5 程序与 L4 电路摘要之间的桥接。"""

from collections.abc import Mapping, Sequence

from qaiji.core import Circuit
from qaiji.core.program.model import ProgramIR
from qaiji.core.semantics import (
    annotate_circuit,
    build_dataflow_summary,
    build_semantic_summary,
    canonical_summary_hash,
)
from qaiji.exceptions import QaijiIRError


[文档] def compute_kernel_ref(circuit: Circuit) -> str: """用单参数固定配方计算引用,不 canonicalize,绑定 qaiji.semantic_summary.v0。 Args: circuit: 待计算引用的 L4 电路。 Returns: 带 sha256 前缀的摘要哈希引用。 """ summary = build_semantic_summary(circuit=circuit, annotations=annotate_circuit(circuit)) return canonical_summary_hash(summary)
[文档] class ProgramValidationError(QaijiIRError): """携带按判决顺序收集的全部程序问题。""" problems: tuple[str, ...] def __init__(self, problems: Sequence[str]) -> None: """保存问题并生成逐行汇总消息。 Args: problems: 先调用序、后输出声明序的问题。 """ self.problems = tuple(problems) super().__init__( f"ProgramIR failed L4 validation with {len(self.problems)} problem(s):\n" + "\n".join(f"- {problem}" for problem in self.problems) )
[文档] def validate_program(program: ProgramIR, kernels: Mapping[str, Circuit]) -> None: """认证调用并核对输出,按调用序、再输出声明序收集问题。 认证的是解析表内容,而非调用方持有的对象;未被引用的表项不校验。 被写入但未声明为输出合法,输出按寄存器名解析,继承 L4 的按名语义。 判决是调用时刻快照,之后修改电路不影响已经返回的结果。 损坏电路的 TypeError 原样传播,不转为程序问题。 Args: program: 待校验的程序。 kernels: 引用到 L4 电路的解析表。 Raises: ProgramValidationError: 引用认证或输出寄存器校验失败。 TypeError: L4 无法分类损坏电路中的节点。 """ problems: list[str] = [] authenticated: dict[int, Circuit] = {} for index, invocation in enumerate(program.quantum_invocations): ref = invocation.kernel_ref if ref not in kernels: problems.append(f"invocation {index}: kernel_ref {ref} is not in the kernel table") continue circuit = kernels[ref] actual = compute_kernel_ref(circuit) if actual != ref: problems.append(f"invocation {index}: kernel re-hashes to {actual}, not {ref}") continue authenticated[index] = circuit for output in program.result_outputs: index, name = output.invocation_index, output.register_name if index not in authenticated: continue circuit = authenticated[index] registers = [register for register in circuit.cregs if register.name == name] prefix = f"output ({index}, {name!r}):" if not registers: problems.append(f"{prefix} register is not declared by the kernel") continue if len(registers) > 1: problems.append(f"{prefix} register is declared {len(registers)} times by the kernel") continue handles = build_dataflow_summary(circuit)["measurement_handles"] written = {handle.creg_index for handle in handles if handle.creg_name == name} missing = sorted(set(range(registers[0].size)) - written) if missing: problems.append(f"{prefix} bits {missing} are never written by a measurement") if problems: raise ProgramValidationError(tuple(problems))