krotov.functionals module

Functionals and chi_constructor routines.

Any chi_constructor routine passed to optimize_pulses() must take the following keyword-arguments:

  • fw_states_T (list of Qobj): The list of states resulting from the forward-propagation of each Objective.initial_state under the guess pulses of the current iteration (the optimized pulses of the previous iteration)
  • objectives (list of Objective): A list of the optimization objectives.
  • tau_vals (list of complex or None): The overlaps of the fw_states_T and the corresponding Objective.target, assuming Objective.target contains a quantum state. If the objective defines no target state, a list of Nones

Krotov’s method does not have an explicit dependence on the optimization functional. It only enters through the chi_constructor which calculates the boundary condition for the backward propagation, that is, the states

\[\Ket{\chi_k^{(i)}(T)} = - \left.\frac{\partial J_T} {\partial \Bra{\phi_k}} \right\vert_{\phi^{(i)}(T)}\]

for functionals defined in Hilbert space, or

\[\Op{\chi}_k^{(i)}(T) = - \left.\frac{\partial J_T} {\partial \langle\!\langle\Op{\rho}_k\vert} \right\vert_{\rho^{(i)}(T)}\]

in Liouville space, using the abstract Hilbert-Schmidt notation \(\langle\!\langle a \vert b \rangle\!\rangle \equiv \tr[a^\dagger b]\). Passing a specific chi_constructor results in the minimization of the final time functional from which that chi_constructor was derived.

The functions in this module that evaluate functionals are intended for use inside a function that is passed as an info_hook to optimize_pulses(). Thus, they calculate \(J_T\) from the same keyword arguments as the info_hook. The values for \(J_T\) may be used in a convergence analysis, see krotov.convergence.

Summary

Data:

F_avg Average gate fidelity
F_re Real-part fidelity
F_sm Square-modulus fidelity
F_ss State-to-state phase-insensitive fidelity
J_T_hs Hilbert-Schmidt distance measure functional \(J_{T,\text{hs}}\)
J_T_re Real-part functional \(J_{T,\text{re}}\)
J_T_sm Square-modulus functional \(J_{T,\text{sm}}\)
J_T_ss State-to-state phase-insensitive functional \(J_{T,\text{ss}}\)
chis_hs States \(\Op{\chi}_k\) for functional \(J_{T,\text{hs}}\)
chis_re States \(\ket{\chi_k}\) for functional \(J_{T,\text{re}}\)
chis_sm States \(\ket{\chi_k}\) for functional \(J_{T,\text{sm}}\)
chis_ss States \(\ket{\chi_k}\) for functional \(J_{T,\text{ss}}\)
f_tau Average of the complex overlaps with the target states
gate Gate that maps basis_states to fw_states_T
mapped_basis Result of applying gate to basis_states

__all__: F_avg, F_re, F_sm, F_ss, J_T_hs, J_T_re, J_T_sm, J_T_ss, chis_hs, chis_re, chis_sm, chis_ss, f_tau, gate, mapped_basis

Reference

krotov.functionals.f_tau(fw_states_T, objectives, tau_vals=None, **kwargs)[source]

Average of the complex overlaps with the target states

That is,

\[f_{\tau} = \frac{1}{N} \sum_{k=1}^{N} w_k \tau_k\]

where \(\tau_k\) are the elements of tau_vals, assumed to be

\[\tau_k = \Braket{\Psi_k(T)}{\Psi_k^{\tgt}},\]

in Hilbert space, or

\[\tau_k = \tr\left[\Op{\rho}_k(T)\Op{\rho}_k^{\tgt}\right]\]

in Liouville space, where \(\ket{\Psi_k}\) or \(\Op{\rho}_k\) are the elements of fw_states_T, and \(\ket{\Psi_k^{\tgt}}\) or \(\Op{\rho}^{\tgt}\) are the target states from the target attribute of the objectives. If tau_vals are None, they will be calculated internally.

