cirq-core 1.4.0.dev20240529225110__py3-none-any.whl → 1.5.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 +587 -569
- cirq/_compat.py +9 -0
- cirq/_compat_test.py +11 -9
- cirq/_import.py +7 -8
- cirq/_version.py +31 -1
- cirq/_version_test.py +1 -1
- cirq/circuits/__init__.py +15 -9
- cirq/circuits/_block_diagram_drawer.py +1 -2
- cirq/circuits/_block_diagram_drawer_test.py +3 -3
- cirq/circuits/_box_drawing_character_data.py +0 -1
- cirq/circuits/_box_drawing_character_data_test.py +2 -2
- cirq/circuits/_bucket_priority_queue.py +0 -1
- cirq/circuits/_bucket_priority_queue_test.py +1 -1
- cirq/circuits/circuit.py +336 -234
- cirq/circuits/circuit_operation.py +102 -52
- cirq/circuits/circuit_operation_test.py +85 -4
- cirq/circuits/circuit_test.py +101 -32
- cirq/circuits/frozen_circuit.py +36 -32
- cirq/circuits/insert_strategy.py +10 -0
- cirq/circuits/insert_strategy_test.py +20 -0
- cirq/circuits/moment.py +79 -80
- cirq/circuits/moment_test.py +105 -2
- cirq/circuits/optimization_pass.py +15 -15
- cirq/circuits/optimization_pass_test.py +8 -9
- cirq/circuits/qasm_output.py +64 -33
- cirq/circuits/qasm_output_test.py +63 -2
- cirq/circuits/text_diagram_drawer.py +26 -56
- cirq/circuits/text_diagram_drawer_test.py +5 -4
- cirq/contrib/__init__.py +2 -2
- cirq/contrib/acquaintance/__init__.py +44 -29
- cirq/contrib/acquaintance/bipartite.py +8 -7
- cirq/contrib/acquaintance/bipartite_test.py +11 -1
- cirq/contrib/acquaintance/devices.py +5 -4
- cirq/contrib/acquaintance/devices_test.py +5 -1
- cirq/contrib/acquaintance/executor.py +18 -21
- cirq/contrib/acquaintance/executor_test.py +3 -2
- cirq/contrib/acquaintance/gates.py +36 -27
- cirq/contrib/acquaintance/gates_test.py +1 -1
- cirq/contrib/acquaintance/inspection_utils.py +10 -9
- cirq/contrib/acquaintance/inspection_utils_test.py +6 -1
- cirq/contrib/acquaintance/mutation_utils.py +10 -10
- cirq/contrib/acquaintance/optimizers.py +7 -6
- cirq/contrib/acquaintance/optimizers_test.py +1 -1
- cirq/contrib/acquaintance/permutation.py +22 -21
- cirq/contrib/acquaintance/permutation_test.py +1 -1
- cirq/contrib/acquaintance/shift.py +8 -6
- cirq/contrib/acquaintance/shift_swap_network.py +6 -4
- cirq/contrib/acquaintance/strategies/__init__.py +9 -3
- cirq/contrib/acquaintance/strategies/complete.py +4 -3
- cirq/contrib/acquaintance/strategies/cubic.py +5 -3
- cirq/contrib/acquaintance/strategies/quartic_paired.py +8 -6
- cirq/contrib/acquaintance/topological_sort.py +4 -2
- cirq/contrib/bayesian_network/__init__.py +3 -1
- cirq/contrib/bayesian_network/bayesian_network_gate.py +5 -3
- cirq/contrib/circuitdag/__init__.py +1 -1
- cirq/contrib/circuitdag/circuit_dag.py +24 -24
- cirq/contrib/circuitdag/circuit_dag_test.py +1 -1
- cirq/contrib/custom_simulators/custom_state_simulator.py +10 -8
- cirq/contrib/custom_simulators/custom_state_simulator_test.py +15 -11
- cirq/contrib/graph_device/__init__.py +8 -8
- cirq/contrib/graph_device/graph_device.py +8 -8
- cirq/contrib/graph_device/graph_device_test.py +0 -1
- cirq/contrib/graph_device/hypergraph_test.py +1 -0
- cirq/contrib/json.py +1 -2
- cirq/contrib/json_test.py +2 -2
- cirq/contrib/noise_models/__init__.py +5 -6
- cirq/contrib/noise_models/noise_models.py +8 -6
- cirq/contrib/paulistring/__init__.py +22 -10
- cirq/contrib/paulistring/clifford_optimize.py +1 -1
- cirq/contrib/paulistring/clifford_optimize_test.py +0 -1
- cirq/contrib/paulistring/clifford_target_gateset.py +15 -12
- cirq/contrib/paulistring/optimize.py +2 -2
- cirq/contrib/paulistring/optimize_test.py +0 -1
- cirq/contrib/paulistring/pauli_string_dag_test.py +0 -1
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +379 -0
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +523 -0
- cirq/contrib/paulistring/pauli_string_optimize.py +3 -1
- cirq/contrib/paulistring/pauli_string_optimize_test.py +1 -3
- cirq/contrib/paulistring/recombine.py +2 -2
- cirq/contrib/paulistring/recombine_test.py +2 -2
- cirq/contrib/paulistring/separate.py +3 -4
- cirq/contrib/qasm_import/__init__.py +2 -2
- cirq/contrib/qasm_import/_lexer.py +21 -26
- cirq/contrib/qasm_import/_lexer_test.py +90 -6
- cirq/contrib/qasm_import/_parser.py +238 -47
- cirq/contrib/qasm_import/_parser_test.py +514 -59
- cirq/contrib/qasm_import/qasm_test.py +1 -1
- cirq/contrib/qcircuit/__init__.py +6 -4
- cirq/contrib/qcircuit/qcircuit_diagram.py +5 -2
- cirq/contrib/qcircuit/qcircuit_pdf.py +1 -2
- cirq/{experiments/grid_parallel_two_qubit_xeb_test.py → contrib/qcircuit/qcircuit_pdf_test.py} +13 -12
- cirq/contrib/qcircuit/qcircuit_test.py +1 -1
- cirq/contrib/quantum_volume/__init__.py +7 -7
- cirq/contrib/quantum_volume/quantum_volume.py +6 -11
- cirq/contrib/quantum_volume/quantum_volume_test.py +3 -1
- cirq/contrib/quimb/__init__.py +16 -13
- cirq/contrib/quimb/density_matrix.py +1 -1
- cirq/contrib/quimb/mps_simulator.py +27 -28
- cirq/contrib/quimb/mps_simulator_test.py +5 -0
- cirq/contrib/quimb/state_vector.py +3 -10
- cirq/contrib/quirk/__init__.py +1 -1
- cirq/contrib/quirk/export_to_quirk.py +3 -3
- cirq/contrib/routing/__init__.py +12 -9
- cirq/contrib/routing/device.py +1 -1
- cirq/contrib/routing/device_test.py +1 -2
- cirq/contrib/routing/greedy.py +7 -5
- cirq/contrib/routing/greedy_test.py +5 -3
- cirq/contrib/routing/initialization.py +3 -1
- cirq/contrib/routing/initialization_test.py +1 -1
- cirq/contrib/routing/swap_network.py +6 -6
- cirq/contrib/routing/utils.py +6 -4
- cirq/contrib/routing/utils_test.py +1 -2
- cirq/{type_workarounds.py → contrib/shuffle_circuits/__init__.py} +5 -10
- cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +250 -0
- cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking_test.py +363 -0
- cirq/contrib/svg/__init__.py +1 -1
- cirq/contrib/svg/svg.py +12 -10
- cirq/contrib/svg/svg_test.py +3 -2
- cirq/devices/__init__.py +34 -25
- cirq/devices/device.py +16 -12
- cirq/devices/device_test.py +1 -0
- cirq/devices/grid_device_metadata.py +16 -12
- cirq/devices/grid_device_metadata_test.py +2 -1
- cirq/devices/grid_qubit.py +31 -26
- cirq/devices/grid_qubit_test.py +30 -1
- cirq/devices/insertion_noise_model.py +6 -6
- cirq/devices/insertion_noise_model_test.py +1 -1
- cirq/devices/line_qubit.py +28 -20
- cirq/devices/line_qubit_test.py +26 -0
- cirq/devices/named_topologies.py +12 -10
- cirq/devices/named_topologies_test.py +5 -4
- cirq/devices/noise_model.py +29 -33
- cirq/devices/noise_properties.py +2 -2
- cirq/devices/noise_properties_test.py +2 -2
- cirq/devices/noise_utils.py +3 -3
- cirq/devices/superconducting_qubits_noise_properties.py +2 -2
- cirq/devices/superconducting_qubits_noise_properties_test.py +3 -3
- cirq/devices/thermal_noise_model.py +2 -1
- cirq/devices/unconstrained_device.py +1 -1
- cirq/devices/unconstrained_device_test.py +6 -0
- cirq/experiments/__init__.py +51 -34
- cirq/experiments/qubit_characterizations.py +17 -15
- cirq/experiments/qubit_characterizations_test.py +4 -6
- cirq/experiments/random_quantum_circuit_generation.py +10 -9
- cirq/experiments/random_quantum_circuit_generation_test.py +21 -4
- cirq/experiments/readout_confusion_matrix.py +73 -8
- cirq/experiments/readout_confusion_matrix_test.py +104 -1
- cirq/experiments/single_qubit_readout_calibration.py +8 -6
- cirq/experiments/single_qubit_readout_calibration_test.py +1 -1
- cirq/experiments/t1_decay_experiment.py +4 -5
- cirq/experiments/t1_decay_experiment_test.py +1 -2
- cirq/experiments/t2_decay_experiment.py +0 -1
- cirq/experiments/t2_decay_experiment_test.py +1 -2
- cirq/experiments/two_qubit_xeb.py +157 -33
- cirq/experiments/two_qubit_xeb_test.py +38 -22
- cirq/experiments/xeb_fitting.py +99 -19
- cirq/experiments/xeb_fitting_test.py +64 -25
- cirq/experiments/xeb_sampling.py +14 -18
- cirq/experiments/xeb_simulation.py +4 -3
- cirq/experiments/xeb_simulation_test.py +20 -14
- cirq/experiments/z_phase_calibration.py +368 -0
- cirq/experiments/z_phase_calibration_test.py +241 -0
- cirq/interop/__init__.py +4 -1
- cirq/interop/quirk/__init__.py +7 -4
- cirq/interop/quirk/cells/__init__.py +17 -6
- cirq/interop/quirk/cells/arithmetic_cells.py +8 -8
- cirq/interop/quirk/cells/arithmetic_cells_test.py +1 -1
- cirq/interop/quirk/cells/cell.py +6 -6
- cirq/interop/quirk/cells/composite_cell.py +5 -5
- cirq/interop/quirk/cells/composite_cell_test.py +1 -1
- cirq/interop/quirk/cells/control_cells.py +1 -1
- cirq/interop/quirk/cells/frequency_space_cells.py +2 -2
- cirq/interop/quirk/cells/ignored_cells.py +1 -1
- cirq/interop/quirk/cells/input_cells.py +1 -1
- cirq/interop/quirk/cells/input_cells_test.py +1 -1
- cirq/interop/quirk/cells/input_rotation_cells.py +1 -1
- cirq/interop/quirk/cells/input_rotation_cells_test.py +1 -1
- cirq/interop/quirk/cells/measurement_cells.py +1 -1
- cirq/interop/quirk/cells/parse.py +8 -7
- cirq/interop/quirk/cells/parse_test.py +2 -2
- cirq/interop/quirk/cells/single_qubit_rotation_cells.py +1 -1
- cirq/interop/quirk/cells/swap_cell_test.py +1 -1
- cirq/interop/quirk/cells/unsupported_cells.py +1 -1
- cirq/interop/quirk/url_to_circuit.py +7 -7
- cirq/interop/quirk/url_to_circuit_test.py +1 -1
- cirq/ion/__init__.py +4 -2
- cirq/json_resolver_cache.py +15 -7
- cirq/linalg/__init__.py +62 -51
- cirq/linalg/combinators.py +4 -4
- cirq/linalg/combinators_test.py +4 -1
- cirq/linalg/decompositions.py +15 -40
- cirq/linalg/decompositions_test.py +16 -22
- cirq/linalg/diagonalize.py +1 -1
- cirq/linalg/diagonalize_test.py +1 -1
- cirq/linalg/operator_spaces.py +20 -4
- cirq/linalg/operator_spaces_test.py +15 -2
- cirq/linalg/predicates.py +3 -3
- cirq/linalg/predicates_test.py +1 -0
- cirq/linalg/tolerance.py +2 -2
- cirq/linalg/transformations.py +30 -12
- cirq/linalg/transformations_test.py +13 -0
- cirq/neutral_atoms/__init__.py +2 -2
- cirq/neutral_atoms/convert_to_neutral_atom_gates_test.py +0 -1
- cirq/ops/__init__.py +172 -132
- cirq/ops/arithmetic_operation.py +2 -2
- cirq/ops/arithmetic_operation_test.py +2 -2
- cirq/ops/boolean_hamiltonian.py +3 -2
- cirq/ops/classically_controlled_operation.py +39 -12
- cirq/ops/classically_controlled_operation_test.py +147 -1
- cirq/ops/clifford_gate.py +38 -36
- cirq/ops/clifford_gate_test.py +75 -1
- cirq/ops/common_channels.py +16 -45
- cirq/ops/common_channels_test.py +10 -0
- cirq/ops/common_gate_families.py +1 -1
- cirq/ops/common_gate_families_test.py +1 -0
- cirq/ops/common_gates.py +48 -49
- cirq/ops/common_gates_test.py +18 -2
- cirq/ops/control_values.py +3 -3
- cirq/ops/control_values_test.py +2 -1
- cirq/ops/controlled_gate.py +36 -23
- cirq/ops/controlled_gate_test.py +70 -3
- cirq/ops/controlled_operation.py +6 -5
- cirq/ops/controlled_operation_test.py +7 -3
- cirq/ops/dense_pauli_string.py +11 -11
- cirq/ops/diagonal_gate.py +2 -2
- cirq/ops/diagonal_gate_test.py +1 -0
- cirq/ops/eigen_gate.py +16 -36
- cirq/ops/eigen_gate_test.py +60 -10
- cirq/ops/fourier_transform.py +1 -3
- cirq/ops/fourier_transform_test.py +2 -1
- cirq/ops/fsim_gate.py +42 -3
- cirq/ops/fsim_gate_test.py +21 -0
- cirq/ops/gate_operation.py +8 -8
- cirq/ops/gate_operation_test.py +4 -2
- cirq/ops/gateset_test.py +11 -2
- cirq/ops/global_phase_op.py +8 -7
- cirq/ops/global_phase_op_test.py +1 -1
- cirq/ops/greedy_qubit_manager_test.py +5 -0
- cirq/ops/identity.py +14 -4
- cirq/ops/identity_test.py +24 -0
- cirq/ops/kraus_channel.py +1 -0
- cirq/ops/kraus_channel_test.py +3 -1
- cirq/ops/linear_combinations.py +27 -21
- cirq/ops/linear_combinations_test.py +23 -4
- cirq/ops/matrix_gates.py +24 -8
- cirq/ops/measure_util.py +2 -2
- cirq/ops/measurement_gate.py +7 -4
- cirq/ops/measurement_gate_test.py +2 -1
- cirq/ops/mixed_unitary_channel.py +1 -0
- cirq/ops/mixed_unitary_channel_test.py +3 -1
- cirq/ops/named_qubit.py +8 -1
- cirq/ops/op_tree.py +3 -30
- cirq/ops/op_tree_test.py +4 -0
- cirq/ops/parallel_gate.py +2 -3
- cirq/ops/parallel_gate_test.py +2 -1
- cirq/ops/parity_gates.py +7 -8
- cirq/ops/parity_gates_test.py +1 -0
- cirq/ops/pauli_gates.py +5 -11
- cirq/ops/pauli_gates_test.py +1 -0
- cirq/ops/pauli_interaction_gate.py +11 -5
- cirq/ops/pauli_interaction_gate_test.py +2 -3
- cirq/ops/pauli_measurement_gate.py +6 -5
- cirq/ops/pauli_measurement_gate_test.py +1 -0
- cirq/ops/pauli_string.py +115 -130
- cirq/ops/pauli_string_phasor.py +21 -20
- cirq/ops/pauli_string_phasor_test.py +13 -3
- cirq/ops/pauli_string_raw_types.py +1 -0
- cirq/ops/pauli_string_test.py +192 -55
- cirq/ops/pauli_sum_exponential.py +3 -4
- cirq/ops/pauli_sum_exponential_test.py +0 -1
- cirq/ops/permutation_gate.py +2 -2
- cirq/ops/permutation_gate_test.py +1 -1
- cirq/ops/phased_iswap_gate.py +6 -7
- cirq/ops/phased_iswap_gate_test.py +21 -5
- cirq/ops/phased_x_gate.py +11 -25
- cirq/ops/phased_x_gate_test.py +19 -3
- cirq/ops/phased_x_z_gate.py +12 -11
- cirq/ops/projector.py +4 -5
- cirq/ops/qubit_manager.py +2 -1
- cirq/ops/qubit_manager_test.py +2 -1
- cirq/ops/qubit_order.py +1 -1
- cirq/ops/random_gate_channel.py +1 -1
- cirq/ops/random_gate_channel_test.py +0 -6
- cirq/ops/raw_types.py +146 -50
- cirq/ops/raw_types_test.py +37 -3
- cirq/ops/state_preparation_channel.py +2 -2
- cirq/ops/state_preparation_channel_test.py +2 -1
- cirq/ops/swap_gates.py +9 -4
- cirq/ops/three_qubit_gates.py +8 -8
- cirq/ops/three_qubit_gates_test.py +1 -0
- cirq/ops/two_qubit_diagonal_gate.py +4 -3
- cirq/ops/uniform_superposition_gate.py +4 -4
- cirq/ops/uniform_superposition_gate_test.py +1 -0
- cirq/ops/wait_gate.py +6 -8
- cirq/protocols/__init__.py +135 -83
- cirq/protocols/act_on_protocol.py +1 -1
- cirq/protocols/act_on_protocol_test.py +1 -1
- cirq/protocols/apply_channel_protocol.py +3 -3
- cirq/protocols/apply_mixture_protocol.py +15 -9
- cirq/protocols/apply_mixture_protocol_test.py +11 -0
- cirq/protocols/apply_unitary_protocol.py +2 -2
- cirq/protocols/apply_unitary_protocol_test.py +2 -1
- cirq/protocols/approximate_equality_protocol.py +7 -8
- cirq/protocols/approximate_equality_protocol_test.py +3 -1
- cirq/protocols/circuit_diagram_info_protocol.py +8 -6
- cirq/protocols/circuit_diagram_info_protocol_test.py +5 -0
- cirq/protocols/commutes_protocol.py +6 -6
- cirq/protocols/control_key_protocol.py +1 -1
- cirq/protocols/decompose_protocol.py +4 -5
- cirq/protocols/decompose_protocol_test.py +2 -1
- cirq/protocols/equal_up_to_global_phase_protocol.py +3 -3
- cirq/protocols/equal_up_to_global_phase_protocol_test.py +7 -0
- cirq/protocols/has_stabilizer_effect_protocol.py +5 -5
- cirq/protocols/has_unitary_protocol.py +1 -1
- cirq/protocols/has_unitary_protocol_test.py +8 -7
- cirq/protocols/hash_from_pickle_test.py +120 -0
- cirq/protocols/inverse_protocol.py +1 -1
- cirq/protocols/json_serialization.py +14 -1
- cirq/protocols/json_serialization_test.py +28 -7
- cirq/protocols/json_test_data/BitMaskKeyCondition.json +86 -0
- cirq/protocols/json_test_data/BitMaskKeyCondition.repr +7 -0
- cirq/protocols/json_test_data/Concat.json +19 -0
- cirq/protocols/json_test_data/Concat.repr +1 -0
- cirq/protocols/json_test_data/README.md +4 -2
- cirq/protocols/json_test_data/SympyCondition.json +60 -15
- cirq/protocols/json_test_data/SympyCondition.repr +4 -1
- cirq/protocols/json_test_data/_InverseCompositeGate.json +10 -0
- cirq/protocols/json_test_data/_InverseCompositeGate.repr +1 -0
- cirq/protocols/json_test_data/__init__.py +1 -1
- cirq/protocols/json_test_data/sympy.And.json +13 -0
- cirq/protocols/json_test_data/sympy.And.repr +1 -0
- cirq/protocols/json_test_data/sympy.Indexed.json +18 -0
- cirq/protocols/json_test_data/sympy.Indexed.repr +1 -0
- cirq/protocols/json_test_data/sympy.IndexedBase.json +9 -0
- cirq/protocols/json_test_data/sympy.IndexedBase.repr +1 -0
- cirq/protocols/json_test_data/sympy.Not.json +9 -0
- cirq/protocols/json_test_data/sympy.Not.repr +1 -0
- cirq/protocols/json_test_data/sympy.Or.json +13 -0
- cirq/protocols/json_test_data/sympy.Or.repr +1 -0
- cirq/protocols/json_test_data/sympy.Xor.json +13 -0
- cirq/protocols/json_test_data/sympy.Xor.repr +1 -0
- cirq/protocols/kraus_protocol.py +8 -8
- cirq/protocols/kraus_protocol_test.py +0 -1
- cirq/protocols/measurement_key_protocol.py +1 -1
- cirq/protocols/measurement_key_protocol_test.py +7 -7
- cirq/protocols/mixture_protocol.py +6 -4
- cirq/protocols/mixture_protocol_test.py +21 -13
- cirq/protocols/pauli_expansion_protocol.py +1 -0
- cirq/protocols/pow_protocol.py +1 -1
- cirq/protocols/qasm.py +25 -6
- cirq/protocols/qasm_test.py +17 -0
- cirq/protocols/qid_shape_protocol.py +2 -2
- cirq/protocols/resolve_parameters.py +2 -3
- cirq/protocols/resolve_parameters_test.py +2 -1
- cirq/protocols/trace_distance_bound.py +1 -1
- cirq/protocols/trace_distance_bound_test.py +1 -0
- cirq/protocols/unitary_protocol.py +3 -3
- cirq/protocols/unitary_protocol_test.py +1 -1
- cirq/qis/__init__.py +48 -35
- cirq/qis/channels_test.py +0 -9
- cirq/qis/clifford_tableau.py +46 -26
- cirq/qis/clifford_tableau_test.py +2 -1
- cirq/qis/entropy.py +115 -0
- cirq/qis/entropy_test.py +43 -0
- cirq/qis/measures.py +5 -4
- cirq/qis/measures_test.py +7 -0
- cirq/qis/noise_utils_test.py +4 -4
- cirq/qis/quantum_state_representation.py +1 -1
- cirq/qis/states.py +7 -7
- cirq/sim/__init__.py +55 -37
- cirq/sim/classical_simulator.py +7 -6
- cirq/sim/classical_simulator_test.py +3 -1
- cirq/sim/clifford/__init__.py +17 -9
- cirq/sim/clifford/clifford_simulator.py +5 -4
- cirq/sim/clifford/clifford_simulator_test.py +32 -9
- cirq/sim/clifford/clifford_tableau_simulation_state.py +1 -1
- cirq/sim/clifford/stabilizer_simulation_state.py +1 -1
- cirq/sim/clifford/stabilizer_state_ch_form.py +4 -3
- cirq/sim/density_matrix_simulator.py +3 -2
- cirq/sim/density_matrix_simulator_test.py +12 -4
- cirq/sim/density_matrix_utils.py +1 -1
- cirq/sim/mux.py +2 -2
- cirq/sim/simulation_state.py +4 -5
- cirq/sim/simulation_state_base.py +2 -2
- cirq/sim/simulation_state_test.py +1 -1
- cirq/sim/simulation_utils.py +3 -1
- cirq/sim/simulation_utils_test.py +2 -3
- cirq/sim/simulator.py +7 -6
- cirq/sim/simulator_base.py +5 -5
- cirq/sim/simulator_test.py +14 -3
- cirq/sim/sparse_simulator.py +4 -3
- cirq/sim/sparse_simulator_test.py +17 -9
- cirq/sim/state_vector.py +2 -2
- cirq/sim/state_vector_simulation_state_test.py +1 -1
- cirq/sim/state_vector_simulator.py +4 -4
- cirq/sim/state_vector_test.py +27 -32
- cirq/study/__init__.py +27 -21
- cirq/study/flatten_expressions.py +5 -6
- cirq/study/flatten_expressions_test.py +1 -1
- cirq/study/resolver.py +14 -11
- cirq/study/resolver_test.py +10 -1
- cirq/study/result.py +3 -3
- cirq/study/sweepable.py +15 -9
- cirq/study/sweepable_test.py +27 -0
- cirq/study/sweeps.py +65 -10
- cirq/study/sweeps_test.py +123 -0
- cirq/testing/__init__.py +86 -57
- cirq/testing/_compat_test_data/module_a/__init__.py +2 -2
- cirq/testing/_compat_test_data/module_a/sub/subsub/__init__.py +1 -1
- cirq/testing/circuit_compare.py +3 -4
- cirq/testing/circuit_compare_test.py +7 -8
- cirq/testing/consistent_act_on.py +3 -3
- cirq/testing/consistent_channels_test.py +2 -1
- cirq/testing/consistent_controlled_gate_op.py +3 -2
- cirq/testing/consistent_controlled_gate_op_test.py +2 -3
- cirq/testing/consistent_decomposition.py +1 -1
- cirq/testing/consistent_decomposition_test.py +1 -2
- cirq/testing/consistent_pauli_expansion_test.py +1 -1
- cirq/testing/consistent_phase_by.py +1 -1
- cirq/testing/consistent_phase_by_test.py +1 -2
- cirq/testing/consistent_protocols.py +11 -11
- cirq/testing/consistent_protocols_test.py +4 -5
- cirq/testing/consistent_qasm.py +8 -12
- cirq/testing/consistent_qasm_test.py +1 -1
- cirq/testing/consistent_resolve_parameters.py +2 -1
- cirq/testing/consistent_specified_has_unitary_test.py +1 -1
- cirq/testing/consistent_unitary.py +3 -1
- cirq/testing/consistent_unitary_test.py +3 -3
- cirq/testing/devices.py +1 -1
- cirq/testing/devices_test.py +1 -0
- cirq/testing/equals_tester.py +2 -4
- cirq/testing/equals_tester_test.py +6 -5
- cirq/testing/equivalent_basis_map.py +1 -0
- cirq/testing/equivalent_basis_map_test.py +0 -1
- cirq/testing/gate_features_test.py +5 -0
- cirq/testing/json.py +4 -4
- cirq/testing/lin_alg_utils_test.py +1 -1
- cirq/testing/order_tester.py +1 -1
- cirq/testing/order_tester_test.py +1 -1
- cirq/testing/pytest_utils.py +57 -0
- cirq/testing/pytest_utils_test.py +35 -0
- cirq/testing/random_circuit.py +2 -2
- cirq/testing/random_circuit_test.py +2 -2
- cirq/testing/routing_devices_test.py +2 -1
- cirq/testing/sample_circuits.py +1 -1
- cirq/testing/sample_gates.py +5 -4
- cirq/testing/sample_gates_test.py +2 -2
- cirq/transformers/__init__.py +101 -82
- cirq/transformers/align.py +12 -1
- cirq/transformers/align_test.py +13 -0
- cirq/transformers/analytical_decompositions/__init__.py +27 -24
- cirq/transformers/analytical_decompositions/clifford_decomposition.py +2 -1
- cirq/transformers/analytical_decompositions/clifford_decomposition_test.py +1 -1
- cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +1 -1
- cirq/transformers/analytical_decompositions/controlled_gate_decomposition_test.py +2 -0
- cirq/transformers/analytical_decompositions/cphase_to_fsim.py +1 -1
- cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py +1 -1
- cirq/transformers/analytical_decompositions/pauli_string_decomposition.py +2 -2
- cirq/transformers/analytical_decompositions/pauli_string_decomposition_test.py +4 -4
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +99 -24
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +105 -14
- cirq/transformers/analytical_decompositions/single_qubit_decompositions.py +1 -1
- cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry.py +1 -1
- cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry_test.py +1 -0
- cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +3 -4
- cirq/transformers/analytical_decompositions/three_qubit_decomposition_test.py +1 -1
- cirq/transformers/analytical_decompositions/two_qubit_state_preparation.py +2 -1
- cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py +2 -1
- cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +5 -6
- cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +2 -2
- cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +1 -1
- cirq/transformers/analytical_decompositions/two_qubit_to_fsim_test.py +1 -2
- cirq/transformers/analytical_decompositions/two_qubit_to_ms.py +2 -2
- cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py +2 -2
- cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap_test.py +2 -1
- cirq/transformers/drop_empty_moments.py +1 -0
- cirq/transformers/drop_negligible_operations.py +1 -0
- cirq/transformers/dynamical_decoupling.py +255 -43
- cirq/transformers/dynamical_decoupling_test.py +730 -17
- cirq/transformers/eject_phased_paulis.py +29 -15
- cirq/transformers/eject_phased_paulis_test.py +3 -8
- cirq/transformers/eject_z.py +3 -2
- cirq/transformers/eject_z_test.py +3 -3
- cirq/transformers/gauge_compiling/__init__.py +25 -9
- cirq/transformers/gauge_compiling/cphase_gauge.py +146 -0
- cirq/transformers/gauge_compiling/cphase_gauge_test.py +42 -0
- cirq/transformers/gauge_compiling/cz_gauge.py +4 -4
- cirq/transformers/gauge_compiling/gauge_compiling.py +245 -6
- cirq/transformers/gauge_compiling/gauge_compiling_test.py +107 -2
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +39 -2
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils_test.py +10 -1
- cirq/transformers/gauge_compiling/iswap_gauge.py +2 -2
- cirq/transformers/gauge_compiling/spin_inversion_gauge.py +2 -2
- cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +23 -5
- cirq/transformers/gauge_compiling/sqrt_iswap_gauge.py +3 -2
- cirq/transformers/heuristic_decompositions/__init__.py +3 -3
- cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +2 -1
- cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils_test.py +1 -1
- cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +4 -4
- cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation_test.py +4 -4
- cirq/transformers/insertion_sort.py +64 -0
- cirq/transformers/insertion_sort_test.py +34 -0
- cirq/transformers/measurement_transformers.py +14 -1
- cirq/transformers/measurement_transformers_test.py +35 -0
- cirq/transformers/merge_k_qubit_gates.py +2 -2
- cirq/transformers/merge_single_qubit_gates.py +1 -1
- cirq/transformers/merge_single_qubit_gates_test.py +1 -1
- cirq/transformers/noise_adding.py +115 -0
- cirq/transformers/noise_adding_test.py +54 -0
- cirq/transformers/optimize_for_target_gateset.py +1 -1
- cirq/transformers/optimize_for_target_gateset_test.py +3 -2
- cirq/transformers/qubit_management_transformers.py +1 -1
- cirq/transformers/randomized_measurements.py +171 -0
- cirq/transformers/randomized_measurements_test.py +68 -0
- cirq/transformers/routing/__init__.py +14 -5
- cirq/transformers/routing/initial_mapper.py +1 -1
- cirq/transformers/routing/initial_mapper_test.py +1 -0
- cirq/transformers/routing/line_initial_mapper.py +3 -2
- cirq/transformers/routing/mapping_manager.py +2 -2
- cirq/transformers/routing/mapping_manager_test.py +2 -2
- cirq/transformers/routing/route_circuit_cqc.py +3 -2
- cirq/transformers/routing/route_circuit_cqc_test.py +2 -1
- cirq/transformers/routing/visualize_routed_circuit.py +1 -0
- cirq/transformers/routing/visualize_routed_circuit_test.py +1 -0
- cirq/transformers/stratify.py +2 -2
- cirq/transformers/synchronize_terminal_measurements.py +2 -1
- cirq/transformers/target_gatesets/__init__.py +7 -5
- cirq/transformers/target_gatesets/compilation_target_gateset.py +16 -3
- cirq/transformers/target_gatesets/compilation_target_gateset_test.py +2 -0
- cirq/transformers/target_gatesets/cz_gateset.py +5 -1
- cirq/transformers/target_gatesets/cz_gateset_test.py +23 -2
- cirq/transformers/target_gatesets/sqrt_iswap_gateset.py +1 -1
- cirq/transformers/target_gatesets/sqrt_iswap_gateset_test.py +3 -2
- cirq/transformers/transformer_api.py +5 -4
- cirq/transformers/transformer_api_test.py +11 -3
- cirq/transformers/transformer_primitives.py +9 -31
- cirq/transformers/transformer_primitives_test.py +6 -5
- cirq/value/__init__.py +51 -30
- cirq/value/abc_alt.py +1 -2
- cirq/value/angle.py +2 -0
- cirq/value/classical_data.py +1 -0
- cirq/value/condition.py +149 -3
- cirq/value/condition_test.py +254 -0
- cirq/value/digits.py +1 -1
- cirq/value/duration.py +4 -4
- cirq/value/duration_test.py +2 -1
- cirq/value/linear_dict.py +85 -24
- cirq/value/linear_dict_test.py +94 -3
- cirq/value/measurement_key.py +9 -2
- cirq/value/periodic_value.py +2 -3
- cirq/value/periodic_value_test.py +5 -0
- cirq/value/probability.py +1 -0
- cirq/value/random_state.py +1 -1
- cirq/value/timestamp.py +2 -4
- cirq/value/timestamp_test.py +2 -1
- cirq/value/type_alias.py +2 -2
- cirq/value/value_equality_attr.py +14 -2
- cirq/value/value_equality_attr_test.py +1 -1
- cirq/vis/__init__.py +9 -6
- cirq/vis/density_matrix.py +1 -1
- cirq/vis/density_matrix_test.py +2 -5
- cirq/vis/heatmap.py +49 -12
- cirq/vis/heatmap_test.py +168 -4
- cirq/vis/histogram.py +1 -1
- cirq/vis/histogram_test.py +1 -2
- cirq/vis/state_histogram.py +7 -5
- cirq/vis/state_histogram_test.py +2 -2
- cirq/work/__init__.py +19 -13
- cirq/work/collector.py +2 -2
- cirq/work/observable_grouping.py +2 -2
- cirq/work/observable_measurement.py +3 -3
- cirq/work/observable_measurement_data.py +5 -2
- cirq/work/observable_measurement_test.py +8 -8
- cirq/work/observable_readout_calibration.py +2 -2
- cirq/work/observable_readout_calibration_test.py +2 -1
- cirq/work/observable_settings.py +8 -7
- cirq/work/observable_settings_test.py +3 -2
- cirq/work/pauli_sum_collector.py +1 -1
- cirq/work/sampler.py +8 -20
- cirq/work/sampler_test.py +4 -3
- cirq/work/zeros_sampler.py +1 -1
- cirq_core-1.5.0.dist-info/METADATA +125 -0
- {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/RECORD +586 -552
- {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/WHEEL +1 -1
- cirq/experiments/grid_parallel_two_qubit_xeb.py +0 -62
- cirq/protocols/json_test_data/GridParallelXEBMetadata.json +0 -119
- cirq/protocols/json_test_data/GridParallelXEBMetadata.repr +0 -1
- cirq_core-1.4.0.dev20240529225110.dist-info/METADATA +0 -50
- {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/LICENSE +0 -0
- {cirq_core-1.4.0.dev20240529225110.dist-info → cirq_core-1.5.0.dist-info}/top_level.txt +0 -0
|
@@ -15,72 +15,191 @@
|
|
|
15
15
|
"""Transformer pass that adds dynamical decoupling operations to a circuit."""
|
|
16
16
|
|
|
17
17
|
from functools import reduce
|
|
18
|
-
from
|
|
18
|
+
from itertools import cycle
|
|
19
|
+
from typing import Dict, Optional, Tuple, TYPE_CHECKING, Union
|
|
19
20
|
|
|
20
|
-
from cirq.transformers import transformer_api
|
|
21
|
-
import cirq
|
|
22
21
|
import numpy as np
|
|
23
22
|
|
|
23
|
+
from cirq import circuits, ops, protocols
|
|
24
|
+
from cirq.protocols import unitary_protocol
|
|
25
|
+
from cirq.protocols.has_stabilizer_effect_protocol import has_stabilizer_effect
|
|
26
|
+
from cirq.protocols.has_unitary_protocol import has_unitary
|
|
27
|
+
from cirq.transformers import transformer_api
|
|
28
|
+
from cirq.transformers.analytical_decompositions import single_qubit_decompositions
|
|
24
29
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
) -> Sequence['cirq.Gate']:
|
|
28
|
-
"""Returns the longest possible dynamical decoupling sequence."""
|
|
29
|
-
repeat_times = num_idle_moments // len(base_sequence)
|
|
30
|
-
return list(base_sequence) * repeat_times
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
import cirq
|
|
31
32
|
|
|
32
33
|
|
|
33
|
-
def _get_dd_sequence_from_schema_name(schema: str) ->
|
|
34
|
+
def _get_dd_sequence_from_schema_name(schema: str) -> Tuple[ops.Gate, ...]:
|
|
34
35
|
"""Gets dynamical decoupling sequence from a schema name."""
|
|
35
|
-
dd_sequence: Sequence['cirq.Gate']
|
|
36
36
|
match schema:
|
|
37
|
+
case 'DEFAULT':
|
|
38
|
+
return (ops.X, ops.Y, ops.X, ops.Y)
|
|
37
39
|
case 'XX_PAIR':
|
|
38
|
-
|
|
40
|
+
return (ops.X, ops.X)
|
|
39
41
|
case 'X_XINV':
|
|
40
|
-
|
|
42
|
+
return (ops.X, ops.X**-1)
|
|
41
43
|
case 'YY_PAIR':
|
|
42
|
-
|
|
44
|
+
return (ops.Y, ops.Y)
|
|
43
45
|
case 'Y_YINV':
|
|
44
|
-
|
|
46
|
+
return (ops.Y, ops.Y**-1)
|
|
45
47
|
case _:
|
|
46
48
|
raise ValueError('Invalid schema name.')
|
|
47
|
-
return dd_sequence
|
|
48
49
|
|
|
49
50
|
|
|
50
|
-
def
|
|
51
|
+
def _pauli_up_to_global_phase(gate: ops.Gate) -> Union[ops.Pauli, None]:
|
|
52
|
+
for pauli_gate in [ops.X, ops.Y, ops.Z]:
|
|
53
|
+
if protocols.equal_up_to_global_phase(gate, pauli_gate):
|
|
54
|
+
return pauli_gate
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _validate_dd_sequence(dd_sequence: Tuple[ops.Gate, ...]) -> None:
|
|
51
59
|
"""Validates a given dynamical decoupling sequence.
|
|
52
60
|
|
|
61
|
+
The sequence should only consists of Pauli gates and is essentially an identity gate.
|
|
62
|
+
|
|
53
63
|
Args:
|
|
54
64
|
dd_sequence: Input dynamical sequence to be validated.
|
|
55
65
|
|
|
56
|
-
Returns:
|
|
57
|
-
A tuple containing:
|
|
58
|
-
- is_valid (bool): True if the dd sequence is valid, False otherwise.
|
|
59
|
-
- error_message (str): An error message if the dd sequence is invalid, else None.
|
|
60
|
-
|
|
61
66
|
Raises:
|
|
62
67
|
ValueError: If dd_sequence is not valid.
|
|
63
68
|
"""
|
|
64
69
|
if len(dd_sequence) < 2:
|
|
65
70
|
raise ValueError('Invalid dynamical decoupling sequence. Expect more than one gates.')
|
|
66
|
-
|
|
71
|
+
for gate in dd_sequence:
|
|
72
|
+
if _pauli_up_to_global_phase(gate) is None:
|
|
73
|
+
raise ValueError(
|
|
74
|
+
'Dynamical decoupling sequence should only contain gates that are essentially'
|
|
75
|
+
' Pauli gates.'
|
|
76
|
+
)
|
|
77
|
+
matrices = [unitary_protocol.unitary(gate) for gate in dd_sequence]
|
|
67
78
|
product = reduce(np.matmul, matrices)
|
|
68
79
|
|
|
69
|
-
if not
|
|
80
|
+
if not protocols.equal_up_to_global_phase(product, np.eye(2)):
|
|
70
81
|
raise ValueError(
|
|
71
82
|
'Invalid dynamical decoupling sequence. Expect sequence production equals'
|
|
72
83
|
f' identity up to a global phase, got {product}.'.replace('\n', ' ')
|
|
73
84
|
)
|
|
74
85
|
|
|
75
86
|
|
|
76
|
-
def _parse_dd_sequence(
|
|
77
|
-
|
|
87
|
+
def _parse_dd_sequence(
|
|
88
|
+
schema: Union[str, Tuple[ops.Gate, ...]],
|
|
89
|
+
) -> Tuple[Tuple[ops.Gate, ...], Dict[ops.Gate, ops.Pauli]]:
|
|
90
|
+
"""Parses and returns dynamical decoupling sequence and its associated pauli map from schema."""
|
|
91
|
+
dd_sequence = None
|
|
78
92
|
if isinstance(schema, str):
|
|
79
93
|
dd_sequence = _get_dd_sequence_from_schema_name(schema)
|
|
80
94
|
else:
|
|
81
95
|
_validate_dd_sequence(schema)
|
|
82
96
|
dd_sequence = schema
|
|
83
|
-
|
|
97
|
+
|
|
98
|
+
# Map gate to Pauli gate. This is necessary as dd sequence might contain gates like X^-1.
|
|
99
|
+
pauli_map: Dict[ops.Gate, ops.Pauli] = {}
|
|
100
|
+
for gate in dd_sequence:
|
|
101
|
+
pauli_gate = _pauli_up_to_global_phase(gate)
|
|
102
|
+
if pauli_gate is not None:
|
|
103
|
+
pauli_map[gate] = pauli_gate
|
|
104
|
+
for gate in [ops.X, ops.Y, ops.Z]:
|
|
105
|
+
pauli_map[gate] = gate
|
|
106
|
+
|
|
107
|
+
return (dd_sequence, pauli_map)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _is_single_qubit_operation(operation: ops.Operation) -> bool:
|
|
111
|
+
return len(operation.qubits) == 1
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _is_single_qubit_gate_moment(moment: circuits.Moment) -> bool:
|
|
115
|
+
return all(_is_single_qubit_operation(op) for op in moment)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _is_clifford_op(op: ops.Operation) -> bool:
|
|
119
|
+
return has_unitary(op) and has_stabilizer_effect(op)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _calc_busy_moment_range_of_each_qubit(
|
|
123
|
+
circuit: circuits.FrozenCircuit,
|
|
124
|
+
) -> Dict[ops.Qid, list[int]]:
|
|
125
|
+
busy_moment_range_by_qubit: Dict[ops.Qid, list[int]] = {
|
|
126
|
+
q: [len(circuit), -1] for q in circuit.all_qubits()
|
|
127
|
+
}
|
|
128
|
+
for moment_id, moment in enumerate(circuit):
|
|
129
|
+
for q in moment.qubits:
|
|
130
|
+
busy_moment_range_by_qubit[q][0] = min(busy_moment_range_by_qubit[q][0], moment_id)
|
|
131
|
+
busy_moment_range_by_qubit[q][1] = max(busy_moment_range_by_qubit[q][1], moment_id)
|
|
132
|
+
return busy_moment_range_by_qubit
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _is_insertable_moment(moment: circuits.Moment, single_qubit_gate_moments_only: bool) -> bool:
|
|
136
|
+
return not single_qubit_gate_moments_only or _is_single_qubit_gate_moment(moment)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _merge_single_qubit_ops_to_phxz(
|
|
140
|
+
q: ops.Qid, operations: Tuple[ops.Operation, ...]
|
|
141
|
+
) -> ops.Operation:
|
|
142
|
+
"""Merges [op1, op2, ...] and returns an equivalent op"""
|
|
143
|
+
if len(operations) == 1:
|
|
144
|
+
return operations[0]
|
|
145
|
+
matrices = [unitary_protocol.unitary(op) for op in reversed(operations)]
|
|
146
|
+
product = reduce(np.matmul, matrices)
|
|
147
|
+
gate = single_qubit_decompositions.single_qubit_matrix_to_phxz(product) or ops.I
|
|
148
|
+
return gate.on(q)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _try_merge_single_qubit_ops_of_two_moments(
|
|
152
|
+
m1: circuits.Moment, m2: circuits.Moment
|
|
153
|
+
) -> Tuple[circuits.Moment, ...]:
|
|
154
|
+
"""Merge single qubit ops of 2 moments if possible, returns 2 moments otherwise."""
|
|
155
|
+
for q in m1.qubits & m2.qubits:
|
|
156
|
+
op1 = m1.operation_at(q)
|
|
157
|
+
op2 = m2.operation_at(q)
|
|
158
|
+
if any(
|
|
159
|
+
not (_is_single_qubit_operation(op) and has_unitary(op))
|
|
160
|
+
for op in [op1, op2]
|
|
161
|
+
if op is not None
|
|
162
|
+
):
|
|
163
|
+
return (m1, m2)
|
|
164
|
+
merged_ops: set[ops.Operation] = set()
|
|
165
|
+
# Merge all operators on q to a single op.
|
|
166
|
+
for q in m1.qubits | m2.qubits:
|
|
167
|
+
# ops_on_q may contain 1 op or 2 ops.
|
|
168
|
+
ops_on_q = [op for op in [m.operation_at(q) for m in [m1, m2]] if op is not None]
|
|
169
|
+
merged_ops.add(_merge_single_qubit_ops_to_phxz(q, tuple(ops_on_q)))
|
|
170
|
+
return (circuits.Moment(merged_ops),)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _calc_pulled_through(
|
|
174
|
+
moment: circuits.Moment, input_pauli_ops: ops.PauliString
|
|
175
|
+
) -> ops.PauliString:
|
|
176
|
+
"""Calculates the pulled_through such that circuit(input_pauli_ops, moment.clifford_ops) is
|
|
177
|
+
equivalent to circuit(moment.clifford_ops, pulled_through).
|
|
178
|
+
"""
|
|
179
|
+
clifford_ops_in_moment: list[ops.Operation] = [
|
|
180
|
+
op for op in moment.operations if _is_clifford_op(op)
|
|
181
|
+
]
|
|
182
|
+
return input_pauli_ops.after(clifford_ops_in_moment)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _get_stop_qubits(moment: circuits.Moment) -> set[ops.Qid]:
|
|
186
|
+
stop_pulling_through_qubits: set[ops.Qid] = set()
|
|
187
|
+
for op in moment:
|
|
188
|
+
if (not _is_clifford_op(op) and not _is_single_qubit_operation(op)) or not has_unitary(
|
|
189
|
+
op
|
|
190
|
+
): # multi-qubit clifford op or non-mergable op.
|
|
191
|
+
stop_pulling_through_qubits.update(op.qubits)
|
|
192
|
+
return stop_pulling_through_qubits
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _need_merge_pulled_through(op_at_q: ops.Operation, is_at_last_busy_moment: bool) -> bool:
|
|
196
|
+
"""With a pulling through pauli gate before op_at_q, need to merge with the
|
|
197
|
+
pauli in the conditions below."""
|
|
198
|
+
# The op must be mergable and single-qubit
|
|
199
|
+
if not (_is_single_qubit_operation(op_at_q) and has_unitary(op_at_q)):
|
|
200
|
+
return False
|
|
201
|
+
# Either non-Clifford or at the last busy moment
|
|
202
|
+
return is_at_last_busy_moment or not _is_clifford_op(op_at_q)
|
|
84
203
|
|
|
85
204
|
|
|
86
205
|
@transformer_api.transformer
|
|
@@ -88,10 +207,11 @@ def add_dynamical_decoupling(
|
|
|
88
207
|
circuit: 'cirq.AbstractCircuit',
|
|
89
208
|
*,
|
|
90
209
|
context: Optional['cirq.TransformerContext'] = None,
|
|
91
|
-
schema: Union[str,
|
|
210
|
+
schema: Union[str, Tuple[ops.Gate, ...]] = 'DEFAULT',
|
|
211
|
+
single_qubit_gate_moments_only: bool = True,
|
|
92
212
|
) -> 'cirq.Circuit':
|
|
93
|
-
"""Adds dynamical decoupling gate operations to
|
|
94
|
-
This transformer
|
|
213
|
+
"""Adds dynamical decoupling gate operations to a given circuit.
|
|
214
|
+
This transformer might add new moments thus change structure of the original circuit.
|
|
95
215
|
|
|
96
216
|
Args:
|
|
97
217
|
circuit: Input circuit to transform.
|
|
@@ -99,24 +219,116 @@ def add_dynamical_decoupling(
|
|
|
99
219
|
schema: Dynamical decoupling schema name or a dynamical decoupling sequence.
|
|
100
220
|
If a schema is specified, provided dynamical decouping sequence will be used.
|
|
101
221
|
Otherwise, customized dynamical decoupling sequence will be applied.
|
|
222
|
+
single_qubit_gate_moments_only: If set True, dynamical decoupling operation will only be
|
|
223
|
+
added in single-qubit gate moments.
|
|
102
224
|
|
|
103
225
|
Returns:
|
|
104
226
|
A copy of the input circuit with dynamical decoupling operations.
|
|
105
227
|
"""
|
|
106
|
-
|
|
107
|
-
|
|
228
|
+
base_dd_sequence, pauli_map = _parse_dd_sequence(schema)
|
|
229
|
+
orig_circuit = circuit.freeze()
|
|
108
230
|
|
|
109
|
-
|
|
231
|
+
busy_moment_range_by_qubit = _calc_busy_moment_range_of_each_qubit(orig_circuit)
|
|
110
232
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
233
|
+
# Stores all the moments of the output circuit chronologically.
|
|
234
|
+
transformed_moments: list[circuits.Moment] = []
|
|
235
|
+
# A PauliString stores the result of 'pulling' Pauli gates past each operations
|
|
236
|
+
# right before the current moment.
|
|
237
|
+
pulled_through: ops.PauliString = ops.PauliString()
|
|
238
|
+
# Iterator of gate to be used in dd sequence for each qubit.
|
|
239
|
+
dd_iter_by_qubits = {q: cycle(base_dd_sequence) for q in circuit.all_qubits()}
|
|
240
|
+
|
|
241
|
+
def _update_pulled_through(q: ops.Qid, insert_gate: ops.Gate) -> ops.Operation:
|
|
242
|
+
nonlocal pulled_through, pauli_map
|
|
243
|
+
pulled_through *= pauli_map[insert_gate].on(q)
|
|
244
|
+
return insert_gate.on(q)
|
|
245
|
+
|
|
246
|
+
# Insert and pull remaining Pauli ops through the whole circuit.
|
|
247
|
+
# General ideas are
|
|
248
|
+
# * Pull through Clifford gates.
|
|
249
|
+
# * Stop at multi-qubit non-Clifford ops (and other non-mergable ops).
|
|
250
|
+
# * Merge to single-qubit non-Clifford ops.
|
|
251
|
+
# * Insert a new moment if necessary.
|
|
252
|
+
# After pulling through pulled_through at `moment`, we expect a transformation of
|
|
253
|
+
# (pulled_through, moment) -> (updated_moment, updated_pulled_through) or
|
|
254
|
+
# (pulled_through, moment) -> (new_moment, updated_moment, updated_pulled_through)
|
|
255
|
+
# Moments structure changes are split into 3 steps:
|
|
256
|
+
# 1, (..., last_moment, pulled_through1, moment, ...)
|
|
257
|
+
# -> (..., try_merge(last_moment, new_moment or None), pulled_through2, moment, ...)
|
|
258
|
+
# 2, (..., pulled_through2, moment, ...) -> (..., pulled_through3, updated_moment, ...)
|
|
259
|
+
# 3, (..., pulled_through3, updated_moment, ...)
|
|
260
|
+
# -> (..., updated_moment, pulled_through4, ...)
|
|
261
|
+
for moment_id, moment in enumerate(orig_circuit.moments):
|
|
262
|
+
# Step 1, insert new_moment if necessary.
|
|
263
|
+
# In detail: stop pulling through for multi-qubit non-Clifford ops or gates without
|
|
264
|
+
# unitary representation (e.g., measure gates). If there are remaining pulled through ops,
|
|
265
|
+
# insert into a new moment before current moment.
|
|
266
|
+
stop_pulling_through_qubits: set[ops.Qid] = _get_stop_qubits(moment)
|
|
267
|
+
new_moment_ops = []
|
|
268
|
+
for q in stop_pulling_through_qubits:
|
|
269
|
+
# Insert the remaining pulled_through
|
|
270
|
+
remaining_pulled_through_gate = pulled_through.get(q)
|
|
271
|
+
if remaining_pulled_through_gate is not None:
|
|
272
|
+
new_moment_ops.append(_update_pulled_through(q, remaining_pulled_through_gate))
|
|
273
|
+
# Reset dd sequence
|
|
274
|
+
dd_iter_by_qubits[q] = cycle(base_dd_sequence)
|
|
275
|
+
# Need to insert a new moment before current moment
|
|
276
|
+
if new_moment_ops:
|
|
277
|
+
# Fill insertable idle moments in the new moment using dd sequence
|
|
278
|
+
for q in orig_circuit.all_qubits() - stop_pulling_through_qubits:
|
|
279
|
+
if busy_moment_range_by_qubit[q][0] < moment_id <= busy_moment_range_by_qubit[q][1]:
|
|
280
|
+
new_moment_ops.append(_update_pulled_through(q, next(dd_iter_by_qubits[q])))
|
|
281
|
+
moments_to_be_appended = _try_merge_single_qubit_ops_of_two_moments(
|
|
282
|
+
transformed_moments.pop(), circuits.Moment(new_moment_ops)
|
|
115
283
|
)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
284
|
+
transformed_moments.extend(moments_to_be_appended)
|
|
285
|
+
|
|
286
|
+
# Step 2, calc updated_moment with insertions / merges.
|
|
287
|
+
updated_moment_ops: set['cirq.Operation'] = set()
|
|
288
|
+
for q in orig_circuit.all_qubits():
|
|
289
|
+
op_at_q = moment.operation_at(q)
|
|
290
|
+
remaining_pulled_through_gate = pulled_through.get(q)
|
|
291
|
+
updated_op = op_at_q
|
|
292
|
+
if op_at_q is None: # insert into idle op
|
|
293
|
+
if not _is_insertable_moment(moment, single_qubit_gate_moments_only):
|
|
294
|
+
continue
|
|
295
|
+
if (
|
|
296
|
+
busy_moment_range_by_qubit[q][0] < moment_id < busy_moment_range_by_qubit[q][1]
|
|
297
|
+
): # insert next pauli gate in the dd sequence
|
|
298
|
+
updated_op = _update_pulled_through(q, next(dd_iter_by_qubits[q]))
|
|
299
|
+
elif ( # insert the remaining pulled through if beyond the ending busy moment
|
|
300
|
+
moment_id > busy_moment_range_by_qubit[q][1]
|
|
301
|
+
and remaining_pulled_through_gate is not None
|
|
302
|
+
):
|
|
303
|
+
updated_op = _update_pulled_through(q, remaining_pulled_through_gate)
|
|
304
|
+
elif (
|
|
305
|
+
remaining_pulled_through_gate is not None
|
|
306
|
+
): # merge pulled-through of q to op_at_q if needed
|
|
307
|
+
if _need_merge_pulled_through(
|
|
308
|
+
op_at_q, moment_id == busy_moment_range_by_qubit[q][1]
|
|
309
|
+
):
|
|
310
|
+
remaining_op = _update_pulled_through(q, remaining_pulled_through_gate)
|
|
311
|
+
updated_op = _merge_single_qubit_ops_to_phxz(q, (remaining_op, op_at_q))
|
|
312
|
+
if updated_op is not None:
|
|
313
|
+
updated_moment_ops.add(updated_op)
|
|
314
|
+
|
|
315
|
+
if updated_moment_ops:
|
|
316
|
+
updated_moment = circuits.Moment(updated_moment_ops)
|
|
317
|
+
transformed_moments.append(updated_moment)
|
|
318
|
+
|
|
319
|
+
# Step 3, update pulled through.
|
|
320
|
+
# In detail: pulling current `pulled_through` through updated_moment.
|
|
321
|
+
pulled_through = _calc_pulled_through(updated_moment, pulled_through)
|
|
322
|
+
|
|
323
|
+
# Insert a new moment if there are remaining pulled-through operations.
|
|
324
|
+
ending_moment_ops = []
|
|
325
|
+
for affected_q, combined_op_in_pauli in pulled_through.items():
|
|
326
|
+
ending_moment_ops.append(combined_op_in_pauli.on(affected_q))
|
|
327
|
+
if ending_moment_ops:
|
|
328
|
+
transformed_moments.extend(
|
|
329
|
+
_try_merge_single_qubit_ops_of_two_moments(
|
|
330
|
+
transformed_moments.pop(), circuits.Moment(ending_moment_ops)
|
|
331
|
+
)
|
|
332
|
+
)
|
|
119
333
|
|
|
120
|
-
|
|
121
|
-
updated_circuit.batch_insert_into(insert_into)
|
|
122
|
-
return updated_circuit
|
|
334
|
+
return circuits.Circuit(transformed_moments)
|