qiskit
qiskit copied to clipboard
TypeError: label expects a string or None when loading a circuit using default label
Environment
- Qiskit version: 0.45.1
- Python version: 3.10.13
- Operating system: Ubuntu 22.04.3 LTS
What is happening?
Running the below code results in TypeError: label expects a string or None. However, I use the default label which is None.
How can we reproduce the issue?
from qiskit import QuantumCircuit, QuantumRegister
from qiskit.circuit.library.standard_gates import CUGate
qr = QuantumRegister(3)
qc = QuantumCircuit(qr, name='qc')
qc.append(CUGate(1, 1, 1, 1).control(1), qr)
from qiskit import qpy
with open('circuit.qpy', 'wb') as fd:
qpy.dump(qc, fd)
with open('circuit.qpy', 'rb') as fd:
qc = qpy.load(fd)[0] # TypeError: label expects a string or None
What should happen?
I expect the code to run without error.
Any suggestions?
No response
@jiannanWang I learned That qpy works with QuantumCircuit Modules not with qiskit.circuit.library. So I checked the documents listed below and modify your code using
qc.cu(theta, phi, lam, gamma, control_qubit, target_qubit, label=None, ctrl_state=None)
supprted with QuantumCircuit and it works correctly with my code editor. here is the code..
from qiskit import QuantumCircuit
from qiskit import qpy
qc = QuantumCircuit(3, name='circuit')
qc.cu(1, 1, 1, 1, 1, 0)
with open('circuit.qpy', 'wb') as fd:
qpy.dump(qc, fd)
with open('circuit.qpy', 'rb') as fd:
new_qc = qpy.load(fd)[0]
Here is the documentation of Cu gate and qpy https://docs.quantum.ibm.com/api/qiskit/qiskit.circuit.library.CUGate https://docs.quantum.ibm.com/api/qiskit/qpy
I Hope It works with you as well.
Hope you are doing well! It's been a while since I submitted this issue. I wonder if there's any update? Thanks!
I revisited this issue and checked the stack track (copied below). From the traceback, it seems during loading, the qpy somehow loaded UGate instead of the CUGate. So the fourth parameter (gamma) of CUGate is passed to the fourth parameter (label) of UGate, which eventually causes this crash.
Traceback (most recent call last):
File "/mnt/test_crash.py", line 12, in <module>
qc = qpy.load(fd)[0] # TypeError: label expects a string or None
File "/root/anaconda3/envs/qiskit/lib/python3.10/site-packages/qiskit/qpy/interface.py", line 301, in load
loader(
File "/root/anaconda3/envs/qiskit/lib/python3.10/site-packages/qiskit/qpy/binary_io/circuits.py", line 1189, in read_circuit
_read_instruction(
File "/root/anaconda3/envs/qiskit/lib/python3.10/site-packages/qiskit/qpy/binary_io/circuits.py", line 273, in _read_instruction
inst_obj = _parse_custom_operation(
File "/root/anaconda3/envs/qiskit/lib/python3.10/site-packages/qiskit/qpy/binary_io/circuits.py", line 396, in _parse_custom_operation
base_gate = _read_instruction(
File "/root/anaconda3/envs/qiskit/lib/python3.10/site-packages/qiskit/qpy/binary_io/circuits.py", line 351, in _read_instruction
gate = gate_class(*params)
File "/root/anaconda3/envs/qiskit/lib/python3.10/site-packages/qiskit/circuit/library/standard_gates/u.py", line 81, in __init__
super().__init__("u", 1, [theta, phi, lam], label=label, duration=duration, unit=unit)
File "/root/anaconda3/envs/qiskit/lib/python3.10/site-packages/qiskit/circuit/gate.py", line 45, in __init__
super().__init__(name, num_qubits, 0, params, label=label, duration=duration, unit=unit)
File "/root/anaconda3/envs/qiskit/lib/python3.10/site-packages/qiskit/circuit/instruction.py", line 95, in __init__
raise TypeError("label expects a string or None")
TypeError: label expects a string or None
After experimenting with the code, the problem seems to boil down to the following. The code
gate = CUGate(1, 1, 1, 1)
print(f"{gate = }")
cgate = gate.control(1)
print(f"{cgate = }")
bgate = cgate.base_gate
print(f"{bgate = }")
outputs
gate = Instruction(name='cu', num_qubits=2, num_clbits=0, params=[1, 1, 1, 1])
cgate = Instruction(name='ccu', num_qubits=3, num_clbits=0, params=[1, 1, 1, 1])
bgate = Instruction(name='u', num_qubits=1, num_clbits=0, params=[1, 1, 1, 1])
That is, we now have a UGate with the wrong number of parameters. I believe this is due to the discrepancy in handling params for generic controlled gates vs. CUGates, see https://github.com/Qiskit/qiskit/blob/9157c04230943d5470e5bb6c31ce0f4c8dedecf6/qiskit/circuit/library/standard_gates/u.py#L148-L157
Having written this, I have no idea how to fix this, leaving the fix to the experts. :)
After experimenting with the code, the problem seems to boil down to the following. The code
gate = CUGate(1, 1, 1, 1) print(f"{gate = }") cgate = gate.control(1) print(f"{cgate = }") bgate = cgate.base_gate print(f"{bgate = }")
outputs
gate = Instruction(name='cu', num_qubits=2, num_clbits=0, params=[1, 1, 1, 1]) cgate = Instruction(name='ccu', num_qubits=3, num_clbits=0, params=[1, 1, 1, 1]) bgate = Instruction(name='u', num_qubits=1, num_clbits=0, params=[1, 1, 1, 1])
Considering this as an example, after creating the cu
instruction, we create a controlled gate ccu
line 240 by passing in operation.params
= [1,1,1,1] (which is params of cu
instruction above) and base_gate = u
gate (which is the base gate of cu
). During which we call the constructor of Instruction
class and assign self.params = params
which causes the failure.
IMO, we should first check whether or not self.params
is empty and then move forward
The following code
https://github.com/Qiskit/qiskit/blob/9157c04230943d5470e5bb6c31ce0f4c8dedecf6/qiskit/circuit/instruction.py#L108
should be
if not self.params:
self.params = params
With this change, the output of the above code snippet is
gate = Instruction(name='cu', num_qubits=2, num_clbits=0, params=[1, 1, 1, 1])
cgate = Instruction(name='ccu', num_qubits=3, num_clbits=0, params=[1, 1, 1])
bgate = Instruction(name='u', num_qubits=1, num_clbits=0, params=[1, 1, 1])