\(N\) is the number of objectives, and \(w_k\) is an optional weight for each objective. For any objective that has a (custom) weight attribute, the \(w_k\) is taken from that attribute; otherwise, \(w_k = 1\). The weights, if present, are not automatically normalized, they are assumed to have values such that the resulting \(f_{\tau}\) lies in the unit circle of the complex plane. Usually, this means that the weights should sum to \(N\). The exception would be for mixed target states, where the weights should compensate for the non-unit purity. The problem is circumvented by using J_T_hs() for mixed target states.

The kwargs are ignored, allowing the function to be used in an info_hook.

krotov.functionals.F_ss(fw_states_T, objectives, tau_vals=None, **kwargs)[source]

State-to-state phase-insensitive fidelity

\[F_{\text{ss}} = \frac{1}{N} \sum_{k=1}^{N} w_k \Abs{\tau_k}^2 \quad\in [0, 1]\]

with \(N\), \(w_k\) and \(\tau_k\) as in f_tau().

The kwargs are ignored, allowing the function to be used in an info_hook.

krotov.functionals.J_T_ss(fw_states_T, objectives, tau_vals=None, **kwargs)[source]

State-to-state phase-insensitive functional \(J_{T,\text{ss}}\)

\[J_{T,\text{ss}} = 1 - F_{\text{ss}} \quad\in [0, 1].\]

All arguments are passed to F_ss().

krotov.functionals.chis_ss(fw_states_T, objectives, tau_vals)[source]

States \(\ket{\chi_k}\) for functional \(J_{T,\text{ss}}\)

\[\Ket{\chi_k} = -\frac{\partial J_{T,\text{ss}}}{\partial \bra{\Psi_k(T)}} = \frac{1}{N} w_k \tau_k \Ket{\Psi^{\tgt}_k}\]

with \(\tau_k\) and \(w_k\) as defined in f_tau().

krotov.functionals.F_sm(fw_states_T, objectives, tau_vals=None, **kwargs)[source]

Square-modulus fidelity

\[F_{\text{sm}} = \Abs{f_{\tau}}^2 \quad\in [0, 1].\]

All arguments are passed to f_tau() to evaluate \(f_{\tau}\).

krotov.functionals.J_T_sm(fw_states_T, objectives, tau_vals=None, **kwargs)[source]

Square-modulus functional \(J_{T,\text{sm}}\)

\[J_{T,\text{sm}} = 1 - F_{\text{sm}} \quad\in [0, 1]\]

All arguments are passed to f_tau() while evaluating \(F_{\text{sm}}\) in F_sm().

krotov.functionals.chis_sm(fw_states_T, objectives, tau_vals)[source]

States \(\ket{\chi_k}\) for functional \(J_{T,\text{sm}}\)

\[\Ket{\chi_k} = -\frac{\partial J_{T,\text{sm}}}{\partial \bra{\Psi_k(T)}} = \frac{1}{N^2} w_k \sum_{j}^{N} w_j\tau_j\Ket{\Psi^{\tgt}_k}\]

with optional weights \(w_k\), cf. f_tau() (default: \(w_k=1\)). If given, the weights should generally sum to \(N\).

krotov.functionals.F_re(fw_states_T, objectives, tau_vals=None, **kwargs)[source]

Real-part fidelity

\[\begin{split}F_{\text{re}} = \Re[f_{\tau}] \quad\in \begin{cases} [-1, 1] & \text{in Hilbert space} \\ [0, 1] & \text{in Liouville space.} \end{cases}\end{split}\]

All arguments are passed to f_tau() to evaluate \(f_{\tau}\).

krotov.functionals.J_T_re(fw_states_T, objectives, tau_vals=None, **kwargs)[source]

Real-part functional \(J_{T,\text{re}}\)

\[\begin{split}J_{T,\text{re}} = 1 - F_{\text{re}} \quad\in \begin{cases} [0, 2] & \text{in Hilbert space} \\ [0, 1] & \text{in Liouville space.} \end{cases}\end{split}\]

All arguments are passed to f_tau() while evaluating \(F_{\text{re}}\) in F_re().

Note

If the fw_states_T or the target states are mixed states, it is preferable to use J_T_hs(), as \(J_{T,\text{re}}\) may take negative values for mixed states.

krotov.functionals.chis_re(fw_states_T, objectives, tau_vals)[source]

