def test_sycamore_gateset_compiles_swap_zz(): qubits = cirq.LineQubit.range(3) gamma = np.random.randn() circuit1 = cirq.Circuit( cirq.SWAP(qubits[0], qubits[1]), cirq.Z(qubits[2]), cirq.ZZ(qubits[0], qubits[1])**gamma, strategy=cirq.InsertStrategy.NEW, ) circuit2 = cirq.Circuit( cirq.ZZ(qubits[0], qubits[1])**gamma, cirq.Z(qubits[2]), cirq.SWAP(qubits[0], qubits[1]), strategy=cirq.InsertStrategy.NEW, ) gateset = cirq_google.SycamoreTargetGateset() compiled_circuit1 = cirq.optimize_for_target_gateset(circuit1, gateset=gateset) compiled_circuit2 = cirq.optimize_for_target_gateset(circuit2, gateset=gateset) cirq.testing.assert_same_circuits(compiled_circuit1, compiled_circuit2) assert (len( list( compiled_circuit1.findall_operations_with_gate_type( cirq_google.SycamoreGate))) == 3) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( circuit1, compiled_circuit1, atol=1e-7)
def test_two_qubit_gates(gate: cirq.Gate, expected_length: int): """Tests that two qubit gates decompose to an equivalent and serializable circuit with the expected length (or less). """ q0 = cirq.GridQubit(5, 3) q1 = cirq.GridQubit(5, 4) original_circuit = cirq.Circuit(gate(q0, q1)) converted_circuit = original_circuit.copy() converted_circuit_iswap_inv = cirq.optimize_for_target_gateset( original_circuit, gateset=cirq.SqrtIswapTargetGateset(use_sqrt_iswap_inv=True)) converted_circuit_iswap = cirq.optimize_for_target_gateset( original_circuit, gateset=cirq.SqrtIswapTargetGateset()) with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'): cgoc.ConvertToSqrtIswapGates().optimize_circuit(converted_circuit) cig.SQRT_ISWAP_GATESET.serialize(converted_circuit) cig.SQRT_ISWAP_GATESET.serialize(converted_circuit_iswap) cig.SQRT_ISWAP_GATESET.serialize(converted_circuit_iswap_inv) assert len(converted_circuit) <= expected_length assert (len(converted_circuit_iswap) <= expected_length or len(converted_circuit_iswap_inv) <= expected_length) assert _unitaries_allclose(original_circuit, converted_circuit) assert _unitaries_allclose(original_circuit, converted_circuit_iswap) assert _unitaries_allclose(original_circuit, converted_circuit_iswap_inv)
def test_givens_rotation(): """Test if the sqrt_iswap synthesis for a givens rotation is correct""" thetas = np.linspace(0, 2 * np.pi, 100) qubits = [cirq.NamedQubit('a'), cirq.NamedQubit('b')] for theta in thetas: program = cirq.Circuit(cirq.givens(theta).on(qubits[0], qubits[1])) unitary = cirq.unitary(program) test_program = program.copy() with cirq.testing.assert_deprecated( "Use cirq.optimize_for_target_gateset", deadline='v1.0'): cgoc.ConvertToSqrtIswapGates().optimize_circuit(test_program) converted_circuit_iswap_inv = cirq.optimize_for_target_gateset( test_program, gateset=cirq.SqrtIswapTargetGateset(use_sqrt_iswap_inv=True)) converted_circuit_iswap = cirq.optimize_for_target_gateset( test_program, gateset=cirq.SqrtIswapTargetGateset()) for circuit in [ test_program, converted_circuit_iswap_inv, converted_circuit_iswap ]: circuit.append(cirq.IdentityGate(2).on(*qubits)) test_unitary = cirq.unitary(circuit) np.testing.assert_allclose( 4, np.abs( np.trace( np.conjugate(np.transpose(test_unitary)) @ unitary)))
def test_convert_to_cz_preserving_moment_structure(): q = cirq.LineQubit.range(5) op = lambda q0, q1: cirq.H(q1).controlled_by(q0) c_orig = cirq.Circuit( cirq.Moment(cirq.X(q[2])), cirq.Moment(op(q[0], q[1]), op(q[2], q[3])), cirq.Moment(op(q[2], q[1]), op(q[4], q[3])), cirq.Moment(op(q[1], q[2]), op(q[3], q[4])), cirq.Moment(op(q[3], q[2]), op(q[1], q[0])), cirq.measure(*q[:2], key="m"), cirq.X(q[2]).with_classical_controls("m"), cirq.CZ(*q[3:]).with_classical_controls("m"), ) c_new = cirq.optimize_for_target_gateset(c_orig, gateset=cirq.CZTargetGateset()) assert c_orig[-2:] == c_new[-2:] c_orig, c_new = c_orig[:-2], c_new[:-2] cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( c_orig, c_new, atol=1e-6) assert all( (all_gates_of_type(m, cirq.Gateset(cirq.AnyUnitaryGateFamily(1))) or all_gates_of_type(m, cirq.Gateset(cirq.CZ))) for m in c_new) c_new = cirq.optimize_for_target_gateset( c_orig, gateset=cirq.CZTargetGateset(allow_partial_czs=True), ignore_failures=False) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( c_orig, c_new, atol=1e-6) assert all( (all_gates_of_type(m, cirq.Gateset(cirq.AnyUnitaryGateFamily(1))) or all_gates_of_type(m, cirq.Gateset(cirq.CZPowGate))) for m in c_new)
def test_two_qubit_gates_with_symbols(gate: cirq.Gate, expected_length: int): """Tests that the gates with symbols decompose without error into a circuit that has an equivalent unitary form. """ q0 = cirq.GridQubit(5, 3) q1 = cirq.GridQubit(5, 4) original_circuit = cirq.Circuit(gate(q0, q1)) converted_circuit = original_circuit.copy() with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'): cgoc.ConvertToSqrtIswapGates().optimize_circuit(converted_circuit) converted_circuit_iswap_inv = cirq.optimize_for_target_gateset( original_circuit, gateset=cirq.SqrtIswapTargetGateset(use_sqrt_iswap_inv=True)) converted_circuit_iswap = cirq.optimize_for_target_gateset( original_circuit, gateset=cirq.SqrtIswapTargetGateset()) assert len(converted_circuit) <= expected_length assert (len(converted_circuit_iswap) <= expected_length or len(converted_circuit_iswap_inv) <= expected_length) # Check if unitaries are the same for val in np.linspace(0, 2 * np.pi, 12): assert _unitaries_allclose( cirq.resolve_parameters(original_circuit, {'t': val}), cirq.resolve_parameters(converted_circuit, {'t': val}), ) assert _unitaries_allclose( cirq.resolve_parameters(original_circuit, {'t': val}), cirq.resolve_parameters(converted_circuit_iswap, {'t': val}), ) assert _unitaries_allclose( cirq.resolve_parameters(original_circuit, {'t': val}), cirq.resolve_parameters(converted_circuit_iswap_inv, {'t': val}), )
def test_two_qubit_compilation_leaves_single_gates_in_gateset(): q = cirq.LineQubit.range(2) gateset = DummyCXTargetGateset() c = cirq.Circuit(cirq.X(q[0]) ** 0.5) cirq.testing.assert_same_circuits(cirq.optimize_for_target_gateset(c, gateset=gateset), c) c = cirq.Circuit(cirq.CNOT(*q[:2])) cirq.testing.assert_same_circuits(cirq.optimize_for_target_gateset(c, gateset=gateset), c)
def assert_optimization_not_broken(circuit: cirq.Circuit): c_new = cirq.optimize_for_target_gateset(circuit, gateset=cirq.CZTargetGateset()) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( circuit, c_new, atol=1e-6) c_new = cirq.optimize_for_target_gateset( circuit, gateset=cirq.CZTargetGateset(allow_partial_czs=True)) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( circuit, c_new, atol=1e-6)
def test_unsupported_gate(): class UnknownGate(cirq.testing.TwoQubitGate): pass q0, q1 = cirq.LineQubit.range(2) circuit = cirq.Circuit(UnknownGate()(q0, q1)) with pytest.raises(ValueError, match='Unable to convert'): cirq.optimize_for_target_gateset( circuit, gateset=cirq_google.SycamoreTargetGateset(), ignore_failures=False )
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_not_decompose_partial_czs(): circuit = cirq.Circuit( cirq.CZPowGate(exponent=0.1, global_shift=-0.5)(*cirq.LineQubit.range(2)), ) cirq.optimize_for_target_gateset(circuit, gateset=cirq.CZTargetGateset()) cz_gates = [ op.gate for op in circuit.all_operations() if isinstance(op, cirq.GateOperation) and isinstance(op.gate, cirq.CZPowGate) ] num_full_cz = sum(1 for cz in cz_gates if cz.exponent % 2 == 1) num_part_cz = sum(1 for cz in cz_gates if cz.exponent % 2 != 1) assert num_full_cz == 0 assert num_part_cz == 1
def test_composite_gates_without_matrix(): class CompositeDummy(cirq.SingleQubitGate): def _decompose_(self, qubits): yield cirq.X(qubits[0]) yield cirq.Y(qubits[0])**0.5 class CompositeDummy2(cirq.testing.TwoQubitGate): def _decompose_(self, qubits): yield cirq.CZ(qubits[0], qubits[1]) yield CompositeDummy()(qubits[1]) q0, q1 = cirq.LineQubit.range(2) circuit = cirq.Circuit( CompositeDummy()(q0), CompositeDummy2()(q0, q1), ) expected = cirq.Circuit( cirq.X(q0), cirq.Y(q0)**0.5, cirq.CZ(q0, q1), cirq.X(q1), cirq.Y(q1)**0.5, ) c_new = cirq.optimize_for_target_gateset(circuit, gateset=cirq.CZTargetGateset()) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( c_new, expected, atol=1e-6) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( c_new, circuit, atol=1e-6)
def test_decompose_multi_qubit_cirq_gates(gate, qubits): circuit = cirq.Circuit(gate(*cirq.LineQubit.range(qubits))) decomposed_circuit = cirq.optimize_for_target_gateset( circuit, gateset=ionq_target_gateset, ignore_failures=False) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( circuit, decomposed_circuit, atol=1e-8) assert ionq_target_gateset.validate(decomposed_circuit)
def test_avoids_decompose_when_matrix_available(): class OtherXX(cirq.testing.TwoQubitGate): # coverage: ignore def _has_unitary_(self) -> bool: return True def _unitary_(self) -> np.ndarray: m = np.array([[0, 1], [1, 0]]) return np.kron(m, m) def _decompose_(self, qubits): assert False class OtherOtherXX(cirq.testing.TwoQubitGate): # coverage: ignore def _has_unitary_(self) -> bool: return True def _unitary_(self) -> np.ndarray: m = np.array([[0, 1], [1, 0]]) return np.kron(m, m) def _decompose_(self, qubits): assert False a, b = cirq.LineQubit.range(2) c = cirq.Circuit(OtherXX()(a, b), OtherOtherXX()(a, b)) c = cirq.optimize_for_target_gateset(c, gateset=cirq.CZTargetGateset()) assert len(c) == 0
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 test_convert_to_sycamore_gates_fsim(): q0, q1 = cirq.LineQubit.range(2) circuit = cirq.Circuit( cirq.FSimGate(theta=np.pi / 2, phi=np.pi / 6)(q0, q1)) compiled_circuit = cirq.optimize_for_target_gateset( circuit, gateset=cirq_google.SycamoreTargetGateset()) cirq.testing.assert_same_circuits(circuit, compiled_circuit)
def decompose_to_device(operation: cirq.Operation, atol: float = 1e-8) -> cirq.OP_TREE: """Decompose operation to ionq native operations. Merges single qubit operations and decomposes two qubit operations into CZ gates. Args: operation: `cirq.Operation` to decompose. atol: absolute error tolerance to use when declaring two unitary operations equal. Returns: cirq.OP_TREE containing decomposed operations. Raises: ValueError: If supplied operation cannot be decomposed for the ionq device. """ return cirq.optimize_for_target_gateset( cirq.Circuit(operation), gateset=ionq_gateset.IonQTargetGateset(), ignore_failures=False).all_operations()
def test_avoids_decompose_fallback_when_matrix_available_two_qubit(): class OtherCZ(cirq.testing.TwoQubitGate): def _unitary_(self) -> np.ndarray: return np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]]) class OtherOtherCZ(cirq.testing.TwoQubitGate): def _decompose_(self, qubits): return OtherCZ().on(*qubits) q00 = cirq.GridQubit(0, 0) q01 = cirq.GridQubit(0, 1) c = cirq.Circuit(OtherCZ().on(q00, q01), OtherOtherCZ().on(q00, q01)) expected_diagram = """ (0, 0): ───@───@─── │ │ (0, 1): ───@───@─── """ converted = cirq.optimize_for_target_gateset( c, gateset=cirq.neutral_atoms.NeutralAtomGateset()) cirq.testing.assert_has_diagram(converted, expected_diagram) with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v0.16', count=2): cirq.neutral_atoms.ConvertToNeutralAtomGates().optimize_circuit(c) cirq.testing.assert_has_diagram(c, expected_diagram)
def test_two_qubit_gates_with_symbols(gate: cirq.Gate, use_sqrt_iswap_inv: bool): # Note that even though these gates are not natively supported by # `cirq.parameterized_2q_op_to_sqrt_iswap_operations`, the transformation succeeds because # `cirq.optimize_for_target_gateset` also relies on `cirq.decompose` as a fallback. c_orig = cirq.Circuit(gate(*cirq.LineQubit.range(2))) c_new = cirq.optimize_for_target_gateset( c_orig, gateset=cirq.SqrtIswapTargetGateset( use_sqrt_iswap_inv=use_sqrt_iswap_inv, additional_gates=[cirq.XPowGate, cirq.YPowGate, cirq.ZPowGate], ), ignore_failures=False, ) # Check that `c_new` only contains sqrt iswap as the 2q entangling gate. sqrt_iswap_gate = cirq.SQRT_ISWAP_INV if use_sqrt_iswap_inv else cirq.SQRT_ISWAP for op in c_new.all_operations(): if cirq.num_qubits(op) == 2: assert op.gate == sqrt_iswap_gate # Check if unitaries are the same for val in np.linspace(0, 2 * np.pi, 10): cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( cirq.resolve_parameters(c_orig, {'t': val}), cirq.resolve_parameters(c_new, {'t': val}), atol=1e-6, )
def assert_optimizes(before: cirq.Circuit, expected: cirq.Circuit, **kwargs): cirq.testing.assert_same_circuits( cirq.optimize_for_target_gateset( before, gateset=cirq.SqrtIswapTargetGateset(**kwargs), ignore_failures=False ), expected, )
def test_optimizes_single_inv_sqrt_iswap_require3(): a, b = cirq.LineQubit.range(2) c = cirq.Circuit(cirq.SQRT_ISWAP_INV(a, b)) assert_optimization_not_broken(c, required_sqrt_iswap_count=3) c = cirq.optimize_for_target_gateset( c, gateset=cirq.SqrtIswapTargetGateset(required_sqrt_iswap_count=3)) assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 3
def test_optimizes_single_iswap_require0(): a, b = cirq.LineQubit.range(2) c = cirq.Circuit(cirq.CNOT(a, b), cirq.CNOT(a, b)) # Minimum 0 sqrt-iSWAP assert_optimization_not_broken(c, required_sqrt_iswap_count=0) c = cirq.optimize_for_target_gateset( c, gateset=cirq.SqrtIswapTargetGateset(required_sqrt_iswap_count=0)) assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 0
def test_optimizes_single_iswap(): a, b = cirq.LineQubit.range(2) c = cirq.Circuit(cirq.ISWAP(a, b)) assert_optimization_not_broken(c) c = cirq.optimize_for_target_gateset(c, gateset=cirq.SqrtIswapTargetGateset()) assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 2
def test_optimizes_single_iswap_require3(): a, b = cirq.LineQubit.range(2) c = cirq.Circuit(cirq.ISWAP(a, b)) # Minimum 2 sqrt-iSWAP but 3 possible assert_optimization_not_broken(c, required_sqrt_iswap_count=3) c = cirq.optimize_for_target_gateset( c, gateset=cirq.SqrtIswapTargetGateset(required_sqrt_iswap_count=3), ignore_failures=False ) assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 3
def test_optimizes_single_inv_sqrt_iswap(): a, b = cirq.LineQubit.range(2) c = cirq.Circuit(cirq.SQRT_ISWAP_INV(a, b)) assert_optimization_not_broken(c) c = cirq.optimize_for_target_gateset( c, gateset=cirq.SqrtIswapTargetGateset(), ignore_failures=False ) assert len([1 for op in c.all_operations() if len(op.qubits) == 2]) == 1
def test_convert_to_sycamore_equivalent_unitaries(gate): circuit = cirq.Circuit(gate.on(*cirq.LineQubit.range(2))) converted_circuit = cirq.optimize_for_target_gateset( circuit, gateset=cirq_google.SycamoreTargetGateset() ) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( circuit, converted_circuit, atol=1e-8 )
def test_optimizes_tagged_partial_cz(): a, b = cirq.LineQubit.range(2) c = cirq.Circuit((cirq.CZ**0.5)(a, b).with_tags('mytag')) assert_optimization_not_broken(c) c = cirq.optimize_for_target_gateset(c, gateset=cirq.CZTargetGateset()) assert (len([ 1 for op in c.all_operations() if len(op.qubits) == 2 ]) == 2), 'It should take 2 CZ gates to decompose a CZ**0.5 gate'
def test_gateset(op: cirq.Operation, is_in_gateset: bool): gateset = nag.NeutralAtomGateset(max_parallel_z=4, max_parallel_xy=3) assert gateset.validate(op) == is_in_gateset converted_ops = cirq.optimize_for_target_gateset(cirq.Circuit(op), gateset=gateset) if is_in_gateset: assert converted_ops == cirq.Circuit(op) assert gateset.validate(converted_ops)
def test_optimizes_single_iswap_require2_raises(): a, b = cirq.LineQubit.range(2) c = cirq.Circuit(cirq.SWAP(a, b)) # Minimum 3 sqrt-iSWAP with pytest.raises(ValueError, match='cannot be decomposed into exactly 2 sqrt-iSWAP gates'): c = cirq.optimize_for_target_gateset( c, gateset=cirq.SqrtIswapTargetGateset(required_sqrt_iswap_count=2), ignore_failures=False, )
def assert_optimization_not_broken( circuit: cirq.Circuit, required_sqrt_iswap_count: Optional[int] = None): c_new = cirq.optimize_for_target_gateset( circuit, gateset=cirq.SqrtIswapTargetGateset( required_sqrt_iswap_count=required_sqrt_iswap_count), ) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( circuit, c_new, atol=1e-6) c_new = cirq.optimize_for_target_gateset( circuit, gateset=cirq.SqrtIswapTargetGateset( use_sqrt_iswap_inv=True, required_sqrt_iswap_count=required_sqrt_iswap_count), ) cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent( circuit, c_new, atol=1e-6)