Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cirq --> pyQuil transpiler error for XX, YY, ZZ gates #386

Open
ryanhill1 opened this issue Aug 30, 2023 · 2 comments
Open

Cirq --> pyQuil transpiler error for XX, YY, ZZ gates #386

ryanhill1 opened this issue Aug 30, 2023 · 2 comments
Labels
bug 🐛 Something isn't working good first issue Good for newcomers transpiler 🚊 Circuit conversions across program types unitaryhack Dedicated issue for UF open-source hackathon

Comments

@ryanhill1
Copy link
Member

ryanhill1 commented Aug 30, 2023

There is a bug transpiling Cirq circuits containing the XXPowGate, YYPowGate or ZZPowGate to pyQuil. Below is a self-contained example showing the bug for the XXPowGate:

import cirq

from qbraid.transpiler import transpile
from qbraid.interface import circuits_allclose

# Create a quantum circuit with two qubits
q0, q1 = cirq.LineQubit.range(2)
cirq_in = cirq.Circuit()

# Add XX, YY, and ZZ gates to the circuit
exponents = [0.5, 1]
for theta in exponents:
    cirq_in.append(cirq.XXPowGate(exponent=theta).on(q0, q1))

pyquil_program = transpile(cirq_in, "pyquil")
cirq_out = transpile(pyquil_program, "cirq")

cirq_roundtrip_equal = circuits_allclose(cirq_in, cirq_out)

print(f"Cirq input:\n{cirq_in}\n")
print(f"Cirq -> pyQuil:\n{pyquil_program}\n")
print(f"pyQuil -> Cirq:\n{cirq_out}\n")
print(f"Cirq expected output:\n{cirq_in}\n")
print(f"Cirq roundtrip unitaries equal: {cirq_roundtrip_equal}")
Cirq input:
0: ───XX───────XX───
      │        │
1: ───XX^0.5───XX───

Cirq -> pyQuil:
RX(pi/2) 0
RX(pi/2) 1
X 0
X 1


pyQuil -> Cirq:
0: ───Rx(0.5π)───X───

1: ───Rx(0.5π)───X───

Cirq expected output:
0: ───XX───────XX───
      │        │
1: ───XX^0.5───XX───

Cirq roundtrip unitaries equal: False
@ryanhill1 ryanhill1 added bug 🐛 Something isn't working transpiler 🚊 Circuit conversions across program types good first issue Good for newcomers labels Aug 30, 2023
ryanhill1 added a commit that referenced this issue Sep 1, 2023
@krpcannon
Copy link

Hi @ryanhill1 , would you kindly assign this issue to me? (or another 'good first issue' as you see fit)

@ryanhill1
Copy link
Member Author

ryanhill1 commented Sep 5, 2023

Hi @krpcannon, absolutely! Upon further investigation, this is actually a bug in cirq_rigetti.quil_output.py that we hope to create a work-around for. For example, cirq_rigetti maps the cirq.ops.XXPowGate to a function _xxpow_gate():

def _xxpow_gate(op: cirq.Operation, formatter: QuilFormatter) -> str:
    gate = cast(cirq.XPowGate, op.gate)
    if gate._exponent == 1:
        return formatter.format('X {0}\nX {1}\n', op.qubits[0], op.qubits[1])
    return formatter.format(
        'RX({0}) {1}\nRX({2}) {3}\n',
        gate._exponent * np.pi,
        op.qubits[0],
        gate._exponent * np.pi,
        op.qubits[1],
    )

which uses two PyQuil X gates (for exponent = 1), or two Rx gates (otherwise). In most cases, this mapping is does not create an output circuit with an equivalent unitary. So we want to re-implement this function in our duplicate qbraid.transpiler.conversions.cirq.cirq_quil_output.py and investigate which built-in PyQuil gate(s) can be used to construct an equivalent mapping. Where/if necessary, we can also fall back to an OpenQASM decomposition for the conversion, e.g.

>>> import cirq
>>> q0, q1 = cirq.LineQubit.range(2)
>>> circuit = cirq.Circuit()
>>> circuit.append(cirq.XXPowGate(exponent=0.5).on(q0,q1)
>>> print(circuit.to_qasm())
// Generated from Cirq v1.3.0.dev20230825224332

OPENQASM 2.0;
include "qelib1.inc";


// Qubits: [q(0), q(1)]
qreg q[2];


// Gate: XX**0.5
ry(pi*-0.5) q[0];
ry(pi*-0.5) q[1];
s q[0];
s q[1];
u3(pi*0.5,0,pi*1.25) q[0];
u3(pi*0.5,pi*1.0,pi*1.75) q[1];
sx q[0];
cx q[0],q[1];
rx(0) q[0];
ry(pi*0.5) q[1];
cx q[1],q[0];
sxdg q[1];
s q[1];
cx q[0],q[1];
u3(pi*0.5,pi*1.25,pi*1.0) q[0];
u3(pi*0.5,pi*0.75,0) q[1];
ry(pi*0.5) q[0];
ry(pi*0.5) q[1];

and converted the decomposed gate set. However, if there is a more compact solution, that would be preferred.

@ryanhill1 ryanhill1 added the unitaryhack Dedicated issue for UF open-source hackathon label May 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something isn't working good first issue Good for newcomers transpiler 🚊 Circuit conversions across program types unitaryhack Dedicated issue for UF open-source hackathon
Projects
None yet
Development

No branches or pull requests

2 participants