Swept parameters' value #1146
Replies: 1 comment
-
@stavros11 this is mainly to you. The practical motivation that moved me to this is related to the amplitude sweeper, since the waveforms are automatically multiplied by the pulse amplitude, but that should be reverted in case of an amplitude sweeper, since it is intended to replace the qibolab/src/qibolab/_core/instruments/qm/controller.py Lines 387 to 395 in 74d98c6 which then becomes duplicated across the drivers. However, since I started contemplating the interface change as well, I also desired our beloved main users feedback @andrea-pasquale @Edoardo-Pedicillo |
Beta Was this translation helpful? Give feedback.
-
This is a subject I always had in the back of my mind, but which I never truly focused.
When we sweep parameters, their values will be specified by the
Sweeper
. But the swept parameters also have another value (either in thePulse
or in theChannel
) which is then just ignored.I believe that this is some potential surface for errors, both for users and drivers. But especially for the latter.
User fix (breaking)
We could change the interface to allow
Pulse
andChannel
to have some optional parameters, taking null values (i.e.None
) when the parameter is swept.This is certainly a breaking change. The usual kind of unexpectedly breaking, because of type invariance[*].
But it is not even necessarily desirable, since it will lead to an unpleasant interface.
Indeed, while this would avoid the superfluous information to be specified, with the current interface for sequence building, it will lead to the requirement to explicitly erase some information from existing pulses. E.g. from natives.
We can iterate on this, and create some smarter factories, and wrappers around them. E.g. we could allow not only the native factories, but even the basic pulses, to have a clone mechanism which will take into account sweepers.
and it can be improved by integrating it in the sequence method
In any case, some work will be needed in order to make it pleasant. And reducing the amount of duplication will be a challenge, since the connection bet
Idea for new sweeper interface: instead of specifying sweepers separately from pulses, we may generate loop indices with a factory, and then specify sweepers locally to the sequence, by allowing
Pulse
attributes to be a sweeper itself, which will take a range of values and a generated index (keeping it possible to sweep multiple quantities in parallel)Drivers' only fix
Instead, it could be much simpler to do this internally, for the drivers' sake.
Since drivers have not yet been exposed (e.g. for external implementation, as plugins), the execution implementation is fully internal, and only
platform.execute()
is exposed to the users.Then, we may preprocess the sequence and pulses, in order to strip the swept parameters.
While stripping, we may actually replace it with
None
(to signal that the information is missing, and it will be supplied by a sweeper somewhere else), or we could already implement part of the idea for new sweepers above, just replacing the value with the sweeper (i.e. a range and an index).In any case, experimenting here is for free (no breaking), and we could use this to optimize the representation which is most effective for the drivers' implementation.
[*]: despite going
T -> Optional[T]
(or in generalUnion[T, ...]
) may seem a non-breaking change, it is when you don't know where the type is usedFunctions and types invariance
Types' compatibility is based on the possibility to replace them without breaking.
Let's make an example.
where the first is clearly a subtype of the second (values of the first type are also part of the second).
If used as return type for function
switching one for the other works smoothly, within the function. I.e. whatever the function was doing, if it were returning
int
, it is also returningOptional[int]
.Instead, if used as argument
then it would miserably fail, if
None
is passed instead of an integer number.In general, this means that if we expose a type as part of our interface, we can never safely trade it for a subtype or supertype, since we have no control if it will be used as input or output of user functions. And, in general, it will be both.
The only thing that should be non-breaking is adding extra arguments to functions, or attributes to classes, providing defaults for them.
Beta Was this translation helpful? Give feedback.
All reactions