-
Notifications
You must be signed in to change notification settings - Fork 989
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
remove cirq.google dependency from three qubit gates test (#3928)
Moves ValidatingTestDevice to cirq.testing and it is used in `three_qubit_gates_test`. This helps removing cirq.google references from cirq. This is related to #3737.
- Loading branch information
Showing
5 changed files
with
248 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# Copyright 2021 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. | ||
"""Provides test devices that can validate circuits.""" | ||
from typing import Tuple, AbstractSet, cast | ||
|
||
from cirq import devices, ops, protocols | ||
|
||
|
||
class ValidatingTestDevice(devices.Device): | ||
"""A fake device that was created to ensure certain Device validation features are | ||
leveraged in Circuit functions. It contains the minimum set of features that tests | ||
require. Feel free to extend the features here as needed. | ||
Args: | ||
qubits: set of qubits on this device | ||
name: the name for repr | ||
allowed_gates: tuple of allowed gate types | ||
allowed_qubit_types: tuple of allowed qubit types | ||
validate_locality: if True, device will validate 2 qubit operations | ||
(except MeasurementGateOperations) whether the two qubits are adjacent. If True, | ||
GridQubits are assumed to be part of the allowed_qubit_types | ||
auto_decompose_gates: when set, for given gates it calls the cirq.decompose protocol | ||
""" | ||
|
||
def __init__( | ||
self, | ||
qubits: AbstractSet[ops.Qid], | ||
name: str = "ValidatingTestDevice", | ||
allowed_gates: Tuple[type, ...] = (ops.Gate,), | ||
allowed_qubit_types: Tuple[type, ...] = (devices.GridQubit,), | ||
validate_locality: bool = False, | ||
auto_decompose_gates: Tuple[type, ...] = tuple(), | ||
): | ||
self.allowed_qubit_types = allowed_qubit_types | ||
self.allowed_gates = allowed_gates | ||
self.qubits = qubits | ||
self._repr = name | ||
self.validate_locality = validate_locality | ||
self.auto_decompose_gates = auto_decompose_gates | ||
if self.validate_locality and devices.GridQubit not in allowed_qubit_types: | ||
raise ValueError("GridQubit must be an allowed qubit type with validate_locality=True") | ||
|
||
def validate_operation(self, operation: ops.Operation) -> None: | ||
# This is pretty close to what the cirq.google.XmonDevice has for validation | ||
for q in operation.qubits: | ||
if not isinstance(q, self.allowed_qubit_types): | ||
raise ValueError(f"Unsupported qubit type: {type(q)!r}") | ||
if q not in self.qubits: | ||
raise ValueError(f'Qubit not on device: {q!r}') | ||
if not isinstance(operation.gate, self.allowed_gates): | ||
raise ValueError(f"Unsupported gate type: {operation.gate!r}") | ||
if self.validate_locality: | ||
if len(operation.qubits) == 2 and not isinstance(operation.gate, ops.MeasurementGate): | ||
p, q = operation.qubits | ||
if not cast(devices.GridQubit, p).is_adjacent(q): | ||
raise ValueError(f'Non-local interaction: {operation!r}.') | ||
|
||
def decompose_operation(self, operation: 'ops.Operation') -> 'ops.OP_TREE': | ||
if isinstance(operation.gate, self.auto_decompose_gates): | ||
return protocols.decompose(operation) | ||
return operation | ||
|
||
def __repr__(self): | ||
return self._repr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
# Copyright 2021 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 pytest | ||
|
||
import cirq | ||
from cirq.testing.devices import ValidatingTestDevice | ||
|
||
|
||
def test_validating_types_and_qubits(): | ||
dev = ValidatingTestDevice( | ||
allowed_qubit_types=(cirq.GridQubit,), | ||
allowed_gates=(cirq.XPowGate,), | ||
qubits={cirq.GridQubit(0, 0)}, | ||
name='test', | ||
) | ||
|
||
dev.validate_operation(cirq.X(cirq.GridQubit(0, 0))) | ||
|
||
with pytest.raises(ValueError, match="Unsupported qubit type"): | ||
dev.validate_operation(cirq.X(cirq.NamedQubit("a"))) | ||
|
||
with pytest.raises(ValueError, match="Qubit not on device"): | ||
dev.validate_operation(cirq.X(cirq.GridQubit(1, 0))) | ||
|
||
with pytest.raises(ValueError, match="Unsupported gate type"): | ||
dev.validate_operation(cirq.Y(cirq.GridQubit(0, 0))) | ||
|
||
|
||
def test_validating_locality(): | ||
dev = ValidatingTestDevice( | ||
allowed_qubit_types=(cirq.GridQubit,), | ||
allowed_gates=(cirq.CZPowGate, cirq.MeasurementGate), | ||
qubits=set(cirq.GridQubit.rect(3, 3)), | ||
name='test', | ||
validate_locality=True, | ||
) | ||
|
||
dev.validate_operation(cirq.CZ(cirq.GridQubit(0, 0), cirq.GridQubit(0, 1))) | ||
dev.validate_operation(cirq.measure(cirq.GridQubit(0, 0), cirq.GridQubit(0, 2))) | ||
|
||
with pytest.raises(ValueError, match="Non-local interaction"): | ||
dev.validate_operation(cirq.CZ(cirq.GridQubit(0, 0), cirq.GridQubit(0, 2))) | ||
|
||
with pytest.raises(ValueError, match="GridQubit must be an allowed qubit type"): | ||
ValidatingTestDevice( | ||
allowed_qubit_types=(cirq.NamedQubit,), | ||
allowed_gates=(cirq.CZPowGate, cirq.MeasurementGate), | ||
qubits=set(cirq.GridQubit.rect(3, 3)), | ||
name='test', | ||
validate_locality=True, | ||
) | ||
|
||
|
||
def test_autodecompose(): | ||
dev = ValidatingTestDevice( | ||
allowed_qubit_types=(cirq.LineQubit,), | ||
allowed_gates=( | ||
cirq.XPowGate, | ||
cirq.ZPowGate, | ||
cirq.CZPowGate, | ||
cirq.YPowGate, | ||
cirq.MeasurementGate, | ||
), | ||
qubits=set(cirq.LineQubit.range(3)), | ||
name='test', | ||
validate_locality=False, | ||
auto_decompose_gates=(cirq.CCXPowGate,), | ||
) | ||
|
||
a, b, c = cirq.LineQubit.range(3) | ||
circuit = cirq.Circuit(cirq.CCX(a, b, c), device=dev) | ||
decomposed = cirq.decompose(cirq.CCX(a, b, c)) | ||
assert circuit.moments == cirq.Circuit(decomposed).moments | ||
|
||
with pytest.raises(ValueError, match="Unsupported gate type: cirq.TOFFOLI"): | ||
dev = ValidatingTestDevice( | ||
allowed_qubit_types=(cirq.LineQubit,), | ||
allowed_gates=( | ||
cirq.XPowGate, | ||
cirq.ZPowGate, | ||
cirq.CZPowGate, | ||
cirq.YPowGate, | ||
cirq.MeasurementGate, | ||
), | ||
qubits=set(cirq.LineQubit.range(3)), | ||
name='test', | ||
validate_locality=False, | ||
auto_decompose_gates=tuple(), | ||
) | ||
|
||
a, b, c = cirq.LineQubit.range(3) | ||
cirq.Circuit(cirq.CCX(a, b, c), device=dev) | ||
|
||
|
||
def test_repr(): | ||
dev = ValidatingTestDevice( | ||
allowed_qubit_types=(cirq.GridQubit,), | ||
allowed_gates=(cirq.CZPowGate, cirq.MeasurementGate), | ||
qubits=set(cirq.GridQubit.rect(3, 3)), | ||
name='test', | ||
validate_locality=True, | ||
) | ||
assert repr(dev) == 'test' | ||
|
||
|
||
def test_defaults(): | ||
dev = ValidatingTestDevice(qubits={cirq.GridQubit(0, 0)}) | ||
assert repr(dev) == 'ValidatingTestDevice' | ||
assert dev.allowed_qubit_types == (cirq.GridQubit,) | ||
assert not dev.validate_locality | ||
assert not dev.auto_decompose_gates |