cirq-core 1.1.0.dev20221220224914__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cirq/__init__.py +8 -0
- cirq/_compat.py +29 -4
- cirq/_compat_test.py +24 -26
- cirq/_version.py +32 -1
- cirq/_version_test.py +1 -1
- cirq/circuits/_block_diagram_drawer_test.py +4 -3
- cirq/circuits/circuit.py +109 -63
- cirq/circuits/circuit_operation.py +2 -3
- cirq/circuits/circuit_operation_test.py +4 -4
- cirq/circuits/circuit_test.py +11 -0
- cirq/circuits/frozen_circuit.py +13 -1
- cirq/circuits/frozen_circuit_test.py +5 -1
- cirq/circuits/moment.py +39 -14
- cirq/circuits/moment_test.py +7 -0
- cirq/circuits/text_diagram_drawer.py +1 -1
- cirq/circuits/text_diagram_drawer_test.py +3 -7
- cirq/contrib/acquaintance/bipartite.py +1 -1
- cirq/contrib/acquaintance/devices.py +2 -2
- cirq/contrib/acquaintance/executor.py +5 -2
- cirq/contrib/acquaintance/gates.py +3 -2
- cirq/contrib/acquaintance/permutation.py +13 -2
- cirq/contrib/acquaintance/testing.py +3 -5
- cirq/contrib/paulistring/recombine.py +3 -6
- cirq/contrib/qasm_import/_parser.py +17 -21
- cirq/contrib/qasm_import/_parser_test.py +30 -45
- cirq/contrib/qcircuit/qcircuit_test.py +3 -7
- cirq/contrib/quantum_volume/quantum_volume.py +3 -3
- cirq/contrib/quimb/mps_simulator.py +1 -1
- cirq/contrib/quimb/state_vector.py +2 -0
- cirq/contrib/quirk/quirk_gate.py +1 -0
- cirq/contrib/svg/svg.py +4 -7
- cirq/contrib/svg/svg_test.py +29 -1
- cirq/devices/grid_qubit.py +26 -28
- cirq/devices/grid_qubit_test.py +21 -5
- cirq/devices/line_qubit.py +10 -12
- cirq/devices/line_qubit_test.py +9 -2
- cirq/devices/named_topologies.py +1 -1
- cirq/devices/noise_model.py +4 -1
- cirq/devices/superconducting_qubits_noise_properties.py +1 -3
- cirq/experiments/n_qubit_tomography.py +1 -1
- cirq/experiments/qubit_characterizations.py +2 -2
- cirq/experiments/single_qubit_readout_calibration.py +1 -1
- cirq/experiments/t2_decay_experiment.py +1 -1
- cirq/experiments/xeb_simulation_test.py +2 -2
- cirq/interop/quirk/cells/testing.py +1 -1
- cirq/json_resolver_cache.py +1 -0
- cirq/linalg/__init__.py +2 -0
- cirq/linalg/decompositions_test.py +4 -4
- cirq/linalg/diagonalize_test.py +5 -6
- cirq/linalg/transformations.py +72 -9
- cirq/linalg/transformations_test.py +23 -7
- cirq/ops/__init__.py +4 -0
- cirq/ops/arithmetic_operation.py +4 -6
- cirq/ops/classically_controlled_operation.py +10 -3
- cirq/ops/clifford_gate.py +1 -7
- cirq/ops/common_channels.py +21 -15
- cirq/ops/common_gate_families.py +2 -3
- cirq/ops/common_gates.py +48 -11
- cirq/ops/common_gates_test.py +4 -0
- cirq/ops/controlled_gate.py +44 -18
- cirq/ops/controlled_operation.py +13 -5
- cirq/ops/dense_pauli_string.py +14 -19
- cirq/ops/diagonal_gate.py +3 -4
- cirq/ops/eigen_gate.py +8 -10
- cirq/ops/eigen_gate_test.py +6 -0
- cirq/ops/gate_operation.py +11 -6
- cirq/ops/gate_operation_test.py +11 -2
- cirq/ops/gateset.py +2 -1
- cirq/ops/gateset_test.py +38 -5
- cirq/ops/global_phase_op.py +28 -2
- cirq/ops/global_phase_op_test.py +21 -0
- cirq/ops/identity.py +1 -1
- cirq/ops/kraus_channel_test.py +2 -2
- cirq/ops/linear_combinations.py +7 -6
- cirq/ops/linear_combinations_test.py +26 -10
- cirq/ops/matrix_gates.py +8 -4
- cirq/ops/matrix_gates_test.py +25 -3
- cirq/ops/measure_util.py +13 -5
- cirq/ops/measure_util_test.py +8 -2
- cirq/ops/measurement_gate.py +1 -1
- cirq/ops/measurement_gate_test.py +9 -4
- cirq/ops/mixed_unitary_channel_test.py +4 -4
- cirq/ops/named_qubit.py +2 -4
- cirq/ops/parity_gates.py +5 -1
- cirq/ops/parity_gates_test.py +6 -0
- cirq/ops/pauli_gates.py +9 -9
- cirq/ops/pauli_string.py +4 -2
- cirq/ops/pauli_string_raw_types.py +4 -11
- cirq/ops/pauli_string_test.py +13 -13
- cirq/ops/pauli_sum_exponential.py +6 -1
- cirq/ops/qubit_manager.py +97 -0
- cirq/ops/qubit_manager_test.py +66 -0
- cirq/ops/raw_types.py +75 -33
- cirq/ops/raw_types_test.py +34 -0
- cirq/ops/three_qubit_gates.py +16 -10
- cirq/ops/three_qubit_gates_test.py +4 -2
- cirq/ops/two_qubit_diagonal_gate.py +3 -3
- cirq/ops/wait_gate.py +1 -1
- cirq/protocols/__init__.py +1 -0
- cirq/protocols/act_on_protocol.py +3 -3
- cirq/protocols/act_on_protocol_test.py +5 -5
- cirq/protocols/apply_channel_protocol.py +9 -8
- cirq/protocols/apply_mixture_protocol.py +8 -8
- cirq/protocols/apply_mixture_protocol_test.py +1 -1
- cirq/protocols/apply_unitary_protocol.py +66 -19
- cirq/protocols/apply_unitary_protocol_test.py +50 -0
- cirq/protocols/circuit_diagram_info_protocol.py +7 -9
- cirq/protocols/decompose_protocol.py +167 -125
- cirq/protocols/decompose_protocol_test.py +132 -2
- cirq/protocols/has_stabilizer_effect_protocol.py +2 -1
- cirq/protocols/inverse_protocol.py +2 -2
- cirq/protocols/json_serialization_test.py +3 -3
- cirq/protocols/json_test_data/Linspace.json +20 -7
- cirq/protocols/json_test_data/Linspace.repr +4 -1
- cirq/protocols/json_test_data/Points.json +19 -8
- cirq/protocols/json_test_data/Points.repr +4 -1
- cirq/protocols/json_test_data/Result.repr_inward +1 -1
- cirq/protocols/json_test_data/ResultDict.repr +1 -1
- cirq/protocols/json_test_data/ResultDict.repr_inward +1 -1
- cirq/protocols/json_test_data/TrialResult.repr_inward +1 -1
- cirq/protocols/json_test_data/XPowGate.json +13 -5
- cirq/protocols/json_test_data/XPowGate.repr +1 -1
- cirq/protocols/json_test_data/ZPowGate.json +13 -5
- cirq/protocols/json_test_data/ZPowGate.repr +1 -1
- cirq/protocols/json_test_data/ZipLongest.json +19 -0
- cirq/protocols/json_test_data/ZipLongest.repr +1 -0
- cirq/protocols/json_test_data/spec.py +1 -0
- cirq/protocols/kraus_protocol.py +3 -4
- cirq/protocols/measurement_key_protocol.py +3 -1
- cirq/protocols/mixture_protocol.py +3 -2
- cirq/protocols/phase_protocol.py +3 -3
- cirq/protocols/pow_protocol.py +1 -2
- cirq/protocols/qasm.py +4 -4
- cirq/protocols/qid_shape_protocol.py +8 -8
- cirq/protocols/resolve_parameters.py +8 -3
- cirq/protocols/resolve_parameters_test.py +3 -3
- cirq/protocols/unitary_protocol.py +19 -11
- cirq/protocols/unitary_protocol_test.py +37 -0
- cirq/qis/channels.py +1 -1
- cirq/qis/clifford_tableau.py +4 -5
- cirq/qis/quantum_state_representation.py +7 -9
- cirq/qis/states.py +21 -13
- cirq/qis/states_test.py +7 -0
- cirq/sim/clifford/clifford_simulator.py +3 -3
- cirq/sim/density_matrix_simulation_state.py +2 -1
- cirq/sim/density_matrix_simulator.py +1 -1
- cirq/sim/density_matrix_simulator_test.py +9 -5
- cirq/sim/density_matrix_utils.py +7 -32
- cirq/sim/mux.py +2 -2
- cirq/sim/simulation_state.py +58 -18
- cirq/sim/simulation_state_base.py +5 -2
- cirq/sim/simulation_state_test.py +121 -9
- cirq/sim/simulation_utils.py +59 -0
- cirq/sim/simulation_utils_test.py +32 -0
- cirq/sim/simulator.py +2 -1
- cirq/sim/simulator_base_test.py +3 -3
- cirq/sim/sparse_simulator.py +1 -1
- cirq/sim/sparse_simulator_test.py +5 -5
- cirq/sim/state_vector.py +7 -36
- cirq/sim/state_vector_simulation_state.py +18 -1
- cirq/sim/state_vector_simulator.py +3 -2
- cirq/sim/state_vector_simulator_test.py +24 -2
- cirq/sim/state_vector_test.py +46 -15
- cirq/study/__init__.py +1 -0
- cirq/study/flatten_expressions.py +2 -2
- cirq/study/resolver.py +2 -0
- cirq/study/resolver_test.py +1 -1
- cirq/study/result.py +1 -1
- cirq/study/sweeps.py +103 -9
- cirq/study/sweeps_test.py +64 -0
- cirq/testing/__init__.py +4 -0
- cirq/testing/circuit_compare.py +15 -18
- cirq/testing/consistent_act_on.py +4 -4
- cirq/testing/consistent_controlled_gate_op_test.py +1 -1
- cirq/testing/consistent_decomposition.py +11 -2
- cirq/testing/consistent_decomposition_test.py +8 -1
- cirq/testing/consistent_protocols.py +2 -0
- cirq/testing/consistent_protocols_test.py +8 -4
- cirq/testing/consistent_qasm.py +8 -15
- cirq/testing/consistent_specified_has_unitary.py +1 -1
- cirq/testing/consistent_unitary.py +85 -0
- cirq/testing/consistent_unitary_test.py +96 -0
- cirq/testing/equivalent_repr_eval.py +10 -10
- cirq/testing/json.py +3 -3
- cirq/testing/logs.py +1 -1
- cirq/testing/order_tester.py +4 -5
- cirq/testing/random_circuit.py +3 -5
- cirq/testing/sample_gates.py +79 -0
- cirq/testing/sample_gates_test.py +59 -0
- cirq/transformers/__init__.py +2 -0
- cirq/transformers/analytical_decompositions/__init__.py +8 -0
- cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +130 -0
- cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +58 -0
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +230 -0
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +112 -0
- cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +1 -3
- cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +1 -1
- cirq/transformers/expand_composite.py +1 -1
- cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +4 -4
- cirq/transformers/measurement_transformers.py +4 -4
- cirq/transformers/merge_single_qubit_gates.py +17 -4
- cirq/transformers/routing/route_circuit_cqc.py +2 -2
- cirq/transformers/stratify.py +125 -62
- cirq/transformers/stratify_test.py +20 -16
- cirq/transformers/transformer_api.py +1 -1
- cirq/transformers/transformer_primitives.py +3 -2
- cirq/transformers/transformer_primitives_test.py +11 -0
- cirq/value/abc_alt.py +3 -2
- cirq/value/abc_alt_test.py +1 -0
- cirq/value/classical_data.py +10 -10
- cirq/value/digits.py +2 -2
- cirq/value/linear_dict.py +18 -19
- cirq/value/product_state.py +7 -6
- cirq/value/value_equality_attr.py +2 -2
- cirq/vis/heatmap.py +1 -1
- cirq/vis/heatmap_test.py +2 -2
- cirq/work/collector.py +2 -2
- cirq/work/observable_measurement_data.py +5 -5
- cirq/work/observable_readout_calibration.py +3 -1
- cirq/work/observable_settings.py +1 -1
- cirq/work/pauli_sum_collector.py +9 -8
- cirq/work/sampler.py +2 -0
- cirq/work/zeros_sampler.py +2 -2
- {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/METADATA +7 -15
- {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/RECORD +228 -214
- {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/WHEEL +1 -1
- {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/LICENSE +0 -0
- {cirq_core-1.1.0.dev20221220224914.dist-info → cirq_core-1.2.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Copyright 2023 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
|
+
|
|
15
|
+
import abc
|
|
16
|
+
import dataclasses
|
|
17
|
+
from typing import Iterable, List, TYPE_CHECKING
|
|
18
|
+
from cirq.ops import raw_types
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
import cirq
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class QubitManager(metaclass=abc.ABCMeta):
|
|
25
|
+
@abc.abstractmethod
|
|
26
|
+
def qalloc(self, n: int, dim: int = 2) -> List['cirq.Qid']:
|
|
27
|
+
"""Allocate `n` clean qubits, i.e. qubits guaranteed to be in state |0>."""
|
|
28
|
+
|
|
29
|
+
@abc.abstractmethod
|
|
30
|
+
def qborrow(self, n: int, dim: int = 2) -> List['cirq.Qid']:
|
|
31
|
+
"""Allocate `n` dirty qubits, i.e. the returned qubits can be in any state."""
|
|
32
|
+
|
|
33
|
+
@abc.abstractmethod
|
|
34
|
+
def qfree(self, qubits: Iterable['cirq.Qid']) -> None:
|
|
35
|
+
"""Free pre-allocated clean or dirty qubits managed by this qubit manager."""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclasses.dataclass(frozen=True)
|
|
39
|
+
class _BaseAncillaQid(raw_types.Qid):
|
|
40
|
+
id: int
|
|
41
|
+
dim: int = 2
|
|
42
|
+
prefix: str = ''
|
|
43
|
+
|
|
44
|
+
def _comparison_key(self) -> int:
|
|
45
|
+
return self.id
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def dimension(self) -> int:
|
|
49
|
+
return self.dim
|
|
50
|
+
|
|
51
|
+
def __repr__(self) -> str:
|
|
52
|
+
dim_str = f', dim={self.dim}' if self.dim != 2 else ''
|
|
53
|
+
prefix_str = f', prefix={self.prefix}' if self.prefix != '' else ''
|
|
54
|
+
return f"cirq.ops.{type(self).__name__}({self.id}{dim_str}{prefix_str})"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class CleanQubit(_BaseAncillaQid):
|
|
58
|
+
"""An internal qid type that represents a clean ancilla allocation."""
|
|
59
|
+
|
|
60
|
+
def __str__(self) -> str:
|
|
61
|
+
dim_str = f' (d={self.dimension})' if self.dim != 2 else ''
|
|
62
|
+
return f"{self.prefix}_c({self.id}){dim_str}"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class BorrowableQubit(_BaseAncillaQid):
|
|
66
|
+
"""An internal qid type that represents a dirty ancilla allocation."""
|
|
67
|
+
|
|
68
|
+
def __str__(self) -> str:
|
|
69
|
+
dim_str = f' (d={self.dimension})' if self.dim != 2 else ''
|
|
70
|
+
return f"{self.prefix}_b({self.id}){dim_str}"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class SimpleQubitManager(QubitManager):
|
|
74
|
+
"""Allocates a new `CleanQubit`/`BorrowableQubit` for every `qalloc`/`qborrow` request."""
|
|
75
|
+
|
|
76
|
+
def __init__(self, prefix: str = ''):
|
|
77
|
+
self._clean_id = 0
|
|
78
|
+
self._borrow_id = 0
|
|
79
|
+
self._prefix = prefix
|
|
80
|
+
|
|
81
|
+
def qalloc(self, n: int, dim: int = 2) -> List['cirq.Qid']:
|
|
82
|
+
self._clean_id += n
|
|
83
|
+
return [CleanQubit(i, dim, self._prefix) for i in range(self._clean_id - n, self._clean_id)]
|
|
84
|
+
|
|
85
|
+
def qborrow(self, n: int, dim: int = 2) -> List['cirq.Qid']:
|
|
86
|
+
self._borrow_id = self._borrow_id + n
|
|
87
|
+
return [
|
|
88
|
+
BorrowableQubit(i, dim, self._prefix)
|
|
89
|
+
for i in range(self._borrow_id - n, self._borrow_id)
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
def qfree(self, qubits: Iterable['cirq.Qid']) -> None:
|
|
93
|
+
for q in qubits:
|
|
94
|
+
good = isinstance(q, CleanQubit) and q.id < self._clean_id
|
|
95
|
+
good |= isinstance(q, BorrowableQubit) and q.id < self._borrow_id
|
|
96
|
+
if not good:
|
|
97
|
+
raise ValueError(f"{q} was not allocated by {self}")
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Copyright 2023 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
|
+
|
|
15
|
+
import cirq
|
|
16
|
+
from cirq.ops import qubit_manager as cqi
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_clean_qubits():
|
|
21
|
+
q = cqi.CleanQubit(1)
|
|
22
|
+
assert q.id == 1
|
|
23
|
+
assert q.dimension == 2
|
|
24
|
+
assert str(q) == '_c(1)'
|
|
25
|
+
assert repr(q) == 'cirq.ops.CleanQubit(1)'
|
|
26
|
+
|
|
27
|
+
q = cqi.CleanQubit(2, dim=3)
|
|
28
|
+
assert q.id == 2
|
|
29
|
+
assert q.dimension == 3
|
|
30
|
+
assert str(q) == '_c(2) (d=3)'
|
|
31
|
+
assert repr(q) == 'cirq.ops.CleanQubit(2, dim=3)'
|
|
32
|
+
|
|
33
|
+
assert cqi.CleanQubit(1) < cqi.CleanQubit(2)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_borrow_qubits():
|
|
37
|
+
q = cqi.BorrowableQubit(10)
|
|
38
|
+
assert q.id == 10
|
|
39
|
+
assert q.dimension == 2
|
|
40
|
+
assert str(q) == '_b(10)'
|
|
41
|
+
assert repr(q) == 'cirq.ops.BorrowableQubit(10)'
|
|
42
|
+
|
|
43
|
+
q = cqi.BorrowableQubit(20, dim=4)
|
|
44
|
+
assert q.id == 20
|
|
45
|
+
assert q.dimension == 4
|
|
46
|
+
assert str(q) == '_b(20) (d=4)'
|
|
47
|
+
assert repr(q) == 'cirq.ops.BorrowableQubit(20, dim=4)'
|
|
48
|
+
|
|
49
|
+
assert cqi.BorrowableQubit(1) < cqi.BorrowableQubit(2)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@pytest.mark.parametrize('_', range(2))
|
|
53
|
+
def test_simple_qubit_manager(_):
|
|
54
|
+
qm = cirq.ops.SimpleQubitManager()
|
|
55
|
+
assert qm.qalloc(1) == [cqi.CleanQubit(0)]
|
|
56
|
+
assert qm.qalloc(2) == [cqi.CleanQubit(1), cqi.CleanQubit(2)]
|
|
57
|
+
assert qm.qalloc(1, dim=3) == [cqi.CleanQubit(3, dim=3)]
|
|
58
|
+
assert qm.qborrow(1) == [cqi.BorrowableQubit(0)]
|
|
59
|
+
assert qm.qborrow(2) == [cqi.BorrowableQubit(1), cqi.BorrowableQubit(2)]
|
|
60
|
+
assert qm.qborrow(1, dim=3) == [cqi.BorrowableQubit(3, dim=3)]
|
|
61
|
+
qm.qfree([cqi.CleanQubit(i) for i in range(3)] + [cqi.CleanQubit(3, dim=3)])
|
|
62
|
+
qm.qfree([cqi.BorrowableQubit(i) for i in range(3)] + [cqi.BorrowableQubit(3, dim=3)])
|
|
63
|
+
with pytest.raises(ValueError, match="not allocated"):
|
|
64
|
+
qm.qfree([cqi.CleanQubit(10)])
|
|
65
|
+
with pytest.raises(ValueError, match="not allocated"):
|
|
66
|
+
qm.qfree([cqi.BorrowableQubit(10)])
|
cirq/ops/raw_types.py
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import abc
|
|
18
18
|
import functools
|
|
19
19
|
from typing import (
|
|
20
|
+
cast,
|
|
20
21
|
AbstractSet,
|
|
21
22
|
Any,
|
|
22
23
|
Callable,
|
|
@@ -30,16 +31,17 @@ from typing import (
|
|
|
30
31
|
Optional,
|
|
31
32
|
Sequence,
|
|
32
33
|
Tuple,
|
|
33
|
-
TypeVar,
|
|
34
34
|
TYPE_CHECKING,
|
|
35
35
|
Union,
|
|
36
36
|
)
|
|
37
|
+
from typing_extensions import Self
|
|
37
38
|
|
|
38
39
|
import numpy as np
|
|
39
40
|
import sympy
|
|
40
41
|
|
|
41
42
|
from cirq import protocols, value
|
|
42
43
|
from cirq._import import LazyLoader
|
|
44
|
+
from cirq._compat import __cirq_debug__, cached_method
|
|
43
45
|
from cirq.type_workarounds import NotImplementedType
|
|
44
46
|
from cirq.ops import control_values as cv
|
|
45
47
|
|
|
@@ -109,7 +111,8 @@ class Qid(metaclass=abc.ABCMeta):
|
|
|
109
111
|
def _cmp_tuple(self):
|
|
110
112
|
return (type(self).__name__, repr(type(self)), self._comparison_key(), self.dimension)
|
|
111
113
|
|
|
112
|
-
|
|
114
|
+
@cached_method
|
|
115
|
+
def __hash__(self) -> int:
|
|
113
116
|
return hash((Qid, self._comparison_key()))
|
|
114
117
|
|
|
115
118
|
def __eq__(self, other):
|
|
@@ -215,7 +218,8 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
|
|
|
215
218
|
Raises:
|
|
216
219
|
ValueError: The gate can't be applied to the qubits.
|
|
217
220
|
"""
|
|
218
|
-
|
|
221
|
+
if __cirq_debug__.get():
|
|
222
|
+
_validate_qid_shape(self, qubits)
|
|
219
223
|
|
|
220
224
|
def on(self, *qubits: Qid) -> 'Operation':
|
|
221
225
|
"""Returns an application of this gate to the given qubits.
|
|
@@ -254,19 +258,33 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
|
|
|
254
258
|
raise TypeError(f'{targets[0]} object is not iterable.')
|
|
255
259
|
t0 = list(targets[0])
|
|
256
260
|
iterator = [t0] if t0 and isinstance(t0[0], Qid) else t0
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
261
|
+
if __cirq_debug__.get():
|
|
262
|
+
for target in iterator:
|
|
263
|
+
if not isinstance(target, Sequence):
|
|
264
|
+
raise ValueError(
|
|
265
|
+
f'Inputs to multi-qubit gates must be Sequence[Qid].'
|
|
266
|
+
f' Type: {type(target)}'
|
|
267
|
+
)
|
|
268
|
+
if not all(isinstance(x, Qid) for x in target):
|
|
269
|
+
raise ValueError(f'All values in sequence should be Qids, but got {target}')
|
|
270
|
+
if len(target) != self._num_qubits_():
|
|
271
|
+
raise ValueError(f'Expected {self._num_qubits_()} qubits, got {target}')
|
|
272
|
+
operations.append(self.on(*target))
|
|
273
|
+
else:
|
|
274
|
+
operations = [self.on(*target) for target in iterator]
|
|
268
275
|
return operations
|
|
269
276
|
|
|
277
|
+
if not __cirq_debug__.get():
|
|
278
|
+
return [
|
|
279
|
+
op
|
|
280
|
+
for q in targets
|
|
281
|
+
for op in (
|
|
282
|
+
self.on_each(*q)
|
|
283
|
+
if isinstance(q, Iterable) and not isinstance(q, str)
|
|
284
|
+
else [self.on(cast('cirq.Qid', q))]
|
|
285
|
+
)
|
|
286
|
+
]
|
|
287
|
+
|
|
270
288
|
for target in targets:
|
|
271
289
|
if isinstance(target, Qid):
|
|
272
290
|
operations.append(self.on(target))
|
|
@@ -342,7 +360,7 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
|
|
|
342
360
|
return self.on(*qubits)
|
|
343
361
|
|
|
344
362
|
def with_probability(self, probability: 'cirq.TParamVal') -> 'cirq.Gate':
|
|
345
|
-
"""Creates a
|
|
363
|
+
"""Creates a probabilistic channel with this gate.
|
|
346
364
|
|
|
347
365
|
Args:
|
|
348
366
|
probability: floating point value between 0 and 1, giving the
|
|
@@ -358,7 +376,7 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
|
|
|
358
376
|
|
|
359
377
|
def controlled(
|
|
360
378
|
self,
|
|
361
|
-
num_controls: int = None,
|
|
379
|
+
num_controls: Optional[int] = None,
|
|
362
380
|
control_values: Optional[
|
|
363
381
|
Union[cv.AbstractControlValues, Sequence[Union[int, Collection[int]]]]
|
|
364
382
|
] = None,
|
|
@@ -406,6 +424,7 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
|
|
|
406
424
|
@value.alternative(requires='_num_qubits_', implementation=_backwards_compatibility_num_qubits)
|
|
407
425
|
def num_qubits(self) -> int:
|
|
408
426
|
"""The number of qubits this gate acts on."""
|
|
427
|
+
raise NotImplementedError
|
|
409
428
|
|
|
410
429
|
def _num_qubits_from_shape(self) -> int:
|
|
411
430
|
shape = self._qid_shape_()
|
|
@@ -420,6 +439,7 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
|
|
|
420
439
|
@value.alternative(requires='_qid_shape_', implementation=_num_qubits_from_shape)
|
|
421
440
|
def _num_qubits_(self) -> int:
|
|
422
441
|
"""The number of qubits this gate acts on."""
|
|
442
|
+
raise NotImplementedError
|
|
423
443
|
|
|
424
444
|
def _default_shape_from_num_qubits(self) -> Tuple[int, ...]:
|
|
425
445
|
num_qubits = self._num_qubits_()
|
|
@@ -433,6 +453,7 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
|
|
|
433
453
|
the gate acts on. E.g. (2, 2, 2) for the three-qubit CCZ gate and
|
|
434
454
|
(3, 3) for a 2-qutrit ternary gate.
|
|
435
455
|
"""
|
|
456
|
+
raise NotImplementedError
|
|
436
457
|
|
|
437
458
|
def _commutes_on_qids_(
|
|
438
459
|
self, qids: 'Sequence[cirq.Qid]', other: Any, *, atol: float = 1e-8
|
|
@@ -462,9 +483,6 @@ class Gate(metaclass=value.ABCMetaImplementAnyOneOf):
|
|
|
462
483
|
return protocols.obj_to_dict_helper(self, attribute_names=[])
|
|
463
484
|
|
|
464
485
|
|
|
465
|
-
TSelf = TypeVar('TSelf', bound='Operation')
|
|
466
|
-
|
|
467
|
-
|
|
468
486
|
class Operation(metaclass=abc.ABCMeta):
|
|
469
487
|
"""An effect applied to a collection of qubits.
|
|
470
488
|
|
|
@@ -488,11 +506,12 @@ class Operation(metaclass=abc.ABCMeta):
|
|
|
488
506
|
"""
|
|
489
507
|
return len(self.qubits)
|
|
490
508
|
|
|
509
|
+
@cached_method
|
|
491
510
|
def _qid_shape_(self) -> Tuple[int, ...]:
|
|
492
511
|
return protocols.qid_shape(self.qubits)
|
|
493
512
|
|
|
494
513
|
@abc.abstractmethod
|
|
495
|
-
def with_qubits(self
|
|
514
|
+
def with_qubits(self, *new_qubits: 'cirq.Qid') -> Self:
|
|
496
515
|
"""Returns the same operation, but applied to different qubits.
|
|
497
516
|
|
|
498
517
|
Args:
|
|
@@ -534,9 +553,8 @@ class Operation(metaclass=abc.ABCMeta):
|
|
|
534
553
|
return TaggedOperation(self, *new_tags)
|
|
535
554
|
|
|
536
555
|
def transform_qubits(
|
|
537
|
-
self:
|
|
538
|
-
|
|
539
|
-
) -> TSelf:
|
|
556
|
+
self, qubit_map: Union[Dict['cirq.Qid', 'cirq.Qid'], Callable[['cirq.Qid'], 'cirq.Qid']]
|
|
557
|
+
) -> Self:
|
|
540
558
|
"""Returns the same operation, but with different qubits.
|
|
541
559
|
|
|
542
560
|
Args:
|
|
@@ -583,7 +601,7 @@ class Operation(metaclass=abc.ABCMeta):
|
|
|
583
601
|
return ops.controlled_operation.ControlledOperation(control_qubits, self, control_values)
|
|
584
602
|
|
|
585
603
|
def with_probability(self, probability: 'cirq.TParamVal') -> 'cirq.Operation':
|
|
586
|
-
"""Creates a
|
|
604
|
+
"""Creates a probabilistic channel with this operation.
|
|
587
605
|
|
|
588
606
|
Args:
|
|
589
607
|
probability: floating point value between 0 and 1, giving the
|
|
@@ -617,7 +635,8 @@ class Operation(metaclass=abc.ABCMeta):
|
|
|
617
635
|
Raises:
|
|
618
636
|
ValueError: The operation had qids that don't match it's qid shape.
|
|
619
637
|
"""
|
|
620
|
-
|
|
638
|
+
if __cirq_debug__.get():
|
|
639
|
+
_validate_qid_shape(self, qubits)
|
|
621
640
|
|
|
622
641
|
def _commutes_(
|
|
623
642
|
self, other: Any, *, atol: float = 1e-8
|
|
@@ -811,7 +830,14 @@ class TaggedOperation(Operation):
|
|
|
811
830
|
return protocols.obj_to_dict_helper(self, ['sub_operation', 'tags'])
|
|
812
831
|
|
|
813
832
|
def _decompose_(self) -> 'cirq.OP_TREE':
|
|
814
|
-
return
|
|
833
|
+
return self._decompose_with_context_()
|
|
834
|
+
|
|
835
|
+
def _decompose_with_context_(
|
|
836
|
+
self, context: Optional['cirq.DecompositionContext'] = None
|
|
837
|
+
) -> 'cirq.OP_TREE':
|
|
838
|
+
return protocols.decompose_once(
|
|
839
|
+
self.sub_operation, default=None, flatten=False, context=context
|
|
840
|
+
)
|
|
815
841
|
|
|
816
842
|
def _pauli_expansion_(self) -> value.LinearDict[str]:
|
|
817
843
|
return protocols.pauli_expansion(self.sub_operation)
|
|
@@ -821,6 +847,7 @@ class TaggedOperation(Operation):
|
|
|
821
847
|
) -> Union[np.ndarray, None, NotImplementedType]:
|
|
822
848
|
return protocols.apply_unitary(self.sub_operation, args, default=None)
|
|
823
849
|
|
|
850
|
+
@cached_method
|
|
824
851
|
def _has_unitary_(self) -> bool:
|
|
825
852
|
return protocols.has_unitary(self.sub_operation)
|
|
826
853
|
|
|
@@ -832,30 +859,36 @@ class TaggedOperation(Operation):
|
|
|
832
859
|
) -> Union[bool, NotImplementedType, None]:
|
|
833
860
|
return protocols.commutes(self.sub_operation, other, atol=atol)
|
|
834
861
|
|
|
862
|
+
@cached_method
|
|
835
863
|
def _has_mixture_(self) -> bool:
|
|
836
864
|
return protocols.has_mixture(self.sub_operation)
|
|
837
865
|
|
|
838
866
|
def _mixture_(self) -> Sequence[Tuple[float, Any]]:
|
|
839
867
|
return protocols.mixture(self.sub_operation, NotImplemented)
|
|
840
868
|
|
|
869
|
+
@cached_method
|
|
841
870
|
def _has_kraus_(self) -> bool:
|
|
842
871
|
return protocols.has_kraus(self.sub_operation)
|
|
843
872
|
|
|
844
873
|
def _kraus_(self) -> Union[Tuple[np.ndarray], NotImplementedType]:
|
|
845
874
|
return protocols.kraus(self.sub_operation, NotImplemented)
|
|
846
875
|
|
|
876
|
+
@cached_method
|
|
847
877
|
def _measurement_key_names_(self) -> FrozenSet[str]:
|
|
848
878
|
return protocols.measurement_key_names(self.sub_operation)
|
|
849
879
|
|
|
880
|
+
@cached_method
|
|
850
881
|
def _measurement_key_objs_(self) -> FrozenSet['cirq.MeasurementKey']:
|
|
851
882
|
return protocols.measurement_key_objs(self.sub_operation)
|
|
852
883
|
|
|
884
|
+
@cached_method
|
|
853
885
|
def _is_measurement_(self) -> bool:
|
|
854
886
|
sub = getattr(self.sub_operation, "_is_measurement_", None)
|
|
855
887
|
if sub is not None:
|
|
856
888
|
return sub()
|
|
857
889
|
return NotImplemented
|
|
858
890
|
|
|
891
|
+
@cached_method
|
|
859
892
|
def _is_parameterized_(self) -> bool:
|
|
860
893
|
return protocols.is_parameterized(self.sub_operation) or any(
|
|
861
894
|
protocols.is_parameterized(tag) for tag in self.tags
|
|
@@ -867,6 +900,7 @@ class TaggedOperation(Operation):
|
|
|
867
900
|
return sub(sim_state)
|
|
868
901
|
return NotImplemented
|
|
869
902
|
|
|
903
|
+
@cached_method
|
|
870
904
|
def _parameter_names_(self) -> AbstractSet[str]:
|
|
871
905
|
tag_params = {name for tag in self.tags for name in protocols.parameter_names(tag)}
|
|
872
906
|
return protocols.parameter_names(self.sub_operation) | tag_params
|
|
@@ -891,6 +925,7 @@ class TaggedOperation(Operation):
|
|
|
891
925
|
) + sub_op_info.wire_symbols[1:]
|
|
892
926
|
return sub_op_info
|
|
893
927
|
|
|
928
|
+
@cached_method
|
|
894
929
|
def _trace_distance_bound_(self) -> float:
|
|
895
930
|
return protocols.trace_distance_bound(self.sub_operation)
|
|
896
931
|
|
|
@@ -951,7 +986,14 @@ class _InverseCompositeGate(Gate):
|
|
|
951
986
|
return NotImplemented
|
|
952
987
|
|
|
953
988
|
def _decompose_(self, qubits):
|
|
954
|
-
return
|
|
989
|
+
return self._decompose_with_context_(qubits)
|
|
990
|
+
|
|
991
|
+
def _decompose_with_context_(
|
|
992
|
+
self, qubits: Sequence['cirq.Qid'], context: Optional['cirq.DecompositionContext'] = None
|
|
993
|
+
) -> 'cirq.OP_TREE':
|
|
994
|
+
return protocols.inverse(
|
|
995
|
+
protocols.decompose_once_with_qubits(self._original, qubits, context=context)
|
|
996
|
+
)
|
|
955
997
|
|
|
956
998
|
def _has_unitary_(self):
|
|
957
999
|
from cirq import protocols, devices
|
|
@@ -962,9 +1004,11 @@ class _InverseCompositeGate(Gate):
|
|
|
962
1004
|
for op in protocols.decompose_once_with_qubits(self._original, qubits)
|
|
963
1005
|
)
|
|
964
1006
|
|
|
1007
|
+
@cached_method
|
|
965
1008
|
def _is_parameterized_(self) -> bool:
|
|
966
1009
|
return protocols.is_parameterized(self._original)
|
|
967
1010
|
|
|
1011
|
+
@cached_method
|
|
968
1012
|
def _parameter_names_(self) -> AbstractSet[str]:
|
|
969
1013
|
return protocols.parameter_names(self._original)
|
|
970
1014
|
|
|
@@ -998,15 +1042,13 @@ def _validate_qid_shape(val: Any, qubits: Sequence['cirq.Qid']) -> None:
|
|
|
998
1042
|
qid_shape = protocols.qid_shape(val)
|
|
999
1043
|
if len(qubits) != len(qid_shape):
|
|
1000
1044
|
raise ValueError(
|
|
1001
|
-
'Wrong number of qubits for <{!r}>. '
|
|
1002
|
-
'Expected {} qubits but got <{!r}>.'
|
|
1045
|
+
f'Wrong number of qubits for <{val!r}>. '
|
|
1046
|
+
f'Expected {len(qid_shape)} qubits but got <{qubits!r}>.'
|
|
1003
1047
|
)
|
|
1004
1048
|
if any(qid.dimension != dimension for qid, dimension in zip(qubits, qid_shape)):
|
|
1005
1049
|
raise ValueError(
|
|
1006
|
-
'Wrong shape of qids for <{!r}>. '
|
|
1007
|
-
'Expected {} but got {} <{!r}>.'
|
|
1008
|
-
val, qid_shape, tuple(qid.dimension for qid in qubits), qubits
|
|
1009
|
-
)
|
|
1050
|
+
f'Wrong shape of qids for <{val!r}>. '
|
|
1051
|
+
f'Expected {qid_shape} but got {tuple(qid.dimension for qid in qubits)} <{qubits!r}>.'
|
|
1010
1052
|
)
|
|
1011
1053
|
if len(set(qubits)) != len(qubits):
|
|
1012
1054
|
raise ValueError(
|
cirq/ops/raw_types_test.py
CHANGED
|
@@ -151,6 +151,29 @@ def test_op_validate():
|
|
|
151
151
|
op2.validate_args([cirq.LineQid(1, 2), cirq.LineQid(1, 2)])
|
|
152
152
|
|
|
153
153
|
|
|
154
|
+
def test_disable_op_validation():
|
|
155
|
+
q0, q1 = cirq.LineQubit.range(2)
|
|
156
|
+
h_op = cirq.H(q0)
|
|
157
|
+
|
|
158
|
+
# Fails normally.
|
|
159
|
+
with pytest.raises(ValueError, match='Wrong number'):
|
|
160
|
+
_ = cirq.H(q0, q1)
|
|
161
|
+
with pytest.raises(ValueError, match='Wrong number'):
|
|
162
|
+
h_op.validate_args([q0, q1])
|
|
163
|
+
|
|
164
|
+
# Passes, skipping validation.
|
|
165
|
+
with cirq.with_debug(False):
|
|
166
|
+
op = cirq.H(q0, q1)
|
|
167
|
+
assert op.qubits == (q0, q1)
|
|
168
|
+
h_op.validate_args([q0, q1])
|
|
169
|
+
|
|
170
|
+
# Fails again when validation is re-enabled.
|
|
171
|
+
with pytest.raises(ValueError, match='Wrong number'):
|
|
172
|
+
_ = cirq.H(q0, q1)
|
|
173
|
+
with pytest.raises(ValueError, match='Wrong number'):
|
|
174
|
+
h_op.validate_args([q0, q1])
|
|
175
|
+
|
|
176
|
+
|
|
154
177
|
def test_default_validation_and_inverse():
|
|
155
178
|
class TestGate(cirq.Gate):
|
|
156
179
|
def _num_qubits_(self):
|
|
@@ -178,6 +201,8 @@ def test_default_validation_and_inverse():
|
|
|
178
201
|
assert i**-1 == t
|
|
179
202
|
assert t**-1 == i
|
|
180
203
|
assert cirq.decompose(i) == [cirq.X(a), cirq.S(b) ** -1, cirq.Z(a)]
|
|
204
|
+
assert [*i._decompose_()] == [cirq.X(a), cirq.S(b) ** -1, cirq.Z(a)]
|
|
205
|
+
assert [*i.gate._decompose_([a, b])] == [cirq.X(a), cirq.S(b) ** -1, cirq.Z(a)]
|
|
181
206
|
cirq.testing.assert_allclose_up_to_global_phase(
|
|
182
207
|
cirq.unitary(i), cirq.unitary(t).conj().T, atol=1e-8
|
|
183
208
|
)
|
|
@@ -595,6 +620,7 @@ def test_tagged_operation_forwards_protocols():
|
|
|
595
620
|
np.testing.assert_equal(cirq.unitary(tagged_h), cirq.unitary(h))
|
|
596
621
|
assert cirq.has_unitary(tagged_h)
|
|
597
622
|
assert cirq.decompose(tagged_h) == cirq.decompose(h)
|
|
623
|
+
assert [*tagged_h._decompose_()] == cirq.decompose(h)
|
|
598
624
|
assert cirq.pauli_expansion(tagged_h) == cirq.pauli_expansion(h)
|
|
599
625
|
assert cirq.equal_up_to_global_phase(h, tagged_h)
|
|
600
626
|
assert np.isclose(cirq.kraus(h), cirq.kraus(tagged_h)).all()
|
|
@@ -787,6 +813,10 @@ def test_single_qubit_gate_validates_on_each():
|
|
|
787
813
|
test_non_qubits = [str(i) for i in range(3)]
|
|
788
814
|
with pytest.raises(ValueError):
|
|
789
815
|
_ = g.on_each(*test_non_qubits)
|
|
816
|
+
|
|
817
|
+
with cirq.with_debug(False):
|
|
818
|
+
assert g.on_each(*test_non_qubits)[0].qubits == ('0',)
|
|
819
|
+
|
|
790
820
|
with pytest.raises(ValueError):
|
|
791
821
|
_ = g.on_each(*test_non_qubits)
|
|
792
822
|
|
|
@@ -853,6 +883,10 @@ def test_on_each_two_qubits():
|
|
|
853
883
|
g.on_each([(a,)])
|
|
854
884
|
with pytest.raises(ValueError, match='Expected 2 qubits'):
|
|
855
885
|
g.on_each([(a, b, a)])
|
|
886
|
+
|
|
887
|
+
with cirq.with_debug(False):
|
|
888
|
+
assert g.on_each([(a, b, a)])[0].qubits == (a, b, a)
|
|
889
|
+
|
|
856
890
|
with pytest.raises(ValueError, match='Expected 2 qubits'):
|
|
857
891
|
g.on_each(zip([a, a]))
|
|
858
892
|
with pytest.raises(ValueError, match='Expected 2 qubits'):
|
cirq/ops/three_qubit_gates.py
CHANGED
|
@@ -176,8 +176,9 @@ class CCZPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
|
176
176
|
if self._exponent == 1:
|
|
177
177
|
return 'cirq.CCZ'
|
|
178
178
|
return f'(cirq.CCZ**{proper_repr(self._exponent)})'
|
|
179
|
-
return
|
|
180
|
-
proper_repr(self._exponent),
|
|
179
|
+
return (
|
|
180
|
+
f'cirq.CCZPowGate(exponent={proper_repr(self._exponent)}, '
|
|
181
|
+
f'global_shift={self._global_shift!r})'
|
|
181
182
|
)
|
|
182
183
|
|
|
183
184
|
def __str__(self) -> str:
|
|
@@ -190,7 +191,7 @@ class CCZPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
|
190
191
|
|
|
191
192
|
def controlled(
|
|
192
193
|
self,
|
|
193
|
-
num_controls: int = None,
|
|
194
|
+
num_controls: Optional[int] = None,
|
|
194
195
|
control_values: Optional[
|
|
195
196
|
Union[cv.AbstractControlValues, Sequence[Union[int, Collection[int]]]]
|
|
196
197
|
] = None,
|
|
@@ -383,9 +384,8 @@ class ThreeQubitDiagonalGate(raw_types.Gate):
|
|
|
383
384
|
return protocols.obj_to_dict_helper(self, attribute_names=["diag_angles_radians"])
|
|
384
385
|
|
|
385
386
|
def __repr__(self) -> str:
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
)
|
|
387
|
+
angles = ','.join(proper_repr(angle) for angle in self._diag_angles_radians)
|
|
388
|
+
return f'cirq.ThreeQubitDiagonalGate([{angles}])'
|
|
389
389
|
|
|
390
390
|
def _num_qubits_(self) -> int:
|
|
391
391
|
return 3
|
|
@@ -488,8 +488,9 @@ class CCXPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
|
488
488
|
if self._exponent == 1:
|
|
489
489
|
return 'cirq.TOFFOLI'
|
|
490
490
|
return f'(cirq.TOFFOLI**{proper_repr(self._exponent)})'
|
|
491
|
-
return
|
|
492
|
-
proper_repr(self._exponent),
|
|
491
|
+
return (
|
|
492
|
+
f'cirq.CCXPowGate(exponent={proper_repr(self._exponent)}, '
|
|
493
|
+
f'global_shift={self._global_shift!r})'
|
|
493
494
|
)
|
|
494
495
|
|
|
495
496
|
def __str__(self) -> str:
|
|
@@ -502,7 +503,7 @@ class CCXPowGate(gate_features.InterchangeableQubitsGate, eigen_gate.EigenGate):
|
|
|
502
503
|
|
|
503
504
|
def controlled(
|
|
504
505
|
self,
|
|
505
|
-
num_controls: int = None,
|
|
506
|
+
num_controls: Optional[int] = None,
|
|
506
507
|
control_values: Optional[
|
|
507
508
|
Union[cv.AbstractControlValues, Sequence[Union[int, Collection[int]]]]
|
|
508
509
|
] = None,
|
|
@@ -661,6 +662,11 @@ class CSwapGate(gate_features.InterchangeableQubitsGate, raw_types.Gate):
|
|
|
661
662
|
def _value_equality_values_(self):
|
|
662
663
|
return ()
|
|
663
664
|
|
|
665
|
+
def __pow__(self, power):
|
|
666
|
+
if power == 1 or power == -1:
|
|
667
|
+
return self
|
|
668
|
+
return NotImplemented
|
|
669
|
+
|
|
664
670
|
def __str__(self) -> str:
|
|
665
671
|
return 'FREDKIN'
|
|
666
672
|
|
|
@@ -672,7 +678,7 @@ class CSwapGate(gate_features.InterchangeableQubitsGate, raw_types.Gate):
|
|
|
672
678
|
|
|
673
679
|
def controlled(
|
|
674
680
|
self,
|
|
675
|
-
num_controls: int = None,
|
|
681
|
+
num_controls: Optional[int] = None,
|
|
676
682
|
control_values: Optional[
|
|
677
683
|
Union[cv.AbstractControlValues, Sequence[Union[int, Collection[int]]]]
|
|
678
684
|
] = None,
|
|
@@ -94,8 +94,9 @@ def test_unitary():
|
|
|
94
94
|
)
|
|
95
95
|
|
|
96
96
|
assert cirq.has_unitary(cirq.CSWAP)
|
|
97
|
+
u = cirq.unitary(cirq.CSWAP)
|
|
97
98
|
np.testing.assert_allclose(
|
|
98
|
-
|
|
99
|
+
u,
|
|
99
100
|
np.array(
|
|
100
101
|
[
|
|
101
102
|
[1, 0, 0, 0, 0, 0, 0, 0],
|
|
@@ -110,6 +111,7 @@ def test_unitary():
|
|
|
110
111
|
),
|
|
111
112
|
atol=1e-8,
|
|
112
113
|
)
|
|
114
|
+
np.testing.assert_allclose(u @ u, np.eye(8))
|
|
113
115
|
|
|
114
116
|
diagonal_angles = [2, 3, 5, 7, 11, 13, 17, 19]
|
|
115
117
|
assert cirq.has_unitary(cirq.ThreeQubitDiagonalGate(diagonal_angles))
|
|
@@ -156,7 +158,7 @@ def test_eq():
|
|
|
156
158
|
eq.add_equality_group(cirq.TOFFOLI(a, b, c), cirq.CCX(a, b, c))
|
|
157
159
|
eq.add_equality_group(cirq.TOFFOLI(a, c, b), cirq.TOFFOLI(c, a, b))
|
|
158
160
|
eq.add_equality_group(cirq.TOFFOLI(a, b, d))
|
|
159
|
-
eq.add_equality_group(cirq.CSWAP(a, b, c), cirq.FREDKIN(a, b, c))
|
|
161
|
+
eq.add_equality_group(cirq.CSWAP(a, b, c), cirq.FREDKIN(a, b, c), cirq.FREDKIN(a, b, c) ** -1)
|
|
160
162
|
eq.add_equality_group(cirq.CSWAP(b, a, c), cirq.CSWAP(b, c, a))
|
|
161
163
|
|
|
162
164
|
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
+
|
|
14
15
|
"""Creates the gate instance for a two qubit diagonal gate.
|
|
15
16
|
|
|
16
17
|
The gate is used to create a 4x4 matrix with the diagonal elements
|
|
@@ -134,9 +135,8 @@ class TwoQubitDiagonalGate(raw_types.Gate):
|
|
|
134
135
|
return tuple(self._diag_angles_radians)
|
|
135
136
|
|
|
136
137
|
def __repr__(self) -> str:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
)
|
|
138
|
+
angles = ','.join(proper_repr(angle) for angle in self._diag_angles_radians)
|
|
139
|
+
return f'cirq.TwoQubitDiagonalGate([{angles}])'
|
|
140
140
|
|
|
141
141
|
def _json_dict_(self) -> Dict[str, Any]:
|
|
142
142
|
return protocols.obj_to_dict_helper(self, attribute_names=["diag_angles_radians"])
|
cirq/ops/wait_gate.py
CHANGED
|
@@ -34,7 +34,7 @@ class WaitGate(raw_types.Gate):
|
|
|
34
34
|
self,
|
|
35
35
|
duration: 'cirq.DURATION_LIKE',
|
|
36
36
|
num_qubits: Optional[int] = None,
|
|
37
|
-
qid_shape: Tuple[int, ...] = None,
|
|
37
|
+
qid_shape: Optional[Tuple[int, ...]] = None,
|
|
38
38
|
) -> None:
|
|
39
39
|
"""Initialize a wait gate with the given duration.
|
|
40
40
|
|