cirq-core 1.6.0.dev20250520054601__py3-none-any.whl → 1.6.0.dev20250520181654__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.
Potentially problematic release.
This version of cirq-core might be problematic. Click here for more details.
- cirq/_compat.py +15 -17
- cirq/_compat_test.py +6 -9
- cirq/_doc.py +2 -2
- cirq/_import.py +6 -6
- cirq/_version.py +1 -1
- cirq/_version_test.py +1 -1
- cirq/circuits/_block_diagram_drawer.py +9 -10
- cirq/circuits/_box_drawing_character_data.py +6 -8
- cirq/circuits/_bucket_priority_queue.py +7 -7
- cirq/circuits/circuit.py +118 -125
- cirq/circuits/circuit_operation.py +38 -52
- cirq/circuits/circuit_test.py +4 -4
- cirq/circuits/frozen_circuit.py +13 -23
- cirq/circuits/moment.py +23 -29
- cirq/circuits/optimization_pass.py +4 -4
- cirq/circuits/optimization_pass_test.py +4 -6
- cirq/circuits/qasm_output.py +11 -11
- cirq/circuits/text_diagram_drawer.py +21 -36
- cirq/contrib/acquaintance/bipartite.py +5 -8
- cirq/contrib/acquaintance/executor.py +5 -5
- cirq/contrib/acquaintance/executor_test.py +3 -3
- cirq/contrib/acquaintance/gates.py +16 -26
- cirq/contrib/acquaintance/gates_test.py +3 -3
- cirq/contrib/acquaintance/mutation_utils.py +4 -4
- cirq/contrib/acquaintance/optimizers.py +4 -4
- cirq/contrib/acquaintance/permutation.py +15 -27
- cirq/contrib/acquaintance/shift.py +3 -3
- cirq/contrib/acquaintance/shift_swap_network.py +4 -4
- cirq/contrib/acquaintance/strategies/cubic.py +2 -2
- cirq/contrib/acquaintance/strategies/quartic_paired.py +6 -6
- cirq/contrib/bayesian_network/bayesian_network_gate.py +9 -10
- cirq/contrib/circuitdag/circuit_dag.py +2 -2
- cirq/contrib/custom_simulators/custom_state_simulator.py +3 -3
- cirq/contrib/custom_simulators/custom_state_simulator_test.py +4 -4
- cirq/contrib/graph_device/graph_device.py +5 -5
- cirq/contrib/graph_device/hypergraph.py +12 -12
- cirq/contrib/graph_device/uniform_graph_device.py +4 -4
- cirq/contrib/paulistring/clifford_optimize.py +2 -2
- cirq/contrib/paulistring/clifford_target_gateset.py +7 -7
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +31 -31
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +23 -23
- cirq/contrib/paulistring/recombine.py +3 -3
- cirq/contrib/paulistring/separate.py +2 -2
- cirq/contrib/qasm_import/_parser.py +20 -32
- cirq/contrib/qcircuit/qcircuit_diagram_info.py +3 -5
- cirq/contrib/quantum_volume/quantum_volume.py +24 -24
- cirq/contrib/quimb/density_matrix.py +12 -14
- cirq/contrib/quimb/mps_simulator.py +20 -20
- cirq/contrib/quimb/state_vector.py +6 -10
- cirq/contrib/quirk/export_to_quirk.py +3 -3
- cirq/contrib/quirk/quirk_gate.py +15 -15
- cirq/contrib/routing/device.py +3 -3
- cirq/contrib/routing/greedy.py +10 -21
- cirq/contrib/routing/initialization.py +2 -2
- cirq/contrib/routing/swap_network.py +3 -3
- cirq/contrib/routing/utils.py +2 -2
- cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +8 -8
- cirq/contrib/svg/svg.py +3 -3
- cirq/devices/grid_device_metadata.py +10 -10
- cirq/devices/grid_qubit.py +20 -20
- cirq/devices/insertion_noise_model.py +5 -5
- cirq/devices/line_qubit.py +13 -13
- cirq/devices/named_topologies.py +18 -29
- cirq/devices/noise_model.py +3 -3
- cirq/devices/noise_properties.py +2 -2
- cirq/devices/noise_properties_test.py +1 -3
- cirq/devices/noise_utils.py +7 -7
- cirq/devices/superconducting_qubits_noise_properties.py +21 -21
- cirq/devices/superconducting_qubits_noise_properties_test.py +5 -7
- cirq/devices/thermal_noise_model.py +14 -14
- cirq/devices/unconstrained_device.py +2 -2
- cirq/experiments/benchmarking/parallel_xeb.py +29 -31
- cirq/experiments/n_qubit_tomography.py +5 -7
- cirq/experiments/qubit_characterizations.py +29 -40
- cirq/experiments/qubit_characterizations_test.py +1 -1
- cirq/experiments/random_quantum_circuit_generation.py +19 -33
- cirq/experiments/random_quantum_circuit_generation_test.py +6 -6
- cirq/experiments/readout_confusion_matrix.py +14 -14
- cirq/experiments/single_qubit_readout_calibration.py +12 -12
- cirq/experiments/t2_decay_experiment.py +7 -7
- cirq/experiments/two_qubit_xeb.py +32 -32
- cirq/experiments/two_qubit_xeb_test.py +5 -5
- cirq/experiments/xeb_fitting.py +25 -25
- cirq/experiments/xeb_sampling.py +22 -33
- cirq/experiments/xeb_simulation.py +5 -5
- cirq/experiments/xeb_simulation_test.py +3 -3
- cirq/experiments/z_phase_calibration.py +19 -19
- cirq/interop/quirk/cells/arithmetic_cells.py +23 -36
- cirq/interop/quirk/cells/cell.py +9 -21
- cirq/interop/quirk/cells/composite_cell.py +7 -22
- cirq/interop/quirk/cells/control_cells.py +8 -8
- cirq/interop/quirk/cells/input_cells.py +4 -4
- cirq/interop/quirk/cells/input_rotation_cells.py +5 -5
- cirq/interop/quirk/cells/parse.py +20 -23
- cirq/interop/quirk/cells/qubit_permutation_cells.py +3 -3
- cirq/interop/quirk/cells/swap_cell.py +3 -3
- cirq/interop/quirk/cells/testing.py +5 -7
- cirq/interop/quirk/url_to_circuit.py +17 -33
- cirq/json_resolver_cache.py +6 -6
- cirq/linalg/decompositions.py +20 -31
- cirq/linalg/diagonalize.py +4 -4
- cirq/linalg/diagonalize_test.py +3 -4
- cirq/linalg/operator_spaces.py +5 -5
- cirq/linalg/predicates.py +7 -7
- cirq/linalg/transformations.py +20 -20
- cirq/ops/arithmetic_operation.py +13 -15
- cirq/ops/boolean_hamiltonian.py +17 -17
- cirq/ops/classically_controlled_operation.py +13 -25
- cirq/ops/clifford_gate.py +31 -35
- cirq/ops/clifford_gate_test.py +2 -3
- cirq/ops/common_channels.py +30 -32
- cirq/ops/common_gates.py +64 -74
- cirq/ops/control_values.py +12 -12
- cirq/ops/controlled_gate.py +15 -30
- cirq/ops/controlled_gate_test.py +5 -5
- cirq/ops/controlled_operation.py +12 -25
- cirq/ops/controlled_operation_test.py +5 -5
- cirq/ops/dense_pauli_string.py +23 -34
- cirq/ops/dense_pauli_string_test.py +1 -2
- cirq/ops/diagonal_gate.py +9 -20
- cirq/ops/diagonal_gate_test.py +1 -3
- cirq/ops/eigen_gate.py +11 -23
- cirq/ops/eigen_gate_test.py +6 -8
- cirq/ops/fourier_transform.py +5 -5
- cirq/ops/fsim_gate.py +14 -14
- cirq/ops/gate_operation.py +23 -44
- cirq/ops/gateset.py +23 -37
- cirq/ops/gateset_test.py +2 -2
- cirq/ops/global_phase_op.py +8 -10
- cirq/ops/greedy_qubit_manager.py +6 -6
- cirq/ops/identity.py +9 -9
- cirq/ops/kraus_channel.py +7 -7
- cirq/ops/linear_combinations.py +29 -48
- cirq/ops/matrix_gates.py +8 -8
- cirq/ops/measure_util.py +13 -14
- cirq/ops/measurement_gate.py +18 -29
- cirq/ops/mixed_unitary_channel.py +8 -8
- cirq/ops/named_qubit.py +10 -10
- cirq/ops/op_tree.py +7 -7
- cirq/ops/parallel_gate.py +5 -5
- cirq/ops/parity_gates.py +14 -14
- cirq/ops/pauli_gates.py +8 -10
- cirq/ops/pauli_interaction_gate.py +6 -6
- cirq/ops/pauli_measurement_gate.py +11 -23
- cirq/ops/pauli_string.py +35 -52
- cirq/ops/pauli_string_phasor.py +4 -14
- cirq/ops/pauli_string_raw_types.py +3 -3
- cirq/ops/pauli_sum_exponential.py +2 -2
- cirq/ops/permutation_gate.py +4 -4
- cirq/ops/phased_iswap_gate.py +9 -9
- cirq/ops/phased_x_gate.py +10 -10
- cirq/ops/phased_x_z_gate.py +11 -11
- cirq/ops/projector.py +6 -6
- cirq/ops/qubit_manager.py +6 -6
- cirq/ops/qubit_order.py +3 -3
- cirq/ops/random_gate_channel.py +4 -4
- cirq/ops/raw_types.py +48 -70
- cirq/ops/state_preparation_channel.py +3 -3
- cirq/ops/swap_gates.py +9 -9
- cirq/ops/tags.py +2 -4
- cirq/ops/three_qubit_gates.py +20 -38
- cirq/ops/two_qubit_diagonal_gate.py +5 -5
- cirq/ops/uniform_superposition_gate.py +2 -2
- cirq/ops/wait_gate.py +5 -5
- cirq/protocols/act_on_protocol_test.py +3 -3
- cirq/protocols/apply_channel_protocol.py +8 -14
- cirq/protocols/apply_mixture_protocol.py +14 -16
- cirq/protocols/apply_mixture_protocol_test.py +5 -6
- cirq/protocols/apply_unitary_protocol.py +17 -19
- cirq/protocols/circuit_diagram_info_protocol.py +19 -30
- cirq/protocols/decompose_protocol.py +30 -34
- cirq/protocols/inverse_protocol.py +7 -7
- cirq/protocols/json_serialization.py +32 -51
- cirq/protocols/json_serialization_test.py +9 -10
- cirq/protocols/kraus_protocol.py +4 -4
- cirq/protocols/kraus_protocol_test.py +3 -3
- cirq/protocols/measurement_key_protocol.py +11 -13
- cirq/protocols/mixture_protocol.py +4 -4
- cirq/protocols/qasm.py +11 -13
- cirq/protocols/qid_shape_protocol.py +6 -8
- cirq/qis/clifford_tableau.py +12 -12
- cirq/qis/measures.py +7 -7
- cirq/qis/quantum_state_representation.py +3 -3
- cirq/qis/states.py +51 -51
- cirq/sim/classical_simulator.py +10 -10
- cirq/sim/clifford/clifford_simulator.py +6 -6
- cirq/sim/clifford/clifford_tableau_simulation_state_test.py +1 -3
- cirq/sim/clifford/stabilizer_sampler.py +4 -4
- cirq/sim/clifford/stabilizer_state_ch_form.py +3 -3
- cirq/sim/density_matrix_simulation_state.py +15 -15
- cirq/sim/density_matrix_simulator.py +11 -11
- cirq/sim/density_matrix_utils.py +9 -9
- cirq/sim/mux.py +9 -9
- cirq/sim/simulation_product_state.py +9 -9
- cirq/sim/simulation_product_state_test.py +2 -2
- cirq/sim/simulation_state.py +14 -27
- cirq/sim/simulation_state_base.py +8 -24
- cirq/sim/simulation_utils.py +3 -4
- cirq/sim/simulator.py +28 -43
- cirq/sim/simulator_base.py +12 -25
- cirq/sim/simulator_base_test.py +6 -6
- cirq/sim/simulator_test.py +7 -7
- cirq/sim/sparse_simulator.py +8 -8
- cirq/sim/state_vector.py +8 -8
- cirq/sim/state_vector_simulation_state.py +17 -17
- cirq/sim/state_vector_simulator.py +4 -4
- cirq/study/flatten_expressions.py +12 -14
- cirq/study/resolver.py +9 -11
- cirq/study/result.py +11 -24
- cirq/study/sweepable.py +5 -5
- cirq/study/sweeps.py +27 -40
- cirq/testing/circuit_compare.py +5 -5
- cirq/testing/consistent_controlled_gate_op_test.py +7 -11
- cirq/testing/consistent_protocols.py +10 -10
- cirq/testing/consistent_protocols_test.py +7 -7
- cirq/testing/consistent_qasm.py +4 -4
- cirq/testing/consistent_qasm_test.py +2 -3
- cirq/testing/devices.py +4 -5
- cirq/testing/equals_tester.py +2 -2
- cirq/testing/equivalent_basis_map.py +4 -4
- cirq/testing/equivalent_repr_eval.py +3 -3
- cirq/testing/json.py +14 -14
- cirq/testing/logs.py +3 -3
- cirq/testing/no_identifier_qubit.py +2 -3
- cirq/testing/random_circuit.py +7 -7
- cirq/testing/random_circuit_test.py +3 -3
- cirq/transformers/analytical_decompositions/clifford_decomposition.py +16 -16
- cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +13 -13
- cirq/transformers/analytical_decompositions/cphase_to_fsim.py +5 -5
- cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py +3 -3
- cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +3 -3
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +4 -4
- cirq/transformers/analytical_decompositions/single_qubit_decompositions.py +6 -7
- cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry.py +2 -2
- cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +7 -7
- cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py +4 -4
- cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +7 -7
- cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +11 -11
- cirq/transformers/analytical_decompositions/two_qubit_to_ms.py +5 -5
- cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py +14 -14
- cirq/transformers/dynamical_decoupling.py +13 -13
- cirq/transformers/dynamical_decoupling_test.py +4 -4
- cirq/transformers/eject_phased_paulis.py +16 -16
- cirq/transformers/eject_z.py +5 -7
- cirq/transformers/gauge_compiling/gauge_compiling.py +38 -38
- cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +2 -2
- cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +8 -8
- cirq/transformers/insertion_sort.py +5 -5
- cirq/transformers/measurement_transformers.py +14 -14
- cirq/transformers/merge_k_qubit_gates_test.py +1 -3
- cirq/transformers/merge_single_qubit_gates_test.py +1 -3
- cirq/transformers/qubit_management_transformers.py +5 -5
- cirq/transformers/routing/initial_mapper.py +4 -4
- cirq/transformers/routing/line_initial_mapper.py +9 -9
- cirq/transformers/routing/mapping_manager.py +7 -7
- cirq/transformers/routing/route_circuit_cqc.py +27 -27
- cirq/transformers/routing/visualize_routed_circuit.py +4 -4
- cirq/transformers/stratify.py +8 -8
- cirq/transformers/synchronize_terminal_measurements.py +6 -6
- cirq/transformers/target_gatesets/compilation_target_gateset.py +8 -8
- cirq/transformers/target_gatesets/compilation_target_gateset_test.py +2 -2
- cirq/transformers/target_gatesets/cz_gateset.py +4 -4
- cirq/transformers/target_gatesets/sqrt_iswap_gateset.py +5 -5
- cirq/transformers/transformer_api.py +11 -26
- cirq/transformers/transformer_primitives.py +24 -36
- cirq/transformers/transformer_primitives_test.py +3 -3
- cirq/value/classical_data.py +18 -18
- cirq/value/condition.py +8 -8
- cirq/value/digits.py +7 -7
- cirq/value/duration.py +12 -12
- cirq/value/linear_dict.py +8 -12
- cirq/value/measurement_key.py +8 -8
- cirq/value/product_state.py +9 -9
- cirq/value/value_equality_attr.py +4 -4
- cirq/vis/heatmap.py +23 -35
- cirq/work/collector.py +9 -17
- cirq/work/observable_grouping.py +4 -7
- cirq/work/observable_measurement.py +29 -41
- cirq/work/observable_measurement_data.py +14 -14
- cirq/work/observable_measurement_test.py +2 -2
- cirq/work/observable_settings.py +9 -10
- cirq/work/pauli_sum_collector.py +5 -5
- cirq/work/sampler.py +17 -17
- cirq/work/zeros_sampler.py +3 -3
- {cirq_core-1.6.0.dev20250520054601.dist-info → cirq_core-1.6.0.dev20250520181654.dist-info}/METADATA +1 -1
- {cirq_core-1.6.0.dev20250520054601.dist-info → cirq_core-1.6.0.dev20250520181654.dist-info}/RECORD +289 -289
- {cirq_core-1.6.0.dev20250520054601.dist-info → cirq_core-1.6.0.dev20250520181654.dist-info}/WHEEL +1 -1
- {cirq_core-1.6.0.dev20250520054601.dist-info → cirq_core-1.6.0.dev20250520181654.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.6.0.dev20250520054601.dist-info → cirq_core-1.6.0.dev20250520181654.dist-info}/top_level.txt +0 -0
cirq/linalg/decompositions.py
CHANGED
|
@@ -18,18 +18,7 @@ from __future__ import annotations
|
|
|
18
18
|
|
|
19
19
|
import cmath
|
|
20
20
|
import math
|
|
21
|
-
from typing import
|
|
22
|
-
Any,
|
|
23
|
-
Callable,
|
|
24
|
-
cast,
|
|
25
|
-
Iterable,
|
|
26
|
-
List,
|
|
27
|
-
Optional,
|
|
28
|
-
Tuple,
|
|
29
|
-
TYPE_CHECKING,
|
|
30
|
-
TypeVar,
|
|
31
|
-
Union,
|
|
32
|
-
)
|
|
21
|
+
from typing import Any, Callable, cast, Iterable, TYPE_CHECKING, TypeVar
|
|
33
22
|
|
|
34
23
|
import matplotlib.pyplot as plt
|
|
35
24
|
import numpy as np
|
|
@@ -70,7 +59,7 @@ def _rotation_matrix(angle: float) -> np.ndarray:
|
|
|
70
59
|
return np.array([[c, -s], [s, c]])
|
|
71
60
|
|
|
72
61
|
|
|
73
|
-
def deconstruct_single_qubit_matrix_into_angles(mat: np.ndarray) ->
|
|
62
|
+
def deconstruct_single_qubit_matrix_into_angles(mat: np.ndarray) -> tuple[float, float, float]:
|
|
74
63
|
r"""Breaks down a 2x2 unitary into ZYZ angle parameters.
|
|
75
64
|
|
|
76
65
|
Given a unitary U, this function returns three angles: $\phi_0, \phi_1, \phi_2$,
|
|
@@ -108,7 +97,7 @@ def deconstruct_single_qubit_matrix_into_angles(mat: np.ndarray) -> Tuple[float,
|
|
|
108
97
|
|
|
109
98
|
def unitary_eig(
|
|
110
99
|
matrix: np.ndarray, check_preconditions: bool = True, atol: float = 1e-8
|
|
111
|
-
) ->
|
|
100
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
112
101
|
r"""Gives the guaranteed unitary eigendecomposition of a normal matrix.
|
|
113
102
|
|
|
114
103
|
All hermitian and unitary matrices are normal matrices. This method was
|
|
@@ -169,7 +158,7 @@ def map_eigenvalues(
|
|
|
169
158
|
|
|
170
159
|
def kron_factor_4x4_to_2x2s(
|
|
171
160
|
matrix: np.ndarray, rtol=1e-5, atol=1e-8
|
|
172
|
-
) ->
|
|
161
|
+
) -> tuple[complex, np.ndarray, np.ndarray]:
|
|
173
162
|
"""Splits a 4x4 matrix U = kron(A, B) into A, B, and a global factor.
|
|
174
163
|
|
|
175
164
|
Requires the matrix to be the kronecker product of two 2x2 unitaries.
|
|
@@ -219,7 +208,7 @@ def kron_factor_4x4_to_2x2s(
|
|
|
219
208
|
|
|
220
209
|
def so4_to_magic_su2s(
|
|
221
210
|
mat: np.ndarray, *, rtol: float = 1e-5, atol: float = 1e-8, check_preconditions: bool = True
|
|
222
|
-
) ->
|
|
211
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
223
212
|
"""Finds 2x2 special-unitaries A, B where mat = Mag.H @ kron(A, B) @ Mag.
|
|
224
213
|
|
|
225
214
|
Mag is the magic basis matrix:
|
|
@@ -265,7 +254,7 @@ class AxisAngleDecomposition:
|
|
|
265
254
|
rotation axis, and g is the global phase.
|
|
266
255
|
"""
|
|
267
256
|
|
|
268
|
-
def __init__(self, *, angle: float, axis:
|
|
257
|
+
def __init__(self, *, angle: float, axis: tuple[float, float, float], global_phase: complex):
|
|
269
258
|
if not np.isclose(np.linalg.norm(axis, 2), 1, atol=1e-8):
|
|
270
259
|
raise ValueError('Axis vector must be normalized.')
|
|
271
260
|
self.global_phase = complex(global_phase)
|
|
@@ -413,9 +402,9 @@ class KakDecomposition:
|
|
|
413
402
|
self,
|
|
414
403
|
*,
|
|
415
404
|
global_phase: complex = complex(1),
|
|
416
|
-
single_qubit_operations_before:
|
|
417
|
-
interaction_coefficients:
|
|
418
|
-
single_qubit_operations_after:
|
|
405
|
+
single_qubit_operations_before: tuple[np.ndarray, np.ndarray] | None = None,
|
|
406
|
+
interaction_coefficients: tuple[float, float, float],
|
|
407
|
+
single_qubit_operations_after: tuple[np.ndarray, np.ndarray] | None = None,
|
|
419
408
|
):
|
|
420
409
|
"""Initializes a decomposition for a two-qubit operation U.
|
|
421
410
|
|
|
@@ -428,12 +417,12 @@ class KakDecomposition:
|
|
|
428
417
|
single_qubit_operations_after: a0, a1 from the above equation.
|
|
429
418
|
"""
|
|
430
419
|
self.global_phase: complex = global_phase
|
|
431
|
-
self.single_qubit_operations_before:
|
|
420
|
+
self.single_qubit_operations_before: tuple[np.ndarray, np.ndarray] = (
|
|
432
421
|
single_qubit_operations_before
|
|
433
422
|
or (np.eye(2, dtype=np.complex64), np.eye(2, dtype=np.complex64))
|
|
434
423
|
)
|
|
435
424
|
self.interaction_coefficients = interaction_coefficients
|
|
436
|
-
self.single_qubit_operations_after:
|
|
425
|
+
self.single_qubit_operations_after: tuple[np.ndarray, np.ndarray] = (
|
|
437
426
|
single_qubit_operations_after
|
|
438
427
|
or (np.eye(2, dtype=np.complex64), np.eye(2, dtype=np.complex64))
|
|
439
428
|
)
|
|
@@ -525,10 +514,10 @@ class KakDecomposition:
|
|
|
525
514
|
|
|
526
515
|
|
|
527
516
|
def scatter_plot_normalized_kak_interaction_coefficients(
|
|
528
|
-
interactions: Iterable[
|
|
517
|
+
interactions: Iterable[np.ndarray | cirq.SupportsUnitary | KakDecomposition],
|
|
529
518
|
*,
|
|
530
519
|
include_frame: bool = True,
|
|
531
|
-
ax:
|
|
520
|
+
ax: mplot3d.axes3d.Axes3D | None = None,
|
|
532
521
|
**kwargs,
|
|
533
522
|
):
|
|
534
523
|
r"""Plots the interaction coefficients of many two-qubit operations.
|
|
@@ -610,8 +599,8 @@ def scatter_plot_normalized_kak_interaction_coefficients(
|
|
|
610
599
|
ax = cast(mplot3d.axes3d.Axes3D, fig.add_subplot(1, 1, 1, projection='3d'))
|
|
611
600
|
|
|
612
601
|
def coord_transform(
|
|
613
|
-
pts:
|
|
614
|
-
) ->
|
|
602
|
+
pts: list[tuple[int, int, int]] | np.ndarray,
|
|
603
|
+
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
615
604
|
if len(pts) == 0:
|
|
616
605
|
return np.array([]), np.array([]), np.array([])
|
|
617
606
|
xs, ys, zs = np.transpose(pts)
|
|
@@ -637,7 +626,7 @@ def scatter_plot_normalized_kak_interaction_coefficients(
|
|
|
637
626
|
|
|
638
627
|
# parse input and extract KAK vector
|
|
639
628
|
if not isinstance(interactions, np.ndarray):
|
|
640
|
-
interactions_extracted:
|
|
629
|
+
interactions_extracted: list[np.ndarray] = [
|
|
641
630
|
a if isinstance(a, np.ndarray) else protocols.unitary(a) for a in interactions
|
|
642
631
|
]
|
|
643
632
|
else:
|
|
@@ -786,9 +775,9 @@ KAK_GAMMA = np.array([[1, 1, 1, 1],
|
|
|
786
775
|
|
|
787
776
|
|
|
788
777
|
def kak_decomposition(
|
|
789
|
-
unitary_object:
|
|
790
|
-
np.ndarray
|
|
791
|
-
|
|
778
|
+
unitary_object: (
|
|
779
|
+
np.ndarray | cirq.SupportsUnitary | cirq.Gate | cirq.Operation | KakDecomposition
|
|
780
|
+
),
|
|
792
781
|
*,
|
|
793
782
|
rtol: float = 1e-5,
|
|
794
783
|
atol: float = 1e-8,
|
|
@@ -858,7 +847,7 @@ def kak_decomposition(
|
|
|
858
847
|
|
|
859
848
|
|
|
860
849
|
def kak_vector(
|
|
861
|
-
unitary:
|
|
850
|
+
unitary: Iterable[np.ndarray] | np.ndarray,
|
|
862
851
|
*,
|
|
863
852
|
rtol: float = 1e-5,
|
|
864
853
|
atol: float = 1e-8,
|
cirq/linalg/diagonalize.py
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
|
-
from typing import Callable
|
|
19
|
+
from typing import Callable
|
|
20
20
|
|
|
21
21
|
import numpy as np
|
|
22
22
|
|
|
@@ -54,7 +54,7 @@ def diagonalize_real_symmetric_matrix(
|
|
|
54
54
|
|
|
55
55
|
def _contiguous_groups(
|
|
56
56
|
length: int, comparator: Callable[[int, int], bool]
|
|
57
|
-
) ->
|
|
57
|
+
) -> list[tuple[int, int]]:
|
|
58
58
|
"""Splits range(length) into approximate equivalence classes.
|
|
59
59
|
|
|
60
60
|
Args:
|
|
@@ -157,7 +157,7 @@ def bidiagonalize_real_matrix_pair_with_symmetric_products(
|
|
|
157
157
|
rtol: float = 1e-5,
|
|
158
158
|
atol: float = 1e-8,
|
|
159
159
|
check_preconditions: bool = True,
|
|
160
|
-
) ->
|
|
160
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
161
161
|
"""Finds orthogonal matrices that diagonalize both mat1 and mat2.
|
|
162
162
|
|
|
163
163
|
Requires mat1 and mat2 to be real.
|
|
@@ -228,7 +228,7 @@ def bidiagonalize_real_matrix_pair_with_symmetric_products(
|
|
|
228
228
|
|
|
229
229
|
def bidiagonalize_unitary_with_special_orthogonals(
|
|
230
230
|
mat: np.ndarray, *, rtol: float = 1e-5, atol: float = 1e-8, check_preconditions: bool = True
|
|
231
|
-
) ->
|
|
231
|
+
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
232
232
|
"""Finds orthogonal matrices L, R such that L @ matrix @ R is diagonal.
|
|
233
233
|
|
|
234
234
|
Args:
|
cirq/linalg/diagonalize_test.py
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
import random
|
|
18
|
-
from typing import Optional, Tuple
|
|
19
18
|
|
|
20
19
|
import numpy as np
|
|
21
20
|
import pytest
|
|
@@ -31,7 +30,7 @@ CNOT = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]])
|
|
|
31
30
|
QFT = np.array([[1, 1, 1, 1], [1, 1j, -1, -1j], [1, -1, 1, -1], [1, -1j, -1, 1j]]) * 0.5
|
|
32
31
|
|
|
33
32
|
|
|
34
|
-
def random_real_diagonal_matrix(n: int, d:
|
|
33
|
+
def random_real_diagonal_matrix(n: int, d: int | None = None) -> np.ndarray:
|
|
35
34
|
return np.diag([random.random() if d is None or k < d else 0 for k in range(n)])
|
|
36
35
|
|
|
37
36
|
|
|
@@ -50,8 +49,8 @@ def random_block_diagonal_symmetric_matrix(*ns: int) -> np.ndarray:
|
|
|
50
49
|
|
|
51
50
|
|
|
52
51
|
def random_bi_diagonalizable_pair(
|
|
53
|
-
n: int, d1:
|
|
54
|
-
) ->
|
|
52
|
+
n: int, d1: int | None = None, d2: int | None = None
|
|
53
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
55
54
|
u = cirq.testing.random_orthogonal(n)
|
|
56
55
|
s = random_real_diagonal_matrix(n, d1)
|
|
57
56
|
z = random_real_diagonal_matrix(n, d2)
|
cirq/linalg/operator_spaces.py
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
|
-
from typing import
|
|
19
|
+
from typing import TYPE_CHECKING
|
|
20
20
|
|
|
21
21
|
import numpy as np
|
|
22
22
|
import sympy
|
|
@@ -36,7 +36,7 @@ PAULI_BASIS = {
|
|
|
36
36
|
document(PAULI_BASIS, """The four Pauli matrices (including identity) keyed by character.""")
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
def kron_bases(*bases:
|
|
39
|
+
def kron_bases(*bases: dict[str, np.ndarray], repeat: int = 1) -> dict[str, np.ndarray]:
|
|
40
40
|
"""Creates tensor product of bases."""
|
|
41
41
|
product_basis = {'': np.array([[1]])}
|
|
42
42
|
for basis in bases * repeat:
|
|
@@ -57,7 +57,7 @@ def hilbert_schmidt_inner_product(m1: np.ndarray, m2: np.ndarray) -> complex:
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
def expand_matrix_in_orthogonal_basis(
|
|
60
|
-
m: np.ndarray, basis:
|
|
60
|
+
m: np.ndarray, basis: dict[str, np.ndarray]
|
|
61
61
|
) -> value.LinearDict[str]:
|
|
62
62
|
"""Computes coefficients of expansion of m in basis.
|
|
63
63
|
|
|
@@ -74,7 +74,7 @@ def expand_matrix_in_orthogonal_basis(
|
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
def matrix_from_basis_coefficients(
|
|
77
|
-
expansion: value.LinearDict[str], basis:
|
|
77
|
+
expansion: value.LinearDict[str], basis: dict[str, np.ndarray]
|
|
78
78
|
) -> np.ndarray:
|
|
79
79
|
"""Computes linear combination of basis vectors with given coefficients."""
|
|
80
80
|
some_element = next(iter(basis.values()))
|
|
@@ -90,7 +90,7 @@ def pow_pauli_combination(
|
|
|
90
90
|
ay: cirq.TParamValComplex,
|
|
91
91
|
az: cirq.TParamValComplex,
|
|
92
92
|
exponent: int,
|
|
93
|
-
) ->
|
|
93
|
+
) -> tuple[
|
|
94
94
|
cirq.TParamValComplex, cirq.TParamValComplex, cirq.TParamValComplex, cirq.TParamValComplex
|
|
95
95
|
]:
|
|
96
96
|
"""Computes non-negative integer power of single-qubit Pauli combination.
|
cirq/linalg/predicates.py
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
19
|
from types import EllipsisType
|
|
20
|
-
from typing import cast,
|
|
20
|
+
from typing import cast, Sequence, Union
|
|
21
21
|
|
|
22
22
|
import numpy as np
|
|
23
23
|
|
|
@@ -231,9 +231,9 @@ def slice_for_qubits_equal_to(
|
|
|
231
231
|
little_endian_qureg_value: int = 0,
|
|
232
232
|
*, # Forces keyword args.
|
|
233
233
|
big_endian_qureg_value: int = 0,
|
|
234
|
-
num_qubits:
|
|
235
|
-
qid_shape:
|
|
236
|
-
) ->
|
|
234
|
+
num_qubits: int | None = None,
|
|
235
|
+
qid_shape: tuple[int, ...] | None = None,
|
|
236
|
+
) -> tuple[slice | int | EllipsisType, ...]:
|
|
237
237
|
"""Returns an index corresponding to a desired subset of an np.ndarray.
|
|
238
238
|
|
|
239
239
|
It is assumed that the np.ndarray's shape is of the form (2, 2, 2, ..., 2).
|
|
@@ -288,10 +288,10 @@ def slice_for_qubits_equal_to(
|
|
|
288
288
|
qid_shape_specified = qid_shape is not None
|
|
289
289
|
if qid_shape is not None or num_qubits is not None:
|
|
290
290
|
if num_qubits is None:
|
|
291
|
-
num_qubits = len(cast(
|
|
291
|
+
num_qubits = len(cast(tuple[int, ...], qid_shape))
|
|
292
292
|
elif qid_shape is None:
|
|
293
293
|
qid_shape = (2,) * num_qubits
|
|
294
|
-
if num_qubits != len(cast(
|
|
294
|
+
if num_qubits != len(cast(tuple[int, ...], qid_shape)):
|
|
295
295
|
raise ValueError('len(qid_shape) != num_qubits')
|
|
296
296
|
if little_endian_qureg_value and big_endian_qureg_value:
|
|
297
297
|
raise ValueError(
|
|
@@ -302,7 +302,7 @@ def slice_for_qubits_equal_to(
|
|
|
302
302
|
out_size = (
|
|
303
303
|
cast(int, num_qubits) if out_size_specified else max(target_qubit_axes, default=-1) + 1
|
|
304
304
|
)
|
|
305
|
-
result = cast(
|
|
305
|
+
result = cast(list[Union[slice, int, EllipsisType]], [slice(None)] * out_size)
|
|
306
306
|
if not out_size_specified:
|
|
307
307
|
result.append(Ellipsis)
|
|
308
308
|
if qid_shape is None:
|
cirq/linalg/transformations.py
CHANGED
|
@@ -19,7 +19,7 @@ from __future__ import annotations
|
|
|
19
19
|
import dataclasses
|
|
20
20
|
import functools
|
|
21
21
|
from types import EllipsisType
|
|
22
|
-
from typing import Any,
|
|
22
|
+
from typing import Any, Sequence
|
|
23
23
|
|
|
24
24
|
import numpy as np
|
|
25
25
|
|
|
@@ -62,7 +62,7 @@ def reflection_matrix_pow(reflection_matrix: np.ndarray, exponent: float):
|
|
|
62
62
|
return pos_part_raised + neg_part_raised
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
def match_global_phase(a: np.ndarray, b: np.ndarray) ->
|
|
65
|
+
def match_global_phase(a: np.ndarray, b: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
|
|
66
66
|
"""Phases the given matrices so that they agree on the phase of one entry.
|
|
67
67
|
|
|
68
68
|
To maximize precision, the position with the largest entry from one of the
|
|
@@ -104,7 +104,7 @@ def targeted_left_multiply(
|
|
|
104
104
|
left_matrix: np.ndarray,
|
|
105
105
|
right_target: np.ndarray,
|
|
106
106
|
target_axes: Sequence[int],
|
|
107
|
-
out:
|
|
107
|
+
out: np.ndarray | None = None,
|
|
108
108
|
) -> np.ndarray:
|
|
109
109
|
"""Left-multiplies the given axes of the target tensor by the given matrix.
|
|
110
110
|
|
|
@@ -179,7 +179,7 @@ class _SliceConfig:
|
|
|
179
179
|
|
|
180
180
|
@dataclasses.dataclass
|
|
181
181
|
class _BuildFromSlicesArgs:
|
|
182
|
-
slices:
|
|
182
|
+
slices: tuple[_SliceConfig, ...]
|
|
183
183
|
scale: complex
|
|
184
184
|
|
|
185
185
|
|
|
@@ -237,8 +237,8 @@ def _build_from_slices(
|
|
|
237
237
|
d = len(source.shape)
|
|
238
238
|
out[...] = 0
|
|
239
239
|
for arg in args:
|
|
240
|
-
source_slice:
|
|
241
|
-
target_slice:
|
|
240
|
+
source_slice: list[Any] = [slice(None)] * d
|
|
241
|
+
target_slice: list[Any] = [slice(None)] * d
|
|
242
242
|
for sleis in arg.slices:
|
|
243
243
|
source_slice[sleis.axis] = sleis.source_index
|
|
244
244
|
target_slice[sleis.axis] = sleis.target_index
|
|
@@ -250,9 +250,9 @@ def targeted_conjugate_about(
|
|
|
250
250
|
tensor: np.ndarray,
|
|
251
251
|
target: np.ndarray,
|
|
252
252
|
indices: Sequence[int],
|
|
253
|
-
conj_indices:
|
|
254
|
-
buffer:
|
|
255
|
-
out:
|
|
253
|
+
conj_indices: Sequence[int] | None = None,
|
|
254
|
+
buffer: np.ndarray | None = None,
|
|
255
|
+
out: np.ndarray | None = None,
|
|
256
256
|
) -> np.ndarray:
|
|
257
257
|
r"""Conjugates the given tensor about the target tensor.
|
|
258
258
|
|
|
@@ -301,8 +301,8 @@ def targeted_conjugate_about(
|
|
|
301
301
|
return targeted_left_multiply(np.conjugate(tensor), first_multiply, conj_indices, out=out)
|
|
302
302
|
|
|
303
303
|
|
|
304
|
-
_TSliceAtom =
|
|
305
|
-
_TSlice =
|
|
304
|
+
_TSliceAtom = int | slice | EllipsisType
|
|
305
|
+
_TSlice = _TSliceAtom | Sequence[_TSliceAtom]
|
|
306
306
|
|
|
307
307
|
|
|
308
308
|
def apply_matrix_to_slices(
|
|
@@ -310,7 +310,7 @@ def apply_matrix_to_slices(
|
|
|
310
310
|
matrix: np.ndarray,
|
|
311
311
|
slices: Sequence[_TSlice],
|
|
312
312
|
*,
|
|
313
|
-
out:
|
|
313
|
+
out: np.ndarray | None = None,
|
|
314
314
|
) -> np.ndarray:
|
|
315
315
|
r"""Left-multiplies an NxN matrix onto N slices of a numpy array.
|
|
316
316
|
|
|
@@ -420,8 +420,8 @@ class EntangledStateError(ValueError):
|
|
|
420
420
|
|
|
421
421
|
|
|
422
422
|
def partial_trace_of_state_vector_as_mixture(
|
|
423
|
-
state_vector: np.ndarray, keep_indices:
|
|
424
|
-
) ->
|
|
423
|
+
state_vector: np.ndarray, keep_indices: list[int], *, atol: float = 1e-8
|
|
424
|
+
) -> tuple[tuple[float, np.ndarray], ...]:
|
|
425
425
|
"""Returns a mixture representing a state vector with only some qubits kept.
|
|
426
426
|
|
|
427
427
|
The input state vector can have any shape, but if it is one-dimensional it
|
|
@@ -455,7 +455,7 @@ def partial_trace_of_state_vector_as_mixture(
|
|
|
455
455
|
if 2**dims != state_vector.size:
|
|
456
456
|
raise ValueError(f'Cannot infer underlying shape of {state_vector.shape}.')
|
|
457
457
|
state_vector = state_vector.reshape((2,) * dims)
|
|
458
|
-
ret_shape:
|
|
458
|
+
ret_shape: tuple[int, ...] = (2 ** len(keep_indices),)
|
|
459
459
|
else:
|
|
460
460
|
ret_shape = tuple(state_vector.shape[i] for i in keep_indices)
|
|
461
461
|
|
|
@@ -476,7 +476,7 @@ def partial_trace_of_state_vector_as_mixture(
|
|
|
476
476
|
|
|
477
477
|
def sub_state_vector(
|
|
478
478
|
state_vector: np.ndarray,
|
|
479
|
-
keep_indices:
|
|
479
|
+
keep_indices: list[int],
|
|
480
480
|
*,
|
|
481
481
|
default: np.ndarray = RaiseValueErrorIfNotProvided,
|
|
482
482
|
atol: float = 1e-6,
|
|
@@ -536,7 +536,7 @@ def sub_state_vector(
|
|
|
536
536
|
|
|
537
537
|
n_qubits = int(np.log2(state_vector.size))
|
|
538
538
|
keep_dims = 1 << len(keep_indices)
|
|
539
|
-
ret_shape:
|
|
539
|
+
ret_shape: tuple[int] | tuple[int, ...]
|
|
540
540
|
if state_vector.shape == (state_vector.size,):
|
|
541
541
|
ret_shape = (keep_dims,)
|
|
542
542
|
state_vector = state_vector.reshape((2,) * n_qubits)
|
|
@@ -634,7 +634,7 @@ def density_matrix_kronecker_product(t1: np.ndarray, t2: np.ndarray) -> np.ndarr
|
|
|
634
634
|
|
|
635
635
|
def factor_state_vector(
|
|
636
636
|
t: np.ndarray, axes: Sequence[int], *, validate=True, atol=1e-07
|
|
637
|
-
) ->
|
|
637
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
638
638
|
"""Factors a state vector into two independent state vectors.
|
|
639
639
|
|
|
640
640
|
This function should only be called on state vectors that are known to be
|
|
@@ -680,7 +680,7 @@ def factor_state_vector(
|
|
|
680
680
|
|
|
681
681
|
def factor_density_matrix(
|
|
682
682
|
t: np.ndarray, axes: Sequence[int], *, validate=True, atol=1e-07
|
|
683
|
-
) ->
|
|
683
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
684
684
|
"""Factors a density matrix into two independent density matrices.
|
|
685
685
|
|
|
686
686
|
This function should only be called on density matrices that are known to
|
|
@@ -748,7 +748,7 @@ def transpose_density_matrix_to_axis_order(t: np.ndarray, axes: Sequence[int]):
|
|
|
748
748
|
return transpose_state_vector_to_axis_order(t, axes)
|
|
749
749
|
|
|
750
750
|
|
|
751
|
-
def _volumes(shape: Sequence[int]) ->
|
|
751
|
+
def _volumes(shape: Sequence[int]) -> list[int]:
|
|
752
752
|
r"""Returns a list of the volume spanned by each dimension.
|
|
753
753
|
|
|
754
754
|
Given a shape=[d_0, d_1, .., d_n] the volume spanned by each dimension is
|
cirq/ops/arithmetic_operation.py
CHANGED
|
@@ -17,7 +17,7 @@ from __future__ import annotations
|
|
|
17
17
|
|
|
18
18
|
import abc
|
|
19
19
|
import itertools
|
|
20
|
-
from typing import cast, Iterable,
|
|
20
|
+
from typing import cast, Iterable, Sequence, TYPE_CHECKING
|
|
21
21
|
|
|
22
22
|
import numpy as np
|
|
23
23
|
from typing_extensions import Self
|
|
@@ -88,7 +88,7 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
|
|
|
88
88
|
"""
|
|
89
89
|
|
|
90
90
|
@abc.abstractmethod
|
|
91
|
-
def registers(self) -> Sequence[
|
|
91
|
+
def registers(self) -> Sequence[int | Sequence[int]]:
|
|
92
92
|
"""The data acted upon by the arithmetic gate.
|
|
93
93
|
|
|
94
94
|
Each register in the list can either be a classical constant (an `int`),
|
|
@@ -105,7 +105,7 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
|
|
|
105
105
|
raise NotImplementedError()
|
|
106
106
|
|
|
107
107
|
@abc.abstractmethod
|
|
108
|
-
def with_registers(self, *new_registers:
|
|
108
|
+
def with_registers(self, *new_registers: int | Sequence[int]) -> Self:
|
|
109
109
|
"""Returns the same fate targeting different registers.
|
|
110
110
|
|
|
111
111
|
Args:
|
|
@@ -119,7 +119,7 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
|
|
|
119
119
|
raise NotImplementedError()
|
|
120
120
|
|
|
121
121
|
@abc.abstractmethod
|
|
122
|
-
def apply(self, *register_values: int) ->
|
|
122
|
+
def apply(self, *register_values: int) -> int | Iterable[int]:
|
|
123
123
|
"""Returns the result of the gate operating on classical values.
|
|
124
124
|
|
|
125
125
|
For example, an addition takes two values (the target and the source),
|
|
@@ -164,7 +164,7 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
|
|
|
164
164
|
"""
|
|
165
165
|
raise NotImplementedError()
|
|
166
166
|
|
|
167
|
-
def _qid_shape_(self) ->
|
|
167
|
+
def _qid_shape_(self) -> tuple[int, ...]:
|
|
168
168
|
shape = []
|
|
169
169
|
for r in self.registers():
|
|
170
170
|
if isinstance(r, Sequence):
|
|
@@ -174,9 +174,9 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
|
|
|
174
174
|
|
|
175
175
|
def _apply_unitary_(self, args: cirq.ApplyUnitaryArgs):
|
|
176
176
|
registers = self.registers()
|
|
177
|
-
input_ranges:
|
|
178
|
-
shape:
|
|
179
|
-
overflow_sizes:
|
|
177
|
+
input_ranges: list[Sequence[int]] = []
|
|
178
|
+
shape: list[int] = []
|
|
179
|
+
overflow_sizes: list[int] = []
|
|
180
180
|
for register in registers:
|
|
181
181
|
if isinstance(register, int):
|
|
182
182
|
input_ranges.append([register])
|
|
@@ -198,8 +198,8 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
|
|
|
198
198
|
output = self.apply(*input_seq)
|
|
199
199
|
|
|
200
200
|
# Wrap into list.
|
|
201
|
-
inputs:
|
|
202
|
-
outputs:
|
|
201
|
+
inputs: list[int] = list(input_seq)
|
|
202
|
+
outputs: list[int] = [output] if isinstance(output, int) else list(output)
|
|
203
203
|
|
|
204
204
|
# Omitted tail values default to the corresponding input value.
|
|
205
205
|
if len(outputs) < len(inputs):
|
|
@@ -221,8 +221,8 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
|
|
|
221
221
|
outputs[i] %= overflow_sizes[i]
|
|
222
222
|
|
|
223
223
|
# Copy amplitude to new location.
|
|
224
|
-
cast(
|
|
225
|
-
cast(
|
|
224
|
+
cast(list[int | slice], outputs).append(slice(None))
|
|
225
|
+
cast(list[int | slice], inputs).append(slice(None))
|
|
226
226
|
dst[tuple(outputs)] = src[tuple(inputs)]
|
|
227
227
|
|
|
228
228
|
# In case the reshaped arrays were copies instead of views.
|
|
@@ -233,9 +233,7 @@ class ArithmeticGate(Gate, metaclass=abc.ABCMeta):
|
|
|
233
233
|
|
|
234
234
|
|
|
235
235
|
def _describe_bad_arithmetic_changed_const(
|
|
236
|
-
registers: Sequence[
|
|
237
|
-
inputs: List[int],
|
|
238
|
-
outputs: List[int],
|
|
236
|
+
registers: Sequence[int | Sequence[cirq.Qid | int]], inputs: list[int], outputs: list[int]
|
|
239
237
|
) -> str:
|
|
240
238
|
from cirq.circuits import TextDiagramDrawer
|
|
241
239
|
|
cirq/ops/boolean_hamiltonian.py
CHANGED
|
@@ -27,7 +27,7 @@ from __future__ import annotations
|
|
|
27
27
|
|
|
28
28
|
import functools
|
|
29
29
|
import itertools
|
|
30
|
-
from typing import Any,
|
|
30
|
+
from typing import Any, Generator, Sequence
|
|
31
31
|
|
|
32
32
|
import sympy.parsing.sympy_parser as sympy_parser
|
|
33
33
|
|
|
@@ -80,13 +80,13 @@ class BooleanHamiltonianGate(raw_types.Gate):
|
|
|
80
80
|
self._boolean_strs: Sequence[str] = boolean_strs
|
|
81
81
|
self._theta: float = theta
|
|
82
82
|
|
|
83
|
-
def _qid_shape_(self) ->
|
|
83
|
+
def _qid_shape_(self) -> tuple[int, ...]:
|
|
84
84
|
return (2,) * len(self._parameter_names)
|
|
85
85
|
|
|
86
86
|
def _value_equality_values_(self) -> Any:
|
|
87
87
|
return tuple(self._parameter_names), tuple(self._boolean_strs), self._theta
|
|
88
88
|
|
|
89
|
-
def _json_dict_(self) ->
|
|
89
|
+
def _json_dict_(self) -> dict[str, Any]:
|
|
90
90
|
return {
|
|
91
91
|
'parameter_names': self._parameter_names,
|
|
92
92
|
'boolean_strs': self._boolean_strs,
|
|
@@ -121,7 +121,7 @@ class BooleanHamiltonianGate(raw_types.Gate):
|
|
|
121
121
|
)
|
|
122
122
|
|
|
123
123
|
|
|
124
|
-
def _gray_code_comparator(k1:
|
|
124
|
+
def _gray_code_comparator(k1: tuple[int, ...], k2: tuple[int, ...], flip: bool = False) -> int:
|
|
125
125
|
"""Compares two Gray-encoded binary numbers.
|
|
126
126
|
|
|
127
127
|
Args:
|
|
@@ -144,8 +144,8 @@ def _gray_code_comparator(k1: Tuple[int, ...], k2: Tuple[int, ...], flip: bool =
|
|
|
144
144
|
|
|
145
145
|
|
|
146
146
|
def _simplify_commuting_cnots(
|
|
147
|
-
cnots:
|
|
148
|
-
) ->
|
|
147
|
+
cnots: list[tuple[int, int]], flip_control_and_target: bool
|
|
148
|
+
) -> tuple[bool, list[tuple[int, int]]]:
|
|
149
149
|
"""Attempts to commute CNOTs and remove cancelling pairs.
|
|
150
150
|
|
|
151
151
|
Commutation relations are based on 9 (flip_control_and_target=False) or 10
|
|
@@ -184,7 +184,7 @@ def _simplify_commuting_cnots(
|
|
|
184
184
|
target, control = (0, 1) if flip_control_and_target else (1, 0)
|
|
185
185
|
|
|
186
186
|
to_remove = set()
|
|
187
|
-
qubit_to_index:
|
|
187
|
+
qubit_to_index: list[tuple[int, dict[int, int]]] = []
|
|
188
188
|
for j in range(len(cnots)):
|
|
189
189
|
if not qubit_to_index or cnots[j][target] != qubit_to_index[-1][0]:
|
|
190
190
|
# The targets (resp. control) don't match, so we create a new dict.
|
|
@@ -205,8 +205,8 @@ def _simplify_commuting_cnots(
|
|
|
205
205
|
|
|
206
206
|
|
|
207
207
|
def _simplify_cnots_triplets(
|
|
208
|
-
cnots:
|
|
209
|
-
) ->
|
|
208
|
+
cnots: list[tuple[int, int]], flip_control_and_target: bool
|
|
209
|
+
) -> tuple[bool, list[tuple[int, int]]]:
|
|
210
210
|
"""Simplifies CNOT pairs according to equation 11 of [4].
|
|
211
211
|
|
|
212
212
|
CNOT(i, j) @ CNOT(j, k) == CNOT(j, k) @ CNOT(i, k) @ CNOT(i, j)
|
|
@@ -231,7 +231,7 @@ def _simplify_cnots_triplets(
|
|
|
231
231
|
# First, we look back for as long as the controls (resp. targets) are the same.
|
|
232
232
|
# They all commute, so all are potential candidates for being simplified.
|
|
233
233
|
# prev_match_index is qubit to index in `cnots` array.
|
|
234
|
-
prev_match_index:
|
|
234
|
+
prev_match_index: dict[int, int] = {}
|
|
235
235
|
for i in range(j - 1, -1, -1):
|
|
236
236
|
# These CNOTs have the same target (resp. control) and though they are not candidates
|
|
237
237
|
# for simplification, since they commute, we can keep looking for candidates.
|
|
@@ -245,7 +245,7 @@ def _simplify_cnots_triplets(
|
|
|
245
245
|
# Next, we look forward for as long as the targets (resp. controls) are the
|
|
246
246
|
# same. They all commute, so all are potential candidates for being simplified.
|
|
247
247
|
# post_match_index is qubit to index in `cnots` array.
|
|
248
|
-
post_match_index:
|
|
248
|
+
post_match_index: dict[int, int] = {}
|
|
249
249
|
for k in range(j + 1, len(cnots)):
|
|
250
250
|
# These CNOTs have the same control (resp. target) and though they are not candidates
|
|
251
251
|
# for simplification, since they commute, we can keep looking for candidates.
|
|
@@ -260,7 +260,7 @@ def _simplify_cnots_triplets(
|
|
|
260
260
|
keys = prev_match_index.keys() & post_match_index.keys()
|
|
261
261
|
for key in keys:
|
|
262
262
|
# We perform the swap which removes the pivot.
|
|
263
|
-
new_idx:
|
|
263
|
+
new_idx: list[int] = (
|
|
264
264
|
# Anything strictly before the pivot that is not the CNOT to swap.
|
|
265
265
|
[idx for idx in range(j) if idx != prev_match_index[key]]
|
|
266
266
|
# The two swapped CNOTs.
|
|
@@ -275,7 +275,7 @@ def _simplify_cnots_triplets(
|
|
|
275
275
|
return False, cnots
|
|
276
276
|
|
|
277
277
|
|
|
278
|
-
def _simplify_cnots(cnots:
|
|
278
|
+
def _simplify_cnots(cnots: list[tuple[int, int]]) -> list[tuple[int, int]]:
|
|
279
279
|
"""Takes a series of CNOTs and tries to applies rule to cancel out gates.
|
|
280
280
|
|
|
281
281
|
Algorithm based on "Efficient quantum circuits for diagonal unitaries without ancillas" by
|
|
@@ -302,7 +302,7 @@ def _simplify_cnots(cnots: List[Tuple[int, int]]) -> List[Tuple[int, int]]:
|
|
|
302
302
|
|
|
303
303
|
|
|
304
304
|
def _get_gates_from_hamiltonians(
|
|
305
|
-
hamiltonian_polynomial_list:
|
|
305
|
+
hamiltonian_polynomial_list: list[cirq.PauliSum], qubit_map: dict[str, cirq.Qid], theta: float
|
|
306
306
|
) -> Generator[cirq.Operation, None, None]:
|
|
307
307
|
"""Builds a circuit according to [1].
|
|
308
308
|
|
|
@@ -326,8 +326,8 @@ def _get_gates_from_hamiltonians(
|
|
|
326
326
|
qubit_idx = tuple(sorted(qubit_indices[qubit] for qubit in pauli_string.qubits))
|
|
327
327
|
hamiltonians[qubit_idx] = w
|
|
328
328
|
|
|
329
|
-
def _apply_cnots(prevh:
|
|
330
|
-
cnots:
|
|
329
|
+
def _apply_cnots(prevh: tuple[int, ...], currh: tuple[int, ...]):
|
|
330
|
+
cnots: list[tuple[int, int]] = []
|
|
331
331
|
|
|
332
332
|
cnots.extend((prevh[i], prevh[-1]) for i in range(len(prevh) - 1))
|
|
333
333
|
cnots.extend((currh[i], currh[-1]) for i in range(len(currh) - 1))
|
|
@@ -341,7 +341,7 @@ def _get_gates_from_hamiltonians(
|
|
|
341
341
|
hamiltonians.keys(), key=functools.cmp_to_key(_gray_code_comparator)
|
|
342
342
|
)
|
|
343
343
|
|
|
344
|
-
previous_h:
|
|
344
|
+
previous_h: tuple[int, ...] = ()
|
|
345
345
|
for h in sorted_hamiltonian_keys:
|
|
346
346
|
w = hamiltonians[h]
|
|
347
347
|
yield _apply_cnots(previous_h, h)
|