Example #1
0
def floquet_modes_table(f_modes_0, f_energies, tlist, H, T, args=None):
    """
    Pre-calculate the Floquet modes for a range of times spanning the floquet
    period. Can later be used as a table to look up the floquet modes for
    any time.

    Parameters
    ----------

    f_modes_0 : list of :class:`qutip.qobj` (kets)
        Floquet modes at :math:`t`

    f_energies : list
        Floquet energies.

    tlist : array
        The list of times at which to evaluate the floquet modes.

    H : :class:`qutip.qobj`
        system Hamiltonian, time-dependent with period `T`

    T : float
        The period of the time-dependence of the hamiltonian.

    args : dictionary
        dictionary with variables required to evaluate H

    Returns
    -------

    output : nested list

        A nested list of Floquet modes as kets for each time in `tlist`

    """

    # truncate tlist to the driving period
    tlist_period = tlist[np.where(tlist <= T)]

    f_modes_table_t = [[] for t in tlist_period]

    opt = Odeoptions()
    opt.rhs_reuse = True

    for n, f_mode in enumerate(f_modes_0):
        output = mesolve(H, f_mode, tlist_period, [], [], args, opt)
        for t_idx, f_state_t in enumerate(output.states):
            f_modes_table_t[t_idx].append(
                f_state_t * exp(1j * f_energies[n] * tlist_period[t_idx]))

    return f_modes_table_t
Example #2
0
def floquet_modes_table(f_modes_0, f_energies, tlist, H, T, args=None):
    """
    Pre-calculate the Floquet modes for a range of times spanning the floquet
    period. Can later be used as a table to look up the floquet modes for
    any time.

    Parameters
    ----------

    f_modes_0 : list of :class:`qutip.qobj` (kets)
        Floquet modes at :math:`t`

    f_energies : list
        Floquet energies.

    tlist : array
        The list of times at which to evaluate the floquet modes.

    H : :class:`qutip.qobj`
        system Hamiltonian, time-dependent with period `T`

    T : float
        The period of the time-dependence of the hamiltonian.

    args : dictionary
        dictionary with variables required to evaluate H

    Returns
    -------

    output : nested list

        A nested list of Floquet modes as kets for each time in `tlist`

    """

    # truncate tlist to the driving period
    tlist_period = tlist[np.where(tlist <= T)]

    f_modes_table_t = [[] for t in tlist_period]

    opt = Odeoptions()
    opt.rhs_reuse = True

    for n, f_mode in enumerate(f_modes_0):
        output = mesolve(H, f_mode, tlist_period, [], [], args, opt)
        for t_idx, f_state_t in enumerate(output.states):
            f_modes_table_t[t_idx].append(
                f_state_t * exp(1j * f_energies[n] * tlist_period[t_idx]))

    return f_modes_table_t
Example #3
0
    def __init__(self, H=None, state0=None, tlist=None, c_ops=[], sc_ops=[],
                 e_ops=[], args=None, ntraj=1, nsubsteps=1,
                 d1=None, d2=None, d2_len=1, rhs=None, homogeneous=True,
                 solver=None, method=None, distribution='normal',
                 store_measurement=False, noise=None,
                 options=Odeoptions(), progress_bar=TextProgressBar()):

        self.H = H
        self.d1 = d1
        self.d2 = d2
        self.d2_len = d2_len
        self.state0 = state0
        self.tlist = tlist
        self.c_ops = c_ops
        self.sc_ops = sc_ops
        self.e_ops = e_ops
        self.ntraj = ntraj
        self.nsubsteps = nsubsteps
        self.solver = solver
        self.method = method
        self.distribution = distribution
        self.homogeneous = homogeneous
        self.rhs = rhs
        self.options = options
        self.progress_bar = progress_bar
        self.store_measurement = store_measurement
        self.store_states = options.store_states
        self.noise = noise
        self.args = args
Example #4
0
def smepdpsolve(H, rho0, tlist, c_ops=[], e_ops=[], ntraj=1, nsubsteps=10,
                options=Odeoptions(), progress_bar=TextProgressBar()):
    """
    A stochastic PDP solver for density matrix evolution.
    """
    if debug:
        print(inspect.stack()[0][3])

    if isinstance(e_ops, dict):
        e_ops_dict = e_ops
        e_ops = [e for e in e_ops.values()]
    else:
        e_ops_dict = None

    ssdata = _StochasticSolverData()
    ssdata.H = H
    ssdata.rho0 = rho0
    ssdata.tlist = tlist
    ssdata.c_ops = c_ops
    ssdata.e_ops = e_ops
    ssdata.ntraj = ntraj
    ssdata.nsubsteps = nsubsteps

    res = smepdpsolve_generic(ssdata, options, progress_bar)

    if e_ops_dict:
        res.expect = {e: res.expect[n]
                      for n, e in enumerate(e_ops_dict.keys())}
    return res
Example #5
0
def sepdpsolve(H, psi0, tlist, c_ops=[], e_ops=[], ntraj=1, nsubsteps=10,
               options=Odeoptions(), progress_bar=TextProgressBar()):
    """
    A stochastic PDP solver for experimental/development and comparison to the 
    stochastic DE solvers. Use mcsolve for real quantum trajectory
    simulations.
    """
    if debug:
        print(inspect.stack()[0][3])

    if isinstance(e_ops, dict):
        e_ops_dict = e_ops
        e_ops = [e for e in e_ops.values()]
    else:
        e_ops_dict = None

    ssdata = _StochasticSolverData()
    ssdata.H = H
    ssdata.psi0 = psi0
    ssdata.tlist = tlist
    ssdata.c_ops = c_ops
    ssdata.e_ops = e_ops
    ssdata.ntraj = ntraj
    ssdata.nsubsteps = nsubsteps

    res = sepdpsolve_generic(ssdata, options, progress_bar)

    if e_ops_dict:
        res.expect = {e: res.expect[n]
                      for n, e in enumerate(e_ops_dict.keys())}
    return res
Example #6
0
def _correlation_me_4op_1t(H,
                           rho0,
                           tlist,
                           c_ops,
                           a_op,
                           b_op,
                           c_op,
                           d_op,
                           args=None,
                           options=Odeoptions()):
    """
    Calculate the four-operator two-time correlation function on the form
    <A(0)B(tau)C(tau)D(0)>.

    See, Gardiner, Quantum Noise, Section 5.2.1
    """

    if debug:
        print(inspect.stack()[0][3])

    if rho0 is None:
        rho0 = steadystate(H, c_ops)
    elif rho0 and isket(rho0):
        rho0 = ket2dm(rho0)

    return mesolve(H,
                   d_op * rho0 * a_op,
                   tlist,
                   c_ops, [b_op * c_op],
                   args=args,
                   options=options).expect[0]
Example #7
0
def _correlation_mc_2op_1t(H,
                           psi0,
                           taulist,
                           c_ops,
                           a_op,
                           b_op,
                           reverse=False,
                           args=None,
                           options=Odeoptions()):
    """
    Internal function for calculating correlation functions using the Monte
    Carlo solver. See :func:`correlation_ss` for usage.
    """

    if debug:
        print(inspect.stack()[0][3])

    if psi0 is None or not isket(psi0):
        raise Exception("_correlation_mc_2op_1t requires initial state as ket")

    b_op_psi0 = b_op * psi0

    norm = b_op_psi0.norm()

    return norm * mcsolve(H,
                          b_op_psi0 / norm,
                          taulist,
                          c_ops, [a_op],
                          args=args,
                          options=options).expect[0]
Example #8
0
def _correlation_es_2op_1t(H,
                           rho0,
                           tlist,
                           c_ops,
                           a_op,
                           b_op,
                           reverse=False,
                           args=None,
                           options=Odeoptions()):
    """
    Internal function for calculating correlation functions using the
    exponential series solver. See :func:`correlation_ss` usage.
    """

    if debug:
        print(inspect.stack()[0][3])

    # contruct the Liouvillian
    L = liouvillian(H, c_ops)

    # find the steady state
    if rho0 is None:
        rho0 = steadystate(L)
    elif rho0 and isket(rho0):
        rho0 = ket2dm(rho0)

    # evaluate the correlation function
    if reverse:
        # <A(t)B(t+tau)>
        solC_tau = ode2es(L, rho0 * a_op)
        return esval(expect(b_op, solC_tau), tlist)
    else:
        # default: <A(t+tau)B(t)>
        solC_tau = ode2es(L, b_op * rho0)
        return esval(expect(a_op, solC_tau), tlist)
Example #9
0
def correlation_mc(H, psi0, tlist, taulist, c_op_list, a_op, b_op):
    """
    Internal function for calculating correlation functions using the Monte
    Carlo solver. See :func:`correlation` usage.
    """

    C_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex)

    ntraj = 100

    opt = Odeoptions()
    opt.gui = False

    psi_t = mcsolve(H, psi0, tlist, c_op_list, [], ntraj=ntraj, options=opt).states

    for t_idx in range(len(tlist)):

        psi0_t = psi_t[0][t_idx]

        C_mat[t_idx, :] = mcsolve(H, b_op * psi0_t, tlist,
                                  c_op_list, [a_op], ntraj=ntraj, options=opt).expect[0]

    return C_mat