States \(\ket{\chi_k}\) for functional \(J_{T,\text{re}}\)

\[\Ket{\chi_k} = -\frac{\partial J_{T,\text{re}}}{\partial \bra{\Psi_k(T)}} = \frac{1}{2N} w_k \Ket{\Psi^{\tgt}_k}\]

with optional weights \(w_k\), cf. f_tau() (default: \(w_k=1\)). If given, the weights should generally sum to \(N\).

Note: tau_vals are ignored, but are present to satisfy the requirments of the chi_constructor interface.

krotov.functionals.J_T_hs(fw_states_T, objectives, tau_vals=None, **kwargs)[source]

Hilbert-Schmidt distance measure functional \(J_{T,\text{hs}}\)

\[\begin{split}J_{T,\text{hs}} = \frac{1}{2N} \sum_{k=1}^{N} w_k \Norm{\Op{\rho}_k(T) - \Op{\rho}_k^{\tgt}}_{\text{hs}}^2 \quad \in \begin{cases} [0, 2] & \text{in Hilbert space} \\ [0, 1] & \text{in Liouville space} \end{cases}\end{split}\]

in Liouville space (using the Hilbert-Schmidt norm), or equivalently with \(\ket{\Psi_k(T)}\) and \(\ket{\Psi_k^{tgt}}\) in Hilbert space. The functional is evaluated as

\[J_{T,\text{hs}} = \frac{1}{2N} \sum_{k=1}^{N} w_k \left( \Norm{\Op{\rho}_k(T)}_{\text{hs}}^2 + \Norm{\Op{\rho}^{\tgt}}_{\text{hs}}^2 - 2 \Re[\tau_k] \right)\]

where the \(\Op{\rho}_k\) are the elements of fw_states_T, the \(\Op{\rho}_k^{\tgt}\) are the target states from the target attribute of the objectives, and the \(\tau_k\) are the elements of tau_vals (which will be calculated internally if passed as None).

The \(w_k\) are optional weights, cf. f_tau(). If given, the weights should generally sum to \(N\).

The kwargs are ignored, allowing the function to be used in an info_hook.

Note

For pure states (or Hilbert space states), \(J_{T,\text{hs}}\) is equivalent to \(J_{T,\text{re}}\), cf. J_T_re(). However, the backward-propagated states \(\chi_k\) obtained from the two functionals (chis_re() and chis_hs()) are not equivalent.

krotov.functionals.chis_hs(fw_states_T, objectives, tau_vals)[source]

States \(\Op{\chi}_k\) for functional \(J_{T,\text{hs}}\)

\[\Op{\chi}_k = -\frac{\partial J_{T,\text{sm}}} {\partial \langle\!\langle \Op{\rho}_k(T)\vert} = \frac{1}{2N} w_k \left(\Op{\rho}^{\tgt}_k - \Op{\rho}_k(T)\right)\]

with optional weights \(w_k\), cf. f_tau() (default: \(w_k=1\)).

This is derived from \(J_{T,\text{hs}}\) rewritten in the abstract Hilbert-Schmidt notation \(\langle\!\langle a \vert b \rangle\!\rangle \equiv \tr[a^\dagger b]\):

\[J_{T,\text{hs}} = \frac{-1}{2N} \sum_{k=1}^{N} w_k \big( \underbrace{ \langle\!\langle \Op{\rho}_k(T) \vert \Op{\rho}_k^{\tgt} \rangle\!\rangle + \langle\!\langle \Op{\rho}_k^{\tgt}\vert \Op{\rho}_k(T) \rangle\!\rangle }_{=2\Re[\tau_k]} - \underbrace{ \langle\!\langle \Op{\rho}_k(T) \vert \Op{\rho}_k(T) \rangle\!\rangle }_{=\Norm{\Op{\rho}_k(T)}_{\text{hs}}^2} - \underbrace{ \langle\!\langle \Op{\rho}_k^{\tgt} \vert \Op{\rho}_k^{\tgt} \rangle\!\rangle }_{=\Norm{\Op{\rho}^{\tgt}}_{\text{hs}}^2} \big).\]

