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
ofQobj
): The list of states resulting from the forward-propagation of eachObjective.initial_state
under the guess pulses of the current iteration (the optimized pulses of the previous iteration)objectives (
list
ofObjective
): A list of the optimization objectives.tau_vals (
list
ofcomplex
orNone
): The overlaps of theObjective.target
and the corresponding fw_states_T, assumingObjective.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
for functionals defined in Hilbert space, or
in Liouville space, using the abstract Hilbert-Schmidt notation \(\langle\!\langle a \vert b \rangle\!\rangle \equiv \tr[a^\dagger b]\). The notation on the right hand side is a Wirtinger derivative, see Eq. (16). 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¶
Functions:
Average gate fidelity |
|
Real-part fidelity |
|
Square-modulus fidelity |
|
State-to-state phase-insensitive fidelity |
|
Hilbert-Schmidt distance measure functional \(J_{T,\text{hs}}\) |
|
Real-part functional \(J_{T,\text{re}}\) |
|
Square-modulus functional \(J_{T,\text{sm}}\) |
|
State-to-state phase-insensitive functional \(J_{T,\text{ss}}\) |
|
States \(\Op{\chi}_k\) for functional \(J_{T,\text{hs}}\) |
|
States \(\ket{\chi_k}\) for functional \(J_{T,\text{re}}\) |
|
States \(\ket{\chi_k}\) for functional \(J_{T,\text{sm}}\) |
|
States \(\ket{\chi_k}\) for functional \(J_{T,\text{ss}}\) |
|
Average complex overlaps of the target states with the fw_states_T. |
|
Gate that maps basis_states to fw_states_T |
|
Apply the gate O 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 complex overlaps of the target states with the fw_states_T.
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^{\tgt}}{\Psi_k(T)},\]in Hilbert space, or
\[\tau_k = \tr\left[\Op{\rho}_k^{\tgt\,\dagger}\Op{\rho}_k(T)\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 may be 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}}\) inF_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}}\) inF_re()
.Note
If the target states are mixed, \(J_{T,\text{re}}\) may take negative values (for fw_states_T that are “in the right direction”, but more pure than the target states). In this case, you may consider using
J_T_hs()
.
-
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()
andchis_hs()
) are not equivalent. This may result in a vastly different optimization landscape that requires a significantly different value of the \(\lambda_a\) value that regulates the overall magnitude of the pulse updates (given in pulse_options inoptimize_pulses()
).
-
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)]] >>> CNOT = qutip.Qobj( ... [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]], ... dims=[[2, 2], [2, 2]] ... ) >>> fw_states_T = mapped_basis(CNOT, basis) >>> U = gate(basis, fw_states_T) >>> assert (U - CNOT).norm() < 1e-15
-
krotov.functionals.
mapped_basis
(O, basis_states)[source]¶ Apply the gate O to basis_states.
Example
>>> from qutip import ket >>> basis = [ket(nums) for nums in [(0, 0), (0, 1), (1, 0), (1, 1)]] >>> CNOT = qutip.Qobj( ... [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]], ... dims=[[2, 2], [2, 2]] ... ) >>> states = mapped_basis(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)