Example #10
0
def _correlation_me_2op_2t(H,
                           rho0,
                           tlist,
                           taulist,
                           c_ops,
                           a_op,
                           b_op,
                           reverse=False,
                           args=None,
                           options=Odeoptions()):
    """
    Internal function for calculating correlation functions using the master
    equation solver. See :func:`correlation` for usage.
    """

    if debug:
        print(inspect.stack()[0][3])

    if rho0 is None:
        rho0 = steadystate(H, c_ops)
    elif rho0 and isket(rho0):
        rho0 = ket2dm(rho0)

    C_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex)

    rho_t_list = mesolve(H, rho0, tlist, c_ops, [], args=args,
                         options=options).states

    if reverse:
        # <A(t)B(t+tau)>
        for t_idx, rho_t in enumerate(rho_t_list):
            C_mat[t_idx, :] = mesolve(H,
                                      rho_t * a_op,
                                      taulist,
                                      c_ops, [b_op],
                                      args=args,
                                      options=options).expect[0]
    else:
        # <A(t+tau)B(t)>
        for t_idx, rho_t in enumerate(rho_t_list):
            C_mat[t_idx, :] = mesolve(H,
                                      b_op * rho_t,
                                      taulist,
                                      c_ops, [a_op],
                                      args=args,
                                      options=options).expect[0]

    return C_mat
Example #11
0
def _correlation_es_2op_2t(H,
                           rho0,
                           tlist,
                           taulist,
                           c_ops,
                           a_op,
                           b_op,
                           reverse=False,
                           args=None,
                           options=Odeoptions()):
    """
    Internal function for calculating correlation functions using the
    exponential series solver. See :func:`correlation` usage.
    """

    if debug:
        print(inspect.stack()[0][3])

    # contruct the Liouvillian
    L = liouvillian(H, c_ops)

    if rho0 is None:
        rho0 = steadystate(L)
    elif rho0 and isket(rho0):
        rho0 = ket2dm(rho0)

    C_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex)

    solES_t = ode2es(L, rho0)

    # evaluate the correlation function
    if reverse:
        # <A(t)B(t+tau)>
        for t_idx in range(len(tlist)):
            rho_t = esval(solES_t, [tlist[t_idx]])
            solES_tau = ode2es(L, rho_t * a_op)
            C_mat[t_idx, :] = esval(expect(b_op, solES_tau), taulist)

    else:
        # default: <A(t+tau)B(t)>
        for t_idx in range(len(tlist)):
            rho_t = esval(solES_t, [tlist[t_idx]])
            solES_tau = ode2es(L, b_op * rho_t)
            C_mat[t_idx, :] = esval(expect(a_op, solES_tau), taulist)

    return C_mat
Example #12
0
def _correlation_mc_2op_2t(H,
                           psi0,
                           tlist,
                           taulist,
                           c_ops,
                           a_op,
                           b_op,
                           reverse=False,
                           args=None,
                           options=Odeoptions()):
    """
    Internal function for calculating correlation functions using the Monte
    Carlo solver. See :func:`correlation` usage.
    """

    if debug:
        print(inspect.stack()[0][3])

    raise NotImplementedError("The Monte-Carlo solver currently cannot be " +
                              "used for correlation functions on the form " +
                              "<A(t)B(t+tau)>")

    if psi0 is None or not isket(psi0):
        raise Exception("_correlation_mc_2op_2t requires initial state as ket")

    C_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex)

    options.gui = False

    psi_t = mcsolve(H, psi0, tlist, c_ops, [], args=args,
                    options=options).states

    for t_idx in range(len(tlist)):

        psi0_t = psi_t[0][t_idx]

        C_mat[t_idx, :] = mcsolve(H,
                                  b_op * psi0_t,
                                  tlist,
                                  c_ops, [a_op],
                                  args=args,
                                  options=options).expect[0]

    return C_mat
Example #13
0
def _correlation_me_4op_2t(H,
                           rho0,
                           tlist,
                           taulist,
                           c_ops,
                           a_op,
                           b_op,
                           c_op,
                           d_op,
                           reverse=False,
                           args=None,
                           options=Odeoptions()):
    """
    Calculate the four-operator two-time correlation function on the form
    <A(t)B(t+tau)C(t+tau)D(t)>.

    See, Gardiner, Quantum Noise, Section 5.2.1
    """

    if debug:
        print(inspect.stack()[0][3])

    if rho0 is None:
        rho0 = steadystate(H, c_ops)
    elif rho0 and isket(rho0):
        rho0 = ket2dm(rho0)

    C_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex)

    rho_t = mesolve(H, rho0, tlist, c_ops, [], args=args,
                    options=options).states

    for t_idx, rho in enumerate(rho_t):
        C_mat[t_idx, :] = mesolve(H,
                                  d_op * rho * a_op,
                                  taulist,
                                  c_ops, [b_op * c_op],
                                  args=args,
                                  options=options).expect[0]

    return C_mat
Example #14
0
def _correlation_me_2op_1t(H,
                           rho0,
                           tlist,
                           c_ops,
                           a_op,
                           b_op,
                           reverse=False,
                           args=None,
                           options=Odeoptions()):
    """
    Internal function for calculating correlation functions using the master
    equation solver. See :func:`correlation_ss` for usage.
    """

    if debug:
        print(inspect.stack()[0][3])

    if rho0 is None:
        rho0 = steadystate(H, c_ops)
    elif rho0 and isket(rho0):
        rho0 = ket2dm(rho0)

    if reverse:
        # <A(t)B(t+tau)>
        return mesolve(H,
                       rho0 * a_op,
                       tlist,
                       c_ops, [b_op],
                       args=args,
                       options=options).expect[0]
    else:
        # <A(t+tau)B(t)>
        return mesolve(H,
                       b_op * rho0,
                       tlist,
                       c_ops, [a_op],
                       args=args,
                       options=options).expect[0]
Example #15
0
def correlation(H,
                rho0,
                tlist,
                taulist,
                c_ops,
                a_op,
                b_op,
                solver="me",
                reverse=False,
                args=None,
                options=Odeoptions()):
    """
    Calculate a two-operator two-time correlation function on the form
    :math:`\left<A(t+\\tau)B(t)\\right>` or
    :math:`\left<A(t)B(t+\\tau)\\right>` (if `reverse=True`), using the
    quantum regression theorem and the evolution solver indicated by the
    *solver* parameter.


    Parameters
    ----------

    H : :class:`qutip.qobj.Qobj`
        system Hamiltonian.

    rho0 : :class:`qutip.qobj.Qobj`
        Initial state density matrix (or state vector). If 'rho0' is
        'None', then the steady state will be used as initial state.

    tlist : *list* / *array*
        list of times for :math:`t`.

    taulist : *list* / *array*
        list of times for :math:`\\tau`.

    c_ops : list of :class:`qutip.qobj.Qobj`
        list of collapse operators.

    a_op : :class:`qutip.qobj`
        operator A.

    b_op : :class:`qutip.qobj`
        operator B.

    solver : str
        choice of solver (`me` for master-equation,
        `es` for exponential series and `mc` for Monte-carlo)

    Returns
    -------

    corr_mat: *array*
        An 2-dimensional *array* (matrix) of correlation values for the times
        specified by `tlist` (first index) and `taulist` (second index). If
        `tlist` is `None`, then a 1-dimensional *array* of correlation values
        is returned instead.

    """

    if debug:
        print(inspect.stack()[0][3])

    return correlation_2op_2t(H,
                              rho0,
                              tlist,
                              taulist,
                              c_ops,
                              a_op,
                              b_op,
                              solver=solver,
                              reverse=reverse,
                              args=args,
                              options=options)
Example #16
0
def correlation_ss(H,
                   taulist,
                   c_ops,
                   a_op,
                   b_op,
                   rho0=None,
                   solver="me",
                   reverse=False,
                   args=None,
                   options=Odeoptions()):
    """
    Calculate a two-operator two-time correlation function
    :math:`\left<A(\\tau)B(0)\\right>` or
    :math:`\left<A(0)B(\\tau)\\right>` (if `reverse=True`),
    using the quantum regression theorem and the evolution solver indicated by
    the *solver* parameter.

    Parameters
    ----------

    H : :class:`qutip.qobj.Qobj`
        system Hamiltonian.

    rho0 : :class:`qutip.qobj.Qobj`
        Initial state density matrix (or state vector). If 'rho0' is
        'None', then the steady state will be used as initial state.

    taulist : *list* / *array*
        list of times for :math:`\\tau`.

    c_ops : list of :class:`qutip.qobj.Qobj`
        list of collapse operators.

    a_op : :class:`qutip.qobj.Qobj`
        operator A.

    b_op : :class:`qutip.qobj.Qobj`
        operator B.

    reverse : bool
        If `True`, calculate :math:`\left<A(0)B(\\tau)\\right>` instead of
        :math:`\left<A(\\tau)B(0)\\right>`.

    solver : str
        choice of solver (`me` for master-equation,
        `es` for exponential series and `mc` for Monte-carlo)

    Returns
    -------

    corr_vec: *array*
        An *array* of correlation values for the times specified by `tlist`

    """

    if debug:
        print(inspect.stack()[0][3])

    return correlation_2op_1t(H,
                              rho0,
                              taulist,
                              c_ops,
                              a_op,
                              b_op,
                              solver,
                              reverse=reverse,
                              args=args,
                              options=options)
