To_openqasm() support for multi-controlled operations

Hi all,

I’m wondering if there has been support for the qml.to_openqasm() function for multi-controlled operations, including inverse QFT and PauliZ. It seems that for >=3-controlled inverse QFT operation, or >=4-controlled PauliZ cannot be converted.

import pennylane as qml

dev = qml.device("default.qubit", wires=6)
@qml.qnode(dev)
def circuit():
    for wire in range(3):
        qml.Hadamard(wires=wire)
    qml.ctrl(qml.QFT, control=[3, 4, 5])(wires=range(3))
    qml.ctrl(qml.PhaseAdder, control=[3, 4, 5])(k=1, x_wires=range(3))
    # qml.ctrl(qml.adjoint(qml.QFT), control=[3, 4, 5])(wires=range(3))
    # qml.ctrl(qml.PauliZ, control=[1, 2, 3, 4, 5])(wires=0)
    return qml.probs(wires=range(3))
qml.draw_mpl(circuit, style='pennylane', wire_order=[0, 1, 2, 3, 4, 5])()
t = qml.to_openqasm(circuit, measure_all=False)()

The code above runs fine, until you uncomment any of two qml.ctrl() lines. Both yield the following error

ValueError: Operation GlobalPhase not supported by the QASM serializer

As I dig around, it seems QFT utilizes the ControlledPhaseShift() operation, which is decomposed to some qml.GlobalPhase() gates that cannot be parsed to openqasm. Is there a way we can use the qml.transforms.combine_global_phase() and then remove the combined global phase, or would there be another workaround this?

Here’s my qml.about():

Version: 0.42.0
Summary: PennyLane is a cross-platform Python library for quantum computing, quantum machine learning, and quantum chemistry. Train a quantum computer the same way as a neural network.
Home-page: 
Author: 
Author-email: 
License-Expression: Apache-2.0
Location: (omitted)
Requires: (omitted)
Required-by: PennyLane-Cirq, PennyLane-qiskit, pennylane_lightning

Platform info:           Windows-10 (omitted)
Python version:          3.11.9
Numpy version:           2.3.0
Scipy version:           1.15.3
Installed devices:
- default.clifford (pennylane-0.42.0)
- default.gaussian (pennylane-0.42.0)
- default.mixed (pennylane-0.42.0)
- default.qubit (pennylane-0.42.0)
- default.qutrit (pennylane-0.42.0)
- default.qutrit.mixed (pennylane-0.42.0)
- default.tensor (pennylane-0.42.0)
- null.qubit (pennylane-0.42.0)
- reference.qubit (pennylane-0.42.0)
- cirq.mixedsimulator (PennyLane-Cirq-0.41.0)
- cirq.pasqal (PennyLane-Cirq-0.41.0)
- cirq.qsim (PennyLane-Cirq-0.41.0)
- cirq.qsimh (PennyLane-Cirq-0.41.0)
- cirq.simulator (PennyLane-Cirq-0.41.0)
- lightning.qubit (pennylane_lightning-0.42.0)
- qiskit.aer (PennyLane-qiskit-0.42.0)
- qiskit.basicaer (PennyLane-qiskit-0.42.0)
- qiskit.basicsim (PennyLane-qiskit-0.42.0)
- qiskit.remote (PennyLane-qiskit-0.42.0)

Thanks for your help!

Hi @vpn , thank you for reporting this.

It does look like there’s an issue when you use more than 4 control qubits, as seen in the simplified code below:

import pennylane as qml

dev = qml.device("default.qubit", wires=6)
@qml.qnode(dev)
def circuit():
    qml.ctrl(qml.PauliZ, control=[2, 3, 4, 5])(wires=0) # works
    qml.ctrl(qml.PauliZ, control=[1, 2, 3, 4, 5])(wires=0) # causes an error
    return qml.probs(wires=range(3))
qml.draw_mpl(circuit, style='pennylane', wire_order=[0, 1, 2, 3, 4, 5])()
t = qml.to_openqasm(circuit, measure_all=False)()

Here’s the full error traceback

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
/usr/local/lib/python3.11/dist-packages/pennylane/tape/qscript.py in to_openqasm(self, wires, rotations, measure_all, precision)
   1255             try:
-> 1256                 gate = OPENQASM_GATES[op.name]
   1257             except KeyError as e:

KeyError: 'GlobalPhase'

The above exception was the direct cause of the following exception:

ValueError                                Traceback (most recent call last)
2 frames
/tmp/ipython-input-330596400.py in <cell line: 0>()
      8     return qml.probs(wires=range(3))
      9 qml.draw_mpl(circuit, style='pennylane', wire_order=[0, 1, 2, 3, 4, 5])()
---> 10 t = qml.to_openqasm(circuit, measure_all=False)()

/usr/local/lib/python3.11/dist-packages/pennylane/io/io.py in wrapper(*args, **kwargs)
    746     def wrapper(*args, **kwargs) -> str:
    747         tape = construct_tape(qnode)(*args, **kwargs)
--> 748         return tape.to_openqasm(
    749             wires=wires, rotations=rotations, measure_all=measure_all, precision=precision
    750         )

/usr/local/lib/python3.11/dist-packages/pennylane/tape/qscript.py in to_openqasm(self, wires, rotations, measure_all, precision)
   1256                 gate = OPENQASM_GATES[op.name]
   1257             except KeyError as e:
-> 1258                 raise ValueError(f"Operation {op.name} not supported by the QASM serializer") from e
   1259 
   1260             wire_labels = ",".join([f"q[{wires.index(w)}]" for w in op.wires.tolist()])

ValueError: Operation GlobalPhase not supported by the QASM serializer

The implementation of to_openqasm comes from the QuantumScript class (see the source code here). Unfortunately there’s something hardcoded that states that for to_openqasm the gates will be decomposed up to depth=10.
What I think is happening is that for gates with more than 4 control qubits this depth is not enough to decompose everything into gates supported by OpenQASM.

As evidence, below is a code example that does work, even though it includes a GlobalPhase gate.

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)
def circuit(phi):
    qml.X(0)
    qml.GlobalPhase(phi)
    return qml.expval(qml.Z(0)), qml.expval(qml.Z(1))

qml.draw_mpl(circuit, style='pennylane')(0.123)
t = qml.to_openqasm(circuit, measure_all=False)(0.123)

So what can you do?
The fastest and easiest option is to create a fork of PennyLane, increase the depth for the to_openqasm decompositions in the QuantumScript class, and test if this solves your problem.
In addition to this we would appreciate it if you can open an issue on our GitHub so that we can keep track of this issue and tackle it when we have capacity, or prioritize it if it’s affecting many people.

I know this is a lot of information so please let us know if you still have any questions or issues.

Thanks for bringing this to our attention!