Closed cyberteej closed 1 year ago
This looks like an issue with qpy that was fixed in terra but not picked up by ibm-runtime. For example, if I do
import io
from qiskit import qpy
with io.BytesIO() as buff:
qpy.dump(circ, buff) # Using circ from earlier example
buff.seek(0)
restored = qpy.load(buff)
restored[0].copy() # Used by the estimator which raised the exception
The code above works, but if I switch to ibm-runtime's qpy this fails with
TypeError: __new__() missing 3 required positional arguments: 'duration', 'amp', and 'sigma'
I don't get the __new__()
error. I get the behavior in #657. I am not sure why the behavior is different. As a workaround, you can try converting your pulses to Waveform so replacing Gaussian(duration=64, amp=0.2, sigma=8)
with Gaussian(duration=64, amp=0.2, sigma=8).get_waveform()
because I think it is only parametric pulses that are broken rather than all pulse gates.
Edit: I do get the __new__()
error if I use the example code given in this issue. It seems like when there are multiple pulse gates defined on a qubit you can get a different error to trigger first, but the underlying cause (qpy mismatch) is the same.
Edit: Another workaround is to overwrite the _pulse_type
attribute on the pulses to something that is not a builtin pulse name (Gaussian, GaussianSquare, Drag, Constant).
I tried both workarounds and ended up getting qiskit.exceptions.QiskitError: 'Cannot apply Operation: custom_gate'
. I tried a different job with pulse gates and it worked, so I think these workarounds work and there might be another issue with the example, which I guess is still pulse gate specific.
This looks like an issue with qpy that was fixed in terra but not picked up by ibm-runtime. For example, if I do
import io from qiskit import qpy with io.BytesIO() as buff: qpy.dump(circ, buff) # Using circ from earlier example buff.seek(0) restored = qpy.load(buff) restored[0].copy() # Used by the estimator which raised the exception
The code above works, but if I switch to ibm-runtime's qpy this fails with
TypeError: __new__() missing 3 required positional arguments: 'duration', 'amp', and 'sigma'
Could you clarify what you mean by the code above works? If I replace the circuit in the estimator with new_circ as defined by restored[0].copy()
, I get the same __new__()
error (qiskit 0.22.3, runtime 0.8.0).
Could you clarify what you mean by the code above works?
Here "works" just means that the code example does not produce the error locally (without submitting to the runtime), not that it produces a circuit that can be submitted to the runtime. For comparison, this code does reproduce the error locally:
import json
from qiskit import QuantumCircuit, assemble, pulse
from qiskit_ibm_runtime.utils import RuntimeEncoder, RuntimeDecoder
with pulse.builder.build(name="x") as sched:
pulse.play(pulse.Gaussian(100, 0.8, 10), pulse.DriveChannel(0))
qc = QuantumCircuit(1)
qc.x(0)
qc.add_calibration("x", (0,), sched)
dumped = json.dumps(qc, cls=RuntimeEncoder)
loaded = json.loads(dumped, cls=RuntimeDecoder)
loaded.copy()
The difference is that this code uses the runtime's version of qpy to dump and load rather than terra's version.
Here is a modified version of your example that gets past the pulse problem (an illustration of my second edited workaround above):
from qiskit_ibm_runtime import QiskitRuntimeService, Estimator, Session
from qiskit.pulse import Gaussian
from qiskit.quantum_info import SparsePauliOp
from qiskit import QuantumCircuit
from qiskit.circuit import Gate
service = QiskitRuntimeService()
backend = service.backend('ibm_oslo')
z_op = SparsePauliOp('Z')
circ = QuantumCircuit(1,1)
circ.h(0)
custom_gate = Gate('custom_gate', 1, [])
circ.append(custom_gate, [0])
circ.measure(0,0)
gauss = Gaussian(duration=64, amp=0.2, sigma=8)
gauss._pulse_type = "custom_gaussian"
with pulse.build(backend=backend) as sched:
pulse.play(gauss, pulse.drive_channel(0))
circ.add_calibration('custom_gate', [0], sched, [])
with Session(service=service, backend=backend) as session:
estimator = Estimator(session=session)
res = estimator.run(circ, z_op)
print(res.result())
For me, this gives:
2022-12-16T15:06:27.524698748Z pass_.run(FencedDAGCircuit(dag))
2022-12-16T15:06:27.524698748Z File "/opt/app-root/lib64/python3.9/site-packages/qiskit/transpiler/passes/optimization/commutation_analysis.py", line 75, in run
2022-12-16T15:06:27.524698748Z does_commute = self.comm_checker.commute(
2022-12-16T15:06:27.524698748Z File "/opt/app-root/lib64/python3.9/site-packages/qiskit/circuit/commutation_checker.py", line 135, in commute
2022-12-16T15:06:27.524698748Z operator_1 = Operator(op1, input_dims=(2,) * len(qarg1), output_dims=(2,) * len(qarg1))
2022-12-16T15:06:27.524698748Z File "/opt/app-root/lib64/python3.9/site-packages/qiskit/quantum_info/operators/operator.py", line 85, in __init__
2022-12-16T15:06:27.524698748Z self._data = self._init_instruction(data).data
2022-12-16T15:06:27.524698748Z File "/opt/app-root/lib64/python3.9/site-packages/qiskit/quantum_info/operators/operator.py", line 520, in _init_instruction
2022-12-16T15:06:27.524698748Z op._append_instruction(instruction)
2022-12-16T15:06:27.524698748Z File "/opt/app-root/lib64/python3.9/site-packages/qiskit/quantum_info/operators/operator.py", line 564, in _append_instruction
2022-12-16T15:06:27.524698748Z raise QiskitError(f"Cannot apply Operation: {obj.name}")
2022-12-16T15:06:27.524698748Z qiskit.exceptions.QiskitError: 'Cannot apply Operation: custom_gate'
Here is a modified version of your example that gets past the pulse problem (an illustration of my second edited workaround above):
from qiskit_ibm_runtime import QiskitRuntimeService, Estimator, Session from qiskit.pulse import Gaussian from qiskit.quantum_info import SparsePauliOp from qiskit import QuantumCircuit from qiskit.circuit import Gate service = QiskitRuntimeService() backend = service.backend('ibm_oslo') z_op = SparsePauliOp('Z') circ = QuantumCircuit(1,1) circ.h(0) custom_gate = Gate('custom_gate', 1, []) circ.append(custom_gate, [0]) circ.measure(0,0) gauss = Gaussian(duration=64, amp=0.2, sigma=8) gauss._pulse_type = "custom_gaussian" with pulse.build(backend=backend) as sched: pulse.play(gauss, pulse.drive_channel(0)) circ.add_calibration('custom_gate', [0], sched, []) with Session(service=service, backend=backend) as session: estimator = Estimator(session=session) res = estimator.run(circ, z_op) print(res.result())
For me, this gives:
2022-12-16T15:06:27.524698748Z pass_.run(FencedDAGCircuit(dag)) 2022-12-16T15:06:27.524698748Z File "/opt/app-root/lib64/python3.9/site-packages/qiskit/transpiler/passes/optimization/commutation_analysis.py", line 75, in run 2022-12-16T15:06:27.524698748Z does_commute = self.comm_checker.commute( 2022-12-16T15:06:27.524698748Z File "/opt/app-root/lib64/python3.9/site-packages/qiskit/circuit/commutation_checker.py", line 135, in commute 2022-12-16T15:06:27.524698748Z operator_1 = Operator(op1, input_dims=(2,) * len(qarg1), output_dims=(2,) * len(qarg1)) 2022-12-16T15:06:27.524698748Z File "/opt/app-root/lib64/python3.9/site-packages/qiskit/quantum_info/operators/operator.py", line 85, in __init__ 2022-12-16T15:06:27.524698748Z self._data = self._init_instruction(data).data 2022-12-16T15:06:27.524698748Z File "/opt/app-root/lib64/python3.9/site-packages/qiskit/quantum_info/operators/operator.py", line 520, in _init_instruction 2022-12-16T15:06:27.524698748Z op._append_instruction(instruction) 2022-12-16T15:06:27.524698748Z File "/opt/app-root/lib64/python3.9/site-packages/qiskit/quantum_info/operators/operator.py", line 564, in _append_instruction 2022-12-16T15:06:27.524698748Z raise QiskitError(f"Cannot apply Operation: {obj.name}") 2022-12-16T15:06:27.524698748Z qiskit.exceptions.QiskitError: 'Cannot apply Operation: custom_gate'
I tried my own version of the waveform approach you mentioned and it gave me a different error, not sure why. The error says trying to find more "in" edges ? I don't know, nothing I try seems to work.
from qiskit import IBMQ
IBMQ.load_account()
provider= IBMQ.get_provider(hub= "provider here")
import qiskit
from qiskit_ibm_runtime import QiskitRuntimeService, Session, Options
from qiskit_ibm_runtime import Estimator as my_runtime_estimator
service = QiskitRuntimeService()
real_backend_manila= provider.get_backend('ibmq_manila')
service_real_backend_waveform_manila = service.backend('ibmq_manila')
from qiskit import pulse
from qiskit.circuit import Gate
from qiskit import QuantumCircuit
from qiskit.circuit.library import standard_gates
from qiskit.pulse.library import Gaussian, Drag
pulse_x_gate = Gate(name='pulse_x_gate', label='p_x_g', num_qubits=2, params=[])
qc_pulse_gate_circuit_waveform_manila = QuantumCircuit(2, 0)
qc_pulse_gate_circuit_waveform_manila.append(pulse_x_gate,[0,1])
sched_waveform_x_manila = Gaussian(duration=64, amp=0.2, sigma=8).get_waveform()
with pulse.build(real_backend_manila, name='custom_pulse_sched_waveform_manila') as custom_pulse_schedule_waveform_manila:
pulse.play(sched_waveform_x_manila, pulse.drive_channel(0))
qc_pulse_gate_circuit_waveform_manila.add_calibration('pulse_x_gate', [0,1],custom_pulse_schedule_waveform_manila)
options_manila = Options()
options_manila.transpilation.skip_transpilation = True
from qiskit.quantum_info import SparsePauliOp
z_op = SparsePauliOp('ZZ')
with Session(service=service, backend=service_real_backend_waveform_manila) as session:
estimator = my_runtime_estimator(session=session,options=options_manila)
res = estimator.run(qc_pulse_gate_circuit_waveform_manila, z_op)
print(res.result())
This gives (part of the long error message):
Started server process [7]
Waiting for application startup.
Application startup complete.
--- Logging error ---
raceback (most recent call last):
File "/provider/programruntime/program_starter_wrapper.py", line 88, in execute
final_result = self.main(backend, self.messenger, **self.user_params)
File "/code/./program.py", line 1399, in main
result = estimator.run(
File "/code/./program.py", line 209, in run
transpiled_circuits = self.transpiled_circuits
File "/code/./program.py", line 392, in transpiled_circuits
self._split_transpile()
File "/code/./program.py", line 435, in _split_transpile
self._transpiled_circuits += self._combine(
File "/code/./program.py", line 449, in _combine
transpiled_circuit.compose(diff_circuit, inplace=True)
File "/opt/app-root/lib64/python3.9/site-packages/qiskit/circuit/quantumcircuit.py", line 931, in compose
raise CircuitError(
qiskit.circuit.exceptions.CircuitError: "Trying to compose with another QuantumCircuit which has more 'in' edges."
@Pauliver90 I haven't tried to get your example to work, but it seems like the problem is related to transpilation. You might try removing your skip_transpilation
option or keep it but do an explicit qiskit.transpile()
call on qc_pulse_gate_circuit_waveform_manila
before passing it to estimator.run()
. My guess is that the estimator program is composing your input circuit with a circuit for the expectation value measurement that has been transpiled for the full number of qubits in the backend. The error seems to be related to the number of qubits not matching between the two circuits.
@tylerjones1 are you still having this issue? We just updated qpy on the server side
Hi @kt474, this issue seems resolved, my snippet runs into an unrelated error. Thanks!
Describe the bug Hi all, it seems to me that using custom pulse gates in conjunction with IBM Runtime is a no-go at the moment.
Steps to reproduce If I run this script, I get sensible results.
On the other hand, if I run this code:
I get an error which boils down to
TypeError: __new__() missing 3 required positional arguments: 'duration', 'amp', and 'sigma'
.Expected behavior Both of these pieces of code work if you simply run them directly on a backend, but one fails if you use Runtime. I would've expected both to work
Suggested solutions 🤷♂️
Additional Information The same is true for Sampler