Example #17
0
def coherence_function_g2(H,
                          rho0,
                          taulist,
                          c_ops,
                          a_op,
                          solver="me",
                          args=None,
                          options=Odeoptions()):
    """
    Calculate the second-order quantum coherence function:

    .. math::

        g^{(2)}(\\tau) =
        \\frac{\\langle a^\\dagger(0)a^\\dagger(\\tau)a(\\tau)a(0)\\rangle}
        {\\langle a^\\dagger(\\tau)a(\\tau)\\rangle
         \\langle a^\\dagger(0)a(0)\\rangle}

    Parameters
    ----------

    H : :class:`qutip.qobj.Qobj`
        system Hamiltonian.

    rho0 : :class:`qutip.qobj.Qobj`
        Initial state density matrix (or state vector). If 'rho0' is
        'None', then the steady state will be used as initial state.

    taulist : *list* / *array*
        list of times for :math:`\\tau`.

    c_ops : list of :class:`qutip.qobj.Qobj`
        list of collapse operators.

    a_op : :class:`qutip.qobj.Qobj`
        The annihilation operator of the mode.

    solver : str
        choice of solver (currently only 'me')

    Returns
    -------

    g2, G2: tuble of *array*
        The normalized and unnormalized second-order coherence function.

    """

    # first calculate the photon number
    if rho0 is None:
        rho0 = steadystate(H, c_ops)
        n = np.array([expect(rho0, a_op.dag() * a_op)])
    else:
        n = mesolve(H,
                    rho0,
                    taulist,
                    c_ops, [a_op.dag() * a_op],
                    args=args,
                    options=options).expect[0]

    # calculate the correlation function G2 and normalize with n to obtain g2
    G2 = correlation_4op_1t(H,
                            rho0,
                            taulist,
                            c_ops,
                            a_op.dag(),
                            a_op.dag(),
                            a_op,
                            a_op,
                            solver=solver,
                            args=args,
                            options=options)
    g2 = G2 / (n[0] * n)

    return g2, G2
Example #18
0
def fmmesolve(H,
              rho0,
              tlist,
              c_ops,
              e_ops=[],
              spectra_cb=[],
              T=None,
              args={},
              options=Odeoptions(),
              floquet_basis=True,
              kmax=5):
    """
    Solve the dynamics for the system using the Floquet-Markov master equation.

    .. note::

        This solver currently does not support multiple collapse operators.

    Parameters
    ----------

    H : :class:`qutip.qobj`
        system Hamiltonian.

    rho0 / psi0 : :class:`qutip.qobj`
        initial density matrix or state vector (ket).

    tlist : *list* / *array*
        list of times for :math:`t`.

    c_ops : list of :class:`qutip.qobj`
        list of collapse operators.

    e_ops : list of :class:`qutip.qobj` / callback function
        list of operators for which to evaluate expectation values.

    spectra_cb : list callback functions
        List of callback functions that compute the noise power spectrum as
        a function of frequency for the collapse operators in `c_ops`.

    T : float
        The period of the time-dependence of the hamiltonian. The default value
        'None' indicates that the 'tlist' spans a single period of the driving.

    args : *dictionary*
        dictionary of parameters for time-dependent Hamiltonians and
        collapse operators.

        This dictionary should also contain an entry 'w_th', which is
        the temperature of the environment (if finite) in the
        energy/frequency units of the Hamiltonian.  For example, if
        the Hamiltonian written in units of 2pi GHz, and the
        temperature is given in K, use the following conversion

        >>> temperature = 25e-3 # unit K
        >>> h = 6.626e-34
        >>> kB = 1.38e-23
        >>> args['w_th'] = temperature * (kB / h) * 2 * pi * 1e-9

    options : :class:`qutip.odeoptions`
        options for the ODE solver.

    k_max : int
        The truncation of the number of sidebands (default 5).

    Returns
    -------

    output : :class:`qutip.odedata`

        An instance of the class :class:`qutip.odedata`, which contains either
        an *array* of expectation values for the times specified by `tlist`.
    """

    if T is None:
        T = max(tlist)

    if len(spectra_cb) == 0:
        # add white noise callbacks if absent
        spectra_cb = [lambda w: 1.0] * len(c_ops)

    f_modes_0, f_energies = floquet_modes(H, T, args)

    f_modes_table_t = floquet_modes_table(f_modes_0, f_energies,
                                          np.linspace(0, T, 500 + 1), H, T,
                                          args)

    # get w_th from args if it exists
    if 'w_th' in args:
        w_th = args['w_th']
    else:
        w_th = 0

    # TODO: loop over input c_ops and spectra_cb, calculate one R for each set

    # calculate the rate-matrices for the floquet-markov master equation
    Delta, X, Gamma, Amat = floquet_master_equation_rates(
        f_modes_0, f_energies, c_ops[0], H, T, args, spectra_cb[0], w_th, kmax,
        f_modes_table_t)

    # the floquet-markov master equation tensor
    R = floquet_master_equation_tensor(Amat, f_energies)

    return floquet_markov_mesolve(R,
                                  f_modes_0,
                                  rho0,
                                  tlist,
                                  e_ops,
                                  f_modes_table=(f_modes_table_t, T),
                                  options=options,
                                  floquet_basis=floquet_basis)
Example #19
0
def odesolve(H, rho0, tlist, c_op_list, e_ops, args=None, options=None):
    """
    Master equation evolution of a density matrix for a given Hamiltonian.

    Evolution of a state vector or density matrix (`rho0`) for a given
    Hamiltonian (`H`) and set of collapse operators (`c_op_list`), by
    integrating the set of ordinary differential equations that define the
    system. The output is either the state vector at arbitrary points in time
    (`tlist`), or the expectation values of the supplied operators
    (`e_ops`).

    For problems with time-dependent Hamiltonians, `H` can be a callback
    function that takes two arguments, time and `args`, and returns the
    Hamiltonian at that point in time. `args` is a list of parameters that is
    passed to the callback function `H` (only used for time-dependent
    Hamiltonians).

    Parameters
    ----------

    H : :class:`qutip.qobj`
        system Hamiltonian, or a callback function for time-dependent
        Hamiltonians.

    rho0 : :class:`qutip.qobj`
        initial density matrix or state vector (ket).

    tlist : *list* / *array*
        list of times for :math:`t`.

    c_op_list : list of :class:`qutip.qobj`
        list of collapse operators.

    e_ops : list of :class:`qutip.qobj` / callback function
        list of operators for which to evaluate expectation values.

    args : *dictionary*
        dictionary of parameters for time-dependent Hamiltonians and
        collapse operators.

    options : :class:`qutip.Odeoptions`
        with options for the ODE solver.


    Returns
    -------
    output :array
    Expectation values of wavefunctions/density matrices
    for the times specified by `tlist`.

    Notes
    -----
    On using callback function: odesolve transforms all :class:`qutip.qobj`
    objects to sparse matrices before handing the problem to the integrator
    function. In order for your callback function to work correctly, pass
    all :class:`qutip.qobj` objects that are used in constructing the
    Hamiltonian via args. odesolve will check for :class:`qutip.qobj` in
    `args` and handle the conversion to sparse matrices. All other
    :class:`qutip.qobj` objects that are not passed via `args` will be
    passed on to the integrator to scipy who will raise an NotImplemented
    exception.

    Deprecated in QuTiP 2.0.0. Use :func:`mesolve` instead.

    """

    warnings.warn("odesolve is deprecated since 2.0.0. Use mesolve instead.",
                  DeprecationWarning)

    if debug:
        print(inspect.stack()[0][3])

    if options is None:
        options = Odeoptions()

    if (c_op_list and len(c_op_list) > 0) or not isket(rho0):
        if isinstance(H, list):
            output = _mesolve_list_td(H, rho0, tlist, c_op_list, e_ops, args,
                                      options, BaseProgressBar())
        if isinstance(
                H, (types.FunctionType, types.BuiltinFunctionType, partial)):
            output = _mesolve_func_td(H, rho0, tlist, c_op_list, e_ops, args,
                                      options, BaseProgressBar())
        else:
            output = _mesolve_const(H, rho0, tlist, c_op_list, e_ops, args,
                                    options, BaseProgressBar())
    else:
        if isinstance(H, list):
            output = _sesolve_list_td(H, rho0, tlist, e_ops, args, options,
                                      BaseProgressBar())
        if isinstance(
                H, (types.FunctionType, types.BuiltinFunctionType, partial)):
            output = _sesolve_func_td(H, rho0, tlist, e_ops, args, options,
                                      BaseProgressBar())
        else:
            output = _sesolve_const(H, rho0, tlist, e_ops, args, options,
                                    BaseProgressBar())

    if len(e_ops) > 0:
        return output.expect
    else:
        return output.states
