SkeletalSystem

class qugradlab.systems.skeletons.SkeletalSystem(drift_coefficients: list[ndarray], drift_skeletons: list[ndarray], ctrl_coefficients: list[ndarray], ctrl_skeletons: list[ndarray], hilbert_space: HilbertSpace, use_graph: bool = True)[source]

Bases: QuantumSystem

A quantum system with a Hamiltonian built upon an operator skeleton.

Attributes

H0

The systems drift Hamiltonian as a dim x dim matrix.

Hs

An array of the system's control Hamiltonians with shape (n_ctrl, dim, dim).

dim

The dimension of states in the quantum system.

evolver

The integrator used for time evolutions of the system.

hilbert_space

The Hilbert space of the system

n_ctrl

The number of control Hamiltonians.

state_shape

The shape of the states in the system.

using_graph

Whether to use TensorFlow graphs during computation.

Methods

H

Computes the system Hamiltonian for the specified control amplitudes.

__init__

_envolope_processing

When calling any evolution method (listed in the See also section section) _pre_processing() is executed on the arguements before the control amplitudes are modulated by the frequencies during _envolope_processing() and then finally the modulated control amplitudes are used by the evolution method.

_pre_processing

When calling any evolution method (listed in the See also section) _pre_processing() is executed on the arguements before the control amplitudes are modulated by the frequencies (during _envolope_processing()) and then finally the modulated control amplitudes are used by the evolution method.

evolved_expectation_value

Evolves a state vector under the time-dependent Hamiltonian defined by the control amplitudes and computes the expectation value of a specified observable with respect to the final state using evolved_expectation_value() from PySTE.

evolved_expectation_value_all

Evolves a state vector under the time-dependent Hamiltonian defined by the control amplitudes and computes the expectation value of a specified observable with respect to the state at each time-step using evolved_expectation_value_all() from PySTE.

get_driving_pulses

When calling any evolution method (listed in the See also section) get_driving_pulses() is executed on the arguements before the evolution method.

gradient

Evolves a state vector under the time-dependent Hamiltonian defined by the control amplitudes and computes the expectation value of a specified observable with respect to the final state and then computes the gradient of the final state with respect to the first argument (args[0]) using switching_function() from PySTE.

initialise_evolver

Initialises evolver with an evolver from PySTE.

propagate

Evolves a state vector under the time-dependent Hamiltonian defined by the control amplitudes using propagate() from PySTE.

propagate_all

Evolves a state vector under the time-dependent Hamiltonian defined by the control amplitudes using propagate_all() from PySTE and returns the state at each time-step.

propagate_collection

Evolves a collection of state vectors under the time-dependent Hamiltonian defined by the control amplitudes using propagate_collection() from PySTE.

pulse_form

Initialises a new QuantumSystem in which _pre_processing() corresponds to executing pulse_function() and piping the output into the previous definition of _pre_processing().

H(ctrl_amp: ndarray[float] | ndarray[Callable[[float], ndarray[float]]]) ndarray[complex] | Callable[[float], ndarray[complex]]

Computes the system Hamiltonian for the specified control amplitudes.

Parameters:

ctrl_amp (NDArray[Shape[s := Any_Shape, n_ctrl], float | Callable[[float], np.ndarray[float]]]) – The control amplitudes (stored in the last axis). The prior axes allow for multiple sets of control amplitudes to be passed and the Hamiltonian for each computed. The control amplitudes can be passed as np.ndarray[float] to compute the system Hamiltonian for a specific value of the control ampltiudes. Alternatively, the control amplitudes can be passed as np.ndarray[Callable[[float], np.ndarray[float]]] where each element is a function of time. This will generate a time-dependent Hamiltonian: a function that takes a single parameter (time) and returns the Hamiltonian at this time.

Returns:

Either the systems Hamiltonian stored in the last two axes (if specific control amplitudes were passed) or a collection of time-dependent Hamiltonians (if time-dependent controls were passed).

Return type:

NDArray[Shape[s, dim, dim], complex] | NDArray[Shape[s], Callable[[float], np.ndarray[complex]]]]

