cirq-core 1.4.1__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 +1 -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.1.dist-info → cirq_core-1.5.0.dist-info}/RECORD +586 -552
- {cirq_core-1.4.1.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.1.dist-info/METADATA +0 -45
- {cirq_core-1.4.1.dist-info → cirq_core-1.5.0.dist-info}/LICENSE +0 -0
- {cirq_core-1.4.1.dist-info → cirq_core-1.5.0.dist-info}/top_level.txt +0 -0
|
@@ -17,14 +17,14 @@ import pytest
|
|
|
17
17
|
|
|
18
18
|
import cirq
|
|
19
19
|
from cirq import value
|
|
20
|
+
from cirq.testing import assert_equivalent_repr, random_special_unitary
|
|
21
|
+
from cirq.transformers.heuristic_decompositions.gate_tabulation_math_utils import (
|
|
22
|
+
unitary_entanglement_fidelity,
|
|
23
|
+
)
|
|
20
24
|
from cirq.transformers.heuristic_decompositions.two_qubit_gate_tabulation import (
|
|
21
25
|
two_qubit_gate_product_tabulation,
|
|
22
26
|
TwoQubitGateTabulation,
|
|
23
27
|
)
|
|
24
|
-
from cirq.transformers.heuristic_decompositions.gate_tabulation_math_utils import (
|
|
25
|
-
unitary_entanglement_fidelity,
|
|
26
|
-
)
|
|
27
|
-
from cirq.testing import random_special_unitary, assert_equivalent_repr
|
|
28
28
|
|
|
29
29
|
_rng = value.parse_random_state(11) # for determinism
|
|
30
30
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Copyright 2024 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
|
+
"""Transformer that sorts commuting operations in increasing order of their `.qubits` tuple."""
|
|
16
|
+
|
|
17
|
+
from typing import Dict, List, Optional, TYPE_CHECKING
|
|
18
|
+
|
|
19
|
+
from cirq import circuits, protocols
|
|
20
|
+
from cirq.transformers import transformer_api
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
import cirq
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@transformer_api.transformer(add_deep_support=True)
|
|
27
|
+
def insertion_sort_transformer(
|
|
28
|
+
circuit: 'cirq.AbstractCircuit', *, context: Optional['cirq.TransformerContext'] = None
|
|
29
|
+
) -> 'cirq.Circuit':
|
|
30
|
+
"""Sorts the operations using their sorted `.qubits` property as comparison key.
|
|
31
|
+
|
|
32
|
+
Operations are swapped only if they commute.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
circuit: input circuit.
|
|
36
|
+
context: optional TransformerContext (not used),
|
|
37
|
+
"""
|
|
38
|
+
final_operations: List['cirq.Operation'] = []
|
|
39
|
+
qubit_index: Dict['cirq.Qid', int] = {
|
|
40
|
+
q: idx for idx, q in enumerate(sorted(circuit.all_qubits()))
|
|
41
|
+
}
|
|
42
|
+
cached_qubit_indices: Dict[int, List[int]] = {}
|
|
43
|
+
for pos, op in enumerate(circuit.all_operations()):
|
|
44
|
+
# here `pos` is at the append position of final_operations
|
|
45
|
+
if (op_qubit_indices := cached_qubit_indices.get(id(op))) is None:
|
|
46
|
+
op_qubit_indices = cached_qubit_indices[id(op)] = sorted(
|
|
47
|
+
qubit_index[q] for q in op.qubits
|
|
48
|
+
)
|
|
49
|
+
for tail_op in reversed(final_operations):
|
|
50
|
+
tail_qubit_indices = cached_qubit_indices[id(tail_op)]
|
|
51
|
+
if op_qubit_indices < tail_qubit_indices and (
|
|
52
|
+
# special case for zero-qubit gates
|
|
53
|
+
not op_qubit_indices
|
|
54
|
+
# check if two sorted sequences are disjoint
|
|
55
|
+
or op_qubit_indices[-1] < tail_qubit_indices[0]
|
|
56
|
+
or set(op_qubit_indices).isdisjoint(tail_qubit_indices)
|
|
57
|
+
# fallback to more expensive commutation check
|
|
58
|
+
or protocols.commutes(op, tail_op, default=False)
|
|
59
|
+
):
|
|
60
|
+
pos -= 1
|
|
61
|
+
continue
|
|
62
|
+
break
|
|
63
|
+
final_operations.insert(pos, op)
|
|
64
|
+
return circuits.Circuit(final_operations)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Copyright 2024 The Cirq Developers
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import cirq
|
|
16
|
+
import cirq.transformers
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_insertion_sort():
|
|
20
|
+
c = cirq.Circuit(
|
|
21
|
+
cirq.CZ(cirq.q(2), cirq.q(1)),
|
|
22
|
+
cirq.CZ(cirq.q(2), cirq.q(4)),
|
|
23
|
+
cirq.CZ(cirq.q(0), cirq.q(1)),
|
|
24
|
+
cirq.CZ(cirq.q(2), cirq.q(1)),
|
|
25
|
+
cirq.GlobalPhaseGate(1j).on(),
|
|
26
|
+
)
|
|
27
|
+
sorted_circuit = cirq.transformers.insertion_sort_transformer(c)
|
|
28
|
+
assert sorted_circuit == cirq.Circuit(
|
|
29
|
+
cirq.GlobalPhaseGate(1j).on(),
|
|
30
|
+
cirq.CZ(cirq.q(0), cirq.q(1)),
|
|
31
|
+
cirq.CZ(cirq.q(2), cirq.q(1)),
|
|
32
|
+
cirq.CZ(cirq.q(2), cirq.q(1)),
|
|
33
|
+
cirq.CZ(cirq.q(2), cirq.q(4)),
|
|
34
|
+
)
|
|
@@ -292,7 +292,20 @@ def drop_terminal_measurements(
|
|
|
292
292
|
def flip_inversion(op: 'cirq.Operation', _) -> 'cirq.OP_TREE':
|
|
293
293
|
if isinstance(op.gate, ops.MeasurementGate):
|
|
294
294
|
return [
|
|
295
|
-
|
|
295
|
+
(
|
|
296
|
+
(ops.X if b else ops.I)
|
|
297
|
+
if q.dimension == 2
|
|
298
|
+
else (
|
|
299
|
+
ops.MatrixGate(
|
|
300
|
+
# Per SimulationState.measure(), swap 0,1 but leave other dims alone
|
|
301
|
+
np.eye(q.dimension)[[1, 0, *range(2, q.dimension)]],
|
|
302
|
+
qid_shape=(q.dimension,),
|
|
303
|
+
)
|
|
304
|
+
if b
|
|
305
|
+
else ops.IdentityGate(qid_shape=(q.dimension,))
|
|
306
|
+
)
|
|
307
|
+
).on(q)
|
|
308
|
+
for q, b in zip(op.qubits, op.gate.full_invert_mask())
|
|
296
309
|
]
|
|
297
310
|
return op
|
|
298
311
|
|
|
@@ -759,6 +759,41 @@ def test_drop_terminal():
|
|
|
759
759
|
)
|
|
760
760
|
|
|
761
761
|
|
|
762
|
+
def test_drop_terminal_qudit():
|
|
763
|
+
q0, q1 = cirq.LineQid.range(2, dimension=3)
|
|
764
|
+
circuit = cirq.Circuit(
|
|
765
|
+
cirq.CircuitOperation(cirq.FrozenCircuit(cirq.measure(q0, q1, key='m', invert_mask=[0, 1])))
|
|
766
|
+
)
|
|
767
|
+
dropped = cirq.drop_terminal_measurements(circuit)
|
|
768
|
+
expected_inversion_matrix = np.array([[0, 1, 0], [1, 0, 0], [0, 0, 1]])
|
|
769
|
+
cirq.testing.assert_same_circuits(
|
|
770
|
+
dropped,
|
|
771
|
+
cirq.Circuit(
|
|
772
|
+
cirq.CircuitOperation(
|
|
773
|
+
cirq.FrozenCircuit(
|
|
774
|
+
cirq.IdentityGate(qid_shape=(3,)).on(q0),
|
|
775
|
+
cirq.MatrixGate(expected_inversion_matrix, qid_shape=(3,)).on(q1),
|
|
776
|
+
)
|
|
777
|
+
)
|
|
778
|
+
),
|
|
779
|
+
)
|
|
780
|
+
# Verify behavior equivalent to simulator (invert_mask swaps 0,1 but leaves 2 alone)
|
|
781
|
+
dropped.append(cirq.measure(q0, q1, key='m'))
|
|
782
|
+
sim = cirq.Simulator()
|
|
783
|
+
c0 = sim.simulate(circuit, initial_state=[0, 0])
|
|
784
|
+
d0 = sim.simulate(dropped, initial_state=[0, 0])
|
|
785
|
+
assert np.all(c0.measurements['m'] == [0, 1])
|
|
786
|
+
assert np.all(d0.measurements['m'] == [0, 1])
|
|
787
|
+
c1 = sim.simulate(circuit, initial_state=[1, 1])
|
|
788
|
+
d1 = sim.simulate(dropped, initial_state=[1, 1])
|
|
789
|
+
assert np.all(c1.measurements['m'] == [1, 0])
|
|
790
|
+
assert np.all(d1.measurements['m'] == [1, 0])
|
|
791
|
+
c2 = sim.simulate(circuit, initial_state=[2, 2])
|
|
792
|
+
d2 = sim.simulate(dropped, initial_state=[2, 2])
|
|
793
|
+
assert np.all(c2.measurements['m'] == [2, 2])
|
|
794
|
+
assert np.all(d2.measurements['m'] == [2, 2])
|
|
795
|
+
|
|
796
|
+
|
|
762
797
|
def test_drop_terminal_nonterminal_error():
|
|
763
798
|
q0, q1 = cirq.LineQubit.range(2)
|
|
764
799
|
circuit = cirq.Circuit(
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformer pass to merge connected components of k-qubit unitary operations."""
|
|
16
16
|
|
|
17
|
-
from typing import cast, Optional,
|
|
17
|
+
from typing import Callable, cast, Optional, TYPE_CHECKING
|
|
18
18
|
|
|
19
|
-
from cirq import ops, protocols
|
|
19
|
+
from cirq import circuits, ops, protocols
|
|
20
20
|
from cirq.transformers import transformer_api, transformer_primitives
|
|
21
21
|
|
|
22
22
|
if TYPE_CHECKING:
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
from typing import Optional, TYPE_CHECKING
|
|
18
18
|
|
|
19
19
|
from cirq import circuits, ops, protocols
|
|
20
|
+
from cirq.transformers import merge_k_qubit_gates, transformer_api, transformer_primitives
|
|
20
21
|
from cirq.transformers.analytical_decompositions import single_qubit_decompositions
|
|
21
|
-
from cirq.transformers import transformer_api, transformer_primitives, merge_k_qubit_gates
|
|
22
22
|
|
|
23
23
|
if TYPE_CHECKING:
|
|
24
24
|
import cirq
|
|
@@ -45,7 +45,7 @@ def test_merge_single_qubit_gates_to_phased_x_and_z():
|
|
|
45
45
|
optimized=cirq.merge_single_qubit_gates_to_phased_x_and_z(c),
|
|
46
46
|
expected=cirq.Circuit(
|
|
47
47
|
cirq.PhasedXPowGate(phase_exponent=1)(a),
|
|
48
|
-
cirq.
|
|
48
|
+
cirq.PhasedXPowGate(phase_exponent=0.5)(b) ** 0.5,
|
|
49
49
|
cirq.CZ(a, b),
|
|
50
50
|
(cirq.PhasedXPowGate(phase_exponent=-0.5)(a)) ** 0.5,
|
|
51
51
|
cirq.measure(b, key="m"),
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Copyright 2024 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 collections.abc import Mapping
|
|
16
|
+
from typing import cast
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
from cirq import circuits, ops
|
|
21
|
+
from cirq.transformers import transformer_api
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _gate_in_moment(gate: ops.Gate, moment: circuits.Moment) -> bool:
|
|
25
|
+
"""Check whether `gate` is in `moment`."""
|
|
26
|
+
return any(op.gate == gate for op in moment)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@transformer_api.transformer
|
|
30
|
+
class DepolarizingNoiseTransformer:
|
|
31
|
+
"""Add local depolarizing noise after two-qubit gates in a specified circuit. More specifically,
|
|
32
|
+
with probability p, append a random non-identity two-qubit Pauli operator after each specified
|
|
33
|
+
two-qubit gate.
|
|
34
|
+
|
|
35
|
+
Attrs:
|
|
36
|
+
p: The probability with which to add noise.
|
|
37
|
+
target_gate: Add depolarizing nose after this type of gate
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self, p: float | Mapping[tuple[ops.Qid, ops.Qid], float], target_gate: ops.Gate = ops.CZ
|
|
42
|
+
):
|
|
43
|
+
"""Initialize the depolarizing noise transformer with some depolarizing probability and
|
|
44
|
+
target gate.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
p: The depolarizing probability, either a single float or a mapping from pairs of qubits
|
|
48
|
+
to floats.
|
|
49
|
+
target_gate: The gate after which to add depolarizing noise.
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
TypeError: If `p` is not either be a float or a mapping from sorted qubit pairs to
|
|
53
|
+
floats.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
if not isinstance(p, (Mapping, float)):
|
|
57
|
+
raise TypeError( # pragma: no cover
|
|
58
|
+
"p must either be a float or a mapping from" # pragma: no cover
|
|
59
|
+
+ "sorted qubit pairs to floats" # pragma: no cover
|
|
60
|
+
) # pragma: no cover
|
|
61
|
+
self.p = p
|
|
62
|
+
self.p_func = (
|
|
63
|
+
(lambda _: p)
|
|
64
|
+
if isinstance(p, (int, float))
|
|
65
|
+
else (lambda pair: cast(Mapping, p).get(pair, 0.0))
|
|
66
|
+
)
|
|
67
|
+
self.target_gate = target_gate
|
|
68
|
+
|
|
69
|
+
def __call__(
|
|
70
|
+
self,
|
|
71
|
+
circuit: circuits.AbstractCircuit,
|
|
72
|
+
rng: np.random.Generator | None = None,
|
|
73
|
+
*,
|
|
74
|
+
context: transformer_api.TransformerContext | None = None,
|
|
75
|
+
):
|
|
76
|
+
"""Apply the transformer to the given circuit.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
circuit: The circuit to add noise to.
|
|
80
|
+
context: Not used; to satisfy transformer API.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
The transformed circuit.
|
|
84
|
+
"""
|
|
85
|
+
if rng is None:
|
|
86
|
+
rng = np.random.default_rng()
|
|
87
|
+
target_gate = self.target_gate
|
|
88
|
+
|
|
89
|
+
# add random Pauli gates with probability p after each of the specified gate
|
|
90
|
+
assert target_gate.num_qubits() == 2, "`target_gate` must be a two-qubit gate."
|
|
91
|
+
paulis = [ops.I, ops.X, ops.Y, ops.Z]
|
|
92
|
+
new_moments = []
|
|
93
|
+
for moment in circuit:
|
|
94
|
+
new_moments.append(moment)
|
|
95
|
+
if _gate_in_moment(target_gate, moment):
|
|
96
|
+
# add a new moment with the Paulis
|
|
97
|
+
target_pairs = {
|
|
98
|
+
tuple(sorted(op.qubits)) for op in moment.operations if op.gate == target_gate
|
|
99
|
+
}
|
|
100
|
+
added_moment_ops = []
|
|
101
|
+
for pair in target_pairs:
|
|
102
|
+
pair_sorted_tuple = (pair[0], pair[1])
|
|
103
|
+
p_i = self.p_func(pair_sorted_tuple)
|
|
104
|
+
apply = rng.choice([True, False], p=[p_i, 1 - p_i])
|
|
105
|
+
if apply:
|
|
106
|
+
choices = [
|
|
107
|
+
(pauli_a(pair[0]), pauli_b(pair[1]))
|
|
108
|
+
for pauli_a in paulis
|
|
109
|
+
for pauli_b in paulis
|
|
110
|
+
][1:]
|
|
111
|
+
pauli_to_apply = rng.choice(np.array(choices, dtype=object))
|
|
112
|
+
added_moment_ops.append(pauli_to_apply)
|
|
113
|
+
if len(added_moment_ops) > 0:
|
|
114
|
+
new_moments.append(circuits.Moment(*added_moment_ops))
|
|
115
|
+
return circuits.Circuit.from_moments(*new_moments)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Copyright 2024 The Cirq Developers
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
import cirq.transformers.noise_adding as na
|
|
18
|
+
from cirq import circuits, devices, ops
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_noise_adding():
|
|
22
|
+
qubits = devices.LineQubit.range(4)
|
|
23
|
+
one_layer = circuits.Circuit(ops.CZ(*qubits[:2]), ops.CZ(*qubits[2:]))
|
|
24
|
+
circuit = one_layer * 10
|
|
25
|
+
|
|
26
|
+
# test that p=0 does nothing
|
|
27
|
+
transformed_circuit_p0 = na.DepolarizingNoiseTransformer(0.0)(circuit)
|
|
28
|
+
assert transformed_circuit_p0 == circuit
|
|
29
|
+
|
|
30
|
+
# test that p=1 doubles the circuit depth
|
|
31
|
+
transformed_circuit_p1 = na.DepolarizingNoiseTransformer(1.0)(circuit)
|
|
32
|
+
assert len(transformed_circuit_p1) == 20
|
|
33
|
+
|
|
34
|
+
# test that we get a deterministic result when using a specific rng
|
|
35
|
+
rng = np.random.default_rng(0)
|
|
36
|
+
transformed_circuit_p0_03 = na.DepolarizingNoiseTransformer(0.03)(circuit, rng=rng)
|
|
37
|
+
expected_circuit = (
|
|
38
|
+
one_layer * 2
|
|
39
|
+
+ circuits.Circuit(ops.I(qubits[2]), ops.Z(qubits[3]))
|
|
40
|
+
+ one_layer * 4
|
|
41
|
+
+ circuits.Circuit(ops.Z(qubits[0]), ops.X(qubits[1]))
|
|
42
|
+
+ one_layer * 4
|
|
43
|
+
+ circuits.Circuit(ops.I(qubits[2]), ops.X(qubits[3]))
|
|
44
|
+
)
|
|
45
|
+
assert transformed_circuit_p0_03 == expected_circuit
|
|
46
|
+
|
|
47
|
+
# test that supplying a dictionary for p works
|
|
48
|
+
transformed_circuit_p_dict = na.DepolarizingNoiseTransformer(
|
|
49
|
+
{tuple(qubits[:2]): 1.0, tuple(qubits[2:]): 0.0}
|
|
50
|
+
)(circuit)
|
|
51
|
+
assert len(transformed_circuit_p_dict) == 20 # depth should be doubled
|
|
52
|
+
assert transformed_circuit_p_dict[1::2].all_qubits() == frozenset(
|
|
53
|
+
qubits[:2]
|
|
54
|
+
) # no single-qubit gates get added to qubits[2:]
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
"""Transformers to rewrite a circuit using gates from a given target gateset."""
|
|
16
16
|
|
|
17
|
-
from typing import
|
|
17
|
+
from typing import Callable, Hashable, Optional, Sequence, TYPE_CHECKING, Union
|
|
18
18
|
|
|
19
19
|
from cirq import circuits
|
|
20
20
|
from cirq.protocols import decompose_protocol as dp
|
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
|
|
15
15
|
from typing import Union
|
|
16
16
|
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
17
19
|
import cirq
|
|
18
20
|
from cirq.protocols.decompose_protocol import DecomposeResult
|
|
19
21
|
from cirq.transformers.optimize_for_target_gateset import _decompose_operations_to_target_gateset
|
|
20
|
-
import pytest
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
def test_decompose_operations_raises_on_stuck():
|
|
@@ -327,7 +328,7 @@ def test_optimize_for_target_gateset_multiple_passes(max_num_passes: Union[int,
|
|
|
327
328
|
|
|
328
329
|
@pytest.mark.parametrize('max_num_passes', [2, None])
|
|
329
330
|
def test_optimize_for_target_gateset_multiple_passes_dont_preserve_moment_structure(
|
|
330
|
-
max_num_passes: Union[int, None]
|
|
331
|
+
max_num_passes: Union[int, None],
|
|
331
332
|
):
|
|
332
333
|
gateset = cirq.CZTargetGateset(preserve_moment_structure=False)
|
|
333
334
|
|
|
@@ -169,7 +169,7 @@ def map_clean_and_borrowable_qubits(
|
|
|
169
169
|
# one from the original system qubits.
|
|
170
170
|
allocated_map[q] = qm.qborrow(1)[0]
|
|
171
171
|
else:
|
|
172
|
-
assert False, f"Unknown temporary qubit type {q}"
|
|
172
|
+
assert False, f"Unknown temporary qubit type {q}" # pragma: no cover
|
|
173
173
|
|
|
174
174
|
# Return the transformed operation / decomposed op-tree.
|
|
175
175
|
return op.transform_qubits({**allocated_map, **trivial_map})
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Copyright 2024 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 collections.abc import Sequence
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
import cirq
|
|
21
|
+
from cirq.ops import SingleQubitCliffordGate
|
|
22
|
+
from cirq.transformers import transformer_api
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@transformer_api.transformer
|
|
26
|
+
class RandomizedMeasurements:
|
|
27
|
+
"""A transformer that appends a moment of random rotations from a given unitary ensemble (pauli,
|
|
28
|
+
clifford, cue)"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, subsystem: Sequence[int] | None = None):
|
|
31
|
+
"""Class structure for performing and analyzing a general randomized measurement protocol.
|
|
32
|
+
For more details on the randomized measurement toolbox see https://arxiv.org/abs/2203.11374
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
subsystem: The specific subsystem (e.g qubit index) to measure in random basis
|
|
36
|
+
rest of the qubits are measured in the computational basis
|
|
37
|
+
"""
|
|
38
|
+
self.subsystem = subsystem
|
|
39
|
+
|
|
40
|
+
def __call__(
|
|
41
|
+
self,
|
|
42
|
+
circuit: "cirq.AbstractCircuit",
|
|
43
|
+
unitary_ensemble: str = "pauli",
|
|
44
|
+
rng: np.random.Generator | None = None,
|
|
45
|
+
*,
|
|
46
|
+
context: transformer_api.TransformerContext | None = None,
|
|
47
|
+
) -> "cirq.Circuit":
|
|
48
|
+
"""Apply the transformer to the given circuit. Given an input circuit returns
|
|
49
|
+
a new circuit with the pre-measurement unitaries and measurements gates added.
|
|
50
|
+
to the qubits in the subsystem provided.If no subsystem is specified in the
|
|
51
|
+
construction of this class it defaults to measuring all the qubits in the
|
|
52
|
+
randomized bases.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
circuit: The circuit to add randomized measurements to.
|
|
56
|
+
unitary_ensemble: Choice of unitary ensemble (pauli/clifford/cue(circular
|
|
57
|
+
unitary ensemble))
|
|
58
|
+
context: Not used; to satisfy transformer API.
|
|
59
|
+
rng: Random number generator.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
A circuit with pre-measurement unitaries and measurements added
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
all_qubits = sorted(circuit.all_qubits())
|
|
66
|
+
if self.subsystem is None:
|
|
67
|
+
subsystem_qubits = all_qubits
|
|
68
|
+
else:
|
|
69
|
+
subsystem_qubits = [all_qubits[s] for s in self.subsystem]
|
|
70
|
+
if rng is None:
|
|
71
|
+
rng = np.random.default_rng()
|
|
72
|
+
|
|
73
|
+
pre_measurement_moment = self.random_single_qubit_unitary_moment(
|
|
74
|
+
unitary_ensemble, subsystem_qubits, rng
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
return cirq.Circuit.from_moments(
|
|
78
|
+
*circuit.moments, pre_measurement_moment, cirq.M(*subsystem_qubits, key="m")
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
def random_single_qubit_unitary_moment(
|
|
82
|
+
self, unitary_ensemble: str, qubits: Sequence[Any], rng: np.random.Generator
|
|
83
|
+
) -> "cirq.Moment":
|
|
84
|
+
"""Outputs the cirq moment associated with the pre-measurement rotations.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
unitary_ensemble: clifford, pauli, cue
|
|
88
|
+
qubits: List of qubits
|
|
89
|
+
rng: Random number generator to be used in sampling.
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
The cirq moment associated with the pre-measurement rotations
|
|
93
|
+
|
|
94
|
+
Raises:
|
|
95
|
+
ValueError: When unitary_ensemble is not one of "cue", "pauli" or "clifford"
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
if unitary_ensemble.lower() == "pauli":
|
|
99
|
+
unitaries = [_pauli_basis_rotation(rng) for _ in range(len(qubits))]
|
|
100
|
+
|
|
101
|
+
elif unitary_ensemble.lower() == "clifford":
|
|
102
|
+
unitaries = [_single_qubit_clifford(rng) for _ in range(len(qubits))]
|
|
103
|
+
|
|
104
|
+
elif unitary_ensemble.lower() == "cue":
|
|
105
|
+
unitaries = [_single_qubit_cue(rng) for _ in range(len(qubits))]
|
|
106
|
+
|
|
107
|
+
else:
|
|
108
|
+
raise ValueError("Only pauli, clifford and cue unitaries are available")
|
|
109
|
+
|
|
110
|
+
op_list: list[cirq.Operation] = []
|
|
111
|
+
|
|
112
|
+
for idx, unitary in enumerate(unitaries):
|
|
113
|
+
op_list.append(unitary.on(qubits[idx]))
|
|
114
|
+
|
|
115
|
+
return cirq.Moment.from_ops(*op_list)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _pauli_basis_rotation(rng: np.random.Generator) -> "cirq.Gate":
|
|
119
|
+
"""Randomly generate a Pauli basis rotation.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
rng: Random number generator
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
cirq gate
|
|
126
|
+
"""
|
|
127
|
+
basis_idx = rng.choice(np.arange(3))
|
|
128
|
+
|
|
129
|
+
if basis_idx == 0:
|
|
130
|
+
gate: "cirq.Gate" = cirq.Ry(rads=-np.pi / 2)
|
|
131
|
+
elif basis_idx == 1:
|
|
132
|
+
gate = cirq.Rx(rads=np.pi / 2)
|
|
133
|
+
else:
|
|
134
|
+
gate = cirq.I
|
|
135
|
+
return gate
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _single_qubit_clifford(rng: np.random.Generator) -> "cirq.Gate":
|
|
139
|
+
"""Randomly generate a single-qubit Clifford rotation.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
rng: Random number generator
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
cirq gate
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
# there are 24 distinct single-qubit Clifford gates
|
|
149
|
+
clifford_idx = rng.choice(np.arange(24))
|
|
150
|
+
|
|
151
|
+
return SingleQubitCliffordGate.to_phased_xz_gate(
|
|
152
|
+
SingleQubitCliffordGate.all_single_qubit_cliffords[clifford_idx]
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _single_qubit_cue(rng: np.random.Generator) -> "cirq.Gate":
|
|
157
|
+
"""Randomly generate a CUE gate.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
rng: Random number generator
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
cirq gate
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
# phasedxz parameters are distinct between -1 and +1
|
|
167
|
+
x_exponent, z_exponent, axis_phase_exponent = 1 - 2 * rng.random(size=3)
|
|
168
|
+
|
|
169
|
+
return cirq.PhasedXZGate(
|
|
170
|
+
x_exponent=x_exponent, z_exponent=z_exponent, axis_phase_exponent=axis_phase_exponent
|
|
171
|
+
)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Copyright 2024 The Cirq Developers
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import pytest
|
|
16
|
+
|
|
17
|
+
import cirq
|
|
18
|
+
import cirq.transformers.randomized_measurements as rand_meas
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_randomized_measurements_appends_two_moments_on_returned_circuit():
|
|
22
|
+
# Create a 4-qubit circuit
|
|
23
|
+
q0, q1, q2, q3 = cirq.LineQubit.range(4)
|
|
24
|
+
circuit_pre = cirq.Circuit(
|
|
25
|
+
[cirq.H(q0), cirq.CNOT(q0, q1), cirq.CNOT(q1, q2), cirq.CNOT(q2, q3)]
|
|
26
|
+
)
|
|
27
|
+
num_moments_pre = len(circuit_pre.moments)
|
|
28
|
+
|
|
29
|
+
# Append randomized measurements to subsystem
|
|
30
|
+
unitary_ensembles = ['pauli', 'clifford', 'cue']
|
|
31
|
+
for u in unitary_ensembles:
|
|
32
|
+
circuit_post = rand_meas.RandomizedMeasurements()(circuit_pre, unitary_ensemble=u)
|
|
33
|
+
num_moments_post = len(circuit_post.moments)
|
|
34
|
+
assert num_moments_post == num_moments_pre + 2
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_append_randomized_measurements_leaves_qubits_not_in_specified_subsystem_unchanged():
|
|
38
|
+
# Create a 4-qubit circuit
|
|
39
|
+
q0, q1, q2, q3 = cirq.LineQubit.range(4)
|
|
40
|
+
circuit = cirq.Circuit([cirq.H(q0), cirq.CNOT(q0, q1), cirq.CNOT(q1, q2), cirq.CNOT(q2, q3)])
|
|
41
|
+
|
|
42
|
+
# Append randomized measurements to subsystem
|
|
43
|
+
circuit = rand_meas.RandomizedMeasurements(subsystem=(0, 1))(circuit)
|
|
44
|
+
# assert latter subsystems were not changed.
|
|
45
|
+
assert circuit.operation_at(q2, 4) is None
|
|
46
|
+
assert circuit.operation_at(q3, 4) is None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_append_randomized_measurements_leaves_qubits_not_in_noncontinuous_subsystem_unchanged():
|
|
50
|
+
# Create a 4-qubit circuit
|
|
51
|
+
q0, q1, q2, q3 = cirq.LineQubit.range(4)
|
|
52
|
+
circuit = cirq.Circuit([cirq.H(q0), cirq.CNOT(q0, q1), cirq.CNOT(q1, q2), cirq.CNOT(q2, q3)])
|
|
53
|
+
|
|
54
|
+
# Append randomized measurements to subsystem
|
|
55
|
+
circuit = rand_meas.RandomizedMeasurements(subsystem=(0, 2))(circuit)
|
|
56
|
+
|
|
57
|
+
# assert latter subsystems were not changed.
|
|
58
|
+
assert circuit.operation_at(q1, 4) is None
|
|
59
|
+
assert circuit.operation_at(q3, 4) is None
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_exception():
|
|
63
|
+
q0, q1, q2, q3 = cirq.LineQubit.range(4)
|
|
64
|
+
circuit = cirq.Circuit([cirq.H(q0), cirq.CNOT(q0, q1), cirq.CNOT(q1, q2), cirq.CNOT(q2, q3)])
|
|
65
|
+
|
|
66
|
+
# Append randomized measurements to subsystem
|
|
67
|
+
with pytest.raises(ValueError):
|
|
68
|
+
rand_meas.RandomizedMeasurements()(circuit, unitary_ensemble="coe")
|