def assert_optimizes(before, after, measure_only_moment=True, with_context=False): context = cirq.TransformerContext( tags_to_ignore=(NO_COMPILE_TAG, )) if with_context else None transformed_circuit = cirq.synchronize_terminal_measurements( before, context=context, after_other_operations=measure_only_moment) cirq.testing.assert_same_circuits(transformed_circuit, after) # Test nested circuit ops. context = cirq.TransformerContext( tags_to_ignore=("ignore", ) + tuple([NO_COMPILE_TAG] if with_context else []), deep=True) c_nested = cirq.Circuit( before, cirq.CircuitOperation(before.freeze()).repeat(5).with_tags("ignore"), before, cirq.CircuitOperation( before.freeze()).repeat(6).with_tags("preserve_tag"), before, ) c_expected = cirq.Circuit( before, cirq.CircuitOperation(before.freeze()).repeat(5).with_tags("ignore"), before, cirq.CircuitOperation( after.freeze()).repeat(6).with_tags("preserve_tag"), after, ) transformed_circuit = cirq.synchronize_terminal_measurements( c_nested, context=context, after_other_operations=measure_only_moment) cirq.testing.assert_same_circuits(transformed_circuit, c_expected)
def test_transformer_decorator_with_defaults(transformer): circuit = cirq.Circuit(cirq.X(cirq.NamedQubit("a"))) context = cirq.TransformerContext(tags_to_ignore=("tags", "to", "ignore")) transformer(circuit) transformer.mock.assert_called_with(circuit, cirq.TransformerContext(), 1e-4, CustomArg()) transformer(circuit, context=context, atol=1e-3) transformer.mock.assert_called_with(circuit, context, 1e-3, CustomArg()) transformer(circuit, context=context, custom_arg=CustomArg(10)) transformer.mock.assert_called_with(circuit, context, 1e-4, CustomArg(10)) transformer(circuit, context=context, atol=1e-2, custom_arg=CustomArg(12)) transformer.mock.assert_called_with(circuit, context, 1e-2, CustomArg(12))
def test_transformer_decorator_adds_support_for_deep(transformer, supports_deep): q = cirq.NamedQubit("q") c_nested_x = cirq.FrozenCircuit(cirq.X(q)) c_nested_y = cirq.FrozenCircuit(cirq.Y(q)) c_nested_xy = cirq.FrozenCircuit( cirq.CircuitOperation(c_nested_x).repeat(5).with_tags("ignore"), cirq.CircuitOperation(c_nested_y).repeat(7).with_tags("preserve_tag"), ) c_nested_yx = cirq.FrozenCircuit( cirq.CircuitOperation(c_nested_y).repeat(7).with_tags("ignore"), cirq.CircuitOperation(c_nested_x).repeat(5).with_tags("preserve_tag"), ) c_orig = cirq.Circuit( cirq.CircuitOperation(c_nested_xy).repeat(4), cirq.CircuitOperation(c_nested_x).repeat(5).with_tags("ignore"), cirq.CircuitOperation(c_nested_y).repeat(6), cirq.CircuitOperation(c_nested_yx).repeat(7), ) context = cirq.TransformerContext(tags_to_ignore=["ignore"], deep=True) transformer(c_orig, context=context) expected_calls = [mock.call(c_orig, context)] if supports_deep: expected_calls = [ mock.call(c_nested_y, context), # c_orig --> xy --> y mock.call(c_nested_xy, context), # c_orig --> xy mock.call(c_nested_y, context), # c_orig --> y mock.call(c_nested_x, context), # c_orig --> yx --> x mock.call(c_nested_yx, context), # c_orig --> yx mock.call(c_orig, context), # c_orig ] transformer.mock.assert_has_calls(expected_calls)
def test_drop_empty_moments(): q1, q2 = cirq.LineQubit.range(2) c_nested = cirq.FrozenCircuit(cirq.Moment(), cirq.Moment(), cirq.Moment([cirq.CNOT(q1, q2)]), cirq.Moment()) c_nested_dropped = cirq.FrozenCircuit(cirq.CNOT(q1, q2)) c_orig = cirq.Circuit( c_nested, cirq.CircuitOperation(c_nested).repeat(6).with_tags("nocompile"), c_nested, cirq.CircuitOperation(c_nested).repeat(5).with_tags("preserve_tag"), c_nested, ) c_expected = cirq.Circuit( c_nested_dropped, cirq.CircuitOperation(c_nested).repeat(6).with_tags("nocompile"), c_nested_dropped, cirq.CircuitOperation(c_nested_dropped).repeat(5).with_tags( "preserve_tag"), c_nested_dropped, ) context = cirq.TransformerContext(tags_to_ignore=("nocompile", ), deep=True) cirq.testing.assert_same_circuits( cirq.drop_empty_moments(c_orig, context=context), c_expected)
def test_align_left_no_compile_context(): q1 = cirq.NamedQubit('q1') q2 = cirq.NamedQubit('q2') cirq.testing.assert_same_circuits( cirq.align_left( cirq.Circuit( [ cirq.Moment([cirq.X(q1)]), cirq.Moment([cirq.Y(q1), cirq.X(q2)]), cirq.Moment([cirq.X(q1), cirq.Y(q2).with_tags("nocompile")]), cirq.Moment([cirq.Y(q1)]), cirq.measure(*[q1, q2], key='a'), ] ), context=cirq.TransformerContext(tags_to_ignore=["nocompile"]), ), cirq.Circuit( [ cirq.Moment([cirq.X(q1), cirq.X(q2)]), cirq.Moment([cirq.Y(q1)]), cirq.Moment([cirq.X(q1), cirq.Y(q2).with_tags("nocompile")]), cirq.Moment([cirq.Y(q1)]), cirq.measure(*[q1, q2], key='a'), ] ), )
def test_merge_single_qubit_gates_into_phased_x_z_deep(): a = cirq.NamedQubit("a") c_nested = cirq.FrozenCircuit(cirq.H(a), cirq.Z(a), cirq.H(a).with_tags("ignore")) c_nested_merged = cirq.FrozenCircuit( cirq.PhasedXPowGate(phase_exponent=-0.5, exponent=0.5).on(a), cirq.H(a).with_tags("ignore")) c_orig = cirq.Circuit( c_nested, cirq.CircuitOperation(c_nested).repeat(4).with_tags("ignore"), c_nested, cirq.CircuitOperation(c_nested).repeat(5).with_tags("preserve_tags"), c_nested, cirq.CircuitOperation(c_nested).repeat(6), ) c_expected = cirq.Circuit( c_nested_merged, cirq.CircuitOperation(c_nested).repeat(4).with_tags("ignore"), c_nested_merged, cirq.CircuitOperation(c_nested_merged).repeat(5).with_tags( "preserve_tags"), c_nested_merged, cirq.CircuitOperation(c_nested_merged).repeat(6), ) context = cirq.TransformerContext(tags_to_ignore=["ignore"], deep=True) c_new = cirq.merge_single_qubit_gates_to_phased_x_and_z(c_orig, context=context) cirq.testing.assert_same_circuits(c_new, c_expected)
def test_decompose_operations_to_target_gateset_default(): q = cirq.LineQubit.range(2) c_orig = cirq.Circuit( cirq.T(q[0]), cirq.SWAP(*q), cirq.T(q[0]), cirq.SWAP(*q).with_tags("ignore"), cirq.measure(q[0], key="m"), cirq.X(q[1]).with_classical_controls("m"), cirq.Moment(cirq.T.on_each(*q)), cirq.SWAP(*q), cirq.T.on_each(*q), ) cirq.testing.assert_has_diagram( c_orig, ''' 0: ───T───×───T───×['ignore']───M───────T───×───T─── │ │ ║ │ 1: ───────×───────×─────────────╫───X───T───×───T─── ║ ║ m: ═════════════════════════════@═══^═══════════════''', ) context = cirq.TransformerContext(tags_to_ignore=("ignore",)) c_new = _decompose_operations_to_target_gateset(c_orig, context=context) cirq.testing.assert_has_diagram( c_new, ''' 0: ───T────────────@───Y^-0.5───@───Y^0.5────@───────────T───×['ignore']───M───────T────────────@───Y^-0.5───@───Y^0.5────@───────────T─── │ │ │ │ ║ │ │ │ 1: ───────Y^-0.5───@───Y^0.5────@───Y^-0.5───@───Y^0.5───────×─────────────╫───X───T───Y^-0.5───@───Y^0.5────@───Y^-0.5───@───Y^0.5───T─── ║ ║ m: ════════════════════════════════════════════════════════════════════════@═══^══════════════════════════════════════════════════════════ ''', )
def test_dephase_nocompile_context(): q0, q1 = cirq.LineQubit.range(2) circuit = cirq.Circuit( cirq.CircuitOperation( cirq.FrozenCircuit( cirq.CX(q1, q0), cirq.measure(q0, key='a').with_tags('nocompile'), cirq.CX(q0, q1), cirq.measure(q1, key='b'), ))) dephased = cirq.dephase_measurements( circuit, context=cirq.TransformerContext(tags_to_ignore=('nocompile', ))) cirq.testing.assert_same_circuits( dephased, cirq.Circuit( cirq.CircuitOperation( cirq.FrozenCircuit( cirq.CX(q1, q0), cirq.measure(q0, key='a').with_tags('nocompile'), cirq.CX(q0, q1), cirq.KrausChannel.from_channel(cirq.phase_damp(1), key='b')(q1), ))), )
def optimized_for_sycamore( circuit: cirq.Circuit, *, qubit_map: Callable[[cirq.Qid], cirq.GridQubit] = lambda e: cast(cirq.GridQubit, e), optimizer_type: str = 'sqrt_iswap', tolerance: float = 1e-5, tabulation_resolution: Optional[float] = None, ) -> cirq.Circuit: """Optimizes a circuit for Google devices. Uses a set of optimizers that will compile to the proper gateset for the device (xmon, sqrt_iswap, or sycamore gates) and then use optimizers to compress the gate depth down as much as is easily algorithmically possible by merging rotations, ejecting Z gates, etc. Args: circuit: The circuit to optimize. qubit_map: Transforms the qubits (e.g. so that they are GridQubits). optimizer_type: A string defining the optimizations to apply. Possible values are 'xmon', 'xmon_partial_cz', 'sqrt_iswap', 'sycamore' tolerance: The tolerance passed to the various circuit optimization passes. tabulation_resolution: If provided, compute a gateset tabulation with the specified resolution and use it to approximately compile arbitrary two-qubit gates for which an analytic compilation is not known. Returns: The optimized circuit. Raises: ValueError: If the `optimizer_type` is not a supported type. """ copy = circuit.copy() if optimizer_type not in _TARGET_GATESETS: raise ValueError( f'{optimizer_type} is not an allowed type. Allowed ' f'types are: {_TARGET_GATESETS.keys()}' ) tabulation: Optional[cirq.TwoQubitGateTabulation] = None if tabulation_resolution is not None: tabulation = _gate_product_tabulation_cached(optimizer_type, tabulation_resolution) if optimizer_type in _TARGET_GATESETS: copy = cirq.optimize_for_target_gateset( circuit, gateset=_TARGET_GATESETS[optimizer_type](tolerance, tabulation), context=cirq.TransformerContext(deep=True), ) copy = cirq.merge_single_qubit_gates_to_phxz(copy, atol=tolerance) copy = cirq.eject_phased_paulis(copy, atol=tolerance) copy = cirq.eject_z(copy, atol=tolerance) copy = cirq.drop_negligible_operations(copy, atol=tolerance) ret = cirq.Circuit( (op.transform_qubits(qubit_map) for op in copy.all_operations()), strategy=cirq.InsertStrategy.EARLIEST, ) return ret
def test_two_qubit_compilation_merge_and_replace_to_target_gateset(): q = cirq.LineQubit.range(2) c_orig = cirq.Circuit( cirq.Moment(cirq.Z(q[1]), cirq.X(q[0])), cirq.Moment(cirq.CZ(*q).with_tags("no_compile")), cirq.Moment(cirq.Z.on_each(*q)), cirq.Moment(cirq.X(q[0])), cirq.Moment(cirq.CZ(*q)), cirq.Moment(cirq.Z.on_each(*q)), cirq.Moment(cirq.X(q[0])), ) cirq.testing.assert_has_diagram( c_orig, ''' 0: ───X───@['no_compile']───Z───X───@───Z───X─── │ │ 1: ───Z───@─────────────────Z───────@───Z─────── ''', ) c_new = cirq.optimize_for_target_gateset( c_orig, gateset=DummyCXTargetGateset(), context=cirq.TransformerContext(tags_to_ignore=("no_compile", )), ) cirq.testing.assert_has_diagram( c_new, ''' 0: ───X───@['no_compile']───X───@───Y───@───Z─── │ │ │ 1: ───Z───@─────────────────X───X───Y───X───Z─── ''', )
def assert_optimizes( before: cirq.Circuit, expected: cirq.Circuit, eject_parameterized: bool = False, *, with_context: bool = False, ): if cirq.has_unitary(before): cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( before, expected, atol=1e-8) context = cirq.TransformerContext( tags_to_ignore=("nocompile", )) if with_context else None circuit = cirq.eject_z(before, eject_parameterized=eject_parameterized, context=context) expected = cirq.eject_z(expected, eject_parameterized=eject_parameterized, context=context) cirq.testing.assert_same_circuits(circuit, expected) # And it should be idempotent. circuit = cirq.eject_z(before, eject_parameterized=eject_parameterized, context=context) cirq.testing.assert_same_circuits(circuit, expected)
def test_align_left_deep(): q1, q2 = cirq.LineQubit.range(2) c_nested = cirq.FrozenCircuit( [ cirq.Moment([cirq.X(q1)]), cirq.Moment([cirq.Y(q2)]), cirq.Moment([cirq.Z(q1), cirq.Y(q2).with_tags("nocompile")]), cirq.Moment([cirq.Y(q1)]), cirq.measure(q2, key='a'), cirq.Z(q1).with_classical_controls('a'), ] ) c_nested_aligned = cirq.FrozenCircuit( cirq.Moment(cirq.X(q1), cirq.Y(q2)), cirq.Moment(cirq.Z(q1)), cirq.Moment([cirq.Y(q1), cirq.Y(q2).with_tags("nocompile")]), cirq.measure(q2, key='a'), cirq.Z(q1).with_classical_controls('a'), ) c_orig = cirq.Circuit( c_nested, cirq.CircuitOperation(c_nested).repeat(6).with_tags("nocompile"), c_nested, cirq.CircuitOperation(c_nested).repeat(5).with_tags("preserve_tag"), ) c_expected = cirq.Circuit( c_nested_aligned, cirq.CircuitOperation(c_nested).repeat(6).with_tags("nocompile"), c_nested_aligned, cirq.CircuitOperation(c_nested_aligned).repeat(5).with_tags("preserve_tag"), ) context = cirq.TransformerContext(tags_to_ignore=["nocompile"], deep=True) cirq.testing.assert_same_circuits(cirq.align_left(c_orig, context=context), c_expected)
def test_transformer_stats_logger_show_levels(capfd): q = cirq.LineQubit.range(2) context = cirq.TransformerContext(logger=cirq.TransformerLogger()) initial_circuit = cirq.Circuit(cirq.H.on_each(*q), cirq.CNOT(*q)) _ = t1(initial_circuit, context=context) info_line = 'LogLevel.INFO Second INFO Log of T1' debug_line = 'LogLevel.DEBUG First Verbose Log of T1' warning_line = 'LogLevel.WARNING Third WARNING Log of T1' for level in [LogLevel.ALL, LogLevel.DEBUG]: context.logger.show(level) out, _ = capfd.readouterr() assert all(line in out for line in [info_line, debug_line, warning_line]) context.logger.show(LogLevel.INFO) out, _ = capfd.readouterr() assert info_line in out and warning_line in out and debug_line not in out context.logger.show(LogLevel.DEBUG) out, _ = capfd.readouterr() assert info_line in out and warning_line in out and debug_line in out context.logger.show(LogLevel.NONE) out, _ = capfd.readouterr() assert all(line not in out for line in [info_line, debug_line, warning_line])
def test_align_left_subset_of_operations(): q1 = cirq.NamedQubit('q1') q2 = cirq.NamedQubit('q2') tag = "op_to_align" c_orig = cirq.Circuit([ cirq.Moment([cirq.Y(q1)]), cirq.Moment([cirq.X(q2)]), cirq.Moment([cirq.X(q1).with_tags(tag)]), cirq.Moment([cirq.Y(q2)]), cirq.measure(*[q1, q2], key='a'), ]) c_exp = cirq.Circuit([ cirq.Moment([cirq.Y(q1)]), cirq.Moment([cirq.X(q1).with_tags(tag), cirq.X(q2)]), cirq.Moment(), cirq.Moment([cirq.Y(q2)]), cirq.measure(*[q1, q2], key='a'), ]) cirq.testing.assert_same_circuits( cirq.toggle_tags( cirq.align_left( cirq.toggle_tags(c_orig, [tag]), context=cirq.TransformerContext(tags_to_ignore=[tag]), ), [tag], ), c_exp, )
def test_merge_swap_rzz_and_2q_unitaries(): q = cirq.LineQubit.range(3) c_orig = cirq.Circuit( cirq.SWAP(*q[:2]), cirq.ZZ(*q[:2]) ** 0.5, cirq.ZZ(*q[:2]) ** 0.25, cirq.SWAP(*q[:2]), cirq.SWAP(q[0], q[2]).with_tags("ignore"), cirq.ZZ(q[0], q[2]) ** 0.75, cirq.Moment(cirq.H.on_each(*q)), cirq.CNOT(q[0], q[2]), cirq.CircuitOperation( cirq.FrozenCircuit( cirq.CNOT(*q[0:2]), cirq.H(q[0]), cirq.CZ(*q[:2]), ) ), cirq.CNOT(*q[1:3]), cirq.X(q[0]), cirq.ZZ(*q[:2]) ** 0.15, cirq.SWAP(*q[:2]), cirq.Moment(cirq.X(q[0]).with_tags("ignore"), cirq.Y(q[1])), cirq.CNOT(*q[:2]), strategy=cirq.InsertStrategy.NEW, ) cirq.testing.assert_has_diagram( c_orig, ''' [ 0: ───@───H───@─── ] 0: ───×───ZZ───────ZZ────────×───×['ignore']───ZZ────────H───@───[ │ │ ]───────X───ZZ────────×───X['ignore']───@─── │ │ │ │ │ │ │ [ 1: ───X───────@─── ] │ │ │ │ │ │ │ │ │ │ │ │ │ │ 1: ───×───ZZ^0.5───ZZ^0.25───×───┼─────────────┼─────────H───┼───#2───────────────────────@───────ZZ^0.15───×───Y─────────────X─── │ │ │ │ 2: ──────────────────────────────×─────────────ZZ^0.75───H───X────────────────────────────X─────────────────────────────────────── ''', ) c_new = sycamore_gateset.merge_swap_rzz_and_2q_unitaries( c_orig, context=cirq.TransformerContext(tags_to_ignore=("ignore",)), merged_swap_rzz_tag='swap_rzz', merged_2q_component_tag='2q_component', ) cirq.testing.assert_has_diagram( c_new, ''' [ [ 0: ───@───H───@─── ] ] [ 0: ───×───ZZ─────── ] [ 0: ───ZZ────────×─── ] [ 0: ───ZZ────────H───@─── ] [ 0: ───────[ │ │ ]───X─── ] [ 0: ───ZZ────────×─── ] [ 0: ───────@─── ] 0: ───[ │ │ ]───────────────────[ │ │ ]───────────────────×['ignore']───[ │ │ ]───────────────────────────[ [ 1: ───X───────@─── ] ]───────────────────────────[ │ │ ]───────────────────X['ignore']───[ │ ]─────────────────── [ 1: ───×───ZZ^0.5─── ]['swap_rzz'] [ 1: ───ZZ^0.25───×─── ]['swap_rzz'] │ [ 2: ───ZZ^0.75───H───X─── ]['2q_component'] [ │ ] [ 1: ───ZZ^0.15───×─── ]['swap_rzz'] [ 1: ───Y───X─── ]['2q_component'] │ │ │ │ [ 1: ───H───#2─────────────────────────── ]['2q_component'] │ │ │ │ │ │ │ │ │ 1: ───#2────────────────────────────────────────#2─────────────────────────────────────────┼─────────────┼──────────────────────────────────────────────────────#2────────────────────────────────────────────────────────────@───────#2───────────────────────────────────────────────────────#2─────────────────────────────────── │ │ │ 2: ────────────────────────────────────────────────────────────────────────────────────────×─────────────#2───────────────────────────────────────────────────────────────────────────────────────────────────────────────────X───────────────────────────────────────────────────────────────────────────────────────────────────── ''', )
def func( circuit: cirq.AbstractCircuit, *, context: Optional[cirq.TransformerContext] = cirq.TransformerContext(), atol: float = 1e-4, custom_arg: CustomArg = CustomArg(), ) -> cirq.FrozenCircuit: my_mock(circuit, context, atol, custom_arg) return circuit.freeze()
def assert_optimizes( before: cirq.Circuit, expected: cirq.Circuit, compare_unitaries: bool = True, eject_parameterized: bool = False, *, with_context: bool = False, ): context = cirq.TransformerContext(tags_to_ignore=("nocompile",)) if with_context else None circuit = cirq.eject_phased_paulis( before, eject_parameterized=eject_parameterized, context=context ) # They should have equivalent effects. if compare_unitaries: if cirq.is_parameterized(circuit): for a in (0, 0.1, 0.5, -1.0, np.pi, np.pi / 2): params = {'x': a, 'y': a / 2, 'z': -2 * a} ( cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( cirq.resolve_parameters(circuit, params), cirq.resolve_parameters(expected, params), 1e-8, ) ) else: ( cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( circuit, expected, 1e-8 ) ) # And match the expected circuit. assert circuit == expected, ( "Circuit wasn't optimized as expected.\n" "INPUT:\n" "{}\n" "\n" "EXPECTED OUTPUT:\n" "{}\n" "\n" "ACTUAL OUTPUT:\n" "{}\n" "\n" "EXPECTED OUTPUT (detailed):\n" "{!r}\n" "\n" "ACTUAL OUTPUT (detailed):\n" "{!r}" ).format(before, expected, circuit, expected, circuit) # And it should be idempotent. circuit = cirq.eject_phased_paulis( circuit, eject_parameterized=eject_parameterized, context=context ) assert circuit == expected
def __call__( self, circuit: cirq.AbstractCircuit, *, context: Optional[cirq.TransformerContext] = cirq.TransformerContext(), atol: float = 1e-4, custom_arg: CustomArg = CustomArg(), ) -> cirq.AbstractCircuit: self.mock(circuit, context, atol, custom_arg) return circuit[::-1]
def test_respects_nocompile_tags(): q = cirq.NamedQubit("q") c = cirq.Circuit( [cirq.Z(q), cirq.H(q), cirq.X(q), cirq.H(q), cirq.X(q).with_tags("nocompile"), cirq.H(q)] ) context = cirq.TransformerContext(tags_to_ignore=("nocompile",)) c = cirq.drop_empty_moments(cirq.merge_k_qubit_unitaries(c, k=1, context=context)) assert len(c) == 3 cirq.testing.assert_allclose_up_to_global_phase(cirq.unitary(c[0]), np.eye(2), atol=1e-7) assert c[1][q] == cirq.X(q).with_tags("nocompile") assert isinstance(c[-1][q].gate, cirq.MatrixGate)
def test_nocompile_context_leaves_invalid_circuit(): q0, q1 = cirq.LineQubit.range(2) circuit = cirq.Circuit( cirq.measure(q0, key='a').with_tags('nocompile'), cirq.X(q1).with_classical_controls('a'), cirq.measure(q1, key='b'), ) with pytest.raises(ValueError, match='Deferred measurement for key=a not found'): _ = cirq.defer_measurements( circuit, context=cirq.TransformerContext(tags_to_ignore=('nocompile',)) )
def test_does_not_clear_small_no_compile(): a = cirq.NamedQubit('a') circuit = cirq.Circuit( cirq.Moment((cirq.Z(a)**0.000001).with_tags(NO_COMPILE_TAG))) cirq.testing.assert_same_circuits( cirq.drop_negligible_operations( circuit, context=cirq.TransformerContext(tags_to_ignore=(NO_COMPILE_TAG, )), atol=0.001), circuit, )
def test_optimize_for_target_gateset(): q = cirq.LineQubit.range(4) c_orig = cirq.Circuit( cirq.QuantumFourierTransformGate(4).on(*q), cirq.Y(q[0]).with_tags("ignore"), cirq.Y(q[1]).with_tags("ignore"), cirq.CNOT(*q[2:]).with_tags("ignore"), cirq.measure(*q[:2], key="m"), cirq.CZ(*q[2:]).with_classical_controls("m"), cirq.inverse(cirq.QuantumFourierTransformGate(4).on(*q)), ) cirq.testing.assert_has_diagram( c_orig, ''' 0: ───qft───Y['ignore']───M───────qft^-1─── │ ║ │ 1: ───#2────Y['ignore']───M───────#2─────── │ ║ │ 2: ───#3────@['ignore']───╫───@───#3─────── │ │ ║ ║ │ 3: ───#4────X─────────────╫───@───#4─────── ║ ║ m: ═══════════════════════@═══^════════════ ''', ) gateset = MatrixGateTargetGateset() context = cirq.TransformerContext(tags_to_ignore=("ignore", )) c_new = cirq.optimize_for_target_gateset(c_orig, gateset=gateset, context=context) cirq.testing.assert_has_diagram( c_new, ''' ┌────────┐ ┌────────┐ ┌────────┐ 0: ───M[1]──────────M[1]──────────────────────M[1]────Y['ignore']───M────────M[1]───────────────────────────M[1]────M[1]───M[1]─── │ │ │ ║ │ │ │ │ 1: ───M[2]───M[1]───┼─────────────M[1]────M[1]┼───────Y['ignore']───M────────┼───M[1]───────────M[1]────M[1]┼───────┼──────M[2]─── │ │ │ │ │ ║ │ │ │ │ │ │ 2: ──────────M[2]───M[2]───M[1]───┼───────M[2]┼───────@['ignore']───╫───@────┼───M[2]────M[1]───┼───────M[2]┼───────M[2]────────── │ │ │ │ ║ ║ │ │ │ │ 3: ────────────────────────M[2]───M[2]────────M[2]────X─────────────╫───@────M[2]────────M[2]───M[2]────────M[2]────────────────── ║ ║ m: ═════════════════════════════════════════════════════════════════@═══^═════════════════════════════════════════════════════════ └────────┘ └────────┘ └────────┘ ''', ) with pytest.raises(ValueError, match="Unable to convert"): # Raises an error due to CCO and Measurement gate, which are not part of the gateset. _ = cirq.optimize_for_target_gateset(c_orig, gateset=gateset, context=context, ignore_failures=False)
def test_nocompile_context(): q0, q1 = cirq.LineQubit.range(2) circuit = cirq.Circuit( cirq.measure(q0, key='a').with_tags('nocompile'), cirq.X(q1).with_classical_controls('a').with_tags('nocompile'), cirq.measure(q1, key='b'), ) deferred = cirq.defer_measurements( circuit, context=cirq.TransformerContext(tags_to_ignore=('nocompile', ))) cirq.testing.assert_same_circuits(deferred, circuit)
def assert_optimizes(before, after, measure_only_moment=True, with_context=False): transformed_circuit = ( cirq.synchronize_terminal_measurements(before, after_other_operations=measure_only_moment) if not with_context else cirq.synchronize_terminal_measurements( before, context=cirq.TransformerContext(tags_to_ignore=(NO_COMPILE_TAG,)), after_other_operations=measure_only_moment, ) ) cirq.testing.assert_same_circuits(transformed_circuit, after)
def test_merge_single_qubit_moments_to_phxz_deep(): q = cirq.LineQubit.range(3) x_t_y = cirq.FrozenCircuit( cirq.Moment(cirq.X.on_each(*q[:2])), cirq.Moment(cirq.T.on_each(*q[1:])), cirq.Moment(cirq.Y.on_each(*q[:2])), ) c_nested = cirq.FrozenCircuit( x_t_y, cirq.Moment(cirq.CZ(*q[:2]), cirq.Y(q[2])), x_t_y, cirq.Moment(cirq.Y(q[0]).with_tags("ignore"), cirq.Z.on_each(*q[1:])), ) c_nested_merged = cirq.FrozenCircuit( [ _phxz(-0.25, 0.0, 0.75)(q[1]), _phxz(0.25, 0.0, 0.25)(q[2]), _phxz(-0.5, 0.0, -1.0)(q[0]) ], [cirq.CZ(q[0], q[1]), cirq.Y(q[2])], [ _phxz(-0.25, 0.0, 0.75)(q[1]), _phxz(0.25, 0.0, 0.25)(q[2]), _phxz(-0.5, 0.0, -1.0)(q[0]) ], cirq.Moment(cirq.Y(q[0]).with_tags("ignore"), cirq.Z.on_each(*q[1:])), ) c_orig = cirq.Circuit( c_nested, cirq.CircuitOperation(c_nested).repeat(4).with_tags("ignore"), c_nested, cirq.CircuitOperation(c_nested).repeat(5).with_tags("preserve_tags"), c_nested, cirq.CircuitOperation(c_nested).repeat(6), ) c_expected = cirq.Circuit( c_nested_merged, cirq.CircuitOperation(c_nested).repeat(4).with_tags("ignore"), c_nested_merged, cirq.CircuitOperation(c_nested_merged).repeat(5).with_tags( "preserve_tags"), c_nested_merged, cirq.CircuitOperation(c_nested_merged).repeat(6), ) context = cirq.TransformerContext(tags_to_ignore=["ignore"], deep=True) c_new = cirq.merge_single_qubit_moments_to_phxz(c_orig, context=context) cirq.testing.assert_allclose_up_to_global_phase(c_new.unitary(), c_expected.unitary(), atol=1e-7)
def test_decompose_operations_raises_on_stuck(): c_orig = cirq.Circuit(cirq.X(cirq.NamedQubit("q")).with_tags("ignore")) gateset = cirq.Gateset(cirq.Y) with pytest.raises(ValueError, match="Unable to convert"): _ = _decompose_operations_to_target_gateset(c_orig, gateset=gateset, ignore_failures=False) # Gates marked with a no-compile tag are completely ignored. c_new = _decompose_operations_to_target_gateset( c_orig, context=cirq.TransformerContext(tags_to_ignore=("ignore",)), gateset=gateset, ignore_failures=False, ) cirq.testing.assert_same_circuits(c_orig, c_new)
def test_optimize_for_target_gateset_deep(): q0, q1 = cirq.LineQubit.range(2) c_nested = cirq.FrozenCircuit(cirq.CX(q0, q1)) c_orig = cirq.Circuit( cirq.CircuitOperation( cirq.FrozenCircuit( cirq.H(q0), cirq.CircuitOperation(c_nested).repeat(3))).repeat(5)) c_expected = cirq.Circuit( cirq.CircuitOperation( cirq.FrozenCircuit( cirq.single_qubit_matrix_to_phxz(cirq.unitary( cirq.H(q0))).on(q0), cirq.CircuitOperation( cirq.FrozenCircuit( cirq.MatrixGate(c_nested.unitary(qubit_order=[q0, q1]), name="M").on(q0, q1))).repeat(3), )).repeat(5)) gateset = MatrixGateTargetGateset() context = cirq.TransformerContext(deep=True) c_new = cirq.optimize_for_target_gateset(c_orig, gateset=gateset, context=context) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( c_new, c_expected) cirq.testing.assert_has_diagram( c_orig, ''' [ [ 0: ───@─── ] ] [ 0: ───H───[ │ ]──────────── ] 0: ───[ [ 1: ───X─── ](loops=3) ]──────────── [ │ ] [ 1: ───────#2──────────────────────── ](loops=5) │ 1: ───#2────────────────────────────────────────────────── ''', ) cirq.testing.assert_has_diagram( c_new, ''' [ [ 0: ───M[1]─── ] ] [ 0: ───PhXZ(a=-0.5,x=0.5,z=-1)───[ │ ]──────────── ] 0: ───[ [ 1: ───M[2]─── ](loops=3) ]──────────── [ │ ] [ 1: ─────────────────────────────#2─────────────────────────── ](loops=5) │ 1: ───#2─────────────────────────────────────────────────────────────────────────── ''', )
def test_drop_terminal_nonterminal_error(): q0, q1 = cirq.LineQubit.range(2) circuit = cirq.Circuit( cirq.CircuitOperation( cirq.FrozenCircuit(cirq.measure(q0, q1, key='a~b', invert_mask=[0, 1]), cirq.CX(q0, q1)) ) ) with pytest.raises(ValueError, match='Circuit contains a non-terminal measurement'): _ = cirq.drop_terminal_measurements(circuit) with pytest.raises(ValueError, match='Context has `deep=False`'): _ = cirq.drop_terminal_measurements(circuit, context=cirq.TransformerContext(deep=False)) with pytest.raises(ValueError, match='Context has `deep=False`'): _ = cirq.drop_terminal_measurements(circuit, context=None)
def test_optimize_for_target_gateset_default(): q = cirq.LineQubit.range(2) c_orig = cirq.Circuit(cirq.T(q[0]), cirq.SWAP(*q), cirq.T(q[0]), cirq.SWAP(*q).with_tags("ignore")) context = cirq.TransformerContext(tags_to_ignore=("ignore", )) c_new = cirq.optimize_for_target_gateset(c_orig, context=context) cirq.testing.assert_has_diagram( c_new, ''' 0: ───T────────────@───Y^-0.5───@───Y^0.5────@───────────T───×['ignore']─── │ │ │ │ 1: ───────Y^-0.5───@───Y^0.5────@───Y^-0.5───@───Y^0.5───────×───────────── ''', ) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( c_orig, c_new, atol=1e-6)
def test_merge_swap_rzz_and_2q_unitaries_deep(): q = cirq.LineQubit.range(3) swap_rzz = cirq.FrozenCircuit(cirq.SWAP(*q[:2]), cirq.ZZ(*q[:2]) ** 0.5) rzz_swap = cirq.FrozenCircuit(cirq.ZZ(*q[1:]) ** 0.25, cirq.SWAP(*q[1:])) x_cnot_x = cirq.FrozenCircuit(cirq.X(q[0]), cirq.CNOT(*q[:2]), cirq.X(q[0])) x_cz_x = cirq.FrozenCircuit(cirq.X(q[2]), cirq.CZ(*q[1:]), cirq.X(q[2])) c_orig = cirq.Circuit( cirq.CircuitOperation(swap_rzz).repeat(3).with_tags("ignore"), cirq.CircuitOperation(rzz_swap).repeat(5).with_tags("preserve_tag"), cirq.CircuitOperation(x_cnot_x).repeat(7).with_tags("ignore"), cirq.CircuitOperation(x_cz_x).repeat(9).with_tags("preserve_tag"), cirq.CircuitOperation( cirq.FrozenCircuit( [swap_rzz, rzz_swap, x_cnot_x, x_cz_x], cirq.Moment(cirq.Y(qq).with_tags("ignore") for qq in q), ) ), ) t_swap_rzz = "_merged_swap_rzz_tag" t_2q_cmp = "_merged_2q_unitaries_component" t_all = "_intermediate_result_tag_apply_to_all" def _wrap_cop(c: cirq.FrozenCircuit, *tags) -> cirq.FrozenCircuit: return cirq.FrozenCircuit(cirq.CircuitOperation(c).with_tags(*tags, t_all)) c_expected = cirq.Circuit( cirq.CircuitOperation(swap_rzz).repeat(3).with_tags("ignore"), cirq.CircuitOperation(_wrap_cop(rzz_swap, t_swap_rzz)).repeat(5).with_tags("preserve_tag"), cirq.CircuitOperation(x_cnot_x).repeat(7).with_tags("ignore"), cirq.CircuitOperation(_wrap_cop(x_cz_x, t_2q_cmp)).repeat(9).with_tags("preserve_tag"), cirq.CircuitOperation( cirq.FrozenCircuit( [_wrap_cop(swap_rzz, t_swap_rzz), _wrap_cop(rzz_swap, t_swap_rzz)], [_wrap_cop(x_cnot_x, t_2q_cmp), _wrap_cop(x_cz_x, t_2q_cmp)], cirq.Moment(cirq.Y(qq).with_tags("ignore") for qq in q), ) ), ) context = cirq.TransformerContext(tags_to_ignore=["ignore"], deep=True) c_new = sycamore_gateset.merge_swap_rzz_and_2q_unitaries( c_orig, context=context, merged_swap_rzz_tag=t_swap_rzz, merged_2q_component_tag=t_2q_cmp, intermediate_result_tag=t_all, ) cirq.testing.assert_same_circuits(cirq.drop_empty_moments(c_new, context=context), c_expected)