TEMPO

Create time-dependent pulses.

@author: hakalas

class tempo.pulse.Pulse(recipe: Pulse_recipe, start_time: float = 0, duration: float = 0, coeff_params: dict | None = None)[source]

Bases: object

A class for creating pulses or time-dependent Hamiltonian objects.

One of the attributes of Pulse is recipe, which is an instance of pulse_recipe.Pulse_recipe, but there is a clear distinction between the two. Pulse recipe can be summarized as a blueprint (a recipe), while individual pulses are created according to the blueprint. Any number of pulses can be created with the same pulse recipe, but they can differ in the numerical values for the input parameters of the time-dependent coefficient.

A dictionary of parameters is passed in the constructor and used to evaluate the time-dependent coefficient of the pulse. The dictionary should contain all of the entries listed in the pulse recipe’s recipe.param_keys list of labels.

Parameters:
  • recipe (pulse_recipe.Pulse_recipe) – Pulse_recipe instance to provide a model for the kind of pulse.

  • start_time (float) – Start time of pulse.

  • duration (float) – Duration of pulse.

  • params (dict of float) – Dictionary of parameters to be passed in the coefficient function of recipe. All entries of recipe’s param_keys must be included in the dictionary.

recipe

pulse_recipe.Pulse_recipe instance to provide a model for the kind of pulse.

Type:

pulse_recipe.Pulse_recipe

start_time

Start time of pulse.

Type:

float

duration

Duration of pulse.

Type:

float

coeff_params

Dictionary of parameters to be passed in the time-dependent coefficient function pulse_recipe.coeff_func.

Type:

dict of float

eval_coeff(t: float, args: dict = {}) float[source]

Evaluate coefficient of pulse at time t. If args is not given, then coeff_params is used as parameter input for coefficient function. If the pulse is off at time t, the coefficient is 0. Warning that using args will mean coeff_params is entirely ignored this execution.

Parameters:
  • t (float) – The time for which to evaluate the coefficient.

  • args (dict of float, optional) – Parameters to use in recipe.coeff_func to evaluate coefficient. If not given, coeff_params is used.

Returns:

pulsecoeff – Pulse coefficient at time t.

Return type:

float

serial_eval_coeff(t: float, args: dict = {}) float[source]

Evaluate coefficient of pulse at time t. Differs from eval_coeff in that the start- and endtimes of the pulse are not taken into account; the coefficient will be evaluated whether the pulse is on or off. This method is called by the method evolver.serial_evolve in the evolver.Evolver class.

Parameters:
  • t (float) – The time for which to evaluate the coefficient.

  • args (dict of float, default = {}) – Always an empty dictionary. coeff_params is used to evaluate the coefficient via recipe.coeff_func

Returns:

coeff – Pulse coefficient at time t.

Return type:

float

update_params(keys: Iterable[str], values: Iterable[float])[source]

Add key-value pairs to coeff_params. keys and values should be the same length. Elements are paired by index.

Parameters:
  • keys (list of str) – List of parameter labels.

  • values (list of float) – List of parameter values.

The Pulse_recipe class to create time-dependent pulse models.

@author: hakalas

class tempo.pulse_recipe.Pulse_recipe(ham: Hamiltonian | None = None, param_keys: Iterable[str] | None = None, coeff_func: LambdaType | None = None)[source]

Bases: object

A class for defining types of pulses.

The Pulse_recipe class is used to create models, or recipes, for different types of pulses or time-dependent Hamiltonians. The pulse.Pulse class is then used to create individual pulse instances.

The Pulse_recipe object is composed of a time-dependent coefficient and an operator. The constructor takes the operator, a list of parameter names, and a callback function. The function, which calculates the time-dependent coefficient of the operator at a time t, must have a signature f(t: float, args: dict) -> float, for example

def func(t, args):
    return args['amp']*np.cos(2*np.pi*args['freq']*t)

