Esempio n. 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 = Options()
    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
Esempio n. 2
0
def propagator(H, t, c_op_list=[], args={}, options=None,
               parallel=False, progress_bar=None, **kwargs):
    """
    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.Options`
        with options for the ODE solver.

    parallel : bool {False, True}
        Run the propagator in parallel mode.
    
    progress_bar: BaseProgressBar
        Optional instance of BaseProgressBar, or a subclass thereof, for
        showing the progress of the simulation. By default no progress bar
        is used, and if set to True a TextProgressBar will be used.

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

    """
    
    kw = _default_kwargs()
    if 'num_cpus' in kwargs:
        num_cpus = kwargs['num_cpus']
    else:
        num_cpus = kw['num_cpus']
    
    if progress_bar is None:
        progress_bar = BaseProgressBar()
    elif progress_bar is True:
        progress_bar = TextProgressBar()

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

    if isinstance(t, (int, float, np.integer, np.floating)):
        tlist = [0, t]
    else:
        tlist = t

    td_type = _td_format_check(H, c_op_list, solver='me')[2]
    if td_type > 0:
        rhs_generate(H, c_op_list, args=args, options=options)
        
    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)
        
        if parallel:
            output = parallel_map(_parallel_sesolve,range(N),
                    task_args=(N,H,tlist,args,options),
                    progress_bar=progress_bar, num_cpus=num_cpus)
            for n in range(N):
                for k, t in enumerate(tlist):
                    u[:, n, k] = output[n].states[k].full().T 
        else:
            progress_bar.start(N)
            for n in range(0, N):
                progress_bar.update(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
            progress_bar.finished()

        # 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]
        sqrt_N = int(np.sqrt(N))
        dims = H0.dims
        
        u = np.zeros([N, N, len(tlist)], dtype=complex)

        if parallel:
            output = parallel_map(_parallel_mesolve,range(N * N),
                    task_args=(sqrt_N,H,tlist,c_op_list,args,options),
                    progress_bar=progress_bar, num_cpus=num_cpus)
            for n in range(N * N):
                for k, t in enumerate(tlist):
                    u[:, n, k] = mat2vec(output[n].states[k].full()).T
        else:
            progress_bar.start(N)
            for n in range(0, N):
                progress_bar.update(n)
                col_idx, row_idx = np.unravel_index(n,(sqrt_N,sqrt_N))
                rho0 = Qobj(sp.csr_matrix(([1],([row_idx],[col_idx])), shape=(sqrt_N,sqrt_N), dtype=complex))
                output = mesolve(H, rho0, tlist, [], [], args, options)
                for k, t in enumerate(tlist):
                    u[:, n, k] = mat2vec(output.states[k].full()).T
            progress_bar.finished()

    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 parallel:
            output = parallel_map(_parallel_mesolve,range(N * N),
                    task_args=(N,H,tlist,c_op_list,args,options),
                    progress_bar=progress_bar, num_cpus=num_cpus)
            for n in range(N * N):
                for k, t in enumerate(tlist):
                    u[:, n, k] = mat2vec(output[n].states[k].full()).T
        else:
            progress_bar.start(N * N)
            for n in range(N * N):
                progress_bar.update(n)
                col_idx, row_idx = np.unravel_index(n,(N,N))
                rho0 = Qobj(sp.csr_matrix(([1],([row_idx],[col_idx])), shape=(N,N), dtype=complex))
                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
            progress_bar.finished()

    if len(tlist) == 2:
        return Qobj(u[:, :, 1], dims=dims)
    else:
        return np.array([Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))], dtype=object)
Esempio n. 3
0
def mcsolve(H,
            psi0,
            tlist,
            c_ops=[],
            e_ops=[],
            ntraj=0,
            args={},
            options=None,
            progress_bar=True,
            map_func=parallel_map,
            map_kwargs={},
            _safe_mode=True):
    r"""Monte Carlo evolution of a state vector :math:`|\psi \rangle` for a
    given Hamiltonian and sets of collapse operators, and possibly, operators
    for calculating expectation values. Options for the underlying ODE solver
    are given by the Options class.

    mcsolve supports time-dependent Hamiltonians and collapse operators using
    either Python functions of strings to represent time-dependent
    coefficients. Note that, the system Hamiltonian MUST have at least one
    constant term.

    As an example of a time-dependent problem, consider a Hamiltonian with two
    terms ``H0`` and ``H1``, where ``H1`` is time-dependent with coefficient
    ``sin(w*t)``, and collapse operators ``C0`` and ``C1``, where ``C1`` is
    time-dependent with coeffcient ``exp(-a*t)``.  Here, w and a are constant
    arguments with values ``W`` and ``A``.

    Using the Python function time-dependent format requires two Python
    functions, one for each collapse coefficient. Therefore, this problem could
    be expressed as::

        def H1_coeff(t,args):
            return sin(args['w']*t)

        def C1_coeff(t,args):
            return exp(-args['a']*t)

        H = [H0, [H1, H1_coeff]]

        c_ops = [C0, [C1, C1_coeff]]

        args={'a': A, 'w': W}

    or in String (Cython) format we could write::

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

        c_ops = [C0, [C1, 'exp(-a*t)']]

        args={'a': A, 'w': W}

    Constant terms are preferably placed first in the Hamiltonian and collapse
    operator lists.

    Parameters
    ----------
    H : :class:`qutip.Qobj`, ``list``
        System Hamiltonian.

    psi0 : :class:`qutip.Qobj`
        Initial state vector

    tlist : array_like
        Times at which results are recorded.

    ntraj : int
        Number of trajectories to run.

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

    e_ops : :class:`qutip.Qobj`, ``list``
        single operator as Qobj or ``list`` or equivalent of Qobj operators
        for calculating expectation values.

    args : dict
        Arguments for time-dependent Hamiltonian and collapse operator terms.

    options : Options
        Instance of ODE solver options.

    progress_bar: BaseProgressBar
        Optional instance of BaseProgressBar, or a subclass thereof, for
        showing the progress of the simulation. Set to None to disable the
        progress bar.

    map_func: function
        A map function for managing the calls to the single-trajactory solver.

    map_kwargs: dictionary
        Optional keyword arguments to the map_func function.

    Returns
    -------
    results : :class:`qutip.solver.Result`
        Object storing all results from the simulation.

    .. note::

        It is possible to reuse the random number seeds from a previous run
        of the mcsolver by passing the output Result object seeds via the
        Options class, i.e. Options(seeds=prev_result.seeds).
    """
    if isinstance(c_ops, (Qobj, QobjEvo)):
        c_ops = [c_ops]

    if options is None:
        options = Options()

    if options.rhs_reuse and not isinstance(H, SolverSystem):
        # TODO: deprecate when going to class based solver.
        if "mcsolve" in solver_safe:
            # print(" ")
            H = solver_safe["mcsolve"]
        else:
            pass
            # raise Exception("Could not find the Hamiltonian to reuse.")

    if not ntraj:
        ntraj = options.ntraj

    if len(c_ops) == 0 and not options.rhs_reuse:
        warn("No c_ops, using sesolve")
        return sesolve(H,
                       psi0,
                       tlist,
                       e_ops=e_ops,
                       args=args,
                       options=options,
                       progress_bar=progress_bar,
                       _safe_mode=_safe_mode)

    try:
        num_traj = int(ntraj)
    except TypeError:
        num_traj = max(ntraj)

    # set the physics
    if not psi0.isket:
        raise Exception("Initial state must be a state vector.")

    # load monte carlo class
    mc = _MC(options)

    if isinstance(H, SolverSystem):
        mc.ss = H
    else:
        mc.make_system(H, c_ops, tlist, args, options)

    mc.reset(tlist[0], psi0)

    mc.set_e_ops(e_ops)

    if options.seeds is not None:
        mc.seed(num_traj, options.seeds)

    if _safe_mode:
        mc.run_test()

    # Run the simulation
    mc.run(num_traj=num_traj,
           tlist=tlist,
           progress_bar=progress_bar,
           map_func=map_func,
           map_kwargs=map_kwargs)

    return mc.get_result(ntraj)
Esempio n. 4
0
            if k != j:

                g = np.sqrt(-1j * g_eff(R, a, j, k))
                L.append(upD(k, N, g) * downD(k, N, g))
                scatterindex.append(j)
                #print("L",len(L)-1,": Scattering at j=",j,"due to impurity site k=",k,"at distance=",a*np.abs(k-j),"with g_eff:","%6.5f" % g_eff(R,a,j,k))
    return L


N = 3
a = 1
timesteps = 100
ntraj = 200
statelist = []
opts = Options(store_states=True, store_final_state=True, ntraj=200)

