diff --git a/cirq/google/optimizers/convert_to_sycamore_gates.py b/cirq/google/optimizers/convert_to_sycamore_gates.py index ed7d576bdde..a6504c33c51 100644 --- a/cirq/google/optimizers/convert_to_sycamore_gates.py +++ b/cirq/google/optimizers/convert_to_sycamore_gates.py @@ -169,6 +169,17 @@ def known_two_q_operations_to_sycamore_operations( New operations iterable object """ gate = op.gate + if isinstance(gate, ops.PhasedISwapPowGate): + if math.isclose(gate.exponent, 1): + return decompose_phased_iswap_into_syc(gate.phase_exponent, qubit_a, + qubit_b) + elif math.isclose(gate.phase_exponent, .25): + return decompose_phased_iswap_into_syc_precomputed( + gate.exponent * np.pi / 2, qubit_a, qubit_b) + else: + raise ValueError( + "To decompose PhasedISwapPowGate, it must have a phase_exponent" + " of .25 OR an exponent of 1.0, but got: {!r}".format(op)) if isinstance(gate, ops.CNotPowGate): return [ ops.Y(qubit_b)**-0.5, @@ -201,6 +212,87 @@ def known_two_q_operations_to_sycamore_operations( raise ValueError("Unrecognized gate: {!r}".format(op)) +def decompose_phased_iswap_into_syc(phase_exponent: float, a: ops.Qid, + b: ops.Qid): + """Decompose PhasedISwap with an exponent of 1. + + This should only be called if the Gate has an exponent of 1 - otherwise, + decompose_phased_iswap_into_syc_precomputed should be used instead. The + advantage of using this function is that the resulting circuit will be + smaller. + + Args: + phase_exponent: The exponent on the Z gates. + a: First qubit id to operate on + b: Second qubit id to operate on + Returns: + a Cirq program implementing the Phased ISWAP gate + + """ + + yield ops.Z(a)**phase_exponent, + yield ops.Z(b)**-phase_exponent, + yield decompose_iswap_into_syc(a, b), + yield ops.Z(a)**-phase_exponent, + yield ops.Z(b)**phase_exponent, + + +def decompose_phased_iswap_into_syc_precomputed(theta: float, a: ops.Qid, + b: ops.Qid): + """Decompose PhasedISwap into sycamore gates using precomputed coefficients. + + This should only be called if the Gate has a phase_exponent of .25. If the + gate has an exponent of 1, decompose_phased_iswap_into_syc should be used + instead. Converting PhasedISwap gates to Sycamore is not supported if + neither of these constraints are satsified. + + This synthesize a PhasedISwap in terms of four sycamore gates. This + compilation converts the gate into a circuit involving two CZ gates, which + themselves are each represented as two Sycamore gates and single-qubit + rotations + + Args: + theta: rotation parameter + a: First qubit id to operate on + b: Second qubit id to operate on + Returns: + a Cirq program implementing the Phased ISWAP gate + + """ + + yield ops.PhasedXPowGate(phase_exponent=0.41175161497166024, + exponent=0.5653807577895922).on(a) + yield ops.PhasedXPowGate(phase_exponent=1.0, exponent=0.5).on(b), + yield (ops.Z**0.7099892314883478).on(b), + yield (ops.Z**0.6746023442550453).on(a), + yield SycamoreGate().on(a, b) + yield ops.PhasedXPowGate(phase_exponent=-0.5154334589432878, + exponent=0.5228733015013345).on(b) + yield ops.PhasedXPowGate(phase_exponent=0.06774925307475355).on(a) + yield SycamoreGate().on(a, b), + yield ops.PhasedXPowGate(phase_exponent=-0.5987667922766213, + exponent=0.4136540654256824).on(a) + yield (ops.Z**-0.9255092746611595).on(b) + yield (ops.Z**-1.333333333333333).on(a) + yield ops.rx(-theta).on(a) + yield ops.rx(-theta).on(b) + + yield ops.PhasedXPowGate(phase_exponent=0.5678998743900456, + exponent=0.5863459345743176).on(a) + yield ops.PhasedXPowGate(phase_exponent=0.3549946157441739).on(b) + yield SycamoreGate().on(a, b) + yield ops.PhasedXPowGate(phase_exponent=-0.5154334589432878, + exponent=0.5228733015013345).on(b) + yield ops.PhasedXPowGate(phase_exponent=0.06774925307475355).on(a) + yield SycamoreGate().on(a, b) + yield ops.PhasedXPowGate(phase_exponent=-0.8151665352515929, + exponent=0.8906746535691492).on(a) + yield ops.PhasedXPowGate(phase_exponent=-0.07449072533884049, + exponent=0.5).on(b) + yield (ops.Z**-0.9255092746611595).on(b) + yield (ops.Z**-0.9777346353961884).on(a) + + def decompose_arbitrary_into_syc_tabulation(qubit_a: ops.Qid, qubit_b: ops.Qid, op: ops.GateOperation, tabulation: GateTabulation): diff --git a/cirq/google/optimizers/convert_to_sycamore_gates_test.py b/cirq/google/optimizers/convert_to_sycamore_gates_test.py index fbf79cc764a..be2a3ccb099 100644 --- a/cirq/google/optimizers/convert_to_sycamore_gates_test.py +++ b/cirq/google/optimizers/convert_to_sycamore_gates_test.py @@ -64,6 +64,18 @@ class UnknownGate(cirq.TwoQubitGate): cgoc.ConvertToSycamoreGates().optimize_circuit(circuit) +def test_unsupported_phased_iswap(): + """Tests that a Phased ISwap with a provided phase_exponent and exponent is + not supported.""" + q0 = cirq.LineQubit(0) + q1 = cirq.LineQubit(1) + circuit = cirq.Circuit( + cirq.PhasedISwapPowGate(exponent=0.5, phase_exponent=.33)(q0, q1)) + with pytest.raises(ValueError, + match='phase_exponent of .25 OR an exponent of 1'): + cgoc.ConvertToSycamoreGates().optimize_circuit(circuit) + + def test_non_gate_operation(): class UnknownOperation(cirq.Operation): @@ -211,8 +223,12 @@ def test_known_two_q_operations_to_sycamore_operations_cnot(): @pytest.mark.parametrize('gate', [ - cirq.MatrixGate(cirq.unitary(cirq.CX), qid_shape=(2, 2)), cirq.ISWAP, - cirq.SWAP, cirq.CNOT, cirq.CZ, *[ + cirq.MatrixGate(cirq.unitary( + cirq.CX), qid_shape=(2, 2)), cirq.ISWAP, cirq.SWAP, cirq.CNOT, cirq.CZ, + cirq.PhasedISwapPowGate(exponent=1.0), + cirq.PhasedISwapPowGate(exponent=1.0, phase_exponent=.33), + cirq.PhasedISwapPowGate(exponent=.66, phase_exponent=.25), + *[cirq.givens(theta) for theta in np.linspace(0, 2 * np.pi, 30)], *[ cirq.ZZPowGate(exponent=2 * phi / np.pi) for phi in np.linspace(0, 2 * np.pi, 30) ], *[