In this example the list of parameter names passed would be keys = ['amp', 'freq']. The dictionary args is not part of the Pulse_recipe class; it is incorporated in the pulse.Pulse class, where one can evaluate the numerical value of the callback function based on a particular dictionary of values. The callback function should not include checks for whether the pulse is on or off; this can be achieved by defining the particular pulse’s start time and end time in the pulse.Pulse class.

Parameters:
  • ham (hamiltonian.Hamiltonian) – Hamiltonian instance that describes the operator part of the pulse.

  • param_keys (list of str) – List of names of parameters used in coeff_func. Names should be strings.

  • coeff_func (function) – Callback function that calculates the time-dependent coefficient using a time t and a dictionary of args.

ham

Hamiltonian instance that describes the operator part of the pulse.

Type:

hamiltonian.Hamiltonian

param_keys

List of names of parameters used in coeff_func. Names should be strings.

Type:

list of str

coeff_func

Callback function that calculates the time-dependent coefficient using a time t and a dictionary of args.

Type:

function

eval_coeff(t: float, params: dict)[source]

Pulse coefficient at time t.

Parameters:
  • t (float) – The time for which to evaluate the coefficient.

  • params (dict of float) – Parameters to use in coeff_func to evaluate coefficient.

Returns:

coeff – Pulse coefficient at time t.

Return type:

float

Sequence (list) of pulses.

@author: hakalas

class tempo.pulse_sequence.Pulse_sequence(pulses: Iterable[Pulse] | None = None, Hstat: Hamiltonian | Qobj | None = None)[source]

Bases: object

Class for creating sequences or lists of pulses.

A Pulse sequence object stores all pulses applied to a system during a single simulation. If there is a static (time-independent) Hamiltonian that applies throughout the entire simulation, this should be passed to the constructor separately.

The pulses may be added all at once in a list in the constructor, or they may be added one by one after the initialization of the pulse sequence.

Parameters:
  • pulses (list of pulse.Pulse) – List of pulse.Pulse instances that make up the pulse sequence. Pulses do not have to be ordered in any way.

  • Hstat (hamiltonian.Hamiltonian or qutip.Qobj, optional) – Time-independent Hamiltonian that applies at all times in the simulation.

pulses

List of pulse.Pulse instances that make up the pulse sequence.

Type:

list of pulse.Pulse

Hstat

Time-independent Hamiltonian that applies at all times in the simulation.

Type:

qutip.Qobj

add_pulse(pls: Pulse | Iterable[Pulse])[source]

Add a pulse or list of pulses to the sequence.

Parameters:

pls (pulse.Pulse or list of pulse.Pulse) – Pulse(s) to be added.

remove_pulse(pls: Pulse | Iterable[Pulse])[source]

Remove a pulse or list of pulses from the sequence. If there are multiple copies of the same pulse in the sequence, then only the first instance is removed.

Parameters:

pls (pulse.Pulse or list of pulse.Pulse) – Pulse(s) to be removed.

timing_info() dict[source]

Get a dictionary with the start time, duration, and end time of the entire pulse sequence. Start time is the start time of the earliest pulse in the sequence, and end time is accordingly the end time of the last-ending pulse in the sequence. Note that the simulation itself may span a longer time duration than this if the times at which the state of the system is evaluated extend outside of the pulse sequence time range; for example, there may be a duration of time at the beginning or end of the simulation where only the static Hamiltonian applies.

The Hamiltonian class for representing Hamiltonian operators.

@author: hakalas

class tempo.hamiltonian.Hamiltonian(ops: dict = {}, op_params: dict = {}, func: LambdaType | None = None)[source]

Bases: object

A class for representing time-independent Hamiltonian operators.

The Hamiltonian object is composed of a numerical coefficient and an operator. The constructor takes a dictionary of parameters and a dictionary of operators, along with a callback function. The Python function tells the Hamiltonian how to combine the parameters and operators into a single term. For example, if the Hamiltonian term is \(a/bC\cdot D\), then

