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
cirq/circuits/circuit.py
CHANGED
|
@@ -19,12 +19,15 @@ Operations. Each Operation is a Gate that acts on some Qubits, for a given
|
|
|
19
19
|
Moment the Operations must all act on distinct Qubits.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
22
24
|
import abc
|
|
23
25
|
import enum
|
|
24
26
|
import html
|
|
25
27
|
import itertools
|
|
26
28
|
import math
|
|
27
29
|
from collections import defaultdict
|
|
30
|
+
from types import NotImplementedType
|
|
28
31
|
from typing import (
|
|
29
32
|
AbstractSet,
|
|
30
33
|
Any,
|
|
@@ -47,10 +50,10 @@ from typing import (
|
|
|
47
50
|
TypeVar,
|
|
48
51
|
Union,
|
|
49
52
|
)
|
|
50
|
-
from typing_extensions import Self
|
|
51
53
|
|
|
52
54
|
import networkx
|
|
53
55
|
import numpy as np
|
|
56
|
+
from typing_extensions import Self
|
|
54
57
|
|
|
55
58
|
import cirq._version
|
|
56
59
|
from cirq import _compat, devices, ops, protocols, qis
|
|
@@ -62,13 +65,13 @@ from cirq.circuits.moment import Moment
|
|
|
62
65
|
from cirq.circuits.qasm_output import QasmOutput
|
|
63
66
|
from cirq.circuits.text_diagram_drawer import TextDiagramDrawer
|
|
64
67
|
from cirq.protocols import circuit_diagram_info_protocol
|
|
65
|
-
from cirq.type_workarounds import NotImplementedType
|
|
66
68
|
|
|
67
69
|
if TYPE_CHECKING:
|
|
68
70
|
import cirq
|
|
69
71
|
|
|
70
72
|
|
|
71
73
|
_TGate = TypeVar('_TGate', bound='cirq.Gate')
|
|
74
|
+
_MOMENT_OR_OP = Union['cirq.Moment', 'cirq.Operation']
|
|
72
75
|
|
|
73
76
|
CIRCUIT_TYPE = TypeVar('CIRCUIT_TYPE', bound='AbstractCircuit')
|
|
74
77
|
document(
|
|
@@ -145,34 +148,36 @@ class AbstractCircuit(abc.ABC):
|
|
|
145
148
|
"""
|
|
146
149
|
|
|
147
150
|
@classmethod
|
|
148
|
-
def from_moments(cls: Type[CIRCUIT_TYPE], *moments:
|
|
151
|
+
def from_moments(cls: Type[CIRCUIT_TYPE], *moments: Optional[cirq.OP_TREE]) -> CIRCUIT_TYPE:
|
|
149
152
|
"""Create a circuit from moment op trees.
|
|
150
153
|
|
|
151
154
|
Args:
|
|
152
|
-
*moments: Op
|
|
153
|
-
will be included directly in the new circuit.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
155
|
+
*moments: Op trees for each moment, which can be one of the following:
|
|
156
|
+
- Moment: will be included directly in the new circuit.
|
|
157
|
+
- AbstractCircuit: will be frozen, wrapped in a CircuitOperation,
|
|
158
|
+
and included in its own moment in the new circuit.
|
|
159
|
+
- None: will be skipped and omitted from the circuit. This can be
|
|
160
|
+
used to include or skip a moment based on a conditional, for example.
|
|
161
|
+
- Other OP_TREE: will be passed to `cirq.Moment` to create a new moment
|
|
162
|
+
which is then included in the new circuit. Note that in this
|
|
163
|
+
case we have the normal restriction that operations in a
|
|
164
|
+
moment must be applied to disjoint sets of qubits.
|
|
160
165
|
"""
|
|
161
166
|
return cls._from_moments(cls._make_moments(moments))
|
|
162
167
|
|
|
163
168
|
@staticmethod
|
|
164
|
-
def _make_moments(moments: Iterable[
|
|
169
|
+
def _make_moments(moments: Iterable[Optional[cirq.OP_TREE]]) -> Iterator[cirq.Moment]:
|
|
165
170
|
for m in moments:
|
|
166
171
|
if isinstance(m, Moment):
|
|
167
172
|
yield m
|
|
168
173
|
elif isinstance(m, AbstractCircuit):
|
|
169
174
|
yield Moment(m.freeze().to_op())
|
|
170
|
-
|
|
175
|
+
elif m is not None:
|
|
171
176
|
yield Moment(m)
|
|
172
177
|
|
|
173
178
|
@classmethod
|
|
174
179
|
@abc.abstractmethod
|
|
175
|
-
def _from_moments(cls: Type[CIRCUIT_TYPE], moments: Iterable[
|
|
180
|
+
def _from_moments(cls: Type[CIRCUIT_TYPE], moments: Iterable[cirq.Moment]) -> CIRCUIT_TYPE:
|
|
176
181
|
"""Create a circuit from moments.
|
|
177
182
|
|
|
178
183
|
This must be implemented by subclasses. It provides a more efficient way
|
|
@@ -185,18 +190,18 @@ class AbstractCircuit(abc.ABC):
|
|
|
185
190
|
|
|
186
191
|
@property
|
|
187
192
|
@abc.abstractmethod
|
|
188
|
-
def moments(self) -> Sequence[
|
|
193
|
+
def moments(self) -> Sequence[cirq.Moment]:
|
|
189
194
|
pass
|
|
190
195
|
|
|
191
196
|
@abc.abstractmethod
|
|
192
|
-
def freeze(self) ->
|
|
197
|
+
def freeze(self) -> cirq.FrozenCircuit:
|
|
193
198
|
"""Creates a FrozenCircuit from this circuit.
|
|
194
199
|
|
|
195
200
|
If 'self' is a FrozenCircuit, the original object is returned.
|
|
196
201
|
"""
|
|
197
202
|
|
|
198
203
|
@abc.abstractmethod
|
|
199
|
-
def unfreeze(self, copy: bool = True) ->
|
|
204
|
+
def unfreeze(self, copy: bool = True) -> cirq.Circuit:
|
|
200
205
|
"""Creates a Circuit from this circuit.
|
|
201
206
|
|
|
202
207
|
Args:
|
|
@@ -214,7 +219,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
214
219
|
and all(m0 == m1 for m0, m1 in zip(self.moments, other.moments))
|
|
215
220
|
)
|
|
216
221
|
|
|
217
|
-
def _approx_eq_(self, other: Any, atol:
|
|
222
|
+
def _approx_eq_(self, other: Any, atol: float) -> bool:
|
|
218
223
|
"""See `cirq.protocols.SupportsApproximateEquality`."""
|
|
219
224
|
if not isinstance(other, AbstractCircuit):
|
|
220
225
|
return NotImplemented
|
|
@@ -228,24 +233,24 @@ class AbstractCircuit(abc.ABC):
|
|
|
228
233
|
def __len__(self) -> int:
|
|
229
234
|
return len(self.moments)
|
|
230
235
|
|
|
231
|
-
def __iter__(self) -> Iterator[
|
|
236
|
+
def __iter__(self) -> Iterator[cirq.Moment]:
|
|
232
237
|
return iter(self.moments)
|
|
233
238
|
|
|
234
|
-
def _decompose_(self) ->
|
|
239
|
+
def _decompose_(self) -> cirq.OP_TREE:
|
|
235
240
|
"""See `cirq.SupportsDecompose`."""
|
|
236
241
|
return self.all_operations()
|
|
237
242
|
|
|
238
243
|
# pylint: disable=function-redefined
|
|
239
244
|
@overload
|
|
240
|
-
def __getitem__(self, key: int) ->
|
|
245
|
+
def __getitem__(self, key: int) -> cirq.Moment:
|
|
241
246
|
pass
|
|
242
247
|
|
|
243
248
|
@overload
|
|
244
|
-
def __getitem__(self, key: Tuple[int,
|
|
249
|
+
def __getitem__(self, key: Tuple[int, cirq.Qid]) -> cirq.Operation:
|
|
245
250
|
pass
|
|
246
251
|
|
|
247
252
|
@overload
|
|
248
|
-
def __getitem__(self, key: Tuple[int, Iterable[
|
|
253
|
+
def __getitem__(self, key: Tuple[int, Iterable[cirq.Qid]]) -> cirq.Moment:
|
|
249
254
|
pass
|
|
250
255
|
|
|
251
256
|
@overload
|
|
@@ -253,11 +258,11 @@ class AbstractCircuit(abc.ABC):
|
|
|
253
258
|
pass
|
|
254
259
|
|
|
255
260
|
@overload
|
|
256
|
-
def __getitem__(self, key: Tuple[slice,
|
|
261
|
+
def __getitem__(self, key: Tuple[slice, cirq.Qid]) -> Self:
|
|
257
262
|
pass
|
|
258
263
|
|
|
259
264
|
@overload
|
|
260
|
-
def __getitem__(self, key: Tuple[slice, Iterable[
|
|
265
|
+
def __getitem__(self, key: Tuple[slice, Iterable[cirq.Qid]]) -> Self:
|
|
261
266
|
pass
|
|
262
267
|
|
|
263
268
|
def __getitem__(self, key):
|
|
@@ -312,7 +317,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
312
317
|
)
|
|
313
318
|
|
|
314
319
|
def _first_moment_operating_on(
|
|
315
|
-
self, qubits: Iterable[
|
|
320
|
+
self, qubits: Iterable[cirq.Qid], indices: Iterable[int]
|
|
316
321
|
) -> Optional[int]:
|
|
317
322
|
qubits = frozenset(qubits)
|
|
318
323
|
for m in indices:
|
|
@@ -322,7 +327,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
322
327
|
|
|
323
328
|
def next_moment_operating_on(
|
|
324
329
|
self,
|
|
325
|
-
qubits: Iterable[
|
|
330
|
+
qubits: Iterable[cirq.Qid],
|
|
326
331
|
start_moment_index: int = 0,
|
|
327
332
|
max_distance: Optional[int] = None,
|
|
328
333
|
) -> Optional[int]:
|
|
@@ -354,8 +359,8 @@ class AbstractCircuit(abc.ABC):
|
|
|
354
359
|
)
|
|
355
360
|
|
|
356
361
|
def next_moments_operating_on(
|
|
357
|
-
self, qubits: Iterable[
|
|
358
|
-
) -> Dict[
|
|
362
|
+
self, qubits: Iterable[cirq.Qid], start_moment_index: int = 0
|
|
363
|
+
) -> Dict[cirq.Qid, int]:
|
|
359
364
|
"""Finds the index of the next moment that touches each qubit.
|
|
360
365
|
|
|
361
366
|
Args:
|
|
@@ -377,7 +382,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
377
382
|
|
|
378
383
|
def prev_moment_operating_on(
|
|
379
384
|
self,
|
|
380
|
-
qubits: Sequence[
|
|
385
|
+
qubits: Sequence[cirq.Qid],
|
|
381
386
|
end_moment_index: Optional[int] = None,
|
|
382
387
|
max_distance: Optional[int] = None,
|
|
383
388
|
) -> Optional[int]:
|
|
@@ -422,10 +427,10 @@ class AbstractCircuit(abc.ABC):
|
|
|
422
427
|
|
|
423
428
|
def reachable_frontier_from(
|
|
424
429
|
self,
|
|
425
|
-
start_frontier: Dict[
|
|
430
|
+
start_frontier: Dict[cirq.Qid, int],
|
|
426
431
|
*,
|
|
427
|
-
is_blocker: Callable[[
|
|
428
|
-
) -> Dict[
|
|
432
|
+
is_blocker: Callable[[cirq.Operation], bool] = lambda op: False,
|
|
433
|
+
) -> Dict[cirq.Qid, int]:
|
|
429
434
|
"""Determines how far can be reached into a circuit under certain rules.
|
|
430
435
|
|
|
431
436
|
The location L = (qubit, moment_index) is *reachable* if and only if the
|
|
@@ -561,11 +566,11 @@ class AbstractCircuit(abc.ABC):
|
|
|
561
566
|
where i is the moment index, q is the qubit, and end_frontier is the
|
|
562
567
|
result of this method.
|
|
563
568
|
"""
|
|
564
|
-
active: Set[
|
|
569
|
+
active: Set[cirq.Qid] = set()
|
|
565
570
|
end_frontier = {}
|
|
566
571
|
queue = BucketPriorityQueue[ops.Operation](drop_duplicate_entries=True)
|
|
567
572
|
|
|
568
|
-
def enqueue_next(qubit:
|
|
573
|
+
def enqueue_next(qubit: cirq.Qid, moment: int) -> None:
|
|
569
574
|
next_moment = self.next_moment_operating_on([qubit], moment)
|
|
570
575
|
if next_moment is None:
|
|
571
576
|
end_frontier[qubit] = max(len(self), start_frontier[qubit])
|
|
@@ -605,10 +610,10 @@ class AbstractCircuit(abc.ABC):
|
|
|
605
610
|
|
|
606
611
|
def findall_operations_between(
|
|
607
612
|
self,
|
|
608
|
-
start_frontier: Dict[
|
|
609
|
-
end_frontier: Dict[
|
|
613
|
+
start_frontier: Dict[cirq.Qid, int],
|
|
614
|
+
end_frontier: Dict[cirq.Qid, int],
|
|
610
615
|
omit_crossing_operations: bool = False,
|
|
611
|
-
) -> List[Tuple[int,
|
|
616
|
+
) -> List[Tuple[int, cirq.Operation]]:
|
|
612
617
|
"""Finds operations between the two given frontiers.
|
|
613
618
|
|
|
614
619
|
If a qubit is in `start_frontier` but not `end_frontier`, its end index
|
|
@@ -653,9 +658,9 @@ class AbstractCircuit(abc.ABC):
|
|
|
653
658
|
|
|
654
659
|
def findall_operations_until_blocked(
|
|
655
660
|
self,
|
|
656
|
-
start_frontier: Dict[
|
|
657
|
-
is_blocker: Callable[[
|
|
658
|
-
) -> List[Tuple[int,
|
|
661
|
+
start_frontier: Dict[cirq.Qid, int],
|
|
662
|
+
is_blocker: Callable[[cirq.Operation], bool] = lambda op: False,
|
|
663
|
+
) -> List[Tuple[int, cirq.Operation]]:
|
|
659
664
|
"""Finds all operations until a blocking operation is hit.
|
|
660
665
|
|
|
661
666
|
An operation is considered blocking if both of the following hold:
|
|
@@ -757,7 +762,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
757
762
|
break
|
|
758
763
|
return op_list
|
|
759
764
|
|
|
760
|
-
def operation_at(self, qubit:
|
|
765
|
+
def operation_at(self, qubit: cirq.Qid, moment_index: int) -> Optional[cirq.Operation]:
|
|
761
766
|
"""Finds the operation on a qubit within a moment, if any.
|
|
762
767
|
|
|
763
768
|
Args:
|
|
@@ -774,8 +779,8 @@ class AbstractCircuit(abc.ABC):
|
|
|
774
779
|
return self.moments[moment_index].operation_at(qubit)
|
|
775
780
|
|
|
776
781
|
def findall_operations(
|
|
777
|
-
self, predicate: Callable[[
|
|
778
|
-
) -> Iterable[Tuple[int,
|
|
782
|
+
self, predicate: Callable[[cirq.Operation], bool]
|
|
783
|
+
) -> Iterable[Tuple[int, cirq.Operation]]:
|
|
779
784
|
"""Find the locations of all operations that satisfy a given condition.
|
|
780
785
|
|
|
781
786
|
This returns an iterator of (index, operation) tuples where each
|
|
@@ -796,7 +801,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
796
801
|
|
|
797
802
|
def findall_operations_with_gate_type(
|
|
798
803
|
self, gate_type: Type[_TGate]
|
|
799
|
-
) -> Iterable[Tuple[int,
|
|
804
|
+
) -> Iterable[Tuple[int, cirq.GateOperation, _TGate]]:
|
|
800
805
|
"""Find the locations of all gate operations of a given type.
|
|
801
806
|
|
|
802
807
|
Args:
|
|
@@ -829,7 +834,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
829
834
|
"""
|
|
830
835
|
return self.are_all_matches_terminal(protocols.is_measurement)
|
|
831
836
|
|
|
832
|
-
def are_all_matches_terminal(self, predicate: Callable[[
|
|
837
|
+
def are_all_matches_terminal(self, predicate: Callable[[cirq.Operation], bool]) -> bool:
|
|
833
838
|
"""Check whether all of the ops that satisfy a predicate are terminal.
|
|
834
839
|
|
|
835
840
|
This method will transparently descend into any CircuitOperations this
|
|
@@ -874,7 +879,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
874
879
|
"""
|
|
875
880
|
return self.are_any_matches_terminal(protocols.is_measurement)
|
|
876
881
|
|
|
877
|
-
def are_any_matches_terminal(self, predicate: Callable[[
|
|
882
|
+
def are_any_matches_terminal(self, predicate: Callable[[cirq.Operation], bool]) -> bool:
|
|
878
883
|
"""Check whether any of the ops that satisfy a predicate are terminal.
|
|
879
884
|
|
|
880
885
|
This method will transparently descend into any CircuitOperations this
|
|
@@ -912,12 +917,12 @@ class AbstractCircuit(abc.ABC):
|
|
|
912
917
|
return True
|
|
913
918
|
return False
|
|
914
919
|
|
|
915
|
-
def _has_op_at(self, moment_index: int, qubits: Iterable[
|
|
920
|
+
def _has_op_at(self, moment_index: int, qubits: Iterable[cirq.Qid]) -> bool:
|
|
916
921
|
return 0 <= moment_index < len(self.moments) and self.moments[moment_index].operates_on(
|
|
917
922
|
qubits
|
|
918
923
|
)
|
|
919
924
|
|
|
920
|
-
def all_qubits(self) -> FrozenSet[
|
|
925
|
+
def all_qubits(self) -> FrozenSet[cirq.Qid]:
|
|
921
926
|
"""Returns the qubits acted upon by Operations in this circuit.
|
|
922
927
|
|
|
923
928
|
Returns: FrozenSet of `cirq.Qid` objects acted on by all operations
|
|
@@ -925,14 +930,14 @@ class AbstractCircuit(abc.ABC):
|
|
|
925
930
|
"""
|
|
926
931
|
return frozenset(q for m in self.moments for q in m.qubits)
|
|
927
932
|
|
|
928
|
-
def all_operations(self) -> Iterator[
|
|
933
|
+
def all_operations(self) -> Iterator[cirq.Operation]:
|
|
929
934
|
"""Returns an iterator over the operations in the circuit.
|
|
930
935
|
|
|
931
936
|
Returns: Iterator over `cirq.Operation` elements found in this circuit.
|
|
932
937
|
"""
|
|
933
938
|
return (op for moment in self for op in moment.operations)
|
|
934
939
|
|
|
935
|
-
def map_operations(self, func: Callable[[
|
|
940
|
+
def map_operations(self, func: Callable[[cirq.Operation], cirq.OP_TREE]) -> Self:
|
|
936
941
|
"""Applies the given function to all operations in this circuit.
|
|
937
942
|
|
|
938
943
|
Args:
|
|
@@ -943,14 +948,14 @@ class AbstractCircuit(abc.ABC):
|
|
|
943
948
|
each operation `op` replaced with `func(op)`.
|
|
944
949
|
"""
|
|
945
950
|
|
|
946
|
-
def map_moment(moment:
|
|
951
|
+
def map_moment(moment: cirq.Moment) -> cirq.Circuit:
|
|
947
952
|
"""Apply func to expand each op into a circuit, then zip up the circuits."""
|
|
948
953
|
return Circuit.zip(*[Circuit(func(op)) for op in moment])
|
|
949
954
|
|
|
950
955
|
return self._from_moments(m for moment in self for m in map_moment(moment))
|
|
951
956
|
|
|
952
957
|
def qid_shape(
|
|
953
|
-
self, qubit_order:
|
|
958
|
+
self, qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT
|
|
954
959
|
) -> Tuple[int, ...]:
|
|
955
960
|
"""Get the qubit shapes of all qubits in this circuit.
|
|
956
961
|
|
|
@@ -960,12 +965,12 @@ class AbstractCircuit(abc.ABC):
|
|
|
960
965
|
qids = ops.QubitOrder.as_qubit_order(qubit_order).order_for(self.all_qubits())
|
|
961
966
|
return protocols.qid_shape(qids)
|
|
962
967
|
|
|
963
|
-
def all_measurement_key_objs(self) -> FrozenSet[
|
|
968
|
+
def all_measurement_key_objs(self) -> FrozenSet[cirq.MeasurementKey]:
|
|
964
969
|
return frozenset(
|
|
965
970
|
key for op in self.all_operations() for key in protocols.measurement_key_objs(op)
|
|
966
971
|
)
|
|
967
972
|
|
|
968
|
-
def _measurement_key_objs_(self) -> FrozenSet[
|
|
973
|
+
def _measurement_key_objs_(self) -> FrozenSet[cirq.MeasurementKey]:
|
|
969
974
|
"""Returns the set of all measurement keys in this circuit.
|
|
970
975
|
|
|
971
976
|
Returns: FrozenSet of `cirq.MeasurementKey` objects that are
|
|
@@ -1000,7 +1005,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
1000
1005
|
)
|
|
1001
1006
|
|
|
1002
1007
|
def _with_rescoped_keys_(
|
|
1003
|
-
self, path: Tuple[str, ...], bindable_keys: FrozenSet[
|
|
1008
|
+
self, path: Tuple[str, ...], bindable_keys: FrozenSet[cirq.MeasurementKey]
|
|
1004
1009
|
):
|
|
1005
1010
|
moments = []
|
|
1006
1011
|
for moment in self.moments:
|
|
@@ -1039,8 +1044,8 @@ class AbstractCircuit(abc.ABC):
|
|
|
1039
1044
|
|
|
1040
1045
|
def unitary(
|
|
1041
1046
|
self,
|
|
1042
|
-
qubit_order:
|
|
1043
|
-
qubits_that_should_be_present: Iterable[
|
|
1047
|
+
qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT,
|
|
1048
|
+
qubits_that_should_be_present: Iterable[cirq.Qid] = (),
|
|
1044
1049
|
ignore_terminal_measurements: bool = True,
|
|
1045
1050
|
dtype: Type[np.complexfloating] = np.complex128,
|
|
1046
1051
|
) -> np.ndarray:
|
|
@@ -1116,12 +1121,12 @@ class AbstractCircuit(abc.ABC):
|
|
|
1116
1121
|
def final_state_vector(
|
|
1117
1122
|
self,
|
|
1118
1123
|
*,
|
|
1119
|
-
initial_state:
|
|
1120
|
-
qubit_order:
|
|
1124
|
+
initial_state: cirq.STATE_VECTOR_LIKE = 0,
|
|
1125
|
+
qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT,
|
|
1121
1126
|
ignore_terminal_measurements: bool = False,
|
|
1122
1127
|
dtype: Type[np.complexfloating] = np.complex128,
|
|
1123
|
-
param_resolver:
|
|
1124
|
-
seed:
|
|
1128
|
+
param_resolver: cirq.ParamResolverOrSimilarType = None,
|
|
1129
|
+
seed: cirq.RANDOM_STATE_OR_SEED_LIKE = None,
|
|
1125
1130
|
) -> np.ndarray:
|
|
1126
1131
|
"""Returns the state vector resulting from acting operations on a state.
|
|
1127
1132
|
|
|
@@ -1179,7 +1184,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
1179
1184
|
transpose: bool = False,
|
|
1180
1185
|
include_tags: bool = True,
|
|
1181
1186
|
precision: Optional[int] = 3,
|
|
1182
|
-
qubit_order:
|
|
1187
|
+
qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT,
|
|
1183
1188
|
) -> str:
|
|
1184
1189
|
"""Returns text containing a diagram describing the circuit.
|
|
1185
1190
|
|
|
@@ -1212,16 +1217,16 @@ class AbstractCircuit(abc.ABC):
|
|
|
1212
1217
|
self,
|
|
1213
1218
|
*,
|
|
1214
1219
|
use_unicode_characters: bool = True,
|
|
1215
|
-
qubit_namer: Optional[Callable[[
|
|
1220
|
+
qubit_namer: Optional[Callable[[cirq.Qid], str]] = None,
|
|
1216
1221
|
transpose: bool = False,
|
|
1217
1222
|
include_tags: bool = True,
|
|
1218
1223
|
draw_moment_groups: bool = True,
|
|
1219
1224
|
precision: Optional[int] = 3,
|
|
1220
|
-
qubit_order:
|
|
1225
|
+
qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT,
|
|
1221
1226
|
get_circuit_diagram_info: Optional[
|
|
1222
|
-
Callable[[
|
|
1227
|
+
Callable[[cirq.Operation, cirq.CircuitDiagramInfoArgs], cirq.CircuitDiagramInfo]
|
|
1223
1228
|
] = None,
|
|
1224
|
-
) ->
|
|
1229
|
+
) -> cirq.TextDiagramDrawer:
|
|
1225
1230
|
"""Returns a TextDiagramDrawer with the circuit drawn into it.
|
|
1226
1231
|
|
|
1227
1232
|
Args:
|
|
@@ -1304,27 +1309,32 @@ class AbstractCircuit(abc.ABC):
|
|
|
1304
1309
|
def _parameter_names_(self) -> AbstractSet[str]:
|
|
1305
1310
|
return {name for op in self.all_operations() for name in protocols.parameter_names(op)}
|
|
1306
1311
|
|
|
1307
|
-
def _resolve_parameters_(self, resolver:
|
|
1312
|
+
def _resolve_parameters_(self, resolver: cirq.ParamResolver, recursive: bool) -> Self:
|
|
1308
1313
|
changed = False
|
|
1309
|
-
resolved_moments: List[
|
|
1314
|
+
resolved_moments: List[cirq.Moment] = []
|
|
1310
1315
|
for moment in self:
|
|
1311
1316
|
resolved_moment = protocols.resolve_parameters(moment, resolver, recursive)
|
|
1312
1317
|
if resolved_moment is not moment:
|
|
1313
1318
|
changed = True
|
|
1314
1319
|
resolved_moments.append(resolved_moment)
|
|
1315
1320
|
if not changed:
|
|
1316
|
-
return self
|
|
1321
|
+
return self # pragma: no cover
|
|
1317
1322
|
return self._from_moments(resolved_moments)
|
|
1318
1323
|
|
|
1319
|
-
def _qasm_(self) -> str:
|
|
1320
|
-
|
|
1324
|
+
def _qasm_(self, args: Optional[cirq.QasmArgs] = None) -> str:
|
|
1325
|
+
if args is None:
|
|
1326
|
+
output = self._to_qasm_output()
|
|
1327
|
+
else:
|
|
1328
|
+
output = self._to_qasm_output(precision=args.precision, version=args.version)
|
|
1329
|
+
return str(output)
|
|
1321
1330
|
|
|
1322
1331
|
def _to_qasm_output(
|
|
1323
1332
|
self,
|
|
1324
1333
|
header: Optional[str] = None,
|
|
1325
1334
|
precision: int = 10,
|
|
1326
|
-
qubit_order:
|
|
1327
|
-
|
|
1335
|
+
qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT,
|
|
1336
|
+
version: str = '2.0',
|
|
1337
|
+
) -> cirq.QasmOutput:
|
|
1328
1338
|
"""Returns a QASM object equivalent to the circuit.
|
|
1329
1339
|
|
|
1330
1340
|
Args:
|
|
@@ -1333,6 +1343,8 @@ class AbstractCircuit(abc.ABC):
|
|
|
1333
1343
|
precision: Number of digits to use when representing numbers.
|
|
1334
1344
|
qubit_order: Determines how qubits are ordered in the QASM
|
|
1335
1345
|
register.
|
|
1346
|
+
version: Version of OpenQASM to render as output. Defaults
|
|
1347
|
+
to OpenQASM 2.0. For OpenQASM 3.0, set this to '3.0'.
|
|
1336
1348
|
"""
|
|
1337
1349
|
if header is None:
|
|
1338
1350
|
header = f'Generated from Cirq v{cirq._version.__version__}'
|
|
@@ -1342,14 +1354,15 @@ class AbstractCircuit(abc.ABC):
|
|
|
1342
1354
|
qubits=qubits,
|
|
1343
1355
|
header=header,
|
|
1344
1356
|
precision=precision,
|
|
1345
|
-
version=
|
|
1357
|
+
version=version,
|
|
1346
1358
|
)
|
|
1347
1359
|
|
|
1348
1360
|
def to_qasm(
|
|
1349
1361
|
self,
|
|
1350
1362
|
header: Optional[str] = None,
|
|
1351
1363
|
precision: int = 10,
|
|
1352
|
-
qubit_order:
|
|
1364
|
+
qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT,
|
|
1365
|
+
version: str = '2.0',
|
|
1353
1366
|
) -> str:
|
|
1354
1367
|
"""Returns QASM equivalent to the circuit.
|
|
1355
1368
|
|
|
@@ -1359,16 +1372,18 @@ class AbstractCircuit(abc.ABC):
|
|
|
1359
1372
|
precision: Number of digits to use when representing numbers.
|
|
1360
1373
|
qubit_order: Determines how qubits are ordered in the QASM
|
|
1361
1374
|
register.
|
|
1375
|
+
version: Version of OpenQASM to output. Defaults to OpenQASM 2.0.
|
|
1376
|
+
Specify '3.0' if OpenQASM 3.0 is desired.
|
|
1362
1377
|
"""
|
|
1363
1378
|
|
|
1364
|
-
return str(self._to_qasm_output(header, precision, qubit_order))
|
|
1379
|
+
return str(self._to_qasm_output(header, precision, qubit_order, version))
|
|
1365
1380
|
|
|
1366
1381
|
def save_qasm(
|
|
1367
1382
|
self,
|
|
1368
1383
|
file_path: Union[str, bytes, int],
|
|
1369
1384
|
header: Optional[str] = None,
|
|
1370
1385
|
precision: int = 10,
|
|
1371
|
-
qubit_order:
|
|
1386
|
+
qubit_order: cirq.QubitOrderOrList = ops.QubitOrder.DEFAULT,
|
|
1372
1387
|
) -> None:
|
|
1373
1388
|
"""Save a QASM file equivalent to the circuit.
|
|
1374
1389
|
|
|
@@ -1390,8 +1405,8 @@ class AbstractCircuit(abc.ABC):
|
|
|
1390
1405
|
return cls(moments, strategy=InsertStrategy.EARLIEST)
|
|
1391
1406
|
|
|
1392
1407
|
def zip(
|
|
1393
|
-
*circuits:
|
|
1394
|
-
) ->
|
|
1408
|
+
*circuits: cirq.AbstractCircuit, align: Union[cirq.Alignment, str] = Alignment.LEFT
|
|
1409
|
+
) -> cirq.AbstractCircuit:
|
|
1395
1410
|
"""Combines operations from circuits in a moment-by-moment fashion.
|
|
1396
1411
|
|
|
1397
1412
|
Moment k of the resulting circuit will have all operations from moment
|
|
@@ -1466,8 +1481,8 @@ class AbstractCircuit(abc.ABC):
|
|
|
1466
1481
|
return result
|
|
1467
1482
|
|
|
1468
1483
|
def concat_ragged(
|
|
1469
|
-
*circuits:
|
|
1470
|
-
) ->
|
|
1484
|
+
*circuits: cirq.AbstractCircuit, align: Union[cirq.Alignment, str] = Alignment.LEFT
|
|
1485
|
+
) -> cirq.AbstractCircuit:
|
|
1471
1486
|
"""Concatenates circuits, overlapping them if possible due to ragged edges.
|
|
1472
1487
|
|
|
1473
1488
|
Starts with the first circuit (index 0), then iterates over the other
|
|
@@ -1510,7 +1525,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
1510
1525
|
|
|
1511
1526
|
# Allocate a buffer large enough to append and prepend all the circuits.
|
|
1512
1527
|
pad_len = sum(len(c) for c in circuits) - n_acc
|
|
1513
|
-
buffer: MutableSequence[
|
|
1528
|
+
buffer: MutableSequence[cirq.Moment] = [cirq.Moment()] * (pad_len * 2 + n_acc)
|
|
1514
1529
|
|
|
1515
1530
|
# Put the initial circuit in the center of the buffer.
|
|
1516
1531
|
offset = pad_len
|
|
@@ -1522,7 +1537,7 @@ class AbstractCircuit(abc.ABC):
|
|
|
1522
1537
|
|
|
1523
1538
|
return cirq.Circuit(buffer[offset : offset + n_acc])
|
|
1524
1539
|
|
|
1525
|
-
def get_independent_qubit_sets(self) -> List[Set[
|
|
1540
|
+
def get_independent_qubit_sets(self) -> List[Set[cirq.Qid]]:
|
|
1526
1541
|
"""Divide circuit's qubits into independent qubit sets.
|
|
1527
1542
|
|
|
1528
1543
|
Independent qubit sets are the qubit sets such that there are
|
|
@@ -1601,17 +1616,17 @@ class AbstractCircuit(abc.ABC):
|
|
|
1601
1616
|
# moments.
|
|
1602
1617
|
return (self._from_moments(m[qubits] for m in self.moments) for qubits in qubit_factors)
|
|
1603
1618
|
|
|
1604
|
-
def _control_keys_(self) -> FrozenSet[
|
|
1619
|
+
def _control_keys_(self) -> FrozenSet[cirq.MeasurementKey]:
|
|
1605
1620
|
controls = frozenset(k for op in self.all_operations() for k in protocols.control_keys(op))
|
|
1606
1621
|
return controls - protocols.measurement_key_objs(self)
|
|
1607
1622
|
|
|
1608
1623
|
|
|
1609
1624
|
def _overlap_collision_time(
|
|
1610
|
-
c1: Sequence[
|
|
1625
|
+
c1: Sequence[cirq.Moment], c2: Sequence[cirq.Moment], align: cirq.Alignment
|
|
1611
1626
|
) -> int:
|
|
1612
1627
|
# Tracks the first used moment index for each qubit in c2.
|
|
1613
1628
|
# Tracks the complementary last used moment index for each qubit in c1.
|
|
1614
|
-
seen_times: Dict[
|
|
1629
|
+
seen_times: Dict[cirq.Qid, int] = {}
|
|
1615
1630
|
|
|
1616
1631
|
# Start scanning from end of first and start of second.
|
|
1617
1632
|
if align == Alignment.LEFT:
|
|
@@ -1649,9 +1664,9 @@ def _overlap_collision_time(
|
|
|
1649
1664
|
def _concat_ragged_helper(
|
|
1650
1665
|
c1_offset: int,
|
|
1651
1666
|
n1: int,
|
|
1652
|
-
buf: MutableSequence[
|
|
1653
|
-
c2: Sequence[
|
|
1654
|
-
align:
|
|
1667
|
+
buf: MutableSequence[cirq.Moment],
|
|
1668
|
+
c2: Sequence[cirq.Moment],
|
|
1669
|
+
align: cirq.Alignment,
|
|
1655
1670
|
) -> Tuple[int, int]:
|
|
1656
1671
|
n2 = len(c2)
|
|
1657
1672
|
shift = _overlap_collision_time(buf[c1_offset : c1_offset + n1], c2, align)
|
|
@@ -1742,7 +1757,7 @@ class Circuit(AbstractCircuit):
|
|
|
1742
1757
|
"""
|
|
1743
1758
|
|
|
1744
1759
|
def __init__(
|
|
1745
|
-
self, *contents:
|
|
1760
|
+
self, *contents: cirq.OP_TREE, strategy: cirq.InsertStrategy = InsertStrategy.EARLIEST
|
|
1746
1761
|
) -> None:
|
|
1747
1762
|
"""Initializes a circuit.
|
|
1748
1763
|
|
|
@@ -1757,19 +1772,22 @@ class Circuit(AbstractCircuit):
|
|
|
1757
1772
|
together. This option does not affect later insertions into the
|
|
1758
1773
|
circuit.
|
|
1759
1774
|
"""
|
|
1760
|
-
self.
|
|
1775
|
+
self._placement_cache: Optional[_PlacementCache] = _PlacementCache()
|
|
1776
|
+
self._moments: List[cirq.Moment] = []
|
|
1761
1777
|
|
|
1762
1778
|
# Implementation note: the following cached properties are set lazily and then
|
|
1763
1779
|
# invalidated and reset to None in `self._mutated()`, which is called any time
|
|
1764
1780
|
# `self._moments` is changed.
|
|
1765
|
-
self._all_qubits: Optional[FrozenSet[
|
|
1766
|
-
self._frozen: Optional[
|
|
1781
|
+
self._all_qubits: Optional[FrozenSet[cirq.Qid]] = None
|
|
1782
|
+
self._frozen: Optional[cirq.FrozenCircuit] = None
|
|
1767
1783
|
self._is_measurement: Optional[bool] = None
|
|
1768
1784
|
self._is_parameterized: Optional[bool] = None
|
|
1769
1785
|
self._parameter_names: Optional[AbstractSet[str]] = None
|
|
1770
|
-
|
|
1786
|
+
if not contents:
|
|
1787
|
+
return
|
|
1771
1788
|
flattened_contents = tuple(ops.flatten_to_ops_or_moments(contents))
|
|
1772
1789
|
if all(isinstance(c, Moment) for c in flattened_contents):
|
|
1790
|
+
self._placement_cache = None
|
|
1773
1791
|
self._moments[:] = cast(Iterable[Moment], flattened_contents)
|
|
1774
1792
|
return
|
|
1775
1793
|
with _compat.block_overlapping_deprecation('.*'):
|
|
@@ -1778,21 +1796,24 @@ class Circuit(AbstractCircuit):
|
|
|
1778
1796
|
else:
|
|
1779
1797
|
self.append(flattened_contents, strategy=strategy)
|
|
1780
1798
|
|
|
1781
|
-
def _mutated(self) -> None:
|
|
1799
|
+
def _mutated(self, *, preserve_placement_cache=False) -> None:
|
|
1782
1800
|
"""Clear cached properties in response to this circuit being mutated."""
|
|
1783
1801
|
self._all_qubits = None
|
|
1784
1802
|
self._frozen = None
|
|
1785
1803
|
self._is_measurement = None
|
|
1786
1804
|
self._is_parameterized = None
|
|
1787
1805
|
self._parameter_names = None
|
|
1806
|
+
if not preserve_placement_cache:
|
|
1807
|
+
self._placement_cache = None
|
|
1788
1808
|
|
|
1789
1809
|
@classmethod
|
|
1790
|
-
def _from_moments(cls, moments: Iterable[
|
|
1810
|
+
def _from_moments(cls, moments: Iterable[cirq.Moment]) -> Circuit:
|
|
1791
1811
|
new_circuit = Circuit()
|
|
1792
1812
|
new_circuit._moments[:] = moments
|
|
1813
|
+
new_circuit._placement_cache = None
|
|
1793
1814
|
return new_circuit
|
|
1794
1815
|
|
|
1795
|
-
def _load_contents_with_earliest_strategy(self, contents:
|
|
1816
|
+
def _load_contents_with_earliest_strategy(self, contents: cirq.OP_TREE):
|
|
1796
1817
|
"""Optimized algorithm to load contents quickly.
|
|
1797
1818
|
|
|
1798
1819
|
The default algorithm appends operations one-at-a-time, letting them
|
|
@@ -1811,27 +1832,18 @@ class Circuit(AbstractCircuit):
|
|
|
1811
1832
|
Non-moment entries will be inserted according to the EARLIEST
|
|
1812
1833
|
insertion strategy.
|
|
1813
1834
|
"""
|
|
1814
|
-
#
|
|
1815
|
-
|
|
1816
|
-
mkey_indices: Dict['cirq.MeasurementKey', int] = {}
|
|
1817
|
-
ckey_indices: Dict['cirq.MeasurementKey', int] = {}
|
|
1835
|
+
# PlacementCache holds dicts from the qubit/key to the greatest moment index that has it.
|
|
1836
|
+
placement_cache = cast(_PlacementCache, self._placement_cache)
|
|
1818
1837
|
|
|
1819
1838
|
# We also maintain the dict from moment index to moments/ops that go into it, for use when
|
|
1820
1839
|
# building the actual moments at the end.
|
|
1821
|
-
op_lists_by_index: Dict[int, List[
|
|
1822
|
-
moments_by_index: Dict[int,
|
|
1823
|
-
|
|
1824
|
-
# For keeping track of length of the circuit thus far.
|
|
1825
|
-
length = 0
|
|
1840
|
+
op_lists_by_index: Dict[int, List[cirq.Operation]] = defaultdict(list)
|
|
1841
|
+
moments_by_index: Dict[int, cirq.Moment] = {}
|
|
1826
1842
|
|
|
1827
1843
|
# "mop" means current moment-or-operation
|
|
1828
1844
|
for mop in ops.flatten_to_ops_or_moments(contents):
|
|
1829
1845
|
# Identify the index of the moment to place this `mop` into.
|
|
1830
|
-
placement_index =
|
|
1831
|
-
mop, qubit_indices, mkey_indices, ckey_indices, length
|
|
1832
|
-
)
|
|
1833
|
-
length = max(length, placement_index + 1) # update the length of the circuit thus far
|
|
1834
|
-
|
|
1846
|
+
placement_index = placement_cache.append(mop)
|
|
1835
1847
|
if isinstance(mop, Moment):
|
|
1836
1848
|
moments_by_index[placement_index] = mop
|
|
1837
1849
|
else:
|
|
@@ -1839,16 +1851,16 @@ class Circuit(AbstractCircuit):
|
|
|
1839
1851
|
|
|
1840
1852
|
# Finally, once everything is placed, we can construct and append the actual moments for
|
|
1841
1853
|
# each index.
|
|
1842
|
-
for i in range(
|
|
1854
|
+
for i in range(placement_cache._length):
|
|
1843
1855
|
if i in moments_by_index:
|
|
1844
1856
|
self._moments.append(moments_by_index[i].with_operations(op_lists_by_index[i]))
|
|
1845
1857
|
else:
|
|
1846
1858
|
self._moments.append(Moment(op_lists_by_index[i]))
|
|
1847
1859
|
|
|
1848
|
-
def __copy__(self) ->
|
|
1860
|
+
def __copy__(self) -> cirq.Circuit:
|
|
1849
1861
|
return self.copy()
|
|
1850
1862
|
|
|
1851
|
-
def freeze(self) ->
|
|
1863
|
+
def freeze(self) -> cirq.FrozenCircuit:
|
|
1852
1864
|
"""Gets a frozen version of this circuit.
|
|
1853
1865
|
|
|
1854
1866
|
Repeated calls to `.freeze()` will return the same FrozenCircuit
|
|
@@ -1857,13 +1869,13 @@ class Circuit(AbstractCircuit):
|
|
|
1857
1869
|
from cirq.circuits.frozen_circuit import FrozenCircuit
|
|
1858
1870
|
|
|
1859
1871
|
if self._frozen is None:
|
|
1860
|
-
self._frozen = FrozenCircuit.
|
|
1872
|
+
self._frozen = FrozenCircuit._from_moments(self._moments)
|
|
1861
1873
|
return self._frozen
|
|
1862
1874
|
|
|
1863
|
-
def unfreeze(self, copy: bool = True) ->
|
|
1875
|
+
def unfreeze(self, copy: bool = True) -> cirq.Circuit:
|
|
1864
1876
|
return self.copy() if copy else self
|
|
1865
1877
|
|
|
1866
|
-
def all_qubits(self) -> FrozenSet[
|
|
1878
|
+
def all_qubits(self) -> FrozenSet[cirq.Qid]:
|
|
1867
1879
|
if self._all_qubits is None:
|
|
1868
1880
|
self._all_qubits = super().all_qubits()
|
|
1869
1881
|
return self._all_qubits
|
|
@@ -1883,19 +1895,20 @@ class Circuit(AbstractCircuit):
|
|
|
1883
1895
|
self._parameter_names = super()._parameter_names_()
|
|
1884
1896
|
return self._parameter_names
|
|
1885
1897
|
|
|
1886
|
-
def copy(self) ->
|
|
1898
|
+
def copy(self) -> Circuit:
|
|
1887
1899
|
"""Return a copy of this circuit."""
|
|
1888
1900
|
copied_circuit = Circuit()
|
|
1889
1901
|
copied_circuit._moments = self._moments[:]
|
|
1902
|
+
copied_circuit._placement_cache = None
|
|
1890
1903
|
return copied_circuit
|
|
1891
1904
|
|
|
1892
1905
|
# pylint: disable=function-redefined
|
|
1893
1906
|
@overload
|
|
1894
|
-
def __setitem__(self, key: int, value:
|
|
1907
|
+
def __setitem__(self, key: int, value: cirq.Moment):
|
|
1895
1908
|
pass
|
|
1896
1909
|
|
|
1897
1910
|
@overload
|
|
1898
|
-
def __setitem__(self, key: slice, value: Iterable[
|
|
1911
|
+
def __setitem__(self, key: slice, value: Iterable[cirq.Moment]):
|
|
1899
1912
|
pass
|
|
1900
1913
|
|
|
1901
1914
|
def __setitem__(self, key, value):
|
|
@@ -1956,7 +1969,7 @@ class Circuit(AbstractCircuit):
|
|
|
1956
1969
|
return NotImplemented
|
|
1957
1970
|
return self * int(repetitions)
|
|
1958
1971
|
|
|
1959
|
-
def __pow__(self, exponent: int) ->
|
|
1972
|
+
def __pow__(self, exponent: int) -> cirq.Circuit:
|
|
1960
1973
|
"""A circuit raised to a power, only valid for exponent -1, the inverse.
|
|
1961
1974
|
|
|
1962
1975
|
This will fail if anything other than -1 is passed to the Circuit by
|
|
@@ -1980,24 +1993,42 @@ class Circuit(AbstractCircuit):
|
|
|
1980
1993
|
__hash__ = None # type: ignore
|
|
1981
1994
|
|
|
1982
1995
|
def concat_ragged(
|
|
1983
|
-
*circuits:
|
|
1984
|
-
) ->
|
|
1996
|
+
*circuits: cirq.AbstractCircuit, align: Union[cirq.Alignment, str] = Alignment.LEFT
|
|
1997
|
+
) -> cirq.Circuit:
|
|
1985
1998
|
return AbstractCircuit.concat_ragged(*circuits, align=align).unfreeze(copy=False)
|
|
1986
1999
|
|
|
1987
2000
|
concat_ragged.__doc__ = AbstractCircuit.concat_ragged.__doc__
|
|
1988
2001
|
|
|
1989
2002
|
def zip(
|
|
1990
|
-
*circuits:
|
|
1991
|
-
) ->
|
|
2003
|
+
*circuits: cirq.AbstractCircuit, align: Union[cirq.Alignment, str] = Alignment.LEFT
|
|
2004
|
+
) -> cirq.Circuit:
|
|
1992
2005
|
return AbstractCircuit.zip(*circuits, align=align).unfreeze(copy=False)
|
|
1993
2006
|
|
|
1994
2007
|
zip.__doc__ = AbstractCircuit.zip.__doc__
|
|
1995
2008
|
|
|
1996
2009
|
def transform_qubits(
|
|
1997
|
-
self, qubit_map: Union[Dict[
|
|
1998
|
-
) ->
|
|
2010
|
+
self, qubit_map: Union[Dict[cirq.Qid, cirq.Qid], Callable[[cirq.Qid], cirq.Qid]]
|
|
2011
|
+
) -> cirq.Circuit:
|
|
1999
2012
|
"""Returns the same circuit, but with different qubits.
|
|
2000
2013
|
|
|
2014
|
+
This function will return a new `Circuit` with the same gates but
|
|
2015
|
+
with qubits mapped according to the argument.
|
|
2016
|
+
|
|
2017
|
+
For example, the following will translate LineQubits to GridQubits:
|
|
2018
|
+
|
|
2019
|
+
>>> grid_qubits = cirq.GridQubit.square(2)
|
|
2020
|
+
>>> line_qubits = cirq.LineQubit.range(4)
|
|
2021
|
+
>>> circuit = cirq.Circuit([cirq.H(q) for q in line_qubits])
|
|
2022
|
+
>>> circuit.transform_qubits(lambda q : grid_qubits[q.x])
|
|
2023
|
+
cirq.Circuit([
|
|
2024
|
+
cirq.Moment(
|
|
2025
|
+
cirq.H(cirq.GridQubit(0, 0)),
|
|
2026
|
+
cirq.H(cirq.GridQubit(0, 1)),
|
|
2027
|
+
cirq.H(cirq.GridQubit(1, 0)),
|
|
2028
|
+
cirq.H(cirq.GridQubit(1, 1)),
|
|
2029
|
+
),
|
|
2030
|
+
])
|
|
2031
|
+
|
|
2001
2032
|
Args:
|
|
2002
2033
|
qubit_map: A function or a dict mapping each current qubit into a desired
|
|
2003
2034
|
new qubit.
|
|
@@ -2012,7 +2043,7 @@ class Circuit(AbstractCircuit):
|
|
|
2012
2043
|
if callable(qubit_map):
|
|
2013
2044
|
transform = qubit_map
|
|
2014
2045
|
elif isinstance(qubit_map, dict):
|
|
2015
|
-
transform = lambda q: qubit_map.get(q, q)
|
|
2046
|
+
transform = lambda q: qubit_map.get(q, q)
|
|
2016
2047
|
else:
|
|
2017
2048
|
raise TypeError('qubit_map must be a function or dict mapping qubits to qubits.')
|
|
2018
2049
|
|
|
@@ -2024,7 +2055,7 @@ class Circuit(AbstractCircuit):
|
|
|
2024
2055
|
return Circuit(op_list)
|
|
2025
2056
|
|
|
2026
2057
|
def earliest_available_moment(
|
|
2027
|
-
self, op:
|
|
2058
|
+
self, op: cirq.Operation, *, end_moment_index: Optional[int] = None
|
|
2028
2059
|
) -> int:
|
|
2029
2060
|
"""Finds the index of the earliest (i.e. left most) moment which can accommodate `op`.
|
|
2030
2061
|
|
|
@@ -2067,50 +2098,7 @@ class Circuit(AbstractCircuit):
|
|
|
2067
2098
|
last_available = k
|
|
2068
2099
|
return last_available
|
|
2069
2100
|
|
|
2070
|
-
def
|
|
2071
|
-
self, splitter_index: int, op: 'cirq.Operation', strategy: 'cirq.InsertStrategy'
|
|
2072
|
-
) -> int:
|
|
2073
|
-
"""Determines and prepares where an insertion will occur.
|
|
2074
|
-
|
|
2075
|
-
Args:
|
|
2076
|
-
splitter_index: The index to insert at.
|
|
2077
|
-
op: The operation that will be inserted.
|
|
2078
|
-
strategy: The insertion strategy.
|
|
2079
|
-
|
|
2080
|
-
Returns:
|
|
2081
|
-
The index of the (possibly new) moment where the insertion should
|
|
2082
|
-
occur.
|
|
2083
|
-
|
|
2084
|
-
Raises:
|
|
2085
|
-
ValueError: Unrecognized append strategy.
|
|
2086
|
-
"""
|
|
2087
|
-
|
|
2088
|
-
if strategy is InsertStrategy.NEW or strategy is InsertStrategy.NEW_THEN_INLINE:
|
|
2089
|
-
self._moments.insert(splitter_index, Moment())
|
|
2090
|
-
self._mutated()
|
|
2091
|
-
return splitter_index
|
|
2092
|
-
|
|
2093
|
-
if strategy is InsertStrategy.INLINE:
|
|
2094
|
-
if 0 <= splitter_index - 1 < len(self._moments) and self._can_add_op_at(
|
|
2095
|
-
splitter_index - 1, op
|
|
2096
|
-
):
|
|
2097
|
-
return splitter_index - 1
|
|
2098
|
-
|
|
2099
|
-
return self._pick_or_create_inserted_op_moment_index(
|
|
2100
|
-
splitter_index, op, InsertStrategy.NEW
|
|
2101
|
-
)
|
|
2102
|
-
|
|
2103
|
-
if strategy is InsertStrategy.EARLIEST:
|
|
2104
|
-
if self._can_add_op_at(splitter_index, op):
|
|
2105
|
-
return self.earliest_available_moment(op, end_moment_index=splitter_index)
|
|
2106
|
-
|
|
2107
|
-
return self._pick_or_create_inserted_op_moment_index(
|
|
2108
|
-
splitter_index, op, InsertStrategy.INLINE
|
|
2109
|
-
)
|
|
2110
|
-
|
|
2111
|
-
raise ValueError(f'Unrecognized append strategy: {strategy}')
|
|
2112
|
-
|
|
2113
|
-
def _can_add_op_at(self, moment_index: int, operation: 'cirq.Operation') -> bool:
|
|
2101
|
+
def _can_add_op_at(self, moment_index: int, operation: cirq.Operation) -> bool:
|
|
2114
2102
|
if not 0 <= moment_index < len(self._moments):
|
|
2115
2103
|
return True
|
|
2116
2104
|
|
|
@@ -2119,8 +2107,8 @@ class Circuit(AbstractCircuit):
|
|
|
2119
2107
|
def insert(
|
|
2120
2108
|
self,
|
|
2121
2109
|
index: int,
|
|
2122
|
-
moment_or_operation_tree:
|
|
2123
|
-
strategy:
|
|
2110
|
+
moment_or_operation_tree: cirq.OP_TREE,
|
|
2111
|
+
strategy: cirq.InsertStrategy = InsertStrategy.EARLIEST,
|
|
2124
2112
|
) -> int:
|
|
2125
2113
|
"""Inserts operations into the circuit.
|
|
2126
2114
|
|
|
@@ -2142,23 +2130,61 @@ class Circuit(AbstractCircuit):
|
|
|
2142
2130
|
"""
|
|
2143
2131
|
# limit index to 0..len(self._moments), also deal with indices smaller 0
|
|
2144
2132
|
k = max(min(index if index >= 0 else len(self._moments) + index, len(self._moments)), 0)
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2133
|
+
if strategy != InsertStrategy.EARLIEST or k != len(self._moments):
|
|
2134
|
+
self._placement_cache = None
|
|
2135
|
+
mops = list(ops.flatten_to_ops_or_moments(moment_or_operation_tree))
|
|
2136
|
+
if self._placement_cache:
|
|
2137
|
+
batches = [mops] # Any grouping would work here; this just happens to be the fastest.
|
|
2138
|
+
elif strategy is InsertStrategy.NEW:
|
|
2139
|
+
batches = [[mop] for mop in mops] # Each op goes into its own moment.
|
|
2140
|
+
else:
|
|
2141
|
+
batches = list(_group_into_moment_compatible(mops))
|
|
2142
|
+
for batch in batches:
|
|
2143
|
+
# Insert a moment if inline/earliest and _any_ op in the batch requires it.
|
|
2144
|
+
if (
|
|
2145
|
+
not self._placement_cache
|
|
2146
|
+
and not isinstance(batch[0], Moment)
|
|
2147
|
+
and strategy in (InsertStrategy.INLINE, InsertStrategy.EARLIEST)
|
|
2148
|
+
and not all(
|
|
2149
|
+
(strategy is InsertStrategy.EARLIEST and self._can_add_op_at(k, op))
|
|
2150
|
+
or (k > 0 and self._can_add_op_at(k - 1, op))
|
|
2151
|
+
for op in cast(List[cirq.Operation], batch)
|
|
2152
|
+
)
|
|
2153
|
+
):
|
|
2154
|
+
self._moments.insert(k, Moment())
|
|
2155
|
+
if strategy is InsertStrategy.INLINE:
|
|
2156
|
+
k += 1
|
|
2157
|
+
max_p = 0
|
|
2158
|
+
for moment_or_op in batch:
|
|
2159
|
+
# Determine Placement
|
|
2160
|
+
if self._placement_cache:
|
|
2161
|
+
p = self._placement_cache.append(moment_or_op)
|
|
2162
|
+
elif isinstance(moment_or_op, Moment):
|
|
2163
|
+
p = k
|
|
2164
|
+
elif strategy in (InsertStrategy.NEW, InsertStrategy.NEW_THEN_INLINE):
|
|
2165
|
+
self._moments.insert(k, Moment())
|
|
2166
|
+
p = k
|
|
2167
|
+
elif strategy is InsertStrategy.INLINE:
|
|
2168
|
+
p = k - 1
|
|
2169
|
+
else: # InsertStrategy.EARLIEST:
|
|
2170
|
+
p = self.earliest_available_moment(moment_or_op, end_moment_index=k)
|
|
2171
|
+
# Place
|
|
2172
|
+
if isinstance(moment_or_op, Moment):
|
|
2173
|
+
self._moments.insert(p, moment_or_op)
|
|
2174
|
+
elif p == len(self._moments):
|
|
2175
|
+
self._moments.append(Moment(moment_or_op))
|
|
2176
|
+
else:
|
|
2177
|
+
self._moments[p] = self._moments[p].with_operation(moment_or_op)
|
|
2178
|
+
# Iterate
|
|
2179
|
+
max_p = max(p, max_p)
|
|
2156
2180
|
if strategy is InsertStrategy.NEW_THEN_INLINE:
|
|
2157
2181
|
strategy = InsertStrategy.INLINE
|
|
2158
|
-
|
|
2182
|
+
k += 1
|
|
2183
|
+
k = max(k, max_p + 1)
|
|
2184
|
+
self._mutated(preserve_placement_cache=True)
|
|
2159
2185
|
return k
|
|
2160
2186
|
|
|
2161
|
-
def insert_into_range(self, operations:
|
|
2187
|
+
def insert_into_range(self, operations: cirq.OP_TREE, start: int, end: int) -> int:
|
|
2162
2188
|
"""Writes operations inline into an area of the circuit.
|
|
2163
2189
|
|
|
2164
2190
|
Args:
|
|
@@ -2201,9 +2227,9 @@ class Circuit(AbstractCircuit):
|
|
|
2201
2227
|
|
|
2202
2228
|
def _push_frontier(
|
|
2203
2229
|
self,
|
|
2204
|
-
early_frontier: Dict[
|
|
2205
|
-
late_frontier: Dict[
|
|
2206
|
-
update_qubits: Optional[Iterable[
|
|
2230
|
+
early_frontier: Dict[cirq.Qid, int],
|
|
2231
|
+
late_frontier: Dict[cirq.Qid, int],
|
|
2232
|
+
update_qubits: Optional[Iterable[cirq.Qid]] = None,
|
|
2207
2233
|
) -> Tuple[int, int]:
|
|
2208
2234
|
"""Inserts moments to separate two frontiers.
|
|
2209
2235
|
|
|
@@ -2246,7 +2272,7 @@ class Circuit(AbstractCircuit):
|
|
|
2246
2272
|
return (0, 0)
|
|
2247
2273
|
|
|
2248
2274
|
def _insert_operations(
|
|
2249
|
-
self, operations: Sequence[
|
|
2275
|
+
self, operations: Sequence[cirq.Operation], insertion_indices: Sequence[int]
|
|
2250
2276
|
) -> None:
|
|
2251
2277
|
"""Inserts operations at the specified moments. Appends new moments if
|
|
2252
2278
|
necessary.
|
|
@@ -2266,18 +2292,15 @@ class Circuit(AbstractCircuit):
|
|
|
2266
2292
|
raise ValueError('operations and insertion_indices must have the same length.')
|
|
2267
2293
|
self._moments += [Moment() for _ in range(1 + max(insertion_indices) - len(self))]
|
|
2268
2294
|
self._mutated()
|
|
2269
|
-
moment_to_ops: Dict[int, List[
|
|
2295
|
+
moment_to_ops: Dict[int, List[cirq.Operation]] = defaultdict(list)
|
|
2270
2296
|
for op_index, moment_index in enumerate(insertion_indices):
|
|
2271
2297
|
moment_to_ops[moment_index].append(operations[op_index])
|
|
2272
2298
|
for moment_index, new_ops in moment_to_ops.items():
|
|
2273
2299
|
self._moments[moment_index] = self._moments[moment_index].with_operations(*new_ops)
|
|
2274
2300
|
|
|
2275
2301
|
def insert_at_frontier(
|
|
2276
|
-
self,
|
|
2277
|
-
|
|
2278
|
-
start: int,
|
|
2279
|
-
frontier: Optional[Dict['cirq.Qid', int]] = None,
|
|
2280
|
-
) -> Dict['cirq.Qid', int]:
|
|
2302
|
+
self, operations: cirq.OP_TREE, start: int, frontier: Optional[Dict[cirq.Qid, int]] = None
|
|
2303
|
+
) -> Dict[cirq.Qid, int]:
|
|
2281
2304
|
"""Inserts operations inline at frontier.
|
|
2282
2305
|
|
|
2283
2306
|
Args:
|
|
@@ -2293,7 +2316,7 @@ class Circuit(AbstractCircuit):
|
|
|
2293
2316
|
frontier = defaultdict(lambda: 0)
|
|
2294
2317
|
flat_ops = tuple(ops.flatten_to_ops(operations))
|
|
2295
2318
|
if not flat_ops:
|
|
2296
|
-
return frontier
|
|
2319
|
+
return frontier # pragma: no cover
|
|
2297
2320
|
qubits = set(q for op in flat_ops for q in op.qubits)
|
|
2298
2321
|
if any(frontier[q] > start for q in qubits):
|
|
2299
2322
|
raise ValueError(
|
|
@@ -2311,7 +2334,7 @@ class Circuit(AbstractCircuit):
|
|
|
2311
2334
|
|
|
2312
2335
|
return frontier
|
|
2313
2336
|
|
|
2314
|
-
def batch_remove(self, removals: Iterable[Tuple[int,
|
|
2337
|
+
def batch_remove(self, removals: Iterable[Tuple[int, cirq.Operation]]) -> None:
|
|
2315
2338
|
"""Removes several operations from a circuit.
|
|
2316
2339
|
|
|
2317
2340
|
Args:
|
|
@@ -2335,7 +2358,7 @@ class Circuit(AbstractCircuit):
|
|
|
2335
2358
|
self._mutated()
|
|
2336
2359
|
|
|
2337
2360
|
def batch_replace(
|
|
2338
|
-
self, replacements: Iterable[Tuple[int,
|
|
2361
|
+
self, replacements: Iterable[Tuple[int, cirq.Operation, cirq.Operation]]
|
|
2339
2362
|
) -> None:
|
|
2340
2363
|
"""Replaces several operations in a circuit with new operations.
|
|
2341
2364
|
|
|
@@ -2359,7 +2382,7 @@ class Circuit(AbstractCircuit):
|
|
|
2359
2382
|
self._moments = copy._moments
|
|
2360
2383
|
self._mutated()
|
|
2361
2384
|
|
|
2362
|
-
def batch_insert_into(self, insert_intos: Iterable[Tuple[int,
|
|
2385
|
+
def batch_insert_into(self, insert_intos: Iterable[Tuple[int, cirq.OP_TREE]]) -> None:
|
|
2363
2386
|
"""Inserts operations into empty spaces in existing moments.
|
|
2364
2387
|
|
|
2365
2388
|
If any of the insertions fails (due to colliding with an existing
|
|
@@ -2380,7 +2403,7 @@ class Circuit(AbstractCircuit):
|
|
|
2380
2403
|
self._moments = copy._moments
|
|
2381
2404
|
self._mutated()
|
|
2382
2405
|
|
|
2383
|
-
def batch_insert(self, insertions: Iterable[Tuple[int,
|
|
2406
|
+
def batch_insert(self, insertions: Iterable[Tuple[int, cirq.OP_TREE]]) -> None:
|
|
2384
2407
|
"""Applies a batched insert operation to the circuit.
|
|
2385
2408
|
|
|
2386
2409
|
Transparently handles the fact that earlier insertions may shift
|
|
@@ -2417,8 +2440,8 @@ class Circuit(AbstractCircuit):
|
|
|
2417
2440
|
|
|
2418
2441
|
def append(
|
|
2419
2442
|
self,
|
|
2420
|
-
moment_or_operation_tree:
|
|
2421
|
-
strategy:
|
|
2443
|
+
moment_or_operation_tree: cirq.OP_TREE,
|
|
2444
|
+
strategy: cirq.InsertStrategy = InsertStrategy.EARLIEST,
|
|
2422
2445
|
) -> None:
|
|
2423
2446
|
"""Appends operations onto the end of the circuit.
|
|
2424
2447
|
|
|
@@ -2430,9 +2453,7 @@ class Circuit(AbstractCircuit):
|
|
|
2430
2453
|
"""
|
|
2431
2454
|
self.insert(len(self._moments), moment_or_operation_tree, strategy)
|
|
2432
2455
|
|
|
2433
|
-
def clear_operations_touching(
|
|
2434
|
-
self, qubits: Iterable['cirq.Qid'], moment_indices: Iterable[int]
|
|
2435
|
-
):
|
|
2456
|
+
def clear_operations_touching(self, qubits: Iterable[cirq.Qid], moment_indices: Iterable[int]):
|
|
2436
2457
|
"""Clears operations that are touching given qubits at given moments.
|
|
2437
2458
|
|
|
2438
2459
|
Args:
|
|
@@ -2447,10 +2468,10 @@ class Circuit(AbstractCircuit):
|
|
|
2447
2468
|
self._mutated()
|
|
2448
2469
|
|
|
2449
2470
|
@property
|
|
2450
|
-
def moments(self) -> Sequence[
|
|
2471
|
+
def moments(self) -> Sequence[cirq.Moment]:
|
|
2451
2472
|
return self._moments
|
|
2452
2473
|
|
|
2453
|
-
def with_noise(self, noise:
|
|
2474
|
+
def with_noise(self, noise: cirq.NOISE_MODEL_LIKE) -> cirq.Circuit:
|
|
2454
2475
|
"""Make a noisy version of the circuit.
|
|
2455
2476
|
|
|
2456
2477
|
Args:
|
|
@@ -2472,10 +2493,10 @@ class Circuit(AbstractCircuit):
|
|
|
2472
2493
|
|
|
2473
2494
|
|
|
2474
2495
|
def _pick_inserted_ops_moment_indices(
|
|
2475
|
-
operations: Sequence[
|
|
2496
|
+
operations: Sequence[cirq.Operation],
|
|
2476
2497
|
start: int = 0,
|
|
2477
|
-
frontier: Optional[Dict[
|
|
2478
|
-
) -> Tuple[Sequence[int], Dict[
|
|
2498
|
+
frontier: Optional[Dict[cirq.Qid, int]] = None,
|
|
2499
|
+
) -> Tuple[Sequence[int], Dict[cirq.Qid, int]]:
|
|
2479
2500
|
"""Greedily assigns operations to moments.
|
|
2480
2501
|
|
|
2481
2502
|
Args:
|
|
@@ -2501,7 +2522,7 @@ def _pick_inserted_ops_moment_indices(
|
|
|
2501
2522
|
return moment_indices, frontier
|
|
2502
2523
|
|
|
2503
2524
|
|
|
2504
|
-
def _get_moment_annotations(moment:
|
|
2525
|
+
def _get_moment_annotations(moment: cirq.Moment) -> Iterator[cirq.Operation]:
|
|
2505
2526
|
for op in moment.operations:
|
|
2506
2527
|
if op.qubits:
|
|
2507
2528
|
continue
|
|
@@ -2517,14 +2538,14 @@ def _get_moment_annotations(moment: 'cirq.Moment') -> Iterator['cirq.Operation']
|
|
|
2517
2538
|
|
|
2518
2539
|
def _draw_moment_annotations(
|
|
2519
2540
|
*,
|
|
2520
|
-
moment:
|
|
2541
|
+
moment: cirq.Moment,
|
|
2521
2542
|
col: int,
|
|
2522
2543
|
use_unicode_characters: bool,
|
|
2523
|
-
label_map: Dict[
|
|
2524
|
-
out_diagram:
|
|
2544
|
+
label_map: Dict[cirq.LabelEntity, int],
|
|
2545
|
+
out_diagram: cirq.TextDiagramDrawer,
|
|
2525
2546
|
precision: Optional[int],
|
|
2526
2547
|
get_circuit_diagram_info: Callable[
|
|
2527
|
-
[
|
|
2548
|
+
[cirq.Operation, cirq.CircuitDiagramInfoArgs], cirq.CircuitDiagramInfo
|
|
2528
2549
|
],
|
|
2529
2550
|
include_tags: bool,
|
|
2530
2551
|
first_annotation_row: int,
|
|
@@ -2549,14 +2570,14 @@ def _draw_moment_annotations(
|
|
|
2549
2570
|
|
|
2550
2571
|
def _draw_moment_in_diagram(
|
|
2551
2572
|
*,
|
|
2552
|
-
moment:
|
|
2573
|
+
moment: cirq.Moment,
|
|
2553
2574
|
use_unicode_characters: bool,
|
|
2554
|
-
label_map: Dict[
|
|
2555
|
-
out_diagram:
|
|
2575
|
+
label_map: Dict[cirq.LabelEntity, int],
|
|
2576
|
+
out_diagram: cirq.TextDiagramDrawer,
|
|
2556
2577
|
precision: Optional[int],
|
|
2557
2578
|
moment_groups: List[Tuple[int, int]],
|
|
2558
2579
|
get_circuit_diagram_info: Optional[
|
|
2559
|
-
Callable[[
|
|
2580
|
+
Callable[[cirq.Operation, cirq.CircuitDiagramInfoArgs], cirq.CircuitDiagramInfo]
|
|
2560
2581
|
],
|
|
2561
2582
|
include_tags: bool,
|
|
2562
2583
|
first_annotation_row: int,
|
|
@@ -2641,7 +2662,7 @@ def _draw_moment_in_diagram(
|
|
|
2641
2662
|
moment_groups.append((x0, max_x))
|
|
2642
2663
|
|
|
2643
2664
|
|
|
2644
|
-
def _get_global_phase_and_tags_for_op(op:
|
|
2665
|
+
def _get_global_phase_and_tags_for_op(op: cirq.Operation) -> Tuple[Optional[complex], List[Any]]:
|
|
2645
2666
|
if isinstance(op.gate, ops.GlobalPhaseGate):
|
|
2646
2667
|
return complex(op.gate.coefficient), list(op.tags)
|
|
2647
2668
|
elif isinstance(op.untagged, CircuitOperation):
|
|
@@ -2675,7 +2696,7 @@ def _formatted_phase(coefficient: complex, unicode: bool, precision: Optional[in
|
|
|
2675
2696
|
def _draw_moment_groups_in_diagram(
|
|
2676
2697
|
moment_groups: List[Tuple[int, int]],
|
|
2677
2698
|
use_unicode_characters: bool,
|
|
2678
|
-
out_diagram:
|
|
2699
|
+
out_diagram: cirq.TextDiagramDrawer,
|
|
2679
2700
|
):
|
|
2680
2701
|
out_diagram.insert_empty_rows(0)
|
|
2681
2702
|
h = out_diagram.height()
|
|
@@ -2705,9 +2726,9 @@ def _draw_moment_groups_in_diagram(
|
|
|
2705
2726
|
|
|
2706
2727
|
|
|
2707
2728
|
def _apply_unitary_circuit(
|
|
2708
|
-
circuit:
|
|
2729
|
+
circuit: cirq.AbstractCircuit,
|
|
2709
2730
|
state: np.ndarray,
|
|
2710
|
-
qubits: Tuple[
|
|
2731
|
+
qubits: Tuple[cirq.Qid, ...],
|
|
2711
2732
|
dtype: Type[np.complexfloating],
|
|
2712
2733
|
) -> np.ndarray:
|
|
2713
2734
|
"""Applies a circuit's unitary effect to the given vector or matrix.
|
|
@@ -2751,7 +2772,7 @@ def _apply_unitary_circuit(
|
|
|
2751
2772
|
return result
|
|
2752
2773
|
|
|
2753
2774
|
|
|
2754
|
-
def _decompose_measurement_inversions(op:
|
|
2775
|
+
def _decompose_measurement_inversions(op: cirq.Operation) -> cirq.OP_TREE:
|
|
2755
2776
|
if isinstance(op.gate, ops.MeasurementGate):
|
|
2756
2777
|
return [ops.X(q) for q, b in zip(op.qubits, op.gate.invert_mask) if b]
|
|
2757
2778
|
return NotImplemented
|
|
@@ -2808,11 +2829,43 @@ def _group_until_different(items: Iterable[_TIn], key: Callable[[_TIn], _TKey],
|
|
|
2808
2829
|
return ((k, [val(i) for i in v]) for (k, v) in itertools.groupby(items, key))
|
|
2809
2830
|
|
|
2810
2831
|
|
|
2832
|
+
def _group_into_moment_compatible(inputs: Sequence[_MOMENT_OR_OP]) -> Iterator[List[_MOMENT_OR_OP]]:
|
|
2833
|
+
"""Groups sequential ops into those that can coexist in a single moment.
|
|
2834
|
+
|
|
2835
|
+
This function will go through the input sequence in order, emitting lists of sequential
|
|
2836
|
+
operations that can go into a single moment. It does not try to rearrange the elements or try
|
|
2837
|
+
to move them to open slots in earlier moments; it simply processes them in order and outputs
|
|
2838
|
+
them. i.e. the output, if flattened, will equal the input.
|
|
2839
|
+
|
|
2840
|
+
Actual Moments in the input will always be emitted by themselves as a single-element list.
|
|
2841
|
+
|
|
2842
|
+
Examples:
|
|
2843
|
+
[X(a), X(b), X(a)] -> [[X(a), X(b)], [X(a)]]
|
|
2844
|
+
[X(a), X(a), X(b)] -> [[X(a)], [X(a), X(b)]]
|
|
2845
|
+
[X(a), Moment(X(b)), X(c)] -> [[X(a)], [Moment(X(b))], [X(c)]]
|
|
2846
|
+
"""
|
|
2847
|
+
batch: List[_MOMENT_OR_OP] = []
|
|
2848
|
+
batch_qubits: Set[cirq.Qid] = set()
|
|
2849
|
+
for mop in inputs:
|
|
2850
|
+
is_moment = isinstance(mop, cirq.Moment)
|
|
2851
|
+
if (is_moment and batch) or not batch_qubits.isdisjoint(mop.qubits):
|
|
2852
|
+
yield batch
|
|
2853
|
+
batch = []
|
|
2854
|
+
batch_qubits.clear()
|
|
2855
|
+
if is_moment:
|
|
2856
|
+
yield [mop]
|
|
2857
|
+
continue
|
|
2858
|
+
batch.append(mop)
|
|
2859
|
+
batch_qubits.update(mop.qubits)
|
|
2860
|
+
if batch:
|
|
2861
|
+
yield batch
|
|
2862
|
+
|
|
2863
|
+
|
|
2811
2864
|
def get_earliest_accommodating_moment_index(
|
|
2812
|
-
moment_or_operation:
|
|
2813
|
-
qubit_indices: Dict[
|
|
2814
|
-
mkey_indices: Dict[
|
|
2815
|
-
ckey_indices: Dict[
|
|
2865
|
+
moment_or_operation: _MOMENT_OR_OP,
|
|
2866
|
+
qubit_indices: Dict[cirq.Qid, int],
|
|
2867
|
+
mkey_indices: Dict[cirq.MeasurementKey, int],
|
|
2868
|
+
ckey_indices: Dict[cirq.MeasurementKey, int],
|
|
2816
2869
|
length: Optional[int] = None,
|
|
2817
2870
|
) -> int:
|
|
2818
2871
|
"""Get the index of the earliest moment that can accommodate the given moment or operation.
|
|
@@ -2823,7 +2876,7 @@ def get_earliest_accommodating_moment_index(
|
|
|
2823
2876
|
Args:
|
|
2824
2877
|
moment_or_operation: The moment operation in question.
|
|
2825
2878
|
qubit_indices: A dictionary mapping qubits to the latest moments that address them.
|
|
2826
|
-
mkey_indices: A dictionary mapping
|
|
2879
|
+
mkey_indices: A dictionary mapping measurement keys to the latest moments that address them.
|
|
2827
2880
|
ckey_indices: A dictionary mapping control keys to the latest moments that address them.
|
|
2828
2881
|
length: The length of the circuit that we are trying to insert a moment or operation into.
|
|
2829
2882
|
Should probably be equal to the maximum of the values in `qubit_indices`,
|
|
@@ -2867,7 +2920,7 @@ def get_earliest_accommodating_moment_index(
|
|
|
2867
2920
|
if mop_ckeys:
|
|
2868
2921
|
last_conflict = max(last_conflict, *[mkey_indices.get(key, -1) for key in mop_ckeys])
|
|
2869
2922
|
|
|
2870
|
-
# The index of the moment to place this moment or
|
|
2923
|
+
# The index of the moment to place this moment or operation ("mop") into.
|
|
2871
2924
|
mop_index = last_conflict + 1
|
|
2872
2925
|
|
|
2873
2926
|
# Update our dicts with data from this `mop` placement. Note `mop_index` will always be greater
|
|
@@ -2880,3 +2933,52 @@ def get_earliest_accommodating_moment_index(
|
|
|
2880
2933
|
ckey_indices[key] = mop_index
|
|
2881
2934
|
|
|
2882
2935
|
return mop_index
|
|
2936
|
+
|
|
2937
|
+
|
|
2938
|
+
class _PlacementCache:
|
|
2939
|
+
"""Maintains qubit and cbit indices for quick op placement.
|
|
2940
|
+
|
|
2941
|
+
Here, we keep track of the greatest moment that contains each qubit,
|
|
2942
|
+
measurement key, and control key, and append operations to the moment after
|
|
2943
|
+
the maximum of these. This avoids having to iterate backwards, checking
|
|
2944
|
+
each moment one at a time.
|
|
2945
|
+
|
|
2946
|
+
It is only valid for `append` operations, and if any other insert strategy
|
|
2947
|
+
is used, or if any operation is added to the circuit without notifying the
|
|
2948
|
+
cache, then the cache must be invalidated for the circuit or rebuilt from
|
|
2949
|
+
scratch. Future improvements may ease this restriction.
|
|
2950
|
+
"""
|
|
2951
|
+
|
|
2952
|
+
def __init__(self) -> None:
|
|
2953
|
+
# These are dicts from the qubit/key to the greatest moment index that has it.
|
|
2954
|
+
self._qubit_indices: Dict[cirq.Qid, int] = {}
|
|
2955
|
+
self._mkey_indices: Dict[cirq.MeasurementKey, int] = {}
|
|
2956
|
+
self._ckey_indices: Dict[cirq.MeasurementKey, int] = {}
|
|
2957
|
+
|
|
2958
|
+
# For keeping track of length of the circuit thus far.
|
|
2959
|
+
self._length = 0
|
|
2960
|
+
|
|
2961
|
+
def append(self, moment_or_operation: _MOMENT_OR_OP) -> int:
|
|
2962
|
+
"""Find placement for moment/operation and update cache.
|
|
2963
|
+
|
|
2964
|
+
Determines the placement index of the provided operation, assuming
|
|
2965
|
+
EARLIEST (append) strategy, and assuming that the internal cache
|
|
2966
|
+
correctly represents the circuit. It then updates the cache and returns
|
|
2967
|
+
the placement index.
|
|
2968
|
+
|
|
2969
|
+
Args:
|
|
2970
|
+
moment_or_operation: The moment or operation to append.
|
|
2971
|
+
|
|
2972
|
+
Returns:
|
|
2973
|
+
The index at which the moment/operation should be placed.
|
|
2974
|
+
"""
|
|
2975
|
+
# Identify the index of the moment to place this into.
|
|
2976
|
+
index = get_earliest_accommodating_moment_index(
|
|
2977
|
+
moment_or_operation,
|
|
2978
|
+
self._qubit_indices,
|
|
2979
|
+
self._mkey_indices,
|
|
2980
|
+
self._ckey_indices,
|
|
2981
|
+
self._length,
|
|
2982
|
+
)
|
|
2983
|
+
self._length = max(self._length, index + 1)
|
|
2984
|
+
return index
|