Open exAClior opened 2 years ago
Hey @exAClior, thanks for reporting the issue! Just to be clear, you're looking for the Qiskit integration to decompose to native OpenQASM gates that can be represented in Qiskit?
Currently, the process of decomposition happens within quilc
after translation from OpenQASM to Quil. So there is a way to get to the native Quil gates, but not the native OpenQASM gates. I don't believe we currently have a way to translate back from Quil, so getting back to native OpenQASM gates would be a pretty big lift.
Was that a feature you're asking for? Sorry if I misunderstood the question 😁
Hello @dbanty, thank you for getting back to me! Let me try to clarify.
Please correct me if I am wrong about this. Rigetti machine supports gates like "XYGate". This is great and I would like to play with it.
I can create a circuit with XYGate in it using Qiskit integration. But the problem is: Qiskit integration seem to require a transpile process before running the circuit on the machine. Using Qiskit integration, Rigetti backend has a basis gateset of "u1,u2,u3,CX". Notice this gateset does not contain XYGate. So the circuit send to Rigetti machine does not contain the XYGate anymore, but the gates equivalent to XYGate in terms of CX and U3. From your feedback, it looks like quilc will do another transpilation but I am not sure if the result circuit will be the one that I want to run.
What I would like to request is that Qiskit Integration does not transpile using basis gateset ['u1','u2','u3','CX'], but the physical gate that will be run on Rigetti's machine! Like XYGate, CZGate, etc. Does it make sense?
Hey, @exAClior.
I'm not overly familiar with our Qiskit integration, but I think I understand your problem. The integration defines the basis with basis_gates=["u1", "u2", "u3", "cx", "id"]
, which, IIUC, means that Qiskit's transpiler will decompose the circuit into these gates. Therefore, any use of XYGate
in your circuit is decomposed into some CX
and some local rotations. (That is also true of CZGate
.) And what you would like to see is XYGate
and CZGate
preserved in the transpiled circuit?
Hello @notmgsk, yes! That's what I wanted to do. Would it be possible to do so?
I see, sorry for the misunderstanding. Yes, we should definitely have our basis_gates
set to all the things we can natively run & translate. Looks like the gates are defined in terms of OpenQASM, so we'll just have to verify which of those gates correlate to XYGate
and CZGate
.
@exAClior do you have a minimal Qiskit program we can use to reproduce this and add in as a new test?
Hello @dbanty, I finally see your point in the first post. Sorry for the nonsense I posted above. Allow me to summarize.
QuilCircuit
. QuilCircuit
gets transpiled and all gates in it are converted into a combination of gates from the basis gateset. quilc
to translate OpenQASM into Quil. Now, CZGate
is very simple to decompose. The basic logic is described below
czcirc = QuilCircuit(2,2)
target_qbit = 1
control_qbit = 0
czcirc.h(target_qbit)
czcirc.cx(control_qbit,target_qbit)
czcirc.h(target_qbit)
XYGate
is a little more complicated. But it could be done as such.
xycirc = QuilCircuit(2, 2)
theta = 0.1
target_qbit = 1
control_qbit = 0
xycirc.u2(0, np.pi / 2, control_qbit)
xycirc.cx(control_qbit, target_qbit)
xycirc.u3(np.pi - 0.5 * theta, 3 * np.pi / 2, 0, control_qbit)
xycirc.u2(-np.pi / 2 - 0.5 * theta, np.pi / 2, target_qbit)
xycirc.cx(control_qbit, target_qbit)
xycirc.u2(-np.pi / 2, np.pi / 2, control_qbit)
xycirc.u2(-np.pi / 2, np.pi / 2, target_qbit)
Eventually, I would like to have the following test pass.
from qiskit_rigetti import RigettiQCSProvider, QuilCircuit
from qiskit import QuantumRegister
from qiskit.circuit import Qubit
from qiskit.circuit.library import CZGate
from qiskit_rigetti.gates import XYGate
from qiskit import transpile
def test_transpile():
"""Test whether XYGate and CZGate remains after the transpile."""
theta = 0.4
p = RigettiQCSProvider()
simulator = p.get_simulator(num_qubits=4, noisy=True) # or
circuit = QuilCircuit(4, 4)
circuit.xy(theta, 0, 1)
circuit.cz(2, 3)
circuit = transpile(circuit, backend=simulator)
circuit.draw('mpl')
assert len(circuit.data) == 2
assert circuit.data[0] == (
XYGate(theta),
[Qubit(QuantumRegister(4, "q"), 0),
Qubit(QuantumRegister(4, "q"), 1)],
[],
)
assert circuit.data[1] == (
CZGate(),
[Qubit(QuantumRegister(4, "q"), 0),
Qubit(QuantumRegister(4, "q"), 1)],
[],
)
@exAClior thanks for all that input. I've started working on a solution to this, though I've hit a bit of a wall. Qiskit defines CZGate
so I was able to inspect it to see that the underlying OpenQASM gate is cz
and add that to the basis. This appears to retain the gate after the transpile
call and still works when executing on QVM.
However, it looks like we've defined the XYGate
as a matrix—not as pointing to an underlying OpenQASM gate. So I'm not sure how we could retain this in OpenQASM. Is there an OpenQASM gate I'm not aware of which is equivalent to XYGate
?
@dbanty This problem actually came up when I was thinking about the solution too! Hence, I said my first two posts are nonsense.
I believe OpenQASM does not have an equivalent gate. This paper https://arxiv.org/abs/2104.14722 seems to indicate that you would have to create an OpenQASM XYGate and provide its decomposition in terms of the existing OpenQASM gates. This sounds like it will create a huge loop and transpile
will lead us to what we begin with.
I see, so maybe the best we can do, then, is to support the OpenQASM cz
in our basis_gates
and leave XY alone for now.
Yeah, I agree.
@exAClior I created #35 to add cz
to our basis gates. Can you test out that branch with some real circuits to make sure it does what you're expecting?
@dbanty Sorry for the delay, I tested it on a few circuits. I think they are doing what I expect. Thank you for fixing this!
Issue
Rigetti hardware provides XYGate and CZ natively. QuantumCircuit that contains CX gate should be transpiled into those for a more accurate representation of what's being run on the hardware. Currently, circuit is being transpiled to the basis gateset of ['u1','u2','u3','cx']. This appears misleading.