def func(ops, op_params):
    return op_params['a']/op_params['b']*ops['C']*ops['D']

ops = {'C': C, 'D': D}
op_params = {'a': a, 'b': b}
Parameters:
  • ops (dict of qutip.Qobj or qutip.Qobj) – Dictionary of all operators that make up the final Hamiltonian. If the Hamiltonian has no specified numerical coefficient and is only composed of one operator, the operator may be passed directly as a qutip.Qobj. In this case params and func are not needed as inputs.

  • op_params (dict, optional) – Dictionary of numerical parameters that make up the coefficient of the final Hamiltonian.

  • func (function, optional) – Callback function that takes the operators and parameters to combine.

ops

Dictionary of all operators that make up the final Hamiltonian.

Type:

dict of qutip.Qobj or qutip.Qobj

op_params

Dictionary of scalars that make up the coefficient of the final Hamiltonian.

Type:

dict of float / float array, Qobj

func

Callback function that takes the operators and scalars to combine.

Type:

function

property H

Time-independent Hamiltonian term as a qutip.Qobj.

Parameters:
  • ops (dict of qutip.Qobj, optional) – Dictionary of operators to pass to the callback function. If None, then the dictionary ops passed in the constructor is used.

  • op_params (dict of float, optional) – Dictionary of numerical parameters to pass to the callback function. If None, then the dictionary op_params passed in the constructor is used.

Returns:

H – Time-independent Hamiltonian with a numerical coefficient part and an operator part.

Return type:

qutip.Qobj

Class to implement time-evolution of a state under applied pulses.

@author: hakalas

class tempo.evolver.Evolver(state_init: Qobj | None = None, tlist: Iterable[float] | None = None, pulse_seq: Pulse_sequence | None = None, c_ops: Iterable[Qobj] | None = None, e_ops: Iterable[Qobj] | Iterable[LambdaType] | None = None, opts: Options | None = None)[source]

Bases: object

Time-evolution of a state under a pulse sequence.

The Evolver object stores information about a particular pulse sequence simulation. Its evolve method evolves the given initial state state_init when the pulses in pulse_seq are applied. evolve relies on QuTiP’s qutip.mesolve method and the inputs c_ops, e_ops, and opts, if defined, are directly passed to mesolve. For these, see mesolve documentation https://qutip.org/docs/latest/apidoc/functions.html#module-qutip.mesolve.

Parameters:
  • state_init (qutip.Qobj) – Initial state vector or density matrix.

  • pulse_seq (pulse_sequence.Pulse_sequence) – Sequence of pulses to be applied to initial state.

  • tlist (list of float) – List of times at which to evaluate the system’s state or the expectation value of the operator(s) in e_ops.

  • Hstat (hamiltonian.Hamiltonian or qutip.Qobj, optional) – Time-independent Hamiltonian that applies at all times in the simulation.

  • c_ops (list of qutip.Qobj) – List of collapse operators.

  • e_ops (list of qutip.Qobj or callback functions) – List of operators for which to evaluate expectation values.

  • opts (qutip.Options) – Options for qutip.mesolve.

state_init

Initial state vector or density matrix.

Type:

qutip.Qobj

tlist

List of times at which to evaluate the system’s state or the expectation value of the operator(s) in e_ops.

Type:

list of float

pulse_seq

Sequence of pulses to be applied to initial state.

Type:

pulse_sequence.Pulse_sequence

c_ops

List of collapse operators.

Type:

list of qutip.Qobj

e_ops

List of operators for which to evaluate expectation values.

Type:

list of qutip.Qobj or callback functions

opts

Options for mesolve.

Type:

qutip.Options

evolve(state_init: Qobj | None = None, tlist: Iterable[float] | None = None, pulse_seq: Pulse_sequence | None = None, c_ops: Iterable[Qobj] | None = None, e_ops: Iterable[Qobj] | None = None, opts: Options | None = None, method: str = 'serial', t_rtol: float = 1e-08) Result[source]

