Skip to content

Commit

Permalink
Adds basic PhasedISwapPow gate to Sycamore decomposition function (#2629
Browse files Browse the repository at this point in the history
)

[EDITED] This algorithm works as follows: 
  - If `exponent` is 1, decompose the circuit into `ZPowGate`s and an `ISWAP`, which takes 12 one-qubit operations and 3 applications of the Sycamore gate.
  - Othwerise, if `phase_exponent` is .25, decompose the circuit into a static set of gates with coefficient, which takes 19 one-qubit operations and 4 applications of the Sycamore gate. This is the one that was in Cirq Internal.
  - If neither of these constraints are satisfied, throw an error.
  • Loading branch information
KevinVillela authored and CirqBot committed Dec 17, 2019
1 parent 933329b commit 5968ccd
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 2 deletions.
92 changes: 92 additions & 0 deletions cirq/google/optimizers/convert_to_sycamore_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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):
Expand Down
20 changes: 18 additions & 2 deletions cirq/google/optimizers/convert_to_sycamore_gates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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)
], *[
Expand Down

0 comments on commit 5968ccd

Please sign in to comment.