# To\_openqasm() support for multi-controlled operations

**URL:** <https://discuss.pennylane.ai/t/to-openqasm-support-for-multi-controlled-operations/8880>\
**Category:** PennyLane Help\
**Created:** [August 6, 2025, 10:35pm UTC](https://discuss.pennylane.ai/t/to-openqasm-support-for-multi-controlled-operations/8880 "2025-08-06T22:35:32Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![vpn](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/vpn/32/1753_2.png) [@vpn](https://discuss.pennylane.ai/u/vpn)\
**Post date:** [August 6, 2025, 10:35pm UTC](https://discuss.pennylane.ai/t/to-openqasm-support-for-multi-controlled-operations/8880/1 "2025-08-06T22:35:32Z")

</div>

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.

```python
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

```auto
ValueError: Operation GlobalPhase not supported by the QASM serializer

```

As I dig around, it seems [QFT](https://docs.pennylane.ai/en/stable/_modules/pennylane/templates/subroutines/qft.html#QFT) utilizes the [ControlledPhaseShift() operation](https://docs.pennylane.ai/en/stable/_modules/pennylane/ops/op_math/controlled_ops.html#ControlledPhaseShift), 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()](https://docs.pennylane.ai/en/stable/code/api/pennylane.transforms.combine_global_phases.html) and then remove the combined global phase, or would there be another workaround this?

Here’s my `qml.about()`:

```plaintext
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!

---

<div class="post-metadata">

**Author:** ![CatalinaAlbornoz](https://yyz2.discourse-cdn.com/flex012/user_avatar/discuss.pennylane.ai/catalinaalbornoz/32/1196_2.png) [@CatalinaAlbornoz](https://discuss.pennylane.ai/u/CatalinaAlbornoz)\
**Post date:** [August 8, 2025, 12:59am UTC](https://discuss.pennylane.ai/t/to-openqasm-support-for-multi-controlled-operations/8880/2 "2025-08-08T00:59:08Z")

</div>

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:

```auto
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

```auto
---------------------------------------------------------------------------
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](https://docs.pennylane.ai/en/stable/_modules/pennylane/tape/qscript.html)). 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.

```auto
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](https://github.com/pennylaneai/pennylane) 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!