Example #20
0
def sesolve(H, rho0, tlist, e_ops, args={}, options=None,
            progress_bar=BaseProgressBar()):
    """
    Schrodinger equation evolution of a state vector for a given Hamiltonian.

    Evolve the state vector or density matrix (`rho0`) using a given
    Hamiltonian (`H`), by integrating the set of ordinary differential
    equations that define the system.

    The output is either the state vector at arbitrary points in time
    (`tlist`), or the expectation values of the supplied operators
    (`e_ops`). If e_ops is a callback function, it is invoked for each
    time in `tlist` with time and the state as arguments, and the function
    does not use any return values.

    Parameters
    ----------

    H : :class:`qutip.qobj`
        system Hamiltonian, or a callback function for time-dependent
        Hamiltonians.

    rho0 : :class:`qutip.qobj`
        initial density matrix or state vector (ket).

    tlist : *list* / *array*
        list of times for :math:`t`.

    e_ops : list of :class:`qutip.qobj` / callback function single
        single operator or list of operators for which to evaluate
        expectation values.

    args : *dictionary*
        dictionary of parameters for time-dependent Hamiltonians and
        collapse operators.

    options : :class:`qutip.Qdeoptions`
        with options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.odedata`

        An instance of the class :class:`qutip.odedata`, which contains either
        an *array* of expectation values for the times specified by `tlist`, or
        an *array* or state vectors or density matrices corresponding to the
        times in `tlist` [if `e_ops` is an empty list], or
        nothing if a callback function was given inplace of operators for
        which to calculate the expectation values.

    """

    if isinstance(e_ops, Qobj):
        e_ops = [e_ops]

    if isinstance(e_ops, dict):
        e_ops_dict = e_ops
        e_ops = [e for e in e_ops.values()]
    else:
        e_ops_dict = None

    # check for type (if any) of time-dependent inputs
    n_const, n_func, n_str = _ode_checks(H, [])

    if options is None:
        options = Odeoptions()

    if (not options.rhs_reuse) or (not odeconfig.tdfunc):
        # reset odeconfig time-dependence flags to default values
        odeconfig.reset()

    if n_func > 0:
        res = _sesolve_list_func_td(H, rho0, tlist, e_ops, args, options,
                                    progress_bar)

    elif n_str > 0:
        res = _sesolve_list_str_td(H, rho0, tlist, e_ops, args, options,
                                   progress_bar)

    elif isinstance(H, (types.FunctionType,
                        types.BuiltinFunctionType,
                        partial)):
        res = _sesolve_func_td(H, rho0, tlist, e_ops, args, options,
                               progress_bar)

    else:
        res = _sesolve_const(H, rho0, tlist, e_ops, args, options,
                             progress_bar)

    if e_ops_dict:
        res.expect = {e: res.expect[n] for n, e in enumerate(e_ops_dict.keys())}

    return res
Example #21
0
def rhs_generate(H, c_ops, args={}, options=Odeoptions(), name=None):
    """
    Generates the Cython functions needed for solving the dynamics of a
    given system using the mesolve function inside a parfor loop.

    Parameters
    ----------
    H : qobj
        System Hamiltonian.
    c_ops : list
        ``list`` of collapse operators.
    args : dict
        Arguments for time-dependent Hamiltonian and collapse operator terms.
    options : Odeoptions
        Instance of ODE solver options.
    name: str
        Name of generated RHS

    Notes
    -----
    Using this function with any solver other than the mesolve function
    will result in an error.

    """
    odeconfig.reset()
    odeconfig.options = options

    if name:
        odeconfig.tdname = name
    else:
        odeconfig.tdname = "rhs" + str(odeconfig.cgen_num)

    Lconst = 0

    Ldata = []
    Linds = []
    Lptrs = []
    Lcoeff = []

    # loop over all hamiltonian terms, convert to superoperator form and
    # add the data of sparse matrix represenation to
    for h_spec in H:
        if isinstance(h_spec, Qobj):
            h = h_spec
            Lconst += -1j * (spre(h) - spost(h))

        elif isinstance(h_spec, list):
            h = h_spec[0]
            h_coeff = h_spec[1]

            L = -1j * (spre(h) - spost(h))

            Ldata.append(L.data.data)
            Linds.append(L.data.indices)
            Lptrs.append(L.data.indptr)
            Lcoeff.append(h_coeff)

        else:
            raise TypeError("Incorrect specification of time-dependent " +
                            "Hamiltonian (expected string format)")

    # loop over all collapse operators
    for c_spec in c_ops:
        if isinstance(c_spec, Qobj):
            c = c_spec
            cdc = c.dag() * c
            Lconst += spre(c) * spost(
                c.dag()) - 0.5 * spre(cdc) - 0.5 * spost(cdc)

        elif isinstance(c_spec, list):
            c = c_spec[0]
            c_coeff = c_spec[1]

            cdc = c.dag() * c
            L = spre(c) * spost(c.dag()) - 0.5 * spre(cdc) - 0.5 * spost(cdc)

            Ldata.append(L.data.data)
            Linds.append(L.data.indices)
            Lptrs.append(L.data.indptr)
            Lcoeff.append("(" + c_coeff + ")**2")

        else:
            raise TypeError("Incorrect specification of time-dependent " +
                            "collapse operators (expected string format)")

    # add the constant part of the lagrangian
    if Lconst != 0:
        Ldata.append(Lconst.data.data)
        Linds.append(Lconst.data.indices)
        Lptrs.append(Lconst.data.indptr)
        Lcoeff.append("1.0")

    # the total number of liouvillian terms (hamiltonian terms + collapse
    # operators)
    n_L_terms = len(Ldata)

    cgen = Codegen(h_terms=n_L_terms,
                   h_tdterms=Lcoeff,
                   args=args,
                   odeconfig=odeconfig)
    cgen.generate(odeconfig.tdname + ".pyx")

    code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs',
                   '<string>', 'exec')
    exec(code)

    odeconfig.tdfunc = cyq_td_ode_rhs
    try:
        os.remove(odeconfig.tdname + ".pyx")
    except:
        pass
Example #22
0
def bloch_redfield_solve(R, ekets, rho0, tlist, e_ops=[], options=None):
    """
    Evolve the ODEs defined by Bloch-Redfield master equation. The
    Bloch-Redfield tensor can be calculated by the function
    :func:`bloch_redfield_tensor`.

    Parameters
    ----------

    R : :class:`qutip.qobj`
        Bloch-Redfield tensor.

    ekets : array of :class:`qutip.qobj`
        Array of kets that make up a basis tranformation for the eigenbasis.

    rho0 : :class:`qutip.qobj`
        Initial density matrix.

    tlist : *list* / *array*
        List of times for :math:`t`.

    e_ops : list of :class:`qutip.qobj` / callback function
        List of operators for which to evaluate expectation values.

    options : :class:`qutip.Qdeoptions`
        Options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.odedata`

        An instance of the class :class:`qutip.odedata`, which contains either
        an *array* of expectation values for the times specified by `tlist`.

    """

    if options is None:
        options = Odeoptions()
        options.nsteps = 2500

    if options.tidy:
        R.tidyup()

    #
    # check initial state
    #
    if isket(rho0):
        # Got a wave function as initial state: convert to density matrix.
        rho0 = rho0 * rho0.dag()

    #
    # prepare output array
    #
    n_e_ops = len(e_ops)
    n_tsteps = len(tlist)
    dt = tlist[1] - tlist[0]

    if n_e_ops == 0:
        result_list = []
    else:
        result_list = []
        for op in e_ops:
            if op.isherm and rho0.isherm:
                result_list.append(np.zeros(n_tsteps))
            else:
                result_list.append(np.zeros(n_tsteps, dtype=complex))

    #
    # transform the initial density matrix and the e_ops opterators to the
    # eigenbasis
    #
    if ekets is not None:
        rho0 = rho0.transform(ekets)
        for n in arange(len(e_ops)):
            e_ops[n] = e_ops[n].transform(ekets, False)

    #
    # setup integrator
    #
    initial_vector = mat2vec(rho0.full())
    r = scipy.integrate.ode(cy_ode_rhs)
    r.set_f_params(R.data.data, R.data.indices, R.data.indptr)
    r.set_integrator('zvode', method=options.method, order=options.order,
                     atol=options.atol, rtol=options.rtol,
                     #nsteps=options.nsteps,
                     #first_step=options.first_step, min_step=options.min_step,
                     max_step=options.max_step)
    r.set_initial_value(initial_vector, tlist[0])

    #
    # start evolution
    #
    rho = Qobj(rho0)

    t_idx = 0
    for t in tlist:
        if not r.successful():
            break

        rho.data = vec2mat(r.y)

        # calculate all the expectation values, or output rho if no operators
        if n_e_ops == 0:
            result_list.append(Qobj(rho))
        else:
            for m in range(0, n_e_ops):
                result_list[m][t_idx] = expect(e_ops[m], rho)

        r.integrate(r.t + dt)
        t_idx += 1

    return result_list
Example #23
0
def brmesolve(H,
              psi0,
              tlist,
              a_ops,
              e_ops=[],
              spectra_cb=[],
              args={},
              options=Odeoptions()):
    """
    Solve the dynamics for the system using the Bloch-Redfeild master equation.

    .. note::

        This solver does not currently support time-dependent Hamiltonian or
        collapse operators.

    Parameters
    ----------

    H : :class:`qutip.qobj`
        System Hamiltonian.

    rho0 / psi0: :class:`qutip.qobj`
        Initial density matrix or state vector (ket).

    tlist : *list* / *array*
        List of times for :math:`t`.

    a_ops : list of :class:`qutip.qobj`
        List of system operators that couple to bath degrees of freedom.

    e_ops : list of :class:`qutip.qobj` / callback function
        List of operators for which to evaluate expectation values.

    args : *dictionary*
        Dictionary of parameters for time-dependent Hamiltonians and collapse
        operators.

    options : :class:`qutip.Qdeoptions`
        Options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.odedata`

        An instance of the class :class:`qutip.odedata`, which contains either
        a list of expectation values, for operators given in e_ops, or a list
        of states for the times specified by `tlist`.
    """

    if not spectra_cb:
        # default to infinite temperature white noise
        spectra_cb = [lambda w: 1.0 for _ in a_ops]

    R, ekets = bloch_redfield_tensor(H, a_ops, spectra_cb)

    output = Odedata()
    output.solver = "brmesolve"
    output.times = tlist

    results = bloch_redfield_solve(R, ekets, psi0, tlist, e_ops, options)

    if e_ops:
        output.expect = results
    else:
        output.states = results

    return output