Note: tau_vals are ignored, but are present to satisfy the requirments of the chi_constructor interface.

krotov.functionals.F_avg(fw_states_T, basis_states, gate, mapped_basis_states=None, prec=1e-05)[source]

Average gate fidelity

\[F_{\text{avg}} = \int \big\langle \Psi \big\vert \Op{O}^\dagger \DynMap[\ketbra{\Psi}{\Psi}] \Op{O} \big\vert \Psi \big\rangle \dd \Psi\]

where \(\Op{O}\) is the target gate, and \(\DynMap\) represents the dynamical map from time zero to \(T\).

In Liouville space, this is numerically evaluated as

\[F_{\text{avg}} = \frac{1}{N (N+1)} \sum_{i,j=1}^N \left( \big\langle \phi_i \big\vert \Op{O}^\dagger \Op{\rho}_{ij} \Op{O} \big\vert \phi_j \big\rangle + \big\langle \phi_i \big\vert \Op{O}^\dagger \Op{\rho}_{jj} \Op{O} \big\vert \phi_i \big\rangle \right),\]

where \(\ket{\phi_i}\) is the \(i\)’th element of basis_states, and \(\Op{\rho}_{ij}\) is the \((i-1) N + j\)’th element of fw_states_T, that is, \(\Op{\rho}_{ij} = \DynMap[\ketbra{\phi_i}{\phi_j}]\), with \(N\) the dimension of the Hilbert space.

In Hilbert space (unitary dynamics), this simplifies to

\[F_{\text{avg}} = \frac{1}{N (N+1)} \left( \Abs{\tr\left[\Op{O}^\dagger \Op{U}\right]}^2 + \tr\left[\Op{O}^\dagger \Op{U} \Op{U}^\dagger \Op{O}\right] \right),\]

where \(\Op{U}\) the gate that maps basis_states to the result of a forward propagation of those basis states, stored in fw_states_T.

Parameters:
  • fw_states_T (list[qutip.Qobj]) – The forward propagated states. For dissipative dynamics, this must be the forward propagation of the full basis of Liouville space, that is, all \(N^2\) dyadic combinations of the Hilbert space logical basis states. For unitary dynamics, the \(N\) forward-propagated basis_states.
  • basis_states (list[qutip.Qobj]) – The \(N\) Hilbert space logical basis states
  • gate (qutip.Qobj) – The \(N \times N\) quantum gate in the logical subspace, e.g. qutip.qip.gates.cnot().
  • mapped_basis_states (None or list[qutip.Qobj]) – If given, the result of applying gate to basis_states. If not given, this will be calculated internally via mapped_basis(). It is recommended to pass pre-calculated mapped_basis_states when evaluating \(F_{\text{avg}}\) repeatedly for the same target.
  • prec (float) – assert that the fidelity is correct at least up to the given precision. Mathematically, \(F_{\text{avg}}\) is a real value. However, errors in the fw_states_T can lead to a small non-zero imaginary part. We assert that this imaginary part is below prec.
krotov.functionals.gate(basis_states, fw_states_T)[source]

Gate that maps basis_states to fw_states_T

Example

>>> from qutip import ket
>>> basis = [ket(nums) for nums in [(0, 0), (0, 1), (1, 0), (1, 1)]]
>>> fw_states_T = mapped_basis(qutip.gates.cnot(), basis)
>>> U = gate(basis, fw_states_T)
>>> assert (U - qutip.gates.cnot()).norm() < 1e-15
krotov.functionals.mapped_basis(gate, basis_states)[source]

Result of applying gate to basis_states

Example

>>> from qutip import ket
>>> basis = [ket(nums) for nums in [(0, 0), (0, 1), (1, 0), (1, 1)]]
>>> states = mapped_basis(qutip.gates.cnot(), basis)
>>> assert (states[0] - ket((0,0))).norm() < 1e-15
>>> assert (states[1] - ket((0,1))).norm() < 1e-15
>>> assert (states[2] - ket((1,1))).norm() < 1e-15  # swap (1, 1) ...
>>> assert (states[3] - ket((1,0))).norm() < 1e-15  # ... and (1, 0)