Compiled quantum circuits in qasm format

import pennylane as qml

dev = qml.device('default.qubit', wires=[0, 1, 2, 3, 4])

@qml.qnode(dev)
def circuit():
    qml.RX(0.5, wires=[0])
    qml.CZ(wires=[0, 4])
    qml.RZ(0.2, wires=[1])
    return qml.probs()

transpiled_circuit = qml.transforms.transpile(circuit, coupling_map=[(0, 2), (1, 2), (2, 3), (2, 4)])

compiled_circuit = qml.compile(
    transpiled_circuit,
    pipeline=[
        qml.transforms.commute_controlled,
        qml.transforms.merge_rotations,
        qml.transforms.cancel_inverses,
    ],
    basis_set=["CNOT", "RX", "RZ"],
)

print(qml.draw(compiled_circuit)())

qml_to_qasm_circuit = compiled_circuit.qtape.to_openqasm()
print(qml_to_qasm_circuit)

Hello pennylane team,

I am trying to generate a qasm file for a compiled quantum circuit. Printing the circuit actually gives me the desired outcome (see first print statement). However, when I try to convert the circuit into qasm format, it always returns the original, uncompiled circuit. Is there something obvious I am missing out?

Thanks in advance for your help!

James

Name: PennyLane Version: 0.36.0

Hi @James , welcome to the Forum!

I can replicate your issue and I’m not sure what’s causing this.
When I run qml.specs(compiled_circuit)() I can see that it’s still showing the CZ.
I’ll forward this for our team to investigate next week.

In the meantime maybe you can try with a custom decomposition as described here in the docs to see if it solves your issue for now.

Let me know if this helps!

Hi @CatalinaAlbornoz ,

Thanks a lot for your reply.

Unfortunately, I still get the original circuit instead of the decomposed one.

Thanks for reporting this @James.

Your question has sparked really good conversations in the team and it seems it will lead to new and better functions for this in future PennyLane releases!

In the meantime, using qml.workflow.construct_batch should work for your particular use case.

(compiled_tape,), _ = qml.workflow.construct_batch(compiled_circuit)()
qml_to_qasm_circuit = compiled_tape.to_openqasm()
print(qml_to_qasm_circuit)

Let me know if this works for you!

Hi @CatalinaAlbornoz ,

Yes, now I get the correct output, thanks a lot.

Now I have the problem that the compiled circuit does not have the desired gateset. When I run the script, I get a compiled circuit that still has an RY gate. Even if I use the custom decomposition method, the unwanted RY gate still remains.

import pennylane as qml
import numpy as np

dev = qml.device('default.qubit', wires=[0, 1, 2, 3, 4])

@qml.qnode(dev)
def circuit():
    qml.RX(0.5, wires=[0])
    qml.CZ(wires=[0, 4])
    qml.RY(0.2, wires=[1])
    return qml.probs()

transpiled_circuit = qml.transforms.transpile(circuit, coupling_map=[(0, 2), (1, 2), (2, 3), (2, 4)])

compiled_circuit = qml.compile(
    transpiled_circuit,
    pipeline=[
        qml.transforms.commute_controlled,
        qml.transforms.merge_rotations,
        qml.transforms.cancel_inverses,
    ],
    basis_set=["CNOT", "RX", "RZ"],
)

def custom_ry(wires, theta):
    return [
        qml.RX(-np.pi/2, wires=wires[0]),
        qml.RZ(theta, wires=wires[0]),
        qml.RX(np.pi/2, wires=wires[0])
    ]

custom_decomps = {qml.RY: custom_ry}
decomp_dev = qml.device("default.qubit", wires=[0, 1, 2, 3, 4], custom_decomps=custom_decomps)
decomp_qnode = qml.QNode(compiled_circuit, decomp_dev)

print(qml.draw(decomp_qnode)())

(compiled_tape,), _ = qml.workflow.construct_batch(decomp_qnode)()
qml_to_qasm_circuit = compiled_tape.to_openqasm()
print(qml_to_qasm_circuit)

Hi @James, I can replicate your error.

Let me see how we can fix this.

Hi @James ,

My colleague Christina found a solution!

In qml.workflow.construct_batch add level="device".

Also, before you were creating a QNode from a QNode so the code below should actually work now.

import pennylane as qml
import numpy as np

def custom_ry(theta, wires):
    return [
        qml.RX(-np.pi/2, wires=wires[0]),
        qml.RZ(theta, wires=wires[0]),
        qml.RX(np.pi/2, wires=wires[0])
    ]

custom_decomps = {qml.RY: custom_ry}
decomp_dev = qml.device("default.qubit", wires=[0, 1, 2, 3, 4], custom_decomps=custom_decomps)

@qml.qnode(decomp_dev)
def decomp_circ():
    qml.RX(0.5, wires=[0])
    qml.CZ(wires=[0, 4])
    qml.RY(0.2, wires=[1])
    return qml.probs()    

transpiled_circuit = qml.transforms.transpile(decomp_circ, coupling_map=[(0, 2), (1, 2), (2, 3), (2, 4)])

compiled_circuit = qml.compile(
    transpiled_circuit,
    pipeline=[
        qml.transforms.commute_controlled,
        qml.transforms.merge_rotations,
        qml.transforms.cancel_inverses,
    ],
    basis_set=["CNOT", "RX", "RZ"],
)

(compiled_tape,), _ = qml.workflow.construct_batch(compiled_circuit, level="device")()

qml_to_qasm_circuit = compiled_tape.to_openqasm()
print(qml_to_qasm_circuit)

Thank you very much @CatalinaAlbornoz and team. Now, everything works as it should.

1 Like

That’s great to hear @James !!