Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
optional_noise_classification_validation.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 """Validation: optional-noise classification layer.
3 
4 Builds on the already passing required-noise bundles and adds explicit optional
5 whole-register depolarizing cases so reviewers can see that:
6 - required local-noise evidence remains milestone-defining,
7 - optional evidence is clearly marked optional,
8 - and optional cases do not count toward mandatory baseline completion.
9 
10 Run with:
11  python benchmarks/density_matrix/noise_support/optional_noise_classification_validation.py
12 """
13 
14 from __future__ import annotations
15 
16 import argparse
17 import json
18 from pathlib import Path
19 import sys
20 
21 import numpy as np
22 
23 REPO_ROOT = Path(__file__).resolve().parents[3]
24 if str(REPO_ROOT) not in sys.path:
25  sys.path.insert(0, str(REPO_ROOT))
26 
27 from benchmarks.density_matrix.circuits import DualBuilder
28 from benchmarks.density_matrix.noise_support.required_local_noise_validation import (
29  REQUIRED_LOCAL_NOISE_MODELS,
30  build_artifact_bundle as build_required_local_noise_bundle,
31  run_validation as run_required_local_noise_validation,
32 )
33 from benchmarks.density_matrix.noise_support.required_local_noise_micro_validation import (
34  build_artifact_bundle as build_required_local_noise_micro_bundle,
35  run_required_local_noise_micro_validation,
36 )
37 from benchmarks.density_matrix.noise_support.support_tiers import (
38  CASE_PURPOSE_OPTIONAL_REGRESSION,
39  CASE_PURPOSE_OPTIONAL_STRESS,
40  OPTIONAL_REASON_WHOLE_REGISTER_DEPOLARIZING,
41  SUPPORT_TIER_VOCABULARY,
42  build_optional_case_classification,
43  build_support_tier_summary,
44 )
45 from benchmarks.density_matrix.validate_squander_vs_qiskit import (
46  PRIMARY_BACKEND,
47  REFERENCE_BACKEND,
48  build_software_metadata,
49  build_threshold_metadata,
50  validate_microcase,
51 )
52 
53 SUITE_NAME = "optional_noise_classification"
54 ARTIFACT_FILENAME = "optional_noise_classification_bundle.json"
55 DEFAULT_OUTPUT_DIR = (
56  REPO_ROOT / "benchmarks" / "density_matrix" / "artifacts" / "noise_support"
57 )
58 ARTIFACT_CORE_FIELDS = (
59  "suite_name",
60  "status",
61  "backend",
62  "reference_backend",
63  "requirements",
64  "thresholds",
65  "software",
66  "summary",
67  "required_artifacts",
68  "cases",
69 )
70 PAULI_MATRICES = {
71  "I": np.eye(2, dtype=complex),
72  "X": np.array([[0, 1], [1, 0]], dtype=complex),
73  "Y": np.array([[0, -1j], [1j, 0]], dtype=complex),
74  "Z": np.array([[1, 0], [0, -1]], dtype=complex),
75 }
76 
77 
78 def _pauli_string_matrix(pauli_string):
79  matrix = np.array([[1.0 + 0.0j]])
80  for symbol in pauli_string:
81  matrix = np.kron(matrix, PAULI_MATRICES[symbol])
82  return matrix
83 
84 
85 def _build_hamiltonian(term_specs):
86  qbit_num = len(term_specs[0][1])
87  matrix = np.zeros((2**qbit_num, 2**qbit_num), dtype=complex)
88  for coeff, pauli_string in term_specs:
89  matrix += coeff * _pauli_string_matrix(pauli_string)
90  return matrix
91 
92 
94  return {
95  "terms": [
96  {"coeff": float(coeff), "pauli_string": pauli_string}
97  for coeff, pauli_string in term_specs
98  ]
99  }
100 
101 
103  builder = DualBuilder(1)
104  builder.U3(0, 0.61, -0.24, 0.39)
105  builder.depolarizing(0.06)
106  return builder
107 
108 
110  builder = DualBuilder(2)
111  builder.U3(0, 0.54, -0.19, 0.42)
112  builder.U3(1, 0.38, 0.27, -0.31)
113  builder.CNOT(1, 0)
114  builder.depolarizing(0.04)
115  return builder
116 
117 
119  *,
120  case_name,
121  qbit_num,
122  builder_fn,
123  required_gate_family,
124  required_noise_models,
125  case_kind,
126  purpose,
127  term_specs,
128 ):
129  return {
130  "case_name": case_name,
131  "qbit_num": qbit_num,
132  "builder_fn": builder_fn,
133  "required_gate_family": list(required_gate_family),
134  "required_noise_models": list(required_noise_models),
135  "case_kind": case_kind,
136  "purpose": purpose,
137  "hamiltonian_matrix": _build_hamiltonian(term_specs),
138  "hamiltonian_metadata": _build_hamiltonian_metadata(term_specs),
139  }
140 
141 
142 OPTIONAL_WHOLE_REGISTER_CASES = (
144  case_name="optional_noise_1q_whole_register_depolarizing_regression",
145  qbit_num=1,
146  builder_fn=build_optional_1q_u3_whole_register_depolarizing,
147  required_gate_family=["U3"],
148  required_noise_models=["depolarizing"],
149  case_kind=CASE_PURPOSE_OPTIONAL_REGRESSION,
150  purpose="Optional regression baseline using whole-register depolarizing on a 1-qubit U3 case.",
151  term_specs=[(0.32, "Z"), (-0.18, "X")],
152  ),
154  case_name="optional_noise_2q_whole_register_depolarizing_stress",
155  qbit_num=2,
156  builder_fn=build_optional_2q_u3_cnot_whole_register_depolarizing,
157  required_gate_family=["U3", "CNOT"],
158  required_noise_models=["depolarizing"],
159  case_kind=CASE_PURPOSE_OPTIONAL_STRESS,
160  purpose="Optional stress baseline using whole-register depolarizing on a 2-qubit U3/CNOT case.",
161  term_specs=[(0.41, "ZI"), (-0.23, "IZ"), (0.17, "XX")],
162  ),
163 )
164 
165 
167  return {
168  "support_tier_vocabulary": list(SUPPORT_TIER_VOCABULARY),
169  "required_local_noise_models": list(REQUIRED_LOCAL_NOISE_MODELS),
170  "optional_noise_models": ["depolarizing"],
171  "optional_case_names": [case["case_name"] for case in OPTIONAL_WHOLE_REGISTER_CASES],
172  "required_bundle_sources": [
173  "required_local_noise_validation",
174  "required_local_noise_micro_validation",
175  ],
176  "required_pass_rate": 1.0,
177  }
178 
179 
181  required_fields = (
182  "case_name",
183  "status",
184  "support_tier",
185  "case_purpose",
186  "optional_reason",
187  "counts_toward_mandatory_baseline",
188  "required_noise_models",
189  "noise_operation_sequence",
190  "whole_register_baseline_classification_pass",
191  "optional_noise_case_pass",
192  )
193  missing_fields = [field for field in required_fields if field not in case]
194  if missing_fields:
195  raise ValueError(
196  "Optional-noise classification case payload is missing required fields: {}".format(
197  ", ".join(missing_fields)
198  )
199  )
200 
201 
202 def run_optional_case(case, *, verbose=False):
203  result = dict(validate_microcase(case, verbose=verbose))
204  result.update(
206  case_purpose=case["case_kind"],
207  optional_reason=OPTIONAL_REASON_WHOLE_REGISTER_DEPOLARIZING,
208  )
209  )
210  result["whole_register_baseline_classification_pass"] = bool(
211  result["noise_operation_sequence"] == ["depolarizing"]
212  and result["required_noise_model_coverage_pass"]
213  and not result["counts_toward_mandatory_baseline"]
214  )
215  result["optional_noise_case_pass"] = bool(
216  result["status"] == "pass"
217  and result["whole_register_baseline_classification_pass"]
218  and result["support_tier"] == "optional"
219  and result["case_purpose"] in {
220  CASE_PURPOSE_OPTIONAL_REGRESSION,
221  CASE_PURPOSE_OPTIONAL_STRESS,
222  }
223  )
225  return result
226 
227 
228 def run_validation(*, verbose=False):
229  required_local_noise_results = run_required_local_noise_validation(verbose=verbose)
230  required_local_noise_bundle = build_required_local_noise_bundle(
231  required_local_noise_results
232  )
233  required_local_noise_micro_results = run_required_local_noise_micro_validation(
234  verbose=verbose
235  )
236  required_local_noise_micro_bundle = build_required_local_noise_micro_bundle(
237  required_local_noise_micro_results
238  )
239  optional_results = [
240  run_optional_case(case, verbose=verbose) for case in OPTIONAL_WHOLE_REGISTER_CASES
241  ]
242  return required_local_noise_bundle, required_local_noise_micro_bundle, optional_results
243 
244 
246  required_local_noise_bundle,
247  required_local_noise_micro_bundle,
248  optional_results,
249 ):
250  optional_results = list(optional_results)
251  required_cases = list(required_local_noise_bundle["cases"]) + list(
252  required_local_noise_micro_bundle["cases"]
253  )
254  required_summary = build_support_tier_summary(required_cases)
255  optional_summary = build_support_tier_summary(optional_results)
256 
257  bundle = {
258  "suite_name": SUITE_NAME,
259  "status": "pass"
260  if required_summary["mandatory_baseline_completed"]
261  and optional_summary["optional_cases_count_toward_mandatory_baseline"] == 0
262  and all(case["optional_noise_case_pass"] for case in optional_results)
263  else "fail",
264  "backend": PRIMARY_BACKEND,
265  "reference_backend": REFERENCE_BACKEND,
266  "requirements": build_requirement_metadata(),
267  "thresholds": build_threshold_metadata(),
268  "software": build_software_metadata(),
269  "summary": {
270  "required_cases": required_summary["required_cases"],
271  "required_passed_cases": required_summary["required_passed_cases"],
272  "required_pass_rate": required_summary["required_pass_rate"],
273  "optional_cases": optional_summary["optional_cases"],
274  "optional_passed_cases": optional_summary["optional_passed_cases"],
275  "optional_pass_rate": optional_summary["optional_pass_rate"],
276  "optional_cases_count_toward_mandatory_baseline": optional_summary[
277  "optional_cases_count_toward_mandatory_baseline"
278  ],
279  "mandatory_baseline_case_count": required_summary[
280  "mandatory_baseline_case_count"
281  ],
282  "mandatory_baseline_passed_cases": required_summary[
283  "mandatory_baseline_passed_cases"
284  ],
285  "mandatory_baseline_completed": required_summary[
286  "mandatory_baseline_completed"
287  ],
288  "support_tiers_present": sorted(
289  set(
290  required_summary["support_tiers_present"]
291  + optional_summary["support_tiers_present"]
292  )
293  ),
294  },
295  "required_artifacts": {
296  "required_local_noise_bundle": {
297  "suite_name": required_local_noise_bundle["suite_name"],
298  "status": required_local_noise_bundle["status"],
299  "summary": required_local_noise_bundle["summary"],
300  },
301  "required_local_noise_micro_bundle": {
302  "suite_name": required_local_noise_micro_bundle["suite_name"],
303  "status": required_local_noise_micro_bundle["status"],
304  "summary": required_local_noise_micro_bundle["summary"],
305  },
306  },
307  "cases": optional_results,
308  }
310  return bundle
311 
312 
314  missing_fields = [field for field in ARTIFACT_CORE_FIELDS if field not in bundle]
315  if missing_fields:
316  raise ValueError(
317  "Optional-noise classification bundle is missing required fields: {}".format(
318  ", ".join(missing_fields)
319  )
320  )
321 
322 
323 def write_artifact_bundle(output_path: Path, bundle):
325  output_path.parent.mkdir(parents=True, exist_ok=True)
326  output_path.write_text(json.dumps(bundle, indent=2, sort_keys=True) + "\n", encoding="utf-8")
327 
328 
330  parser = argparse.ArgumentParser(description=__doc__)
331  parser.add_argument(
332  "--output-dir",
333  type=Path,
334  default=DEFAULT_OUTPUT_DIR,
335  help="Directory for the optional-noise classification JSON artifact bundle.",
336  )
337  parser.add_argument(
338  "--quiet",
339  action="store_true",
340  help="Suppress per-case validation output.",
341  )
342  return parser.parse_args()
343 
344 
345 def main():
346  args = parse_args()
347  required_local_noise_bundle, required_local_noise_micro_bundle, optional_results = (
349  verbose=not args.quiet
350  )
351  )
352  bundle = build_artifact_bundle(
353  required_local_noise_bundle,
354  required_local_noise_micro_bundle,
355  optional_results,
356  )
357  output_path = args.output_dir / ARTIFACT_FILENAME
358  write_artifact_bundle(output_path, bundle)
359  print(
360  "Wrote {} with status {} (required baseline completed: {}; optional cases: {}/{})".format(
361  output_path,
362  bundle["status"],
363  bundle["summary"]["mandatory_baseline_completed"],
364  bundle["summary"]["optional_passed_cases"],
365  bundle["summary"]["optional_cases"],
366  )
367  )
368  if bundle["status"] != "pass":
369  raise SystemExit(1)
370 
371 
372 if __name__ == "__main__":
373  main()
def validate_microcase(case, verbose=True)
def _make_optional_case(case_name, qbit_num, builder_fn, required_gate_family, required_noise_models, case_kind, purpose, term_specs)
def build_support_tier_summary(cases)
def build_optional_case_classification(case_purpose, optional_reason)
def build_software_metadata()
def build_artifact_bundle(required_local_noise_bundle, required_local_noise_micro_bundle, optional_results)