cirq-core 1.7.0.dev20250924231107__py3-none-any.whl → 1.7.0.dev20251203004401__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.
- cirq/__init__.py +1 -0
- cirq/_compat.py +3 -2
- cirq/_compat_test.py +16 -15
- cirq/_doc.py +4 -3
- cirq/_import.py +2 -1
- cirq/_version.py +1 -1
- cirq/_version_test.py +1 -1
- cirq/circuits/_bucket_priority_queue.py +2 -1
- cirq/circuits/circuit.py +7 -13
- cirq/circuits/circuit_operation.py +2 -1
- cirq/circuits/circuit_test.py +13 -12
- cirq/circuits/frozen_circuit.py +3 -2
- cirq/circuits/moment.py +3 -15
- cirq/circuits/optimization_pass.py +2 -1
- cirq/circuits/qasm_output.py +39 -10
- cirq/circuits/qasm_output_test.py +51 -2
- cirq/circuits/text_diagram_drawer.py +2 -1
- cirq/contrib/acquaintance/bipartite.py +2 -1
- cirq/contrib/acquaintance/devices.py +1 -1
- cirq/contrib/acquaintance/executor.py +4 -5
- cirq/contrib/acquaintance/executor_test.py +2 -1
- cirq/contrib/acquaintance/gates.py +2 -1
- cirq/contrib/acquaintance/gates_test.py +1 -1
- cirq/contrib/acquaintance/inspection_utils.py +2 -1
- cirq/contrib/acquaintance/mutation_utils.py +2 -1
- cirq/contrib/acquaintance/optimizers.py +2 -1
- cirq/contrib/acquaintance/permutation.py +2 -1
- cirq/contrib/acquaintance/permutation_test.py +1 -1
- cirq/contrib/acquaintance/shift.py +2 -1
- cirq/contrib/acquaintance/shift_swap_network.py +2 -1
- cirq/contrib/acquaintance/strategies/complete.py +3 -2
- cirq/contrib/acquaintance/strategies/cubic.py +2 -1
- cirq/contrib/acquaintance/strategies/quartic_paired.py +2 -1
- cirq/contrib/acquaintance/strategies/quartic_paired_test.py +1 -1
- cirq/contrib/acquaintance/testing.py +2 -1
- cirq/contrib/acquaintance/topological_sort.py +2 -1
- cirq/contrib/bayesian_network/bayesian_network_gate.py +3 -2
- cirq/contrib/circuitdag/circuit_dag.py +4 -2
- cirq/contrib/custom_simulators/custom_state_simulator.py +2 -1
- cirq/contrib/custom_simulators/custom_state_simulator_test.py +1 -1
- cirq/contrib/graph_device/graph_device.py +2 -1
- cirq/contrib/graph_device/graph_device_test.py +2 -1
- cirq/contrib/graph_device/hypergraph.py +2 -1
- cirq/contrib/graph_device/uniform_graph_device.py +2 -1
- cirq/contrib/json.py +14 -2
- cirq/contrib/json_test_data/BayesianNetworkGate.json +10 -0
- cirq/contrib/json_test_data/BayesianNetworkGate.repr +3 -0
- cirq/contrib/json_test_data/QuantumVolumeResult.json +169 -0
- cirq/contrib/json_test_data/QuantumVolumeResult.repr +22 -0
- cirq/contrib/json_test_data/SwapPermutationGate.json +3 -0
- cirq/contrib/json_test_data/SwapPermutationGate.repr +1 -0
- cirq/contrib/json_test_data/spec.py +0 -2
- cirq/contrib/noise_models/noise_models.py +2 -1
- cirq/contrib/paulistring/clifford_optimize.py +20 -2
- cirq/contrib/paulistring/optimize.py +1 -1
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation.py +146 -35
- cirq/contrib/paulistring/pauli_string_measurement_with_readout_mitigation_test.py +74 -171
- cirq/contrib/paulistring/recombine.py +5 -2
- cirq/contrib/paulistring/separate.py +1 -1
- cirq/contrib/qasm_import/_parser.py +2 -1
- cirq/contrib/qasm_import/_parser_test.py +3 -3
- cirq/contrib/quantikz/__init__.py +21 -0
- cirq/contrib/quantikz/circuit_to_latex_quantikz.py +680 -0
- cirq/contrib/quantikz/circuit_to_latex_quantikz_test.py +253 -0
- cirq/contrib/quantikz/circuit_to_latex_render.py +424 -0
- cirq/contrib/quantikz/circuit_to_latex_render_test.py +44 -0
- cirq/contrib/quantum_volume/quantum_volume.py +2 -1
- cirq/contrib/quimb/density_matrix.py +1 -1
- cirq/contrib/quimb/grid_circuits.py +2 -1
- cirq/contrib/quimb/grid_circuits_test.py +1 -1
- cirq/contrib/quimb/mps_simulator.py +4 -3
- cirq/contrib/quimb/state_vector.py +2 -1
- cirq/contrib/quirk/export_to_quirk.py +2 -1
- cirq/contrib/quirk/linearize_circuit.py +1 -1
- cirq/contrib/quirk/quirk_gate.py +2 -1
- cirq/contrib/routing/device.py +1 -1
- cirq/contrib/routing/greedy.py +2 -1
- cirq/contrib/routing/initialization.py +2 -1
- cirq/contrib/routing/router.py +2 -1
- cirq/contrib/routing/swap_network.py +2 -1
- cirq/contrib/routing/utils.py +2 -1
- cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking.py +7 -5
- cirq/contrib/shuffle_circuits/shuffle_circuits_with_readout_benchmarking_test.py +6 -6
- cirq/devices/device.py +2 -1
- cirq/devices/grid_device_metadata.py +2 -1
- cirq/devices/grid_qubit.py +7 -6
- cirq/devices/insertion_noise_model.py +2 -1
- cirq/devices/line_qubit.py +2 -1
- cirq/devices/named_topologies.py +2 -1
- cirq/devices/noise_model.py +2 -1
- cirq/devices/noise_model_test.py +1 -1
- cirq/devices/noise_properties.py +2 -1
- cirq/devices/superconducting_qubits_noise_properties_test.py +2 -1
- cirq/devices/thermal_noise_model.py +2 -1
- cirq/experiments/__init__.py +2 -0
- cirq/experiments/benchmarking/parallel_xeb.py +2 -1
- cirq/experiments/benchmarking/parallel_xeb_test.py +1 -1
- cirq/experiments/fidelity_estimation.py +2 -1
- cirq/experiments/fidelity_estimation_test.py +1 -1
- cirq/experiments/ghz_2d.py +150 -0
- cirq/experiments/ghz_2d_test.py +155 -0
- cirq/experiments/n_qubit_tomography.py +2 -1
- cirq/experiments/n_qubit_tomography_test.py +1 -1
- cirq/experiments/purity_estimation.py +1 -1
- cirq/experiments/qubit_characterizations.py +2 -1
- cirq/experiments/random_quantum_circuit_generation.py +2 -1
- cirq/experiments/random_quantum_circuit_generation_test.py +2 -1
- cirq/experiments/readout_confusion_matrix.py +2 -1
- cirq/experiments/readout_confusion_matrix_test.py +1 -1
- cirq/experiments/single_qubit_readout_calibration.py +2 -1
- cirq/experiments/single_qubit_readout_calibration_test.py +1 -1
- cirq/experiments/t1_decay_experiment.py +2 -1
- cirq/experiments/two_qubit_xeb.py +2 -1
- cirq/experiments/two_qubit_xeb_test.py +1 -1
- cirq/experiments/xeb_fitting.py +2 -1
- cirq/experiments/xeb_fitting_test.py +1 -1
- cirq/experiments/xeb_sampling.py +5 -3
- cirq/experiments/xeb_sampling_test.py +1 -1
- cirq/experiments/xeb_simulation.py +2 -1
- cirq/experiments/xeb_simulation_test.py +2 -1
- cirq/experiments/z_phase_calibration.py +2 -1
- cirq/experiments/z_phase_calibration_test.py +18 -3
- cirq/interop/quirk/cells/__init__.py +1 -2
- cirq/interop/quirk/cells/all_cells.py +2 -1
- cirq/interop/quirk/cells/arithmetic_cells.py +2 -1
- cirq/interop/quirk/cells/cell.py +2 -1
- cirq/interop/quirk/cells/composite_cell.py +2 -1
- cirq/interop/quirk/cells/composite_cell_test.py +1 -1
- cirq/interop/quirk/cells/control_cells.py +2 -1
- cirq/interop/quirk/cells/frequency_space_cells.py +1 -1
- cirq/interop/quirk/cells/ignored_cells.py +1 -1
- cirq/interop/quirk/cells/input_cells.py +2 -1
- cirq/interop/quirk/cells/input_rotation_cells.py +2 -1
- cirq/interop/quirk/cells/measurement_cells.py +2 -1
- cirq/interop/quirk/cells/parse.py +2 -11
- cirq/interop/quirk/cells/qubit_permutation_cells.py +2 -1
- cirq/interop/quirk/cells/scalar_cells.py +2 -1
- cirq/interop/quirk/cells/single_qubit_rotation_cells.py +2 -1
- cirq/interop/quirk/cells/swap_cell.py +2 -1
- cirq/interop/quirk/cells/unsupported_cells.py +1 -1
- cirq/interop/quirk/url_to_circuit.py +2 -1
- cirq/json_resolver_cache.py +0 -2
- cirq/linalg/decompositions.py +6 -2
- cirq/linalg/decompositions_test.py +1 -0
- cirq/linalg/diagonalize.py +1 -1
- cirq/linalg/predicates.py +2 -1
- cirq/linalg/tolerance.py +2 -1
- cirq/linalg/transformations.py +2 -1
- cirq/ops/arithmetic_operation.py +2 -1
- cirq/ops/arithmetic_operation_test.py +1 -1
- cirq/ops/boolean_hamiltonian.py +4 -3
- cirq/ops/classically_controlled_operation.py +3 -2
- cirq/ops/clifford_gate.py +2 -1
- cirq/ops/clifford_gate_test.py +1 -2
- cirq/ops/common_channels.py +2 -1
- cirq/ops/common_gates.py +2 -1
- cirq/ops/control_values.py +2 -1
- cirq/ops/controlled_gate.py +3 -2
- cirq/ops/controlled_gate_test.py +2 -1
- cirq/ops/controlled_operation.py +3 -2
- cirq/ops/controlled_operation_test.py +2 -1
- cirq/ops/dense_pauli_string.py +3 -13
- cirq/ops/diagonal_gate.py +3 -2
- cirq/ops/eigen_gate.py +9 -7
- cirq/ops/fourier_transform.py +3 -2
- cirq/ops/fourier_transform_test.py +2 -4
- cirq/ops/fsim_gate.py +3 -2
- cirq/ops/gate_operation.py +8 -12
- cirq/ops/gateset.py +22 -2
- cirq/ops/global_phase_op.py +3 -2
- cirq/ops/greedy_qubit_manager.py +2 -1
- cirq/ops/identity.py +2 -1
- cirq/ops/kraus_channel.py +2 -1
- cirq/ops/linear_combinations.py +8 -3
- cirq/ops/linear_combinations_test.py +23 -1
- cirq/ops/matrix_gates.py +2 -1
- cirq/ops/measure_util.py +2 -1
- cirq/ops/measurement_gate.py +2 -1
- cirq/ops/mixed_unitary_channel.py +2 -1
- cirq/ops/named_qubit.py +2 -2
- cirq/ops/op_tree.py +2 -1
- cirq/ops/parallel_gate.py +3 -2
- cirq/ops/parity_gates.py +2 -1
- cirq/ops/pauli_interaction_gate.py +2 -1
- cirq/ops/pauli_measurement_gate.py +2 -1
- cirq/ops/pauli_string.py +6 -12
- cirq/ops/pauli_string_phasor.py +3 -2
- cirq/ops/pauli_string_raw_types.py +2 -1
- cirq/ops/pauli_string_test.py +2 -2
- cirq/ops/pauli_sum_exponential.py +2 -1
- cirq/ops/permutation_gate.py +2 -1
- cirq/ops/phased_iswap_gate.py +3 -2
- cirq/ops/phased_x_gate.py +5 -4
- cirq/ops/phased_x_z_gate.py +12 -5
- cirq/ops/projector.py +2 -1
- cirq/ops/qubit_manager.py +2 -1
- cirq/ops/qubit_order.py +2 -1
- cirq/ops/qubit_order_or_list.py +1 -1
- cirq/ops/random_gate_channel.py +3 -2
- cirq/ops/raw_types.py +7 -15
- cirq/ops/raw_types_test.py +4 -3
- cirq/ops/state_preparation_channel.py +2 -1
- cirq/ops/three_qubit_gates.py +3 -2
- cirq/ops/two_qubit_diagonal_gate.py +3 -2
- cirq/ops/uniform_superposition_gate.py +2 -1
- cirq/ops/wait_gate.py +10 -4
- cirq/protocols/act_on_protocol.py +2 -1
- cirq/protocols/act_on_protocol_test.py +2 -1
- cirq/protocols/apply_channel_protocol.py +2 -1
- cirq/protocols/apply_mixture_protocol.py +2 -1
- cirq/protocols/apply_mixture_protocol_test.py +2 -1
- cirq/protocols/apply_unitary_protocol.py +2 -1
- cirq/protocols/apply_unitary_protocol_test.py +2 -0
- cirq/protocols/approximate_equality_protocol.py +2 -1
- cirq/protocols/circuit_diagram_info_protocol.py +2 -1
- cirq/protocols/decompose_protocol.py +2 -12
- cirq/protocols/has_stabilizer_effect_protocol.py +1 -1
- cirq/protocols/hash_from_pickle_test.py +2 -2
- cirq/protocols/inverse_protocol.py +2 -1
- cirq/protocols/json_serialization.py +2 -1
- cirq/protocols/kraus_protocol.py +4 -3
- cirq/protocols/kraus_protocol_test.py +2 -2
- cirq/protocols/measurement_key_protocol.py +2 -1
- cirq/protocols/mixture_protocol.py +2 -1
- cirq/protocols/pow_protocol.py +2 -1
- cirq/protocols/qasm.py +2 -1
- cirq/protocols/qid_shape_protocol.py +2 -1
- cirq/protocols/resolve_parameters.py +16 -14
- cirq/protocols/trace_distance_bound.py +2 -1
- cirq/protocols/unitary_protocol.py +21 -21
- cirq/qis/channels.py +1 -1
- cirq/qis/channels_test.py +1 -1
- cirq/qis/clifford_tableau.py +2 -1
- cirq/qis/entropy.py +2 -2
- cirq/qis/quantum_state_representation.py +2 -1
- cirq/qis/states.py +7 -2
- cirq/sim/classical_simulator.py +2 -1
- cirq/sim/clifford/clifford_simulator.py +2 -1
- cirq/sim/clifford/clifford_simulator_test.py +1 -1
- cirq/sim/clifford/clifford_tableau_simulation_state.py +2 -1
- cirq/sim/clifford/stabilizer_ch_form_simulation_state.py +2 -1
- cirq/sim/clifford/stabilizer_sampler.py +1 -1
- cirq/sim/clifford/stabilizer_simulation_state.py +2 -1
- cirq/sim/clifford/stabilizer_state_ch_form.py +3 -2
- cirq/sim/clifford/stabilizer_state_ch_form_test.py +0 -1
- cirq/sim/density_matrix_simulation_state.py +2 -1
- cirq/sim/density_matrix_simulator.py +2 -1
- cirq/sim/density_matrix_utils.py +2 -1
- cirq/sim/mux.py +2 -1
- cirq/sim/mux_test.py +0 -1
- cirq/sim/simulation_product_state.py +2 -1
- cirq/sim/simulation_product_state_test.py +2 -1
- cirq/sim/simulation_state.py +2 -1
- cirq/sim/simulation_state_base.py +2 -1
- cirq/sim/simulation_state_test.py +2 -1
- cirq/sim/simulation_utils.py +2 -1
- cirq/sim/simulator.py +2 -1
- cirq/sim/simulator_base.py +2 -1
- cirq/sim/simulator_base_test.py +2 -1
- cirq/sim/simulator_test.py +2 -1
- cirq/sim/sparse_simulator.py +2 -1
- cirq/sim/state_vector.py +2 -1
- cirq/sim/state_vector_simulation_state.py +2 -1
- cirq/sim/state_vector_simulator.py +2 -1
- cirq/sim/state_vector_test.py +1 -2
- cirq/study/__init__.py +1 -0
- cirq/study/flatten_expressions.py +2 -1
- cirq/study/resolver.py +31 -18
- cirq/study/resolver_test.py +1 -1
- cirq/study/result.py +2 -1
- cirq/study/sweepable.py +2 -1
- cirq/study/sweeps.py +26 -1
- cirq/study/sweeps_test.py +24 -0
- cirq/testing/_compat_test_data/__init__.py +3 -3
- cirq/testing/circuit_compare.py +2 -1
- cirq/testing/consistent_act_on_test.py +1 -1
- cirq/testing/consistent_controlled_gate_op.py +1 -1
- cirq/testing/consistent_controlled_gate_op_test.py +2 -1
- cirq/testing/consistent_protocols.py +2 -1
- cirq/testing/consistent_protocols_test.py +3 -3
- cirq/testing/consistent_qasm.py +2 -1
- cirq/testing/consistent_resolve_parameters.py +1 -1
- cirq/testing/consistent_unitary.py +1 -1
- cirq/testing/consistent_unitary_test.py +1 -1
- cirq/testing/deprecation.py +1 -1
- cirq/testing/devices.py +3 -2
- cirq/testing/equals_tester.py +4 -3
- cirq/testing/equivalent_basis_map.py +4 -2
- cirq/testing/json.py +3 -2
- cirq/testing/logs.py +1 -1
- cirq/testing/op_tree.py +1 -1
- cirq/testing/order_tester.py +2 -2
- cirq/testing/pytest_utils.py +2 -1
- cirq/testing/random_circuit.py +2 -1
- cirq/testing/random_circuit_test.py +2 -1
- cirq/testing/repr_pretty_tester.py +3 -3
- cirq/transformers/__init__.py +1 -0
- cirq/transformers/_connected_component.py +231 -0
- cirq/transformers/_connected_component_test.py +200 -0
- cirq/transformers/align_test.py +13 -13
- cirq/transformers/analytical_decompositions/clifford_decomposition.py +8 -7
- cirq/transformers/analytical_decompositions/clifford_decomposition_test.py +5 -5
- cirq/transformers/analytical_decompositions/controlled_gate_decomposition.py +11 -10
- cirq/transformers/analytical_decompositions/controlled_gate_decomposition_test.py +6 -6
- cirq/transformers/analytical_decompositions/cphase_to_fsim.py +3 -2
- cirq/transformers/analytical_decompositions/cphase_to_fsim_test.py +11 -10
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition.py +8 -7
- cirq/transformers/analytical_decompositions/quantum_shannon_decomposition_test.py +17 -20
- cirq/transformers/analytical_decompositions/single_qubit_decompositions_test.py +33 -27
- cirq/transformers/analytical_decompositions/single_to_two_qubit_isometry_test.py +1 -1
- cirq/transformers/analytical_decompositions/three_qubit_decomposition.py +1 -1
- cirq/transformers/analytical_decompositions/two_qubit_state_preparation_test.py +12 -11
- cirq/transformers/analytical_decompositions/two_qubit_to_cz.py +5 -2
- cirq/transformers/analytical_decompositions/two_qubit_to_cz_test.py +3 -3
- cirq/transformers/analytical_decompositions/two_qubit_to_fsim.py +2 -1
- cirq/transformers/analytical_decompositions/two_qubit_to_ms.py +2 -1
- cirq/transformers/analytical_decompositions/two_qubit_to_ms_test.py +2 -2
- cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap.py +2 -1
- cirq/transformers/analytical_decompositions/two_qubit_to_sqrt_iswap_test.py +32 -30
- cirq/transformers/drop_negligible_operations_test.py +7 -7
- cirq/transformers/dynamical_decoupling.py +185 -112
- cirq/transformers/dynamical_decoupling_test.py +195 -201
- cirq/transformers/eject_phased_paulis.py +2 -1
- cirq/transformers/eject_phased_paulis_test.py +3 -2
- cirq/transformers/eject_z.py +4 -3
- cirq/transformers/eject_z_test.py +23 -25
- cirq/transformers/expand_composite.py +3 -2
- cirq/transformers/expand_composite_test.py +14 -14
- cirq/transformers/gauge_compiling/__init__.py +8 -0
- cirq/transformers/gauge_compiling/gauge_compiling.py +3 -2
- cirq/transformers/gauge_compiling/gauge_compiling_test.py +14 -12
- cirq/transformers/gauge_compiling/gauge_compiling_test_utils.py +3 -3
- cirq/transformers/gauge_compiling/idle_moments_gauge.py +5 -2
- cirq/transformers/gauge_compiling/multi_moment_cphase_gauge.py +242 -0
- cirq/transformers/gauge_compiling/multi_moment_cphase_gauge_test.py +243 -0
- cirq/transformers/gauge_compiling/multi_moment_gauge_compiling.py +151 -0
- cirq/transformers/gauge_compiling/sqrt_cz_gauge.py +2 -1
- cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils.py +1 -1
- cirq/transformers/heuristic_decompositions/gate_tabulation_math_utils_test.py +6 -6
- cirq/transformers/heuristic_decompositions/two_qubit_gate_tabulation.py +2 -1
- cirq/transformers/measurement_transformers.py +2 -1
- cirq/transformers/measurement_transformers_test.py +45 -39
- cirq/transformers/merge_k_qubit_gates.py +2 -1
- cirq/transformers/merge_k_qubit_gates_test.py +1 -1
- cirq/transformers/merge_single_qubit_gates.py +2 -1
- cirq/transformers/merge_single_qubit_gates_test.py +22 -22
- cirq/transformers/noise_adding_test.py +2 -2
- cirq/transformers/optimize_for_target_gateset.py +2 -1
- cirq/transformers/optimize_for_target_gateset_test.py +11 -9
- cirq/transformers/qubit_management_transformers_test.py +6 -2
- cirq/transformers/routing/mapping_manager.py +2 -1
- cirq/transformers/routing/route_circuit_cqc.py +2 -1
- cirq/transformers/stratify.py +2 -1
- cirq/transformers/symbolize.py +2 -1
- cirq/transformers/tag_transformers.py +2 -1
- cirq/transformers/target_gatesets/compilation_target_gateset.py +2 -1
- cirq/transformers/target_gatesets/cz_gateset.py +2 -1
- cirq/transformers/target_gatesets/cz_gateset_test.py +1 -1
- cirq/transformers/target_gatesets/sqrt_iswap_gateset.py +2 -1
- cirq/transformers/transformer_api.py +2 -1
- cirq/transformers/transformer_primitives.py +271 -145
- cirq/transformers/transformer_primitives_test.py +185 -1
- cirq/value/abc_alt.py +2 -1
- cirq/value/classical_data.py +2 -1
- cirq/value/condition.py +2 -1
- cirq/value/digits.py +9 -2
- cirq/value/duration.py +6 -5
- cirq/value/linear_dict.py +4 -9
- cirq/value/measurement_key.py +2 -1
- cirq/value/periodic_value.py +3 -2
- cirq/value/product_state.py +2 -1
- cirq/value/value_equality_attr.py +2 -1
- cirq/vis/density_matrix.py +1 -1
- cirq/vis/heatmap.py +2 -1
- cirq/vis/histogram.py +2 -1
- cirq/vis/state_histogram.py +2 -1
- cirq/work/collector.py +2 -1
- cirq/work/observable_grouping.py +2 -1
- cirq/work/observable_measurement.py +2 -1
- cirq/work/observable_measurement_data.py +2 -1
- cirq/work/observable_measurement_test.py +1 -1
- cirq/work/observable_readout_calibration.py +2 -1
- cirq/work/observable_readout_calibration_test.py +1 -1
- cirq/work/observable_settings.py +2 -1
- cirq/work/sampler.py +2 -1
- cirq/work/sampler_test.py +1 -1
- {cirq_core-1.7.0.dev20250924231107.dist-info → cirq_core-1.7.0.dev20251203004401.dist-info}/METADATA +4 -4
- {cirq_core-1.7.0.dev20250924231107.dist-info → cirq_core-1.7.0.dev20251203004401.dist-info}/RECORD +391 -374
- cirq/contrib/json_test.py +0 -33
- {cirq_core-1.7.0.dev20250924231107.dist-info → cirq_core-1.7.0.dev20251203004401.dist-info}/WHEEL +0 -0
- {cirq_core-1.7.0.dev20250924231107.dist-info → cirq_core-1.7.0.dev20251203004401.dist-info}/licenses/LICENSE +0 -0
- {cirq_core-1.7.0.dev20250924231107.dist-info → cirq_core-1.7.0.dev20251203004401.dist-info}/top_level.txt +0 -0
|
@@ -17,12 +17,22 @@
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
19
|
import bisect
|
|
20
|
+
import copy
|
|
20
21
|
import dataclasses
|
|
22
|
+
import itertools
|
|
21
23
|
from collections import defaultdict
|
|
22
|
-
from
|
|
24
|
+
from collections.abc import Callable, Hashable, Sequence
|
|
25
|
+
from typing import cast, TYPE_CHECKING
|
|
23
26
|
|
|
24
27
|
from cirq import circuits, ops, protocols
|
|
25
28
|
from cirq.circuits.circuit import CIRCUIT_TYPE
|
|
29
|
+
from cirq.transformers._connected_component import (
|
|
30
|
+
Component,
|
|
31
|
+
ComponentSet,
|
|
32
|
+
ComponentWithCircuitOp,
|
|
33
|
+
ComponentWithCircuitOpSet,
|
|
34
|
+
ComponentWithOpsSet,
|
|
35
|
+
)
|
|
26
36
|
|
|
27
37
|
if TYPE_CHECKING:
|
|
28
38
|
import cirq
|
|
@@ -49,6 +59,33 @@ def _create_target_circuit_type(ops: ops.OP_TREE, target_circuit: CIRCUIT_TYPE)
|
|
|
49
59
|
return cast(CIRCUIT_TYPE, circuits.Circuit(ops))
|
|
50
60
|
|
|
51
61
|
|
|
62
|
+
def _insort_last(indices: list[int], value: int) -> None:
|
|
63
|
+
"""Insert value to a sorted list of indices.
|
|
64
|
+
|
|
65
|
+
Optimized for the majority case when the value is the last in the list.
|
|
66
|
+
"""
|
|
67
|
+
if indices and value < indices[-1]:
|
|
68
|
+
bisect.insort(indices, value)
|
|
69
|
+
else:
|
|
70
|
+
indices.append(value)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _remove_last(indices: list[int], value: int) -> None:
|
|
74
|
+
"""Remove value from a sorted list of indices.
|
|
75
|
+
|
|
76
|
+
Optimized for the majority case when the value is the last in the list.
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
ValueError: If the value is not in the list.
|
|
80
|
+
"""
|
|
81
|
+
if indices and (
|
|
82
|
+
indices[pos := -1] == value or indices[pos := bisect.bisect_left(indices, value)] == value
|
|
83
|
+
):
|
|
84
|
+
indices.pop(pos)
|
|
85
|
+
else:
|
|
86
|
+
raise ValueError("The value is not in the list of indices") # pragma: no cover
|
|
87
|
+
|
|
88
|
+
|
|
52
89
|
def map_moments(
|
|
53
90
|
circuit: CIRCUIT_TYPE,
|
|
54
91
|
map_func: Callable[[circuits.Moment, int], circuits.Moment | Sequence[circuits.Moment]],
|
|
@@ -282,17 +319,23 @@ def map_operations_and_unroll(
|
|
|
282
319
|
|
|
283
320
|
@dataclasses.dataclass
|
|
284
321
|
class _MergedCircuit:
|
|
285
|
-
"""An optimized internal representation of a circuit, tailored for
|
|
322
|
+
"""An optimized internal representation of a circuit, tailored for merge operations.
|
|
323
|
+
|
|
324
|
+
Operations are represented as mergeable components.
|
|
325
|
+
Each component has a moment id, a set of qubits, a set of measurement keys, and a set of
|
|
326
|
+
control keys. The moment id is the index of the moment that contains the component.
|
|
286
327
|
|
|
287
328
|
Attributes:
|
|
288
|
-
qubit_indexes: Mapping from qubits to (sorted) list of
|
|
289
|
-
acting on the qubit.
|
|
290
|
-
mkey_indexes: Mapping from measurement keys to (sorted) list of
|
|
291
|
-
measurement operations with the same key.
|
|
292
|
-
ckey_indexes: Mapping from measurement keys to (sorted) list of
|
|
293
|
-
classically controlled operations controlled on the same key.
|
|
294
|
-
|
|
295
|
-
|
|
329
|
+
qubit_indexes: Mapping from qubits to (sorted) list of component moments containing
|
|
330
|
+
operations acting on the qubit.
|
|
331
|
+
mkey_indexes: Mapping from measurement keys to (sorted) list of component moments
|
|
332
|
+
containing measurement operations with the same key.
|
|
333
|
+
ckey_indexes: Mapping from measurement keys to (sorted) list of component moments
|
|
334
|
+
containing classically controlled operations controlled on the same key.
|
|
335
|
+
components_by_index: List of components indexed by moment id.
|
|
336
|
+
For a moment id, we use a dictionary to keep track of the
|
|
337
|
+
components in the moment. The dictionary instead of a set is used to preserve
|
|
338
|
+
insertion order and the dictionary's values are intentionally unused.
|
|
296
339
|
"""
|
|
297
340
|
|
|
298
341
|
qubit_indexes: dict[cirq.Qid, list[int]] = dataclasses.field(
|
|
@@ -304,54 +347,203 @@ class _MergedCircuit:
|
|
|
304
347
|
ckey_indexes: dict[cirq.MeasurementKey, list[int]] = dataclasses.field(
|
|
305
348
|
default_factory=lambda: defaultdict(lambda: [-1])
|
|
306
349
|
)
|
|
307
|
-
|
|
350
|
+
components_by_index: list[dict[Component, None]] = dataclasses.field(default_factory=list)
|
|
308
351
|
|
|
309
352
|
def append_empty_moment(self) -> None:
|
|
310
|
-
self.
|
|
311
|
-
|
|
312
|
-
def
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
for
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
for
|
|
332
|
-
self.
|
|
333
|
-
for
|
|
334
|
-
self.
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
353
|
+
self.components_by_index.append({})
|
|
354
|
+
|
|
355
|
+
def add_component(self, c: Component) -> None:
|
|
356
|
+
"""Adds a new components to merged circuit."""
|
|
357
|
+
self.components_by_index[c.moment_id][c] = None
|
|
358
|
+
for q in c.qubits:
|
|
359
|
+
_insort_last(self.qubit_indexes[q], c.moment_id)
|
|
360
|
+
for mkey in c.mkeys:
|
|
361
|
+
_insort_last(self.mkey_indexes[mkey], c.moment_id)
|
|
362
|
+
for ckey in c.ckeys:
|
|
363
|
+
_insort_last(self.ckey_indexes[ckey], c.moment_id)
|
|
364
|
+
|
|
365
|
+
def remove_component(self, c: Component, c_data: Component) -> None:
|
|
366
|
+
"""Removes a component from the merged circuit.
|
|
367
|
+
|
|
368
|
+
Args:
|
|
369
|
+
c: Reference to the component to be removed.
|
|
370
|
+
c_data: Copy of the data in c before any component merges involving c
|
|
371
|
+
(this is necessary as component merges alter the component data).
|
|
372
|
+
"""
|
|
373
|
+
self.components_by_index[c_data.moment_id].pop(c)
|
|
374
|
+
for q in c_data.qubits:
|
|
375
|
+
_remove_last(self.qubit_indexes[q], c_data.moment_id)
|
|
376
|
+
for mkey in c_data.mkeys:
|
|
377
|
+
_remove_last(self.mkey_indexes[mkey], c_data.moment_id)
|
|
378
|
+
for ckey in c_data.ckeys:
|
|
379
|
+
_remove_last(self.ckey_indexes[ckey], c_data.moment_id)
|
|
380
|
+
|
|
381
|
+
def get_mergeable_components(self, c: Component, c_qs: set[cirq.Qid]) -> list[Component]:
|
|
382
|
+
"""Finds all components that can be merged with c.
|
|
383
|
+
|
|
384
|
+
Args:
|
|
385
|
+
c: Component to be merged with existing components.
|
|
386
|
+
c_qs: Subset of c.qubits used to decide which components are mergeable.
|
|
387
|
+
|
|
388
|
+
Returns:
|
|
389
|
+
List of mergeable components.
|
|
390
|
+
"""
|
|
391
|
+
# Find the index of previous moment which can be merged with `c`.
|
|
342
392
|
idx = max(
|
|
343
|
-
|
|
393
|
+
itertools.chain(
|
|
394
|
+
(self.qubit_indexes[q][-1] for q in c_qs),
|
|
395
|
+
(self.mkey_indexes[ckey][-1] for ckey in c.ckeys),
|
|
396
|
+
(self.ckey_indexes[mkey][-1] for mkey in c.mkeys),
|
|
397
|
+
),
|
|
398
|
+
default=-1,
|
|
344
399
|
)
|
|
345
|
-
# Return the set of overlapping
|
|
400
|
+
# Return the set of overlapping components in moment with index `idx`.
|
|
346
401
|
if idx == -1:
|
|
347
|
-
return
|
|
402
|
+
return []
|
|
403
|
+
|
|
404
|
+
return [c for c in self.components_by_index[idx] if not c_qs.isdisjoint(c.qubits)]
|
|
405
|
+
|
|
406
|
+
def get_cirq_circuit(self, cset: ComponentSet, merged_circuit_op_tag: str) -> cirq.Circuit:
|
|
407
|
+
"""Returns the merged circuit.
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
cset: Disjoint set data structure containing the components.
|
|
411
|
+
merged_circuit_op_tag: Tag to use for CircuitOperations.
|
|
412
|
+
|
|
413
|
+
Returns:
|
|
414
|
+
The circuit with merged components as a CircuitOperation.
|
|
415
|
+
"""
|
|
416
|
+
component_ops: dict[Component, list[cirq.Operation]] = defaultdict(list)
|
|
417
|
+
|
|
418
|
+
# Traverse the components in creation order and collect operations
|
|
419
|
+
for c in cset.components():
|
|
420
|
+
root = cset.find(c)
|
|
421
|
+
component_ops[root].append(c.op)
|
|
422
|
+
|
|
423
|
+
moments = []
|
|
424
|
+
for m in self.components_by_index:
|
|
425
|
+
ops = []
|
|
426
|
+
for c in m.keys():
|
|
427
|
+
if isinstance(c, ComponentWithCircuitOp):
|
|
428
|
+
ops.append(c.circuit_op)
|
|
429
|
+
continue
|
|
430
|
+
if len(component_ops[c]) == 1:
|
|
431
|
+
ops.append(component_ops[c][0])
|
|
432
|
+
else:
|
|
433
|
+
ops.append(
|
|
434
|
+
circuits.CircuitOperation(
|
|
435
|
+
circuits.FrozenCircuit(component_ops[c])
|
|
436
|
+
).with_tags(merged_circuit_op_tag)
|
|
437
|
+
)
|
|
438
|
+
moments.append(circuits.Moment(ops))
|
|
439
|
+
return circuits.Circuit(moments)
|
|
348
440
|
|
|
349
|
-
return idx, [
|
|
350
|
-
left_op for left_op in self.ops_by_index[idx] if not op_qs.isdisjoint(left_op.qubits)
|
|
351
|
-
]
|
|
352
441
|
|
|
353
|
-
|
|
354
|
-
|
|
442
|
+
def _merge_operations_impl(
|
|
443
|
+
circuit: CIRCUIT_TYPE,
|
|
444
|
+
cset: ComponentSet,
|
|
445
|
+
*,
|
|
446
|
+
merged_circuit_op_tag: str = "Merged connected component",
|
|
447
|
+
tags_to_ignore: Sequence[Hashable] = (),
|
|
448
|
+
deep: bool = False,
|
|
449
|
+
) -> CIRCUIT_TYPE:
|
|
450
|
+
"""Merges operations in a circuit.
|
|
451
|
+
|
|
452
|
+
Two operations op1 and op2 are merge-able if
|
|
453
|
+
- There is no other operations between op1 and op2 in the circuit
|
|
454
|
+
- is_subset(op1.qubits, op2.qubits) or is_subset(op2.qubits, op1.qubits)
|
|
455
|
+
|
|
456
|
+
The method iterates on the input circuit moment-by-moment from left to right and attempts
|
|
457
|
+
to repeatedly merge each operation in the latest moment with all the corresponding merge-able
|
|
458
|
+
operations to its left.
|
|
459
|
+
|
|
460
|
+
Operations are wrapped in a component and then cset.merge() is called to merge two
|
|
461
|
+
components.
|
|
462
|
+
|
|
463
|
+
If op1 and op2 are merged, both op1 and op2 are deleted from the circuit and
|
|
464
|
+
the merged component is inserted at the index corresponding to the larger
|
|
465
|
+
of op1/op2. If both op1 and op2 act on the same number of qubits, the merged component is
|
|
466
|
+
inserted in the smaller moment index to minimize circuit depth.
|
|
467
|
+
|
|
468
|
+
At the end every component with more than one operation is replaced by a CircuitOperation.
|
|
469
|
+
|
|
470
|
+
Args:
|
|
471
|
+
circuit: Input circuit to apply the transformations on. The input circuit is not mutated.
|
|
472
|
+
cset: Disjoint set data structure that is used to create and merge components.
|
|
473
|
+
merged_circuit_op_tag: Tag used for CircuitOperations created from merged components.
|
|
474
|
+
tags_to_ignore: Sequence of tags which should be ignored during the merge: operations with
|
|
475
|
+
these tags will not be merged.
|
|
476
|
+
deep: If true, the transformer primitive will be recursively applied to all circuits
|
|
477
|
+
wrapped inside circuit operations.
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
Returns:
|
|
481
|
+
Copy of input circuit with merged operations.
|
|
482
|
+
"""
|
|
483
|
+
tags_to_ignore_set = set(tags_to_ignore)
|
|
484
|
+
|
|
485
|
+
merged_circuit = _MergedCircuit()
|
|
486
|
+
for moment_idx, current_moment in enumerate(circuit):
|
|
487
|
+
merged_circuit.append_empty_moment()
|
|
488
|
+
for op in sorted(current_moment.operations, key=lambda op: op.qubits):
|
|
489
|
+
if (
|
|
490
|
+
deep
|
|
491
|
+
and isinstance(op.untagged, circuits.CircuitOperation)
|
|
492
|
+
and tags_to_ignore_set.isdisjoint(op.tags)
|
|
493
|
+
):
|
|
494
|
+
op_untagged = op.untagged
|
|
495
|
+
merged_op = op_untagged.replace(
|
|
496
|
+
circuit=_merge_operations_impl(
|
|
497
|
+
op_untagged.circuit,
|
|
498
|
+
cset,
|
|
499
|
+
merged_circuit_op_tag=merged_circuit_op_tag,
|
|
500
|
+
tags_to_ignore=tags_to_ignore,
|
|
501
|
+
deep=True,
|
|
502
|
+
)
|
|
503
|
+
).with_tags(*op.tags)
|
|
504
|
+
c = cset.new_component(merged_op, moment_idx, is_mergeable=False)
|
|
505
|
+
merged_circuit.add_component(c)
|
|
506
|
+
continue
|
|
507
|
+
|
|
508
|
+
c = cset.new_component(
|
|
509
|
+
op, moment_idx, is_mergeable=tags_to_ignore_set.isdisjoint(op.tags)
|
|
510
|
+
)
|
|
511
|
+
if not c.is_mergeable:
|
|
512
|
+
merged_circuit.add_component(c)
|
|
513
|
+
continue
|
|
514
|
+
|
|
515
|
+
c_qs = set(c.qubits)
|
|
516
|
+
left_comp = merged_circuit.get_mergeable_components(c, c_qs)
|
|
517
|
+
if len(left_comp) == 1 and c_qs.issubset(left_comp[0].qubits):
|
|
518
|
+
# Make a shallow copy of the left component data before merge
|
|
519
|
+
left_c_data = copy.copy(left_comp[0])
|
|
520
|
+
# Case-1: Try to merge c with the larger component on the left.
|
|
521
|
+
new_comp = cset.merge(left_comp[0], c, merge_left=True)
|
|
522
|
+
if new_comp is not None:
|
|
523
|
+
merged_circuit.remove_component(left_comp[0], left_c_data)
|
|
524
|
+
merged_circuit.add_component(new_comp)
|
|
525
|
+
else:
|
|
526
|
+
merged_circuit.add_component(c)
|
|
527
|
+
continue
|
|
528
|
+
|
|
529
|
+
while left_comp and c_qs:
|
|
530
|
+
# Case-2: left_c will merge right into `c` whenever possible.
|
|
531
|
+
for left_c in left_comp:
|
|
532
|
+
is_merged = False
|
|
533
|
+
if c_qs.issuperset(left_c.qubits):
|
|
534
|
+
# Make a shallow copy of the left component data before merge
|
|
535
|
+
left_c_data = copy.copy(left_c)
|
|
536
|
+
# Try to merge left_c into c
|
|
537
|
+
new_comp = cset.merge(left_c, c, merge_left=False)
|
|
538
|
+
if new_comp is not None:
|
|
539
|
+
merged_circuit.remove_component(left_c, left_c_data)
|
|
540
|
+
c, is_merged = new_comp, True
|
|
541
|
+
if not is_merged:
|
|
542
|
+
c_qs -= left_c.qubits
|
|
543
|
+
left_comp = merged_circuit.get_mergeable_components(c, c_qs)
|
|
544
|
+
merged_circuit.add_component(c)
|
|
545
|
+
ret_circuit = merged_circuit.get_cirq_circuit(cset, merged_circuit_op_tag)
|
|
546
|
+
return _to_target_circuit_type(ret_circuit, circuit)
|
|
355
547
|
|
|
356
548
|
|
|
357
549
|
def merge_operations(
|
|
@@ -407,12 +599,8 @@ def merge_operations(
|
|
|
407
599
|
ValueError if the merged operation acts on new qubits outside the set of qubits
|
|
408
600
|
corresponding to the original operations to be merged.
|
|
409
601
|
"""
|
|
410
|
-
_circuit_op_tag = "_internal_tag_to_mark_circuit_ops_in_circuit"
|
|
411
|
-
tags_to_ignore_set = set(tags_to_ignore) | {_circuit_op_tag}
|
|
412
602
|
|
|
413
603
|
def apply_merge_func(op1: ops.Operation, op2: ops.Operation) -> ops.Operation | None:
|
|
414
|
-
if not all(tags_to_ignore_set.isdisjoint(op.tags) for op in [op1, op2]):
|
|
415
|
-
return None
|
|
416
604
|
new_op = merge_func(op1, op2)
|
|
417
605
|
qubit_set = frozenset(op1.qubits + op2.qubits)
|
|
418
606
|
if new_op is not None and not qubit_set.issuperset(new_op.qubits):
|
|
@@ -422,63 +610,15 @@ def merge_operations(
|
|
|
422
610
|
)
|
|
423
611
|
return new_op
|
|
424
612
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
merged_circuit.append_empty_moment()
|
|
428
|
-
for op in sorted(current_moment.operations, key=lambda op: op.qubits):
|
|
429
|
-
if (
|
|
430
|
-
deep
|
|
431
|
-
and isinstance(op.untagged, circuits.CircuitOperation)
|
|
432
|
-
and tags_to_ignore_set.isdisjoint(op.tags)
|
|
433
|
-
):
|
|
434
|
-
op_untagged = op.untagged
|
|
435
|
-
merged_circuit.add_op_to_moment(
|
|
436
|
-
moment_idx,
|
|
437
|
-
op_untagged.replace(
|
|
438
|
-
circuit=merge_operations(
|
|
439
|
-
op_untagged.circuit,
|
|
440
|
-
merge_func,
|
|
441
|
-
tags_to_ignore=tags_to_ignore,
|
|
442
|
-
deep=True,
|
|
443
|
-
)
|
|
444
|
-
).with_tags(*op.tags, _circuit_op_tag),
|
|
445
|
-
)
|
|
446
|
-
continue
|
|
447
|
-
|
|
448
|
-
op_qs = set(op.qubits)
|
|
449
|
-
left_idx, left_ops = merged_circuit.get_mergeable_ops(op, op_qs)
|
|
450
|
-
if len(left_ops) == 1 and op_qs.issubset(left_ops[0].qubits):
|
|
451
|
-
# Case-1: Try to merge op with the larger operation on the left.
|
|
452
|
-
new_op = apply_merge_func(left_ops[0], op)
|
|
453
|
-
if new_op is not None:
|
|
454
|
-
merged_circuit.remove_op_from_moment(left_idx, left_ops[0])
|
|
455
|
-
merged_circuit.add_op_to_moment(left_idx, new_op)
|
|
456
|
-
else:
|
|
457
|
-
merged_circuit.add_op_to_moment(moment_idx, op)
|
|
458
|
-
continue
|
|
613
|
+
def is_mergeable(_: cirq.Operation):
|
|
614
|
+
return True
|
|
459
615
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
new_op = apply_merge_func(left_op, op)
|
|
467
|
-
if new_op is not None:
|
|
468
|
-
merged_circuit.remove_op_from_moment(left_idx, left_op)
|
|
469
|
-
op, is_merged = new_op, True
|
|
470
|
-
if not is_merged:
|
|
471
|
-
op_qs -= frozenset(left_op.qubits)
|
|
472
|
-
left_idx, left_ops = merged_circuit.get_mergeable_ops(op, op_qs)
|
|
473
|
-
merged_circuit.add_op_to_moment(moment_idx, op)
|
|
474
|
-
ret_circuit = merged_circuit.get_cirq_circuit()
|
|
475
|
-
if deep:
|
|
476
|
-
ret_circuit = map_operations(
|
|
477
|
-
ret_circuit,
|
|
478
|
-
lambda o, _: o.untagged.with_tags(*(set(o.tags) - {_circuit_op_tag})),
|
|
479
|
-
deep=True,
|
|
480
|
-
)
|
|
481
|
-
return _to_target_circuit_type(ret_circuit, circuit)
|
|
616
|
+
return _merge_operations_impl(
|
|
617
|
+
circuit,
|
|
618
|
+
ComponentWithCircuitOpSet(is_mergeable, apply_merge_func),
|
|
619
|
+
tags_to_ignore=tags_to_ignore,
|
|
620
|
+
deep=deep,
|
|
621
|
+
)
|
|
482
622
|
|
|
483
623
|
|
|
484
624
|
def merge_operations_to_circuit_op(
|
|
@@ -491,10 +631,9 @@ def merge_operations_to_circuit_op(
|
|
|
491
631
|
) -> CIRCUIT_TYPE:
|
|
492
632
|
"""Merges connected components of operations and wraps each component into a circuit operation.
|
|
493
633
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
strategy.
|
|
634
|
+
Moment structure is preserved for operations that do not participate in merging.
|
|
635
|
+
For merged operations, the newly created circuit operations are constructed by inserting
|
|
636
|
+
operations using EARLIEST strategy.
|
|
498
637
|
If you need more control on moment structure of newly created circuit operations, consider
|
|
499
638
|
using `cirq.merge_operations` directly with a custom `merge_func`.
|
|
500
639
|
|
|
@@ -514,24 +653,16 @@ def merge_operations_to_circuit_op(
|
|
|
514
653
|
Copy of input circuit with valid connected components wrapped in tagged circuit operations.
|
|
515
654
|
"""
|
|
516
655
|
|
|
517
|
-
def
|
|
518
|
-
|
|
519
|
-
op_untagged = op.untagged
|
|
520
|
-
return (
|
|
521
|
-
[*op_untagged.circuit.all_operations()]
|
|
522
|
-
if isinstance(op_untagged, circuits.CircuitOperation)
|
|
523
|
-
and merged_circuit_op_tag in op.tags
|
|
524
|
-
else [op]
|
|
525
|
-
)
|
|
656
|
+
def is_mergeable(_: cirq.Operation):
|
|
657
|
+
return True
|
|
526
658
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
return merge_operations(circuit, merge_func, tags_to_ignore=tags_to_ignore, deep=deep)
|
|
659
|
+
return _merge_operations_impl(
|
|
660
|
+
circuit,
|
|
661
|
+
ComponentWithOpsSet(is_mergeable, can_merge),
|
|
662
|
+
merged_circuit_op_tag=merged_circuit_op_tag,
|
|
663
|
+
tags_to_ignore=tags_to_ignore,
|
|
664
|
+
deep=deep,
|
|
665
|
+
)
|
|
535
666
|
|
|
536
667
|
|
|
537
668
|
def merge_k_qubit_unitaries_to_circuit_op(
|
|
@@ -544,10 +675,9 @@ def merge_k_qubit_unitaries_to_circuit_op(
|
|
|
544
675
|
) -> CIRCUIT_TYPE:
|
|
545
676
|
"""Merges connected components of operations, acting on <= k qubits, into circuit operations.
|
|
546
677
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
are constructed by inserting operations using EARLIEST strategy.
|
|
678
|
+
Moment structure is preserved for operations that do not participate in merging.
|
|
679
|
+
For merged operations, the newly created circuit operations are constructed by inserting
|
|
680
|
+
operations using EARLIEST strategy.
|
|
551
681
|
|
|
552
682
|
Args:
|
|
553
683
|
circuit: Input circuit to apply the transformations on. The input circuit is not mutated.
|
|
@@ -563,18 +693,14 @@ def merge_k_qubit_unitaries_to_circuit_op(
|
|
|
563
693
|
Copy of input circuit with valid connected components wrapped in tagged circuit operations.
|
|
564
694
|
"""
|
|
565
695
|
|
|
566
|
-
def
|
|
567
|
-
return
|
|
568
|
-
protocols.num_qubits(op) <= k and protocols.has_unitary(op)
|
|
569
|
-
for op_list in [ops1, ops2]
|
|
570
|
-
for op in op_list
|
|
571
|
-
)
|
|
696
|
+
def is_mergeable(op: cirq.Operation):
|
|
697
|
+
return protocols.num_qubits(op) <= k and protocols.has_unitary(op)
|
|
572
698
|
|
|
573
|
-
return
|
|
699
|
+
return _merge_operations_impl(
|
|
574
700
|
circuit,
|
|
575
|
-
|
|
576
|
-
tags_to_ignore=tags_to_ignore,
|
|
701
|
+
ComponentSet(is_mergeable),
|
|
577
702
|
merged_circuit_op_tag=merged_circuit_op_tag or f"Merged {k}q unitary connected component.",
|
|
703
|
+
tags_to_ignore=tags_to_ignore,
|
|
578
704
|
deep=deep,
|
|
579
705
|
)
|
|
580
706
|
|