tracedEEav = np.zeros(timesteps)
tracedGGav = np.zeros(timesteps)
purityAav = np.zeros(timesteps)
purityBav = np.zeros(timesteps)
purityCav = np.zeros(timesteps)
concav = np.zeros(timesteps)
VNav = np.zeros(timesteps)
disavgs = 1
i = 1

for r in [4.0]:
    for t in np.ones(disavgs):
        print(i, "of", disavgs)
        i = i + 1
Esempio n. 5
0
def correlation(H,
                state0,
                tlist,
                taulist,
                c_ops,
                a_op,
                b_op,
                solver="me",
                reverse=False,
                args=None,
                options=Options(ntraj=[20, 100])):
    """
    Calculate the two-operator two-time correlation function:
    :math:`\left<A(t+\\tau)B(t)\\right>`
    along two time axes using the quantum regression theorem and the
    evolution solver indicated by the `solver` parameter.

    Parameters
    ----------

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

    state0 : :class:`qutip.qobj.Qobj`
        Initial state density matrix :math:`\\rho(t_0)` or state vector
        :math:`\\psi(t_0)`. If 'state0' is 'None', then the steady state will
        be used as the initial state. The 'steady-state' is only implemented
        for the `me` and `es` solvers.

    tlist : *list* / *array*
        list of times for :math:`t`. tlist must be positive and contain the
        element `0`. When taking steady-steady correlations only one tlist
        value is necessary, i.e. :math:`t \rightarrow \infty`; here tlist is
        automatically set, ignoring user input.

    taulist : *list* / *array*
        list of times for :math:`\\tau`. taulist must be positive and contain
        the element `0`.

    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(t)B(t+\\tau)\\right>` instead of
        :math:`\left<A(t+\\tau)B(t)\\right>`.

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

    options : :class:`qutip.solver.Options`
        solver options class. `ntraj` is taken as a two-element list because
        the `mc` correlator calls `mcsolve()` recursively; by default,
        `ntraj=[20, 100]`. `mc_corr_eps` prevents divide-by-zero errors in
        the `mc` correlator; by default, `mc_corr_eps=1e-10`.

    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.

    """

    warn("correlation() now legacy, please use correlation_2op_2t()",
         FutureWarning)

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

    return correlation_2op_2t(H,
                              state0,
                              tlist,
                              taulist,
                              c_ops,
                              a_op,
                              b_op,
                              solver=solver,
                              reverse=reverse,
                              args=args,
                              options=options)
Esempio n. 6
0
def correlation_2op_1t(H,
                       state0,
                       taulist,
                       c_ops,
                       a_op,
                       b_op,
                       solver="me",
                       reverse=False,
                       args=None,
                       options=Options(ntraj=[20, 100])):
    """
    Calculate the two-operator two-time correlation function:
    :math: `\left<A(t+\\tau)B(t)\\right>`
    along one time axis using the quantum regression theorem and the evolution
    solver indicated by the `solver` parameter.

    Parameters
    ----------

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

    state0 : :class:`qutip.qobj.Qobj`
        Initial state density matrix :math:`\\rho(t_0)` or state vector
        :math:`\\psi(t_0)`. If 'state0' is 'None', then the steady state will
        be used as the initial state. The 'steady-state' is only implemented
        for the `me` and `es` solvers.

    taulist : *list* / *array*
        list of times for :math:`\\tau`. taulist must be positive and contain
        the element `0`.

    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(t)B(t+\\tau)\\right>` instead of
        :math:`\left<A(t+\\tau)B(t)\\right>`.

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

    options : :class:`qutip.solver.Options`
        solver options class. `ntraj` is taken as a two-element list because
        the `mc` correlator calls `mcsolve()` recursively; by default,
        `ntraj=[20, 100]`. `mc_corr_eps` prevents divide-by-zero errors in
        the `mc` correlator; by default, `mc_corr_eps=1e-10`.

    Returns
    -------

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

    References
    ----------

    See, Gardiner, Quantum Noise, Section 5.2.

    """

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

    if reverse:
        A_op = a_op
        B_op = b_op
        C_op = 1
    else:
        A_op = 1
        B_op = a_op
        C_op = b_op

    return _correlation_2t(H,
                           state0, [0],
                           taulist,
                           c_ops,
                           A_op,
                           B_op,
                           C_op,
                           solver=solver,
                           args=args,
                           options=options)[0]
Esempio n. 7
0
def _correlation_mc_2t(H,
                       state0,
                       tlist,
                       taulist,
                       c_ops,
                       a_op,
                       b_op,
                       c_op,
                       args=None,
                       options=Options()):
    """
    Internal function for calculating the three-operator two-time
    correlation function:
    <A(t)B(t+tau)C(t)>
    using a Monte Carlo solver.
    """

    # the solvers only work for positive time differences and the correlators
    # require positive tau
    if state0 is None:
        raise NotImplementedError("steady state not implemented for " +
                                  "mc solver, please use `es` or `me`")
    elif not isket(state0):
        raise TypeError("state0 must be a state vector.")
    psi0 = state0

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

    psi_t_mat = mcsolve(H,
                        psi0,
                        tlist,
                        c_ops, [],
                        args=args,
                        ntraj=options.ntraj[0],
                        options=options,
                        progress_bar=None).states

    corr_mat = np.zeros([np.size(tlist), np.size(taulist)], dtype=complex)
    H_shifted, _args = _transform_H_t_shift(H, args)

    # calculation of <A(t)B(t+tau)C(t)> from only knowledge of psi0 requires
    # averaging over both t and tau
    for t_idx in range(np.size(tlist)):
        if not isinstance(H, Qobj):
            _args["_t0"] = tlist[t_idx]

        for trial_idx in range(options.ntraj[0]):
            if isinstance(a_op, Qobj) and isinstance(c_op, Qobj):
                if a_op.dag() == c_op:
                    # A shortcut here, requires only 1/4 the trials
                    chi_0 = (options.mc_corr_eps + c_op) * \
                            psi_t_mat[trial_idx, t_idx]

                    # evolve these states and calculate expectation value of B
                    c_tau = chi_0.norm()**2 * mcsolve(
                        H_shifted,
                        chi_0 / chi_0.norm(),
                        taulist,
                        c_ops, [b_op],
                        args=_args,
                        ntraj=options.ntraj[1],
                        options=options,
                        progress_bar=None).expect[0]

                    # final correlation vector computed by combining the
                    # averages
                    corr_mat[t_idx, :] += c_tau / options.ntraj[1]
            else:
                # otherwise, need four trial wavefunctions
                # (Ad+C)*psi_t, (Ad+iC)*psi_t, (Ad-C)*psi_t, (Ad-iC)*psi_t
                if isinstance(a_op, Qobj):
                    a_op_dag = a_op.dag()
                else:
                    # assume this is a number, ex. i.e. a_op = 1
                    # if this is not correct, the over-loaded addition
                    # operation will raise errors
                    a_op_dag = a_op
                chi_0 = [
                    (options.mc_corr_eps + a_op_dag +
                     exp(1j * x * pi / 2) * c_op) * psi_t_mat[trial_idx, t_idx]
                    for x in range(4)
                ]

                # evolve these states and calculate expectation value of B
                c_tau = [
                    chi.norm()**2 * mcsolve(H_shifted,
                                            chi / chi.norm(),
                                            taulist,
                                            c_ops, [b_op],
                                            args=_args,
                                            ntraj=options.ntraj[1],
                                            options=options,
                                            progress_bar=None).expect[0]
                    for chi in chi_0
                ]

                # final correlation vector computed by combining the averages
                corr_mat[t_idx, :] += \
                    1/(4*options.ntraj[0]) * (c_tau[0] - c_tau[2] -
                                              1j*c_tau[1] + 1j*c_tau[3])
        if t_idx == 1:
            options.rhs_reuse = True

    return corr_mat
