qugrad.systems.TransformedSystem

class qugrad.systems.TransformedSystem(original_system: QuantumSystem, H0: ndarray[complex], Hs: ndarray[complex], hilbert_space: HilbertSpace)[source]

Bases: QuantumSystem

A base class for representing a transformation on a qugrad.QuantumSystem.

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).

base_system

The system before any transformations were applied.

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.

original_system

The system that was transformed into this system

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__

Performs a transformation on a qugrad.QuantumSystem.

_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 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__(original_system: QuantumSystem, H0: ndarray[complex], Hs: ndarray[complex], hilbert_space: HilbertSpace)[source]

Performs a transformation on a qugrad.QuantumSystem.

Parameters:
  • original_system (QuantumSystem) – The system to be transformed into this system

  • H0 (NDArray[Shape[dim, dim], complex]) – The new drift Hamiltonian

  • Hs (NDArray[Shape[”n_ctrl, dim, dim”], complex] | NDArray[Shape[n_ctrl * dim, dim], complex]) – The new control Hamiltonians either as an array of control Hamiltonians or the control Hamiltonians stacked along the first axis.

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

_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(*args)[source]

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.

This is a placeholder for original_system._pre_processing().

Parameters:

*args – The placeholder parameters. The actual parameters will be the same as original_system._pre_processing().

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]]

evolved_expectation_value(*args) complex[source]

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:
  • *args[:-1] – The placeholder parameters. The actual parameters will be the same as original_system._pre_processing().

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

Returns:

The expectation value.

Return type:

complex

evolved_expectation_value_all(*args) ndarray[complex][source]

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:
  • *args[:-1] – The placeholder parameters. The actual parameters will be the same as original_system._pre_processing().

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

Returns:

get_driving_pulses(*args) tuple[ndarray[complex], ndarray[complex], float][source]

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

Parameters:

*args – The placeholder parameters. The actual parameters will be the same as original_system._pre_processing().

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(*args) tuple[float, ndarray[float]][source]

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:
  • *args[:-1] – The placeholder parameters. The actual parameters will be the same as original_system._pre_processing().

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

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(*args) ndarray[complex][source]

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

Parameters:

*args – The placeholder parameters. The actual parameters will be the same as original_system._pre_processing().

Returns:

The final state

Return type:

NDArray[Shape[state_shape], complex]

propagate_all(*args) ndarray[complex][source]

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:

*args – The placeholder parameters. The actual parameters will be the same as original_system._pre_processing().

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(*args) ndarray[complex][source]

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

Parameters:

*args – The placeholder parameters. The actual parameters will be the same as original_system._pre_processing().

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 base_system: QuantumSystem

The system before any transformations were applied. That is base_system is the recursive original_system (original_system.original_system.original_system....) until original_system is no longer a TransformedSystem.

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 original_system: QuantumSystem

The system that was transformed into this system

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.