__init__(drift_coefficients: list[ndarray], drift_skeletons: list[ndarray], ctrl_coefficients: list[ndarray], ctrl_skeletons: list[ndarray], hilbert_space: HilbertSpace, use_graph: bool = True)[source]
Parameters:
  • drift_coefficients (list[np.ndarray]) – The coefficients of the drift Hamiltonian

  • drift_skeletons (list[np.ndarray]) – The operator skeletons for the drift Hamiltonian

  • coefficients (list[np.ndarray]) – The coefficients of the control Hamiltonians

  • skeletons (list[np.ndarray]) – The operator skeletons for the control Hamiltonians

  • hilbert_space (HilbertSpace) – The Hilbert space of the system

  • use_graph (bool) – Whether to use TensorFlow graphs during computation, by default True

_envolope_processing(ctrl_amp, dt: float, frequencies, number_channels: list[int]) tuple

When calling any evolution method (listed in the See also section section) _pre_processing() is executed on the arguements before the control amplitudes are modulated by the frequencies during _envolope_processing() and then finally the modulated control amplitudes are used by the evolution method.

Parameters:
  • ctrl_amp (tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]) – The envolope control amplitudes

  • dt (float) – The itegration time step

  • frequencies (tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]) – The frequencies to modulate the control amplitudes with

  • number_channels (list[int]) –

    The number of channels associated with each control Hamiltonian

    Warning

    This must be a list and not an NDArray or a TensorFlow tensor.

Returns:

The modulated control amplitudes

Return type:

tf.Tensor[Shape[n_time_steps, n_ctrl], tf.complex128]

_pre_processing(ctrl_amp: ndarray[complex], initial_state: ndarray[complex], dt: float, frequencies: ndarray[complex], number_channels: list[int]) tuple

When calling any evolution method (listed in the See also section) _pre_processing() is executed on the arguements before the control amplitudes are modulated by the frequencies (during _envolope_processing()) and then finally the modulated control amplitudes are used by the evolution method.

_pre_processing() should be overridden to produce desired pulse shapes. You can either override _pre_processing() directly by creating a child class, or you can use pulse_form().

For gradient() to function correctly _pre_processing() should be written in TensorFlow.

Parameters:
  • ctrl_amp (NDArray[Shape[n_time_steps, n_ctrl], complex]) – The envolope control amplitudes

  • initial_state (NDArray[Shape[state_shape], complex]) – The initial state for the integrator

  • dt (float) – The itegration time step

  • frequencies (NDArray[Shape[n_time_steps, n_ctrl], complex]) – The frequencies to modulate the control amplitudes with

  • number_channels (list[int]) –

    The number of channels associated with each control Hamiltonian

    Warning

    This must be a list and not an NDArray or a TensorFlow tensor.

Returns:

A tuple of 1. The control amplitude envolopes 2. The initial state 3. The integrator time step 4. The frequencies to modulate the control amplitude envolopes with 5. A list of the number of channels for each control Hamiltonian

Warning

The number of channels for each control Hamiltonian must be stored as a list and not an NDArray or a TensorFlow tensor.

Return type:

tuple[tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128], tf.Tensor[Shape[state_shape], tf.complex128], float, tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128], list[int]]

Warning

Keyword arguments are not supported.

evolved_expectation_value(ctrl_amp: ndarray[complex], initial_state: ndarray[complex], dt: float, frequencies: ndarray[complex], number_channels: list[int], observable: ndarray[complex]) complex

Evolves a state vector under the time-dependent Hamiltonian defined by the control amplitudes and computes the expectation value of a specified observable with respect to the final state using evolved_expectation_value() from PySTE.

Parameters:
  • ctrl_amp (tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]) – The envolope control amplitudes

  • initial_state (NDArray[Shape[state_shape], complex]) – The initial state for the integrator

  • dt (float) – The itegration time step

  • frequencies (tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]) – The frequencies to modulate the control amplitudes with

  • number_channels (list[int]) –

    The number of channels associated with each control Hamiltonian

    Warning

    This must be a list and not an NDArray or a TensorFlow tensor.

  • observable (NDArray[Shape[dim, dim], complex]) – The observable to take the expectation value of.

Warning

Keyword arguments are not supported.

Returns:

The expectation value.

Return type:

complex

evolved_expectation_value_all(ctrl_amp: ndarray[complex], initial_state: ndarray[complex], dt: float, frequencies: ndarray[complex], number_channels: list[int], observable: ndarray[complex]) ndarray[complex]

