cirq-core 1.5.0.dev20250409222543__py3-none-any.whl → 1.6.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.
Potentially problematic release.
This version of cirq-core might be problematic. Click here for more details.
- cirq/__init__.py +16 -17
- cirq/_compat.py +21 -20
- cirq/_compat_test.py +14 -34
- cirq/_doc.py +4 -2
- cirq/_import.py +8 -6
- cirq/_import_test.py +4 -2
- cirq/_version.py +6 -6
- cirq/_version_test.py +2 -2
- cirq/circuits/_block_diagram_drawer.py +11 -10
- cirq/circuits/_block_diagram_drawer_test.py +8 -6
- cirq/circuits/_box_drawing_character_data.py +8 -8
- cirq/circuits/_box_drawing_character_data_test.py +3 -1
- cirq/circuits/_bucket_priority_queue.py +9 -7
- cirq/circuits/_bucket_priority_queue_test.py +22 -20
- cirq/circuits/circuit.py +248 -172
- cirq/circuits/circuit_operation.py +73 -83
- cirq/circuits/circuit_operation_test.py +128 -90
- cirq/circuits/circuit_test.py +211 -151
- cirq/circuits/frozen_circuit.py +23 -60
- cirq/circuits/frozen_circuit_test.py +31 -8
- cirq/circuits/insert_strategy.py +7 -5
- cirq/circuits/insert_strategy_test.py +4 -2
- cirq/circuits/moment.py +88 -40
- cirq/circuits/moment_test.py +128 -51
- cirq/circuits/optimization_pass.py +5 -5
- cirq/circuits/optimization_pass_test.py +10 -10
- cirq/circuits/qasm_output.py +11 -11
- cirq/circuits/qasm_output_test.py +25 -22
- cirq/circuits/text_diagram_drawer.py +23 -38
- cirq/circuits/text_diagram_drawer_test.py +19 -17
- cirq/conftest.py +4 -3
- cirq/contrib/__init__.py +4 -4
- cirq/contrib/acquaintance/__init__.py +1 -1
- cirq/contrib/acquaintance/bipartite.py +5 -8
- cirq/contrib/acquaintance/bipartite_test.py +18 -13
- cirq/contrib/acquaintance/devices.py +2 -2
- cirq/contrib/acquaintance/devices_test.py +5 -3
- cirq/contrib/acquaintance/executor.py +5 -5
- cirq/contrib/acquaintance/executor_test.py +13 -9
- cirq/contrib/acquaintance/gates.py +18 -28
- cirq/contrib/acquaintance/gates_test.py +24 -20
- cirq/contrib/acquaintance/inspection_utils.py +8 -4
- cirq/contrib/acquaintance/inspection_utils_test.py +4 -2
- cirq/contrib/acquaintance/mutation_utils.py +4 -4
- cirq/contrib/acquaintance/mutation_utils_test.py +4 -2
- cirq/contrib/acquaintance/optimizers.py +4 -4
- cirq/contrib/acquaintance/optimizers_test.py +4 -1
- cirq/contrib/acquaintance/permutation.py +15 -27
- cirq/contrib/acquaintance/permutation_test.py +26 -17
- cirq/contrib/acquaintance/shift.py +4 -4
- cirq/contrib/acquaintance/shift_swap_network.py +4 -4
- cirq/contrib/acquaintance/shift_swap_network_test.py +9 -6
- cirq/contrib/acquaintance/shift_test.py +8 -6
- cirq/contrib/acquaintance/strategies/cubic.py +2 -2
- cirq/contrib/acquaintance/strategies/cubic_test.py +4 -2
- cirq/contrib/acquaintance/strategies/quartic_paired.py +6 -6
- cirq/contrib/acquaintance/strategies/quartic_paired_test.py +10 -6
- cirq/contrib/acquaintance/testing.py +2 -0
- cirq/contrib/acquaintance/topological_sort.py +2 -2
- cirq/contrib/acquaintance/topological_sort_test.py +3 -1
- cirq/contrib/bayesian_network/bayesian_network_gate.py +9 -10
- cirq/contrib/bayesian_network/bayesian_network_gate_test.py +14 -9
- cirq/contrib/circuitdag/circuit_dag.py +4 -4
- cirq/contrib/circuitdag/circuit_dag_test.py +17 -15
- cirq/contrib/custom_simulators/custom_state_simulator.py +5 -5
- cirq/contrib/custom_simulators/custom_state_simulator_test.py +22 -17
- cirq/contrib/graph_device/graph_device.py +12 -11
- cirq/contrib/graph_device/graph_device_test.py +18 -14
- cirq/contrib/graph_device/hypergraph.py +16 -14
- cirq/contrib/graph_device/hypergraph_test.py +13 -11
- cirq/contrib/graph_device/uniform_graph_device.py +6 -4
- cirq/contrib/graph_device/uniform_graph_device_test.py +11 -3
- cirq/contrib/hacks/disable_validation.py +6 -1
- cirq/contrib/hacks/disable_validation_test.py +3 -1
- cirq/contrib/json.py +31 -5
- cirq/contrib/json_test.py +6 -3
- cirq/contrib/json_test_data/DampedReadoutNoiseModel.json +12 -0
- cirq/contrib/json_test_data/DampedReadoutNoiseModel.repr +4 -0
- cirq/contrib/json_test_data/DepolarizingNoiseModel.json +12 -0
- cirq/contrib/json_test_data/DepolarizingNoiseModel.repr +4 -0
- cirq/contrib/json_test_data/DepolarizingWithDampedReadoutNoiseModel.json +6 -0
- cirq/contrib/json_test_data/DepolarizingWithDampedReadoutNoiseModel.repr +1 -0
- cirq/contrib/json_test_data/DepolarizingWithReadoutNoiseModel.json +5 -0
- cirq/contrib/json_test_data/DepolarizingWithReadoutNoiseModel.repr +1 -0
- cirq/contrib/json_test_data/ReadoutNoiseModel.json +12 -0
- cirq/contrib/json_test_data/ReadoutNoiseModel.repr +4 -0
- cirq/contrib/json_test_data/__init__.py +17 -0
- cirq/contrib/json_test_data/spec.py +32 -0
- cirq/contrib/noise_models/noise_models.py +119 -5
- cirq/contrib/noise_models/noise_models_test.py +37 -9
- cirq/contrib/paulistring/clifford_optimize.py +6 -4
- cirq/contrib/paulistring/clifford_optimize_test.py +6 -5
- cirq/contrib/paulistring/clifford_target_gateset.py +10 -10
- cirq/contrib/paulistring/clifford_target_gateset_test.py +13 -11
- cirq/contrib/paulistring/optimize.py +2 -0
- cirq/contrib/paulistring/optimize_test.py +4 -3
- cirq/contrib/paulistring/pauli_string_dag.py +2 -0
- cirq/contrib/paulistring/pauli_string_dag_test.py +3 -1
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +255 -120
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +398 -19
- cirq/contrib/paulistring/pauli_string_optimize.py +7 -1
- cirq/contrib/paulistring/pauli_string_optimize_test.py +5 -3
- cirq/contrib/paulistring/recombine.py +6 -4
- cirq/contrib/paulistring/recombine_test.py +3 -1
- cirq/contrib/paulistring/separate.py +9 -6
- cirq/contrib/paulistring/separate_test.py +3 -1
- cirq/contrib/qasm_import/_lexer.py +3 -2
- cirq/contrib/qasm_import/_lexer_test.py +49 -13
- cirq/contrib/qasm_import/_parser.py +547 -83
- cirq/contrib/qasm_import/_parser_test.py +988 -97
- cirq/contrib/qasm_import/exception.py +2 -0
- cirq/contrib/qasm_import/qasm.py +8 -2
- cirq/contrib/qasm_import/qasm_test.py +7 -4
- cirq/contrib/qcircuit/qcircuit_diagram_info.py +5 -5
- cirq/contrib/qcircuit/qcircuit_diagram_info_test.py +4 -1
- cirq/contrib/qcircuit/qcircuit_pdf.py +7 -3
- cirq/contrib/qcircuit/qcircuit_pdf_test.py +3 -1
- cirq/contrib/qcircuit/qcircuit_test.py +10 -8
- cirq/contrib/quantum_volume/quantum_volume.py +31 -27
- cirq/contrib/quantum_volume/quantum_volume_test.py +19 -16
- cirq/contrib/quimb/density_matrix.py +15 -14
- cirq/contrib/quimb/density_matrix_test.py +10 -7
- cirq/contrib/quimb/grid_circuits.py +5 -2
- cirq/contrib/quimb/grid_circuits_test.py +3 -0
- cirq/contrib/quimb/mps_simulator.py +20 -20
- cirq/contrib/quimb/mps_simulator_test.py +3 -0
- cirq/contrib/quimb/state_vector.py +12 -11
- cirq/contrib/quimb/state_vector_test.py +3 -0
- cirq/contrib/quirk/export_to_quirk.py +5 -3
- cirq/contrib/quirk/export_to_quirk_test.py +18 -16
- cirq/contrib/quirk/linearize_circuit.py +2 -0
- cirq/contrib/quirk/quirk_gate.py +18 -17
- cirq/contrib/routing/device.py +5 -3
- cirq/contrib/routing/device_test.py +2 -0
- cirq/contrib/routing/greedy.py +10 -21
- cirq/contrib/routing/greedy_test.py +4 -2
- cirq/contrib/routing/initialization.py +2 -2
- cirq/contrib/routing/initialization_test.py +5 -3
- cirq/contrib/routing/router.py +9 -5
- cirq/contrib/routing/router_test.py +2 -0
- cirq/contrib/routing/swap_network.py +3 -3
- cirq/contrib/routing/swap_network_test.py +3 -1
- cirq/contrib/routing/utils.py +2 -2
- cirq/contrib/routing/utils_test.py +3 -0
- cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +15 -9
- cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking_test.py +3 -0
- cirq/contrib/svg/svg.py +3 -3
- cirq/contrib/svg/svg_test.py +8 -5
- cirq/devices/device.py +4 -4
- cirq/devices/device_test.py +7 -4
- cirq/devices/grid_device_metadata.py +10 -10
- cirq/devices/grid_device_metadata_test.py +3 -0
- cirq/devices/grid_qubit.py +29 -21
- cirq/devices/grid_qubit_test.py +3 -0
- cirq/devices/insertion_noise_model.py +7 -7
- cirq/devices/insertion_noise_model_test.py +7 -5
- cirq/devices/line_qubit.py +13 -13
- cirq/devices/line_qubit_test.py +2 -0
- cirq/devices/named_topologies.py +18 -29
- cirq/devices/named_topologies_test.py +13 -10
- cirq/devices/noise_model.py +3 -3
- cirq/devices/noise_model_test.py +19 -15
- cirq/devices/noise_properties.py +15 -6
- cirq/devices/noise_properties_test.py +34 -3
- cirq/devices/noise_utils.py +11 -9
- cirq/devices/noise_utils_test.py +2 -0
- cirq/devices/superconducting_qubits_noise_properties.py +23 -22
- cirq/devices/superconducting_qubits_noise_properties_test.py +6 -6
- cirq/devices/thermal_noise_model.py +107 -37
- cirq/devices/thermal_noise_model_test.py +21 -0
- cirq/devices/unconstrained_device.py +5 -3
- cirq/devices/unconstrained_device_test.py +2 -0
- cirq/experiments/__init__.py +4 -2
- cirq/experiments/benchmarking/__init__.py +17 -0
- cirq/experiments/benchmarking/parallel_xeb.py +677 -0
- cirq/experiments/benchmarking/parallel_xeb_test.py +447 -0
- cirq/experiments/fidelity_estimation.py +14 -8
- cirq/experiments/fidelity_estimation_test.py +3 -0
- cirq/experiments/n_qubit_tomography.py +17 -16
- cirq/experiments/n_qubit_tomography_test.py +8 -5
- cirq/experiments/purity_estimation.py +2 -0
- cirq/experiments/purity_estimation_test.py +2 -0
- cirq/experiments/qubit_characterizations.py +207 -103
- cirq/experiments/qubit_characterizations_test.py +40 -12
- cirq/experiments/random_quantum_circuit_generation.py +56 -70
- cirq/experiments/random_quantum_circuit_generation_test.py +11 -8
- cirq/experiments/readout_confusion_matrix.py +24 -22
- cirq/experiments/readout_confusion_matrix_test.py +2 -0
- cirq/experiments/single_qubit_readout_calibration.py +30 -15
- cirq/experiments/single_qubit_readout_calibration_test.py +5 -2
- cirq/experiments/t1_decay_experiment.py +9 -7
- cirq/experiments/t1_decay_experiment_test.py +13 -11
- cirq/experiments/t2_decay_experiment.py +16 -13
- cirq/experiments/t2_decay_experiment_test.py +2 -0
- cirq/experiments/two_qubit_xeb.py +64 -57
- cirq/experiments/two_qubit_xeb_test.py +10 -6
- cirq/experiments/xeb_fitting.py +39 -35
- cirq/experiments/xeb_sampling.py +37 -44
- cirq/experiments/xeb_sampling_test.py +3 -0
- cirq/experiments/xeb_simulation.py +14 -10
- cirq/experiments/xeb_simulation_test.py +5 -5
- cirq/experiments/z_phase_calibration.py +32 -29
- cirq/experiments/z_phase_calibration_test.py +3 -4
- cirq/interop/quirk/cells/__init__.py +1 -1
- cirq/interop/quirk/cells/all_cells.py +7 -2
- cirq/interop/quirk/cells/arithmetic_cells.py +29 -41
- cirq/interop/quirk/cells/arithmetic_cells_test.py +17 -14
- cirq/interop/quirk/cells/cell.py +19 -28
- cirq/interop/quirk/cells/cell_test.py +3 -0
- cirq/interop/quirk/cells/composite_cell.py +13 -28
- cirq/interop/quirk/cells/composite_cell_test.py +2 -0
- cirq/interop/quirk/cells/control_cells.py +15 -15
- cirq/interop/quirk/cells/control_cells_test.py +7 -5
- cirq/interop/quirk/cells/frequency_space_cells.py +4 -3
- cirq/interop/quirk/cells/frequency_space_cells_test.py +3 -1
- cirq/interop/quirk/cells/ignored_cells.py +3 -0
- cirq/interop/quirk/cells/ignored_cells_test.py +3 -1
- cirq/interop/quirk/cells/input_cells.py +7 -5
- cirq/interop/quirk/cells/input_cells_test.py +7 -5
- cirq/interop/quirk/cells/input_rotation_cells.py +15 -13
- cirq/interop/quirk/cells/input_rotation_cells_test.py +9 -7
- cirq/interop/quirk/cells/measurement_cells.py +5 -2
- cirq/interop/quirk/cells/measurement_cells_test.py +3 -1
- cirq/interop/quirk/cells/parse.py +22 -23
- cirq/interop/quirk/cells/parse_test.py +12 -10
- cirq/interop/quirk/cells/qubit_permutation_cells.py +5 -3
- cirq/interop/quirk/cells/qubit_permutation_cells_test.py +9 -7
- cirq/interop/quirk/cells/scalar_cells.py +4 -1
- cirq/interop/quirk/cells/scalar_cells_test.py +3 -1
- cirq/interop/quirk/cells/single_qubit_rotation_cells.py +5 -2
- cirq/interop/quirk/cells/single_qubit_rotation_cells_test.py +5 -3
- cirq/interop/quirk/cells/swap_cell.py +8 -6
- cirq/interop/quirk/cells/swap_cell_test.py +6 -4
- cirq/interop/quirk/cells/testing.py +6 -6
- cirq/interop/quirk/cells/testing_test.py +8 -6
- cirq/interop/quirk/cells/unsupported_cells.py +3 -0
- cirq/interop/quirk/cells/unsupported_cells_test.py +4 -2
- cirq/interop/quirk/url_to_circuit.py +23 -36
- cirq/interop/quirk/url_to_circuit_test.py +4 -1
- cirq/json_resolver_cache.py +14 -12
- cirq/linalg/__init__.py +4 -6
- cirq/linalg/combinators.py +7 -5
- cirq/linalg/combinators_test.py +10 -7
- cirq/linalg/decompositions.py +24 -35
- cirq/linalg/decompositions_test.py +3 -1
- cirq/linalg/diagonalize.py +6 -4
- cirq/linalg/diagonalize_test.py +15 -14
- cirq/linalg/operator_spaces.py +14 -14
- cirq/linalg/operator_spaces_test.py +13 -11
- cirq/linalg/predicates.py +18 -9
- cirq/linalg/predicates_test.py +5 -0
- cirq/linalg/tolerance.py +6 -3
- cirq/linalg/tolerance_test.py +6 -4
- cirq/linalg/transformations.py +23 -20
- cirq/linalg/transformations_test.py +73 -43
- cirq/neutral_atoms/convert_to_neutral_atom_gates.py +9 -3
- cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py +3 -1
- cirq/neutral_atoms/neutral_atom_devices.py +2 -0
- cirq/ops/__init__.py +2 -0
- cirq/ops/arithmetic_operation.py +21 -21
- cirq/ops/arithmetic_operation_test.py +7 -8
- cirq/ops/boolean_hamiltonian.py +23 -22
- cirq/ops/boolean_hamiltonian_test.py +12 -9
- cirq/ops/classically_controlled_operation.py +31 -36
- cirq/ops/classically_controlled_operation_test.py +121 -117
- cirq/ops/clifford_gate.py +98 -81
- cirq/ops/clifford_gate_test.py +72 -57
- cirq/ops/common_channels.py +44 -44
- cirq/ops/common_channels_test.py +83 -81
- cirq/ops/common_gate_families.py +9 -7
- cirq/ops/common_gate_families_test.py +11 -7
- cirq/ops/common_gates.py +164 -183
- cirq/ops/common_gates_test.py +135 -95
- cirq/ops/control_values.py +23 -26
- cirq/ops/control_values_test.py +22 -20
- cirq/ops/controlled_gate.py +64 -112
- cirq/ops/controlled_gate_test.py +130 -35
- cirq/ops/controlled_operation.py +24 -35
- cirq/ops/controlled_operation_test.py +8 -6
- cirq/ops/dense_pauli_string.py +38 -49
- cirq/ops/dense_pauli_string_test.py +4 -2
- cirq/ops/diagonal_gate.py +18 -31
- cirq/ops/diagonal_gate_test.py +13 -13
- cirq/ops/eigen_gate.py +29 -29
- cirq/ops/eigen_gate_test.py +45 -28
- cirq/ops/fourier_transform.py +14 -20
- cirq/ops/fourier_transform_test.py +15 -12
- cirq/ops/fsim_gate.py +43 -42
- cirq/ops/fsim_gate_test.py +29 -29
- cirq/ops/gate_features.py +2 -0
- cirq/ops/gate_features_test.py +5 -3
- cirq/ops/gate_operation.py +43 -65
- cirq/ops/gate_operation_test.py +46 -42
- cirq/ops/gateset.py +28 -40
- cirq/ops/gateset_test.py +4 -2
- cirq/ops/global_phase_op.py +45 -20
- cirq/ops/global_phase_op_test.py +44 -20
- cirq/ops/greedy_qubit_manager.py +10 -8
- cirq/ops/greedy_qubit_manager_test.py +5 -3
- cirq/ops/identity.py +14 -12
- cirq/ops/identity_test.py +24 -20
- cirq/ops/kraus_channel.py +11 -8
- cirq/ops/kraus_channel_test.py +14 -11
- cirq/ops/linear_combinations.py +65 -77
- cirq/ops/linear_combinations_test.py +14 -9
- cirq/ops/matrix_gates.py +21 -18
- cirq/ops/matrix_gates_test.py +16 -0
- cirq/ops/measure_util.py +15 -20
- cirq/ops/measure_util_test.py +2 -0
- cirq/ops/measurement_gate.py +26 -37
- cirq/ops/measurement_gate_test.py +2 -0
- cirq/ops/mixed_unitary_channel.py +12 -9
- cirq/ops/mixed_unitary_channel_test.py +14 -11
- cirq/ops/named_qubit.py +16 -13
- cirq/ops/named_qubit_test.py +15 -13
- cirq/ops/op_tree.py +9 -7
- cirq/ops/op_tree_test.py +22 -19
- cirq/ops/parallel_gate.py +15 -17
- cirq/ops/parallel_gate_test.py +18 -16
- cirq/ops/parity_gates.py +23 -25
- cirq/ops/parity_gates_test.py +36 -32
- cirq/ops/pauli_gates.py +22 -21
- cirq/ops/pauli_gates_test.py +29 -20
- cirq/ops/pauli_interaction_gate.py +15 -19
- cirq/ops/pauli_interaction_gate_test.py +10 -8
- cirq/ops/pauli_measurement_gate.py +23 -35
- cirq/ops/pauli_measurement_gate_test.py +2 -0
- cirq/ops/pauli_string.py +92 -120
- cirq/ops/pauli_string_phasor.py +52 -45
- cirq/ops/pauli_string_phasor_test.py +4 -5
- cirq/ops/pauli_string_raw_types.py +9 -7
- cirq/ops/pauli_string_raw_types_test.py +2 -0
- cirq/ops/pauli_string_test.py +31 -154
- cirq/ops/pauli_sum_exponential.py +12 -12
- cirq/ops/pauli_sum_exponential_test.py +12 -10
- cirq/ops/permutation_gate.py +8 -6
- cirq/ops/permutation_gate_test.py +10 -8
- cirq/ops/phased_iswap_gate.py +16 -16
- cirq/ops/phased_iswap_gate_test.py +17 -15
- cirq/ops/phased_x_gate.py +16 -17
- cirq/ops/phased_x_gate_test.py +18 -16
- cirq/ops/phased_x_z_gate.py +24 -22
- cirq/ops/phased_x_z_gate_test.py +17 -11
- cirq/ops/projector.py +16 -11
- cirq/ops/projector_test.py +19 -16
- cirq/ops/qid_util.py +7 -5
- cirq/ops/qid_util_test.py +2 -0
- cirq/ops/qubit_manager.py +11 -9
- cirq/ops/qubit_manager_test.py +6 -4
- cirq/ops/qubit_order.py +11 -14
- cirq/ops/qubit_order_or_list.py +4 -2
- cirq/ops/qubit_order_test.py +12 -10
- cirq/ops/random_gate_channel.py +12 -10
- cirq/ops/random_gate_channel_test.py +14 -11
- cirq/ops/raw_types.py +109 -129
- cirq/ops/raw_types_test.py +63 -57
- cirq/ops/state_preparation_channel.py +7 -7
- cirq/ops/state_preparation_channel_test.py +11 -9
- cirq/ops/swap_gates.py +13 -15
- cirq/ops/swap_gates_test.py +19 -17
- cirq/ops/tags.py +5 -3
- cirq/ops/tags_test.py +4 -2
- cirq/ops/three_qubit_gates.py +43 -76
- cirq/ops/three_qubit_gates_test.py +19 -17
- cirq/ops/two_qubit_diagonal_gate.py +13 -13
- cirq/ops/two_qubit_diagonal_gate_test.py +10 -8
- cirq/ops/uniform_superposition_gate.py +5 -3
- cirq/ops/uniform_superposition_gate_test.py +5 -3
- cirq/ops/wait_gate.py +17 -14
- cirq/ops/wait_gate_test.py +9 -6
- cirq/protocols/__init__.py +0 -3
- cirq/protocols/act_on_protocol.py +8 -6
- cirq/protocols/act_on_protocol_test.py +15 -12
- cirq/protocols/apply_channel_protocol.py +10 -14
- cirq/protocols/apply_channel_protocol_test.py +2 -0
- cirq/protocols/apply_mixture_protocol.py +13 -42
- cirq/protocols/apply_mixture_protocol_test.py +7 -5
- cirq/protocols/apply_unitary_protocol.py +39 -34
- cirq/protocols/apply_unitary_protocol_test.py +4 -1
- cirq/protocols/approximate_equality_protocol.py +2 -0
- cirq/protocols/approximate_equality_protocol_test.py +2 -0
- cirq/protocols/circuit_diagram_info_protocol.py +58 -42
- cirq/protocols/circuit_diagram_info_protocol_test.py +70 -12
- cirq/protocols/commutes_protocol.py +8 -7
- cirq/protocols/commutes_protocol_test.py +2 -0
- cirq/protocols/control_key_protocol.py +6 -4
- cirq/protocols/control_key_protocol_test.py +3 -1
- cirq/protocols/decompose_protocol.py +49 -48
- cirq/protocols/decompose_protocol_test.py +27 -16
- cirq/protocols/equal_up_to_global_phase_protocol.py +2 -0
- cirq/protocols/equal_up_to_global_phase_protocol_test.py +9 -6
- cirq/protocols/has_stabilizer_effect_protocol.py +7 -5
- cirq/protocols/has_stabilizer_effect_protocol_test.py +7 -5
- cirq/protocols/has_unitary_protocol.py +10 -6
- cirq/protocols/has_unitary_protocol_test.py +13 -8
- cirq/protocols/hash_from_pickle_test.py +2 -11
- cirq/protocols/inverse_protocol.py +13 -16
- cirq/protocols/inverse_protocol_test.py +5 -3
- cirq/protocols/json_serialization.py +35 -54
- cirq/protocols/json_serialization_test.py +14 -21
- cirq/protocols/json_test_data/CXSWAP.json +46 -0
- cirq/protocols/json_test_data/CXSWAP.repr +13 -0
- cirq/protocols/json_test_data/CZSWAP.json +46 -0
- cirq/protocols/json_test_data/CZSWAP.repr +13 -0
- cirq/protocols/json_test_data/CircuitOperation.json +6 -3
- cirq/protocols/json_test_data/CircuitOperation.repr_inward +4 -2
- cirq/protocols/json_test_data/Moment.json +24 -1
- cirq/protocols/json_test_data/Moment.repr +6 -1
- cirq/protocols/json_test_data/ThermalNoiseModel.json +32 -0
- cirq/protocols/json_test_data/ThermalNoiseModel.repr +1 -0
- cirq/protocols/json_test_data/spec.py +6 -2
- cirq/protocols/kraus_protocol.py +47 -7
- cirq/protocols/kraus_protocol_test.py +86 -12
- cirq/protocols/measurement_key_protocol.py +15 -16
- cirq/protocols/measurement_key_protocol_test.py +13 -11
- cirq/protocols/mixture_protocol.py +7 -5
- cirq/protocols/mixture_protocol_test.py +4 -2
- cirq/protocols/mul_protocol.py +2 -3
- cirq/protocols/mul_protocol_test.py +2 -0
- cirq/protocols/pauli_expansion_protocol.py +6 -3
- cirq/protocols/pauli_expansion_protocol_test.py +5 -3
- cirq/protocols/phase_protocol.py +2 -0
- cirq/protocols/phase_protocol_test.py +3 -1
- cirq/protocols/pow_protocol.py +11 -16
- cirq/protocols/pow_protocol_test.py +2 -0
- cirq/protocols/qasm.py +14 -20
- cirq/protocols/qasm_test.py +6 -3
- cirq/protocols/qid_shape_protocol.py +8 -8
- cirq/protocols/qid_shape_protocol_test.py +3 -1
- cirq/protocols/resolve_parameters.py +5 -3
- cirq/protocols/resolve_parameters_test.py +8 -7
- cirq/protocols/trace_distance_bound.py +6 -4
- cirq/protocols/trace_distance_bound_test.py +3 -1
- cirq/protocols/unitary_protocol.py +17 -7
- cirq/protocols/unitary_protocol_test.py +12 -2
- cirq/qis/channels.py +6 -2
- cirq/qis/channels_test.py +20 -16
- cirq/qis/clifford_tableau.py +21 -19
- cirq/qis/clifford_tableau_test.py +2 -2
- cirq/qis/entropy.py +14 -3
- cirq/qis/entropy_test.py +3 -1
- cirq/qis/measures.py +13 -13
- cirq/qis/measures_test.py +20 -14
- cirq/qis/noise_utils.py +2 -0
- cirq/qis/noise_utils_test.py +9 -7
- cirq/qis/quantum_state_representation.py +7 -8
- cirq/qis/states.py +58 -56
- cirq/qis/states_test.py +2 -0
- cirq/sim/classical_simulator.py +23 -22
- cirq/sim/classical_simulator_test.py +2 -0
- cirq/sim/clifford/clifford_simulator.py +23 -21
- cirq/sim/clifford/clifford_simulator_test.py +7 -4
- cirq/sim/clifford/clifford_tableau_simulation_state.py +10 -7
- cirq/sim/clifford/clifford_tableau_simulation_state_test.py +5 -5
- cirq/sim/clifford/stabilizer_ch_form_simulation_state.py +8 -6
- cirq/sim/clifford/stabilizer_ch_form_simulation_state_test.py +8 -6
- cirq/sim/clifford/stabilizer_sampler.py +9 -7
- cirq/sim/clifford/stabilizer_sampler_test.py +4 -2
- cirq/sim/clifford/stabilizer_simulation_state.py +14 -13
- cirq/sim/clifford/stabilizer_simulation_state_test.py +6 -4
- cirq/sim/clifford/stabilizer_state_ch_form.py +13 -11
- cirq/sim/clifford/stabilizer_state_ch_form_test.py +4 -2
- cirq/sim/density_matrix_simulation_state.py +26 -27
- cirq/sim/density_matrix_simulation_state_test.py +10 -8
- cirq/sim/density_matrix_simulator.py +30 -28
- cirq/sim/density_matrix_simulator_test.py +48 -48
- cirq/sim/density_matrix_utils.py +13 -11
- cirq/sim/density_matrix_utils_test.py +38 -36
- cirq/sim/mux.py +33 -31
- cirq/sim/mux_test.py +3 -0
- cirq/sim/simulation_product_state.py +15 -15
- cirq/sim/simulation_product_state_test.py +29 -26
- cirq/sim/simulation_state.py +29 -38
- cirq/sim/simulation_state_base.py +21 -32
- cirq/sim/simulation_state_test.py +15 -13
- cirq/sim/simulation_utils.py +5 -2
- cirq/sim/simulation_utils_test.py +5 -2
- cirq/sim/simulator.py +90 -106
- cirq/sim/simulator_base.py +33 -45
- cirq/sim/simulator_base_test.py +20 -15
- cirq/sim/simulator_test.py +23 -14
- cirq/sim/sparse_simulator.py +19 -17
- cirq/sim/sparse_simulator_test.py +41 -40
- cirq/sim/state_vector.py +15 -12
- cirq/sim/state_vector_simulation_state.py +31 -31
- cirq/sim/state_vector_simulation_state_test.py +16 -14
- cirq/sim/state_vector_simulator.py +17 -14
- cirq/sim/state_vector_simulator_test.py +2 -0
- cirq/sim/state_vector_test.py +6 -3
- cirq/study/flatten_expressions.py +16 -15
- cirq/study/flatten_expressions_test.py +13 -11
- cirq/study/resolver.py +18 -17
- cirq/study/resolver_test.py +22 -20
- cirq/study/result.py +17 -27
- cirq/study/result_test.py +2 -0
- cirq/study/sweepable.py +12 -10
- cirq/study/sweepable_test.py +3 -0
- cirq/study/sweeps.py +42 -61
- cirq/study/sweeps_test.py +33 -0
- cirq/testing/__init__.py +7 -11
- cirq/testing/_compat_test_data/module_a/__init__.py +1 -0
- cirq/testing/_compat_test_data/module_a/module_b/__init__.py +1 -0
- cirq/testing/_compat_test_data/module_a/sub/__init__.py +1 -0
- cirq/testing/circuit_compare.py +8 -17
- cirq/testing/circuit_compare_test.py +2 -0
- cirq/testing/consistent_act_on.py +13 -11
- cirq/testing/consistent_act_on_test.py +5 -3
- cirq/testing/consistent_channels.py +2 -0
- cirq/testing/consistent_channels_test.py +10 -8
- cirq/testing/consistent_controlled_gate_op.py +5 -5
- cirq/testing/consistent_controlled_gate_op_test.py +18 -18
- cirq/testing/consistent_decomposition.py +2 -2
- cirq/testing/consistent_decomposition_test.py +4 -2
- cirq/testing/consistent_pauli_expansion.py +2 -0
- cirq/testing/consistent_pauli_expansion_test.py +3 -1
- cirq/testing/consistent_phase_by.py +2 -0
- cirq/testing/consistent_phase_by_test.py +3 -1
- cirq/testing/consistent_protocols.py +14 -20
- cirq/testing/consistent_protocols_test.py +13 -11
- cirq/testing/consistent_qasm.py +6 -4
- cirq/testing/consistent_qasm_test.py +7 -7
- cirq/testing/consistent_resolve_parameters.py +2 -0
- cirq/testing/consistent_specified_has_unitary.py +2 -2
- cirq/testing/consistent_specified_has_unitary_test.py +6 -4
- cirq/testing/consistent_unitary.py +1 -0
- cirq/testing/consistent_unitary_test.py +4 -2
- cirq/testing/deprecation.py +5 -2
- cirq/testing/deprecation_test.py +5 -2
- cirq/testing/devices.py +7 -4
- cirq/testing/devices_test.py +7 -4
- cirq/testing/equals_tester.py +4 -2
- cirq/testing/equals_tester_test.py +21 -17
- cirq/testing/equivalent_basis_map.py +6 -4
- cirq/testing/equivalent_basis_map_test.py +6 -4
- cirq/testing/equivalent_repr_eval.py +6 -4
- cirq/testing/equivalent_repr_eval_test.py +5 -3
- cirq/testing/gate_features.py +2 -0
- cirq/testing/gate_features_test.py +7 -5
- cirq/testing/json.py +19 -15
- cirq/testing/json_test.py +5 -3
- cirq/testing/lin_alg_utils.py +10 -11
- cirq/testing/lin_alg_utils_test.py +14 -12
- cirq/testing/logs.py +7 -6
- cirq/testing/logs_test.py +9 -7
- cirq/testing/no_identifier_qubit.py +4 -2
- cirq/testing/no_identifier_qubit_test.py +5 -3
- cirq/testing/op_tree.py +2 -0
- cirq/testing/op_tree_test.py +4 -1
- cirq/testing/order_tester.py +2 -0
- cirq/testing/order_tester_test.py +8 -6
- cirq/testing/pytest_utils.py +2 -0
- cirq/testing/pytest_utils_test.py +4 -2
- cirq/testing/random_circuit.py +21 -20
- cirq/testing/random_circuit_test.py +12 -9
- cirq/testing/repr_pretty_tester.py +1 -0
- cirq/testing/repr_pretty_tester_test.py +5 -3
- cirq/testing/routing_devices.py +4 -1
- cirq/testing/routing_devices_test.py +9 -6
- cirq/testing/sample_circuits.py +4 -1
- cirq/testing/sample_circuits_test.py +3 -1
- cirq/testing/sample_gates.py +3 -0
- cirq/testing/sample_gates_test.py +5 -2
- cirq/transformers/__init__.py +11 -4
- cirq/transformers/align.py +9 -7
- cirq/transformers/align_test.py +2 -0
- cirq/transformers/analytical_decompositions/__init__.py +3 -6
- cirq/transformers/analytical_decompositions/clifford_decomposition.py +18 -16
- cirq/transformers/analytical_decompositions/clifford_decomposition_test.py +2 -0
- cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +19 -16
- cirq/transformers/analytical_decompositions/controlled_gate_decomposition_test.py +2 -0
- cirq/transformers/analytical_decompositions/cphase_to_fsim.py +11 -9
- cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py +5 -3
- cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +5 -3
- cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +5 -3
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +141 -44
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +35 -1
- cirq/transformers/analytical_decompositions/single_qubit_decompositions.py +8 -7
- cirq/transformers/analytical_decompositions/single_qubit_decompositions_test.py +2 -0
- cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry.py +7 -4
- cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry_test.py +3 -0
- cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +11 -19
- cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +8 -33
- cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py +9 -11
- cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py +2 -0
- cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +91 -27
- cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +36 -7
- cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +20 -21
- cirq/transformers/analytical_decompositions/two_qubit_to_fsim_test.py +8 -6
- cirq/transformers/analytical_decompositions/two_qubit_to_ms.py +13 -15
- cirq/transformers/analytical_decompositions/two_qubit_to_ms_test.py +3 -1
- cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py +39 -41
- cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap_test.py +2 -0
- cirq/transformers/drop_empty_moments.py +5 -3
- cirq/transformers/drop_empty_moments_test.py +4 -2
- cirq/transformers/drop_negligible_operations.py +7 -5
- cirq/transformers/drop_negligible_operations_test.py +2 -0
- cirq/transformers/dynamical_decoupling.py +49 -42
- cirq/transformers/dynamical_decoupling_test.py +223 -205
- cirq/transformers/eject_phased_paulis.py +28 -26
- cirq/transformers/eject_phased_paulis_test.py +12 -9
- cirq/transformers/eject_z.py +12 -12
- cirq/transformers/eject_z_test.py +2 -2
- cirq/transformers/expand_composite.py +6 -4
- cirq/transformers/expand_composite_test.py +3 -1
- cirq/transformers/gauge_compiling/__init__.py +3 -1
- cirq/transformers/gauge_compiling/cphase_gauge.py +2 -0
- cirq/transformers/gauge_compiling/cphase_gauge_test.py +2 -0
- cirq/transformers/gauge_compiling/cz_gauge.py +2 -0
- cirq/transformers/gauge_compiling/cz_gauge_test.py +1 -0
- cirq/transformers/gauge_compiling/gauge_compiling.py +45 -41
- cirq/transformers/gauge_compiling/gauge_compiling_test.py +2 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +1 -0
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +5 -1
- cirq/transformers/gauge_compiling/iswap_gauge.py +2 -0
- cirq/transformers/gauge_compiling/iswap_gauge_test.py +1 -0
- cirq/transformers/gauge_compiling/spin_inversion_gauge.py +2 -0
- cirq/transformers/gauge_compiling/spin_inversion_gauge_test.py +2 -0
- cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +7 -6
- cirq/transformers/gauge_compiling/sqrt_cz_gauge_test.py +2 -0
- cirq/transformers/gauge_compiling/sqrt_iswap_gauge.py +2 -0
- cirq/transformers/gauge_compiling/sqrt_iswap_gauge_test.py +2 -0
- cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +6 -3
- cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils_test.py +3 -0
- cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +12 -9
- cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation_test.py +9 -7
- cirq/transformers/insertion_sort.py +8 -6
- cirq/transformers/insertion_sort_test.py +3 -1
- cirq/transformers/measurement_transformers.py +29 -29
- cirq/transformers/measurement_transformers_test.py +2 -0
- cirq/transformers/merge_k_qubit_gates.py +12 -10
- cirq/transformers/merge_k_qubit_gates_test.py +18 -18
- cirq/transformers/merge_single_qubit_gates.py +197 -20
- cirq/transformers/merge_single_qubit_gates_test.py +177 -5
- cirq/transformers/noise_adding.py +5 -3
- cirq/transformers/noise_adding_test.py +2 -0
- cirq/transformers/optimize_for_target_gateset.py +19 -17
- cirq/transformers/optimize_for_target_gateset_test.py +11 -8
- cirq/transformers/qubit_management_transformers.py +13 -11
- cirq/transformers/qubit_management_transformers_test.py +5 -3
- cirq/transformers/randomized_measurements.py +16 -14
- cirq/transformers/randomized_measurements_test.py +10 -4
- cirq/transformers/routing/initial_mapper.py +6 -4
- cirq/transformers/routing/initial_mapper_test.py +2 -0
- cirq/transformers/routing/line_initial_mapper.py +16 -14
- cirq/transformers/routing/line_initial_mapper_test.py +9 -7
- cirq/transformers/routing/mapping_manager.py +10 -10
- cirq/transformers/routing/mapping_manager_test.py +2 -0
- cirq/transformers/routing/route_circuit_cqc.py +33 -31
- cirq/transformers/routing/route_circuit_cqc_test.py +15 -13
- cirq/transformers/routing/visualize_routed_circuit.py +8 -7
- cirq/transformers/routing/visualize_routed_circuit_test.py +4 -2
- cirq/transformers/stratify.py +17 -15
- cirq/transformers/stratify_test.py +3 -0
- cirq/transformers/symbolize.py +103 -0
- cirq/transformers/symbolize_test.py +62 -0
- cirq/transformers/synchronize_terminal_measurements.py +10 -10
- cirq/transformers/synchronize_terminal_measurements_test.py +12 -10
- cirq/transformers/tag_transformers.py +97 -0
- cirq/transformers/tag_transformers_test.py +103 -0
- cirq/transformers/target_gatesets/compilation_target_gateset.py +21 -19
- cirq/transformers/target_gatesets/compilation_target_gateset_test.py +20 -16
- cirq/transformers/target_gatesets/cz_gateset.py +7 -5
- cirq/transformers/target_gatesets/cz_gateset_test.py +21 -19
- cirq/transformers/target_gatesets/sqrt_iswap_gateset.py +9 -7
- cirq/transformers/target_gatesets/sqrt_iswap_gateset_test.py +25 -25
- cirq/transformers/transformer_api.py +34 -47
- cirq/transformers/transformer_api_test.py +9 -8
- cirq/transformers/transformer_primitives.py +39 -49
- cirq/transformers/transformer_primitives_test.py +10 -17
- cirq/value/abc_alt.py +6 -4
- cirq/value/abc_alt_test.py +5 -3
- cirq/value/angle.py +11 -12
- cirq/value/angle_test.py +5 -3
- cirq/value/classical_data.py +27 -27
- cirq/value/classical_data_test.py +11 -8
- cirq/value/condition.py +26 -24
- cirq/value/condition_test.py +2 -0
- cirq/value/digits.py +14 -11
- cirq/value/digits_test.py +2 -0
- cirq/value/duration.py +23 -20
- cirq/value/duration_test.py +2 -0
- cirq/value/linear_dict.py +25 -30
- cirq/value/linear_dict_test.py +10 -8
- cirq/value/measurement_key.py +12 -12
- cirq/value/measurement_key_test.py +2 -0
- cirq/value/periodic_value.py +4 -4
- cirq/value/periodic_value_test.py +11 -7
- cirq/value/probability.py +3 -1
- cirq/value/probability_test.py +4 -2
- cirq/value/product_state.py +15 -13
- cirq/value/product_state_test.py +4 -1
- cirq/value/random_state.py +2 -0
- cirq/value/random_state_test.py +5 -3
- cirq/value/timestamp.py +11 -7
- cirq/value/timestamp_test.py +14 -12
- cirq/value/type_alias.py +4 -4
- cirq/value/value_equality_attr.py +8 -9
- cirq/value/value_equality_attr_test.py +14 -11
- cirq/vis/density_matrix.py +3 -3
- cirq/vis/density_matrix_test.py +20 -17
- cirq/vis/heatmap.py +24 -37
- cirq/vis/heatmap_test.py +3 -0
- cirq/vis/histogram.py +9 -6
- cirq/vis/histogram_test.py +5 -2
- cirq/vis/state_histogram.py +10 -8
- cirq/vis/state_histogram_test.py +7 -5
- cirq/vis/vis_utils.py +4 -1
- cirq/vis/vis_utils_test.py +4 -1
- cirq/work/collector.py +12 -18
- cirq/work/collector_test.py +15 -10
- cirq/work/observable_grouping.py +6 -7
- cirq/work/observable_grouping_test.py +10 -9
- cirq/work/observable_measurement.py +47 -45
- cirq/work/observable_measurement_data.py +22 -17
- cirq/work/observable_measurement_data_test.py +4 -1
- cirq/work/observable_measurement_test.py +48 -29
- cirq/work/observable_readout_calibration.py +5 -2
- cirq/work/observable_readout_calibration_test.py +5 -2
- cirq/work/observable_settings.py +13 -22
- cirq/work/observable_settings_test.py +9 -7
- cirq/work/pauli_sum_collector.py +12 -10
- cirq/work/pauli_sum_collector_test.py +9 -9
- cirq/work/sampler.py +42 -43
- cirq/work/sampler_test.py +31 -24
- cirq/work/zeros_sampler.py +6 -4
- cirq/work/zeros_sampler_test.py +7 -5
- {cirq_core-1.5.0.dev20250409222543.dist-info → cirq_core-1.6.0.dist-info}/METADATA +7 -8
- cirq_core-1.6.0.dist-info/RECORD +1241 -0
- {cirq_core-1.5.0.dev20250409222543.dist-info → cirq_core-1.6.0.dist-info}/WHEEL +1 -1
- cirq_core-1.5.0.dev20250409222543.dist-info/RECORD +0 -1216
- {cirq_core-1.5.0.dev20250409222543.dist-info → cirq_core-1.6.0.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.5.0.dev20250409222543.dist-info → cirq_core-1.6.0.dist-info}/top_level.txt +0 -0
cirq/transformers/stratify.py
CHANGED
|
@@ -14,8 +14,10 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformer pass to repack circuits avoiding simultaneous operations with different classes."""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
17
19
|
import itertools
|
|
18
|
-
from typing import Callable,
|
|
20
|
+
from typing import Callable, Iterable, Sequence, TYPE_CHECKING, Union
|
|
19
21
|
|
|
20
22
|
from cirq import _import, circuits, ops, protocols
|
|
21
23
|
from cirq.transformers import transformer_api
|
|
@@ -31,17 +33,17 @@ Classifier = Callable[['cirq.Operation'], bool]
|
|
|
31
33
|
|
|
32
34
|
# Any of the possible operation categories that we can stratify on.
|
|
33
35
|
Category = Union[
|
|
34
|
-
'cirq.Gate', 'cirq.Operation',
|
|
36
|
+
'cirq.Gate', 'cirq.Operation', type['cirq.Gate'], type['cirq.Operation'], Classifier
|
|
35
37
|
]
|
|
36
38
|
|
|
37
39
|
|
|
38
40
|
@transformer_api.transformer(add_deep_support=True)
|
|
39
41
|
def stratified_circuit(
|
|
40
|
-
circuit:
|
|
42
|
+
circuit: cirq.AbstractCircuit,
|
|
41
43
|
*,
|
|
42
|
-
context:
|
|
44
|
+
context: cirq.TransformerContext | None = None,
|
|
43
45
|
categories: Iterable[Category] = (),
|
|
44
|
-
) ->
|
|
46
|
+
) -> cirq.Circuit:
|
|
45
47
|
"""Repacks avoiding simultaneous operations with different classes.
|
|
46
48
|
|
|
47
49
|
This transforms the given circuit to ensure that no operations of different categories are
|
|
@@ -96,9 +98,9 @@ def stratified_circuit(
|
|
|
96
98
|
def _stratify_circuit(
|
|
97
99
|
circuit: circuits.AbstractCircuit,
|
|
98
100
|
*,
|
|
99
|
-
context:
|
|
101
|
+
context: cirq.TransformerContext,
|
|
100
102
|
classifiers: Sequence[Classifier],
|
|
101
|
-
) ->
|
|
103
|
+
) -> cirq.Circuit:
|
|
102
104
|
"""Performs the stratification by iterating through the operations in the
|
|
103
105
|
circuit and using the given classifiers to align them.
|
|
104
106
|
|
|
@@ -115,12 +117,12 @@ def _stratify_circuit(
|
|
|
115
117
|
The stratified circuit.
|
|
116
118
|
"""
|
|
117
119
|
num_classes = len(classifiers) + 1 # include one "extra" category for ignored operations
|
|
118
|
-
new_moments:
|
|
120
|
+
new_moments: list[list[cirq.Operation]] = []
|
|
119
121
|
|
|
120
122
|
# Keep track of the latest time index for each qubit, measurement key, and control key.
|
|
121
|
-
qubit_time_index:
|
|
122
|
-
measurement_time_index:
|
|
123
|
-
control_time_index:
|
|
123
|
+
qubit_time_index: dict[cirq.Qid, int] = {}
|
|
124
|
+
measurement_time_index: dict[cirq.MeasurementKey, int] = {}
|
|
125
|
+
control_time_index: dict[cirq.MeasurementKey, int] = {}
|
|
124
126
|
|
|
125
127
|
# The minimum time index for operations with a tag in context.tags_to_ignore.
|
|
126
128
|
last_ignored_ops_time_index = 0
|
|
@@ -162,7 +164,7 @@ def _stratify_circuit(
|
|
|
162
164
|
new_moments += [[] for _ in range(num_classes)]
|
|
163
165
|
new_moments[time_index].append(op)
|
|
164
166
|
|
|
165
|
-
# Update qubit,
|
|
167
|
+
# Update qubit, measurement key, and control key moments.
|
|
166
168
|
for qubit in op.qubits:
|
|
167
169
|
qubit_time_index[qubit] = time_index
|
|
168
170
|
for key in protocols.measurement_key_objs(op):
|
|
@@ -175,7 +177,7 @@ def _stratify_circuit(
|
|
|
175
177
|
|
|
176
178
|
def _get_classifiers(
|
|
177
179
|
circuit: circuits.AbstractCircuit, categories: Iterable[Category]
|
|
178
|
-
) ->
|
|
180
|
+
) -> list[Classifier]:
|
|
179
181
|
"""Convert a collection of categories into a list of classifiers.
|
|
180
182
|
|
|
181
183
|
The returned list of classifiers is:
|
|
@@ -221,12 +223,12 @@ def _category_to_classifier(category) -> Classifier:
|
|
|
221
223
|
)
|
|
222
224
|
|
|
223
225
|
|
|
224
|
-
def _mock_classifier(op:
|
|
226
|
+
def _mock_classifier(op: cirq.Operation) -> bool:
|
|
225
227
|
"""Mock classifier, used to "complete" a collection of classifiers and make it exhaustive."""
|
|
226
228
|
return False # pragma: no cover
|
|
227
229
|
|
|
228
230
|
|
|
229
|
-
def _get_op_class(op:
|
|
231
|
+
def _get_op_class(op: cirq.Operation, classifiers: Sequence[Classifier]) -> int:
|
|
230
232
|
"""Get the "class" of an operator, by index."""
|
|
231
233
|
for class_index, classifier in enumerate(classifiers):
|
|
232
234
|
if classifier is _mock_classifier:
|
|
@@ -11,6 +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
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
14
17
|
import pytest
|
|
15
18
|
|
|
16
19
|
import cirq
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Copyright 2025 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
|
+
"""Transformers that symbolize operations."""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import re
|
|
20
|
+
from typing import Hashable, TYPE_CHECKING
|
|
21
|
+
|
|
22
|
+
import attrs
|
|
23
|
+
import sympy
|
|
24
|
+
from attrs import validators
|
|
25
|
+
|
|
26
|
+
from cirq import ops
|
|
27
|
+
from cirq.transformers import transformer_api, transformer_primitives
|
|
28
|
+
|
|
29
|
+
if TYPE_CHECKING:
|
|
30
|
+
import cirq
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@attrs.frozen
|
|
34
|
+
class SymbolizeTag:
|
|
35
|
+
prefix: str = attrs.field(
|
|
36
|
+
validator=validators.and_(validators.instance_of(str), validators.min_len(1))
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@transformer_api.transformer
|
|
41
|
+
def symbolize_single_qubit_gates_by_indexed_tags(
|
|
42
|
+
circuit: cirq.AbstractCircuit,
|
|
43
|
+
*,
|
|
44
|
+
context: cirq.TransformerContext | None = None,
|
|
45
|
+
symbolize_tag: SymbolizeTag = SymbolizeTag(prefix="TO-PHXZ"),
|
|
46
|
+
) -> cirq.Circuit:
|
|
47
|
+
"""Symbolizes single qubit operations by indexed tags prefixed by symbolize_tag.prefix.
|
|
48
|
+
|
|
49
|
+
Example:
|
|
50
|
+
>>> from cirq import transformers
|
|
51
|
+
>>> q0, q1 = cirq.LineQubit.range(2)
|
|
52
|
+
>>> c = cirq.Circuit(
|
|
53
|
+
... cirq.X(q0).with_tags("phxz_0"),
|
|
54
|
+
... cirq.CZ(q0,q1),
|
|
55
|
+
... cirq.Y(q0).with_tags("phxz_1"),
|
|
56
|
+
... cirq.X(q0))
|
|
57
|
+
>>> print(c)
|
|
58
|
+
0: ───X[phxz_0]───@───Y[phxz_1]───X───
|
|
59
|
+
│
|
|
60
|
+
1: ───────────────@───────────────────
|
|
61
|
+
>>> new_circuit = cirq.symbolize_single_qubit_gates_by_indexed_tags(
|
|
62
|
+
... c, symbolize_tag=transformers.SymbolizeTag(prefix="phxz"))
|
|
63
|
+
>>> print(new_circuit)
|
|
64
|
+
0: ───PhXZ(a=a0,x=x0,z=z0)───@───PhXZ(a=a1,x=x1,z=z1)───X───
|
|
65
|
+
│
|
|
66
|
+
1: ──────────────────────────@──────────────────────────────
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
circuit: Input circuit to apply the transformations on. The input circuit is not mutated.
|
|
70
|
+
context: `cirq.TransformerContext` storing common configurable options for transformers.
|
|
71
|
+
symbolize_tag: The tag info used to symbolize the phxz gate. Prefix is required.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Copy of the transformed input circuit.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
def _map_func(op: cirq.Operation, _):
|
|
78
|
+
"""Maps an op with tag `{tag_prefix}_i` to a symbolized `PhasedXZGate(xi,zi,ai)`."""
|
|
79
|
+
tags: set[Hashable] = set(op.tags)
|
|
80
|
+
tag_id: None | int = None
|
|
81
|
+
for tag in tags:
|
|
82
|
+
if re.fullmatch(f"{symbolize_tag.prefix}_\\d+", str(tag)):
|
|
83
|
+
if tag_id is None:
|
|
84
|
+
tag_id = int(str(tag).rsplit("_", maxsplit=-1)[-1])
|
|
85
|
+
else:
|
|
86
|
+
raise ValueError(f"Multiple tags are prefixed with {symbolize_tag.prefix}.")
|
|
87
|
+
if tag_id is None:
|
|
88
|
+
return op
|
|
89
|
+
tags.remove(f"{symbolize_tag.prefix}_{tag_id}")
|
|
90
|
+
phxz_params = {
|
|
91
|
+
"x_exponent": sympy.Symbol(f"x{tag_id}"),
|
|
92
|
+
"z_exponent": sympy.Symbol(f"z{tag_id}"),
|
|
93
|
+
"axis_phase_exponent": sympy.Symbol(f"a{tag_id}"),
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return ops.PhasedXZGate(**phxz_params).on(*op.qubits).with_tags(*tags)
|
|
97
|
+
|
|
98
|
+
return transformer_primitives.map_operations(
|
|
99
|
+
circuit.freeze(),
|
|
100
|
+
_map_func,
|
|
101
|
+
deep=context.deep if context else False,
|
|
102
|
+
tags_to_ignore=context.tags_to_ignore if context else [],
|
|
103
|
+
).unfreeze(copy=False)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Copyright 2025 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
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import pytest
|
|
18
|
+
import sympy
|
|
19
|
+
|
|
20
|
+
import cirq
|
|
21
|
+
from cirq.transformers.symbolize import SymbolizeTag
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_symbolize_single_qubit_gates_by_indexed_tags_success():
|
|
25
|
+
q = cirq.NamedQubit("a")
|
|
26
|
+
input_circuit = cirq.Circuit(
|
|
27
|
+
cirq.X(q).with_tags("phxz_1"), cirq.Y(q).with_tags("tag1"), cirq.Z(q).with_tags("phxz_0")
|
|
28
|
+
)
|
|
29
|
+
output_circuit = cirq.symbolize_single_qubit_gates_by_indexed_tags(
|
|
30
|
+
input_circuit, symbolize_tag=SymbolizeTag(prefix="phxz")
|
|
31
|
+
)
|
|
32
|
+
cirq.testing.assert_same_circuits(
|
|
33
|
+
output_circuit,
|
|
34
|
+
cirq.Circuit(
|
|
35
|
+
cirq.PhasedXZGate(
|
|
36
|
+
x_exponent=sympy.Symbol("x1"),
|
|
37
|
+
z_exponent=sympy.Symbol("z1"),
|
|
38
|
+
axis_phase_exponent=sympy.Symbol("a1"),
|
|
39
|
+
).on(q),
|
|
40
|
+
cirq.Y(q).with_tags("tag1"),
|
|
41
|
+
cirq.PhasedXZGate(
|
|
42
|
+
x_exponent=sympy.Symbol("x0"),
|
|
43
|
+
z_exponent=sympy.Symbol("z0"),
|
|
44
|
+
axis_phase_exponent=sympy.Symbol("a0"),
|
|
45
|
+
).on(q),
|
|
46
|
+
),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_symbolize_single_qubit_gates_by_indexed_tags_multiple_tags():
|
|
51
|
+
q = cirq.NamedQubit("a")
|
|
52
|
+
input_circuit = cirq.Circuit(cirq.X(q).with_tags("TO-PHXZ_0", "TO-PHXZ_2"))
|
|
53
|
+
|
|
54
|
+
with pytest.raises(ValueError, match="Multiple tags are prefixed with TO-PHXZ."):
|
|
55
|
+
cirq.symbolize_single_qubit_gates_by_indexed_tags(input_circuit)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_symbolize_tag_invalid_prefix():
|
|
59
|
+
with pytest.raises(ValueError, match="Length of 'prefix' must be >= 1: 0"):
|
|
60
|
+
SymbolizeTag(prefix="")
|
|
61
|
+
with pytest.raises(TypeError, match="'prefix' must be <class 'str'>"):
|
|
62
|
+
SymbolizeTag(prefix=[1])
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformer pass to move terminal measurements to the end of circuit."""
|
|
16
16
|
|
|
17
|
-
from
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import TYPE_CHECKING
|
|
18
20
|
|
|
19
21
|
from cirq import circuits, protocols
|
|
20
22
|
from cirq.transformers import transformer_api
|
|
@@ -23,9 +25,7 @@ if TYPE_CHECKING:
|
|
|
23
25
|
import cirq
|
|
24
26
|
|
|
25
27
|
|
|
26
|
-
def find_terminal_measurements(
|
|
27
|
-
circuit: 'cirq.AbstractCircuit',
|
|
28
|
-
) -> List[Tuple[int, 'cirq.Operation']]:
|
|
28
|
+
def find_terminal_measurements(circuit: cirq.AbstractCircuit) -> list[tuple[int, cirq.Operation]]:
|
|
29
29
|
"""Finds all terminal measurements in the given circuit.
|
|
30
30
|
|
|
31
31
|
A measurement is terminal if there are no other operations acting on the measured qubits
|
|
@@ -39,9 +39,9 @@ def find_terminal_measurements(
|
|
|
39
39
|
(moment_index, measurement_operation).
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
|
-
open_qubits:
|
|
43
|
-
seen_control_keys:
|
|
44
|
-
terminal_measurements:
|
|
42
|
+
open_qubits: set[cirq.Qid] = set(circuit.all_qubits())
|
|
43
|
+
seen_control_keys: set[cirq.MeasurementKey] = set()
|
|
44
|
+
terminal_measurements: set[tuple[int, cirq.Operation]] = set()
|
|
45
45
|
for i in range(len(circuit) - 1, -1, -1):
|
|
46
46
|
moment = circuit[i]
|
|
47
47
|
for q in open_qubits:
|
|
@@ -62,11 +62,11 @@ def find_terminal_measurements(
|
|
|
62
62
|
|
|
63
63
|
@transformer_api.transformer(add_deep_support=True)
|
|
64
64
|
def synchronize_terminal_measurements(
|
|
65
|
-
circuit:
|
|
65
|
+
circuit: cirq.AbstractCircuit,
|
|
66
66
|
*,
|
|
67
|
-
context:
|
|
67
|
+
context: cirq.TransformerContext | None = None,
|
|
68
68
|
after_other_operations: bool = True,
|
|
69
|
-
) ->
|
|
69
|
+
) -> cirq.Circuit:
|
|
70
70
|
"""Move measurements to the end of the circuit.
|
|
71
71
|
|
|
72
72
|
Move all measurements in a circuit to the final moment, if it can accommodate them (without
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
15
17
|
import cirq
|
|
16
18
|
|
|
17
19
|
NO_COMPILE_TAG = "no_compile_tag"
|
|
@@ -48,14 +50,14 @@ def assert_optimizes(before, after, measure_only_moment=True, with_context=False
|
|
|
48
50
|
cirq.testing.assert_same_circuits(transformed_circuit, c_expected)
|
|
49
51
|
|
|
50
52
|
|
|
51
|
-
def test_no_move():
|
|
53
|
+
def test_no_move() -> None:
|
|
52
54
|
q1 = cirq.NamedQubit('q1')
|
|
53
55
|
before = cirq.Circuit([cirq.Moment([cirq.H(q1)])])
|
|
54
56
|
after = before
|
|
55
57
|
assert_optimizes(before=before, after=after)
|
|
56
58
|
|
|
57
59
|
|
|
58
|
-
def test_simple_align():
|
|
60
|
+
def test_simple_align() -> None:
|
|
59
61
|
q1 = cirq.NamedQubit('q1')
|
|
60
62
|
q2 = cirq.NamedQubit('q2')
|
|
61
63
|
before = cirq.Circuit(
|
|
@@ -76,7 +78,7 @@ def test_simple_align():
|
|
|
76
78
|
assert_optimizes(before=before, after=before, with_context=True)
|
|
77
79
|
|
|
78
80
|
|
|
79
|
-
def test_simple_partial_align():
|
|
81
|
+
def test_simple_partial_align() -> None:
|
|
80
82
|
q1 = cirq.NamedQubit('q1')
|
|
81
83
|
q2 = cirq.NamedQubit('q2')
|
|
82
84
|
before = cirq.Circuit(
|
|
@@ -96,7 +98,7 @@ def test_simple_partial_align():
|
|
|
96
98
|
assert_optimizes(before=before, after=before, with_context=True)
|
|
97
99
|
|
|
98
100
|
|
|
99
|
-
def test_slide_forward_one():
|
|
101
|
+
def test_slide_forward_one() -> None:
|
|
100
102
|
q1 = cirq.NamedQubit('q1')
|
|
101
103
|
q2 = cirq.NamedQubit('q2')
|
|
102
104
|
q3 = cirq.NamedQubit('q3')
|
|
@@ -119,7 +121,7 @@ def test_slide_forward_one():
|
|
|
119
121
|
assert_optimizes(before=before, after=after_no_compile, with_context=True)
|
|
120
122
|
|
|
121
123
|
|
|
122
|
-
def test_no_slide_forward_one():
|
|
124
|
+
def test_no_slide_forward_one() -> None:
|
|
123
125
|
q1 = cirq.NamedQubit('q1')
|
|
124
126
|
q2 = cirq.NamedQubit('q2')
|
|
125
127
|
q3 = cirq.NamedQubit('q3')
|
|
@@ -128,7 +130,7 @@ def test_no_slide_forward_one():
|
|
|
128
130
|
assert_optimizes(before=before, after=after, measure_only_moment=False)
|
|
129
131
|
|
|
130
132
|
|
|
131
|
-
def test_blocked_shift_one():
|
|
133
|
+
def test_blocked_shift_one() -> None:
|
|
132
134
|
q1 = cirq.NamedQubit('q1')
|
|
133
135
|
q2 = cirq.NamedQubit('q2')
|
|
134
136
|
before = cirq.Circuit(
|
|
@@ -150,7 +152,7 @@ def test_blocked_shift_one():
|
|
|
150
152
|
assert_optimizes(before=before, after=before, with_context=True)
|
|
151
153
|
|
|
152
154
|
|
|
153
|
-
def test_complex_move():
|
|
155
|
+
def test_complex_move() -> None:
|
|
154
156
|
q1 = cirq.NamedQubit('q1')
|
|
155
157
|
q2 = cirq.NamedQubit('q2')
|
|
156
158
|
q3 = cirq.NamedQubit('q3')
|
|
@@ -182,7 +184,7 @@ def test_complex_move():
|
|
|
182
184
|
assert_optimizes(before=before, after=before, with_context=True)
|
|
183
185
|
|
|
184
186
|
|
|
185
|
-
def test_complex_move_no_slide():
|
|
187
|
+
def test_complex_move_no_slide() -> None:
|
|
186
188
|
q1 = cirq.NamedQubit('q1')
|
|
187
189
|
q2 = cirq.NamedQubit('q2')
|
|
188
190
|
q3 = cirq.NamedQubit('q3')
|
|
@@ -208,13 +210,13 @@ def test_complex_move_no_slide():
|
|
|
208
210
|
assert_optimizes(before=before, after=before, measure_only_moment=False, with_context=True)
|
|
209
211
|
|
|
210
212
|
|
|
211
|
-
def test_multi_qubit():
|
|
213
|
+
def test_multi_qubit() -> None:
|
|
212
214
|
q0, q1 = cirq.LineQubit.range(2)
|
|
213
215
|
circuit = cirq.Circuit(cirq.H(q1), cirq.measure(q0, q1, key='m'))
|
|
214
216
|
assert_optimizes(before=circuit, after=circuit)
|
|
215
217
|
|
|
216
218
|
|
|
217
|
-
def test_classically_controlled_op():
|
|
219
|
+
def test_classically_controlled_op() -> None:
|
|
218
220
|
q0, q1 = cirq.LineQubit.range(2)
|
|
219
221
|
circuit = cirq.Circuit(
|
|
220
222
|
cirq.H(q0), cirq.measure(q0, key='m'), cirq.X(q1).with_classical_controls('m')
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Copyright 2025 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
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import itertools
|
|
18
|
+
from typing import Callable, Hashable, TYPE_CHECKING
|
|
19
|
+
|
|
20
|
+
from cirq.transformers import transformer_api, transformer_primitives
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
import cirq
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@transformer_api.transformer
|
|
27
|
+
def index_tags(
|
|
28
|
+
circuit: cirq.AbstractCircuit,
|
|
29
|
+
*,
|
|
30
|
+
context: cirq.TransformerContext | None = None,
|
|
31
|
+
target_tags: set[Hashable] | None = None,
|
|
32
|
+
) -> cirq.Circuit:
|
|
33
|
+
"""Indexes tags in target_tags as tag_0, tag_1, ... per tag.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
circuit: Input circuit to apply the transformations on. The input circuit is not mutated.
|
|
37
|
+
context: `cirq.TransformerContext` storing common configurable options for transformers.
|
|
38
|
+
target_tags: Tags to be indexed.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Copy of the transformed input circuit.
|
|
42
|
+
"""
|
|
43
|
+
if context and context.tags_to_ignore:
|
|
44
|
+
raise ValueError("index_tags doesn't support tags_to_ignore, use function args instead.")
|
|
45
|
+
if not target_tags:
|
|
46
|
+
return circuit.unfreeze(copy=False)
|
|
47
|
+
tag_iter_by_tags = {tag: itertools.count(start=0, step=1) for tag in target_tags}
|
|
48
|
+
|
|
49
|
+
def _map_func(op: cirq.Operation, _) -> cirq.OP_TREE:
|
|
50
|
+
tag_set = set(op.tags)
|
|
51
|
+
nonlocal tag_iter_by_tags
|
|
52
|
+
for tag in target_tags.intersection(op.tags):
|
|
53
|
+
tag_set.remove(tag)
|
|
54
|
+
tag_set.add(f"{tag}_{next(tag_iter_by_tags[tag])}")
|
|
55
|
+
|
|
56
|
+
return op.untagged.with_tags(*tag_set)
|
|
57
|
+
|
|
58
|
+
return transformer_primitives.map_operations(
|
|
59
|
+
circuit, _map_func, deep=context.deep if context else False
|
|
60
|
+
).unfreeze(copy=False)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@transformer_api.transformer
|
|
64
|
+
def remove_tags(
|
|
65
|
+
circuit: cirq.AbstractCircuit,
|
|
66
|
+
*,
|
|
67
|
+
context: cirq.TransformerContext | None = None,
|
|
68
|
+
target_tags: set[Hashable] | None = None,
|
|
69
|
+
remove_if: Callable[[Hashable], bool] = lambda _: False,
|
|
70
|
+
) -> cirq.Circuit:
|
|
71
|
+
"""Removes tags from the operations based on the input args.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
circuit: Input circuit to apply the transformations on. The input circuit is not mutated.
|
|
75
|
+
context: `cirq.TransformerContext` storing common configurable options for transformers.
|
|
76
|
+
target_tags: Tags to be removed.
|
|
77
|
+
remove_if: A callable(tag) that returns True if the tag should be removed.
|
|
78
|
+
Defaults to False.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Copy of the transformed input circuit.
|
|
82
|
+
"""
|
|
83
|
+
if context and context.tags_to_ignore:
|
|
84
|
+
raise ValueError("remove_tags doesn't support tags_to_ignore, use function args instead.")
|
|
85
|
+
target_tags = target_tags or set()
|
|
86
|
+
|
|
87
|
+
def _map_func(op: cirq.Operation, _) -> cirq.OP_TREE:
|
|
88
|
+
remaining_tags = set()
|
|
89
|
+
for tag in op.tags:
|
|
90
|
+
if not remove_if(tag) and tag not in target_tags:
|
|
91
|
+
remaining_tags.add(tag)
|
|
92
|
+
|
|
93
|
+
return op.untagged.with_tags(*remaining_tags)
|
|
94
|
+
|
|
95
|
+
return transformer_primitives.map_operations(
|
|
96
|
+
circuit, _map_func, deep=context.deep if context else False
|
|
97
|
+
).unfreeze(copy=False)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Copyright 2025 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
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
19
|
+
import cirq
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def check_same_circuit_with_same_tag_sets(circuit1, circuit2):
|
|
23
|
+
for op1, op2 in zip(circuit1.all_operations(), circuit2.all_operations()):
|
|
24
|
+
assert set(op1.tags) == set(op2.tags)
|
|
25
|
+
assert op1.untagged == op2.untagged
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_index_tags():
|
|
29
|
+
q0, q1 = cirq.LineQubit.range(2)
|
|
30
|
+
input_circuit = cirq.Circuit(
|
|
31
|
+
cirq.X(q0).with_tags("tag1", "tag2"),
|
|
32
|
+
cirq.Y(q1).with_tags("tag1"),
|
|
33
|
+
cirq.CZ(q0, q1).with_tags("tag2"),
|
|
34
|
+
)
|
|
35
|
+
expected_circuit = cirq.Circuit(
|
|
36
|
+
cirq.X(q0).with_tags("tag1_0", "tag2_0"),
|
|
37
|
+
cirq.Y(q1).with_tags("tag1_1"),
|
|
38
|
+
cirq.CZ(q0, q1).with_tags("tag2_1"),
|
|
39
|
+
)
|
|
40
|
+
check_same_circuit_with_same_tag_sets(
|
|
41
|
+
cirq.index_tags(input_circuit, target_tags={"tag1", "tag2"}), expected_circuit
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_index_tags_empty_target_tags():
|
|
46
|
+
q0, q1 = cirq.LineQubit.range(2)
|
|
47
|
+
input_circuit = cirq.Circuit(
|
|
48
|
+
cirq.X(q0).with_tags("tag1", "tag2"),
|
|
49
|
+
cirq.Y(q1).with_tags("tag1"),
|
|
50
|
+
cirq.CZ(q0, q1).with_tags("tag2"),
|
|
51
|
+
)
|
|
52
|
+
check_same_circuit_with_same_tag_sets(
|
|
53
|
+
cirq.index_tags(input_circuit, target_tags={}), input_circuit
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_remove_tags():
|
|
58
|
+
q0, q1 = cirq.LineQubit.range(2)
|
|
59
|
+
input_circuit = cirq.Circuit(
|
|
60
|
+
cirq.X(q0).with_tags("tag1", "tag2"),
|
|
61
|
+
cirq.Y(q1).with_tags("tag1"),
|
|
62
|
+
cirq.CZ(q0, q1).with_tags("tag2"),
|
|
63
|
+
)
|
|
64
|
+
expected_circuit = cirq.Circuit(
|
|
65
|
+
cirq.X(q0).with_tags("tag2"), cirq.Y(q1), cirq.CZ(q0, q1).with_tags("tag2")
|
|
66
|
+
)
|
|
67
|
+
check_same_circuit_with_same_tag_sets(
|
|
68
|
+
cirq.remove_tags(input_circuit, target_tags={"tag1"}), expected_circuit
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_remove_tags_via_remove_if():
|
|
73
|
+
q0, q1 = cirq.LineQubit.range(2)
|
|
74
|
+
input_circuit = cirq.Circuit(
|
|
75
|
+
cirq.X(q0).with_tags("tag1", "tag2"),
|
|
76
|
+
cirq.Y(q1).with_tags("not_tag1"),
|
|
77
|
+
cirq.CZ(q0, q1).with_tags("tag2"),
|
|
78
|
+
)
|
|
79
|
+
expected_circuit = cirq.Circuit(cirq.X(q0), cirq.Y(q1).with_tags("not_tag1"), cirq.CZ(q0, q1))
|
|
80
|
+
check_same_circuit_with_same_tag_sets(
|
|
81
|
+
cirq.remove_tags(input_circuit, remove_if=lambda tag: tag.startswith("tag")),
|
|
82
|
+
expected_circuit,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_index_tags_with_tags_to_ignore():
|
|
87
|
+
with pytest.raises(
|
|
88
|
+
ValueError, match="index_tags doesn't support tags_to_ignore, use function args instead."
|
|
89
|
+
):
|
|
90
|
+
cirq.index_tags(
|
|
91
|
+
circuit=cirq.Circuit(),
|
|
92
|
+
target_tags={"tag0"},
|
|
93
|
+
context=cirq.TransformerContext(tags_to_ignore=["tag0"]),
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_remove_tags_with_tags_to_ignore():
|
|
98
|
+
with pytest.raises(
|
|
99
|
+
ValueError, match="remove_tags doesn't support tags_to_ignore, use function args instead."
|
|
100
|
+
):
|
|
101
|
+
cirq.remove_tags(
|
|
102
|
+
circuit=cirq.Circuit(), context=cirq.TransformerContext(tags_to_ignore=["tag0"])
|
|
103
|
+
)
|