SparseUnitaryEvolver_nctrl_dim

class py_ste.evolvers.SparseUnitaryEvolver_nctrl_dim(drift_hamiltonian: ndarray[complex128], control_hamiltonians: ndarray[complex128])[source]

Bases: SparseUnitaryEvolver

A class to store the diagonalised drift and control Hamiltonians with sparse matrices and precompiled values of n_ctrl and dim.

Important

This is not the actual class name nctrl and dim should be replaced with positive integers to specify their values. For example, SparseUnitaryEvolver_3_2 is a valid class name with n_ctrl =3 control Hamiltonians acting on a dim =2 dimensional vector space. If only one of nctrl and dim is precompiled the other should be specified as Dynamic. For example, SparseUnitaryEvolver_Dynamic_2 is a valid class name with a dynamic number of control Hamiltonians (n_ctrl =-1) acting on a dim =2 dimensional vector space.

On initialisation the Hamiltonians are diagonalised and the eigenvectors and values stored as sparse and dense matrices, respectively. This initial diagonalisation may be slow and takes \(O(\textrm{dim}^3)\) time for a \(\textrm{dim}\times \textrm{dim}\) Hamiltonian. However, it allows each step of the Suzuki-Trotter expansion to be implimented with sparse matrix multiplication and only scalar exponentiation opposed to matrix exponentiation.

Note

This class is a Python wrapper around the C++ struct:

Suzuki_Trotter_Evolver::UnitaryEvolver<n_ctrl, dim, SMatrix>

from Suzuki-Trotter-Evolver.

Note

Unlike SparseUnitaryEvolver, n_ctrl and dim are baked into the class when the C++ code is compiled allowing for more efficient state propagation.

Attributes

dim

The dimension of the vector space the Hamiltonians act upon used to compile the C++ backend.

dim_x_n_ctrl

The dimension of rows in each control Hamiltonian multiplied by the number of control Hamiltonians upon used to compile the C++ backend.

n_ctrl

The number of control Hamiltonians used to compile the C++ backend.

length

The number of control Hamiltonians.

d0

The eigenvalues, \(\operatorname{diag}(D_0)\), of the drift Hamiltonian: \(H_0=U_0D_0U_0^\dagger\).

ds

The eigenvalues, \(\left(\operatorname{diag}(D_i)\right)_{i=1}^{\textrm{length}}\), of the control Hamiltonians: \(H_i=U_iD_iU_i^\dagger\) for all \(i\in\left[\textrm{length}\right]\).

u0

The unitary transformation, \(U_0\), that diagonalises the drift Hamiltonian: \(H_0=U_0D_0U_0^\dagger\).

u0_inverse

The inverse of the unitary transformation, \(U_0^\dagger\), that diagonalises the drift Hamiltonian: \(H_0=U_0D_0U_0^\dagger\).

us

The unitary transformations, \((U_i^\dagger U_{i-1})_{i=1}^{\textrm{length}}\), from the eigen basis of \(H_{i-1}\) to the eigen basis of \(H_i\).

us_individual

The unitary transformations, \(\left(U_i\right)_{i=1}^{\textrm{length}}\), that diagonalise the control Hamiltonians: \(H_i=U_iD_iU_i^\dagger\) for all \(i\in\left[\textrm{length}\right]\).

us_inverse_individual

The inverse of the unitary transformations, \((U_i^\dagger)_{i=1}^{\textrm{length}}\), that diagonalise the control Hamiltonians: \(H_i=U_iD_iU_i^\dagger\) for all \(i\in\left[\textrm{length}\right]\).

hs

The control Hamiltonians: \(H_i\) for all \(i\in\left[\textrm{length}\right]\).

u0_inverse_u_last

The unitary transformation, \(U_0^\dagger U_{\textrm{length}}\), from the eigen basis of \(H_{\textrm{length}}\) to the eigen basis of \(H_0\).

Methods

__init__

Initialises a new unitary evolver with the Hamiltonian

evolved_expectation_value

Calculates the expectation value with respect to an observable of an evolved state vector evolved under a control Hamiltonian modulated by the control amplitudes.

evolved_expectation_value_all

Calculates the expectation values with respect to an observable of a time series of state vectors evolved under a control Hamiltonian modulated by the control amplitudes.

evolved_gate_infidelity

Calculates the gate infidelity with respect to a target gate of the gate produced by the control Hamiltonian modulated by the control amplitudes.

evolved_inner_product

Calculates the real inner product of an evolved state vector with a fixed vector.

evolved_inner_product_all

Calculates the real inner products of a time series of evolved state vectors with a fixed vector.

gate_switching_function