Esempio n. 8
0
def correlation(H,
                rho0,
                tlist,
                taulist,
                c_ops,
                a_op,
                b_op,
                solver="me",
                reverse=False,
                args=None,
                options=Options()):
    """
    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)
Esempio n. 9
0
def correlation_4op_2t(H, state0, tlist, taulist, c_ops,
                       a_op, b_op, c_op, d_op, solver="me", args={},
                       options=Options(ntraj=[20, 100])):
    """
    Calculate the four-operator two-time correlation function:
    :math:`\left<A(t)B(t+\\tau)C(t+\\tau)D(t)\\right>`
    along two time axes using the quantum regression theorem and the
    evolution solver indicated by the `solver` parameter.

    Note: it is not possibly to calculate a physically meaningful correlation
    of this form where :math:`\\tau<0`.

    Parameters
    ----------

    H : Qobj
        system Hamiltonian, may be time-dependent for solver choice of `me` or
        `mc`.

    rho0 : Qobj
        Initial state density matrix :math:`\\rho_0` or state vector
        :math:`\\psi_0`. If 'state0' is 'None', then the steady state will
        be used as the initial state. The 'steady-state' is only implemented
        for the `me` and `es` solvers.

    tlist : array_like
        list of times for :math:`t`. tlist must be positive and contain the
        element `0`. When taking steady-steady correlations only one tlist
        value is necessary, i.e. when :math:`t \\rightarrow \\infty`; here
        tlist is automatically set, ignoring user input.

    taulist : array_like
        list of times for :math:`\\tau`. taulist must be positive and contain
        the element `0`.

    c_ops : list
        list of collapse operators, may be time-dependent for solver choice of
        `me` or `mc`.

    a_op : Qobj
        operator A.

    b_op : Qobj
        operator B.

    c_op : Qobj
        operator C.

    d_op : Qobj
        operator D.

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

    options : Options
        solver options class. `ntraj` is taken as a two-element list because
        the `mc` correlator calls `mcsolve()` recursively; by default,
        `ntraj=[20, 100]`. `mc_corr_eps` prevents divide-by-zero errors in
        the `mc` correlator; by default, `mc_corr_eps=1e-10`.

    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.

    """

    warn("correlation_4op_2t() now legacy, please use correlation_3op_2t()",
         FutureWarning)
    warn("the reverse argument has been removed as it did not contain any" +
         "new physical information", DeprecationWarning)

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

    return correlation_3op_2t(H, state0, tlist, taulist, c_ops,
                              a_op, b_op * c_op, d_op,
                              solver=solver, args=args, options=options)
Esempio n. 10
0
def coherence_function_g2(H, state0, taulist, c_ops, a_op, solver="me", args={},
                          options=Options(ntraj=[20, 100])):
    """
    Calculate the normalized 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}

    using the quantum regression theorem and the evolution solver indicated by
    the `solver` parameter.

    Parameters
    ----------
    H : Qobj
        system Hamiltonian, may be time-dependent for solver choice of `me` or
        `mc`.
    state0 : Qobj
        Initial state density matrix :math:`\\rho(t_0)` or state vector
        :math:`\\psi(t_0)`. If 'state0' is 'None', then the steady state will
        be used as the initial state. The 'steady-state' is only implemented
        for the `me` and `es` solvers.
    taulist : array_like
        list of times for :math:`\\tau`. taulist must be positive and contain
        the element `0`.
    c_ops : list
        list of collapse operators, may be time-dependent for solver choice of
        `me` or `mc`.
    a_op : Qobj
        operator A.
    solver : str
        choice of solver (`me` for master-equation and
        `es` for exponential series).
    options : Options
        solver options class. `ntraj` is taken as a two-element list because
        the `mc` correlator calls `mcsolve()` recursively; by default,
        `ntraj=[20, 100]`. `mc_corr_eps` prevents divide-by-zero errors in
        the `mc` correlator; by default, `mc_corr_eps=1e-10`.

    Returns
    -------
    g2, G2 : tuple
        The normalized and unnormalized second-order coherence function.

    """

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

    # calculate the correlation function G2 and normalize with n to obtain g2
    G2 = correlation_3op_1t(H, state0, 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
Esempio n. 11
0
def correlation_2op_2t(H, state0, tlist, taulist, c_ops, a_op, b_op,
                       solver="me", reverse=False, args={},
                       options=Options(ntraj=[20, 100])):
    """
    Calculate the two-operator two-time correlation function:
    :math:`\left<A(t+\\tau)B(t)\\right>`
    along two time axes using the quantum regression theorem and the
    evolution solver indicated by the `solver` parameter.

    Parameters
    ----------
    H : Qobj
        system Hamiltonian, may be time-dependent for solver choice of `me` or
        `mc`.
    state0 : Qobj
        Initial state density matrix :math:`\\rho_0` or state vector
        :math:`\\psi_0`. If 'state0' is 'None', then the steady state will
        be used as the initial state. The 'steady-state' is only implemented
        for the `me` and `es` solvers.
    tlist : array_like
        list of times for :math:`t`. tlist must be positive and contain the
        element `0`. When taking steady-steady correlations only one tlist
        value is necessary, i.e. when :math:`t \\rightarrow \\infty`; here
        tlist is automatically set, ignoring user input.
    taulist : array_like
        list of times for :math:`\\tau`. taulist must be positive and contain
        the element `0`.
    c_ops : list
        list of collapse operators, may be time-dependent for solver choice of
        `me` or `mc`.
    a_op : Qobj
        operator A.
    b_op : Qobj
        operator B.
    reverse : bool {False, True}
        If `True`, calculate :math:`\left<A(t)B(t+\\tau)\\right>` instead of
        :math:`\left<A(t+\\tau)B(t)\\right>`.
    solver : str
        choice of solver (`me` for master-equation, `mc` for Monte Carlo, and
        `es` for exponential series).
    options : Options
        solver options class. `ntraj` is taken as a two-element list because
        the `mc` correlator calls `mcsolve()` recursively; by default,
        `ntraj=[20, 100]`. `mc_corr_eps` prevents divide-by-zero errors in
        the `mc` correlator; by default, `mc_corr_eps=1e-10`.

    Returns
    -------
    corr_mat : ndarray
        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.

    """

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

    if tlist is None:
        return correlation_2op_1t(H, state0, taulist, c_ops, a_op, b_op,
                                  solver=solver, reverse=reverse, args=args,
                                  options=options)
    else:
        if reverse:
            A_op = a_op
            B_op = b_op
            C_op = 1
        else:
            A_op = 1
            B_op = a_op
            C_op = b_op

        return _correlation_2t(H, state0, tlist, taulist,
                               c_ops, A_op, B_op, C_op,
                               solver=solver, args=args, options=options)
Esempio n. 12
0
def sesolve(H, psi0, tlist, e_ops=None, args=None, options=None,
            progress_bar=None, _safe_mode=True):
    """
    Schrödinger equation evolution of a state vector or unitary matrix for a
    given Hamiltonian.

    Evolve the state vector (``psi0``) using a given Hamiltonian (``H``), by
    integrating the set of ordinary differential equations that define the
    system. Alternatively evolve a unitary matrix in solving the Schrodinger
    operator equation.

    The output is either the state vector or unitary matrix 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. ``e_ops`` cannot be used in conjunction
    with solving the Schrodinger operator equation

    Parameters
    ----------

    H : :class:`~Qobj`, :class:`~QobjEvo`, list, or callable
        System Hamiltonian as a :obj:`~Qobj , list of :obj:`Qobj` and
        coefficient, :obj:`~QObjEvo`, or a callback function for time-dependent
        Hamiltonians.  List format and options can be found in QobjEvo's
        description.

    psi0 : :class:`~Qobj`
        Initial state vector (ket) or initial unitary operator ``psi0 = U``.

    tlist : array_like of float
        List of times for :math:`t`.

    e_ops : list of :class:`~Qobj` or callback function, optional
        Single operator or list of operators for which to evaluate expectation
        values.  For operator evolution, the overlap is computed: ::

            (e_ops[i].dag() * op(t)).tr()

    args : dict, optional
        Dictionary of scope parameters for time-dependent Hamiltonians.

    options : :obj:`~solver.Options`, optional
        Options for the ODE solver.

    progress_bar : :obj:`~BaseProgressBar`, optional
        Optional instance of :obj:`~BaseProgressBar`, or a subclass thereof,
        for showing the progress of the simulation.

    Returns
    -------

    output: :class:`~solver.Result`
        An instance of the class :class:`~solver.Result`, which contains either
        an array of expectation values for the times specified by ``tlist``, or
        an array or state vectors 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 e_ops is None:
        e_ops = []
    if isinstance(e_ops, Qobj):
        e_ops = [e_ops]
    elif isinstance(e_ops, dict):
        e_ops_dict = e_ops
        e_ops = [e for e in e_ops.values()]
    else:
        e_ops_dict = None

    if progress_bar is None:
        progress_bar = BaseProgressBar()
    if progress_bar is True:
        progress_bar = TextProgressBar()

    if not (psi0.isket or psi0.isunitary):
        raise TypeError("The unitary solver requires psi0 to be"
                        " a ket as initial state"
                        " or a unitary as initial operator.")

    if options is None:
        options = Options()
    if options.rhs_reuse and not isinstance(H, SolverSystem):
        # TODO: deprecate when going to class based solver.
        if "sesolve" in solver_safe:
            H = solver_safe["sesolve"]

    if args is None:
        args = {}

    check_use_openmp(options)

    if isinstance(H, SolverSystem):
        ss = H
    elif isinstance(H, (list, Qobj, QobjEvo)):
        ss = _sesolve_QobjEvo(H, tlist, args, options)
    elif callable(H):
        ss = _sesolve_func_td(H, args, options)
    else:
        raise Exception("Invalid H type")

    func, ode_args = ss.makefunc(ss, psi0, args, e_ops, options)

    if _safe_mode:
        v = psi0.full().ravel('F')
        func(0., v, *ode_args) + v

    res = _generic_ode_solve(func, ode_args, psi0, tlist, e_ops, options,
                             progress_bar, dims=psi0.dims)
    if e_ops_dict:
        res.expect = {e: res.expect[n]
                      for n, e in enumerate(e_ops_dict.keys())}
    res.SolverSystem = ss
    return res
Esempio n. 13
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 = Options()
    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 = Result()
    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)

    #
    # 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 = Qobj(vec2mat(r.y), rho0.dims, rho0.shape)

        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, True))
        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, True))
            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
Esempio n. 14
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.Options`
        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 = Options()

    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