Evolve state_init using given pulse sequence. Collapse operators c_ops may be passed. Return a qutip.Result object which stores output for each timestamp given in tlist. If e_ops is left as None, qutip.Result contains the state vector of the system at each timestamp in its states attribute. Otherwise, the expectation values of the operator(s) listed in e_ops are stored in qutip.Result.expect in a 2-dimensional list.

The parameter evolve_method may take one of three values: ‘regular’, ‘serial’, or ‘serial_safe’. These describe different ways of solving the evolution of the state, but ultimately all use qutip.mesolve at their base. The two serial options significantly reduce runtime for evolving systems with many pulses, especially if the total number of pulses is much larger than the number of overlapping pulses at any given instant. ‘serial’ is the fastest of the three, but ‘serial_safe’ is slightly more true to the plain qutip.mesolve (denoted by ‘regular’) in terms of state accuracy. One can additionally control the relative error tolerance in integration by changing the parameter t_rtol, which applies to ‘serial’ and ‘serial_safe’.

Parameters:
  • state_init (qutip.Qobj) – Initial state vector or density matrix.

  • tlist (list of float) – List of times at which to evaluate the system’s state or the expectation value of the operator(s) in e_ops.

  • pulse_seq (pulse_sequence.Pulse_sequence) – Pulse sequence instance containing the pulses for this simulation.

  • c_ops (list of qutip.Qobj) – List of collapse operators.

  • e_ops (list of qutip.Qobj) – List of operators for which to evaluate expectation values.

  • opts (qutip.Options) – Options for mesolve.

  • method (str {'regular', 'serial', 'serial_safe'}, default = 'serial') – Choice of which solving method to use.

  • t_rtol (float, default = 1e-8) – Relative time-step tolerance. Determines which relative time differences can be resolved in serial and serial_safe evolve methods.

Returns:

result – System state or expectation value at tlist timestamps.

Return type:

qutip.Result

generate_H(pulse_seq: Pulse_sequence)[source]

Put Hamiltonian terms (static Hamiltonian and pulses) in a list together. The static Hamiltonian is first. Time-dependent (pulse) terms are [operator, callback function] pairs. The resulting list is in the correct format to be passed directly into mesolve as H. Return types are equivalent to mesolve.

Parameters:

pulse_seq (pulse_sequence.Pulse_sequence) – Sequence of pulses to be applied to the state.

Returns:

H – List of qutip.Qobj instances and [qutip.Qobj, callback function] pairs. List of Hamiltonian terms and their coefficients at each point in time.

Return type:

list of qutip.Qobj or list of [qutip.Qobj, function]

serial_evolve(pulse_seq: Pulse_sequence, state_init: Qobj, tlist: Iterable[float], c_ops: Iterable[Qobj], e_ops: Iterable[Qobj], opts: Options, t_rtol: float)[source]
serial_generate_H(pulselist: Iterable[Pulse], safe: bool = False)[source]

Generate H (Hamiltonian) for use given a pulselist.

Parameters:
  • pulselist (Iterable of type Pulse) – List with which to build the Hamiltonian.

  • safe (Boolean) – Whether or not we should use the serial_eval_coeff for the pulses (unsafe) or the eval_coeff (safe).

Returns:

H – List with the Hamiltonians of each pulse and the coefficient [[H, coeff], …]

Return type:

List

serial_safe_evolve(pulse_seq: Pulse_sequence, state_init: Qobj, tlist: Iterable[float], c_ops: Iterable[Qobj] | None = None, e_ops: Iterable[Qobj] | None = None, opts: Iterable[Qobj] | Iterable[LambdaType] | None = None, t_rtol: float = 1e-08)[source]
tempo.evolver.create_result_object(e_ops=None, opts=None, times=None, states=None, expect_values=None)[source]

Create a QuTiP Result object compatible with QuTiP 5.x.

tempo.evolver.safe_copy_result_attributes(to_result, from_result)[source]

Safely copy attributes from one Result object to another, handling missing attributes.