Handling parameters in ParaQeet¶
The OptimizationMap is a utility class that collects all parameters
that shall be considered during optimization and associates them with
the corresponding Optimizable interface. With this class,
Quantity objects can be traced back to the Optimizable to which
they belong. Before optimization, an instance of this class needs to be
filled and passed to the optimizer.
from paraqeet.optimizable import Optimizable
from paraqeet.optimization_map import OptimizationMap
from paraqeet.quantity import Quantity
from paraqeet.signal.envelopes import ConstantEnvelope, FlatTopGaussianEnvelope
from paraqeet.signal.iq_mixer import IQMixer
Example devices and their parameters¶
We define a tone and a signal generator and look at their parameters:
tone = ConstantEnvelope()
gen = IQMixer(envelopes=[tone])
We note that both tone and gen are instances of Optimizable.
print(isinstance(tone, Optimizable))
print(isinstance(gen, Optimizable))
True
True
As such they must have a get_parameters method implemented. We can
obtain the (default) parameters of the tone as
params_tone = tone.get_parameters()
print(params_tone)
[Amplitude: 24.7 MHz x 2pi, t_final: 32 ns]
and those of the generator as
params_gen = gen.get_parameters()
print(params_gen)
[Amplitude: 24.7 MHz x 2pi, t_final: 32 ns, lo_freq: 4.8 GHz x 2pi, Phase: 0 rad]
As we see, in this case, gen has the parameters of the tone as
its parameters. Moreover, it has two additional parameters, namely, the
frequency of the local oscillator (‘lo_freq’) and the phase of the pulse
(‘Phase’). We also note that the get_parameters returns a list of
ParaQeet’s Quantity objects:
print(isinstance(params_gen, list))
print([isinstance(param, Quantity) for param in params_gen])
True
[True, True, True, True]
The Optimization Map¶
To handle the parameters of both tones, we make an
OptimizationMapand add the parameters of the gen explcitely.
optmap = OptimizationMap()
optmap.add(gen, params_gen)
Note that we also need to pass gen itself when we add the
corresponding parameters to the optmap. We can get a list output of all
parameters with
optmap.get_all_parameters()
[Amplitude: 24.7 MHz x 2pi,
t_final: 32 ns,
lo_freq: 4.8 GHz x 2pi,
Phase: 0 rad]
If we just want to optimize the frequency, we set
optmap.add(gen, [params_gen[2]])
optmap.get_all_parameters()
[lo_freq: 4.8 GHz x 2pi]
which overwrites the previous parameters associated with gen.
Adding more devices¶
As a second drive, we create a signal shaped by a flat-top Gaussian envelope:
tone_2 = FlatTopGaussianEnvelope()
gen_2 = IQMixer(envelopes=[tone_2])
If we don’t specify an explicit list of parameters, all of them get added.
optmap.add(gen_2)
optmap.get_all_parameters()
[lo_freq: 4.8 GHz x 2pi,
Amplitude: 24.7 MHz x 2pi,
t_up: 6.4 ns,
t_down: 25.6 ns,
ramp_time: 3.2 ns,
lo_freq: 4.8 GHz x 2pi,
Phase: 0 rad]
If we just print optmap we can also see that the parameters are
associated with different objects
print(optmap)
==== <class 'paraqeet.signal.iq_mixer.IQMixer'> ====
[lo_freq: 4.8 GHz x 2pi]
==== <class 'paraqeet.signal.iq_mixer.IQMixer'> ====
[Amplitude: 24.7 MHz x 2pi, t_up: 6.4 ns, t_down: 25.6 ns, ramp_time: 3.2 ns, lo_freq: 4.8 GHz x 2pi, Phase: 0 rad]
Selecting parameters¶
There is a convenient filter method to select parameters based on properties. The following example selects all amplitudes:
def all_amplitudes(par):
"""Get the amplitudes."""
return par.get_name() == "Amplitude"
optmap.filter_parameters(all_amplitudes)
optmap.get_all_parameters()
[Amplitude: 24.7 MHz x 2pi]
print(optmap)
==== <class 'paraqeet.signal.iq_mixer.IQMixer'> ====
[Amplitude: 24.7 MHz x 2pi]
Adding back all parameters:
optmap.add(gen)
optmap.add(gen_2)
print(optmap)
==== <class 'paraqeet.signal.iq_mixer.IQMixer'> ====
[Amplitude: 24.7 MHz x 2pi, t_up: 6.4 ns, t_down: 25.6 ns, ramp_time: 3.2 ns, lo_freq: 4.8 GHz x 2pi, Phase: 0 rad]
==== <class 'paraqeet.signal.iq_mixer.IQMixer'> ====
[Amplitude: 24.7 MHz x 2pi, t_final: 32 ns, lo_freq: 4.8 GHz x 2pi, Phase: 0 rad]
Now, we select every parameter with unit “Hz”:
def hz_filter(par):
"""Get every parameter with the unit 'Hz'."""
return par.get_unit() == "Hz"
optmap.filter_parameters(hz_filter)
print(optmap)
==== <class 'paraqeet.signal.iq_mixer.IQMixer'> ====
[Amplitude: 24.7 MHz x 2pi, lo_freq: 4.8 GHz x 2pi]
==== <class 'paraqeet.signal.iq_mixer.IQMixer'> ====
[Amplitude: 24.7 MHz x 2pi, lo_freq: 4.8 GHz x 2pi]
In the following notebooks we will put to practice what we learned in
this notebook and use the OptimizationMap to select the parameters
to optimize in optimal control tasks.