Esempio n. 15
0
def floquet_modes_table(f_modes_0,
                        f_energies,
                        tlist,
                        H,
                        T,
                        args=None,
                        options=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

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

    Returns
    -------

    output : nested list

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

    """
    options = copy(options) or Options()
    # truncate tlist to the driving period
    tlist_period = tlist[np.where(tlist <= T)]

    f_modes_table_t = [[] for t in tlist_period]

    opt = options
    opt.rhs_reuse = True
    rhs_clear()

    for n, f_mode in enumerate(f_modes_0):
        output = sesolve(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
Esempio n. 16
0
def sesolve(H,
            rho0,
            tlist,
            e_ops=[],
            args={},
            options=None,
            progress_bar=None,
            _safe_mode=True):
    """
    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.
            
    progress_bar : BaseProgressBar
        Optional instance of BaseProgressBar, or a subclass thereof, for
        showing the progress of the simulation.

    Returns
    -------

    output: :class:`qutip.solver`

        An instance of the class :class:`qutip.solver`, 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

    if _safe_mode:
        _solver_safety_check(H, rho0, c_ops=[], e_ops=e_ops, args=args)

    if progress_bar is None:
        progress_bar = BaseProgressBar()
    elif progress_bar is True:
        progress_bar = TextProgressBar()

    # convert array based time-dependence to string format
    H, _, args = _td_wrap_array_str(H, [], args, tlist)
    # check for type (if any) of time-dependent inputs
    n_const, n_func, n_str = _td_format_check(H, [])

    if options is None:
        options = Options()

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

    #check if should use OPENMP
    check_use_openmp(options)

    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
Esempio n. 17
0
def fsesolve(H,
             psi0,
             tlist,
             e_ops=[],
             T=None,
             args={},
             Tsteps=100,
             options_modes=None):
    """
    Solve the Schrodinger equation using the Floquet formalism.

    Parameters
    ----------

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

    psi0 : :class:`qutip.qobj`
        Initial state vector (ket).

    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. If this
        list is empty, the state vectors for each time in `tlist` will be
        returned instead of expectation values.

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

    args : dictionary
        Dictionary with variables required to evaluate H.

    Tsteps : integer
        The number of time steps in one driving period for which to
        precalculate the Floquet modes. `Tsteps` should be an even number.

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

    Returns
    -------

    output : :class:`qutip.solver.Result`

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

    if not T:
        # assume that tlist span exactly one period of the driving
        T = tlist[-1]

    if options_modes is None:
        options_modes_table = Options()
    else:
        options_modes_table = options_modes

    # find the floquet modes for the time-dependent hamiltonian
    f_modes_0, f_energies = floquet_modes(H, T, args, options=options_modes)

    # calculate the wavefunctions using the from the floquet modes
    f_modes_table_t = floquet_modes_table(f_modes_0,
                                          f_energies,
                                          np.linspace(0, T, Tsteps + 1),
                                          H,
                                          T,
                                          args,
                                          options=options_modes_table)

    # setup Result for storing the results
    output = Result()
    output.times = tlist
    output.solver = "fsesolve"

    if isinstance(e_ops, FunctionType):
        output.num_expect = 0
        expt_callback = True

    elif isinstance(e_ops, list):

        output.num_expect = len(e_ops)
        expt_callback = False

        if output.num_expect == 0:
            output.states = []
        else:
            output.expect = []
            for op in e_ops:
                if op.isherm:
                    output.expect.append(np.zeros(len(tlist)))
                else:
                    output.expect.append(np.zeros(len(tlist), dtype=complex))

    else:
        raise TypeError("e_ops must be a list Qobj or a callback function")

    psi0_fb = psi0.transform(f_modes_0)
    for t_idx, t in enumerate(tlist):
        f_modes_t = floquet_modes_t_lookup(f_modes_table_t, t, T)
        f_states_t = floquet_states(f_modes_t, f_energies, t)
        psi_t = psi0_fb.transform(f_states_t, True)

        if expt_callback:
            # use callback method
            e_ops(t, psi_t)
        else:
            # calculate all the expectation values, or output psi if
            # no expectation value operators where defined
            if output.num_expect == 0:
                output.states.append(Qobj(psi_t))
            else:
                for e_idx, e in enumerate(e_ops):
                    output.expect[e_idx][t_idx] = expect(e, psi_t)

    return output
Esempio n. 18
0
def mesolve(H,
            rho0,
            tlist,
            c_ops=None,
            e_ops=None,
            args=None,
            options=None,
            progress_bar=None,
            _safe_mode=True):
    """
    Master equation evolution of a density matrix for a given Hamiltonian and
    set of collapse operators, or a Liouvillian.

    Evolve the state vector or density matrix (`rho0`) using a given
    Hamiltonian or Liouvillian (`H`) and an optional set of collapse operators
    (`c_ops`), by integrating the set of ordinary differential equations
    that define the system. In the absence of collapse 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.

    If either `H` or the Qobj elements in `c_ops` are superoperators, they
    will be treated as direct contributions to the total system Liouvillian.
    This allows the solution of master equations that are not in standard
    Lindblad form.

    **Time-dependent operators**

    For time-dependent problems, `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*), a callback
    function (*list callback format*) that evaluates to the time-dependent
    coefficient for the corresponding operator, or a NumPy array (*list
    array format*) which specifies the value of the coefficient to the
    corresponding operator for each value of t in `tlist`.

    Alternatively, `H` (but not `c_ops`) can be a callback function with the
    signature `f(t, args) -> Qobj` (*callback format*), which can return the
    Hamiltonian or Liouvillian superoperator at any point in time.  If the
    equation cannot be put in standard Lindblad form, then this time-dependence
    format must be used.

    *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).

        H = [[H0, np.sin(w*tlist)], [H1, np.sin(2*w*tlist)]]

    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 their second argument.

    **Additional options**

    Additional options to mesolve can be set via the `options` argument, which
    should be an instance of :class:`qutip.solver.Options`. Many ODE
    integration options can be set this way, and the `store_states` and
    `store_final_state` options can be used to store states even though
    expectation values are requested via the `e_ops` argument.

    .. note::

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

    .. note::

        On using callback functions: 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`. mesolve 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 in scipy which will raise a NotImplemented
        exception.

    Parameters
    ----------

    H : :class:`qutip.Qobj`
        System Hamiltonian, or a callback function for time-dependent
        Hamiltonians, or alternatively a system Liouvillian.

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

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

    c_ops : None / list of :class:`qutip.Qobj`
        single collapse operator, or list of collapse operators, or a list
        of Liouvillian superoperators.

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

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

    options : None / :class:`qutip.Options`
        with options for the solver.

    progress_bar : None / BaseProgressBar
        Optional instance of BaseProgressBar, or a subclass thereof, for
        showing the progress of the simulation.

    Returns
    -------
    result: :class:`qutip.Result`

        An instance of the class :class:`qutip.Result`, which contains
        either an *array* `result.expect` of expectation values for the times
        specified by `tlist`, or an *array* `result.states` of 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 in place of
        operators for which to calculate the expectation values.

    """
    if c_ops is None:
        c_ops = []
    if isinstance(c_ops, (Qobj, QobjEvo)):
        c_ops = [c_ops]

    if e_ops is None:
        e_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

    if progress_bar is None:
        progress_bar = BaseProgressBar()
    if progress_bar is True:
        progress_bar = TextProgressBar()

    # check if rho0 is a superoperator, in which case e_ops argument should
    # be empty, i.e., e_ops = []
    # TODO: e_ops for superoperator
    if issuper(rho0) and not e_ops == []:
        raise TypeError("Must have e_ops = [] when initial condition rho0 is" +
                        " a superoperator.")

    if options is None:
        options = Options()
    if options.rhs_reuse and not isinstance(H, SolverSystem):
        # TODO: deprecate when going to class based solver.
        if "mesolve" in solver_safe:
            # print(" ")
            H = solver_safe["mesolve"]
        else:
            pass
            # raise Exception("Could not find the Hamiltonian to reuse.")

    if args is None:
        args = {}

    check_use_openmp(options)

    use_mesolve = ((c_ops and len(c_ops) > 0) or (not isket(rho0))
                   or (isinstance(H, Qobj) and issuper(H))
                   or (isinstance(H, QobjEvo) and issuper(H.cte))
                   or (isinstance(H, list) and isinstance(H[0], Qobj)
                       and issuper(H[0]))
                   or (not isinstance(H, (Qobj, QobjEvo)) and callable(H)
                       and not options.rhs_with_state and issuper(H(0., args)))
                   or (not isinstance(H, (Qobj, QobjEvo)) and callable(H)
                       and options.rhs_with_state))

    if not use_mesolve:
        return sesolve(H,
                       rho0,
                       tlist,
                       e_ops=e_ops,
                       args=args,
                       options=options,
                       progress_bar=progress_bar,
                       _safe_mode=_safe_mode)

    if isket(rho0):
        rho0 = ket2dm(rho0)
    if (not (rho0.isoper or rho0.issuper)) or (rho0.dims[0] != rho0.dims[1]):
        raise ValueError(
            "input state must be a pure state vector, square density matrix, "
            "or superoperator")

    if isinstance(H, SolverSystem):
        ss = H
    elif isinstance(H, (list, Qobj, QobjEvo)):
        ss = _mesolve_QobjEvo(H, c_ops, tlist, args, options)
    elif callable(H):
        ss = _mesolve_func_td(H, c_ops, rho0, tlist, args, options)
    else:
        raise Exception("Invalid H type")

    func, ode_args = ss.makefunc(ss, rho0, args, e_ops, options)

    if _safe_mode:
        # This is to test safety of the function before starting the loop.
        v = rho0.full().ravel('F')
        func(0., v, *ode_args) + v

    res = _generic_ode_solve(func,
                             ode_args,
                             rho0,
                             tlist,
                             e_ops,
                             options,
                             progress_bar,
                             dims=rho0.dims)
    res.num_collapse = len(c_ops)

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

    return res
Esempio n. 19
0
def floquet_markov_mesolve(
    R,
    rho0,
    tlist,
    e_ops,
    options=None,
    floquet_basis=True,
    f_modes_0=None,
    f_modes_table_t=None,
    f_energies=None,
    T=None,
):
    """
    Solve the dynamics for the system using the Floquet-Markov master equation.

    .. note::

        It is important to understand in which frame and basis the results
        are returned here.

    Parameters
    ----------

    R : array
        The Floquet-Markov master equation tensor `R`.

    rho0 : :class:`qutip.qobj`
        Initial density matrix.  If ``f_modes_0`` is not passed, this density
        matrix is assumed to be in the Floquet picture.

    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.solver`
        options for the ODE solver.

    floquet_basis: bool, True
        If ``True``, states and expectation values will be returned in the
        Floquet basis.  If ``False``, a transformation will be made to the
        computational basis; this will be in the lab frame if
        ``f_modes_table``, ``T` and ``f_energies`` are all supplied, or the
        interaction picture (defined purely be f_modes_0) if they are not.

    f_modes_0 : list of :class:`qutip.qobj` (kets), optional
        A list of initial Floquet modes, used to transform the given starting
        density matrix into the Floquet basis.  If this is not passed, it is
        assumed that ``rho`` is already in the Floquet basis.

    f_modes_table_t : nested list of :class:`qutip.qobj` (kets), optional
        A lookup-table of Floquet modes at times precalculated by
        :func:`qutip.floquet.floquet_modes_table`.  Necessary if
        ``floquet_basis`` is ``False`` and the transformation should be made
        back to the lab frame.

    f_energies : array_like of float, optional
        The precalculated Floquet quasienergies.  Necessary if
        ``floquet_basis`` is ``False`` and the transformation should be made
        back to the lab frame.

    T : float, optional
        The time period of driving.  Necessary if ``floquet_basis`` is
        ``False`` and the transformation should be made back to the lab frame.

    Returns
    -------

    output : :class:`qutip.solver.Result`
        An instance of the class :class:`qutip.solver.Result`, which
        contains either an *array* of expectation values or an array of
        state vectors, for the times specified by `tlist`.
    """
    opt = options or Options()
    if opt.tidy:
        R.tidyup()
    rho0 = rho0.proj() if rho0.isket else rho0

    # Prepare output object.
    dt = tlist[1] - tlist[0]
    output = Result()
    output.solver = "fmmesolve"
    output.times = tlist
    if isinstance(e_ops, FunctionType):
        expt_callback = True
        store_states = opt.store_states or False
    else:
        expt_callback = False
        try:
            e_ops = list(e_ops)
        except TypeError:
            raise TypeError("`e_ops` must be iterable or a function") from None
        n_expt_op = len(e_ops)
        if n_expt_op == 0:
            store_states = True
        else:
            output.expect = []
            output.num_expect = n_expt_op
            for op in e_ops:
                dtype = np.float64 if op.isherm else np.complex128
                output.expect.append(np.zeros(len(tlist), dtype=dtype))
        store_states = opt.store_states or (n_expt_op == 0)
    if store_states:
        output.states = []

    # Choose which frame transformations should be done on the initial and
    # evolved states.
    lab_lookup = [f_modes_table_t, f_energies, T]
    if (any(x is None for x in lab_lookup)
            and not all(x is None for x in lab_lookup)):
        warnings.warn(
            "if transformation back to the computational basis in the lab"
            "frame is desired, all of `f_modes_t`, `f_energies` and `T` must"
            "be supplied.")
        f_modes_table_t = f_energies = T = None

    # Initial state.
    if f_modes_0 is not None:
        rho0 = rho0.transform(f_modes_0)

    # Evolved states.
    if floquet_basis:

        def transform(rho, t):
            return rho
    elif f_modes_table_t is not None:
        # Lab frame, computational basis.
        def transform(rho, t):
            f_modes_t = floquet_modes_t_lookup(f_modes_table_t, t, T)
            f_states_t = floquet_states(f_modes_t, f_energies, t)
            return rho.transform(f_states_t, True)
    elif f_modes_0 is not None:
        # Interaction picture, computational basis.
        def transform(rho, t):
            return rho.transform(f_modes_0, False)
    else:
        raise ValueError(
            "cannot transform out of the Floquet basis without some knowledge "
            "of the Floquet modes.  Pass `f_modes_0`, or all of `f_modes_t`, "
            "`f_energies` and `T`.")

    # 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])

    # Main evolution loop.
    for t_idx, t in enumerate(tlist):
        if not r.successful():
            break
        rho = transform(Qobj(vec2mat(r.y), rho0.dims, rho0.shape), t)
        if expt_callback:
            e_ops(t, rho)
        else:
            for m, e_op in enumerate(e_ops):
                output.expect[m][t_idx] = expect(e_op, rho)
        if store_states:
            output.states.append(rho)
        r.integrate(r.t + dt)
    return output
Esempio n. 20
0
def coherence_function_g2(H,
                          taulist,
                          c_ops,
                          a_op,
                          solver="me",
                          args=None,
                          options=Options(ntraj=[20, 100])):
    """
    Calculate the normalized second-order quantum coherence function:

    .. math::

        g^{(2)}(\\tau) = \lim_{t \to \infty}
        \\frac{\\langle a^\\dagger(t)a^\\dagger(t+\\tau)
        a(t+\\tau)a(t)\\rangle}
        {\\langle a^\\dagger(t)a(t)\\rangle^2}

    using the quantum regression theorem and the evolution solver indicated by
    the `solver` parameter. Note: g2 is only defined for stationary
    statistics (uses steady state rho0).

    Parameters
    ----------

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

    taulist : *list* / *array*
        list of times for :math:`\\tau`. taulist must be positive and contain
        the element `0`.

    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 (`me` for master-equation and
        `es` for exponential series)

    options : :class:`qutip.solver.Options`
        solver options class. `ntraj` is taken as a two-element list because
        the `mc` correlator calls `mcsolve()` recursively; by default,
        `ntraj=[20, 100]`. `mc_corr_eps` prevents divide-by-zero errors in
        the `mc` correlator; by default, `mc_corr_eps=1e-10`.

    Returns
    -------

    g2: *array*
        The normalized second-order coherence function.

    """

    # first calculate the the steady state photon number
    rho0 = steadystate(H, c_ops)
    n = np.array([expect(rho0, a_op.dag() * a_op)])

    # calculate the correlation function G2 and normalize with n to obtain g2
    G2 = correlation_3op_1t(H,
                            None,
                            taulist,
                            c_ops,
                            a_op.dag(),
                            a_op.dag() * a_op,
                            a_op,
                            solver=solver,
                            args=args,
                            options=options)
    g2 = G2 / n**2

    return g2
Esempio n. 21
0
def fmmesolve(H,
              rho0,
              tlist,
              c_ops=[],
              e_ops=[],
              spectra_cb=[],
              T=None,
              args={},
              options=Options(),
              floquet_basis=True,
              kmax=5,
              _safe_mode=True,
              options_modes=None):
    """
    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 # doctest: +SKIP
        >>> h = 6.626e-34 # doctest: +SKIP
        >>> kB = 1.38e-23 # doctest: +SKIP
        >>> args['w_th'] = temperature * (kB / h) * 2 * pi * 1e-9 \
            #doctest: +SKIP

    options : :class:`qutip.solver`
        options for the ODE solver. For solving the master equation.

    floquet_basis : bool
        Will return results in Floquet basis or computational basis
        (optional).

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

    options_modes : :class:`qutip.solver`
        options for the ODE solver. For computing Floquet modes.

    Returns
    -------

    output : :class:`qutip.solver`

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

    if _safe_mode:
        _solver_safety_check(H, rho0, c_ops, e_ops, args)

    if options_modes is None:
        options_modes_table = Options()
    else:
        options_modes_table = options_modes

    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, options=options_modes)

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

    # 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,
                                  rho0,
                                  tlist,
                                  e_ops,
                                  options=options,
                                  floquet_basis=floquet_basis,
                                  f_modes_0=f_modes_0,
                                  f_modes_table_t=f_modes_table_t,
                                  T=T,
                                  f_energies=f_energies)
