rigetti / qiskit-rigetti

Qiskit provider serving Rigetti hardware & simulator backends.
Apache License 2.0
9 stars 6 forks source link

Backend basis gate does not match with those provided by Hardware #34

Open exAClior opened 2 years ago

exAClior commented 2 years ago

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.

dbanty commented 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 😁

exAClior commented 2 years ago

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?

notmgsk commented 2 years ago

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?

exAClior commented 2 years ago

Hello @notmgsk, yes! That's what I wanted to do. Would it be possible to do so?

dbanty commented 2 years ago

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?

exAClior commented 2 years ago

Hello @dbanty, I finally see your point in the first post. Sorry for the nonsense I posted above. Allow me to summarize.

  1. User constructs a QuilCircuit.
  2. QuilCircuit gets transpiled and all gates in it are converted into a combination of gates from the basis gateset.
  3. The transpiled circuit is then converted into OpenQASM and sent to Rigetti's machine.
  4. Rigetti uses quilc to translate OpenQASM into Quil.
  5. Quil instructions are run on the machine.

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)],
        [],
    )
dbanty commented 2 years ago

@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?

exAClior commented 2 years ago

@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.

dbanty commented 2 years ago

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.

exAClior commented 2 years ago

Yeah, I agree.

dbanty commented 2 years ago

@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?

exAClior commented 2 years ago

@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!