Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
unsupported_bridge_validation.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 """Validation: unsupported bridge cases.
3 
4 Captures representative unsupported bridge requests as structured artifacts. The
5 goal is to prove that unsupported circuit-source, lowering, and noise-boundary
6 cases fail before execution and surface a stable first unsupported condition.
7 
8 Run with:
9  python benchmarks/density_matrix/bridge_scope/unsupported_bridge_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 import numpy as np
20 
21 REPO_ROOT = Path(__file__).resolve().parents[3]
22 if str(REPO_ROOT) not in sys.path:
23  sys.path.insert(0, str(REPO_ROOT))
24 
25 from examples.VQE.shot_noise_measurement import generate_zz_xx_hamiltonian
26 from benchmarks.density_matrix.workflow_evidence.exact_density_vqe_validation import (
27  DEFAULT_ANSATZ,
28  DEFAULT_INNER_BLOCKS,
29  DEFAULT_LAYERS,
30  PRIMARY_BACKEND,
31  build_case_metadata,
32  build_software_metadata,
33  build_optimizer_config,
34  build_hamiltonian_metadata,
35  build_initial_parameters,
36  build_open_chain_topology,
37 )
38 from squander import Variational_Quantum_Eigensolver
39 from squander.gates.qgd_Circuit import qgd_Circuit
40 
41 SUITE_NAME = "unsupported_bridge_validation"
42 ARTIFACT_FILENAME = "unsupported_bridge_bundle.json"
43 ARTIFACT_CORE_FIELDS = (
44  "suite_name",
45  "status",
46  "backend",
47  "requirements",
48  "summary",
49  "software",
50  "cases",
51 )
52 
53 
55  return {
56  "expected_status": "unsupported",
57  "required_categories": [
58  "circuit_source",
59  "lowering_path",
60  "noise_insertion",
61  "noise_type",
62  ],
63  "canonical_bridge_fields": [
64  "bridge_source_type",
65  "unsupported_category",
66  "first_unsupported_condition",
67  "unsupported_reason",
68  "source_pass",
69  "gate_pass",
70  "noise_pass",
71  "operation_match_pass",
72  "execution_ready",
73  ],
74  }
75 
76 
77 def build_density_vqe(qbit_num: int, density_noise=None, *, ansatz: str = DEFAULT_ANSATZ):
78  if density_noise is None:
79  density_noise = []
80  topology = build_open_chain_topology(qbit_num)
81  hamiltonian, _ = generate_zz_xx_hamiltonian(
82  n_qubits=qbit_num,
83  h=0.5,
84  topology=topology,
85  Jz=1.0,
86  Jx=1.0,
87  Jy=1.0,
88  )
89  vqe = Variational_Quantum_Eigensolver(
90  hamiltonian,
91  qbit_num,
93  backend=PRIMARY_BACKEND,
94  density_noise=density_noise,
95  )
96  vqe.set_Ansatz(ansatz)
97  return vqe, topology
98 
99 
101  *,
102  case_name: str,
103  qbit_num: int,
104  topology,
105  density_noise,
106  purpose: str,
107  unsupported_category: str,
108  first_unsupported_condition: str,
109  bridge_source_type: str,
110  ansatz: str = DEFAULT_ANSATZ,
111 ):
112  metadata = build_case_metadata(
113  backend=PRIMARY_BACKEND,
114  qbit_num=qbit_num,
115  topology=topology,
116  density_noise=density_noise,
117  ansatz=ansatz,
118  hamiltonian=build_hamiltonian_metadata(),
119  )
120  metadata.update(
121  {
122  "case_name": case_name,
123  "case_kind": "unsupported_bridge_validation",
124  "purpose": purpose,
125  "bridge_source_type": bridge_source_type,
126  "unsupported_category": unsupported_category,
127  "first_unsupported_condition": first_unsupported_condition,
128  "source_pass": False,
129  "gate_pass": False,
130  "noise_pass": False,
131  "operation_match_pass": False,
132  "execution_ready": False,
133  }
134  )
135  return metadata
136 
137 
139  qbit_num = 2
140  vqe, topology = build_density_vqe(qbit_num)
141  custom_circuit = qgd_Circuit(qbit_num)
142  custom_circuit.add_H(0)
143  custom_circuit.add_CNOT(1, 0)
144  vqe.set_Gate_Structure(custom_circuit)
145 
146  metadata = _base_case_metadata(
147  case_name="unsupported_bridge_custom_gate_structure_source",
148  qbit_num=qbit_num,
149  topology=topology,
150  density_noise=[],
151  purpose="Verify a custom manual circuit source fails before bridge execution with a source-category unsupported result.",
152  unsupported_category="circuit_source",
153  first_unsupported_condition="custom_gate_structure",
154  bridge_source_type="custom_gate_structure",
155  )
156 
157  def runner():
158  vqe.describe_density_bridge()
159 
160  return metadata, runner, "unsupported circuit source in density backend path: custom_gate_structure"
161 
162 
164  qbit_num = 2
165  vqe, topology = build_density_vqe(
166  qbit_num,
167  density_noise=[],
168  ansatz="HEA_ZYZ",
169  )
170  vqe.Generate_Circuit(DEFAULT_LAYERS, DEFAULT_INNER_BLOCKS)
171  parameters = build_initial_parameters(vqe.get_Parameter_Num())
172  vqe.set_Optimized_Parameters(parameters)
173 
174  metadata = _base_case_metadata(
175  case_name="unsupported_bridge_hea_zyz_lowering",
176  qbit_num=qbit_num,
177  topology=topology,
178  density_noise=[],
179  purpose="Verify the unsupported HEA_ZYZ lowering path fails before bridge execution.",
180  unsupported_category="lowering_path",
181  first_unsupported_condition="generated_hea_zyz",
182  bridge_source_type="generated_hea_zyz",
183  ansatz="HEA_ZYZ",
184  )
185 
186  def runner():
187  vqe.describe_density_bridge()
188 
189  return metadata, runner, "currently supports only the HEA ansatz"
190 
191 
193  qbit_num = 2
194  density_noise = [
195  {
196  "channel": "local_depolarizing",
197  "target": 0,
198  "after_gate_index": 999,
199  "error_rate": 0.1,
200  }
201  ]
202  vqe, topology = build_density_vqe(qbit_num, density_noise=density_noise)
203  vqe.Generate_Circuit(DEFAULT_LAYERS, DEFAULT_INNER_BLOCKS)
204 
205  metadata = _base_case_metadata(
206  case_name="unsupported_bridge_after_gate_index",
207  qbit_num=qbit_num,
208  topology=topology,
209  density_noise=density_noise,
210  purpose="Verify invalid ordered noise insertion fails before density execution.",
211  unsupported_category="noise_insertion",
212  first_unsupported_condition="after_gate_index",
213  bridge_source_type="generated_hea",
214  )
215  metadata["source_pass"] = True
216  metadata["gate_pass"] = True
217 
218  def runner():
219  vqe.describe_density_bridge()
220 
221  return metadata, runner, "after_gate_index exceeds generated gate count"
222 
223 
225  qbit_num = 1
226  topology = build_open_chain_topology(qbit_num)
227  requested_density_noise = [
228  {
229  "channel": "readout_noise",
230  "target": 0,
231  "after_gate_index": 0,
232  "value": 0.1,
233  }
234  ]
235  metadata = _base_case_metadata(
236  case_name="unsupported_bridge_noise_channel",
237  qbit_num=qbit_num,
238  topology=topology,
239  density_noise=requested_density_noise,
240  purpose="Verify unsupported density-noise channel names fail during bridge configuration.",
241  unsupported_category="noise_type",
242  first_unsupported_condition="unsupported_density_noise_channel",
243  bridge_source_type="unset",
244  )
245 
246  def runner():
247  Variational_Quantum_Eigensolver(
249  n_qubits=qbit_num,
250  h=0.5,
251  topology=topology,
252  Jz=1.0,
253  Jx=1.0,
254  Jy=1.0,
255  )[0],
256  qbit_num,
258  backend=PRIMARY_BACKEND,
259  density_noise=requested_density_noise,
260  )
261 
262  return metadata, runner, "Unsupported density-noise channel"
263 
264 
265 UNSUPPORTED_CASE_BUILDERS = (
266  case_custom_gate_structure_source,
267  case_hea_zyz_lowering,
268  case_invalid_after_gate_index,
269  case_invalid_noise_channel,
270 )
271 
272 
273 def capture_unsupported_case(case_builder, verbose=True):
274  metadata, runner, expected_error_fragment = case_builder()
275  try:
276  runner()
277  result = dict(metadata)
278  result.update(
279  {
280  "status": "fail",
281  "unsupported_reason": "Case executed successfully but was expected to fail.",
282  "error_match_pass": False,
283  }
284  )
285  except Exception as exc:
286  result = dict(metadata)
287  result.update(
288  {
289  "status": "unsupported",
290  "unsupported_reason": str(exc),
291  "error_match_pass": expected_error_fragment in str(exc),
292  }
293  )
294 
295  if verbose:
296  print(
297  " {case_name:<52} category={category:<14} status={status}".format(
298  case_name=result["case_name"],
299  category=result["unsupported_category"],
300  status=result["status"].upper(),
301  )
302  )
303 
304  return result
305 
306 
307 def run_validation(verbose=True):
308  print("=" * 78)
309  print(" Unsupported Bridge Validation [{}]".format(PRIMARY_BACKEND))
310  print("=" * 78)
311  return [capture_unsupported_case(builder, verbose=verbose) for builder in UNSUPPORTED_CASE_BUILDERS]
312 
313 
315  unsupported = sum(1 for result in results if result["status"] == "unsupported")
316  error_match = sum(1 for result in results if result.get("error_match_pass", False))
317  total = len(results)
318  bundle = {
319  "suite_name": SUITE_NAME,
320  "status": "pass" if unsupported == total and error_match == total else "fail",
321  "backend": PRIMARY_BACKEND,
322  "requirements": build_requirement_metadata(),
323  "software": build_software_metadata(),
324  "summary": {
325  "total_cases": total,
326  "unsupported_cases": unsupported,
327  "failed_cases": total - unsupported,
328  "error_match_count": error_match,
329  "required_case_count": total,
330  },
331  "cases": results,
332  }
334  return bundle
335 
336 
338  missing_fields = [field for field in ARTIFACT_CORE_FIELDS if field not in bundle]
339  if missing_fields:
340  raise ValueError(
341  "Artifact bundle is missing required fields: {}".format(
342  ", ".join(missing_fields)
343  )
344  )
345 
346 
347 def write_artifact_bundle(output_path: Path, bundle):
349  output_path.parent.mkdir(parents=True, exist_ok=True)
350  output_path.write_text(json.dumps(bundle, indent=2) + "\n", encoding="utf-8")
351 
352 
353 def print_summary(bundle):
354  print("\n" + "=" * 78)
355  print(" SUMMARY")
356  print("=" * 78)
357  for result in bundle["cases"]:
358  details = []
359  if result["status"] != "unsupported":
360  details.append("status")
361  if not result.get("error_match_pass", False):
362  details.append("error_match")
363  print(
364  " {case_name:<52} category={category:<14} status={status}{detail_suffix}".format(
365  case_name=result["case_name"],
366  category=result["unsupported_category"],
367  status=result["status"].upper(),
368  detail_suffix="" if not details else " (" + ",".join(details) + ")",
369  )
370  )
371 
372  print("\n" + "-" * 78)
373  print(
374  " Total: {unsupported}/{total} representative unsupported bridge cases behaved as expected".format(
375  unsupported=bundle["summary"]["unsupported_cases"],
376  total=bundle["summary"]["total_cases"],
377  )
378  )
379  if bundle["status"] == "pass":
380  print("\n ALL TESTS PASSED - Unsupported bridge validation gate is closed.")
381  else:
382  print("\n Some representative unsupported bridge cases did not behave as expected.")
383  print("=" * 78)
384 
385 
386 def main():
387  parser = argparse.ArgumentParser(description=__doc__)
388  parser.add_argument(
389  "--output-dir",
390  type=Path,
391  default=None,
392  help="Optional directory for the unsupported-bridge JSON artifact bundle.",
393  )
394  args = parser.parse_args()
395 
396  results = run_validation()
397  bundle = build_artifact_bundle(results)
398  print_summary(bundle)
399 
400  if args.output_dir is not None:
401  write_artifact_bundle(args.output_dir / ARTIFACT_FILENAME, bundle)
402 
403  if bundle["status"] != "pass":
404  raise SystemExit(1)
405 
406 
407 if __name__ == "__main__":
408  main()
def build_optimizer_config()
def build_open_chain_topology
def build_software_metadata()
def capture_unsupported_case(case_builder, verbose=True)