Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
noise_support_publication_bundle.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 """Validation: publication-ready noise-support evidence bundle.
3 
4 Builds the top-level noise-support manifest by assembling the delivered
5 artifacts into one reproducible, machine-checkable package.
6 
7 Run with:
8  python benchmarks/density_matrix/noise_support/noise_support_publication_bundle.py
9 """
10 
11 from __future__ import annotations
12 
13 import argparse
14 import json
15 import sys
16 from pathlib import Path
17 
18 REPO_ROOT = Path(__file__).resolve().parents[3]
19 if str(REPO_ROOT) not in sys.path:
20  sys.path.insert(0, str(REPO_ROOT))
21 
22 from benchmarks.density_matrix.workflow_evidence.exact_density_vqe_validation import (
23  PRIMARY_BACKEND,
24  REFERENCE_BACKEND,
25  EXACT_REGIME_PARAMETER_SET_COUNT,
26  EXACT_REGIME_WORKFLOW_QUBITS,
27  build_software_metadata,
28  get_git_revision,
29  write_json,
30 )
31 from benchmarks.density_matrix.noise_support.required_local_noise_validation import (
32  ARTIFACT_FILENAME as REQUIRED_LOCAL_NOISE_ARTIFACT_FILENAME,
33  write_artifact_bundle as write_required_local_noise_bundle_file,
34 )
35 from benchmarks.density_matrix.noise_support.required_local_noise_micro_validation import (
36  ARTIFACT_FILENAME as REQUIRED_LOCAL_NOISE_MICRO_ARTIFACT_FILENAME,
37  write_artifact_bundle as write_required_local_noise_micro_bundle_file,
38 )
39 from benchmarks.density_matrix.noise_support.optional_noise_classification_validation import (
40  ARTIFACT_FILENAME as OPTIONAL_NOISE_CLASSIFICATION_ARTIFACT_FILENAME,
41  build_artifact_bundle as build_optional_noise_classification_bundle,
42  run_validation as run_optional_noise_classification_validation,
43  write_artifact_bundle as write_optional_noise_classification_bundle_file,
44 )
45 from benchmarks.density_matrix.noise_support.unsupported_noise_validation import (
46  ARTIFACT_FILENAME as UNSUPPORTED_NOISE_ARTIFACT_FILENAME,
47  build_artifact_bundle as build_unsupported_noise_bundle,
48  run_validation as run_unsupported_noise_validation,
49  write_artifact_bundle as write_unsupported_noise_bundle_file,
50 )
51 from benchmarks.density_matrix.noise_support.required_local_noise_workflow_validation import (
52  TRACE_ARTIFACT_FILENAME as REQUIRED_LOCAL_NOISE_TRACE_ARTIFACT_FILENAME,
53  WORKFLOW_BUNDLE_FILENAME as REQUIRED_LOCAL_NOISE_WORKFLOW_BUNDLE_FILENAME,
54  run_validation as run_required_local_noise_workflow_validation,
55  write_artifact_bundle as write_required_local_noise_workflow_bundle_file,
56 )
57 
58 SUITE_NAME = "noise_support_publication_evidence"
59 ARTIFACT_FILENAME = "noise_support_publication_bundle.json"
60 DEFAULT_OUTPUT_DIR = (
61  REPO_ROOT / "benchmarks" / "density_matrix" / "artifacts" / "noise_support"
62 )
63 BUNDLE_FIELDS = (
64  "suite_name",
65  "status",
66  "backend",
67  "reference_backend",
68  "software",
69  "provenance",
70  "summary",
71  "artifacts",
72 )
73 
74 
76  *,
77  artifact_id,
78  artifact_class,
79  mandatory,
80  path,
81  status,
82  expected_statuses,
83  purpose,
84  generation_command,
85  summary,
86 ):
87  return {
88  "artifact_id": artifact_id,
89  "artifact_class": artifact_class,
90  "mandatory": mandatory,
91  "path": path,
92  "status": status,
93  "expected_statuses": list(expected_statuses),
94  "purpose": purpose,
95  "generation_command": generation_command,
96  "summary": dict(summary),
97  }
98 
99 
100 def _load_json(path: Path):
101  return json.loads(path.read_text(encoding="utf-8"))
102 
103 
105  output_dir: Path,
106  *,
107  required_local_noise_bundle,
108  required_local_noise_micro_bundle,
109  optional_noise_classification_bundle,
110  unsupported_noise_bundle,
111  required_local_noise_workflow_bundle,
112  required_local_noise_trace_result,
113 ):
114  output_dir = Path(output_dir)
115  required_local_noise_command = (
116  f"python benchmarks/density_matrix/noise_support/required_local_noise_validation.py "
117  f"--output-dir {output_dir}"
118  )
119  required_local_noise_micro_command = (
120  f"python benchmarks/density_matrix/noise_support/required_local_noise_micro_validation.py "
121  f"--output-dir {output_dir}"
122  )
123  optional_noise_command = (
124  f"python benchmarks/density_matrix/noise_support/optional_noise_classification_validation.py "
125  f"--output-dir {output_dir}"
126  )
127  unsupported_noise_command = (
128  f"python benchmarks/density_matrix/noise_support/unsupported_noise_validation.py "
129  f"--output-dir {output_dir}"
130  )
131  required_local_noise_workflow_command = (
132  f"python benchmarks/density_matrix/noise_support/required_local_noise_workflow_validation.py "
133  f"--output-dir {output_dir}"
134  )
135  publication_bundle_command = (
136  f"python benchmarks/density_matrix/noise_support/noise_support_publication_bundle.py "
137  f"--output-dir {output_dir}"
138  )
139 
140  artifacts = [
142  artifact_id="required_local_noise_bundle",
143  artifact_class="required_positive_path_bundle",
144  mandatory=True,
145  path=REQUIRED_LOCAL_NOISE_ARTIFACT_FILENAME,
146  status=required_local_noise_bundle["status"],
147  expected_statuses=["pass"],
148  purpose="Required positive-path evidence for the three mandatory local-noise models.",
149  generation_command=required_local_noise_command,
150  summary={
151  "total_cases": required_local_noise_bundle["summary"]["total_cases"],
152  "passed_cases": required_local_noise_bundle["summary"]["passed_cases"],
153  "required_pass_rate": required_local_noise_bundle["summary"][
154  "required_pass_rate"
155  ],
156  "support_tiers_present": required_local_noise_bundle["summary"][
157  "support_tiers_present"
158  ],
159  },
160  ),
162  artifact_id="required_local_noise_micro_bundle",
163  artifact_class="required_micro_validation_bundle",
164  mandatory=True,
165  path=REQUIRED_LOCAL_NOISE_MICRO_ARTIFACT_FILENAME,
166  status=required_local_noise_micro_bundle["status"],
167  expected_statuses=["pass"],
168  purpose="Mandatory 1 to 3 qubit exact micro-validation for the required local-noise baseline.",
169  generation_command=required_local_noise_micro_command,
170  summary={
171  "total_cases": required_local_noise_micro_bundle["summary"][
172  "total_cases"
173  ],
174  "passed_cases": required_local_noise_micro_bundle["summary"][
175  "passed_cases"
176  ],
177  "required_pass_rate": required_local_noise_micro_bundle["summary"][
178  "required_pass_rate"
179  ],
180  "required_noise_models_covered": required_local_noise_micro_bundle[
181  "summary"
182  ][
183  "required_noise_models_covered"
184  ],
185  },
186  ),
188  artifact_id="optional_noise_classification_bundle",
189  artifact_class="optional_classification_bundle",
190  mandatory=True,
191  path=OPTIONAL_NOISE_CLASSIFICATION_ARTIFACT_FILENAME,
192  status=optional_noise_classification_bundle["status"],
193  expected_statuses=["pass"],
194  purpose="Optional-baseline classification that keeps whole-register depolarizing outside the mandatory baseline.",
195  generation_command=optional_noise_command,
196  summary={
197  "required_cases": optional_noise_classification_bundle["summary"][
198  "required_cases"
199  ],
200  "optional_cases": optional_noise_classification_bundle["summary"][
201  "optional_cases"
202  ],
203  "optional_pass_rate": optional_noise_classification_bundle["summary"][
204  "optional_pass_rate"
205  ],
206  "mandatory_baseline_completed": optional_noise_classification_bundle[
207  "summary"
208  ][
209  "mandatory_baseline_completed"
210  ],
211  "support_tiers_present": optional_noise_classification_bundle[
212  "summary"
213  ][
214  "support_tiers_present"
215  ],
216  },
217  ),
219  artifact_id="unsupported_noise_bundle",
220  artifact_class="unsupported_noise_bundle",
221  mandatory=True,
222  path=UNSUPPORTED_NOISE_ARTIFACT_FILENAME,
223  status=unsupported_noise_bundle["status"],
224  expected_statuses=["pass"],
225  purpose="Structured negative evidence for deferred families and invalid noise schedule/configuration requests.",
226  generation_command=unsupported_noise_command,
227  summary={
228  "total_cases": unsupported_noise_bundle["summary"]["total_cases"],
229  "deferred_cases": unsupported_noise_bundle["summary"]["deferred_cases"],
230  "unsupported_cases": unsupported_noise_bundle["summary"][
231  "unsupported_cases"
232  ],
233  "unsupported_status_cases": unsupported_noise_bundle["summary"][
234  "unsupported_status_cases"
235  ],
236  "boundary_passed_cases": unsupported_noise_bundle["summary"][
237  "boundary_passed_cases"
238  ],
239  },
240  ),
242  artifact_id="required_local_noise_workflow_bundle",
243  artifact_class="required_workflow_bundle",
244  mandatory=True,
245  path=REQUIRED_LOCAL_NOISE_WORKFLOW_BUNDLE_FILENAME,
246  status=required_local_noise_workflow_bundle["status"],
247  expected_statuses=["pass"],
248  purpose="Required-local-noise workflow sufficiency bundle across the accepted exact regime.",
249  generation_command=required_local_noise_workflow_command,
250  summary={
251  "required_cases": required_local_noise_workflow_bundle["summary"][
252  "required_cases"
253  ],
254  "required_passed_cases": required_local_noise_workflow_bundle[
255  "summary"
256  ][
257  "required_passed_cases"
258  ],
259  "required_pass_rate": required_local_noise_workflow_bundle["summary"][
260  "required_pass_rate"
261  ],
262  "mandatory_baseline_completed": required_local_noise_workflow_bundle[
263  "summary"
264  ][
265  "mandatory_baseline_completed"
266  ],
267  "unsupported_status_cases": required_local_noise_workflow_bundle[
268  "summary"
269  ][
270  "unsupported_status_cases"
271  ],
272  "required_trace_case_name": required_local_noise_workflow_bundle[
273  "summary"
274  ][
275  "required_trace_case_name"
276  ],
277  "required_trace_completed": required_local_noise_workflow_bundle[
278  "summary"
279  ][
280  "required_trace_completed"
281  ],
282  },
283  ),
285  artifact_id="required_local_noise_trace_4q",
286  artifact_class="required_workflow_trace",
287  mandatory=True,
288  path=REQUIRED_LOCAL_NOISE_TRACE_ARTIFACT_FILENAME,
289  status=required_local_noise_trace_result["status"],
290  expected_statuses=["completed"],
291  purpose="Bounded required-local-noise optimization trace for the anchor workflow.",
292  generation_command=required_local_noise_workflow_command,
293  summary={
294  "case_name": required_local_noise_trace_result["case_name"],
295  "support_tier": required_local_noise_trace_result["support_tier"],
296  "case_purpose": required_local_noise_trace_result["case_purpose"],
297  "required_validation_trace": required_local_noise_trace_result[
298  "required_validation_trace"
299  ],
300  "workflow_completed": required_local_noise_trace_result[
301  "workflow_completed"
302  ],
303  "optimizer": required_local_noise_trace_result["optimizer"],
304  "parameter_count": required_local_noise_trace_result["parameter_count"],
305  },
306  ),
307  ]
308 
309  mandatory_artifacts = [artifact for artifact in artifacts if artifact["mandatory"]]
310  present_count = 0
311  status_match_count = 0
312  for artifact in mandatory_artifacts:
313  if (output_dir / artifact["path"]).exists():
314  present_count += 1
315  if artifact["status"] in artifact["expected_statuses"]:
316  status_match_count += 1
317 
318  workflow_trace_reference_pass = (
319  required_local_noise_workflow_bundle["summary"]["required_trace_case_name"]
320  == required_local_noise_trace_result["case_name"]
321  )
322 
323  bundle_status = (
324  "pass"
325  if present_count == len(mandatory_artifacts)
326  and status_match_count == len(mandatory_artifacts)
327  and workflow_trace_reference_pass
328  else "fail"
329  )
330 
331  bundle = {
332  "suite_name": SUITE_NAME,
333  "status": bundle_status,
334  "backend": PRIMARY_BACKEND,
335  "reference_backend": REFERENCE_BACKEND,
336  "software": build_software_metadata(),
337  "provenance": {
338  "generation_command": publication_bundle_command,
339  "working_directory": str(REPO_ROOT),
340  "git_revision": get_git_revision(),
341  "conda_env_assumption": "qgd",
342  },
343  "summary": {
344  "mandatory_artifact_count": len(mandatory_artifacts),
345  "present_artifact_count": present_count,
346  "status_match_count": status_match_count,
347  "missing_artifact_count": len(mandatory_artifacts) - present_count,
348  "mismatched_status_count": len(mandatory_artifacts) - status_match_count,
349  "workflow_trace_reference_pass": workflow_trace_reference_pass,
350  },
351  "artifacts": artifacts,
352  }
354  return bundle
355 
356 
357 def validate_noise_support_publication_bundle(bundle, bundle_dir: Path):
358  missing_fields = [field for field in BUNDLE_FIELDS if field not in bundle]
359  if missing_fields:
360  raise ValueError(
361  "Noise-support publication bundle is missing required fields: {}".format(
362  ", ".join(missing_fields)
363  )
364  )
365 
366  required_ids = {
367  "required_local_noise_bundle",
368  "required_local_noise_micro_bundle",
369  "optional_noise_classification_bundle",
370  "unsupported_noise_bundle",
371  "required_local_noise_workflow_bundle",
372  "required_local_noise_trace_4q",
373  }
374  artifact_ids = {artifact["artifact_id"] for artifact in bundle["artifacts"]}
375  missing_ids = required_ids - artifact_ids
376  if missing_ids:
377  raise ValueError(
378  "Noise-support publication bundle is missing required artifact IDs: {}".format(
379  ", ".join(sorted(missing_ids))
380  )
381  )
382 
383  required_payload_fields = {
384  "required_local_noise_bundle": {
385  "suite_name",
386  "status",
387  "requirements",
388  "software",
389  "summary",
390  "cases",
391  },
392  "required_local_noise_micro_bundle": {
393  "suite_name",
394  "status",
395  "requirements",
396  "thresholds",
397  "software",
398  "summary",
399  "cases",
400  },
401  "optional_noise_classification_bundle": {
402  "suite_name",
403  "status",
404  "requirements",
405  "thresholds",
406  "software",
407  "summary",
408  "cases",
409  "required_artifacts",
410  },
411  "unsupported_noise_bundle": {
412  "suite_name",
413  "status",
414  "requirements",
415  "software",
416  "summary",
417  "cases",
418  },
419  "required_local_noise_workflow_bundle": {
420  "suite_name",
421  "status",
422  "thresholds",
423  "software",
424  "summary",
425  "cases",
426  },
427  "required_local_noise_trace_4q": {
428  "case_name",
429  "status",
430  "support_tier",
431  "case_purpose",
432  "required_validation_trace",
433  "workflow_completed",
434  "optimizer",
435  "parameter_count",
436  },
437  }
438  required_summary_fields = {
439  "required_local_noise_bundle": {
440  "total_cases",
441  "passed_cases",
442  "required_pass_rate",
443  },
444  "required_local_noise_micro_bundle": {
445  "total_cases",
446  "passed_cases",
447  "required_pass_rate",
448  "required_noise_models_covered",
449  },
450  "optional_noise_classification_bundle": {
451  "required_cases",
452  "optional_cases",
453  "optional_pass_rate",
454  "mandatory_baseline_completed",
455  },
456  "unsupported_noise_bundle": {
457  "deferred_cases",
458  "unsupported_cases",
459  "unsupported_status_cases",
460  "boundary_passed_cases",
461  },
462  "required_local_noise_workflow_bundle": {
463  "required_cases",
464  "required_passed_cases",
465  "required_pass_rate",
466  "mandatory_baseline_completed",
467  "unsupported_status_cases",
468  "required_trace_case_name",
469  "required_trace_present",
470  "required_trace_completed",
471  "required_trace_bridge_supported",
472  },
473  }
474 
475  loaded_payloads = {}
476  for artifact in bundle["artifacts"]:
477  artifact_path = bundle_dir / artifact["path"]
478  if artifact["mandatory"] and not artifact_path.exists():
479  raise ValueError(
480  "Noise-support publication bundle is missing artifact file: {}".format(
481  artifact["path"]
482  )
483  )
484  if artifact["status"] not in artifact["expected_statuses"]:
485  raise ValueError(
486  "Noise-support publication artifact {} has unexpected status {}".format(
487  artifact["artifact_id"], artifact["status"]
488  )
489  )
490 
491  payload = _load_json(artifact_path)
492  loaded_payloads[artifact["artifact_id"]] = payload
493 
494  payload_missing_fields = [
495  field
496  for field in required_payload_fields[artifact["artifact_id"]]
497  if field not in payload
498  ]
499  if payload_missing_fields:
500  raise ValueError(
501  "Artifact {} is missing required payload fields: {}".format(
502  artifact["artifact_id"], ", ".join(payload_missing_fields)
503  )
504  )
505 
506  if artifact["artifact_id"] in required_summary_fields:
507  summary_missing_fields = [
508  field
509  for field in required_summary_fields[artifact["artifact_id"]]
510  if field not in payload["summary"]
511  ]
512  if summary_missing_fields:
513  raise ValueError(
514  "Artifact {} is missing required summary fields: {}".format(
515  artifact["artifact_id"], ", ".join(summary_missing_fields)
516  )
517  )
518 
519  workflow_payload = loaded_payloads[
520  "required_local_noise_workflow_bundle"
521  ]
522  trace_payload = loaded_payloads["required_local_noise_trace_4q"]
523  if workflow_payload["summary"]["required_trace_case_name"] != trace_payload["case_name"]:
524  raise ValueError(
525  "Required-local-noise workflow bundle trace reference does not match the trace artifact"
526  )
527 
528 
529 def write_noise_support_publication_bundle(output_path: Path, bundle):
530  validate_noise_support_publication_bundle(bundle, output_path.parent)
531  output_path.parent.mkdir(parents=True, exist_ok=True)
532  output_path.write_text(
533  json.dumps(bundle, indent=2, sort_keys=True) + "\n",
534  encoding="utf-8",
535  )
536 
537 
539  output_dir: Path,
540  *,
541  qubit_sizes=EXACT_REGIME_WORKFLOW_QUBITS,
542  parameter_set_count: int = EXACT_REGIME_PARAMETER_SET_COUNT,
543  verbose=False,
544 ):
545  output_dir = Path(output_dir)
546  output_dir.mkdir(parents=True, exist_ok=True)
547 
548  required_local_noise_bundle, required_local_noise_micro_bundle, optional_results = (
549  run_optional_noise_classification_validation(verbose=verbose)
550  )
551  optional_noise_classification_bundle = build_optional_noise_classification_bundle(
552  required_local_noise_bundle,
553  required_local_noise_micro_bundle,
554  optional_results,
555  )
556  write_required_local_noise_bundle_file(
557  output_dir / REQUIRED_LOCAL_NOISE_ARTIFACT_FILENAME,
558  required_local_noise_bundle,
559  )
560  write_required_local_noise_micro_bundle_file(
561  output_dir / REQUIRED_LOCAL_NOISE_MICRO_ARTIFACT_FILENAME,
562  required_local_noise_micro_bundle,
563  )
564  write_optional_noise_classification_bundle_file(
565  output_dir / OPTIONAL_NOISE_CLASSIFICATION_ARTIFACT_FILENAME,
566  optional_noise_classification_bundle,
567  )
568 
569  unsupported_noise_results = run_unsupported_noise_validation(verbose=verbose)
570  unsupported_noise_bundle = build_unsupported_noise_bundle(
571  unsupported_noise_results
572  )
573  write_unsupported_noise_bundle_file(
574  output_dir / UNSUPPORTED_NOISE_ARTIFACT_FILENAME,
575  unsupported_noise_bundle,
576  )
577 
578  _, required_local_noise_trace_result, required_local_noise_workflow_bundle = (
579  run_required_local_noise_workflow_validation(
580  qubit_sizes=qubit_sizes,
581  parameter_set_count=parameter_set_count,
582  verbose=verbose,
583  )
584  )
585  write_required_local_noise_workflow_bundle_file(
586  output_dir / REQUIRED_LOCAL_NOISE_WORKFLOW_BUNDLE_FILENAME,
587  required_local_noise_workflow_bundle,
588  trace_result=required_local_noise_trace_result,
589  )
590  write_json(
591  output_dir / REQUIRED_LOCAL_NOISE_TRACE_ARTIFACT_FILENAME,
592  required_local_noise_trace_result,
593  )
594 
596  output_dir,
597  required_local_noise_bundle=required_local_noise_bundle,
598  required_local_noise_micro_bundle=required_local_noise_micro_bundle,
599  optional_noise_classification_bundle=optional_noise_classification_bundle,
600  unsupported_noise_bundle=unsupported_noise_bundle,
601  required_local_noise_workflow_bundle=required_local_noise_workflow_bundle,
602  required_local_noise_trace_result=required_local_noise_trace_result,
603  )
604  write_noise_support_publication_bundle(output_dir / ARTIFACT_FILENAME, bundle)
605  return bundle
606 
607 
609  parser = argparse.ArgumentParser(description=__doc__)
610  parser.add_argument(
611  "--output-dir",
612  type=Path,
613  default=DEFAULT_OUTPUT_DIR,
614  help="Directory for the noise-support publication JSON artifacts.",
615  )
616  parser.add_argument(
617  "--parameter-set-count",
618  type=int,
619  default=EXACT_REGIME_PARAMETER_SET_COUNT,
620  help="Number of fixed parameter vectors per workflow qubit size.",
621  )
622  parser.add_argument(
623  "--qubit-sizes",
624  type=int,
625  nargs="*",
626  default=list(EXACT_REGIME_WORKFLOW_QUBITS),
627  help="Workflow qubit sizes to include in the prerequisite workflow bundle.",
628  )
629  parser.add_argument(
630  "--quiet",
631  action="store_true",
632  help="Suppress progress output from prerequisite bundle generators.",
633  )
634  return parser.parse_args()
635 
636 
637 def main():
638  args = parse_args()
640  args.output_dir,
641  qubit_sizes=tuple(args.qubit_sizes),
642  parameter_set_count=args.parameter_set_count,
643  verbose=not args.quiet,
644  )
645  print(
646  "Wrote {} with status {} ({}/{})".format(
647  args.output_dir / ARTIFACT_FILENAME,
648  bundle["status"],
649  bundle["summary"]["present_artifact_count"],
650  bundle["summary"]["mandatory_artifact_count"],
651  )
652  )
653  if bundle["status"] != "pass":
654  raise SystemExit(1)
655 
656 
657 if __name__ == "__main__":
658  main()
def _build_artifact_entry(artifact_id, artifact_class, mandatory, path, status, expected_statuses, purpose, generation_command, summary)
def build_software_metadata()