Python API¤
The floquet Python API consists largely of the floquet_analysis function which initializes a FloquetAnalysis class. We can then call run(filepath)
on instances of this class to perform the Floquet simulation. The computed data is then saved both as attributes of the class and also to the file specified by filepath
, which should be a string specifying a h5py
file.
Floquet methods¤
FloquetAnalysis
¤
Bases: Serializable
Perform a floquet analysis to identify nonlinear resonances.
In most workflows, one needs only to call the run() method which performs both the displaced state fit and the Blais branch analysis. For an example workflow, see the transmon tutorial.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
model |
Model
|
Class specifying the model, including the Hamiltonian, drive amplitudes, frequencies |
required |
state_indices |
list | None
|
State indices of interest. Defaults to [0, 1], indicating the two lowest-energy states. |
None
|
options |
Options
|
Options for the Floquet analysis. |
Options()
|
init_data_to_save |
dict | None
|
Initial parameter metadata to save to file. Defaults to None. |
None
|
bare_state_array()
¤
Return array of bare states.
Used to specify initial bare states for the Blais branch analysis.
identify_floquet_modes(f_modes_energies, params_0, displaced_state, previous_coefficients)
¤
Return floquet modes with largest overlap with ideal displaced state.
Also return that overlap value.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
f_modes_energies |
tuple[ndarray, Qobj]
|
output of self.run_one_floquet(params) |
required |
params_0 |
tuple[float, float]
|
(omega_d_0, amp_0) to use for displaced fit |
required |
displaced_state |
DisplacedState
|
Instance of DisplacedState |
required |
previous_coefficients |
ndarray
|
Coefficients from the previous amplitude range that will be used when calculating overlap of the floquet modes against the 'bare' states specified by previous_coefficients |
required |
run(filepath=None)
¤
Perform floquet analysis over range of amplitudes and drive frequencies.
This function largely performs two calculations. The first is the Xiao analysis introduced in https://arxiv.org/abs/2304.13656, fitting the extracted Floquet modes to the "ideal" displaced state which does not include resonances by design (because we fit to a low order polynomial and ignore any floquet modes with overlap with the bare state below a given threshold). This analysis produces the "scar" plots. The second is the Blais branch analysis, which tracks the Floquet modes by stepping in drive amplitude for a given drive frequency. For this reason the code is structured to parallelize over drive frequency, but scans in a loop over drive amplitude. This way the two calculations can be performed simultaneously.
A nice bonus is that both of the above mentioned calculations determine essentially independently whether a resonance occurs. In the first, it is deviation of the Floquet mode from the fitted displaced state. In the second, it is branch swapping that indicates a resonance, independent of any fit. Thus the two simulations can be used for cross validation of one another.
We perform these simulations iteratively over the drive amplitudes as specified by fit_range_fraction. This is to allow for simulations stretching to large drive amplitudes, where the overlap with the bare eigenstate would fall below the threshold (due to ac Stark shift) even in the absence of any resonances. We thus use the fit from the previous range of drive amplitudes as our new bare state.
run_one_floquet(omega_d_amp)
¤
Run one instance of the problem for a pair of drive frequency and amp.
Returns floquet modes as numpy column vectors, as well as the quasienergies.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
omega_d_amp |
tuple[float, float]
|
Pair of drive frequency and amp. |
required |
Displaced state¤
DisplacedState
¤
Class providing methods for computing displaced states.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
hilbert_dim |
int
|
Hilbert space dimension |
required |
model |
Model
|
Model including the Hamiltonian, drive amplitudes, frequencies, state indices |
required |
state_indices |
list
|
States of interest |
required |
options |
Options
|
Options used |
required |
bare_state_coefficients(state_idx)
¤
For bare state only component is itself.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
state_idx |
int
|
Coefficients for the state \(|state_idx\rangle\) that when evaluated at any amplitude or frequency simply return the bare state. Note that this should be the actual state index, and not the array index (for instance if we have state_indices=[0, 1, 3] because we're not interested in the second excited state, for the 3rd excited state we should pass 3 here and not 2). |
required |
displaced_state(omega_d, amp, state_idx, coefficients)
¤
Construct the ideal displaced state based on a polynomial expansion.
overlap_with_bare_states(amp_idx_0, coefficients, floquet_modes)
¤
Calculate overlap of floquet modes with 'bare' states.
'Bare' here is defined loosely. For the first range of amplitudes, the bare states are truly the bare states (the coefficients are obtained from bare_state_coefficients, which give the bare states). For later ranges, we define the bare state as the state obtained from the fit from previous range, with amplitude evaluated at the lower edge of amplitudes for the new region. This is, in a sense, the most natural choice, since it is most analogous to what is done in the first window when the overlap is computed against bare eigenstates (that obviously don't have amplitude dependence). Moreover, the fit coefficients for the previous window by definition were obtained in a window that does not include the one we are currently investigating. Asking for the state with amplitude values outside of the fit window should be done at your own peril.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
amp_idx_0 |
int
|
Index specifying the lower bound of the amplitude range. |
required |
coefficients |
ndarray
|
coefficients that specify the bare state that we calculate overlaps of Floquet modes against |
required |
floquet_modes |
ndarray
|
Floquet modes to be compared to the bare states given by coefficients |
required |
Returns: overlaps with shape (w,a,s) where w is the number of drive frequencies, a is the number of drive amplitudes (specified by amp_idxs) and s is the number of states we are investigating
overlap_with_displaced_states(amp_idxs, coefficients, floquet_modes)
¤
Calculate overlap of floquet modes with 'ideal' displaced states.
This is done here for a specific amplitude range.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
amp_idxs |
list
|
list of lower and upper amplitude indices specifying the range of drive amplitudes this calculation should be done for |
required |
coefficients |
ndarray
|
coefficients that specify the displaced state that we calculate overlaps of Floquet modes against |
required |
floquet_modes |
ndarray
|
Floquet modes to be compared to the displaced states given by coefficients |
required |
Returns: overlaps with shape (w,a,s) where w is the number of drive frequencies, a is the number of drive amplitudes (specified by amp_idxs) and s is the number of states we are investigating
DisplacedStateFit
¤
Bases: DisplacedState
Methods for fitting an ideal displaced state to calculated Floquet modes.
displaced_states_fit(omega_d_amp_slice, ovlp_with_bare_states, floquet_modes)
¤
Perform a fit for the indicated range, ignoring specified modes.
We loop over all states in state_indices and perform the fit for a given amplitude range. We ignore floquet modes (not included in the fit) where the corresponding value in ovlp_with_bare_states is below the threshold specified in options.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
omega_d_amp_slice |
list
|
Pairs of omega_d, amplitude values at which the floquet modes have been computed and which we will use as the independent variables to fit the Floquet modes |
required |
ovlp_with_bare_states |
ndarray
|
Bare state overlaps that has shape (w, a, s) where w is drive frequency, a is drive amplitude and s is state_indices |
required |
floquet_modes |
ndarray
|
Floquet mode array with the same shape as ovlp_with_bare_states except with an additional trailing dimension h, the Hilbert-space dimension. |
required |
Returns:
Type | Description |
---|---|
ndarray
|
Optimized fit coefficients |
Model¤
Model
¤
Bases: Serializable
Specify the model, including the Hamiltonian, drive strengths and frequencies.
Can be subclassed to e.g. override the hamiltonian() method for a different (but still periodic!) Hamiltonian.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
H0 |
Qobj | ndarray | list
|
Drift Hamiltonian, which must be diagonal and provided in units such that H0 can be passed directly to qutip. |
required |
H1 |
Qobj | ndarray | list
|
Drive operator, which should be unitless (for instance the charge-number operator n of the transmon). It will be multiplied by a drive amplitude that we scan over from drive_parameters.drive_amplitudes. |
required |
omega_d_values |
ndarray
|
drive frequencies to scan over |
required |
drive_amplitudes |
ndarray
|
amp values to scan over. Can be one dimensional in which case these amplitudes are used for all omega_d, or it can be two dimensional in which case the first dimension are the amplitudes to scan over and the second are the amplitudes for respective drive frequencies |
required |
amp_to_idx(amp, omega_d)
¤
Return index corresponding to amplitude value.
Because the drive amplitude can depend on the drive frequency, we also must pass the drive frequency here.
hamiltonian(omega_d_amp)
¤
Return the Hamiltonian we actually simulate.
omega_d_amp_params(amp_idxs)
¤
Return ordered chain object of the specified omega_d and amplitude values.
omega_d_to_idx(omega_d)
¤
Return index corresponding to omega_d value.
Amplitude conversion utilities¤
ChiacToAmp
¤
Convert given induced ac-stark shift values to drive amplitudes.
Consider a qubit coupled to an oscillator with the interaction Hamiltonian \(H_I = g(ab^{\dagger} + a^{\dagger}b)\). If the oscillator is driven to an average occupation number of \(\bar{n}\), then the effective drive strength seen by the qubit is \(\Omega_d = 2 g \sqrt{\bar{n}}\). On the other hand based on a Schrieffer-Wolff transformation, the interaction hamiltonian is \(H^{(2)} = \chi a^{\dagger}ab^{\dagger}b\). The average induced ac-stark shift is then \(\chi_{ac} = \chi \bar{n}\). Thus \(\Omega_d = 2g\sqrt{\chi_{\rm ac}/\chi}\). Observe that since \(\chi \sim g^2\), \(g\) effectively cancels out and can be set to 1.
XiSqToAmp
¤
Convert given \(|\xi|^2\) value into a drive amplitude.
This is based on the equivalence \(\xi = 2 \Omega_d \omega_d / (\omega_d^2-\omega^2)\), where in this definition \(|\xi|^2= 2 \chi_{\rm ac} / \alpha\) where \(\chi_{\rm ac}\) is the induced ac stark shift, \(\alpha\) is the anharmonicity and \(\Omega_d\) is the drive amplitude.
amplitudes_for_omega_d(xi_sq_linspace)
¤
Return drive amplitudes corresponding to \(|\xi|^2\) values.
Options¤
Options
¤
Bases: Serializable
Options for the floquet analysis.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
fit_range_fraction |
float
|
Fraction of the amplitude range to sweep over before changing the definition of the bare state to that of the fitted state from the previous range. For instance if fit_range_fraction=0.4, then the amplitude range is split up into three chunks: the first 40% of the amplitude linspace, then from 40% -> 80%, then from 80% to the full range. For the first fraction of amplitudes, they are compared to the bare eigenstates for identification. For the second range, they are compared to the fitted state from the first range. And so on. Defaults to 1.0, indicating that no iteration is performed. |
1.0
|
floquet_sampling_time_fraction |
float
|
What point of the drive period we want to sample the Floquet modes. Defaults to 0.0, indicating the floquet modes at t=0*T where T is the drive period. |
0.0
|
fit_cutoff |
int
|
Cutoff for the fit polynomial of the displaced state. Defaults to 4. |
4
|
overlap_cutoff |
float
|
Cutoff for fitting overlaps. Floquet modes with overlap with the "bare" state below this cutoff are not included in the fit (as they may be experiencing a resonance). Defaults to 0.8. |
0.8
|
nsteps |
int
|
QuTiP integration parameter, number of steps the solver can take. Defaults to 30_000. |
30000
|
num_cpus |
int
|
Number of cpus to use in parallel computation of Floquet modes over the different values of omega_d, amp. Defaults to 1. |
1
|
save_floquet_modes |
bool
|
Indicating whether to save the extracted Floquet modes themselves. Such data is often unnecessary and requires a fair amount of storage, so the default is False. |
False
|
File utilities¤
Serializable
¤
Mixin class for reading and writing to file using h5py.
__new__(*args, **kwargs)
¤
Records which parameters should be saved so they can be passed to init.
serialize()
¤
Serialize a class so that it is ready to be written.
This method creates nested dictionaries appropriate for writing to h5 files. Importantly, we save metadata associated with the class itself and any classes it takes as input so that they can be reinstantiated later.
Returns:
Name | Type | Description |
---|---|---|
initdata |
dict
|
Dictionary of data to save, in a format appropriate to pass to h5 |
write_to_file(filepath, data_dict=None)
¤
Write a class and associated data to file.
The goal is to be able to read back both the data that was saved and all of the data necessary to reinitialize the class.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
filepath |
str | Path
|
Path to the file where we want to save the data. Must be an h5 or h5py file |
required |
data_dict |
dict | None
|
Dictionary containing various raw data to save |
None
|
get_init_params(obj)
¤
Returns a list of parameters entering __init__
of obj
.
read_from_file(filepath)
¤
Read a class and associated data from file.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
filepath |
str | Path
|
Path to the file containing both raw data and the information needed to reinitialize our class |
required |
Returns:
Name | Type | Description |
---|---|---|
new_class_instance |
Serializable
|
Class that inherits from Serializable that was earlier written with its method write_to_file |
data_dict |
dict
|
Dictionary of data that was passed to write_to_file at the time |