Source code for cirq.experiments.google_v2_supremacy_circuit

# Copyright 2018 The Cirq Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import random
from typing import Callable, Iterable, TypeVar, cast, Sequence

from cirq.circuits import InsertStrategy
from cirq import circuits, devices, google, ops


[docs]def generate_supremacy_circuit_google_v2(qubits: Iterable[devices.GridQubit], cz_depth: int, seed: int) -> circuits.Circuit: """ Generates Google Random Circuits v2 as in github.com/sboixo/GRCS cz_v2. See also https://arxiv.org/abs/1807.10749 Args: qubits: qubit grid in which to generate the circuit. cz_depth: number of layers with CZ gates. seed: seed for the random instance. Returns: A circuit corresponding to instance inst_{n_rows}x{n_cols}_{cz_depth+1}_{seed} The mapping of qubits is cirq.GridQubit(j,k) -> q[j*n_cols+k] (as in the QASM mapping) """ non_diagonal_gates = [ops.common_gates.X**(1/2), ops.common_gates.Y**(1/2)] rand_gen = random.Random(seed).random circuit = circuits.Circuit() # Add an initial moment of Hadamards circuit.append(ops.common_gates.H(qubit) for qubit in qubits) layer_index = 0 if cz_depth: layer_index = _add_cz_layer(layer_index, circuit) # In the first moment, add T gates when possible for qubit in qubits: if not circuit.operation_at(qubit, 1): circuit.append(ops.common_gates.T(qubit), strategy=InsertStrategy.EARLIEST) for moment_index in range(2, cz_depth+1): layer_index = _add_cz_layer(layer_index, circuit) # Add single qubit gates in the same moment for qubit in qubits: if not circuit.operation_at(qubit, moment_index): last_op = circuit.operation_at(qubit, moment_index-1) if last_op: gate = cast(ops.GateOperation, last_op).gate # Add a random non diagonal gate after a CZ if gate == ops.CZ: circuit.append(_choice(rand_gen, non_diagonal_gates).on(qubit), strategy=InsertStrategy.EARLIEST) # Add a T gate after a non diagonal gate elif not gate == ops.T: circuit.append(ops.common_gates.T(qubit), strategy=InsertStrategy.EARLIEST) # Add a final moment of Hadamards circuit.append(ops.common_gates.H(qubit) for qubit in qubits) return circuit
[docs]def generate_supremacy_circuit_google_v2_grid(n_rows: int, n_cols: int, cz_depth: int, seed: int ) -> circuits.Circuit: """ Generates Google Random Circuits v2 as in github.com/sboixo/GRCS cz_v2. See also https://arxiv.org/abs/1807.10749 Args: n_rows: number of rows of a 2D lattice. n_cols: number of columns. cz_depth: number of layers with CZ gates. seed: seed for the random instance. Returns: A circuit corresponding to instance inst_{n_rows}x{n_cols}_{cz_depth+1}_{seed} The mapping of qubits is cirq.GridQubit(j,k) -> q[j*n_cols+k] (as in the QASM mapping) """ qubits = [devices.GridQubit(i, j) for i in range(n_rows) for j in range(n_cols)] return generate_supremacy_circuit_google_v2(qubits, cz_depth, seed)
[docs]def generate_supremacy_circuit_google_v2_bristlecone(n_rows: int, cz_depth: int, seed: int ) -> circuits.Circuit: """ Generates Google Random Circuits v2 in Bristlecone. See also https://arxiv.org/abs/1807.10749 Args: n_rows: number of rows in a Bristlecone lattice. Note that we do not include single qubit corners. cz_depth: number of layers with CZ gates. seed: seed for the random instance. Returns: A circuit with given size and seed. """ def get_qubits(n_rows): def count_neighbors(qubits, qubit): """Counts the qubits that the given qubit can interact with.""" possibles = [ devices.GridQubit(qubit.row + 1, qubit.col), devices.GridQubit(qubit.row - 1, qubit.col), devices.GridQubit(qubit.row, qubit.col + 1), devices.GridQubit(qubit.row, qubit.col - 1), ] return len(list(e for e in possibles if e in qubits)) assert 1 <= n_rows <= 11 max_row = n_rows - 1 dev = google.Bristlecone # we need a consistent order of qubits qubits = list(dev.qubits) qubits.sort() qubits = [q for q in qubits if q.row <= max_row and q.row + q.col < n_rows + 6 and q.row - q.col < n_rows - 5] qubits = [q for q in qubits if count_neighbors(qubits, q) > 1] return qubits qubits = get_qubits(n_rows) return generate_supremacy_circuit_google_v2(qubits, cz_depth, seed)
T = TypeVar('T') def _choice(rand_gen: Callable[[], float], sequence: Sequence[T]) -> T: """Choose a random element from a non-empty sequence. Use this instead of random.choice, with random.random(), for reproducibility """ return sequence[int(rand_gen() * len(sequence))] def _add_cz_layer(layer_index: int, circuit: circuits.Circuit) -> int: cz_layer = None while not cz_layer: qubits = cast(Iterable[devices.GridQubit], circuit.all_qubits()) cz_layer = list(_make_cz_layer(qubits, layer_index)) layer_index += 1 circuit.append(cz_layer) return layer_index def _make_cz_layer(qubits: Iterable[devices.GridQubit], layer_index: int ) -> Iterable[ops.Operation]: """ Each layer index corresponds to a shift/transpose of this CZ pattern: ●───● ● ● ●───● ● ● . . . ● ● ●───● ● ● ●───● . . . ●───● ● ● ●───● ● ● . . . ● ● ●───● ● ● ●───● . . . ●───● ● ● ●───● ● ● . . . ● ● ●───● ● ● ●───● . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Labelled edges, showing the exact index-to-CZs mapping (mod 8): ●─0─●─2─●─4─●─6─●─0─. . . 3│ 7│ 3│ 7│ 3│ ●─4─●─6─●─0─●─2─●─4─. . . 1│ 5│ 1│ 5│ 1│ ●─0─●─2─●─4─●─6─●─0─. . . 7│ 3│ 7│ 3│ 7│ ●─4─●─6─●─0─●─2─●─4─. . . 5│ 1│ 5│ 1│ 5│ ●─0─●─2─●─4─●─6─●─0─. . . 3│ 7│ 3│ 7│ 3│ . . . . . . . . . . . . . . . . . . Note that, for small devices, some layers will be empty because the layer only contains edges not present on the device. """ # map to an internal layer index to match the cycle order of public circuits layer_index_map = [0, 3, 2, 1, 4, 7, 6, 5] internal_layer_index = layer_index_map[layer_index % 8] dir_row = internal_layer_index % 2 dir_col = 1 - dir_row shift = (internal_layer_index >> 1) % 4 for q in qubits: q2 = devices.GridQubit(q.row + dir_row, q.col + dir_col) if q2 not in qubits: continue # This edge isn't on the device. if (q.row * (2 - dir_row) + q.col * (2 - dir_col)) % 4 != shift: continue # No CZ along this edge for this layer. yield ops.common_gates.CZ(q, q2)