Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
calibration_workload_matrix_validation.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 """Validation: Phase 3 planner-calibration workload-matrix surface.
3 
4 Builds the full candidate-by-workload inventory and records stable workload
5 provenance for the mandatory continuity, microcase, and structured workload
6 classes.
7 
8 Run with:
9  python benchmarks/density_matrix/planner_calibration/calibration_workload_matrix_validation.py
10 """
11 
12 from __future__ import annotations
13 
14 import argparse
15 import json
16 import sys
17 from pathlib import Path
18 
19 REPO_ROOT = Path(__file__).resolve().parents[3]
20 if str(REPO_ROOT) not in sys.path:
21  sys.path.insert(0, str(REPO_ROOT))
22 
23 from benchmarks.density_matrix.planner_calibration.common import (
24  PLANNER_CALIBRATION_CANDIDATE_SCHEMA_VERSION,
25  PLANNER_CALIBRATION_SUPPORTED_CANDIDATE_PARTITION_QUBITS,
26 )
27 from benchmarks.density_matrix.planner_calibration.case_selection import (
28  PLANNER_CALIBRATION_CASE_KIND_CONTINUITY,
29  PLANNER_CALIBRATION_CASE_KIND_MICROCASE,
30  PLANNER_CALIBRATION_CASE_KIND_STRUCTURED,
31  PLANNER_CALIBRATION_CONTINUITY_QUBITS,
32  iter_planner_calibration_candidate_cases,
33 )
34 from benchmarks.density_matrix.planner_surface.common import build_software_metadata
35 from benchmarks.density_matrix.planner_surface.workloads import (
36  MANDATORY_NOISE_PATTERNS,
37  STRUCTURED_FAMILY_NAMES,
38  STRUCTURED_QUBITS,
39  mandatory_microcase_definitions,
40 )
41 
42 SUITE_NAME = "phase3_planner_calibration_workload_matrix"
43 ARTIFACT_FILENAME = "calibration_workload_matrix_bundle.json"
44 DEFAULT_OUTPUT_DIR = (
45  REPO_ROOT
46  / "benchmarks"
47  / "density_matrix"
48  / "artifacts"
49  / "planner_calibration"
50  / "calibration_workload_matrix"
51 )
52 ARTIFACT_CORE_FIELDS = (
53  "suite_name",
54  "status",
55  "candidate_schema_version",
56  "software",
57  "summary",
58  "cases",
59 )
60 
61 
62 def _case_from_descriptor(metadata: dict, descriptor_set) -> dict:
63  payload = descriptor_set.to_dict()
64  return {
65  "candidate_id": metadata["candidate_id"],
66  "planner_family": metadata["planner_family"],
67  "planner_variant": metadata["planner_variant"],
68  "max_partition_qubits": metadata["max_partition_qubits"],
69  "case_kind": metadata["case_kind"],
70  "source_type": payload["source_type"],
71  "workload_id": payload["workload_id"],
72  "qbit_num": payload["qbit_num"],
73  "family_name": metadata["family_name"],
74  "noise_pattern": metadata["noise_pattern"],
75  "seed": metadata["seed"],
76  "planning_time_ms": metadata["planning_time_ms"],
77  "partition_count": payload["partition_count"],
78  "descriptor_member_count": payload["descriptor_member_count"],
79  "max_partition_span": payload["max_partition_span"],
80  "partition_member_counts": payload["partition_member_counts"],
81  "workload_matrix_pass": (
82  metadata["max_partition_qubits"] in PLANNER_CALIBRATION_SUPPORTED_CANDIDATE_PARTITION_QUBITS
83  and payload["partition_count"] > 0
84  and payload["workload_id"] == metadata["workload_id"]
85  ),
86  }
87 
88 
89 def build_cases() -> list[dict]:
90  return [
91  _case_from_descriptor(metadata, descriptor_set)
92  for metadata, descriptor_set, _, _ in iter_planner_calibration_candidate_cases()
93  ]
94 
95 
96 def build_artifact_bundle(cases: list[dict]) -> dict:
97  candidate_ids = sorted({case["candidate_id"] for case in cases})
98  continuity_cases = [
99  case for case in cases if case["case_kind"] == PLANNER_CALIBRATION_CASE_KIND_CONTINUITY
100  ]
101  microcase_cases = [case for case in cases if case["case_kind"] == PLANNER_CALIBRATION_CASE_KIND_MICROCASE]
102  structured_cases = [
103  case for case in cases if case["case_kind"] == PLANNER_CALIBRATION_CASE_KIND_STRUCTURED
104  ]
105  microcase_workload_ids = {
106  definition["case_name"] for definition in mandatory_microcase_definitions()
107  }
108  expected_structured_combinations = {
109  (family_name, qbit_num, noise_pattern)
110  for family_name in STRUCTURED_FAMILY_NAMES
111  for qbit_num in STRUCTURED_QUBITS
112  for noise_pattern in MANDATORY_NOISE_PATTERNS
113  }
114  observed_structured_combinations = {
115  (case["family_name"], case["qbit_num"], case["noise_pattern"])
116  for case in structured_cases
117  }
118  workload_matrix_passes = sum(case["workload_matrix_pass"] for case in cases)
119  bundle = {
120  "suite_name": SUITE_NAME,
121  "status": "pass"
122  if workload_matrix_passes == len(cases)
123  and {case["qbit_num"] for case in continuity_cases} == set(PLANNER_CALIBRATION_CONTINUITY_QUBITS)
124  and {case["workload_id"] for case in microcase_cases} == microcase_workload_ids
125  and observed_structured_combinations == expected_structured_combinations
126  else "fail",
127  "candidate_schema_version": PLANNER_CALIBRATION_CANDIDATE_SCHEMA_VERSION,
128  "software": build_software_metadata(),
129  "summary": {
130  "total_cases": len(cases),
131  "workload_matrix_passes": workload_matrix_passes,
132  "candidate_ids": candidate_ids,
133  "continuity_cases": len(continuity_cases),
134  "microcases": len(microcase_cases),
135  "structured_cases": len(structured_cases),
136  "continuity_qubits": sorted({case["qbit_num"] for case in continuity_cases}),
137  "microcase_workload_ids": sorted({case["workload_id"] for case in microcase_cases}),
138  "structured_family_names": sorted(
139  {case["family_name"] for case in structured_cases}
140  ),
141  "structured_noise_patterns": sorted(
142  {case["noise_pattern"] for case in structured_cases}
143  ),
144  },
145  "cases": cases,
146  }
147  missing = [field for field in ARTIFACT_CORE_FIELDS if field not in bundle]
148  if missing:
149  raise ValueError(
150  "Calibration workload-matrix bundle missing required fields: {}".format(
151  ", ".join(missing)
152  )
153  )
154  return bundle
155 
156 
157 def write_artifact_bundle(bundle: dict, output_dir: Path = DEFAULT_OUTPUT_DIR) -> Path:
158  output_dir.mkdir(parents=True, exist_ok=True)
159  output_path = output_dir / ARTIFACT_FILENAME
160  output_path.write_text(json.dumps(bundle, indent=2, sort_keys=True) + "\n")
161  return output_path
162 
163 
164 def main(argv: list[str] | None = None) -> int:
165  parser = argparse.ArgumentParser(description=__doc__)
166  parser.add_argument(
167  "--output-dir",
168  type=Path,
169  default=DEFAULT_OUTPUT_DIR,
170  help="Directory to write the calibration workload-matrix bundle into.",
171  )
172  parser.add_argument(
173  "--quiet",
174  action="store_true",
175  help="Suppress per-case console output.",
176  )
177  args = parser.parse_args(argv)
178 
179  cases = build_cases()
180  bundle = build_artifact_bundle(cases)
181  output_path = write_artifact_bundle(bundle, output_dir=args.output_dir)
182 
183  if not args.quiet:
184  print(
185  "cases={total_cases}, continuity={continuity_cases}, microcases={microcases}, structured={structured_cases}".format(
186  **bundle["summary"]
187  )
188  )
189  print("Wrote {}".format(output_path))
190 
191  return 0 if bundle["status"] == "pass" else 1
192 
193 
194 if __name__ == "__main__":
195  raise SystemExit(main())
def build_software_metadata()