Example #24
0
def bloch_redfield_solve(R, ekets, rho0, tlist, e_ops=[], options=None):
    """
    Evolve the ODEs defined by Bloch-Redfield master equation. The
    Bloch-Redfield tensor can be calculated by the function
    :func:`bloch_redfield_tensor`.

    Parameters
    ----------

    R : :class:`qutip.qobj`
        Bloch-Redfield tensor.

    ekets : array of :class:`qutip.qobj`
        Array of kets that make up a basis tranformation for the eigenbasis.

    rho0 : :class:`qutip.qobj`
        Initial density matrix.

    tlist : *list* / *array*
        List of times for :math:`t`.

    e_ops : list of :class:`qutip.qobj` / callback function
        List of operators for which to evaluate expectation values.

    options : :class:`qutip.Qdeoptions`
        Options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.odedata`

        An instance of the class :class:`qutip.odedata`, which contains either
        an *array* of expectation values for the times specified by `tlist`.

    """

    if options is None:
        options = Odeoptions()
        options.nsteps = 2500

    if options.tidy:
        R.tidyup()

    #
    # check initial state
    #
    if isket(rho0):
        # Got a wave function as initial state: convert to density matrix.
        rho0 = rho0 * rho0.dag()

    #
    # prepare output array
    #
    n_e_ops = len(e_ops)
    n_tsteps = len(tlist)
    dt = tlist[1] - tlist[0]

    if n_e_ops == 0:
        result_list = []
    else:
        result_list = []
        for op in e_ops:
            if op.isherm and rho0.isherm:
                result_list.append(np.zeros(n_tsteps))
            else:
                result_list.append(np.zeros(n_tsteps, dtype=complex))

    #
    # transform the initial density matrix and the e_ops opterators to the
    # eigenbasis
    #
    if ekets is not None:
        rho0 = rho0.transform(ekets)
        for n in arange(len(e_ops)):
            e_ops[n] = e_ops[n].transform(ekets, False)

    #
    # setup integrator
    #
    initial_vector = mat2vec(rho0.full())
    r = scipy.integrate.ode(cy_ode_rhs)
    r.set_f_params(R.data.data, R.data.indices, R.data.indptr)
    r.set_integrator(
        'zvode',
        method=options.method,
        order=options.order,
        atol=options.atol,
        rtol=options.rtol,
        #nsteps=options.nsteps,
        #first_step=options.first_step, min_step=options.min_step,
        max_step=options.max_step)
    r.set_initial_value(initial_vector, tlist[0])

    #
    # start evolution
    #
    rho = Qobj(rho0)

    t_idx = 0
    for t in tlist:
        if not r.successful():
            break

        rho.data = vec2mat(r.y)

        # calculate all the expectation values, or output rho if no operators
        if n_e_ops == 0:
            result_list.append(Qobj(rho))
        else:
            for m in range(0, n_e_ops):
                result_list[m][t_idx] = expect(e_ops[m], rho)

        r.integrate(r.t + dt)
        t_idx += 1

    return result_list
Example #25
0
def floquet_markov_mesolve(R,
                           ekets,
                           rho0,
                           tlist,
                           e_ops,
                           f_modes_table=None,
                           options=None,
                           floquet_basis=True):
    """
    Solve the dynamics for the system using the Floquet-Markov master equation.
    """

    if options is None:
        opt = Odeoptions()
    else:
        opt = options

    if opt.tidy:
        R.tidyup()

    #
    # check initial state
    #
    if isket(rho0):
        # Got a wave function as initial state: convert to density matrix.
        rho0 = ket2dm(rho0)

    #
    # prepare output array
    #
    n_tsteps = len(tlist)
    dt = tlist[1] - tlist[0]

    output = Odedata()
    output.solver = "fmmesolve"
    output.times = tlist

    if isinstance(e_ops, FunctionType):
        n_expt_op = 0
        expt_callback = True

    elif isinstance(e_ops, list):

        n_expt_op = len(e_ops)
        expt_callback = False

        if n_expt_op == 0:
            output.states = []
        else:
            if not f_modes_table:
                raise TypeError("The Floquet mode table has to be provided " +
                                "when requesting expectation values.")

            output.expect = []
            output.num_expect = n_expt_op
            for op in e_ops:
                if op.isherm:
                    output.expect.append(np.zeros(n_tsteps))
                else:
                    output.expect.append(np.zeros(n_tsteps, dtype=complex))

    else:
        raise TypeError("Expectation parameter must be a list or a function")

    #
    # transform the initial density matrix to the eigenbasis: from
    # computational basis to the floquet basis
    #
    if ekets is not None:
        rho0 = rho0.transform(ekets, True)

    #
    # setup integrator
    #
    initial_vector = mat2vec(rho0.full())
    r = scipy.integrate.ode(cy_ode_rhs)
    r.set_f_params(R.data.data, R.data.indices, R.data.indptr)
    r.set_integrator('zvode',
                     method=opt.method,
                     order=opt.order,
                     atol=opt.atol,
                     rtol=opt.rtol,
                     max_step=opt.max_step)
    r.set_initial_value(initial_vector, tlist[0])

    #
    # start evolution
    #
    rho = Qobj(rho0)

    t_idx = 0
    for t in tlist:
        if not r.successful():
            break

        rho.data = vec2mat(r.y)

        if expt_callback:
            # use callback method
            if floquet_basis:
                e_ops(t, Qobj(rho))
            else:
                f_modes_table_t, T = f_modes_table
                f_modes_t = floquet_modes_t_lookup(f_modes_table_t, t, T)
                e_ops(t, Qobj(rho).transform(f_modes_t, False))
        else:
            # calculate all the expectation values, or output rho if
            # no operators
            if n_expt_op == 0:
                if floquet_basis:
                    output.states.append(Qobj(rho))
                else:
                    f_modes_table_t, T = f_modes_table
                    f_modes_t = floquet_modes_t_lookup(f_modes_table_t, t, T)
                    output.states.append(Qobj(rho).transform(f_modes_t, False))
            else:
                f_modes_table_t, T = f_modes_table
                f_modes_t = floquet_modes_t_lookup(f_modes_table_t, t, T)
                for m in range(0, n_expt_op):
                    output.expect[m][t_idx] = \
                        expect(e_ops[m], rho.transform(f_modes_t, False))

        r.integrate(r.t + dt)
        t_idx += 1

    return output
Example #26
0
def mcsolve_f90(H, psi0, tlist, c_ops, e_ops, ntraj=None,
                options=Odeoptions(), sparse_dms=True, serial=False,
                ptrace_sel=[], calc_entropy=False):
    """
    Monte-Carlo wave function solver with fortran 90 backend.
    Usage is identical to qutip.mcsolve, for problems without explicit
    time-dependence, and with some optional input:

    Parameters
    ----------
    H : qobj
        System Hamiltonian.
    psi0 : qobj
        Initial state vector
    tlist : array_like
        Times at which results are recorded.
    ntraj : int
        Number of trajectories to run.
    c_ops : array_like
        ``list`` or ``array`` of collapse operators.
    e_ops : array_like
        ``list`` or ``array`` of operators for calculating expectation values.
    options : Odeoptions
        Instance of ODE solver options.
    sparse_dms : boolean
        If averaged density matrices are returned, they will be stored as
        sparse (Compressed Row Format) matrices during computation if
        sparse_dms = True (default), and dense matrices otherwise. Dense
        matrices might be preferable for smaller systems.
    serial : boolean
        If True (default is False) the solver will not make use of the
        multiprocessing module, and simply run in serial.
    ptrace_sel: list
        This optional argument specifies a list of components to keep when
        returning a partially traced density matrix. This can be convenient for
        large systems where memory becomes a problem, but you are only
        interested in parts of the density matrix.
    calc_entropy : boolean
        If ptrace_sel is specified, calc_entropy=True will have the solver
        return the averaged entropy over trajectories in results.entropy. This
        can be interpreted as a measure of entanglement. See Phys. Rev. Lett.
        93, 120408 (2004), Phys. Rev. A 86, 022310 (2012).

    Returns
    -------
    results : Odedata
        Object storing all results from simulation.

    """
    if ntraj is None:
        ntraj = options.ntraj

    if psi0.type != 'ket':
        raise Exception("Initial state must be a state vector.")
    odeconfig.options = options
    # set num_cpus to the value given in qutip.settings
    # if none in Odeoptions
    if not odeconfig.options.num_cpus:
        odeconfig.options.num_cpus = qutip.settings.num_cpus
    # set initial value data
    if options.tidy:
        odeconfig.psi0 = psi0.tidyup(options.atol).full()
    else:
        odeconfig.psi0 = psi0.full()
    odeconfig.psi0_dims = psi0.dims
    odeconfig.psi0_shape = psi0.shape
    # set general items
    odeconfig.tlist = tlist
    if isinstance(ntraj, (list, np.ndarray)):
        raise Exception("ntraj as list argument is not supported.")
    else:
        odeconfig.ntraj = ntraj
        # ntraj_list = [ntraj]
    # set norm finding constants
    odeconfig.norm_tol = options.norm_tol
    odeconfig.norm_steps = options.norm_steps

    if not options.rhs_reuse:
        odeconfig.soft_reset()
        # no time dependence
        odeconfig.tflag = 0
        # check for collapse operators
        if len(c_ops) > 0:
            odeconfig.cflag = 1
        else:
            odeconfig.cflag = 0
        # Configure data
        _mc_data_config(H, psi0, [], c_ops, [], [], e_ops, options, odeconfig)

    # Load Monte Carlo class
    mc = _MC_class()
    # Set solver type
    if (options.method == 'adams'):
        mc.mf = 10
    elif (options.method == 'bdf'):
        mc.mf = 22
    else:
        if debug:
            print('Unrecognized method for ode solver, using "adams".')
        mc.mf = 10
    # store ket and density matrix dims and shape for convenience
    mc.psi0_dims = psi0.dims
    mc.psi0_shape = psi0.shape
    mc.dm_dims = (psi0 * psi0.dag()).dims
    mc.dm_shape = (psi0 * psi0.dag()).shape
    # use sparse density matrices during computation?
    mc.sparse_dms = sparse_dms
    # run in serial?
    mc.serial_run = serial or (ntraj == 1)
    # are we doing a partial trace for returned states?
    mc.ptrace_sel = ptrace_sel
    if (ptrace_sel != []):
        if debug:
            print("ptrace_sel set to " + str(ptrace_sel))
            print("We are using dense density matrices during computation " +
                  "when performing partial trace. Setting sparse_dms = False")
            print("This feature is experimental.")
        mc.sparse_dms = False
        mc.dm_dims = psi0.ptrace(ptrace_sel).dims
        mc.dm_shape = psi0.ptrace(ptrace_sel).shape
    if (calc_entropy):
        if (ptrace_sel == []):
            if debug:
                print("calc_entropy = True, but ptrace_sel = []. Please set " +
                     "a list of components to keep when calculating average " +
                     "entropy of reduced density matrix in ptrace_sel. " +
                     "Setting calc_entropy = False.")
            calc_entropy = False
        mc.calc_entropy = calc_entropy

    # construct output Odedata object
    output = Odedata()

    # Run
    mc.run()
    output.states = mc.sol.states
    output.expect = mc.sol.expect
    output.col_times = mc.sol.col_times
    output.col_which = mc.sol.col_which
    if (hasattr(mc.sol, 'entropy')):
        output.entropy = mc.sol.entropy

    output.solver = 'Fortran 90 Monte Carlo solver'
    # simulation parameters
    output.times = odeconfig.tlist
    output.num_expect = odeconfig.e_num
    output.num_collapse = odeconfig.c_num
    output.ntraj = odeconfig.ntraj

    return output