Esempio n. 22
0
def correlation_ss(H,
                   taulist,
                   c_ops,
                   a_op,
                   b_op,
                   solver="me",
                   reverse=False,
                   args=None,
                   options=Options(ntraj=[20, 100])):
    """
    Calculate the two-operator two-time correlation function:

    .. math::

        \lim_{t \to \infty} \left<A(t+\\tau)B(t)\\right>

    along one time axis (given steady-state initial conditions) using the
    quantum regression theorem and the evolution solver indicated by the
    `solver` parameter.

    Parameters
    ----------

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

    taulist : *list* / *array*
        list of times for :math:`\\tau`. taulist must be positive and contain
        the element `0`.

    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:`\lim_{t \to \infty} \left<A(t)B(t+\\tau)\\right>` instead of
        :math:`\lim_{t \to \infty} \left<A(t+\\tau)B(t)\\right>`.

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

    options : :class:`qutip.solver.Options`
        solver options class. `ntraj` is taken as a two-element list because
        the `mc` correlator calls `mcsolve()` recursively; by default,
        `ntraj=[20, 100]`. `mc_corr_eps` prevents divide-by-zero errors in
        the `mc` correlator; by default, `mc_corr_eps=1e-10`.

    Returns
    -------

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

    References
    ----------

    See, Gardiner, Quantum Noise, Section 5.2.

    """

    warn(
        "correlation_ss() now legacy, please use correlation_2op_1t() with" +
        "initial state as None", FutureWarning)

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

    return correlation_2op_1t(H,
                              None,
                              taulist,
                              c_ops,
                              a_op,
                              b_op,
                              solver=solver,
                              reverse=reverse,
                              args=args,
                              options=options)
