diff --git a/.gitignore b/.gitignore index 0c75f26d..f1694406 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,7 @@ docs/_build/ # mypy .mypy_cache/ + +# QC-App-Oriented-Benchmarks +__data/ +__images/ diff --git a/metriq_gym/benchmarks/qedc_benchmarks.py b/metriq_gym/benchmarks/qedc_benchmarks.py index 3ed67f45..625c4042 100644 --- a/metriq_gym/benchmarks/qedc_benchmarks.py +++ b/metriq_gym/benchmarks/qedc_benchmarks.py @@ -19,6 +19,7 @@ from metriq_gym.helpers.task_helpers import flatten_counts from _common import metrics +from _common.qiskit import execute as ex QEDC_BENCHMARK_IMPORTS: dict[JobType, str] = { @@ -32,36 +33,34 @@ Type: QEDC_Metrics Description: The structure for all returned QED-C circuit metrics. - The first key represents the number of qubits for the group of circuits. - The second key represents the unique identifier for a circuit in the group. + + 1. The first key represents the number of qubits for the group of circuits or the subtitle. + 2. The second key represents the unique identifier for a circuit in the group. - This may be a secret string for Bernstein-Vazirani, theta value for Phase-Estimation, and so on. Benchmark specific documentation can be found in QED-C's QC-App-Oriented-Benchmarks repository. - The third key represents the metric being stored. + 3. The third key represents the metric being stored. + Example for Bernstein-Vazirani: { '3': { - '1': {'create_time': 0.16371703147888184, - 'fidelity': 1.0, + '1': {'fidelity': 1.0, 'hf_fidelity': 1.0}, - '2': {'create_time': 0.0005087852478027344, - 'fidelity': 1.0, + '2': {'fidelity': 1.0, 'hf_fidelity': 1.0} }, '4': { - '1': {'create_time': 0.0005209445953369141, - 'fidelity': 1.0, + '1': {'fidelity': 1.0, 'hf_fidelity': 1.0}, - '3': {'create_time': 0.00047206878662109375, - 'fidelity': 1.0, + '3': {'fidelity': 1.0, 'hf_fidelity': 1.0}, - '5': {'create_time': 0.0005078315734863281, - 'fidelity': 1.0, + '5': {'fidelity': 1.0, 'hf_fidelity': 1.0} } +'subtitle': "device = X" } """ -QEDC_Metrics = dict[str, dict[str, dict[str, float]]] +QEDC_Metrics = dict[str, dict[str, dict[str, float]] | str] @dataclass @@ -141,7 +140,7 @@ def get_counts(self, _): benchmark_name = str(params["benchmark_name"]) benchmark = import_benchmark_module(benchmark_name) - # Restore circuit metrics dictionary from the dispatch data + # Restore circuit metrics from the dispatch data metrics.circuit_metrics = job_data.circuit_metrics # Iterate and get the metrics for each circuit in the list. @@ -171,8 +170,32 @@ def get_counts(self, _): None, result_object, int(num_qubits), int(circuit_id), params["num_shots"] ) + # Store the fidelity. metrics.store_metric(num_qubits, circuit_id, "fidelity", fidelity) + # Code below plots the metrics: + + # Compute statistics for metrics. + metrics.aggregate_metrics() + + # Set backend information for plot titles. + provider_name = "qBraid" + device_name = "" + + # Set plot titles. + benchmark_title = f"{benchmark_name} ({params.get('method', '1')})" + subtitle = f"Benchmark Results - {benchmark_title} - {provider_name}" + metrics.circuit_metrics["subtitle"] = f"device = {device_name}" + + # Determine which metrics to plot. + filters = ["fidelity", "hf_fidelity", "depth", "2q", "vbplot"] + + # Plot the metrics. + metrics.plot_metrics(subtitle, filters=filters) + + # Remove subtilte key. + metrics.circuit_metrics.pop("subtitle", None) + return metrics.circuit_metrics @@ -184,7 +207,8 @@ def get_circuits_and_metrics( Uses QED-C submodule to obtain circuits and circuit metrics. Args: - params: the parameters to run the benchmark with, also includes benchmark_name. + benchmark_name: the name of the benchmark. + params: the parameters to run the benchmark with. Returns: circuits: the list of quantum circuits for the benchmark. @@ -201,9 +225,12 @@ def get_circuits_and_metrics( get_circuits=True, ) - # Remove the subtitle key to keep our desired format. + # Remove the subtitle key for iterating purposes. circuit_metrics.pop("subtitle", None) + # Copy any initial creation metrics (i.e. create_time). + metrics.circuit_metrics = circuit_metrics + # Store the circuit identifiers and a flat list of circuits. circuit_identifiers = [] flat_circuits = [] @@ -212,7 +239,16 @@ def get_circuits_and_metrics( circuit_identifiers.append((num_qubits, circuit_id)) flat_circuits.append(circuits[num_qubits][circuit_id]) - return flat_circuits, circuit_metrics, circuit_identifiers + # Compute circuit properties (depth, etc.) and store to metrics. + ex.compute_and_store_circuit_info( + circuits[num_qubits][circuit_id], + str(num_qubits), + str(circuit_id), + do_transpile_metrics=True, + use_normalized_depth=True, + ) + + return flat_circuits, metrics.circuit_metrics, circuit_identifiers class QEDCBenchmark(Benchmark): diff --git a/metriq_gym/schemas/examples/bernstein_vazirani.example.json b/metriq_gym/schemas/examples/bernstein_vazirani.example.json index 624bc99b..3d56edfc 100644 --- a/metriq_gym/schemas/examples/bernstein_vazirani.example.json +++ b/metriq_gym/schemas/examples/bernstein_vazirani.example.json @@ -2,7 +2,7 @@ "benchmark_name": "Bernstein-Vazirani", "num_shots": 1000, "min_qubits": 2, - "max_qubits": 6, + "max_qubits": 10, "skip_qubits": 1, "max_circuits": 3, "method": 1 diff --git a/metriq_gym/schemas/examples/hidden_shift.example.json b/metriq_gym/schemas/examples/hidden_shift.example.json index 79a497e8..85f391e4 100644 --- a/metriq_gym/schemas/examples/hidden_shift.example.json +++ b/metriq_gym/schemas/examples/hidden_shift.example.json @@ -2,7 +2,7 @@ "benchmark_name": "Hidden Shift", "num_shots": 1000, "min_qubits": 2, - "max_qubits": 6, + "max_qubits": 10, "skip_qubits": 1, "max_circuits": 3, "method": 1 diff --git a/metriq_gym/schemas/examples/phase_estimation.example.json b/metriq_gym/schemas/examples/phase_estimation.example.json index 6c0674ce..69c128e5 100644 --- a/metriq_gym/schemas/examples/phase_estimation.example.json +++ b/metriq_gym/schemas/examples/phase_estimation.example.json @@ -2,7 +2,7 @@ "benchmark_name": "Phase Estimation", "num_shots": 1000, "min_qubits": 2, - "max_qubits": 6, + "max_qubits": 10, "skip_qubits": 1, "max_circuits": 3, "method": 1, diff --git a/metriq_gym/schemas/examples/quantum_fourier_transform.example.json b/metriq_gym/schemas/examples/quantum_fourier_transform.example.json index 3937d6bd..a6a2d006 100644 --- a/metriq_gym/schemas/examples/quantum_fourier_transform.example.json +++ b/metriq_gym/schemas/examples/quantum_fourier_transform.example.json @@ -2,7 +2,7 @@ "benchmark_name": "Quantum Fourier Transform", "num_shots": 1000, "min_qubits": 2, - "max_qubits": 6, + "max_qubits": 10, "skip_qubits": 1, "max_circuits": 3, "method": 1, diff --git a/metriq_gym/schemas/phase_estimation.schema.json b/metriq_gym/schemas/phase_estimation.schema.json index 62fce7ff..2f97d545 100644 --- a/metriq_gym/schemas/phase_estimation.schema.json +++ b/metriq_gym/schemas/phase_estimation.schema.json @@ -62,7 +62,6 @@ "description": "Creates circuits with mid-circuit measurements.", "default": false, "examples": [true] - } }, "required": ["benchmark_name"], diff --git a/metriq_gym/schemas/quantum_fourier_transform.schema.json b/metriq_gym/schemas/quantum_fourier_transform.schema.json index 6515fee3..26aae2bd 100644 --- a/metriq_gym/schemas/quantum_fourier_transform.schema.json +++ b/metriq_gym/schemas/quantum_fourier_transform.schema.json @@ -64,7 +64,6 @@ "description": "Creates circuits with mid-circuit measurements.", "default": false, "examples": [true] - } }, "required": ["benchmark_name"],