Example #27
0
def brmesolve(H,
              psi0,
              tlist,
              c_ops,
              e_ops=[],
              spectra_cb=[],
              args={},
              options=Odeoptions()):
    """
    Solve the dynamics for the system using the Bloch-Redfeild master equation.

    .. note::

        This solver does not currently support time-dependent Hamiltonian or
        collapse operators.

    Parameters
    ----------

    H : :class:`qutip.qobj`
        System Hamiltonian.

    rho0 / psi0: :class:`qutip.qobj`
        Initial density matrix or state vector (ket).

    tlist : *list* / *array*
        List of times for :math:`t`.

    c_ops : list of :class:`qutip.qobj`
        List of collapse operators.

    expt_ops : list of :class:`qutip.qobj` / callback function
        List of operators for which to evaluate expectation values.

    args : *dictionary*
        Dictionary of parameters for time-dependent Hamiltonians and collapse
        operators.

    options : :class:`qutip.Qdeoptions`
        Options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.odedata`

        An instance of the class :class:`qutip.odedata`, which contains either
        an *array* of expectation values for the times specified by `tlist`.
    """

    if len(spectra_cb) == 0:
        for n in range(len(c_ops)):
            # add white noise callbacks if absent
            spectra_cb.append(lambda w: 1.0)

    R, ekets = bloch_redfield_tensor(H, c_ops, spectra_cb)

    output = Odedata()
    output.times = tlist

    results = bloch_redfield_solve(R, ekets, psi0, tlist, e_ops, options)

    if len(e_ops):
        output.expect = results
    else:
        output.states = results

    return output
Example #28
0
def mesolve(H,
            rho0,
            tlist,
            c_ops,
            e_ops,
            args={},
            options=None,
            progress_bar=BaseProgressBar()):
    """
    Master equation evolution of a density matrix for a given Hamiltonian.

    Evolve the state vector or density matrix (`rho0`) using a given
    Hamiltonian (`H`) and an [optional] set of collapse operators
    (`c_op_list`), by integrating the set of ordinary differential equations
    that define the system. In the absense of collase operators the system is
    evolved according to the unitary evolution of the Hamiltonian.

    The output is either the state vector at arbitrary points in time
    (`tlist`), or the expectation values of the supplied operators
    (`e_ops`). If e_ops is a callback function, it is invoked for each
    time in `tlist` with time and the state as arguments, and the function
    does not use any return values.

    **Time-dependent operators**

    For problems with time-dependent problems `H` and `c_ops` can be callback
    functions that takes two arguments, time and `args`, and returns the
    Hamiltonian or Liuovillian for the system at that point in time
    (*callback format*).

    Alternatively, `H` and `c_ops` can be a specified in a nested-list format
    where each element in the list is a list of length 2, containing an
    operator (:class:`qutip.qobj`) at the first element and where the
    second element is either a string (*list string format*) or a callback
    function (*list callback format*) that evaluates to the time-dependent
    coefficient for the corresponding operator.

    *Examples*

        H = [[H0, 'sin(w*t)'], [H1, 'sin(2*w*t)']]

        H = [[H0, f0_t], [H1, f1_t]]

        where f0_t and f1_t are python functions with signature f_t(t, args).

    In the *list string format* and *list callback format*, the string
    expression and the callback function must evaluate to a real or complex
    number (coefficient for the corresponding operator).

    In all cases of time-dependent operators, `args` is a dictionary of
    parameters that is used when evaluating operators. It is passed to the
    callback functions as second argument

    .. note::

        If an element in the list-specification of the Hamiltonian or
        the list of collapse operators are in super-operator for it will be
        added to the total Liouvillian of the problem with out further
        transformation. This allows for using mesolve for solving master
        equations that are not on standard Lindblad form.

    .. note::

        On using callback function: mesolve transforms all :class:`qutip.qobj`
        objects to sparse matrices before handing the problem to the integrator
        function. In order for your callback function to work correctly, pass
        all :class:`qutip.qobj` objects that are used in constructing the
        Hamiltonian via args. odesolve will check for :class:`qutip.qobj` in
        `args` and handle the conversion to sparse matrices. All other
        :class:`qutip.qobj` objects that are not passed via `args` will be
        passed on to the integrator to scipy who will raise an NotImplemented
        exception.

    Parameters
    ----------

    H : :class:`qutip.qobj`
        system Hamiltonian, or a callback function for time-dependent
        Hamiltonians.

    rho0 : :class:`qutip.qobj`
        initial density matrix or state vector (ket).

    tlist : *list* / *array*
        list of times for :math:`t`.

    c_ops : list of :class:`qutip.qobj`
        single collapse operator, or list of collapse operators.

    e_ops : list of :class:`qutip.qobj` / callback function single
        single operator or list of operators for which to evaluate
        expectation values.

    args : *dictionary*
        dictionary of parameters for time-dependent Hamiltonians and
        collapse operators.

    options : :class:`qutip.Odeoptions`
        with options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.odedata`

        An instance of the class :class:`qutip.odedata`, which contains either
        an *array* of expectation values for the times specified by `tlist`, or
        an *array* or state vectors or density matrices corresponding to the
        times in `tlist` [if `e_ops` is an empty list], or
        nothing if a callback function was given inplace of operators for
        which to calculate the expectation values.

    """

    # check whether c_ops or e_ops is is a single operator
    # if so convert it to a list containing only that operator
    if isinstance(c_ops, Qobj):
        c_ops = [c_ops]

    if isinstance(e_ops, Qobj):
        e_ops = [e_ops]

    if isinstance(e_ops, dict):
        e_ops_dict = e_ops
        e_ops = [e for e in e_ops.values()]
    else:
        e_ops_dict = None

    # check for type (if any) of time-dependent inputs
    n_const, n_func, n_str = _ode_checks(H, c_ops)

    if options is None:
        options = Odeoptions()

    if (not options.rhs_reuse) or (not odeconfig.tdfunc):
        # reset odeconfig collapse and time-dependence flags to default values
        odeconfig.reset()

    res = None

    #
    # dispatch the appropriate solver
    #
    if ((c_ops and len(c_ops) > 0) or (not isket(rho0))
            or (isinstance(H, Qobj) and issuper(H)) or
        (isinstance(H, list) and isinstance(H[0], Qobj) and issuper(H[0]))):

        #
        # we have collapse operators
        #

        #
        # find out if we are dealing with all-constant hamiltonian and
        # collapse operators or if we have at least one time-dependent
        # operator. Then delegate to appropriate solver...
        #

        if isinstance(H, Qobj):
            # constant hamiltonian
            if n_func == 0 and n_str == 0:
                # constant collapse operators
                res = _mesolve_const(H, rho0, tlist, c_ops, e_ops, args,
                                     options, progress_bar)
            elif n_str > 0:
                # constant hamiltonian but time-dependent collapse
                # operators in list string format
                res = _mesolve_list_str_td([H], rho0, tlist, c_ops, e_ops,
                                           args, options, progress_bar)
            elif n_func > 0:
                # constant hamiltonian but time-dependent collapse
                # operators in list function format
                res = _mesolve_list_func_td([H], rho0, tlist, c_ops, e_ops,
                                            args, options, progress_bar)

        elif isinstance(
                H, (types.FunctionType, types.BuiltinFunctionType, partial)):
            # old style time-dependence: must have constant collapse operators
            if n_str > 0:  # or n_func > 0:
                raise TypeError("Incorrect format: function-format " +
                                "Hamiltonian cannot be mixed with " +
                                "time-dependent collapse operators.")
            else:
                res = _mesolve_func_td(H, rho0, tlist, c_ops, e_ops, args,
                                       options, progress_bar)

        elif isinstance(H, list):
            # determine if we are dealing with list of [Qobj, string] or
            # [Qobj, function] style time-dependencies (for pure python and
            # cython, respectively)
            if n_func > 0:
                res = _mesolve_list_func_td(H, rho0, tlist, c_ops, e_ops, args,
                                            options, progress_bar)
            else:
                res = _mesolve_list_str_td(H, rho0, tlist, c_ops, e_ops, args,
                                           options, progress_bar)

        else:
            raise TypeError("Incorrect specification of Hamiltonian " +
                            "or collapse operators.")

    else:
        #
        # no collapse operators: unitary dynamics
        #
        if n_func > 0:
            res = _sesolve_list_func_td(H, rho0, tlist, e_ops, args, options,
                                        progress_bar)
        elif n_str > 0:
            res = _sesolve_list_str_td(H, rho0, tlist, e_ops, args, options,
                                       progress_bar)
        elif isinstance(
                H, (types.FunctionType, types.BuiltinFunctionType, partial)):
            res = _sesolve_func_td(H, rho0, tlist, e_ops, args, options,
                                   progress_bar)
        else:
            res = _sesolve_const(H, rho0, tlist, e_ops, args, options,
                                 progress_bar)

    if e_ops_dict:
        res.expect = {
            e: res.expect[n]
            for n, e in enumerate(e_ops_dict.keys())
        }

    return res