Esempio n. 23
0
def rhs_generate(H,
                 c_ops,
                 args={},
                 options=Options(),
                 name=None,
                 cleanup=True):
    """
    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 : Options
        Instance of ODE solver options.

    name: str
        Name of generated RHS

    cleanup: bool
        Whether the generated cython file should be automatically removed or
        not.

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

    """
    config.reset()
    config.options = options

    if name:
        config.tdname = name
    else:
        config.tdname = "rhs" + str(os.getpid()) + str(config.cgen_num)

    Lconst = 0

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

    # loop over all hamiltonian terms, convert to superoperator form and
    # add the data of sparse matrix represenation to

    msg = "Incorrect specification of time-dependence: "

    for h_spec in H:
        if isinstance(h_spec, Qobj):
            h = h_spec

            if not isinstance(h, Qobj):
                raise TypeError(msg + "expected Qobj")

            if h.isoper:
                Lconst += -1j * (spre(h) - spost(h))
            elif h.issuper:
                Lconst += h
            else:
                raise TypeError(msg + "expected operator or superoperator")

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

            if not isinstance(h, Qobj):
                raise TypeError(msg + "expected Qobj")

            if h.isoper:
                L = -1j * (spre(h) - spost(h))
            elif h.issuper:
                L = h
            else:
                raise TypeError(msg + "expected operator or superoperator")

            Ldata.append(L.data.data)
            Linds.append(L.data.indices)
            Lptrs.append(L.data.indptr)
            if isinstance(h_coeff, Cubic_Spline):
                Lobj.append(h_coeff.coeffs)
            Lcoeff.append(h_coeff)

        else:
            raise TypeError(msg + "expected string format")

    # loop over all collapse operators
    for c_spec in c_ops:
        if isinstance(c_spec, Qobj):
            c = c_spec

            if not isinstance(c, Qobj):
                raise TypeError(msg + "expected Qobj")

            if c.isoper:
                cdc = c.dag() * c
                Lconst += spre(c) * spost(c.dag()) - 0.5 * spre(cdc) \
                                                   - 0.5 * spost(cdc)
            elif c.issuper:
                Lconst += c
            else:
                raise TypeError(msg + "expected operator or superoperator")

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

            if not isinstance(c, Qobj):
                raise TypeError(msg + "expected Qobj")

            if c.isoper:
                cdc = c.dag() * c
                L = spre(c) * spost(c.dag()) - 0.5 * spre(cdc) \
                                             - 0.5 * spost(cdc)
                c_coeff = "(" + c_coeff + ")**2"
            elif c.issuper:
                L = c
            else:
                raise TypeError(msg + "expected operator or superoperator")

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

        else:
            raise TypeError(msg + "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,
                   config=config)
    cgen.generate(config.tdname + ".pyx")

    code = compile('from ' + config.tdname + ' import cy_td_ode_rhs',
                   '<string>', 'exec')
    exec(code, globals())

    config.tdfunc = cy_td_ode_rhs

    if cleanup:
        try:
            os.remove(config.tdname + ".pyx")
        except:
            pass
Esempio n. 24
0
def correlation_4op_1t(H,
                       state0,
                       taulist,
                       c_ops,
                       a_op,
                       b_op,
                       c_op,
                       d_op,
                       solver="me",
                       args=None,
                       options=Options(ntraj=[20, 100])):
    """
    Calculate the four-operator two-time correlation function:
    :math:`\left<A(t)B(t+\\tau)C(t+\\tau)D(t)\\right>`
    along one time axis using the quantum regression theorem and the
    evolution solver indicated by the `solver` parameter.

    Note: it is not possibly to calculate a physically meaningful correlation
    of this form where :math:`\\tau<0`.

    Parameters
    ----------

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

    rho0 : :class:`qutip.qobj.Qobj`
        Initial state density matrix :math:`\\rho(t_0)` or state vector
        :math:`\\psi(t_0)`. If 'state0' is 'None', then the steady state will
        be used as the initial state. The 'steady-state' is only implemented
        for the `me` and `es` solvers.

    taulist : *list* / *array*
        list of times for :math:`\\tau`. taulist must be positive and contain
        the element `0`.

    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 (`me` for master-equation, `mc` for Monte Carlo, and
        `es` for exponential series)

    options : :class:`qutip.solver.Options`
        solver options class. `ntraj` is taken as a two-element list because
        the `mc` correlator calls `mcsolve()` recursively; by default,
        `ntraj=[20, 100]`. `mc_corr_eps` prevents divide-by-zero errors in
        the `mc` correlator; by default, `mc_corr_eps=1e-10`.

    Returns
    -------

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

    References
    ----------

    See, Gardiner, Quantum Noise, Section 5.2.

    """

    warn("correlation_4op_1t() now legacy, please use correlation_3op_1t()",
         FutureWarning)
    warn(
        "the reverse argument has been removed as it did not contain any" +
        "new physical information", DeprecationWarning)

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

    return correlation_3op_1t(H,
                              state0,
                              taulist,
                              c_ops,
                              a_op,
                              b_op * c_op,
                              d_op,
                              solver=solver,
                              args=args,
                              options=options)