Evolves a state vector under the time-dependent Hamiltonian defined by the control amplitudes and computes the expectation value of a specified observable with respect to the state at each time-step using evolved_expectation_value_all() from PySTE.

Parameters:
  • ctrl_amp (tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]) – The envolope control amplitudes

  • initial_state (NDArray[Shape[state_shape], complex]) – The initial state for the integrator

  • dt (float) – The itegration time step

  • frequencies (tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]) – The frequencies to modulate the control amplitudes with

  • number_channels (list[int]) –

    The number of channels associated with each control Hamiltonian

    Warning

    This must be a list and not an NDArray or a TensorFlow tensor.

  • observable (NDArray[Shape[dim, dim], complex]) – The observable to take the expectation value of.

Warning

Keyword arguments are not supported.

Returns:

The state at each integrator time step (including the initial state).

Return type:

NDArray[Shape[n_time_steps+1], complex]

get_driving_pulses(ctrl_amp: ndarray[complex], initial_states: ndarray[complex], dt: float, frequencies: ndarray[complex], number_channels: list[int]) tuple[ndarray[complex], ndarray[complex], float]

When calling any evolution method (listed in the See also section) get_driving_pulses() is executed on the arguements before the evolution method.

Parameters:
  • ctrl_amp (NDArray[Shape[n_time_steps, n_ctrl], complex]) – The envolope control amplitudes

  • initial_state (NDArray[Shape[state_shape], complex]) – The initial state for the integrator

  • dt (float) – The itegration time step

  • frequencies (NDArray[Shape[n_time_steps, n_ctrl], complex]) – The frequencies to modulate the control amplitudes with

  • number_channels (list[int]) –

    The number of channels associated with each control Hamiltonian

    Warning

    This must be a list and not an NDArray or a TensorFlow tensor.

Warning

Keyword arguments are not supported.

Returns:

A tuple of: 1. Control amplitudes 2. Initial state 3. Integrator time step

Return type:

tuple[NDArray[Shape[n_time_steps, n_ctrl], complex], NDArray[Shape[state_shape], complex], float]

gradient(ctrl_amp: ndarray[complex], initial_state: ndarray[complex], dt: float, frequencies: ndarray[complex], number_channels: list[int], observable: ndarray[complex]) tuple[float, ndarray[float]]

Evolves a state vector under the time-dependent Hamiltonian defined by the control amplitudes and computes the expectation value of a specified observable with respect to the final state and then computes the gradient of the final state with respect to the first argument (args[0]) using switching_function() from PySTE.

Parameters:
  • ctrl_amp (tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]) – The envolope control amplitudes

  • initial_state (NDArray[Shape[state_shape], complex]) – The initial state for the integrator

  • dt (float) – The itegration time step

  • frequencies (tf.Tensor[Shape[n_time_steps, total_n_channels], tf.complex128]) – The frequencies to modulate the control amplitudes with

  • number_channels (list[int]) –

    The number of channels associated with each control Hamiltonian

    Warning

    This must be a list and not an NDArray or a TensorFlow tensor.

  • observable (NDArray[Shape[dim, dim], complex]) – The observable to take the expectation value of.

Warning

Keyword arguments are not supported.

Returns:

A tuple of the expectation value and the gradient.

Return type:

tuple[complex, NDArray[Shape[n_parameters], float]]

initialise_evolver(sparse: bool = False, force_dynamic: bool = False)

Initialises evolver with an evolver from PySTE. PySTE is Python wrapper around the C++ header-only library Suzuki-Trotter-Evolver: a fast Schrödinger solver utilising the first-order Suzuki-Trotter expansion.

Warning

This can take a very long time to execute, especially for large Hilbert space dimensions. If you plan to evolve the same quantum system many times we recommended pickling the evolver.

Parameters:
  • sparse (bool) – Whether to use sparse or dense matrices during integration. To make a decision on whether sparse or dense matrices are likely to lead to faster integration you can consult the benchmarks at https://PySTE.readthedocs.io/en/latest/benchmarks.

  • force_dynamic (bool) –

    Whether to force PySTE to use a dynamic evolver.

    Note

    PySTE has precompiled evolvers for specific Hilbert space dimensions and numbers of control Hamiltonians. When these cannot be found PySTE uses less efficient evolvers with the Hilbert space dimension and the number of controls determined dynamically at runtime.

