From b9777e362c2262727c800cf4c737cd2e5e0fa9ff Mon Sep 17 00:00:00 2001 From: Purva Thakre Date: Fri, 19 May 2023 06:27:45 -0500 Subject: [PATCH 01/14] mirror qv circuit --- .../mirror_quantum_volume_circuits.py | 64 +++++++++++++++++++ mitiq/benchmarks/quantum_volume_circuits.py | 2 +- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 mitiq/benchmarks/mirror_quantum_volume_circuits.py diff --git a/mitiq/benchmarks/mirror_quantum_volume_circuits.py b/mitiq/benchmarks/mirror_quantum_volume_circuits.py new file mode 100644 index 0000000000..6c960db5f1 --- /dev/null +++ b/mitiq/benchmarks/mirror_quantum_volume_circuits.py @@ -0,0 +1,64 @@ +# Copyright (C) 2023 Unitary Fund +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +"""Functions to create a Mirror Quantum Volume Benchmarking circuit +as defined in https://arxiv.org/abs/2303.02108.""" + +from mitiq.benchmarks.quantum_volume_circuits import generate_quantum_volume_circuit +import cirq + +def generate_mirror_qv_circuit( + num_qubits: int, + depth: int, + decompose: bool = False, + seed: Optional[int] = None, + return_type: Optional[str] = None, +) -> Tuple[QPROGRAM, Sequence[Bitstring]]: + """Generate a mirror quantum volume circuit with the given number of qubits and + depth. + + The generated circuit consists of a quantum volume circuit upto `depth/2` layers + followed by an inverse of the quantum volume portion upto `depth/2`. + + The output bit-string is always supposed to be a string of zeroes. + + Args: + num_qubits: The number of qubits in the generated circuit. + depth: The number of layers in the generated circuit. + decompose: Recursively decomposes the randomly sampled (numerical) + unitary matrix gates into simpler gates. + seed: Seed for generating random circuit. + return_type: String which specifies the type of the returned + circuits. See the keys of ``mitiq.SUPPORTED_PROGRAM_TYPES`` + for options. If ``None``, the returned circuits have type + ``cirq.Circuit``. + + Returns: + A quantum volume circuit acting on ``num_qubits`` qubits. + A list of the bitstrings for the returned circuit. + """ + first_half_depth = int(depth/2) + random_option = random.RandomState(seed) + + circ = cirq.Circuit() + qv_half = generate_quantum_volume_circuit(num_qubits, first_half_depth, decompose, random_option) + mirror_qv_half = cirq.inverse(qv_half) + circ.append(qv_half, mirror_qv_half) + + return(circ) + + + + diff --git a/mitiq/benchmarks/quantum_volume_circuits.py b/mitiq/benchmarks/quantum_volume_circuits.py index 4b4781a742..afe2db6a6e 100644 --- a/mitiq/benchmarks/quantum_volume_circuits.py +++ b/mitiq/benchmarks/quantum_volume_circuits.py @@ -47,7 +47,7 @@ def generate_quantum_volume_circuit( Args: num_qubits: The number of qubits in the generated circuit. - depth: The number of qubits in the generated circuit. + depth: The number of layers in the generated circuit. decompose: Recursively decomposes the randomly sampled (numerical) unitary matrix gates into simpler gates. seed: Seed for generating random circuit. From 08a98da1588ac8c64ef807dc7ff13417e0176881 Mon Sep 17 00:00:00 2001 From: Purva Thakre Date: Fri, 19 May 2023 08:07:03 -0500 Subject: [PATCH 02/14] bitstring test --- ...lume_circuits.py => mirror_qv_circuits.py} | 59 +++++++++++-------- .../tests/test_mirror_qv_circuits.py | 22 +++++++ 2 files changed, 58 insertions(+), 23 deletions(-) rename mitiq/benchmarks/{mirror_quantum_volume_circuits.py => mirror_qv_circuits.py} (58%) create mode 100644 mitiq/benchmarks/tests/test_mirror_qv_circuits.py diff --git a/mitiq/benchmarks/mirror_quantum_volume_circuits.py b/mitiq/benchmarks/mirror_qv_circuits.py similarity index 58% rename from mitiq/benchmarks/mirror_quantum_volume_circuits.py rename to mitiq/benchmarks/mirror_qv_circuits.py index 6c960db5f1..8db2ffb5c3 100644 --- a/mitiq/benchmarks/mirror_quantum_volume_circuits.py +++ b/mitiq/benchmarks/mirror_qv_circuits.py @@ -1,21 +1,17 @@ -# Copyright (C) 2023 Unitary Fund +# Copyright (C) Unitary Fund # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# This source code is licensed under the GPL license (v3) found in the +# LICENSE file in the root directory of this source tree. """Functions to create a Mirror Quantum Volume Benchmarking circuit as defined in https://arxiv.org/abs/2303.02108.""" +from typing import Optional, Tuple, Sequence +import numpy as np + +from mitiq import QPROGRAM +from mitiq.interface import convert_from_mitiq + from mitiq.benchmarks.quantum_volume_circuits import generate_quantum_volume_circuit import cirq @@ -30,7 +26,11 @@ def generate_mirror_qv_circuit( depth. The generated circuit consists of a quantum volume circuit upto `depth/2` layers - followed by an inverse of the quantum volume portion upto `depth/2`. + followed by an inverse of the quantum volume portion upto `depth/2` when `depth` + is an even number. + + When `depth` is odd, the layers will be chnaged to `depth+1`. + The output bit-string is always supposed to be a string of zeroes. @@ -49,16 +49,29 @@ def generate_mirror_qv_circuit( A quantum volume circuit acting on ``num_qubits`` qubits. A list of the bitstrings for the returned circuit. """ + + if depth%2 !=0: + depth = depth + 1 + else: + depth = depth first_half_depth = int(depth/2) - random_option = random.RandomState(seed) circ = cirq.Circuit() - qv_half = generate_quantum_volume_circuit(num_qubits, first_half_depth, decompose, random_option) - mirror_qv_half = cirq.inverse(qv_half) - circ.append(qv_half, mirror_qv_half) - - return(circ) - - - + qv_half = generate_quantum_volume_circuit(num_qubits, first_half_depth, seed=seed, decompose=decompose) + mirror_qv_half = cirq.inverse(qv_half[0]) + circ.append(qv_half[0], mirror_qv_half) + + #un-squash circuit moments + output_circ = cirq.Circuit() + output_ops = list(circ.all_operations()) + for i in output_ops: + output_circ.append(i, strategy=cirq.InsertStrategy.NEW) + + + # get the bitstring + circ_with_measurements = output_circ + cirq.measure(output_circ.all_qubits()) + simulate_result = cirq.Simulator().run(circ_with_measurements) + bitstring = list(simulate_result.measurements.values())[0][0].tolist() + + return(output_circ, bitstring) \ No newline at end of file diff --git a/mitiq/benchmarks/tests/test_mirror_qv_circuits.py b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py new file mode 100644 index 0000000000..5908c35bea --- /dev/null +++ b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py @@ -0,0 +1,22 @@ +# Copyright (C) Unitary Fund +# +# This source code is licensed under the GPL license (v3) found in the +# LICENSE file in the root directory of this source tree. + +"""Tests for mirror quantum volume circuits.""" + +import pytest +import cirq + +from mitiq.benchmarks.mirror_qv_circuits import generate_mirror_qv_circuit + +def test_generate_mirror_qv_circuit_bitstring(): + test_circ, _ = generate_mirror_qv_circuit(4, 3) + bit_test= cirq.Simulator().run(test_circ, repetitions=1000) + test_bitstring = list(bit_test.measurements.values())[0][0].tolist() + expected_bitstring = [0] * 4 + assert test_bitstring == expected_bitstring + + + + From 56be748216929bd43432014a30dbbee8c9a00c5c Mon Sep 17 00:00:00 2001 From: Purva Thakre Date: Fri, 19 May 2023 08:28:27 -0500 Subject: [PATCH 03/14] test change --- mitiq/benchmarks/mirror_qv_circuits.py | 27 +++++++------------ .../tests/test_mirror_qv_circuits.py | 2 +- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/mitiq/benchmarks/mirror_qv_circuits.py b/mitiq/benchmarks/mirror_qv_circuits.py index 8db2ffb5c3..bbe26cb21d 100644 --- a/mitiq/benchmarks/mirror_qv_circuits.py +++ b/mitiq/benchmarks/mirror_qv_circuits.py @@ -10,6 +10,7 @@ import numpy as np from mitiq import QPROGRAM +from mitiq import Bitstring from mitiq.interface import convert_from_mitiq from mitiq.benchmarks.quantum_volume_circuits import generate_quantum_volume_circuit @@ -50,28 +51,18 @@ def generate_mirror_qv_circuit( A list of the bitstrings for the returned circuit. """ - if depth%2 !=0: - depth = depth + 1 - else: - depth = depth - first_half_depth = int(depth/2) - - circ = cirq.Circuit() - qv_half = generate_quantum_volume_circuit(num_qubits, first_half_depth, seed=seed, decompose=decompose) - mirror_qv_half = cirq.inverse(qv_half[0]) - circ.append(qv_half[0], mirror_qv_half) + first_half_depth = depth - #un-squash circuit moments - output_circ = cirq.Circuit() - output_ops = list(circ.all_operations()) - for i in output_ops: - output_circ.append(i, strategy=cirq.InsertStrategy.NEW) - + qv_half_circ, _ = generate_quantum_volume_circuit(num_qubits, first_half_depth, seed=seed, decompose=decompose) + mirror_half_circ = cirq.inverse(half_circ) + circ = qv_half_circ + mirror_half_circ + circ_with_mes = circ + cirq.measure(circ.all_qubits()) + # get the bitstring - circ_with_measurements = output_circ + cirq.measure(output_circ.all_qubits()) + circ_with_measurements = circ + cirq.measure(circ.all_qubits()) simulate_result = cirq.Simulator().run(circ_with_measurements) bitstring = list(simulate_result.measurements.values())[0][0].tolist() - return(output_circ, bitstring) \ No newline at end of file + return(circ, bitstring) \ No newline at end of file diff --git a/mitiq/benchmarks/tests/test_mirror_qv_circuits.py b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py index 5908c35bea..347978a5ab 100644 --- a/mitiq/benchmarks/tests/test_mirror_qv_circuits.py +++ b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py @@ -12,7 +12,7 @@ def test_generate_mirror_qv_circuit_bitstring(): test_circ, _ = generate_mirror_qv_circuit(4, 3) - bit_test= cirq.Simulator().run(test_circ, repetitions=1000) + bit_test= cirq.Simulator().run(test_circ + cirq.measure(test_circ.all_qubits()), repetitions=1000) test_bitstring = list(bit_test.measurements.values())[0][0].tolist() expected_bitstring = [0] * 4 assert test_bitstring == expected_bitstring From 290519a75c58f03064394ab576ba730f7f22e339 Mon Sep 17 00:00:00 2001 From: Purva Thakre Date: Fri, 19 May 2023 08:35:26 -0500 Subject: [PATCH 04/14] style format --- mitiq/benchmarks/mirror_qv_circuits.py | 40 ++++++++++--------- .../tests/test_mirror_qv_circuits.py | 13 +++--- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/mitiq/benchmarks/mirror_qv_circuits.py b/mitiq/benchmarks/mirror_qv_circuits.py index bbe26cb21d..033396b960 100644 --- a/mitiq/benchmarks/mirror_qv_circuits.py +++ b/mitiq/benchmarks/mirror_qv_circuits.py @@ -7,15 +7,18 @@ as defined in https://arxiv.org/abs/2303.02108.""" from typing import Optional, Tuple, Sequence -import numpy as np + from mitiq import QPROGRAM from mitiq import Bitstring -from mitiq.interface import convert_from_mitiq -from mitiq.benchmarks.quantum_volume_circuits import generate_quantum_volume_circuit + +from mitiq.benchmarks.quantum_volume_circuits import ( + generate_quantum_volume_circuit, +) import cirq + def generate_mirror_qv_circuit( num_qubits: int, depth: int, @@ -23,17 +26,17 @@ def generate_mirror_qv_circuit( seed: Optional[int] = None, return_type: Optional[str] = None, ) -> Tuple[QPROGRAM, Sequence[Bitstring]]: - """Generate a mirror quantum volume circuit with the given number of qubits and - depth. + """Generate a mirror quantum volume circuit with the given number of qubits + and depth. + + The generated circuit consists of a quantum volume circuit upto `depth/2` + layers followed by an inverse of the quantum volume portion upto `depth/2` + when `depth` is an even number. - The generated circuit consists of a quantum volume circuit upto `depth/2` layers - followed by an inverse of the quantum volume portion upto `depth/2` when `depth` - is an even number. - When `depth` is odd, the layers will be chnaged to `depth+1`. - - The output bit-string is always supposed to be a string of zeroes. + + The output bit-string is always supposed to be a string of zeroes. Args: num_qubits: The number of qubits in the generated circuit. @@ -50,19 +53,18 @@ def generate_mirror_qv_circuit( A quantum volume circuit acting on ``num_qubits`` qubits. A list of the bitstrings for the returned circuit. """ - + first_half_depth = depth - - qv_half_circ, _ = generate_quantum_volume_circuit(num_qubits, first_half_depth, seed=seed, decompose=decompose) - mirror_half_circ = cirq.inverse(half_circ) + + qv_half_circ, _ = generate_quantum_volume_circuit( + num_qubits, first_half_depth, seed=seed, decompose=decompose + ) + mirror_half_circ = cirq.inverse(qv_half_circ) circ = qv_half_circ + mirror_half_circ - circ_with_mes = circ + cirq.measure(circ.all_qubits()) - # get the bitstring circ_with_measurements = circ + cirq.measure(circ.all_qubits()) simulate_result = cirq.Simulator().run(circ_with_measurements) bitstring = list(simulate_result.measurements.values())[0][0].tolist() - - return(circ, bitstring) \ No newline at end of file + return (circ, bitstring) diff --git a/mitiq/benchmarks/tests/test_mirror_qv_circuits.py b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py index 347978a5ab..9c14732d2c 100644 --- a/mitiq/benchmarks/tests/test_mirror_qv_circuits.py +++ b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py @@ -5,18 +5,17 @@ """Tests for mirror quantum volume circuits.""" -import pytest + import cirq from mitiq.benchmarks.mirror_qv_circuits import generate_mirror_qv_circuit + def test_generate_mirror_qv_circuit_bitstring(): - test_circ, _ = generate_mirror_qv_circuit(4, 3) - bit_test= cirq.Simulator().run(test_circ + cirq.measure(test_circ.all_qubits()), repetitions=1000) + test_circ, _ = generate_mirror_qv_circuit(4, 3) + bit_test = cirq.Simulator().run( + test_circ + cirq.measure(test_circ.all_qubits()), repetitions=1000 + ) test_bitstring = list(bit_test.measurements.values())[0][0].tolist() expected_bitstring = [0] * 4 assert test_bitstring == expected_bitstring - - - - From 121c4143a25dc1c756e8e2005481d7d992be6137 Mon Sep 17 00:00:00 2001 From: Purva Thakre Date: Fri, 19 May 2023 12:05:25 -0500 Subject: [PATCH 05/14] odd/even depth --- mitiq/benchmarks/mirror_qv_circuits.py | 6 +++++- mitiq/benchmarks/tests/test_mirror_qv_circuits.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/mitiq/benchmarks/mirror_qv_circuits.py b/mitiq/benchmarks/mirror_qv_circuits.py index 033396b960..7dd8707399 100644 --- a/mitiq/benchmarks/mirror_qv_circuits.py +++ b/mitiq/benchmarks/mirror_qv_circuits.py @@ -54,7 +54,11 @@ def generate_mirror_qv_circuit( A list of the bitstrings for the returned circuit. """ - first_half_depth = depth + if depth%2 ==0: + first_half_depth = int(depth/2) + else: + first_half_depth = int((depth+1)/2) + qv_half_circ, _ = generate_quantum_volume_circuit( num_qubits, first_half_depth, seed=seed, decompose=decompose diff --git a/mitiq/benchmarks/tests/test_mirror_qv_circuits.py b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py index 9c14732d2c..552dabdab5 100644 --- a/mitiq/benchmarks/tests/test_mirror_qv_circuits.py +++ b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py @@ -12,6 +12,7 @@ def test_generate_mirror_qv_circuit_bitstring(): + # odd depth layers test_circ, _ = generate_mirror_qv_circuit(4, 3) bit_test = cirq.Simulator().run( test_circ + cirq.measure(test_circ.all_qubits()), repetitions=1000 @@ -19,3 +20,12 @@ def test_generate_mirror_qv_circuit_bitstring(): test_bitstring = list(bit_test.measurements.values())[0][0].tolist() expected_bitstring = [0] * 4 assert test_bitstring == expected_bitstring + + # even depth layers + test_circ, _ = generate_mirror_qv_circuit(4, 4) + bit_test = cirq.Simulator().run( + test_circ + cirq.measure(test_circ.all_qubits()), repetitions=1000 + ) + test_bitstring = list(bit_test.measurements.values())[0][0].tolist() + expected_bitstring = [0] * 4 + assert test_bitstring == expected_bitstring From 2bf73b49a1a1ef00c3fda10a844b6b5d2ffec615 Mon Sep 17 00:00:00 2001 From: Purva Thakre Date: Fri, 19 May 2023 16:40:34 -0500 Subject: [PATCH 06/14] mypy --- mitiq/benchmarks/mirror_qv_circuits.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/mitiq/benchmarks/mirror_qv_circuits.py b/mitiq/benchmarks/mirror_qv_circuits.py index 7dd8707399..715abe4b3a 100644 --- a/mitiq/benchmarks/mirror_qv_circuits.py +++ b/mitiq/benchmarks/mirror_qv_circuits.py @@ -11,6 +11,7 @@ from mitiq import QPROGRAM from mitiq import Bitstring +from mitiq.interface.conversions import convert_to_mitiq from mitiq.benchmarks.quantum_volume_circuits import ( @@ -59,11 +60,17 @@ def generate_mirror_qv_circuit( else: first_half_depth = int((depth+1)/2) - - qv_half_circ, _ = generate_quantum_volume_circuit( + qv_generated, _ = generate_quantum_volume_circuit( num_qubits, first_half_depth, seed=seed, decompose=decompose ) - mirror_half_circ = cirq.inverse(qv_half_circ) + qv_half_circ, _ = convert_to_mitiq(qv_generated) + + mirror_half_circ = cirq.Circuit() + qv_half_ops = list(qv_half_circ.all_operations()) + for i in range(len(qv_half_ops))[::-1]: + op_inverse = cirq.inverse(qv_half_ops[i]) + mirror_half_circ.append(op_inverse, strategy=cirq.InsertStrategy.NEW) + circ = qv_half_circ + mirror_half_circ # get the bitstring From 9cb259dfb92359e3a9b1b71bd633ef18275f12b6 Mon Sep 17 00:00:00 2001 From: Purva Thakre Date: Fri, 19 May 2023 16:41:48 -0500 Subject: [PATCH 07/14] format --- mitiq/benchmarks/mirror_qv_circuits.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mitiq/benchmarks/mirror_qv_circuits.py b/mitiq/benchmarks/mirror_qv_circuits.py index 715abe4b3a..a0e90bd15c 100644 --- a/mitiq/benchmarks/mirror_qv_circuits.py +++ b/mitiq/benchmarks/mirror_qv_circuits.py @@ -55,11 +55,11 @@ def generate_mirror_qv_circuit( A list of the bitstrings for the returned circuit. """ - if depth%2 ==0: - first_half_depth = int(depth/2) + if depth % 2 == 0: + first_half_depth = int(depth / 2) else: - first_half_depth = int((depth+1)/2) - + first_half_depth = int((depth + 1) / 2) + qv_generated, _ = generate_quantum_volume_circuit( num_qubits, first_half_depth, seed=seed, decompose=decompose ) From 71ad3857a97b064b10611dd124f1d7699c9e2fde Mon Sep 17 00:00:00 2001 From: Purva Thakre Date: Fri, 19 May 2023 18:06:39 -0500 Subject: [PATCH 08/14] change generate circuit test --- mitiq/benchmarks/mirror_qv_circuits.py | 4 +++ .../tests/test_mirror_qv_circuits.py | 27 +++++++++++-------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/mitiq/benchmarks/mirror_qv_circuits.py b/mitiq/benchmarks/mirror_qv_circuits.py index a0e90bd15c..2de002d23b 100644 --- a/mitiq/benchmarks/mirror_qv_circuits.py +++ b/mitiq/benchmarks/mirror_qv_circuits.py @@ -54,6 +54,10 @@ def generate_mirror_qv_circuit( A quantum volume circuit acting on ``num_qubits`` qubits. A list of the bitstrings for the returned circuit. """ + if depth <= 0: + raise ValueError( + "{} is invalid for the generated circuit depth.", depth + ) if depth % 2 == 0: first_half_depth = int(depth / 2) diff --git a/mitiq/benchmarks/tests/test_mirror_qv_circuits.py b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py index 552dabdab5..a7c733567c 100644 --- a/mitiq/benchmarks/tests/test_mirror_qv_circuits.py +++ b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py @@ -7,25 +7,30 @@ import cirq +import pytest from mitiq.benchmarks.mirror_qv_circuits import generate_mirror_qv_circuit -def test_generate_mirror_qv_circuit_bitstring(): - # odd depth layers - test_circ, _ = generate_mirror_qv_circuit(4, 3) - bit_test = cirq.Simulator().run( - test_circ + cirq.measure(test_circ.all_qubits()), repetitions=1000 - ) - test_bitstring = list(bit_test.measurements.values())[0][0].tolist() - expected_bitstring = [0] * 4 - assert test_bitstring == expected_bitstring +@pytest.mark.parametrize( + "depth_num", + [1, 2, 3, 4, 5, 6, 7, 8], +) +def test_generate_mirror_qv_circuit(depth_num): + test_circ, _ = generate_mirror_qv_circuit(4, depth_num) - # even depth layers - test_circ, _ = generate_mirror_qv_circuit(4, 4) + # check bitstring is all 0's bit_test = cirq.Simulator().run( test_circ + cirq.measure(test_circ.all_qubits()), repetitions=1000 ) test_bitstring = list(bit_test.measurements.values())[0][0].tolist() expected_bitstring = [0] * 4 assert test_bitstring == expected_bitstring + + +def test_bad_depth_number(): + for n in (-1, 0): + with pytest.raises( + ValueError, match="{} is invalid for the generated circuit depth." + ): + generate_mirror_qv_circuit(3, n) From 4eb4af62865361c43809011a6583d3286c53590c Mon Sep 17 00:00:00 2001 From: Purva Thakre Date: Sat, 20 May 2023 20:41:14 -0500 Subject: [PATCH 09/14] change qv tests to mirror_qv --- mitiq/benchmarks/mirror_qv_circuits.py | 9 ++++-- .../tests/test_mirror_qv_circuits.py | 32 +++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/mitiq/benchmarks/mirror_qv_circuits.py b/mitiq/benchmarks/mirror_qv_circuits.py index 2de002d23b..b66f7b27e7 100644 --- a/mitiq/benchmarks/mirror_qv_circuits.py +++ b/mitiq/benchmarks/mirror_qv_circuits.py @@ -11,7 +11,7 @@ from mitiq import QPROGRAM from mitiq import Bitstring -from mitiq.interface.conversions import convert_to_mitiq +from mitiq.interface.conversions import convert_to_mitiq, convert_from_mitiq from mitiq.benchmarks.quantum_volume_circuits import ( @@ -82,4 +82,9 @@ def generate_mirror_qv_circuit( simulate_result = cirq.Simulator().run(circ_with_measurements) bitstring = list(simulate_result.measurements.values())[0][0].tolist() - return (circ, bitstring) + if decompose: + # Decompose random unitary gates into simpler gates. + circ = cirq.Circuit(cirq.decompose(circ)) + + return_type = "cirq" if not return_type else return_type + return convert_from_mitiq(circ, return_type), bitstring diff --git a/mitiq/benchmarks/tests/test_mirror_qv_circuits.py b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py index a7c733567c..cc5352ab76 100644 --- a/mitiq/benchmarks/tests/test_mirror_qv_circuits.py +++ b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py @@ -10,6 +10,7 @@ import pytest from mitiq.benchmarks.mirror_qv_circuits import generate_mirror_qv_circuit +from mitiq import SUPPORTED_PROGRAM_TYPES @pytest.mark.parametrize( @@ -34,3 +35,34 @@ def test_bad_depth_number(): ValueError, match="{} is invalid for the generated circuit depth." ): generate_mirror_qv_circuit(3, n) + + +@pytest.mark.parametrize("return_type", SUPPORTED_PROGRAM_TYPES.keys()) +def test_volume_conversion(return_type): + circuit, _ = generate_mirror_qv_circuit(4, 3, return_type=return_type) + assert return_type in circuit.__module__ + + +def test_generate_model_circuit_with_seed(): + """Test that a model circuit is determined by its seed.""" + circuit_1, _ = generate_mirror_qv_circuit(4, 3, seed=1) + circuit_2, _ = generate_mirror_qv_circuit(4, 3, seed=1) + circuit_3, _ = generate_mirror_qv_circuit(4, 3, seed=2) + + assert circuit_1 == circuit_2 + assert circuit_2 != circuit_3 + + +def test_circuit_decomposition(): + """Test that decomposed circuit consists of gates in default cirq gatest. + As defined in cirq.protocols.decompose_protocol, this default gateset is + ops.XPowGate, + ops.YPowGate, + ops.ZPowGate, + ops.CZPowGate, + ops.MeasurementGate, + ops.GlobalPhaseGate + """ + circuit, _ = generate_mirror_qv_circuit(4, 3, decompose=True) + for op in [operation for moment in circuit for operation in moment]: + assert op in cirq.protocols.decompose_protocol.DECOMPOSE_TARGET_GATESET From 6e868b04f6b4608bcbf382fbcef1d378c9aa388d Mon Sep 17 00:00:00 2001 From: Purva Thakre Date: Sat, 20 May 2023 20:55:28 -0500 Subject: [PATCH 10/14] ref api doc --- docs/source/apidoc.md | 6 ++++++ docs/source/refs.bib | 11 +++++++++++ mitiq/benchmarks/mirror_qv_circuits.py | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/source/apidoc.md b/docs/source/apidoc.md index e6f1eda93c..f21c62640a 100644 --- a/docs/source/apidoc.md +++ b/docs/source/apidoc.md @@ -47,6 +47,12 @@ :members: ``` +### W State Circuits +```{eval-rst} +.. automodule:: mitiq.benchmarks.mirror_qv_circuits.py + :members: +``` + ## Circuit types and result types ```{eval-rst} diff --git a/docs/source/refs.bib b/docs/source/refs.bib index 36cdc2945e..07d641e34d 100644 --- a/docs/source/refs.bib +++ b/docs/source/refs.bib @@ -1,6 +1,17 @@ # Style for keys: Lastname_YYYY_PRL, # Letter A + +@misc{Amico_2023_arxiv, + author = {{Amico}, Mirko and {Zhang}, Helena and {Jurcevic}, Petar and {Bishop}, Lev S. and {Nation}, Paul and {Wack}, Andrew and {McKay}, David C.}, + title = {{Defining Standard Strategies for Quantum Benchmarks}}, + year = {2023}, + month = {mar}, + archiveprefix = {arXiv}, + eprint = {2303.02108}, + primaryclass = {quant-ph}, +} + # Letter B @article{Bonet_2018_PRA, diff --git a/mitiq/benchmarks/mirror_qv_circuits.py b/mitiq/benchmarks/mirror_qv_circuits.py index b66f7b27e7..05bc526b12 100644 --- a/mitiq/benchmarks/mirror_qv_circuits.py +++ b/mitiq/benchmarks/mirror_qv_circuits.py @@ -28,7 +28,7 @@ def generate_mirror_qv_circuit( return_type: Optional[str] = None, ) -> Tuple[QPROGRAM, Sequence[Bitstring]]: """Generate a mirror quantum volume circuit with the given number of qubits - and depth. + and depth as defined in :cite:`Amico_2023_arxiv`. The generated circuit consists of a quantum volume circuit upto `depth/2` layers followed by an inverse of the quantum volume portion upto `depth/2` From 721386f74f34ed8bdcdb76cdb4406b4e293949a9 Mon Sep 17 00:00:00 2001 From: Purva Thakre Date: Sat, 20 May 2023 21:34:50 -0500 Subject: [PATCH 11/14] api typo --- docs/source/apidoc.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/apidoc.md b/docs/source/apidoc.md index f21c62640a..0d000a3457 100644 --- a/docs/source/apidoc.md +++ b/docs/source/apidoc.md @@ -47,9 +47,9 @@ :members: ``` -### W State Circuits +### Mirror Quantum Volume Circuits ```{eval-rst} -.. automodule:: mitiq.benchmarks.mirror_qv_circuits.py +.. automodule:: mitiq.benchmarks.mirror_qv_circuits :members: ``` From 76763412f81f45695c5198084142755008bf2808 Mon Sep 17 00:00:00 2001 From: Purva Thakre <66048318+purva-thakre@users.noreply.github.com> Date: Thu, 1 Jun 2023 22:40:47 -0500 Subject: [PATCH 12/14] Apply suggestions from code review Co-authored-by: Misty Wahl <82074193+Misty-W@users.noreply.github.com> --- mitiq/benchmarks/mirror_qv_circuits.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mitiq/benchmarks/mirror_qv_circuits.py b/mitiq/benchmarks/mirror_qv_circuits.py index 05bc526b12..c63d9a65bf 100644 --- a/mitiq/benchmarks/mirror_qv_circuits.py +++ b/mitiq/benchmarks/mirror_qv_circuits.py @@ -30,14 +30,14 @@ def generate_mirror_qv_circuit( """Generate a mirror quantum volume circuit with the given number of qubits and depth as defined in :cite:`Amico_2023_arxiv`. - The generated circuit consists of a quantum volume circuit upto `depth/2` - layers followed by an inverse of the quantum volume portion upto `depth/2` + The generated circuit consists of a quantum volume circuit up to `depth/2` + layers followed by an inverse of the quantum volume portion up to `depth/2` when `depth` is an even number. - When `depth` is odd, the layers will be chnaged to `depth+1`. + When `depth` is odd, the layers will be changed to `depth+1`. - The output bit-string is always supposed to be a string of zeroes. + The ideal output bit-string is a string of zeroes. Args: num_qubits: The number of qubits in the generated circuit. From b8a3f2fac86a183259e5e54be4608fcf6b641885 Mon Sep 17 00:00:00 2001 From: Purva Thakre Date: Fri, 2 Jun 2023 10:42:14 -0500 Subject: [PATCH 13/14] remove bitstring --- mitiq/benchmarks/mirror_qv_circuits.py | 12 +++--------- mitiq/benchmarks/tests/test_mirror_qv_circuits.py | 15 +++++++++------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/mitiq/benchmarks/mirror_qv_circuits.py b/mitiq/benchmarks/mirror_qv_circuits.py index c63d9a65bf..e0d2b8f676 100644 --- a/mitiq/benchmarks/mirror_qv_circuits.py +++ b/mitiq/benchmarks/mirror_qv_circuits.py @@ -6,11 +6,10 @@ """Functions to create a Mirror Quantum Volume Benchmarking circuit as defined in https://arxiv.org/abs/2303.02108.""" -from typing import Optional, Tuple, Sequence +from typing import Optional from mitiq import QPROGRAM -from mitiq import Bitstring from mitiq.interface.conversions import convert_to_mitiq, convert_from_mitiq @@ -26,7 +25,7 @@ def generate_mirror_qv_circuit( decompose: bool = False, seed: Optional[int] = None, return_type: Optional[str] = None, -) -> Tuple[QPROGRAM, Sequence[Bitstring]]: +) -> QPROGRAM: """Generate a mirror quantum volume circuit with the given number of qubits and depth as defined in :cite:`Amico_2023_arxiv`. @@ -77,14 +76,9 @@ def generate_mirror_qv_circuit( circ = qv_half_circ + mirror_half_circ - # get the bitstring - circ_with_measurements = circ + cirq.measure(circ.all_qubits()) - simulate_result = cirq.Simulator().run(circ_with_measurements) - bitstring = list(simulate_result.measurements.values())[0][0].tolist() - if decompose: # Decompose random unitary gates into simpler gates. circ = cirq.Circuit(cirq.decompose(circ)) return_type = "cirq" if not return_type else return_type - return convert_from_mitiq(circ, return_type), bitstring + return convert_from_mitiq(circ, return_type) diff --git a/mitiq/benchmarks/tests/test_mirror_qv_circuits.py b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py index cc5352ab76..1e10f19291 100644 --- a/mitiq/benchmarks/tests/test_mirror_qv_circuits.py +++ b/mitiq/benchmarks/tests/test_mirror_qv_circuits.py @@ -18,7 +18,8 @@ [1, 2, 3, 4, 5, 6, 7, 8], ) def test_generate_mirror_qv_circuit(depth_num): - test_circ, _ = generate_mirror_qv_circuit(4, depth_num) + """Check the circuit output.""" + test_circ = generate_mirror_qv_circuit(4, depth_num) # check bitstring is all 0's bit_test = cirq.Simulator().run( @@ -30,6 +31,7 @@ def test_generate_mirror_qv_circuit(depth_num): def test_bad_depth_number(): + """Check if an unacceptable depth number rasies an error.""" for n in (-1, 0): with pytest.raises( ValueError, match="{} is invalid for the generated circuit depth." @@ -39,15 +41,16 @@ def test_bad_depth_number(): @pytest.mark.parametrize("return_type", SUPPORTED_PROGRAM_TYPES.keys()) def test_volume_conversion(return_type): - circuit, _ = generate_mirror_qv_circuit(4, 3, return_type=return_type) + """Check generated circuit's return type.""" + circuit = generate_mirror_qv_circuit(4, 3, return_type=return_type) assert return_type in circuit.__module__ def test_generate_model_circuit_with_seed(): """Test that a model circuit is determined by its seed.""" - circuit_1, _ = generate_mirror_qv_circuit(4, 3, seed=1) - circuit_2, _ = generate_mirror_qv_circuit(4, 3, seed=1) - circuit_3, _ = generate_mirror_qv_circuit(4, 3, seed=2) + circuit_1 = generate_mirror_qv_circuit(4, 3, seed=1) + circuit_2 = generate_mirror_qv_circuit(4, 3, seed=1) + circuit_3 = generate_mirror_qv_circuit(4, 3, seed=2) assert circuit_1 == circuit_2 assert circuit_2 != circuit_3 @@ -63,6 +66,6 @@ def test_circuit_decomposition(): ops.MeasurementGate, ops.GlobalPhaseGate """ - circuit, _ = generate_mirror_qv_circuit(4, 3, decompose=True) + circuit = generate_mirror_qv_circuit(4, 3, decompose=True) for op in [operation for moment in circuit for operation in moment]: assert op in cirq.protocols.decompose_protocol.DECOMPOSE_TARGET_GATESET From 838e5e61daa8aeb50e829e4b1b1570bc0afcaf38 Mon Sep 17 00:00:00 2001 From: Purva Thakre <66048318+purva-thakre@users.noreply.github.com> Date: Wed, 7 Jun 2023 15:34:45 -0500 Subject: [PATCH 14/14] Update mitiq/benchmarks/mirror_qv_circuits.py Co-authored-by: Andrea Mari --- mitiq/benchmarks/mirror_qv_circuits.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mitiq/benchmarks/mirror_qv_circuits.py b/mitiq/benchmarks/mirror_qv_circuits.py index e0d2b8f676..a6578520d5 100644 --- a/mitiq/benchmarks/mirror_qv_circuits.py +++ b/mitiq/benchmarks/mirror_qv_circuits.py @@ -51,7 +51,6 @@ def generate_mirror_qv_circuit( Returns: A quantum volume circuit acting on ``num_qubits`` qubits. - A list of the bitstrings for the returned circuit. """ if depth <= 0: raise ValueError(