Esempio n. 25
0
def correlation_2op_2t(H,
                       rho0,
                       tlist,
                       taulist,
                       c_ops,
                       a_op,
                       b_op,
                       solver="me",
                       reverse=False,
                       args=None,
                       options=Options()):
    """
    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
def mesolve_checkpoint(H, rho0, tlist, c_ops, e_ops, save, subdir, args={}, options=None,
            progress_bar=None):
    """
    Master equation evolution of a density matrix for a given Hamiltonian and
    set of collapse operators, or a Liouvillian.

    Evolve the state vector or density matrix (`rho0`) using a given
    Hamiltonian (`H`) and an [optional] set of collapse operators
    (`c_ops`), by integrating the set of ordinary differential equations
    that define the system. In the absence of collapse 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.

    If either `H` or the Qobj elements in `c_ops` are superoperators, they
    will be treated as direct contributions to the total system Liouvillian.
    This allows to solve master equations that are not on standard Lindblad
    form by passing a custom Liouvillian in place of either the `H` or `c_ops`
    elements.

    **Time-dependent operators**

    For time-dependent problems, `H` and `c_ops` can be callback
    functions that takes two arguments, time and `args`, and returns the
    Hamiltonian or Liouvillian 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*), a callback
    function (*list callback format*) that evaluates to the time-dependent
    coefficient for the corresponding operator, or a NumPy array (*list
    array format*) which specifies the value of the coefficient to the
    corresponding operator for each value of t in tlist.

    *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).

        H = [[H0, np.sin(w*tlist)], [H1, np.sin(2*w*tlist)]]

    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.

    **Additional options**

    Additional options to mesolve can be set via the `options` argument, which
    should be an instance of :class:`qutip.solver.Options`. Many ODE
    integration options can be set this way, and the `store_states` and
    `store_final_state` options can be used to store states even though
    expectation values are requested via the `e_ops` argument.

    .. note::

        If an element in the list-specification of the Hamiltonian or
        the list of collapse operators are in superoperator form 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. mesolve 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 in scipy which will raise an NotImplemented
        exception.

    Parameters
    ----------

    H : :class:`qutip.Qobj`
        System Hamiltonian, or a callback function for time-dependent
        Hamiltonians, or alternatively a system Liouvillian.

    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, or a list
        of Liouvillian superoperators.

    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.Options`
        with options for the solver.

    progress_bar: BaseProgressBar
        Optional instance of BaseProgressBar, or a subclass thereof, for
        showing the progress of the simulation.

    Returns
    -------

    result: :class:`qutip.Result`

        An instance of the class :class:`qutip.Result`, which contains
        either an *array* `result.expect` of expectation values for the times
        specified by `tlist`, or an *array* `result.states` of 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 in place of
        operators for which to calculate the expectation values.

    """

    if progress_bar is None:
        progress_bar = BaseProgressBar()
    elif progress_bar is True:
        progress_bar = TextProgressBar()

    # 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]

    # convert array based time-dependence to string format
    H, c_ops, args = _td_wrap_array_str(H, c_ops, args, tlist)

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

    if options is None:
        options = Options()

    if (not options.rhs_reuse) or (not config.tdfunc):
        # reset config collapse and time-dependence flags to default values
        config.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_checkpoint(H, rho0, tlist, c_ops,
                                     e_ops, args, options,
                                     progress_bar, save, subdir)

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

    return res
Esempio n. 27
0
def correlation_4op_2t(H,
                       rho0,
                       tlist,
                       taulist,
                       c_ops,
                       a_op,
                       b_op,
                       c_op,
                       d_op,
                       solver="me",
                       args=None,
                       options=Options()):
    """
    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)
Esempio n. 28
0
def propagator(H,
               t,
               c_op_list=[],
               args={},
               options=None,
               unitary_mode='batch',
               parallel=False,
               progress_bar=None,
               _safe_mode=True,
               **kwargs):
    r"""
    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.Options`
        with options for the ODE solver.

    unitary_mode = str ('batch', 'single')
        Solve all basis vectors simulaneously ('batch') or individually
        ('single').

    parallel : bool {False, True}
        Run the propagator in parallel mode. This will override the
        unitary_mode settings if set to True.

    progress_bar: BaseProgressBar
        Optional instance of BaseProgressBar, or a subclass thereof, for
        showing the progress of the simulation. By default no progress bar
        is used, and if set to True a TextProgressBar will be used.

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

    """
    kw = _default_kwargs()
    if 'num_cpus' in kwargs:
        num_cpus = kwargs['num_cpus']
    else:
        num_cpus = kw['num_cpus']

    if progress_bar is None:
        progress_bar = BaseProgressBar()
    elif progress_bar is True:
        progress_bar = TextProgressBar()

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

    if isinstance(t, (int, float, np.integer, np.floating)):
        tlist = [0, t]
    else:
        tlist = t

    if _safe_mode:
        _solver_safety_check(H, None, c_ops=c_op_list, e_ops=[], args=args)

    td_type = _td_format_check(H, c_op_list, solver='me')

    if isinstance(
            H,
        (types.FunctionType, types.BuiltinFunctionType, functools.partial)):
        H0 = H(0.0, args)
        if unitary_mode == 'batch':
            # batch don't work with function Hamiltonian
            unitary_mode = 'single'
    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

        if parallel:
            unitary_mode = 'single'
            u = np.zeros([N, N, len(tlist)], dtype=complex)
            output = parallel_map(_parallel_sesolve,
                                  range(N),
                                  task_args=(N, H, tlist, args, options),
                                  progress_bar=progress_bar,
                                  num_cpus=num_cpus)
            for n in range(N):
                for k, t in enumerate(tlist):
                    u[:, n, k] = output[n].states[k].full().T
        else:
            if unitary_mode == 'single':
                output = sesolve(H,
                                 qeye(dims[0]),
                                 tlist, [],
                                 args,
                                 options,
                                 _safe_mode=False)
                return output.states[-1] if len(tlist) == 2 else output.states

            elif unitary_mode == 'batch':
                u = np.zeros(len(tlist), dtype=object)
                _rows = np.array([(N + 1) * m for m in range(N)])
                _cols = np.zeros_like(_rows)
                _data = np.ones_like(_rows, dtype=complex)
                psi0 = Qobj(sp.coo_matrix((_data, (_rows, _cols))).tocsr())
                if td_type[1] > 0 or td_type[2] > 0:
                    H2 = []
                    for k in range(len(H)):
                        if isinstance(H[k], list):
                            H2.append([tensor(qeye(N), H[k][0]), H[k][1]])
                        else:
                            H2.append(tensor(qeye(N), H[k]))
                else:
                    H2 = tensor(qeye(N), H)
                options.normalize_output = False
                output = sesolve(H2,
                                 psi0,
                                 tlist, [],
                                 args=args,
                                 options=options,
                                 _safe_mode=False)
                for k, t in enumerate(tlist):
                    u[k] = sp_reshape(output.states[k].data, (N, N))
                    unit_row_norm(u[k].data, u[k].indptr, u[k].shape[0])
                    u[k] = u[k].T.tocsr()
            else:
                raise ValueError('Invalid unitary mode.')

    elif len(c_op_list) == 0 and H0.issuper:
        # calculate the propagator for the vector representation of the
        # density matrix (a superoperator propagator)
        unitary_mode = 'single'
        N = H0.shape[0]
        sqrt_N = int(np.sqrt(N))
        dims = H0.dims

        if parallel:
            output = parallel_map(_parallel_mesolve,
                                  range(N),
                                  task_args=(sqrt_N, H, tlist, c_op_list, args,
                                             options),
                                  task_kwargs={"dims": H0.dims[0]},
                                  progress_bar=progress_bar,
                                  num_cpus=num_cpus)

            u = np.zeros([N, N, len(tlist)], dtype=complex)
            for n in range(N):
                for k, t in enumerate(tlist):
                    u[:, n, k] = mat2vec(output[n].states[k].full()).T
        else:
            rho0 = qeye(H0.dims[0])
            output = mesolve(H,
                             rho0,
                             tlist,
                             args=args,
                             options=options,
                             _safe_mode=False)
            return output.states[-1] if len(tlist) == 2 else output.states

    else:
        # calculate the propagator for the vector representation of the
        # density matrix (a superoperator propagator)
        unitary_mode = 'single'
        N = H0.shape[0]
        dims = [H0.dims, H0.dims]

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

        if parallel:
            output = parallel_map(_parallel_mesolve,
                                  range(N * N),
                                  task_args=(N, H, tlist, c_op_list, args,
                                             options),
                                  task_kwargs={"dims": H0.dims},
                                  progress_bar=progress_bar,
                                  num_cpus=num_cpus)
            for n in range(N * N):
                for k, t in enumerate(tlist):
                    u[:, n, k] = mat2vec(output[n].states[k].full()).T
        else:
            progress_bar.start(N * N)
            for n in range(N * N):
                progress_bar.update(n)
                col_idx, row_idx = np.unravel_index(n, (N, N))
                rho0 = projection(N, row_idx, col_idx)
                rho0.dims = H0.dims
                output = mesolve(H,
                                 rho0,
                                 tlist,
                                 c_ops=c_op_list,
                                 args=args,
                                 options=options,
                                 _safe_mode=False)
                for k, t in enumerate(tlist):
                    u[:, n, k] = mat2vec(output.states[k].full()).T
            progress_bar.finished()

    if len(tlist) == 2:
        data = u[-1] if unitary_mode == 'batch' else u[:, :, 1]
        return Qobj(data, dims=dims)

    out = np.empty((len(tlist), ), dtype=object)
    if unitary_mode == 'batch':
        out[:] = [Qobj(u[k], dims=dims) for k in range(len(tlist))]
    else:
        out[:] = [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))]
    return out
Esempio n. 29
0
def coherence_function_g2(H,
                          rho0,
                          taulist,
                          c_ops,
                          a_op,
                          solver="me",
                          args=None,
                          options=Options()):
    """
    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
