Source code for krotov.mu

r"""Routines for `mu` in :func:`krotov.optimize.optimize_pulses`

The first-order Krotov update equation is usually written as

.. math::

       \Delta \epsilon(t) \propto \Im
       \Bigg\langle
         \chi_k^{(i)}(t)
       \Bigg\vert
         \Bigg(
            \left.\frac{\partial \Op{H}}{\partial \epsilon}\right\vert_{
                {\scriptsize \begin{matrix}
                    \phi^{(i+1)}(t)\\\epsilon^{(i+1)}(t)
                \end{matrix}}}
         \Bigg)
       \Bigg\vert
         \phi_k^{(i+1)}(t)
       \Bigg\rangle\,,

where $\ket{\chi_k}$ are states backward-propagated from a boundary condition
determined by the functional, $\ket{\phi_k}$ are forward-propagated from the
initial states, and $\frac{\partial \Op{H}}{\partial \epsilon}$ is the
derivative of the Hamiltonian with respect to the field. However, this is true
only for Hilbert-space states evolving under a Schrödinger equation.

More generally (e.g. when the states $\chi_k$ and $\phi_k$ are density matrices
and the equation of motion is the master equation in Lindblad form), the
correct formulation is

.. math::

    \frac{\partial \Op{H}}{\partial \epsilon}
    \rightarrow
    \mu = \frac{\partial H}{\partial \epsilon}\,,

where $H$ is now the abstract operator appearing in the equation of motion of
the abstract state

.. math::

    \dot\phi_k(t) = -i H \phi_k(t)


For density matrices, we have

.. math::

    \frac{\partial}{\partial t}\Op{\rho}_k(t) = \Liouville \Op{\rho}_k(t)

and thus $H = i \Liouville$.

To allow for arbitrary equations of motion, a routine `mu` may be passed to
:func:`.optimize_pulses` that returns the abstract operator $\mu$ as a
:class:`~qutip.Qobj`, or alternatively as a callable that takes $\phi_k$ as its
argument and evaluates $\mu \phi_k$. The default `mu` is
:func:`derivative_wrt_pulse`, which covers the most common equation of motions:

* standard Schrödinger equation
* master equation, where either the `H` attribute of the objective contains a
  Hamiltonian and there are Lindblad operators in `c_ops`, or the `H` attribute
  contains a super-operator $\Liouville$ directly (the case discussed above).

Alternative implementations of `mu` must have the same signature as
:func:`derivative_wrt_pulse`, but should only be required in rare
circumstances, such as when the derivative still depends on the control values
or on the states. (Or, if you can provide a more efficient problem-specific
implementation).
"""

__all__ = ['derivative_wrt_pulse']


[docs]def derivative_wrt_pulse( objectives, i_objective, pulses, pulses_mapping, i_pulse, time_index ): r"""Calculate ∂H/∂ϵ for the standard equations of motion. Args: objectives (list): List of :class:`.Objective` instances i_objective (int): The index of the objective in `objectives` whose equation of motion the derivative should be calculated. pulses (list): The list of pulses occuring in `objectives` pulses_mapping (list): The mapping of elements of `pulses` to the components of `objectives`, as returned by :func:`.extract_controls_mapping` i_pulse (int): The index of the pulse in `pulses` for which to calculate the derivative time_index (int): The index of the value in ``pulses[i_pulse]`` that should be plugged in to ∂H/∂ϵ. Not used, as this routine only considers equations of motion that are linear in the controls. Returns: callable: The quantum operator or super-operator that represents ∂H/∂ϵ. In general, the return type can be any callable `mu` so that ``mu(state)`` calculates the result of applying ∂H/∂ϵ to `state`. In most cases, a :class:`~qutip.Qobj` will be returned, which is just the most convenient example of an appropriate callable. This function covers the following cases: * the :attr:`~.Objective.H` attribute of the objective contains a Hamiltonian, there are no :attr:`~.Objective.c_ops` (Schrödinger equation: the abstract H in ∂H/∂ϵ is the Hamiltonian directly) * the :attr:`~.Objective.H` attribute of the objective contains a Hamiltonian $\Op{H}$, and there are Lindblad operators $\Op{L}_i$ in :attr:`~.Objective.c_ops` (master equation in Lindblad form). The abstract H is $i \Liouville$ for the Liouvillian defined as .. math:: \Liouville[\Op{\rho}] = -i[\Op{H},\Op{\rho}]+\sum_{i} \left( \Op{L}_i \Op{\rho} \Op{L}_i^\dagger - \frac{1}{2} \left\{ \Op{L}_i^\dagger \Op{L}_i, \Op{\rho}\right\} \right) * the :attr:`~.Objective.H` attribute of the objective contains a super-operator $\Liouville$, there are no :attr:`~.Objective.c_ops` (general master equation). The abstract H is again $i \Liouville$. """ objective = objectives[i_objective] ham_mapping = pulses_mapping[i_objective][0][i_pulse] eqm_factor = -1j # the factor in front of objective.H in the eqm if len(ham_mapping) == 0: return lambda state: 0 * state else: mu = objective.H[ham_mapping[0]][0] if mu.type == 'super': eqm_factor = 1 mu *= 1j for i in ham_mapping[1:]: mu += (1j * eqm_factor) * objective.H[i][0] for i_c_op in range(len(objective.c_ops)): if len(pulses_mapping[i_objective][i_c_op + 1][i_pulse]) != 0: raise NotImplementedError( "Time-dependent collapse operators not implemented" ) return mu