Calculates the switching function for a Mayer problem with the gate infidelity as the cost function. More precisely if the cost function is $$ J\left[\vec a(t)\right] \coloneqq\mathcal I(U\left[\vec a(t); T\right], \texttt{target}) \coloneqq 1-\frac{\left|\Tr\left[\texttt{target}^\dagger \cdot U\left[\vec a(t); T\right]\right]\right|^2 +\texttt{dim}}{\texttt{dim}(\texttt{dim}+1)}. $$ where \(T=N\Delta t\), then the switching function is $$ \begin{align} &\phi_j(t)\coloneqq\frac{\delta J}{\delta a_j(t)}\\ &=\frac{2}{\texttt{dim}(\texttt{dim}+1)}\operatorname{Im}\left( \Tr\left[U^\dagger(N\Delta t)\cdot\texttt{target}\right] \Tr\left[\texttt{target}^\dagger \cdot U(t\to T)H_j U[\vec a(t);t]\right]\right). \end{align} $$ Using the first-order Suzuki-Trotter expansion we can express the switching function as $$ \begin{align} &\phi_j(n\Delta t)=\frac{1}{\Delta t}\pdv{J}{a_{nj}}\\ &=\!\frac{2}{\texttt{dim}(\texttt{dim}+1)}\operatorname{Im} \!\left( \Tr\!\left[U^\dagger(N\Delta t)\cdot\texttt{target}\right] \vphantom{[\prod_{k=j}^{\textrm{length}}}\right.\\ &\left.\cdot\Tr\!\left[\texttt{target}^\dagger\!\cdot\! \left[\prod_{i>n}^N\prod_{k=1}^{\textrm{length}} e^{-ia_{ik}H_k\Delta t}\right]\!\!\! \left[\prod_{k=j}^{\textrm{length}} e^{-ia_{nk}H_k\Delta t}\right]\!H_j\!\! \left[\prod_{k=0}^{j-1} e^{-ia_{nk}H_k\Delta t}\right] \! U(\left[n-1\right]\Delta t)\right]\right), \end{align} $$ where for numerical efficiency we replace \(e^{-ia_{ik}H_k\Delta t}\) with \(U_ke^{-ia_{ik}D_k\Delta t}U_k^\dagger\) as in get_evolution().

get_evolution

Computes the unitary corresponding to the evolution under the differential equation $$ \dot U=-iHU. $$ The computation is performed using the first-order Suzuki-Trotter expansion: $$ \begin{align} U(N\Delta t)&=\prod_{i=1}^N\prod_{j=0}^{\textrm{length}} e^{-ia_{ij}H_j\Delta t}+\mathcal E\\ &=\prod_{i=1}^N\prod_{j=0}^{\textrm{length}} U_je^{-ia_{ij}D_j\Delta t}U_j^\dagger+\mathcal E. \end{align} $$ where \(a_{nj}\coloneqq a(n\Delta t)\), we set \(a_{n0}=1\) for notational ease, and the additive error \(\mathcal E\) is $$ \begin{align} \mathcal E&=\mathcal O\left( \Delta t^2\left[\sum_{i=1}^N\sum_{j=1}^{\textrm{length}}\dot a_{ij} \norm{H_j} +\sum_{i=1}^N\sum_{j,k=0}^{\textrm{length}}a_{ij}a_{ik} \norm{[H_j,H_k]}\right] \right)\\ &=\mathcal O\left( N\Delta t^2\textrm{length}\left[\omega E+\alpha^2+E^2\right] \right) \end{align} $$ where \(\dot a_{nj}\coloneqq\dot a_j(n\Delta t)\) and $$ \begin{align} \omega&\coloneqq\max_{\substack{i\in\left[1,N\right]\\ j\in\left[1,\textrm{length}\right]}}\left|\dot a_{ij}\right|,\\ \alpha&\coloneqq\max_{\substack{i\in\left[1,N\right]\\ j\in\left[0,\textrm{length}\right]}}\left|a_{ij}\right|,\\ E&\coloneqq\max_{j\in\left[0,\textrm{length}\right]}\norm{H_j}. \end{align} $$ Note the error is quadratic in \(\Delta t\) but linear in \(N\). We can also view this as being linear in \(\Delta t\) and linear in total evolution time \(N\Delta t\). Additionally, by Nyquist's theorem this asymptotic error scaling will not be achieved until the time step \(\Delta t\) is smaller than \(\frac{1}{2\Omega}\) where \(\Omega\) is the largest energy or frequency in the system.

propagate

Propagates the state vector using the first-order Suzuki-Trotter expansion.

propagate_all

Propagates the state vector using the first-order Suzuki-Trotter expansion and returns the resulting state vector at every time step.

propagate_collection

Propagates a collection of state vectors using the first-order Suzuki-Trotter expansion.

switching_function

Calculates the switching function for a Mayer problem with an expectation value as the cost function.

__init__(drift_hamiltonian: ndarray[complex128], control_hamiltonians: ndarray[complex128])

Initialises a new unitary evolver with the Hamiltonian

\[ H(t)=H_0+\sum_{j=1}^{\textrm{length}}a_j(t)H_j, \]
where \(H_0\) is the drift Hamiltonian and \(H_j\) are the control Hamiltonians modulated by control amplitudes \(a_j(t)\) which need not be specified during initialisation.

Parameters:
  • drift_hamiltonian (NDArray[Shape[runtime_dim, runtime_dim], complex128]) – The drift Hamiltonian.

  • control_hamiltonians (NDArray[Shape[runtime_dim * length, runtime_dim], complex128]) – The control Hamiltonians.

evolved_expectation_value(ctrl_amp: ndarray[complex128], state: ndarray[complex128], dt: float, observable: ndarray[complex128]) complex

Calculates the expectation value with respect to an observable of an evolved state vector evolved under a control Hamiltonian modulated by the control amplitudes. The integration is performed using propagate().

Parameters:
  • ctrl_amp (NDArray[Shape[time_steps, length], complex128]) – \(\left(a_{ij}\right)\) The control amplitudes at each time step expressed as an \(N\times\textrm{length}\) matrix where the element \(a_{ij}\) corresponds to the control amplitude of the \(j\)th control Hamiltonian at the \(i\)th time step.

  • state (NDArray[Shape[runtime_dim], complex128]) – \(\left[\psi(0)\right]\) The state vector to propagate.

  • dt (float) – (\(\Delta t\)) The time step to propagate by.

  • observable (NDArray[Shape[runtime_dim, runtime_dim], complex128]) – \((\hat O)\) The observable to calculate the expectation value of.

Returns:

The expectation value of the observable, \(\langle\hat O\rangle \equiv\psi^\dagger(N\Delta t)\hat O\psi(N\Delta t)\).

Return type:

complex

Note

This function is a wrapper around the C++ function Suzuki_Trotter_Evolver::UnitaryEvolver::evolved_expectation_value().

evolved_expectation_value_all(ctrl_amp: ndarray[complex128], state: ndarray[complex128], dt: float, observable: ndarray[complex128]) ndarray[complex128]

Calculates the expectation values with respect to an observable of a time series of state vectors evolved under a control Hamiltonian modulated by the control amplitudes. The integration is performed using propagate_all().

Parameters:
  • ctrl_amp (NDArray[Shape[time_steps, length], complex128]) – \(\left(a_{ij}\right)\) The control amplitudes at each time step expressed as an \(N\times\textrm{length}\) matrix where the element \(a_{ij}\) corresponds to the control amplitude of the \(j\)th control Hamiltonian at the \(i\)th time step.

  • state (NDArray[Shape[runtime_dim], complex128]) – \(\left[\psi(0)\right]\) The state vector to propagate.

  • dt (float) – (\(\Delta t\)) The time step to propagate by.

  • observable (NDArray[Shape[runtime_dim, runtime_dim], complex128]) – \((\hat O)\) The observable to calculate the expectation value of.

Returns:

The expectation value of the observable, \(\left(\psi^\dagger(n\Delta t)\hat O\psi(N\Delta t)\right)_{n=0}^N\).

Return type:

NDArray[Shape[time_steps + 1], complex128]

Note

This function is a wrapper around the C++ function Suzuki_Trotter_Evolver::UnitaryEvolver::evolved_expectation_value_all().

evolved_gate_infidelity(ctrl_amp: ndarray[complex128], dt: float, target: ndarray[complex128]) float

Calculates the gate infidelity with respect to a target gate of the gate produced by the control Hamiltonian modulated by the control amplitudes. The integration is performed using get_evolution().

Parameters:
  • ctrl_amp (NDArray[Shape[time_steps, length], complex128]) – \(\left(a_{ij}\right)\) The control amplitudes at each time step expressed as an \(N\times\textrm{length}\) matrix where the element \(a_{ij}\) corresponds to the control amplitude of the \(j\)th control Hamiltonian at the \(i\)th time step.

  • dt (float) – (\(\Delta t\)) The time step to propagate by.

  • target (NDArray[Shape[runtime_dim, runtime_dim], complex128]) – The target gate to calculate the infidelity with respect to.

Returns:

The gate infidelity with respect to the target gate:

\[ \mathcal I(U(N\Delta t), \texttt{target}) \coloneqq 1-\frac{ \left|\Tr\left[ \texttt{target}^\dagger\cdot U(N\Delta t)\right]\right|^2 +\texttt{dim}}{\texttt{dim}(\texttt{dim}+1)}. \]

Return type:

float

Note

This function is a wrapper around the C++ function Suzuki_Trotter_Evolver::UnitaryEvolver::evolved_gate_infidelity().

See also

  • unitary_gate_infidelity().

evolved_inner_product(ctrl_amp: ndarray[complex128], state: ndarray[complex128], dt: float, fixed_vector: ndarray[complex128]) complex

Calculates the real inner product of an evolved state vector with a fixed vector. The evolved state vector is evolved under a control Hamiltonian modulated by the control amplitudes. The integration is performed using propagate().

Parameters:
  • ctrl_amp (NDArray[Shape[time_steps, length], complex128]) – \(\left(a_{ij}\right)\) The control amplitudes at each time step expressed as an \(N\times\textrm{length}\) matrix where the element \(a_{ij}\) corresponds to the control amplitude of the \(j\)th control Hamiltonian at the \(i\)th time step.

  • state (NDArray[Shape[runtime_dim], complex128]) – \(\left[\psi(0)\right]\) The state vector to propagate.

  • dt (float) – (\(\Delta t\)) The time step to propagate by.

  • fixed_vector (NDArray[Shape[runtime_dim], complex128]) – \((\xi)\) The fixed vector to calculate the inner product with.

Returns:

The inner product of the evolved state vector with the fixed vector, \(\sum_{i=1}^\texttt{dim}\xi_i\psi_i(N\Delta t)\).

Return type:

complex

Note

This function is a wrapper around the C++ function Suzuki_Trotter_Evolver::UnitaryEvolver::evolved_inner_product().

evolved_inner_product_all(ctrl_amp: ndarray[complex128], state: ndarray[complex128], dt: float, fixed_vector: ndarray[complex128]) ndarray[complex128]

Calculates the real inner products of a time series of evolved state vectors with a fixed vector. The evolved state vector is evolved under a control Hamiltonian modulated by the control amplitudes. The integration is performed using propagate_all()`().

Parameters:
  • ctrl_amp (NDArray[Shape[time_steps, length], complex128]) – \(\left(a_{ij}\right)\) The control amplitudes at each time step expressed as an \(N\times\textrm{length}\) matrix where the element \(a_{ij}\) corresponds to the control amplitude of the \(j\)th control Hamiltonian at the \(i\)th time step.

  • state (NDArray[Shape[runtime_dim], complex128]) – \(\left[\psi(0)\right]\) The state vector to propagate.

  • dt (float) – (\(\Delta t\)) The time step to propagate by.

  • fixed_vector (NDArray[Shape[runtime_dim], complex128]) – \((\xi)\) The fixed vector to calculate the inner product with.

Returns:

The inner products of the evolved state vectors with the fixed vector, \(\left( \sum_{i=1}^\texttt{dim}\xi_i\psi_i(n\Delta t)\right)_{n=0}^N\).

Return type:

NDArray[Shape[time_steps + 1], complex128]

Note

This function is a wrapper around the C++ function Suzuki_Trotter_Evolver::UnitaryEvolver::evolved_inner_product_all().

gate_switching_function(ctrl_amp: ndarray[complex128], dt: float, target: ndarray[complex128]) tuple[float, ndarray[float64]]

Calculates the switching function for a Mayer problem with the gate infidelity as the cost function. More precisely if the cost function is

\[ J\left[\vec a(t)\right] \coloneqq\mathcal I(U\left[\vec a(t); T\right], \texttt{target}) \coloneqq 1-\frac{\left|\Tr\left[\texttt{target}^\dagger \cdot U\left[\vec a(t); T\right]\right]\right|^2 +\texttt{dim}}{\texttt{dim}(\texttt{dim}+1)}. \]
where \(T=N\Delta t\), then the switching function is
\[\begin{split} \begin{align} &\phi_j(t)\coloneqq\frac{\delta J}{\delta a_j(t)}\\ &=\frac{2}{\texttt{dim}(\texttt{dim}+1)}\operatorname{Im}\left( \Tr\left[U^\dagger(N\Delta t)\cdot\texttt{target}\right] \Tr\left[\texttt{target}^\dagger \cdot U(t\to T)H_j U[\vec a(t);t]\right]\right). \end{align} \end{split}\]
Using the first-order Suzuki-Trotter expansion we can express the switching function as $$ \begin{align}

&phi_j(nDelta t)=frac{1}{Delta t}pdv{J}{a_{nj}}\ &=!frac{2}{texttt{dim}(texttt{dim}+1)}operatorname{Im}

!left( Tr!left[U^dagger(NDelta t)cdottexttt{target}right] vphantom{[prod_{k=j}^{textrm{length}}}right.\ &left.cdotTr!left[texttt{target}^dagger!cdot! left[prod_{i>n}^Nprod_{k=1}^{textrm{length}} e^{-ia_{ik}H_kDelta t}right]!!! left[prod_{k=j}^{textrm{length}} e^{-ia_{nk}H_kDelta t}right]!H_j!! left[prod_{k=0}^{j-1} e^{-ia_{nk}H_kDelta t}right] ! U(left[n-1right]Delta t)right]right),

\end{align} $$ where for numerical efficiency we replace \(e^{-ia_{ik}H_k\Delta t}\) with \(U_ke^{-ia_{ik}D_k\Delta t}U_k^\dagger\) as in get_evolution().

Parameters:
  • ctrl_amp (NDArray[Shape[time_steps, length], complex128]) – \(\left(a_{ij}\right)\) The control amplitudes at each time step expressed as an \(N\times\textrm{length}\) matrix where the element \(a_{ij}\) corresponds to the control amplitude of the \(j\)th control Hamiltonian at the \(i\)th time step.

  • dt (float) – (\(\Delta t\)) The time step to propagate by.

  • target (NDArray[Shape[runtime_dim, runtime_dim], complex128]) – The target gate to calculate the infidelity with respect to.

Returns:

The gate infidelity, \(I(U\left[\vec a(t); T\right], \texttt{target})\) and the switching function, \(\phi_j(n\Delta t)\) for all \(j\in\left[1,\textrm{length}\right]\) and \(n\in\left[1,N\right]\).

Return type:

tuple[float, NDArray[Shape[time_steps, length], float64]]

get_evolution(ctrl_amp: ndarray[complex128], dt: float) ndarray[complex128]

Computes the unitary corresponding to the evolution under the differential equation

\[ \dot U=-iHU. \]
The computation is performed using the first-order Suzuki-Trotter expansion: $$ \begin{align}

U(NDelta t)&=prod_{i=1}^Nprod_{j=0}^{textrm{length}}

e^{-ia_{ij}H_jDelta t}+mathcal E\

&=prod_{i=1}^Nprod_{j=0}^{textrm{length}}

U_je^{-ia_{ij}D_jDelta t}U_j^dagger+mathcal E.

\end{align} $$ where \(a_{nj}\coloneqq a(n\Delta t)\), we set \(a_{n0}=1\) for notational ease, and the additive error \(\mathcal E\) is $$ \begin{align} \mathcal E&=\mathcal O\left(

Delta t^2left[sum_{i=1}^Nsum_{j=1}^{textrm{length}}dot a_{ij} norm{H_j} +sum_{i=1}^Nsum_{j,k=0}^{textrm{length}}a_{ij}a_{ik} norm{[H_j,H_k]}right] right)\

&=mathcal Oleft(

NDelta t^2textrm{length}left[omega E+alpha^2+E^2right] right)

\end{align} $$ where \(\dot a_{nj}\coloneqq\dot a_j(n\Delta t)\) and $$ \begin{align}

omega&coloneqqmax_{substack{iinleft[1,Nright]\

jinleft[1,textrm{length}right]}}left|dot a_{ij}right|,\

alpha&coloneqqmax_{substack{iinleft[1,Nright]\

jinleft[0,textrm{length}right]}}left|a_{ij}right|,\

E&coloneqqmax_{jinleft[0,textrm{length}right]}norm{H_j}.

\end{align} $$ Note the error is quadratic in \(\Delta t\) but linear in \(N\). We can also view this as being linear in \(\Delta t\) and linear in total evolution time \(N\Delta t\). Additionally, by Nyquist’s theorem this asymptotic error scaling will not be achieved until the time step \(\Delta t\) is smaller than \(\frac{1}{2\Omega}\) where \(\Omega\) is the largest energy or frequency in the system.

Parameters:
  • ctrl_amp (NDArray[Shape[time_steps, length], complex128]) – \(\left(a_{ij}\right)\) The control amplitudes at each time step expressed as an \(N\times\textrm{length}\) matrix where the element \(a_{ij}\) corresponds to the control amplitude of the \(j\)th control Hamiltonian at the \(i\)th time step.

  • dt (float) – (\(\Delta t\)) The time step to propagate by.

Returns:

The unitary corresponding to the evolution, \(U(N\Delta t)\).

Return type:

NDArray[Shape[runtime_dim, runtime_dim], complex128]

Note

This function is a wrapper around the C++ function Suzuki_Trotter_Evolver::UnitaryEvolver::get_evolution().

propagate(ctrl_amp: ndarray[complex128], state: ndarray[complex128], dt: float) ndarray[complex128]

Propagates the state vector using the first-order Suzuki-Trotter expansion. More precisely, a state vector, \(\psi(0)\), is evolved under the differential equation

\[ \dot\psi=-iH\psi \]
using the first-order Suzuki-Trotter expansion:
\[\begin{split} \begin{align} \psi(N\Delta t)&=\prod_{i=1}^N\prod_{j=0}^{\textrm{length}} e^{-ia_{ij}H_j\Delta t}\psi(0)+\mathcal E\\ &=\prod_{i=1}^N\prod_{j=0}^{\textrm{length}} U_je^{-ia_{ij}D_j\Delta t}U_j^\dagger\psi(0)+\mathcal E. \end{align} \end{split}\]
where \(a_{nj}\coloneqq a(n\Delta t)\), we set \(a_{n0}=1\) for notational ease, and the additive error \(\mathcal E\) is
\[\begin{split} \begin{align} \mathcal E&=\mathcal O\left( \Delta t^2\left[\sum_{i=1}^N\sum_{j=1}^{\textrm{length}}\dot a_{ij} \norm{H_j} +\sum_{i=1}^N\sum_{j,k=0}^{\textrm{length}}a_{ij}a_{ik} \norm{[H_j,H_k]}\right] \right)\\ &=\mathcal O\left( N\Delta t^2\textrm{length}\left[\omega E+\alpha^2+E^2\right] \right) \end{align} \end{split}\]
where \(\dot a_{nj}\coloneqq\dot a_j(n\Delta t)\) and
\[\begin{split} \begin{align} \omega&\coloneqq\max_{\substack{i\in\left[1,N\right]\\ j\in\left[1,\textrm{length}\right]}}\left|\dot a_{ij}\right|,\\ \alpha&\coloneqq\max_{\substack{i\in\left[1,N\right]\\ j\in\left[0,\textrm{length}\right]}}\left|a_{ij}\right|,\\ E&\coloneqq\max_{j\in\left[0,\textrm{length}\right]}\norm{H_j}. \end{align} \end{split}\]
Note the error is quadratic in \(\Delta t\) but linear in \(N\). We can also view this as being linear in \(\Delta t\) and linear in total evolution time \(N\Delta t\). Additionally, by Nyquist’s theorem this asymptotic error scaling will not be achieved until the time step \(\Delta t\) is smaller than \(\frac{1}{2\Omega}\) where \(\Omega\) is the largest energy or frequency in the system.

Parameters:
  • ctrl_amp (NDArray[Shape[time_steps, length], complex128]) – \(\left(a_{ij}\right)\) The control amplitudes at each time step expressed as an \(N\times\textrm{length}\) matrix where the element \(a_{ij}\) corresponds to the control amplitude of the \(j\)th control Hamiltonian at the \(i\)th time step.

  • state (NDArray[Shape[runtime_dim], complex128]) – \(\left[\psi(0)\right]\) The state vector to propagate.

  • dt (float) – (\(\Delta t\)) The time step to propagate by.

Returns:

The propagated state vector, \(\psi(N\Delta t)\).

Return type:

NDArray[Shape[runtime_dim], complex128]

Note

This function is a wrapper around the C++ function Suzuki_Trotter_Evolver::UnitaryEvolver::propagate().

propagate_all(ctrl_amp: ndarray[complex128], state: ndarray[complex128], dt: float) ndarray[complex128]

Propagates the state vector using the first-order Suzuki-Trotter expansion and returns the resulting state vector at every time step. More precisely, a state vector, \(\psi(0)\), is evolved under the differential equation

\[ \dot\psi=-iH\psi \]
using the first-order Suzuki-Trotter expansion:
\[\begin{split} \begin{align} \psi(n\Delta t)&=\prod_{i=1}^n\prod_{j=0}^{\textrm{length}} e^{-ia_{ij}H_j\Delta t}\psi(0)+\mathcal E \quad\forall n\in\left[0, N\right]\\ &=\prod_{i=1}^n\prod_{j=0}^{\textrm{length}} U_je^{-ia_{ij}D_j\Delta t}U_j^\dagger\psi(0)+\mathcal E \quad\forall n\in\left[0, N\right]. \end{align} \end{split}\]
where \(a_{nj}\coloneqq a(n\Delta t)\), we set \(a_{n0}=1\) for notational ease, and the additive error \(\mathcal E\) is
\[\begin{split} \begin{align} \mathcal E&=\mathcal O\left( \Delta t^2\left[\sum_{i=1}^N\sum_{j=1}^{\textrm{length}}\dot a_{ij} \norm{H_j} +\sum_{i=1}^N\sum_{j,k=0}^{\textrm{length}}a_{ij}a_{ik} \norm{[H_j,H_k]}\right] \right)\\ &=\mathcal O\left( N\Delta t^2\textrm{length}\left[\omega E+\alpha^2+E^2\right] \right) \end{align} \end{split}\]
where \(\dot a_{nj}\coloneqq\dot a_j(n\Delta t)\) and
\[\begin{split} \begin{align} \omega&\coloneqq\max_{\substack{i\in\left[1,N\right]\\ j\in\left[1,\textrm{length}\right]}}\left|\dot a_{ij}\right|,\\ \alpha&\coloneqq\max_{\substack{i\in\left[1,N\right]\\ j\in\left[0,\textrm{length}\right]}}\left|a_{ij}\right|,\\ E&\coloneqq\max_{j\in\left[0,\textrm{length}\right]}\norm{H_j}. \end{align} \end{split}\]
Note the error is quadratic in \(\Delta t\) but linear in \(N\). We can also view this as being linear in \(\Delta t\) and linear in total evolution time \(N\Delta t\). Additionally, by Nyquist’s theorem this asymptotic error scaling will not be achieved until the time step \(\Delta t\) is smaller than \(\frac{1}{2\Omega}\) where \(\Omega\) is the largest energy or frequency in the system.

Parameters:
  • ctrl_amp (NDArray[Shape[time_steps, length], complex128]) – \(\left(a_{ij}\right)\) The control amplitudes at each time step expressed as an \(N\times\textrm{length}\) matrix where the element \(a_{ij}\) corresponds to the control amplitude of the \(j\)th control Hamiltonian at the \(i\)th time step.

  • state (NDArray[Shape[runtime_dim], complex128]) – \(\left[\psi(0)\right]\) The state vector to propagate.

  • dt (float) – (\(\Delta t\)) The time step to propagate by.

Returns:

The propagated state vector at each time step, \(\left(\psi(n\Delta t)\right)_{n=0}^N\).

Return type:

NDArray[Shape[runtime_dim, time_steps + 1], complex128]

Note

This function is a wrapper around the C++ function Suzuki_Trotter_Evolver::UnitaryEvolver::propagate_all().

propagate_collection(ctrl_amp: ndarray[complex128], states: ndarray[complex128], dt: float) ndarray[complex128]

Propagates a collection of state vectors using the first-order Suzuki-Trotter expansion. More precisely, a collection of state vectors, \(\left(\psi_k(0)\right)_{k}\), are evolved under the differential equation

\[ \dot\psi_k=-iH\psi_k \]
using the first-order Suzuki-Trotter expansion:
\[\begin{split} \begin{align} \psi_k(N\Delta t)&=\prod_{i=1}^N\prod_{j=0}^{\textrm{length}} e^{-ia_{ij}H_j\Delta t}\psi_k(0)+\mathcal E\\ &=\prod_{i=1}^N\prod_{j=0}^{\textrm{length}} U_je^{-ia_{ij}D_j\Delta t}U_j^\dagger\psi_k(0)+\mathcal E. \end{align} \end{split}\]
where \(a_{nj}\coloneqq a(n\Delta t)\), we set \(a_{n0}=1\) for notational ease, and the addative error \(\mathcal E\) is
\[\begin{split} \begin{align} \mathcal E&=\mathcal O\left( \Delta t^2\left[\sum_{i=1}^N\sum_{j=1}^{\textrm{length}}\dot a_{ij} \norm{H_j} +\sum_{i=1}^N\sum_{j,k=0}^{\textrm{length}}a_{ij}a_{ik} \norm{[H_j,H_k]}\right] \right)\\ &=\mathcal O\left( N\Delta t^2\textrm{length}\left[\omega E+\alpha^2+E^2\right] \right) \end{align} \end{split}\]
where \(\dot a_{nj}\coloneqq\dot a_j(n\Delta t)\) and
\[\begin{split} \begin{align} \omega&\coloneqq\max_{\substack{i\in\left[1,N\right]\\ j\in\left[1,\textrm{length}\right]}}\left|\dot a_{ij}\right|,\\ \alpha&\coloneqq\max_{\substack{i\in\left[1,N\right]\\ j\in\left[0,\textrm{length}\right]}}\left|a_{ij}\right|,\\ E&\coloneqq\max_{j\in\left[0,\textrm{length}\right]}\norm{H_j}. \end{align} \end{split}\]
Note the error is quadratic in \(\Delta t\) but linear in \(N\). We can also view this as being linear in \(\Delta t\) and linear in total evolution time \(N\Delta t\). Additionally, by Nyquist’s theorem this asymptotic error scaling will not be achieved until the time step \(\Delta t\) is smaller than \(\frac{1}{2\Omega}\) where \(\Omega\) is the largest energy or frequency in the system.

Parameters:
  • ctrl_amp (NDArray[Shape[time_steps, length], complex128]) – \(\left(a_{ij}\right)\) The control amplitudes at each time step expressed as an \(N\times\textrm{length}\) matrix where the element \(a_{ij}\) corresponds to the control amplitude of the \(j\)th control Hamiltonian at the \(i\)th time step.

  • states (NDArray[Shape[runtime_dim, number_of_states], complex128]) – \(\left[\left(\psi(0)\right)_{k}\right]\) A collection of state vectors to propagate expressed as a matrix with each column corresponding to a state vector.

  • dt (float) – (\(\Delta t\)) The time step to propagate by.

Returns:

The propagated state vectors, \(\left(\psi_k(N\Delta t)\right)_k\).

Return type:

NDArray[Shape[runtime_dim, number_of_states], complex128]

Note

This function is a wrapper around the C++ function Suzuki_Trotter_Evolver::UnitaryEvolver::propagate_collection().

switching_function(ctrl_amp: ndarray[complex128], state: ndarray[complex128], dt: float, cost: ndarray[complex128]) tuple[complex, ndarray[float64]]

Calculates the switching function for a Mayer problem with an expectation value as the cost function. More precisely if the cost function is

\[ J\left[\vec a(t)\right]\coloneqq\langle\hat O\rangle \equiv\psi^\dagger[\vec a(t);T] \hat O\psi[\vec a(t);T], \]
where \(T=N\Delta t\), then the switching function is
\[ \phi_j(t)\coloneqq\frac{\delta J}{\delta a_j(t)} =2\operatorname{Im}\left(\psi^\dagger[\vec a(t);T] \hat OU(t\to T)H_j\psi[\vec a(t);t]\right). \]
using the first-order Suzuki-Trotter expansion we can express the switching function as
\[\begin{split} \begin{align} &\phi_j(n\Delta t)=\frac{1}{\Delta t}\pdv{J}{a_{nj}}\\ &=\!2\operatorname{Im}\!\left(\psi^\dagger(T) \hat O\!\!\left[\prod_{i>n}^N\prod_{k=1}^{\textrm{length}} e^{-ia_{ik}H_k\Delta t}\right]\!\!\! \left[\prod_{k=j}^{\textrm{length}} e^{-ia_{nk}H_k\Delta t}\right]\!H_j\!\! \left[\prod_{k=0}^{j-1} e^{-ia_{nk}H_k\Delta t}\right] \!\psi(\left[n-1\right]\Delta t)\right), \end{align} \end{split}\]
where for numerical efficiency we replace \(e^{-ia_{ik}H_k\Delta t}\) with \(U_ke^{-ia_{ik}D_k\Delta t}U_k^\dagger\) as in propagate().

Parameters:
  • ctrl_amp (NDArray[Shape[time_steps, length], complex128]) – \(\left(a_{ij}\right)\) The control amplitudes at each time step expressed as an \(N\times\textrm{length}\) matrix where the element \(a_{ij}\) corresponds to the control amplitude of the \(j\)th control Hamiltonian at the \(i\)th time step.

  • state (NDArray[Shape[runtime_dim], complex128]) – \(\left[\psi(0)\right]\) The initial state vector.

  • dt (float) – (\(\Delta t\)) The time step.

  • cost (NDArray[Shape[runtime_dim, runtime_dim], complex128]) – \((\hat O)\) The observable to calculate the expectation value of.

Returns:

The expectation value, \(\psi^\dagger(T)\hat O\psi(T)\), and the switching function, \(\phi_j(n\Delta t)\) for all \(j\in\left[1,\textrm{length}\right]\) and \(n\in\left[1,N\right]\).

Return type:

tuple[complex, NDArray[Shape[time_steps, length], float64]]

Note

This function is a wrapper around the C++ function Suzuki_Trotter_Evolver::UnitaryEvolver::switching_function().

d0: ndarray

The eigenvalues, \(\operatorname{diag}(D_0)\), of the drift Hamiltonian: \(H_0=U_0D_0U_0^\dagger\).

Note

This is a wrapper around the C++ member Suzuki_Trotter_Evolver::UnitaryEvolver::d0.

See also

dim: int = None

The dimension of the vector space the Hamiltonians act upon used to compile the C++ backend. Equal to the value in the class name. A value of -1 represents Dynamic in the class name and implies the value is not precompiled in the C++.

dim_x_n_ctrl: int = None

The dimension of rows in each control Hamiltonian multiplied by the number of control Hamiltonians upon used to compile the C++ backend. This is the number of rows for the control_hamiltonians argument for __init__(). A value of -1 implies the value is not precompiled in the C++.

Note

This is a wrapper around the C++ member Suzuki_Trotter_Evolver::UnitaryEvolver::dim_x_n_ctrl.

ds: list[ndarray]

The eigenvalues, \(\left(\operatorname{diag}(D_i)\right)_{i=1}^{\textrm{length}}\), of the control Hamiltonians: \(H_i=U_iD_iU_i^\dagger\) for all \(i\in\left[\textrm{length}\right]\).

Note

This is a wrapper around the C++ member Suzuki_Trotter_Evolver::UnitaryEvolver::ds.

hs: list[ndarray]

The control Hamiltonians: \(H_i\) for all \(i\in\left[\textrm{length}\right]\).

Note

This is a wrapper around the C++ member Suzuki_Trotter_Evolver::UnitaryEvolver::hs.

length: int

The number of control Hamiltonians. This is the value at runtime while n_ctrl was the value at compile time. These two values will be equal unless n_ctrl==-1. If n_ctrl==-1 then length is the actual number of control Hamiltonians.

Note

This is a wrapper around the C++ member Suzuki_Trotter_Evolver::UnitaryEvolver::length.

n_ctrl: int = None

The number of control Hamiltonians used to compile the C++ backend. Equal to the value in the class name. A value of -1 represents Dynamic in the class name and implies the value is not precompiled in the C++. This was the value at compile time while length is the value at runtime time.

u0: ndarray

The unitary transformation, \(U_0\), that diagonalises the drift Hamiltonian: \(H_0=U_0D_0U_0^\dagger\).

Note

This is a wrapper around the C++ member Suzuki_Trotter_Evolver::UnitaryEvolver::u0.

u0_inverse: ndarray

The inverse of the unitary transformation, \(U_0^\dagger\), that diagonalises the drift Hamiltonian: \(H_0=U_0D_0U_0^\dagger\).

Note

This is a wrapper around the C++ member Suzuki_Trotter_Evolver::UnitaryEvolver::u0_inverse.

u0_inverse_u_last: list[ndarray]

The unitary transformation, \(U_0^\dagger U_{\textrm{length}}\), from the eigen basis of \(H_{\textrm{length}}\) to the eigen basis of \(H_0\).

Note

This is a wrapper around the C++ member Suzuki_Trotter_Evolver::UnitaryEvolver::u0_inverse_u_last.

us: list[ndarray]

The unitary transformations, \((U_i^\dagger U_{i-1})_{i=1}^{\textrm{length}}\), from the eigen basis of \(H_{i-1}\) to the eigen basis of \(H_i\).

Note

This is a wrapper around the C++ member Suzuki_Trotter_Evolver::UnitaryEvolver::us.

us_individual: list[ndarray]

The unitary transformations, \(\left(U_i\right)_{i=1}^{\textrm{length}}\), that diagonalise the control Hamiltonians: \(H_i=U_iD_iU_i^\dagger\) for all \(i\in\left[\textrm{length}\right]\).

Note

This is a wrapper around the C++ member Suzuki_Trotter_Evolver::UnitaryEvolver::us_individual.

us_inverse_individual: list[ndarray]

The inverse of the unitary transformations, \((U_i^\dagger)_{i=1}^{\textrm{length}}\), that diagonalise the control Hamiltonians: \(H_i=U_iD_iU_i^\dagger\) for all \(i\in\left[\textrm{length}\right]\).

Note

This is a wrapper around the C++ member Suzuki_Trotter_Evolver::UnitaryEvolver::us_inverse_individual.

See also