Esempio n. 30
0
def propagator(H, t, c_op_list=[], args={}, options=None,
               unitary_mode='batch', parallel=False, 
               progress_bar=None, **kwargs):
    """
    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.Options`
        with options for the ODE solver.

    unitary_mode = str ('batch', 'single')
        Solve all basis vectors simulaneously ('batch') or individually 
        ('single').
    
    parallel : bool {False, True}
        Run the propagator in parallel mode. This will override the 
        unitary_mode settings if set to True.
    
    progress_bar: BaseProgressBar
        Optional instance of BaseProgressBar, or a subclass thereof, for
        showing the progress of the simulation. By default no progress bar
        is used, and if set to True a TextProgressBar will be used.

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

    """
    kw = _default_kwargs()
    if 'num_cpus' in kwargs:
        num_cpus = kwargs['num_cpus']
    else:
        num_cpus = kw['num_cpus']
    
    if progress_bar is None:
        progress_bar = BaseProgressBar()
    elif progress_bar is True:
        progress_bar = TextProgressBar()

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

    if isinstance(t, (int, float, np.integer, np.floating)):
        tlist = [0, t]
    else:
        tlist = t

    td_type = _td_format_check(H, c_op_list, solver='me')
        
    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
        
        if parallel:
            unitary_mode = 'single'
            u = np.zeros([N, N, len(tlist)], dtype=complex)
            output = parallel_map(_parallel_sesolve,range(N),
                    task_args=(N,H, tlist,args,options),
                    progress_bar=progress_bar, num_cpus=num_cpus)
            for n in range(N):
                for k, t in enumerate(tlist):
                    u[:, n, k] = output[n].states[k].full().T 
        else:
            if unitary_mode == 'single':
                u = np.zeros([N, N, len(tlist)], dtype=complex)
                progress_bar.start(N)
                for n in range(0, N):
                    progress_bar.update(n)
                    psi0 = basis(N, n)
                    output = sesolve(H, psi0, tlist, [], args, options, _safe_mode=False) 
                    for k, t in enumerate(tlist):
                        u[:, n, k] = output.states[k].full().T
                    progress_bar.finished() 

            elif unitary_mode =='batch':
                u = np.zeros(len(tlist), dtype=object)
                _rows = np.array([(N+1)*m for m in range(N)])
                _cols = np.zeros_like(_rows)
                _data = np.ones_like(_rows,dtype=complex)
                psi0 = Qobj(sp.coo_matrix((_data,(_rows,_cols))).tocsr())
                if td_type[1] > 0 or td_type[2] > 0:
                    H2 = []
                    for k in range(len(H)):
                        if isinstance(H[k], list):
                            H2.append([tensor(qeye(N), H[k][0]), H[k][1]])
                        else:
                            H2.append(tensor(qeye(N), H[k]))
                else:
                    H2 = tensor(qeye(N), H)
                output = sesolve(H2, psi0, tlist, [] , args = args, _safe_mode=False, 
                             options=Options(normalize_output=False))
                for k, t in enumerate(tlist):
                    u[k] = sp_reshape(output.states[k].data, (N, N))
                    unit_row_norm(u[k].data, u[k].indptr, u[k].shape[0])
                    u[k] = u[k].T.tocsr()
            else:
                raise Exception('Invalid unitary mode.')
                        

    elif len(c_op_list) == 0 and H0.issuper:
        # calculate the propagator for the vector representation of the
        # density matrix (a superoperator propagator)
        unitary_mode = 'single'
        N = H0.shape[0]
        sqrt_N = int(np.sqrt(N))
        dims = H0.dims
        
        u = np.zeros([N, N, len(tlist)], dtype=complex)

        if parallel:
            output = parallel_map(_parallel_mesolve,range(N * N),
                    task_args=(sqrt_N,H,tlist,c_op_list,args,options),
                    progress_bar=progress_bar, num_cpus=num_cpus)
            for n in range(N * N):
                for k, t in enumerate(tlist):
                    u[:, n, k] = mat2vec(output[n].states[k].full()).T
        else:
            progress_bar.start(N)
            for n in range(0, N):
                progress_bar.update(n)
                col_idx, row_idx = np.unravel_index(n,(sqrt_N,sqrt_N))
                rho0 = Qobj(sp.csr_matrix(([1],([row_idx],[col_idx])), shape=(sqrt_N,sqrt_N), dtype=complex))
                output = mesolve(H, rho0, tlist, [], [], args, options, _safe_mode=False)
                for k, t in enumerate(tlist):
                    u[:, n, k] = mat2vec(output.states[k].full()).T
            progress_bar.finished()

    else:
        # calculate the propagator for the vector representation of the
        # density matrix (a superoperator propagator)
        unitary_mode = 'single'
        N = H0.shape[0]
        dims = [H0.dims, H0.dims]

        u = np.zeros([N * N, N * N, len(tlist)], dtype=complex)
        
        if parallel:
            output = parallel_map(_parallel_mesolve,range(N * N),
                    task_args=(N,H,tlist,c_op_list,args,options),
                    progress_bar=progress_bar, num_cpus=num_cpus)
            for n in range(N * N):
                for k, t in enumerate(tlist):
                    u[:, n, k] = mat2vec(output[n].states[k].full()).T
        else:
            progress_bar.start(N * N)
            for n in range(N * N):
                progress_bar.update(n)
                col_idx, row_idx = np.unravel_index(n,(N,N))
                rho0 = Qobj(sp.csr_matrix(([1],([row_idx],[col_idx])), shape=(N,N), dtype=complex))
                output = mesolve(H, rho0, tlist, c_op_list, [], args, options, _safe_mode=False)
                for k, t in enumerate(tlist):
                    u[:, n, k] = mat2vec(output.states[k].full()).T
            progress_bar.finished()

    if len(tlist) == 2:
        if unitary_mode == 'batch':
            return Qobj(u[-1], dims=dims)
        else:
            return Qobj(u[:, :, 1], dims=dims)
    else:
        if unitary_mode == 'batch':
            return np.array([Qobj(u[k], dims=dims) for k in range(len(tlist))], dtype=object)
        else:
            return np.array([Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))], dtype=object)
Esempio n. 31
0
def correlation_ss(H,
                   taulist,
                   c_ops,
                   a_op,
                   b_op,
                   rho0=None,
                   solver="me",
                   reverse=False,
                   args=None,
                   options=Options()):
    """
    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)
Esempio n. 32
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.Options`
        with options for the ODE solver.

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

    """

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

    if isinstance(t, (int, float, np.integer, np.floating)):
        tlist = [0, t]
    else:
        tlist = 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))]
Esempio n. 33
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 absence of collapse 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 Liouvillian 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*), a callback
    function (*list callback format*) that evaluates to the time-dependent
    coefficient for the corresponding operator, or a numpy array (*list
    array format*) which specifies the value of the coefficient to the
    corresponding operator for each value of t in tlist.

    *Examples*

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

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

        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 form 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. mesolve 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 in scipy which 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.Options`
        with options for the ODE solver.

    progress_bar: TextProgressBar
        Optional instance of BaseProgressBar, or a subclass thereof, for
        showing the progress of the simulation.

    Returns
    -------

    output: :class:`qutip.solver`

        An instance of the class :class:`qutip.solver`, 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 in place of operators for
        which to calculate the expectation values.

    """
    #Cast Qobj instances to lists of one element
    c_ops, e_ops = map(qobj_list, [c_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

    # convert array based time-dependence to string format
    H, c_ops, args = _td_wrap_array_str(H, c_ops, args, tlist)

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

    if options is None:
        options = Options()

    if (not options.rhs_reuse) or (not config.tdfunc):
        # reset config collapse and time-dependence flags to default values
        config.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)):
            # function-callback 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