Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
end_to_end_trace_validation.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 """Validation: end-to-end workflow plus trace gate.
3 
4 Builds the end-to-end execution gate from:
5 - the emitted canonical workflow contract,
6 - the committed validation workflow baseline bundle, from which the canonical 4q
7  and 6q end-to-end cases are selected,
8 - and the committed validation trace artifact.
9 
10 This layer is intentionally thin:
11 - it freezes one 4q case, one 6q case, and one required trace as the mandatory
12  gate,
13 - it ties those evidence items to the workflow-contract identity,
14 - and it makes missing or malformed required evidence fail explicitly.
15 
16 Run with:
17  python benchmarks/density_matrix/workflow_evidence/end_to_end_trace_validation.py
18 """
19 
20 from __future__ import annotations
21 
22 import argparse
23 import json
24 import sys
25 from collections import Counter
26 from pathlib import Path
27 
28 REPO_ROOT = Path(__file__).resolve().parents[3]
29 if str(REPO_ROOT) not in sys.path:
30  sys.path.insert(0, str(REPO_ROOT))
31 
32 from benchmarks.density_matrix.workflow_evidence.workflow_contract_validation import (
33  ARTIFACT_FILENAME as WORKFLOW_CONTRACT_ARTIFACT_FILENAME,
34  CONTRACT_VERSION,
35  DEFAULT_OUTPUT_DIR as WORKFLOW_EVIDENCE_OUTPUT_DIR,
36  REFERENCE_BACKEND,
37  STATUS_VOCABULARY,
38  WORKFLOW_ID,
39  build_software_metadata,
40  get_git_revision,
41  run_validation as run_workflow_contract_validation,
42  validate_artifact_bundle as validate_workflow_contract_artifact,
43 )
44 
45 SUITE_NAME = "end_to_end_trace_validation"
46 ARTIFACT_FILENAME = "end_to_end_trace_bundle.json"
47 DEFAULT_OUTPUT_DIR = WORKFLOW_EVIDENCE_OUTPUT_DIR
48 WORKFLOW_CONTRACT_PATH = DEFAULT_OUTPUT_DIR / WORKFLOW_CONTRACT_ARTIFACT_FILENAME
49 VALIDATION_WORKFLOW_BASELINE_PATH = (
50  REPO_ROOT
51  / "benchmarks"
52  / "density_matrix"
53  / "artifacts"
54  / "validation_evidence"
55  / "workflow_baseline_bundle.json"
56 )
57 VALIDATION_TRACE_ARTIFACT_PATH = (
58  REPO_ROOT
59  / "benchmarks"
60  / "density_matrix"
61  / "artifacts"
62  / "validation_evidence"
63  / "optimization_trace_4q.json"
64 )
65 MANDATORY_END_TO_END_CASE_NAMES = ("exact_regime_4q_set_00", "exact_regime_6q_set_00")
66 MANDATORY_END_TO_END_QUBITS = (4, 6)
67 TRACE_CASE_NAME = "optimization_trace_4q"
68 CANONICAL_END_TO_END_PARAMETER_SET_ID = "set_00"
69 ARTIFACT_CORE_FIELDS = (
70  "suite_name",
71  "status",
72  "workflow_id",
73  "contract_version",
74  "backend",
75  "reference_backend",
76  "requirements",
77  "thresholds",
78  "software",
79  "provenance",
80  "summary",
81  "required_artifacts",
82  "cases",
83  "trace_artifact",
84 )
85 
86 
87 def _load_json(path: Path):
88  return json.loads(path.read_text(encoding="utf-8"))
89 
90 
91 def _load_workflow_contract(path: Path = WORKFLOW_CONTRACT_PATH):
92  if path.exists():
93  artifact = _load_json(path)
94  validate_workflow_contract_artifact(artifact)
95  return artifact
96  _, artifact = run_workflow_contract_validation(verbose=False)
97  return artifact
98 
99 
100 def get_required_end_to_end_qubits(workflow_contract):
101  return tuple(workflow_contract["thresholds"]["required_end_to_end_qubits"])
102 
103 
104 def get_required_trace_case_name(workflow_contract):
105  return workflow_contract["input_contract"]["execution_modes"][
106  "bounded_optimization_trace"
107  ]["canonical_trace_case_name"]
108 
109 
111  return tuple(
112  f"exact_regime_{qbit_num}q_{CANONICAL_END_TO_END_PARAMETER_SET_ID}"
113  for qbit_num in get_required_end_to_end_qubits(workflow_contract)
114  )
115 
116 
117 def build_requirement_metadata(workflow_contract):
118  mandatory_end_to_end_qubits = get_required_end_to_end_qubits(workflow_contract)
119  mandatory_case_names = build_mandatory_end_to_end_case_names(workflow_contract)
120  required_trace_case_name = get_required_trace_case_name(workflow_contract)
121  return {
122  "workflow_id": workflow_contract["workflow_id"],
123  "contract_version": workflow_contract["contract_version"],
124  "mandatory_end_to_end_case_names": list(mandatory_case_names),
125  "mandatory_end_to_end_qubits": list(mandatory_end_to_end_qubits),
126  "required_trace_case_name": required_trace_case_name,
127  "status_vocabulary": list(STATUS_VOCABULARY),
128  "required_bundle_sources": [
129  workflow_contract["suite_name"],
130  "workflow_baseline_validation",
131  "trace_anchor_validation",
132  ],
133  }
134 
135 
136 def build_threshold_metadata(workflow_contract, workflow_bundle):
137  workflow_thresholds = workflow_bundle["thresholds"]
138  contract_thresholds = workflow_contract["thresholds"]
139  return {
140  "absolute_energy_error": contract_thresholds["absolute_energy_error"],
141  "rho_is_valid_tol": contract_thresholds["rho_is_valid_tol"],
142  "trace_deviation": contract_thresholds["trace_deviation"],
143  "observable_imag_abs": contract_thresholds["observable_imag_abs"],
144  "required_pass_rate": contract_thresholds["required_pass_rate"],
145  "required_end_to_end_qubits": list(
146  contract_thresholds["required_end_to_end_qubits"]
147  ),
148  "required_trace_case_name": get_required_trace_case_name(workflow_contract),
149  "workflow_thresholds_match_contract": all(
150  workflow_thresholds[field] == contract_thresholds[field]
151  for field in (
152  "absolute_energy_error",
153  "rho_is_valid_tol",
154  "trace_deviation",
155  "observable_imag_abs",
156  "required_pass_rate",
157  )
158  ),
159  }
160 
161 
163  required_fields = (
164  "case_name",
165  "status",
166  "backend",
167  "reference_backend",
168  "qbit_num",
169  "workflow_completed",
170  "parameter_set_id",
171  "absolute_energy_error",
172  "energy_pass",
173  "density_valid_pass",
174  "trace_pass",
175  "observable_pass",
176  "bridge_supported_pass",
177  "support_tier",
178  "case_purpose",
179  "counts_toward_mandatory_baseline",
180  "workflow_id",
181  "contract_version",
182  "workflow_evidence_role",
183  "required_workflow_case",
184  )
185  missing_fields = [field for field in required_fields if field not in case]
186  if missing_fields:
187  raise ValueError(
188  "End-to-end trace case is missing required fields: {}".format(
189  ", ".join(missing_fields)
190  )
191  )
192 
193 
194 def validate_trace_artifact(trace_artifact):
195  required_fields = (
196  "case_name",
197  "status",
198  "backend",
199  "qbit_num",
200  "workflow_completed",
201  "bridge_supported_pass",
202  "optimizer",
203  "parameter_count",
204  "initial_energy",
205  "final_energy",
206  "energy_improvement",
207  "total_trace_runtime_ms",
208  "process_peak_rss_kb",
209  "workflow_id",
210  "contract_version",
211  "workflow_evidence_role",
212  "required_workflow_trace",
213  )
214  missing_fields = [
215  field for field in required_fields if field not in trace_artifact
216  ]
217  if missing_fields:
218  raise ValueError(
219  "End-to-end trace artifact is missing required fields: {}".format(
220  ", ".join(missing_fields)
221  )
222  )
223 
224 
225 def build_case_identity_summary(cases, mandatory_case_names, mandatory_qubits):
226  case_names = [case["case_name"] for case in cases]
227  counts = Counter(case_names)
228  duplicate_case_names = sorted(
229  case_name for case_name, count in counts.items() if count > 1
230  )
231  missing_mandatory_case_names = sorted(
232  set(mandatory_case_names) - set(case_names)
233  )
234  unexpected_case_names = sorted(
235  set(case_names) - set(mandatory_case_names)
236  )
237  observed_qubits = sorted(case["qbit_num"] for case in cases)
238  missing_mandatory_qubits = sorted(set(mandatory_qubits) - set(observed_qubits))
239  unexpected_mandatory_qubits = sorted(
240  set(observed_qubits) - set(mandatory_qubits)
241  )
242  stable_case_ids_present = (
243  not duplicate_case_names
244  and not missing_mandatory_case_names
245  and not unexpected_case_names
246  and not missing_mandatory_qubits
247  and not unexpected_mandatory_qubits
248  and len(case_names) == len(mandatory_case_names)
249  )
250  return {
251  "observed_case_names": case_names,
252  "observed_qubits": observed_qubits,
253  "missing_mandatory_case_names": missing_mandatory_case_names,
254  "missing_mandatory_qubits": missing_mandatory_qubits,
255  "duplicate_case_names": duplicate_case_names,
256  "unexpected_case_names": unexpected_case_names,
257  "unexpected_mandatory_qubits": unexpected_mandatory_qubits,
258  "stable_case_ids_present": stable_case_ids_present,
259  }
260 
261 
262 def _enrich_end_to_end_case(case, workflow_contract):
263  case = dict(case)
264  case["workflow_id"] = workflow_contract["workflow_id"]
265  case["contract_version"] = workflow_contract["contract_version"]
266  case["workflow_evidence_role"] = "required_end_to_end"
267  case["required_workflow_case"] = True
268  return case
269 
270 
271 def _enrich_trace_artifact(trace_artifact, workflow_contract):
272  trace_artifact = dict(trace_artifact)
273  trace_artifact["workflow_id"] = workflow_contract["workflow_id"]
274  trace_artifact["contract_version"] = workflow_contract["contract_version"]
275  trace_artifact["workflow_evidence_role"] = "required_trace"
276  trace_artifact["required_workflow_trace"] = True
277  return trace_artifact
278 
279 
280 def _extract_mandatory_cases(workflow_bundle, workflow_contract):
281  selected_cases = []
282  for case_name in build_mandatory_end_to_end_case_names(workflow_contract):
283  matching_cases = [
284  case for case in workflow_bundle["cases"] if case["case_name"] == case_name
285  ]
286  if matching_cases:
287  selected_cases.append(
288  _enrich_end_to_end_case(matching_cases[0], workflow_contract)
289  )
290  return selected_cases
291 
292 
293 def build_artifact_bundle(workflow_contract, workflow_bundle, trace_artifact):
294  mandatory_case_names = build_mandatory_end_to_end_case_names(workflow_contract)
295  mandatory_end_to_end_qubits = get_required_end_to_end_qubits(workflow_contract)
296  required_trace_case_name = get_required_trace_case_name(workflow_contract)
297  cases = _extract_mandatory_cases(workflow_bundle, workflow_contract)
298  for case in cases:
300 
301  trace_artifact = _enrich_trace_artifact(trace_artifact, workflow_contract)
302  validate_trace_artifact(trace_artifact)
303 
304  case_identity = build_case_identity_summary(
305  cases, mandatory_case_names, mandatory_end_to_end_qubits
306  )
307  threshold_metadata = build_threshold_metadata(workflow_contract, workflow_bundle)
308  total_cases = len(cases)
309  passed_end_to_end_cases = sum(
310  bool(
311  case["status"] == "pass"
312  and case["workflow_completed"]
313  and case["bridge_supported_pass"]
314  )
315  for case in cases
316  )
317  unsupported_cases = sum(case["status"] == "unsupported" for case in cases)
318  all_cases_required = all(case["support_tier"] == "required" for case in cases)
319  all_cases_mandatory = all(
320  case["counts_toward_mandatory_baseline"] for case in cases
321  )
322  all_cases_match_contract = all(
323  case["workflow_id"] == workflow_contract["workflow_id"]
324  and case["contract_version"] == workflow_contract["contract_version"]
325  for case in cases
326  )
327  end_to_end_qubits_match_contract = sorted(
328  case["qbit_num"] for case in cases
329  ) == sorted(mandatory_end_to_end_qubits)
330  required_trace_present = trace_artifact["case_name"] == required_trace_case_name and bool(
331  trace_artifact["required_workflow_trace"]
332  )
333  required_trace_completed = bool(
334  trace_artifact["status"] == "completed"
335  and trace_artifact["workflow_completed"]
336  )
337  required_trace_bridge_supported = bool(
338  trace_artifact["bridge_supported_pass"]
339  )
340  trace_case_name_matches_contract = (
341  trace_artifact["case_name"] == required_trace_case_name
342  )
343  trace_matches_contract = bool(
344  trace_artifact["workflow_id"] == workflow_contract["workflow_id"]
345  and trace_artifact["contract_version"] == workflow_contract["contract_version"]
346  )
347  end_to_end_gate_completed = bool(
348  workflow_contract["status"] == "pass"
349  and case_identity["stable_case_ids_present"]
350  and passed_end_to_end_cases == len(mandatory_case_names)
351  and unsupported_cases == 0
352  and all_cases_required
353  and all_cases_mandatory
354  and all_cases_match_contract
355  and end_to_end_qubits_match_contract
356  and required_trace_present
357  and required_trace_completed
358  and required_trace_bridge_supported
359  and trace_case_name_matches_contract
360  and trace_matches_contract
361  and threshold_metadata["workflow_thresholds_match_contract"]
362  )
363 
364  bundle = {
365  "suite_name": SUITE_NAME,
366  "status": "pass" if end_to_end_gate_completed else "fail",
367  "workflow_id": workflow_contract["workflow_id"],
368  "contract_version": workflow_contract["contract_version"],
369  "backend": workflow_contract["backend"],
370  "reference_backend": workflow_contract["reference_backend"],
371  "requirements": build_requirement_metadata(workflow_contract),
372  "thresholds": threshold_metadata,
373  "software": build_software_metadata(),
374  "provenance": {
375  "generation_command": (
376  "python benchmarks/density_matrix/"
377  "workflow_evidence/end_to_end_trace_validation.py"
378  ),
379  "working_directory": str(REPO_ROOT),
380  "git_revision": get_git_revision(),
381  "workflow_contract_path": str(WORKFLOW_CONTRACT_PATH),
382  "validation_workflow_baseline_path": str(
383  VALIDATION_WORKFLOW_BASELINE_PATH
384  ),
385  "validation_trace_artifact_path": str(VALIDATION_TRACE_ARTIFACT_PATH),
386  },
387  "summary": {
388  "total_end_to_end_cases": total_cases,
389  "passed_end_to_end_cases": passed_end_to_end_cases,
390  "failed_end_to_end_cases": total_cases - passed_end_to_end_cases,
391  "unsupported_end_to_end_cases": unsupported_cases,
392  **case_identity,
393  "all_cases_required": all_cases_required,
394  "all_cases_count_toward_mandatory_baseline": all_cases_mandatory,
395  "all_cases_match_contract": all_cases_match_contract,
396  "end_to_end_qubits_match_contract": end_to_end_qubits_match_contract,
397  "required_trace_case_name": trace_artifact["case_name"],
398  "required_trace_present": required_trace_present,
399  "required_trace_completed": required_trace_completed,
400  "required_trace_bridge_supported": required_trace_bridge_supported,
401  "trace_case_name_matches_contract": trace_case_name_matches_contract,
402  "trace_matches_contract": trace_matches_contract,
403  "workflow_thresholds_match_contract": threshold_metadata[
404  "workflow_thresholds_match_contract"
405  ],
406  "end_to_end_gate_completed": end_to_end_gate_completed,
407  },
408  "required_artifacts": {
409  "workflow_contract": {
410  "suite_name": workflow_contract["suite_name"],
411  "status": workflow_contract["status"],
412  "workflow_id": workflow_contract["workflow_id"],
413  "contract_version": workflow_contract["contract_version"],
414  "thresholds": workflow_contract["thresholds"],
415  "summary": workflow_contract["summary"],
416  },
417  "validation_workflow_baseline_reference": {
418  "suite_name": workflow_bundle["suite_name"],
419  "status": workflow_bundle["status"],
420  "summary": workflow_bundle["summary"],
421  },
422  "validation_trace_artifact": {
423  "case_name": trace_artifact["case_name"],
424  "status": trace_artifact["status"],
425  "workflow_completed": trace_artifact["workflow_completed"],
426  },
427  },
428  "cases": cases,
429  "trace_artifact": trace_artifact,
430  }
432  return bundle
433 
434 
436  missing_fields = [field for field in ARTIFACT_CORE_FIELDS if field not in bundle]
437  if missing_fields:
438  raise ValueError(
439  "End-to-end trace bundle is missing required fields: {}".format(
440  ", ".join(missing_fields)
441  )
442  )
443 
444  if bundle["workflow_id"] != WORKFLOW_ID:
445  raise ValueError(
446  "End-to-end trace bundle has unexpected workflow_id '{}'".format(
447  bundle["workflow_id"]
448  )
449  )
450  if bundle["contract_version"] != CONTRACT_VERSION:
451  raise ValueError(
452  "End-to-end trace bundle has unexpected contract_version '{}'".format(
453  bundle["contract_version"]
454  )
455  )
456  if (
457  bundle["requirements"]["mandatory_end_to_end_qubits"]
458  != bundle["thresholds"]["required_end_to_end_qubits"]
459  ):
460  raise ValueError(
461  "End-to-end trace bundle has inconsistent end-to-end qubit requirements"
462  )
463  if (
464  bundle["requirements"]["required_trace_case_name"]
465  != bundle["thresholds"]["required_trace_case_name"]
466  ):
467  raise ValueError(
468  "End-to-end trace bundle has inconsistent trace-case requirements"
469  )
470  if bundle["summary"]["stable_case_ids_present"] is False and bundle["status"] == "pass":
471  raise ValueError(
472  "End-to-end trace bundle cannot pass without stable mandatory case IDs"
473  )
474  if (
475  bundle["summary"]["end_to_end_qubits_match_contract"] is False
476  and bundle["status"] == "pass"
477  ):
478  raise ValueError(
479  "End-to-end trace bundle cannot pass without matching workflow-contract end-to-end qubit requirements"
480  )
481  if (
482  bundle["summary"]["trace_case_name_matches_contract"] is False
483  and bundle["status"] == "pass"
484  ):
485  raise ValueError(
486  "End-to-end trace bundle cannot pass without matching workflow-contract trace-case requirements"
487  )
488  if (
489  bundle["summary"]["workflow_thresholds_match_contract"] is False
490  and bundle["status"] == "pass"
491  ):
492  raise ValueError(
493  "End-to-end trace bundle cannot pass when workflow thresholds drift from workflow-contract metadata"
494  )
495  if bundle["summary"]["end_to_end_gate_completed"] != (bundle["status"] == "pass"):
496  raise ValueError(
497  "End-to-end trace bundle end_to_end_gate_completed summary is inconsistent"
498  )
499 
500 
501 def write_artifact_bundle(output_path: Path, bundle):
503  output_path.parent.mkdir(parents=True, exist_ok=True)
504  output_path.write_text(
505  json.dumps(bundle, indent=2, sort_keys=True) + "\n", encoding="utf-8"
506  )
507 
508 
509 def run_validation(
510  *,
511  workflow_contract_path: Path = WORKFLOW_CONTRACT_PATH,
512  workflow_bundle_path: Path = VALIDATION_WORKFLOW_BASELINE_PATH,
513  trace_artifact_path: Path = VALIDATION_TRACE_ARTIFACT_PATH,
514  verbose=False,
515 ):
516  workflow_contract = _load_workflow_contract(workflow_contract_path)
517  workflow_bundle = _load_json(workflow_bundle_path)
518  trace_artifact = _load_json(trace_artifact_path)
519  bundle = build_artifact_bundle(workflow_contract, workflow_bundle, trace_artifact)
520  if verbose:
521  print(
522  "{} [{}] end_to_end={}/{} trace={}".format(
523  bundle["suite_name"],
524  bundle["status"],
525  bundle["summary"]["passed_end_to_end_cases"],
526  bundle["summary"]["total_end_to_end_cases"],
527  bundle["summary"]["required_trace_completed"],
528  )
529  )
530  return workflow_contract, workflow_bundle, trace_artifact, bundle
531 
532 
534  parser = argparse.ArgumentParser(description=__doc__)
535  parser.add_argument(
536  "--output-dir",
537  type=Path,
538  default=DEFAULT_OUTPUT_DIR,
539  help="Directory for the end-to-end trace JSON artifact bundle.",
540  )
541  parser.add_argument(
542  "--workflow-contract-path",
543  type=Path,
544  default=WORKFLOW_CONTRACT_PATH,
545  help="Path to the canonical workflow-contract artifact.",
546  )
547  parser.add_argument(
548  "--workflow-bundle-path",
549  type=Path,
550  default=VALIDATION_WORKFLOW_BASELINE_PATH,
551  help="Path to the committed validation workflow-baseline bundle.",
552  )
553  parser.add_argument(
554  "--trace-artifact-path",
555  type=Path,
556  default=VALIDATION_TRACE_ARTIFACT_PATH,
557  help="Path to the committed validation trace artifact.",
558  )
559  parser.add_argument(
560  "--quiet",
561  action="store_true",
562  help="Suppress summary output.",
563  )
564  return parser.parse_args()
565 
566 
567 def main():
568  args = parse_args()
569  _, _, _, bundle = run_validation(
570  workflow_contract_path=args.workflow_contract_path,
571  workflow_bundle_path=args.workflow_bundle_path,
572  trace_artifact_path=args.trace_artifact_path,
573  verbose=not args.quiet,
574  )
575  output_path = args.output_dir / ARTIFACT_FILENAME
576  write_artifact_bundle(output_path, bundle)
577  print(
578  "Wrote {} with status {} ({}/{})".format(
579  output_path,
580  bundle["status"],
581  bundle["summary"]["passed_end_to_end_cases"],
582  bundle["summary"]["total_end_to_end_cases"],
583  )
584  )
585  if bundle["status"] != "pass":
586  raise SystemExit(1)
587 
588 
589 if __name__ == "__main__":
590  main()
def build_case_identity_summary(cases, mandatory_case_names, mandatory_qubits)
def build_artifact_bundle(workflow_contract, workflow_bundle, trace_artifact)
def get_required_end_to_end_qubits(workflow_contract)
def build_threshold_metadata(workflow_contract, workflow_bundle)
def build_mandatory_end_to_end_case_names(workflow_contract)
def build_requirement_metadata(workflow_contract)
def _enrich_end_to_end_case(case, workflow_contract)
def _extract_mandatory_cases(workflow_bundle, workflow_contract)
def get_required_trace_case_name(workflow_contract)
def build_software_metadata()
def _enrich_trace_artifact(trace_artifact, workflow_contract)