Skip to content

Commit 9fc388c

Browse files
tanujkhattarrht
authored andcommitted
Fix asv setup and add benchmarks for circuit construction (quantumlib#5845)
Part of quantumlib#5833 and quantumlib#3840 Fixes quantumlib#4695 Running the benchmarks on master currently gives the following output for circuit construction benchmarks: ```bash [ 75.00%] ··· circuit_construction.NDCircuit.time_circuit_construction ok [ 75.00%] ··· ===================== ============= ============= ============= ============ -- Depth(D) --------------------- ------------------------------------------------------ Number of Qubits(N) 1 10 100 1000 ===================== ============= ============= ============= ============ 1 38.3±0.2μs 235±3μs 2.12±0.01ms 21.2±0.1ms 10 109±0.6μs 901±4μs 8.73±0.02ms 89.2±0.2ms 100 770±4μs 7.32±0.02ms 74.4±0.4ms 764±9ms 1000 7.30±0.02ms 72.0±0.2ms 739±4ms 7.57±0.03s ===================== ============= ============= ============= ============ [ 87.50%] ··· circuit_construction.SurfaceCode_Rotated_Memory_Z.time_surface_code_circuit_construction ok [ 87.50%] ··· ========== ============= distance ---------- ------------- 3 1.97±0.01ms 5 7.67±0.07ms 7 22.6±0.1ms 9 59.8±0.4ms 11 122±0.7ms 13 232±1ms 15 407±2ms 17 701±2ms 19 1.09±0.02s 21 1.60±0.02s 23 2.25±0.01s 25 3.24±0.06s ========== ============= [100.00%] ··· circuit_construction.SurfaceCode_Rotated_Memory_Z.track_surface_code_circuit_operation_count ok [100.00%] ··· ========== ========= distance ---------- --------- 3 369 5 3225 7 12985 9 36369 11 82401 13 162409 15 290025 17 481185 19 754129 21 1129401 23 1629849 25 2280625 ========== ========= ``` Note that the circuit construction for d21 surface code takes only 1.6 seconds. This is because we are constructing moment-by-moment instead of appending operations (in which case the earliest strategy takes a significant amount of time). Going forward, we should add more benchmarks for different use cases. Once this is merged, https://cirq-infra.uc.r.appspot.com/ would be updated with the new benchmarks and we can see the improvement / regressions we make to circuit construction performance over time / commits. cc @dabacon @maffoo @dstrain115
1 parent ea2fd2e commit 9fc388c

File tree

4 files changed

+139
-69
lines changed

4 files changed

+139
-69
lines changed

asv.conf.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{
2-
// See https://asv.readthedocs.io/en/stable/asv.conf.json.html for documentation.
32
"version": 1,
43
"project": "Cirq",
54
"project_url": "https://quantumai.google/cirq",
65
"repo": ".",
6+
"repo_subdir": "cirq-core/",
77
"branches": ["master"],
88
"dvcs": "git",
99
"environment_type": "virtualenv",
1010
"show_commit_url": "https://github.com/quantumlib/Cirq/commit/",
11-
"pythons": ["3.7", "3.8"],
11+
"pythons": ["3.8"],
1212
"benchmark_dir": "benchmarks",
1313
"env_dir": ".asv/env",
1414
"results_dir": ".asv/results",

benchmarks/bench_examples.py

-63
This file was deleted.

benchmarks/bench_linalg_decompositions.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,5 @@ def time_kak_decomposition(target):
3737
cirq.kak_decomposition(target)
3838

3939

40-
time_kak_decomposition.params = [ # type: ignore
41-
[np.eye(4), SWAP, SWAP * 1j, CZ, CNOT, SWAP.dot(CZ)]
42-
+ [cirq.testing.random_unitary(4) for _ in range(10)]
43-
]
40+
time_kak_decomposition.params = [cirq.IdentityGate(2), cirq.SWAP, cirq.ISWAP, cirq.CZ, cirq.CNOT]
4441
time_kak_decomposition.param_names = ["gate"] # type: ignore

benchmarks/circuit_construction.py

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# Copyright 2022 The Cirq Developers
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
import itertools
15+
from typing import Tuple, Set, Sequence
16+
17+
import cirq
18+
19+
20+
def rotated_surface_code_memory_z_cycle(
21+
data_qubits: Set[cirq.Qid],
22+
z_measure_qubits: Set[cirq.Qid],
23+
x_measure_qubits: Set[cirq.Qid],
24+
z_order: Sequence[Tuple[int, int]],
25+
x_order: Sequence[Tuple[int, int]],
26+
) -> cirq.Circuit:
27+
"""Constructs a circuit for a single round of rotated memory Z surface code.
28+
29+
Args:
30+
data_qubits: data qubits for the surface code patch.
31+
z_measure_qubits: measure qubits to measure Z stabilizers for surface code patch.
32+
x_measure_qubits: measure qubits to measure X stabilizers for surface code patch.
33+
z_order: Specifies the order in which the 2/4 data qubit neighbours of a Z measure qubit
34+
should be processed.
35+
x_order: Specifies the order in which the 2/4 data qubit neighbours of a X measure qubit
36+
should be processed.
37+
38+
Returns:
39+
A `cirq.Circuit` for a single round of rotated memory Z surface code cycle.
40+
"""
41+
42+
circuit = cirq.Circuit()
43+
circuit += cirq.Moment([cirq.H(q) for q in x_measure_qubits])
44+
for k in range(4):
45+
op_list = []
46+
for measure_qubits, add, is_x in [
47+
[x_measure_qubits, x_order[k], True],
48+
[z_measure_qubits, z_order[k], False],
49+
]:
50+
for q_meas in measure_qubits:
51+
q_data = q_meas + add
52+
if q_data in data_qubits:
53+
op_list.append(cirq.CNOT(q_meas, q_data) if is_x else cirq.CNOT(q_data, q_meas))
54+
circuit += cirq.Moment(op_list)
55+
circuit += cirq.Moment([cirq.H(q) for q in x_measure_qubits])
56+
circuit += cirq.Moment(cirq.measure_each(*x_measure_qubits, *z_measure_qubits))
57+
return circuit
58+
59+
60+
def surface_code_circuit(
61+
distance: int, num_rounds: int, moment_by_moment: bool = True
62+
) -> cirq.Circuit:
63+
"""Constructs a rotated memory Z surface code circuit with `distance` and `num_rounds`.
64+
65+
The circuit has `dxd` data qubits and `d ** 2 - 1` measure qubits, where `d` is the distance
66+
of surface code. For more details on rotated surface codes and qubit indexing, see figure 13
67+
https://arxiv.org/abs/1111.4022.
68+
69+
Args:
70+
distance: Distance of the surface code.
71+
num_rounds: Number of error correction rounds for memory Z experiment.
72+
moment_by_moment: If True, the circuit is constructed moment-by-moment instead of
73+
operation-by-operation. This is useful to benchmark different circuit construction
74+
patterns for the same circuit.
75+
76+
Returns:
77+
A `cirq.Circuit` for surface code memory Z experiment for `distance` and `num_rounds`.
78+
"""
79+
80+
def ndrange(*ranges: Tuple[int, ...]):
81+
return itertools.product(*[range(*r) for r in ranges])
82+
83+
data_qubits = {cirq.q(2 * x + 1, 2 * y + 1) for x, y in ndrange((distance,), (distance,))}
84+
z_measure_qubits = {
85+
cirq.q(2 * x, 2 * y) for x, y in ndrange((1, distance), (distance + 1,)) if x % 2 != y % 2
86+
}
87+
x_measure_qubits = {
88+
cirq.q(2 * x, 2 * y) for x, y in ndrange((distance + 1,), (1, distance)) if x % 2 == y % 2
89+
}
90+
x_order = [(1, 1), (1, -1), (-1, 1), (-1, -1)]
91+
z_order = [(1, 1), (-1, 1), (1, -1), (-1, -1)]
92+
surface_code_cycle = rotated_surface_code_memory_z_cycle(
93+
data_qubits, x_measure_qubits, z_measure_qubits, x_order, z_order
94+
)
95+
if moment_by_moment:
96+
return cirq.Circuit(
97+
surface_code_cycle * num_rounds, cirq.Moment(cirq.measure_each(*data_qubits))
98+
)
99+
else:
100+
return cirq.Circuit(
101+
[*surface_code_cycle.all_operations()] * num_rounds, cirq.measure_each(*data_qubits)
102+
)
103+
104+
105+
class SurfaceCodeRotatedMemoryZ:
106+
pretty_name = "Surface Code Rotated Memory-Z Benchmarks."
107+
params = [*range(3, 26, 2)]
108+
param_names = ["distance"]
109+
110+
def time_circuit_construction_moment_by_moment(self, distance: int) -> None:
111+
"""Benchmark circuit construction for Rotated Bottom-Z Surface code."""
112+
_ = surface_code_circuit(distance, distance * distance)
113+
114+
def time_circuit_construction_operations_by_operation(self, distance: int) -> None:
115+
"""Benchmark circuit construction for Rotated Bottom-Z Surface code."""
116+
_ = surface_code_circuit(distance, distance * distance, False)
117+
118+
def track_circuit_operation_count(self, distance: int) -> int:
119+
"""Benchmark operation count for Rotated Bottom-Z Surface code."""
120+
circuit = surface_code_circuit(distance, distance * distance)
121+
return sum(1 for _ in circuit.all_operations())
122+
123+
def track_circuit_depth(self, distance: int) -> int:
124+
"""Benchmark operation count for Rotated Bottom-Z Surface code."""
125+
circuit = surface_code_circuit(distance, distance * distance)
126+
return len(circuit)
127+
128+
129+
class XOnAllQubitsCircuit:
130+
pretty_name = "N * D times X gate on all qubits."
131+
params = [[1, 10, 100, 1000], [1, 10, 100, 1000]]
132+
param_names = ["Number of Qubits(N)", "Depth(D)"]
133+
134+
def time_circuit_construction(self, N: int, D: int):
135+
q = cirq.LineQubit.range(N)
136+
return cirq.Circuit(cirq.Moment(cirq.X.on_each(*q)) for _ in range(D))

0 commit comments

Comments
 (0)