Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Serializable parametric pulse (#7821)
* Symbolic parametric pulse This PR makes following changes. 1. add `_define` method to ParametricPulse. This method is expected to be implemented by each ParametricPulse subclass. Subclass must return Sympy or symengine symbolic equation that can be serialized. This method is called once in the constructor to fill `.definition` attribute of the instance. This definition is used for QPY serialization. 2. change behavior of `get_waveform` This method is originally implemented as abstractmethod that calls another callback that generates numpy array of samples (thus not serializable). Now this is a baseclass method that generates waveform array from the symbolic equation. 3. minor updates Now pulse parameters are not direct class attribute. Parameter names are defined as class attribute `PARAMS_DEF` and values are stored as instance variable `param_values`. This is good for writing serializer since it doesn't need to know attribute of each subclass, but just can call name def and values to get data to serialize. * Improve performance of parametrized pulse evaluation * Implement Constant pulse using Piecewise This works around an issue with sympy where its lambda returns a scalar instead of an array when the expression evaluates to a scalar: sympy/sympy#5642 * Fall back to sympy for parametric pulse evaluation * Use sympy Symbol with sympy lambdify * WIP: cache symbolic pulse lambda functions * move lambdify to init subclass for called once * turn parameter properties into attribute and remove slots * remove attribute and add __getattr__ and readd slots for better performance. * move symbolic funcs directly to _define * Convert numerical_func to staticmethod Co-authored-by: Will Shanks <[email protected]> * remove symbolic add constraints, numerical func is renamed to definition for better integration with circuit instruction * revert changes to parametric pulse and create new symbolic pulse file * add ITE-like program * sympy runtime import * update test notebook * add attribute docs * fix non-constraints * remove pulse type instance variable * use descriptor * remove redundant comment * Update - Add symbolic pulse to assemble - Add symbplic pulse to parameter manager - Remove risefall ratio from GaussianSquare paramters * keep raw data for QPY encoding * update unittest * update helper function name * add reno * remove notebook * fix lint * fix unittest and logic * add more docs * review comments * lint fix * fix documentation * minor drawer fix * documentation upgrade Co-authored-by: Daniel J. Egger <[email protected]> * review comment misc Co-authored-by: Will Shanks <[email protected]> * remove abstract class methods This commit removes class methods for symbolic expression so that SymbolicPulse can be instantiated by itself. And descriptors only saves Dict[Expr, Callable], i.e. lambda cache, rather than enforcing name-based mapping. * add error handling for amplitude * treat amp as a special parameter * Remove expressions for amplitude validation * support symengine - symengine doesn't support lamdify of complex expression, e.g. DRAG pulse - symengine doesn't support Less expression with complex value substitution - symengine Lambda function doesn't support args in mixture of complex and float object To overcome these, envelope expressions are separately stored for I, Q channel, and evaluation of 'amp' is excluded from symbolic operation. Thus in this implementation symbols are all real numbers. * use real=False option * review comment Co-authored-by: Will Shanks <[email protected]> * - fix attribute - duration and amp are required - instantiate subclass with expression - remove __dict__ usage in __getattr__ and readd __slots__ - fix documentation - update private attirbute names * undo change to requirements-dev * fix __getattr__ mechanism Directly accessing to the instance variable crashes copy and deepcopy because when the object is copied the __init__ is not called before the first getattr is called. Then copied instance tries to find missing (not initialized) attribute in recursive way. use of __getattribute__ fixes this problem. * fix type hint reference * simplification * move amp from constructor to `parameters` dict * review comment Co-authored-by: Will Shanks <[email protected]> * fix bug - use getattr in __eq__; e.g. Waveform doesn't have envelope - fix parameter maanger in addition, this replaces _param_vals and _param_names tuple with _params dictionary because overhead of generating a dict is significant. * fix typo * add eval_conditions to skip waveform generation * fall back to sympy lamdify when function is not supported * documentation update Co-authored-by: Will Shanks <[email protected]> Co-authored-by: Daniel Egger <[email protected]> * replace eval_conditions with valid_amp_conditions Co-authored-by: Will Shanks <[email protected]> * update hashing and equality, redefine expressions more immutably * add error message for missing parameter * cleanup * check parameter before hashing * move amp check to constructor * add envelope to hash * update docs * Update qiskit/pulse/library/symbolic_pulses.py Co-authored-by: Matthew Treinish <[email protected]> * lint Co-authored-by: Will Shanks <[email protected]> Co-authored-by: Daniel J. Egger <[email protected]> Co-authored-by: Matthew Treinish <[email protected]>
- Loading branch information