propagate(ctrl_amp: ndarray[complex], initial_state: ndarray[complex], dt: float, frequencies: ndarray[complex], number_channels: list[int]) ndarray[complex]

Evolves a state vector under the time-dependent Hamiltonian defined by the control amplitudes using propagate() from PySTE.

Parameters:
  • ctrl_amp (NDArray[Shape[n_time_steps, n_ctrl], complex]) – The envolope control amplitudes

  • initial_state (NDArray[Shape[state_shape], complex]) – The initial state for the integrator

  • dt (float) – The itegration time step

  • frequencies (NDArray[Shape[n_time_steps, n_ctrl], complex]) – The frequencies to modulate the control amplitudes with

  • number_channels (list[int]) –

    The number of channels associated with each control Hamiltonian

    Warning

    This must be a list and not an NDArray or a TensorFlow tensor.

Warning

Keyword arguments are not supported.

Returns:

The final state

Return type:

NDArray[Shape[state_shape], complex]

propagate_all(ctrl_amp: ndarray[complex], initial_states: ndarray[complex], dt: float, frequencies: ndarray[complex], number_channels: list[int]) ndarray[complex]

Evolves a state vector under the time-dependent Hamiltonian defined by the control amplitudes using propagate_all() from PySTE and returns the state at each time-step.

Parameters:
  • ctrl_amp (NDArray[Shape[n_time_steps, n_ctrl], complex]) – The envolope control amplitudes

  • initial_state (NDArray[Shape[state_shape], complex]) – The initial state for the integrator

  • dt (float) – The itegration time step

  • frequencies (NDArray[Shape[n_time_steps, n_ctrl], complex]) – The frequencies to modulate the control amplitudes with

  • number_channels (list[int]) –

    The number of channels associated with each control Hamiltonian

    Warning

    This must be a list and not an NDArray or a TensorFlow tensor.

Warning

Keyword arguments are not supported.

Returns:

The state at each integrator time step (including the initial state).

Return type:

NDArray[Shape[n_time_steps+1, state_shape], complex]

propagate_collection(ctrl_amp: ndarray[complex], initial_states: ndarray[complex], dt: float, frequencies: ndarray[complex], number_channels: list[int]) ndarray[complex]

Evolves a collection of state vectors under the time-dependent Hamiltonian defined by the control amplitudes using propagate_collection() from PySTE.

Parameters:
  • ctrl_amp (NDArray[Shape[n_time_steps, n_ctrl], complex]) – The envolope control amplitudes

  • initial_states (NDArray[Shape[n_states, state_shape], complex]) – The initial state for the integrator

  • dt (float) – The itegration time step

  • frequencies (NDArray[Shape[n_time_steps, n_ctrl], complex]) – The frequencies to modulate the control amplitudes with

  • number_channels (list[int]) –

    The number of channels associated with each control Hamiltonian

    Warning

    This must be a list and not an NDArray or a TensorFlow tensor.

Warning

Keyword arguments are not supported.

Returns:

The final state

Return type:

NDArray[Shape[n_states, state_shape], complex]

pulse_form(pulse_function: Callable, path: str | None = None) PulseForm

Initialises a new QuantumSystem in which _pre_processing() corresponds to executing pulse_function() and piping the output into the previous definition of _pre_processing().

Parameters:

pulse_function (Callable) – The function to compose with _pre_processing().

Returns:

The new QuantumSystem

Return type:

PulseForm

property H0: ndarray[complex]

The systems drift Hamiltonian as a dim x dim matrix.

See also

Hs

property Hs: ndarray[complex]

An array of the system’s control Hamiltonians with shape (n_ctrl, dim, dim).

See also

H0

property dim: int

The dimension of states in the quantum system.

See also

state_shape

property evolver: UnitaryEvolver

The integrator used for time evolutions of the system.

Note

The evolver can take a while to initialise and so is not initialised until evolver is is first used or when initialise_evolver() is called. Using evolver before calling initialise_evolver() initialises the evolver with the default parameters of initialise_evolver().

property hilbert_space: HilbertSpace

The Hilbert space of the system

property n_ctrl: int

The number of control Hamiltonians.

property state_shape: tuple[int]

The shape of the states in the system.

See also

dim

property using_graph: bool

Whether to use TensorFlow graphs during computation. Using a TensorFlow graph will increase the speed of computation. However, you have to be careful that function parameters have not been baked into the graph leading to unexpected behaviour.