cirq-core 1.1.0.dev20221219200817__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/conftest.py +8 -0
- 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.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/METADATA +7 -15
- {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/RECORD +229 -215
- {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/WHEEL +1 -1
- {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/LICENSE +0 -0
- {cirq_core-1.1.0.dev20221219200817.dist-info → cirq_core-1.2.0.dist-info}/top_level.txt +0 -0
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from typing import Any, Sequence, TYPE_CHECKING, Union
|
|
15
|
+
from typing import Any, Optional, Sequence, TYPE_CHECKING, Union
|
|
16
16
|
|
|
17
17
|
from typing_extensions import Protocol
|
|
18
18
|
|
|
@@ -89,7 +89,7 @@ class SupportsActOnQubits(Protocol):
|
|
|
89
89
|
def act_on(
|
|
90
90
|
action: Any,
|
|
91
91
|
sim_state: 'cirq.SimulationStateBase',
|
|
92
|
-
qubits: Sequence['cirq.Qid'] = None,
|
|
92
|
+
qubits: Optional[Sequence['cirq.Qid']] = None,
|
|
93
93
|
*,
|
|
94
94
|
allow_decompose: bool = True,
|
|
95
95
|
):
|
|
@@ -149,7 +149,7 @@ def act_on(
|
|
|
149
149
|
|
|
150
150
|
arg_fallback = getattr(sim_state, '_act_on_fallback_', None)
|
|
151
151
|
if arg_fallback is not None:
|
|
152
|
-
qubits = action.qubits if
|
|
152
|
+
qubits = action.qubits if is_op else qubits
|
|
153
153
|
result = arg_fallback(action, qubits=qubits, allow_decompose=allow_decompose)
|
|
154
154
|
if result is True:
|
|
155
155
|
return
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
from typing import Any, Sequence, Tuple
|
|
15
|
+
from typing_extensions import Self
|
|
15
16
|
|
|
16
17
|
import numpy as np
|
|
17
18
|
import pytest
|
|
18
19
|
|
|
19
20
|
import cirq
|
|
20
|
-
from cirq.ops.raw_types import TSelf
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class DummyQuantumState(cirq.QuantumStateRepresentation):
|
|
@@ -62,10 +62,10 @@ def test_act_on_fallback_errors():
|
|
|
62
62
|
def test_act_on_errors():
|
|
63
63
|
class Op(cirq.Operation):
|
|
64
64
|
@property
|
|
65
|
-
def qubits(self) -> Tuple['cirq.Qid', ...]:
|
|
65
|
+
def qubits(self) -> Tuple['cirq.Qid', ...]: # type: ignore[empty-body]
|
|
66
66
|
pass
|
|
67
67
|
|
|
68
|
-
def with_qubits(self
|
|
68
|
+
def with_qubits(self, *new_qubits: 'cirq.Qid') -> Self: # type: ignore[empty-body]
|
|
69
69
|
pass
|
|
70
70
|
|
|
71
71
|
def _act_on_(self, sim_state):
|
|
@@ -79,10 +79,10 @@ def test_act_on_errors():
|
|
|
79
79
|
def test_qubits_not_allowed_for_operations():
|
|
80
80
|
class Op(cirq.Operation):
|
|
81
81
|
@property
|
|
82
|
-
def qubits(self) -> Tuple['cirq.Qid', ...]:
|
|
82
|
+
def qubits(self) -> Tuple['cirq.Qid', ...]: # type: ignore[empty-body]
|
|
83
83
|
pass
|
|
84
84
|
|
|
85
|
-
def with_qubits(self
|
|
85
|
+
def with_qubits(self, *new_qubits: 'cirq.Qid') -> Self: # type: ignore[empty-body]
|
|
86
86
|
pass
|
|
87
87
|
|
|
88
88
|
state = DummySimulationState()
|
|
@@ -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
|
"""A protocol for implementing high performance channel evolutions."""
|
|
15
16
|
|
|
16
17
|
from typing import Any, Iterable, Optional, Sequence, TypeVar, Tuple, Union
|
|
@@ -142,7 +143,7 @@ class SupportsApplyChannel(Protocol):
|
|
|
142
143
|
`args.target_tensor` and the given buffers.
|
|
143
144
|
|
|
144
145
|
Returns:
|
|
145
|
-
If the receiving object is not able to apply a
|
|
146
|
+
If the receiving object is not able to apply a channel, None
|
|
146
147
|
or NotImplemented should be returned.
|
|
147
148
|
|
|
148
149
|
If the receiving object is able to work inline, it should directly
|
|
@@ -224,13 +225,13 @@ def apply_channel(
|
|
|
224
225
|
raise ValueError(
|
|
225
226
|
'Invalid target_tensor shape or selected axes. '
|
|
226
227
|
'The selected left and right shape of target_tensor '
|
|
227
|
-
'are not equal. Got {!r} and {!r}.'
|
|
228
|
+
f'are not equal. Got {left_shape!r} and {right_shape!r}.'
|
|
228
229
|
)
|
|
229
230
|
if val_qid_shape != left_shape:
|
|
230
231
|
raise ValueError(
|
|
231
232
|
'Invalid channel qid shape is not equal to the '
|
|
232
233
|
'selected left and right shape of target_tensor. '
|
|
233
|
-
'Got {!r} but expected {!r}.'
|
|
234
|
+
f'Got {val_qid_shape!r} but expected {left_shape!r}.'
|
|
234
235
|
)
|
|
235
236
|
|
|
236
237
|
# Check if the specialized method is present.
|
|
@@ -240,9 +241,9 @@ def apply_channel(
|
|
|
240
241
|
|
|
241
242
|
def err_str(buf_num_str):
|
|
242
243
|
return (
|
|
243
|
-
"Object of type '{}' returned a result object equal to "
|
|
244
|
-
"auxiliary_buffer{}. This type violates the contract "
|
|
245
|
-
"that appears in apply_channel's documentation."
|
|
244
|
+
f"Object of type '{type(val)}' returned a result object equal to "
|
|
245
|
+
f"auxiliary_buffer{buf_num_str}. This type violates the contract "
|
|
246
|
+
"that appears in apply_channel's documentation."
|
|
246
247
|
)
|
|
247
248
|
|
|
248
249
|
assert result is not args.auxiliary_buffer0, err_str('0')
|
|
@@ -263,9 +264,9 @@ def apply_channel(
|
|
|
263
264
|
if default is not RaiseTypeErrorIfNotProvided:
|
|
264
265
|
return default
|
|
265
266
|
raise TypeError(
|
|
266
|
-
"object of type '{}' has no _apply_channel_, _apply_unitary_, "
|
|
267
|
+
f"object of type '{type(val)}' has no _apply_channel_, _apply_unitary_, "
|
|
267
268
|
"_unitary_, or _kraus_ methods (or they returned None or "
|
|
268
|
-
"NotImplemented)."
|
|
269
|
+
"NotImplemented)."
|
|
269
270
|
)
|
|
270
271
|
|
|
271
272
|
|
|
@@ -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
|
"""A protocol for implementing high performance mixture evolutions."""
|
|
15
16
|
|
|
16
17
|
from typing import Any, cast, Iterable, Optional, Tuple, TypeVar, Union
|
|
@@ -245,9 +246,9 @@ def apply_mixture(
|
|
|
245
246
|
|
|
246
247
|
def err_str(buf_num_str):
|
|
247
248
|
return (
|
|
248
|
-
"Object of type '{}' returned a result object equal to "
|
|
249
|
-
"auxiliary_buffer{}. This type violates the contract "
|
|
250
|
-
"that appears in apply_mixture's documentation."
|
|
249
|
+
f"Object of type '{type(val)}' returned a result object equal to "
|
|
250
|
+
f"auxiliary_buffer{buf_num_str}. This type violates the contract "
|
|
251
|
+
"that appears in apply_mixture's documentation."
|
|
251
252
|
)
|
|
252
253
|
|
|
253
254
|
assert result is not args.auxiliary_buffer0, err_str('0')
|
|
@@ -269,9 +270,8 @@ def apply_mixture(
|
|
|
269
270
|
if default is not RaiseTypeErrorIfNotProvided:
|
|
270
271
|
return default
|
|
271
272
|
raise TypeError(
|
|
272
|
-
"object of type '{}' has no _apply_mixture_, _apply_unitary_, "
|
|
273
|
-
"_unitary_, or _mixture_ methods (or they returned None or "
|
|
274
|
-
"NotImplemented).".format(type(val))
|
|
273
|
+
f"object of type '{type(val)}' has no _apply_mixture_, _apply_unitary_, "
|
|
274
|
+
"_unitary_, or _mixture_ methods (or they returned None or NotImplemented)."
|
|
275
275
|
)
|
|
276
276
|
|
|
277
277
|
|
|
@@ -287,7 +287,7 @@ def _validate_input(val: Any, args: 'ApplyMixtureArgs') -> Tuple[Any, 'ApplyMixt
|
|
|
287
287
|
raise ValueError(
|
|
288
288
|
'Invalid mixture qid shape is not equal to the '
|
|
289
289
|
'selected left and right shape of target_tensor. '
|
|
290
|
-
'Got {!r} but expected {!r}.'
|
|
290
|
+
f'Got {val_qid_shape!r} but expected {left_shape!r}.'
|
|
291
291
|
)
|
|
292
292
|
|
|
293
293
|
if args.right_axes is not None:
|
|
@@ -298,7 +298,7 @@ def _validate_input(val: Any, args: 'ApplyMixtureArgs') -> Tuple[Any, 'ApplyMixt
|
|
|
298
298
|
raise ValueError(
|
|
299
299
|
'Invalid target_tensor shape or selected axes. '
|
|
300
300
|
'The selected left and right shape of '
|
|
301
|
-
'target_tensor are not equal. Got {!r} and {!r}.'
|
|
301
|
+
f'target_tensor are not equal. Got {left_shape!r} and {right_shape!r}.'
|
|
302
302
|
)
|
|
303
303
|
|
|
304
304
|
return val, args, is_density_matrix
|
|
@@ -33,7 +33,7 @@ def assert_apply_mixture_returns(
|
|
|
33
33
|
left_axes: Iterable[int],
|
|
34
34
|
right_axes: Optional[Iterable[int]],
|
|
35
35
|
assert_result_is_out_buf: bool = False,
|
|
36
|
-
expected_result: np.ndarray = None,
|
|
36
|
+
expected_result: Optional[np.ndarray] = None,
|
|
37
37
|
):
|
|
38
38
|
out_buf, buf0, buf1 = make_buffers(rho.shape, rho.dtype)
|
|
39
39
|
result = cirq.apply_mixture(
|
|
@@ -11,7 +11,9 @@
|
|
|
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
|
"""A protocol for implementing high performance unitary left-multiplies."""
|
|
16
|
+
|
|
15
17
|
import warnings
|
|
16
18
|
from typing import Any, cast, Iterable, Optional, Sequence, Tuple, TYPE_CHECKING, TypeVar, Union
|
|
17
19
|
|
|
@@ -133,6 +135,33 @@ class ApplyUnitaryArgs:
|
|
|
133
135
|
state = qis.one_hot(index=(0,) * num_qubits, shape=qid_shape, dtype=np.complex128)
|
|
134
136
|
return ApplyUnitaryArgs(state, np.empty_like(state), range(num_qubits))
|
|
135
137
|
|
|
138
|
+
@classmethod
|
|
139
|
+
def for_unitary(
|
|
140
|
+
cls, num_qubits: Optional[int] = None, *, qid_shape: Optional[Tuple[int, ...]] = None
|
|
141
|
+
) -> 'ApplyUnitaryArgs':
|
|
142
|
+
"""A default instance corresponding to an identity matrix.
|
|
143
|
+
|
|
144
|
+
Specify exactly one argument.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
num_qubits: The number of qubits to make space for in the state.
|
|
148
|
+
qid_shape: A tuple representing the number of quantum levels of each
|
|
149
|
+
qubit the identity matrix applies to. `qid_shape` is (2, 2, 2) for
|
|
150
|
+
a three-qubit identity operation tensor.
|
|
151
|
+
|
|
152
|
+
Raises:
|
|
153
|
+
TypeError: If exactly neither `num_qubits` or `qid_shape` is provided or
|
|
154
|
+
both are provided.
|
|
155
|
+
"""
|
|
156
|
+
if (num_qubits is None) == (qid_shape is None):
|
|
157
|
+
raise TypeError('Specify exactly one of num_qubits or qid_shape.')
|
|
158
|
+
if num_qubits is not None:
|
|
159
|
+
qid_shape = (2,) * num_qubits
|
|
160
|
+
qid_shape = cast(Tuple[int, ...], qid_shape) # Satisfy mypy
|
|
161
|
+
num_qubits = len(qid_shape)
|
|
162
|
+
state = qis.eye_tensor(qid_shape, dtype=np.complex128)
|
|
163
|
+
return ApplyUnitaryArgs(state, np.empty_like(state), range(num_qubits))
|
|
164
|
+
|
|
136
165
|
def with_axes_transposed_to_start(self) -> 'ApplyUnitaryArgs':
|
|
137
166
|
"""Returns a transposed view of the same arguments.
|
|
138
167
|
|
|
@@ -376,8 +405,8 @@ def apply_unitary(
|
|
|
376
405
|
"cirq.apply_unitary failed. "
|
|
377
406
|
"Value doesn't have a (non-parameterized) unitary effect.\n"
|
|
378
407
|
"\n"
|
|
379
|
-
"type: {}\n"
|
|
380
|
-
"value: {!r}\n"
|
|
408
|
+
f"type: {type(unitary_value)}\n"
|
|
409
|
+
f"value: {unitary_value!r}\n"
|
|
381
410
|
"\n"
|
|
382
411
|
"The value failed to satisfy any of the following criteria:\n"
|
|
383
412
|
"- An `_apply_unitary_(self, args) method that returned a value "
|
|
@@ -386,7 +415,6 @@ def apply_unitary(
|
|
|
386
415
|
"besides None or NotImplemented.\n"
|
|
387
416
|
"- A `_decompose_(self)` method that returned a "
|
|
388
417
|
"list of unitary operations.\n"
|
|
389
|
-
"".format(type(unitary_value), unitary_value)
|
|
390
418
|
)
|
|
391
419
|
|
|
392
420
|
|
|
@@ -409,19 +437,7 @@ def _strat_apply_unitary_from_apply_unitary(
|
|
|
409
437
|
return _incorporate_result_into_target(args, sub_args, sub_result)
|
|
410
438
|
|
|
411
439
|
|
|
412
|
-
def
|
|
413
|
-
unitary_value: Any, args: ApplyUnitaryArgs
|
|
414
|
-
) -> Optional[np.ndarray]:
|
|
415
|
-
# Check for magic method.
|
|
416
|
-
method = getattr(unitary_value, '_unitary_', None)
|
|
417
|
-
if method is None:
|
|
418
|
-
return NotImplemented
|
|
419
|
-
|
|
420
|
-
# Attempt to get the unitary matrix.
|
|
421
|
-
matrix = method()
|
|
422
|
-
if matrix is NotImplemented or matrix is None:
|
|
423
|
-
return matrix
|
|
424
|
-
|
|
440
|
+
def _apply_unitary_from_matrix(matrix: np.ndarray, unitary_value: Any, args: ApplyUnitaryArgs):
|
|
425
441
|
if args.slices is None:
|
|
426
442
|
val_qid_shape = qid_shape_protocol.qid_shape(unitary_value, default=(2,) * len(args.axes))
|
|
427
443
|
slices = tuple(slice(0, size) for size in val_qid_shape)
|
|
@@ -450,11 +466,42 @@ def _strat_apply_unitary_from_unitary(
|
|
|
450
466
|
return _incorporate_result_into_target(args, sub_args, sub_result)
|
|
451
467
|
|
|
452
468
|
|
|
469
|
+
def _strat_apply_unitary_from_unitary(
|
|
470
|
+
unitary_value: Any, args: ApplyUnitaryArgs
|
|
471
|
+
) -> Optional[np.ndarray]:
|
|
472
|
+
# Check for magic method.
|
|
473
|
+
method = getattr(unitary_value, '_unitary_', None)
|
|
474
|
+
if method is None:
|
|
475
|
+
return NotImplemented
|
|
476
|
+
|
|
477
|
+
# Attempt to get the unitary matrix.
|
|
478
|
+
matrix = method()
|
|
479
|
+
if matrix is NotImplemented or matrix is None:
|
|
480
|
+
return matrix
|
|
481
|
+
|
|
482
|
+
return _apply_unitary_from_matrix(matrix, unitary_value, args)
|
|
483
|
+
|
|
484
|
+
|
|
453
485
|
def _strat_apply_unitary_from_decompose(val: Any, args: ApplyUnitaryArgs) -> Optional[np.ndarray]:
|
|
454
486
|
operations, qubits, _ = _try_decompose_into_operations_and_qubits(val)
|
|
455
487
|
if operations is None:
|
|
456
488
|
return NotImplemented
|
|
457
|
-
|
|
489
|
+
all_qubits = frozenset([q for op in operations for q in op.qubits])
|
|
490
|
+
ancilla = tuple(sorted(all_qubits.difference(qubits)))
|
|
491
|
+
if not len(ancilla):
|
|
492
|
+
return apply_unitaries(operations, qubits, args, None)
|
|
493
|
+
ordered_qubits = ancilla + tuple(qubits)
|
|
494
|
+
all_qid_shapes = qid_shape_protocol.qid_shape(ordered_qubits)
|
|
495
|
+
result = apply_unitaries(
|
|
496
|
+
operations, ordered_qubits, ApplyUnitaryArgs.for_unitary(qid_shape=all_qid_shapes), None
|
|
497
|
+
)
|
|
498
|
+
if result is None or result is NotImplemented:
|
|
499
|
+
return result
|
|
500
|
+
result = result.reshape((np.prod(all_qid_shapes, dtype=np.int64), -1))
|
|
501
|
+
val_qid_shape = qid_shape_protocol.qid_shape(qubits)
|
|
502
|
+
state_vec_length = np.prod(val_qid_shape, dtype=np.int64)
|
|
503
|
+
result = result[:state_vec_length, :state_vec_length]
|
|
504
|
+
return _apply_unitary_from_matrix(result, val, args)
|
|
458
505
|
|
|
459
506
|
|
|
460
507
|
def apply_unitaries(
|
|
@@ -528,8 +575,8 @@ def apply_unitaries(
|
|
|
528
575
|
"There was a non-unitary value in the `unitary_values` "
|
|
529
576
|
"list.\n"
|
|
530
577
|
"\n"
|
|
531
|
-
"non-unitary value type: {}\n"
|
|
532
|
-
"non-unitary value: {!r}"
|
|
578
|
+
f"non-unitary value type: {type(op)}\n"
|
|
579
|
+
f"non-unitary value: {op!r}"
|
|
533
580
|
)
|
|
534
581
|
return default
|
|
535
582
|
|
|
@@ -717,3 +717,53 @@ def test_cast_to_complex():
|
|
|
717
717
|
np.ComplexWarning, match='Casting complex values to real discards the imaginary part'
|
|
718
718
|
):
|
|
719
719
|
cirq.apply_unitary(y0, args)
|
|
720
|
+
|
|
721
|
+
|
|
722
|
+
class NotDecomposableGate(cirq.Gate):
|
|
723
|
+
def num_qubits(self):
|
|
724
|
+
return 1
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
class DecomposableGate(cirq.Gate):
|
|
728
|
+
def __init__(self, sub_gate: cirq.Gate, allocate_ancilla: bool) -> None:
|
|
729
|
+
super().__init__()
|
|
730
|
+
self._sub_gate = sub_gate
|
|
731
|
+
self._allocate_ancilla = allocate_ancilla
|
|
732
|
+
|
|
733
|
+
def num_qubits(self):
|
|
734
|
+
return 1
|
|
735
|
+
|
|
736
|
+
def _decompose_(self, qubits):
|
|
737
|
+
if self._allocate_ancilla:
|
|
738
|
+
yield cirq.Z(cirq.NamedQubit('DecomposableGateQubit'))
|
|
739
|
+
yield self._sub_gate(qubits[0])
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
def test_strat_apply_unitary_from_decompose():
|
|
743
|
+
state = np.eye(2, dtype=np.complex128)
|
|
744
|
+
args = cirq.ApplyUnitaryArgs(
|
|
745
|
+
target_tensor=state, available_buffer=np.zeros_like(state), axes=(0,)
|
|
746
|
+
)
|
|
747
|
+
np.testing.assert_allclose(
|
|
748
|
+
cirq.apply_unitaries(
|
|
749
|
+
[DecomposableGate(cirq.X, False)(cirq.LineQubit(0))], [cirq.LineQubit(0)], args
|
|
750
|
+
),
|
|
751
|
+
[[0, 1], [1, 0]],
|
|
752
|
+
)
|
|
753
|
+
|
|
754
|
+
with pytest.raises(TypeError):
|
|
755
|
+
_ = cirq.apply_unitaries(
|
|
756
|
+
[DecomposableGate(NotDecomposableGate(), True)(cirq.LineQubit(0))],
|
|
757
|
+
[cirq.LineQubit(0)],
|
|
758
|
+
args,
|
|
759
|
+
)
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
def test_unitary_construction():
|
|
763
|
+
with pytest.raises(TypeError):
|
|
764
|
+
_ = cirq.ApplyUnitaryArgs.for_unitary()
|
|
765
|
+
|
|
766
|
+
np.testing.assert_allclose(
|
|
767
|
+
cirq.ApplyUnitaryArgs.for_unitary(num_qubits=3).target_tensor,
|
|
768
|
+
cirq.eye_tensor((2,) * 3, dtype=np.complex128),
|
|
769
|
+
)
|
|
@@ -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
|
import re
|
|
15
16
|
from fractions import Fraction
|
|
16
17
|
from typing import (
|
|
@@ -73,7 +74,7 @@ class CircuitDiagramInfo:
|
|
|
73
74
|
could be mistaken for an identity wire). Defaults to True.
|
|
74
75
|
|
|
75
76
|
Raises:
|
|
76
|
-
ValueError: If `wire_symbols` is a string, and not an
|
|
77
|
+
ValueError: If `wire_symbols` is a string, and not an iterable
|
|
77
78
|
of strings.
|
|
78
79
|
"""
|
|
79
80
|
if isinstance(wire_symbols, str):
|
|
@@ -118,13 +119,10 @@ class CircuitDiagramInfo:
|
|
|
118
119
|
else:
|
|
119
120
|
ks = (0,)
|
|
120
121
|
for k in ks:
|
|
121
|
-
result[k] +=
|
|
122
|
+
result[k] += f"^{exponent}"
|
|
122
123
|
return result
|
|
123
124
|
|
|
124
|
-
def _formatted_exponent(
|
|
125
|
-
self: 'cirq.CircuitDiagramInfo', args: 'cirq.CircuitDiagramInfoArgs'
|
|
126
|
-
) -> Optional[str]:
|
|
127
|
-
|
|
125
|
+
def _formatted_exponent(self, args: 'cirq.CircuitDiagramInfoArgs') -> Optional[str]:
|
|
128
126
|
if protocols.is_parameterized(self.exponent):
|
|
129
127
|
name = str(self.exponent)
|
|
130
128
|
return f'({name})' if _is_exposed_formula(name) else name
|
|
@@ -273,7 +271,7 @@ class CircuitDiagramInfoArgs:
|
|
|
273
271
|
if radians == 0:
|
|
274
272
|
return '0'
|
|
275
273
|
if radians == -np.pi:
|
|
276
|
-
return
|
|
274
|
+
return f"-{unit}"
|
|
277
275
|
if self.precision is not None and not isinstance(radians, sympy.Basic):
|
|
278
276
|
quantity = self.format_real(radians / np.pi)
|
|
279
277
|
return quantity + unit
|
|
@@ -433,8 +431,8 @@ def circuit_diagram_info(
|
|
|
433
431
|
if getter is None:
|
|
434
432
|
raise TypeError(f"object of type '{type(val)}' has no _circuit_diagram_info_ method.")
|
|
435
433
|
raise TypeError(
|
|
436
|
-
"object of type '{}' does have a _circuit_diagram_info_ "
|
|
437
|
-
"method, but it returned NotImplemented."
|
|
434
|
+
f"object of type '{type(val)}' does have a _circuit_diagram_info_ "
|
|
435
|
+
"method, but it returned NotImplemented."
|
|
438
436
|
)
|
|
439
437
|
|
|
440
438
|
|