Example #29
0
def correlation_2op_2t(H,
                       rho0,
                       tlist,
                       taulist,
                       c_ops,
                       a_op,
                       b_op,
                       solver="me",
                       reverse=False,
                       args=None,
                       options=Odeoptions()):
    """
    Calculate a two-operator two-time correlation function on the form
    :math:`\left<A(t+\\tau)B(t)\\right>` or
    :math:`\left<A(t)B(t+\\tau)\\right>` (if `reverse=True`), using the
    quantum regression theorem and the evolution solver indicated by the
    *solver* parameter.


    Parameters
    ----------

    H : :class:`qutip.qobj.Qobj`
        system Hamiltonian.

    rho0 : :class:`qutip.qobj.Qobj`
        Initial state density matrix :math:`\\rho(t_0)` (or state vector). If
        'rho0' is 'None', then the steady state will be used as initial state.

    tlist : *list* / *array*
        list of times for :math:`t`.

    taulist : *list* / *array*
        list of times for :math:`\\tau`.

    c_ops : list of :class:`qutip.qobj.Qobj`
        list of collapse operators.

    a_op : :class:`qutip.qobj.Qobj`
        operator A.

    b_op : :class:`qutip.qobj.Qobj`
        operator B.

    solver : str
        choice of solver (`me` for master-equation,
        `es` for exponential series and `mc` for Monte-carlo)

    reverse : bool
        If `True`, calculate :math:`\left<A(t)B(t+\\tau)\\right>` instead of
        :math:`\left<A(t+\\tau)B(t)\\right>`.

    Returns
    -------

    corr_mat: *array*
        An 2-dimensional *array* (matrix) of correlation values for the times
        specified by `tlist` (first index) and `taulist` (second index). If
        `tlist` is `None`, then a 1-dimensional *array* of correlation values
        is returned instead.

    """

    if debug:
        print(inspect.stack()[0][3])

    if tlist is None:
        # only interested in correlation vs one time coordinate, so we can use
        # the ss solver with the supplied density matrix as initial state (in
        # place of the steady state)
        return correlation_2op_1t(H,
                                  rho0,
                                  taulist,
                                  c_ops,
                                  a_op,
                                  b_op,
                                  solver,
                                  reverse,
                                  args=args,
                                  options=options)

    if solver == "me":
        return _correlation_me_2op_2t(H,
                                      rho0,
                                      tlist,
                                      taulist,
                                      c_ops,
                                      a_op,
                                      b_op,
                                      reverse,
                                      args=args,
                                      options=options)
    elif solver == "es":
        return _correlation_es_2op_2t(H,
                                      rho0,
                                      tlist,
                                      taulist,
                                      c_ops,
                                      a_op,
                                      b_op,
                                      reverse,
                                      args=args,
                                      options=options)
    elif solver == "mc":
        return _correlation_mc_2op_2t(H,
                                      rho0,
                                      tlist,
                                      taulist,
                                      c_ops,
                                      a_op,
                                      b_op,
                                      reverse,
                                      args=args,
                                      options=options)
    else:
        raise "Unrecognized choice of solver %s (use me, es or mc)." % solver
Example #30
0
def propagator(H, t, c_op_list, args=None, options=None, sparse=False):
    """
    Calculate the propagator U(t) for the density matrix or wave function such
    that :math:`\psi(t) = U(t)\psi(0)` or
    :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)`
    where :math:`\\rho_{\mathrm vec}` is the vector representation of the
    density matrix.

    Parameters
    ----------
    H : qobj or list
        Hamiltonian as a Qobj instance of a nested list of Qobjs and
        coefficients in the list-string or list-function format for
        time-dependent Hamiltonians (see description in :func:`qutip.mesolve`).

    t : float or array-like
        Time or list of times for which to evaluate the propagator.

    c_op_list : list
        List of qobj collapse operators.

    args : list/array/dictionary
        Parameters to callback functions for time-dependent Hamiltonians and
        collapse operators.

    options : :class:`qutip.Odeoptions`
        with options for the ODE solver.

    Returns
    -------
     a : qobj
        Instance representing the propagator :math:`U(t)`.

    """

    if options is None:
        options = Odeoptions()
        options.rhs_reuse = True
        rhs_clear()

    tlist = [0, t] if isinstance(t, (int, float, np.int64, np.float64)) else t

    if isinstance(H, (types.FunctionType, types.BuiltinFunctionType,
                      functools.partial)):
        H0 = H(0.0, args)
    elif isinstance(H, list):
        H0 = H[0][0] if isinstance(H[0], list) else H[0]
    else:
        H0 = H

    if len(c_op_list) == 0 and H0.isoper:
        # calculate propagator for the wave function

        N = H0.shape[0]
        dims = H0.dims
        u = np.zeros([N, N, len(tlist)], dtype=complex)

        for n in range(0, N):
            psi0 = basis(N, n)
            output = sesolve(H, psi0, tlist, [], args, options)
            for k, t in enumerate(tlist):
                u[:, n, k] = output.states[k].full().T

        # todo: evolving a batch of wave functions:
        # psi_0_list = [basis(N, n) for n in range(N)]
        # psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], args, options)
        # for n in range(0, N):
        #    u[:,n] = psi_t_list[n][1].full().T


    elif len(c_op_list) == 0 and H0.issuper:
        # calculate the propagator for the vector representation of the
        # density matrix (a superoperator propagator)

        N = H0.shape[0]
        dims = H0.dims

        u = np.zeros([N, N, len(tlist)], dtype=complex)

        for n in range(0, N):
            psi0 = basis(N, n)
            rho0 = Qobj(vec2mat(psi0.full()))
            output = mesolve(H, rho0, tlist, [], [], args, options)
            for k, t in enumerate(tlist):
                u[:, n, k] = mat2vec(output.states[k].full()).T

    else:
        # calculate the propagator for the vector representation of the
        # density matrix (a superoperator propagator)

        N = H0.shape[0]
        dims = [H0.dims, H0.dims]

        u = np.zeros([N * N, N * N, len(tlist)], dtype=complex)

        if sparse:
            for n in range(N * N):
                psi0 = basis(N * N, n)
                psi0.dims = [dims[0], 1]
                rho0 = vector_to_operator(psi0)
                output = mesolve(H, rho0, tlist, c_op_list, [], args, options)
                for k, t in enumerate(tlist):
                    u[:, n, k] = operator_to_vector(output.states[k]).full(squeeze=True)

        else:  
            for n in range(N * N):
                psi0 = basis(N * N, n)
                rho0 = Qobj(vec2mat(psi0.full()))
                output = mesolve(H, rho0, tlist, c_op_list, [], args, options)
                for k, t in enumerate(tlist):
                    u[:, n, k] = mat2vec(output.states[k].full()).T


    if len(tlist) == 2:
        return Qobj(u[:, :, 1], dims=dims)
    else:
        return [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))]
