Qiskit / qiskit

Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.
https://www.ibm.com/quantum/qiskit
Apache License 2.0
5.19k stars 2.35k forks source link

Generic parametric pulse #9954

Open wshanks opened 1 year ago

wshanks commented 1 year ago

What should we add?

https://github.com/Qiskit/qiskit-terra/pull/7821 introduced the SymbolicPulse class and began the deprecation of the ParametricPulse class. SymbolicPulse is generally preferrable because you write a serializable (through symengine) expression for the pulse shape and create a self-contained serializable definition of a pulse whereas ParametricPulse requires that the pulse shape be defined as Python code in a subclass and then the shape can only be serialized and deserialized if the deserialization environment has the same pulse subclass defined, which prevents the use of parametrized custom pulse shapes.

Despite the benefits of using SymbolicPulse over ParametricPulse, here I would like to request support for something like ParametricPulse, specifically a Pulse class that contains a name and set of parameters but does not contain a definition of the pulse. When GaussianSquareDrag was added to qiskit and to the IBM provider as a supported pulse type, there were problems with the rollout related to mismatched versions -- an older version of qiskit that did not have GaussianSquareDrag could not load a backend reporting a gaussian square drag pulse (note: loading of backend data is lazier now so this would be less of a problem than before). The problem comes from the to_type method in ParametricPulseShapes here:

https://github.com/Qiskit/qiskit-terra/blob/a50fe82b7cf97964ef5982520f590873905055ef/qiskit/qobj/converters/pulse_instruction.py#L41-L93

which is used to load backend pulses and can only handle one of the hard coded types in the enum. Rather than failing for another pulse name, I would like it to create a generic parametric pulse object with the pulse name and pulse parameters.

For the purpose of sending parametrized pulses to an IBM backend, currently only the name and parameters are submitted, not the pulse shape definition. So a generic pulse with a name and parameter dictionary would be sufficient for receiving pulse data, modifying it, and submitting back to the backend even if qiskit did not have a SymbolicPulse defined for a particular shape.

The pulse shape definition is needed for get_waveform(). I think there are two use cases for get_waveform(). One is for use in calling draw() on a pulse schedule. When adding a generic parametric pulse like requested here, we could also add some special case to draw() to account for it (draw a box with the correct width to indicate that there is a pulse with unknown shape in that place). The second is for alternative backends (like qiskit-dynamics' DynamicsBackend) that do need the pulse shape if one was trying to take pulses from a live IBM backend and then run them in simulation. I don't think there is much to do in this case -- if the pulse shape is not published, it just can't be used locally. I think that is okay. The goal here is to reduce the opportunities for breaking a user's workflow on a new pulse.

nkanazawa1989 commented 1 year ago

Thanks Will. I think this is reasonable idea. Alternatively we can update IBM provider to use symbolic pulse and serialize calibration data with QPY, but likely this causes unwanted Qiskit dependency on the backend system.

Indeed once we implement a pulse compiler built upon the generic pass manager we should be able to decouple the symbolic expression from the pulse instance. I think this separation will speedup the pulse program construction if user doesn't require visualization. So what I am also thinking of is SymbolicPulse = GenericParametricPulse + definition which will be managed by a pass in the compiler. Note that GenericParametricPulse is not necessary materialized, i.e. SymbolicPulse with .definition = None should be generic parametric pulse, i.e. definition is sort of metadata.

This pass manager pass can consume backend constraints for the supported parametric pulses, and attaches the definition from the separate pulse registry (this could be dataclass of shape, constraints, etc..) if the .definition is missing. Expert user can of course manually add symbolic definition to the custom pulse so that the program can be ported to another environment without the definition.