Example #31
0
def correlation_4op_2t(H,
                       rho0,
                       tlist,
                       taulist,
                       c_ops,
                       a_op,
                       b_op,
                       c_op,
                       d_op,
                       solver="me",
                       args=None,
                       options=Odeoptions()):
    """
    Calculate the four-operator two-time correlation function on the from
    :math:`\left<A(t)B(t+\\tau)C(t+\\tau)D(t)\\right>` using the quantum
    regression theorem and the solver indicated by the 'solver' parameter.

    Parameters
    ----------

    H : :class:`qutip.qobj.Qobj`
        system Hamiltonian.

    rho0 : :class:`qutip.qobj.Qobj`
        Initial state density matrix (or state vector). If 'rho0' is
        'None', then the steady state will be used as initial state.

    tlist : *list* / *array*
        list of times for :math:`t`.

    taulist : *list* / *array*
        list of times for :math:`\\tau`.

    c_ops : list of :class:`qutip.qobj.Qobj`
        list of collapse operators.

    a_op : :class:`qutip.qobj.Qobj`
        operator A.

    b_op : :class:`qutip.qobj.Qobj`
        operator B.

    c_op : :class:`qutip.qobj.Qobj`
        operator C.

    d_op : :class:`qutip.qobj.Qobj`
        operator D.

    solver : str
        choice of solver (currently only `me` for master-equation)

    Returns
    -------

    corr_mat: *array*
        An 2-dimensional *array* (matrix) of correlation values for the times
        specified by `tlist` (first index) and `taulist` (second index). If
        `tlist` is `None`, then a 1-dimensional *array* of correlation values
        is returned instead.

    References
    ----------

    See, Gardiner, Quantum Noise, Section 5.2.1.

    """

    if debug:
        print(inspect.stack()[0][3])

    if solver == "me":
        return _correlation_me_4op_2t(H,
                                      rho0,
                                      tlist,
                                      taulist,
                                      c_ops,
                                      a_op,
                                      b_op,
                                      c_op,
                                      d_op,
                                      args=args,
                                      options=options)
    else:
        raise NotImplementedError("Unrecognized choice of solver %s." % solver)
Example #32
0
def mi_mcsolve(H,
               psi0,
               tlist,
               c_ops,
               e_ops,
               ntraj=500,
               args={},
               options=Odeoptions()):
    if psi0.type != 'ket':
        raise ValueError("psi0 must be a state vector")
    if type(ntraj) == int:
        ntraj = [ntraj]
    elif type(ntraj[0]) != int:
        raise ValueError(
            "ntraj must either be an integer or a list of integers")

    num_eops = len(e_ops)
    num_cops = len(c_ops)
    # Just use mcsolve if there aren't any collapse or expect. operators
    if num_eops == num_cops == 0:
        raise ValueError(
            "Must supply at least one expectation value operator.")
        # should not ever meet this condition
        #return qutip.mcsolve(H, psi0, tlist, c_ops, e_ops, ntraj, args, options)
    elif num_cops == 0:
        ntraj = 1

    # Let's be sure we're not changing anything:
    H = copy.deepcopy(H)
    H = np.matrix(H.full())
    psi0 = copy.deepcopy(psi0)
    psi0 = psi0.full()
    tlist = copy.deepcopy(tlist)
    c_ops = copy.deepcopy(c_ops)
    for i in range(num_cops):
        c_ops[i] = np.matrix(c_ops[i].full())
    e_ops = copy.deepcopy(e_ops)
    eops_herm = [False for _ in range(num_eops)]
    for i in range(num_eops):
        e_ops[i] = np.matrix(e_ops[i].full())
        eops_herm[i] = not any(abs(e_ops[i].getH() - e_ops[i]) >
                               1e-15)  # check if each e_op is Hermetian

    # Construct the effective Hamiltonian
    Heff = H
    for cop in c_ops:
        Heff += -0.5j * np.dot(cop.getH(), cop)
    Heff = (-1j) * Heff
    # Find the eigenstates of the effective Hamiltonian
    la, v = np.linalg.eig(Heff)
    # Construct the similarity transformation matricies
    S = np.matrix(v)
    Sinv = np.linalg.inv(S)
    Heff_diag = np.dot(Sinv, np.dot(Heff, S)).round(10)

    for i in range(num_cops):
        c_ops[i] = np.dot(
            c_ops[i], S)  # Multiply each Collapse Operator to the left by S

    psi0 = psi0 / np.linalg.norm(psi0)
    psi0_nb = np.dot(Sinv, psi0)  # change basis for initial state vector

    for i in range(num_eops):
        e_ops[i] = np.dot(
            S.getH(), np.dot(e_ops[i], S)
        )  # Change basis for the operator for which expectation values are requested

    if len(ntraj) > 1:
        exp_vals = [
            list(
                np.zeros(len(tlist),
                         dtype=(float if eops_herm[i] else complex))
                for i in range(num_eops)) for _ in range(len(ntraj))
        ]
        collapse_times_out = [list() for _ in range(len(ntraj))]
        which_op_out = [list() for _ in range(len(ntraj))]
    else:
        exp_vals = list(
            np.zeros(len(tlist), dtype=(float if eops_herm[i] else complex))
            for i in range(num_eops))
        collapse_times_out, which_op_out = list(), list()
    for _n in range(len(ntraj)):  # ntraj can be passed in as a list
        print "Calculation Starting on", multiprocessing.cpu_count(), "CPUs"
        p = Pool()

        def callback(r):  # method to display progress
            callback.counter += 1
            if (round(100.0 * float(callback.counter) / callback.ntraj) >=
                    10 + round(100.0 * float(callback.last) / callback.ntraj)):
                print "Progress: %.0f%% (approx. %.2fs remaining)" % (
                    (100.0 * float(callback.counter) / callback.ntraj),
                    ((time.time() - callback.start) / callback.counter *
                     (callback.ntraj - callback.counter)))
                callback.last = callback.counter

        callback.last = 0
        callback.counter = 0
        callback.ntraj = ntraj[_n]
        callback.start = time.time()

        results = [
            r.get() for r in [
                p.apply_async(one_traj, (Heff_diag, S, Sinv, psi0_nb, tlist,
                                         e_ops, c_ops, num_eops,
                                         num_cops), {}, callback)
                for _ in range(ntraj[_n])
            ]
        ]
        p.close()
        p.join()
        # The following is a manipulation of the data resulting from the calculation
        # The goal is to output the results in an identical format as those from qutip.mcsolve()
        if len(ntraj) > 1:
            for i in range(ntraj[_n]):
                collapse_times_out[_n].append(results[i][1])
                which_op_out[_n].append(results[i][2])
                for j in range(num_eops):
                    if eops_herm[j]: exp_vals[_n][j] += results[i][0][j].real
                    else: exp_vals[_n][j] += results[i][0][j]
            for i in range(num_eops):
                exp_vals[_n][i] = exp_vals[_n][i] / ntraj[_n]
        else:
            for i in range(ntraj[_n]):
                collapse_times_out.append(results[i][1])
                which_op_out.append(results[i][2])
                for j in range(num_eops):
                    if eops_herm[j]: exp_vals[j] += results[i][0][j].real
                    else: exp_vals[j] += results[i][0][j]
            for i in range(num_eops):
                exp_vals[i] = exp_vals[i] / ntraj[_n]
    output = Odedata()
    output.solver = 'mi_mcsolve'
    output.expect = exp_vals
    output.times = tlist
    output.num_expect = num_eops
    output.num_collapse = num_cops
    output.ntraj = ntraj
    output.col_times = collapse_times_out
    output.col_which = which_op_out
    return output
Example #33
0
def bloch_redfield_solve(R, ekets, rho0, tlist, e_ops=[], options=None):
    """
    Evolve the ODEs defined by Bloch-Redfield master equation. The
    Bloch-Redfield tensor can be calculated by the function
    :func:`bloch_redfield_tensor`.

    Parameters
    ----------

    R : :class:`qutip.qobj`
        Bloch-Redfield tensor.

    ekets : array of :class:`qutip.qobj`
        Array of kets that make up a basis tranformation for the eigenbasis.

    rho0 : :class:`qutip.qobj`
        Initial density matrix.

    tlist : *list* / *array*
        List of times for :math:`t`.

    e_ops : list of :class:`qutip.qobj` / callback function
        List of operators for which to evaluate expectation values.

    options : :class:`qutip.Qdeoptions`
        Options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.odedata`

        An instance of the class :class:`qutip.odedata`, which contains either
        an *array* of expectation values for the times specified by `tlist`.

    """

    if options is None:
        options = Odeoptions()

    if options.tidy:
        R.tidyup()

    #
    # check initial state
    #
    if isket(rho0):
        # Got a wave function as initial state: convert to density matrix.
        rho0 = rho0 * rho0.dag()

    #
    # prepare output array
    #
    n_tsteps = len(tlist)
    dt = tlist[1] - tlist[0]
    result_list = []

    #
    # transform the initial density matrix and the e_ops opterators to the
    # eigenbasis
    #
    rho_eb = rho0.transform(ekets)
    e_eb_ops = [e.transform(ekets) for e in e_ops]

    for e_eb in e_eb_ops:
        result_list.append(np.zeros(n_tsteps, dtype=complex))

    #
    # setup integrator
    #
    initial_vector = mat2vec(rho_eb.full())
    r = scipy.integrate.ode(cy_ode_rhs)
    r.set_f_params(R.data.data, R.data.indices, R.data.indptr)
    r.set_integrator('zvode',
                     method=options.method,
                     order=options.order,
                     atol=options.atol,
                     rtol=options.rtol,
                     nsteps=options.nsteps,
                     first_step=options.first_step,
                     min_step=options.min_step,
                     max_step=options.max_step)
    r.set_initial_value(initial_vector, tlist[0])

    #
    # start evolution
    #
    dt = np.diff(tlist)
    for t_idx, _ in enumerate(tlist):

        if not r.successful():
            break

        rho_eb.data = vec2mat(r.y)

        # calculate all the expectation values, or output rho_eb if no
        # expectation value operators are given
        if e_ops:
            rho_eb_tmp = Qobj(rho_eb)
            for m, e in enumerate(e_eb_ops):
                result_list[m][t_idx] = expect(e, rho_eb_tmp)
        else:
            result_list.append(rho_eb.transform(ekets, True))

        if t_idx < n_tsteps - 1:
            r.integrate(r.t + dt[t_idx])

    return result_list