Ejemplo 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 = Odeoptions()
    opt.rhs_reuse = True

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

    return f_modes_table_t
Ejemplo n.º 2
0
def floquet_modes_table(f_modes_0, f_energies, tlist, H, T, args=None):
    """
    Pre-calculate the Floquet modes for a range of times spanning the floquet
    period. Can later be used as a table to look up the floquet modes for
    any time.
    
    Parameters
    ----------
    
    f_modes_0 : list of :class:`qutip.Qobj` (kets)
        Floquet modes at :math:`t`

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

    H : :class:`qutip.Qobj`
        system Hamiltonian, time-dependent with period `T`
        
    T : float
        The period of the time-dependence of the hamiltonian. 

    args : dictionary
        dictionary with variables required to evaluate H     
     
    Returns
    -------

    output : nested list

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

    """

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

    f_modes_table_t = [[] for t in tlist_period]

    opt = Odeoptions()
    opt.rhs_reuse = True

    for n, f_mode in enumerate(f_modes_0):
        output = mesolve(H, f_mode, tlist_period, [], [], args, opt)
        for t_idx, f_state_t in enumerate(output.states):
            f_modes_table_t[t_idx].append(f_state_t * exp(1j * f_energies[n]*tlist_period[t_idx]))
        
    return f_modes_table_t    
Ejemplo n.º 3
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.
    
    """

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

    f_modes_table_t = [[] for t in tlist_period]

    opt = Odeoptions()
    opt.rhs_reuse = True

    for n, f_mode in enumerate(f_modes_0):
        output = mesolve(H, f_mode, tlist_period, [], [], args, opt)
        for t_idx, f_state_t in enumerate(output.states):
            f_modes_table_t[t_idx].append(f_state_t * exp(1j * f_energies[n]*tlist_period[t_idx]))
        
    return f_modes_table_t    
Ejemplo n.º 4
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.
    
    """

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

    f_modes_table_t = [[] for t in tlist_period]

    opt = Odeoptions()
    opt.rhs_reuse = True

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

    return f_modes_table_t
Ejemplo n.º 5
0
def odesolve(H, rho0, tlist, c_op_list, expt_ops, H_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 (`expt_ops`). 

    For problems with time-dependent Hamiltonians, `H` can be a callback function
    that takes two arguments, time and `H_args`, and returns the Hamiltonian
    at that point in time. `H_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.
    
    expt_ops : list of :class:`qutip.Qobj` / callback function
        list of operators for which to evaluate expectation values.
     
    H_args : *dictionary*
        dictionary of parameters for time-dependent Hamiltonians and collapse operators.
     
    options : :class:`qutip.Qdeoptions`
        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 H_args. odesolve will check for :class:`qutip.Qobj` in
    `H_args` and handle the conversion to sparse matrices. All other
    :class:`qutip.Qobj` objects that are not passed via `H_args` will be
    passed on to the integrator to scipy who will raise an NotImplemented
    exception.
        
    Depreciated in QuTiP 2.0.0.  Use :func:`mesolve` instead.
        
    """

    if options == None:
        options = Odeoptions()
        options.nsteps = 2500  #
        options.max_step = max(tlist)/10.0 # take at least 10 steps.. 
        
    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, expt_ops, H_args, options)
        if isinstance(H, FunctionType):
            output = mesolve_func_td(H, rho0, tlist, c_op_list, expt_ops, H_args, options)
        else:
            output = mesolve_const(H, rho0, tlist, c_op_list, expt_ops, H_args, options)
    else:
        if isinstance(H, list):
            output = wfsolve_list_td(H, rho0, tlist, expt_ops, H_args, options)
        if isinstance(H, FunctionType):
            output = wfsolve_func_td(H, rho0, tlist, expt_ops, H_args, options)
        else:
            output = wfsolve_const(H, rho0, tlist, expt_ops, H_args, options)

    if len(expt_ops) > 0:
        return output.expect
    else:
        return output.states
Ejemplo n.º 6
0
def bloch_redfield_solve(R, ekets, rho0, tlist, e_ops=[], opt=None):
    """
    Evolve the ODEs defined by Bloch-Redfeild master equation.
    """

    if opt == None:
        opt = Odeoptions()
        opt.nsteps = 2500  #

    if opt.tidy:
        R.tidyup()

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

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

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

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

    #
    # setup integrator
    #
    initial_vector = mat2vec(rho0.full())
    r = scipy.integrate.ode(cyq_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,  #nsteps=opt.nsteps,
        #first_step=opt.first_step, min_step=opt.min_step,
        max_step=opt.max_step)
    r.set_initial_value(initial_vector, tlist[0])

    #
    # start evolution
    #
    rho = Qobj(rho0)

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

        rho.data = vec2mat(r.y)

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

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

    return result_list
Ejemplo n.º 7
0
def propagator(H, t, c_op_list, H_args=None, opt=None):
    """
    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 
        Hamiltonian
        
    t : float 
        Time.
        
    c_op_list : list 
        List of qobj collapse operators.
        
    Other Parameters
    ----------------
    H_args : list/array/dictionary 
        Parameters to callback functions for time-dependent Hamiltonians.
    
    Returns
    -------
     a : qobj 
        Instance representing the propagator :math:`U(t)`.
    
    """

    if opt == None:
        opt = Odeoptions()
        opt.rhs_reuse = True

    if len(c_op_list) == 0:
        # calculate propagator for the wave function

        if isinstance(H, FunctionType):
            H0 = H(0.0, H_args)
            N = H0.shape[0]
        elif isinstance(H, list):
            if isinstance(H[0], list):
                H0 = H[0][0]
                N = H0.shape[0]
            else:
                H0 = H[0]
                N = H0.shape[0]
        else:
            N = H.shape[0]

        u = zeros([N, N], dtype=complex)

        for n in range(0, N):
            psi0 = basis(N, n)
            output = mesolve(H, psi0, [0, t], [], [], H_args, opt)
            u[:, n] = output.states[1].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], [], [], H_args, opt)
        #for n in range(0, N):
        #    u[:,n] = psi_t_list[n][1].full().T

    else:
        # calculate the propagator for the vector representation of the
        # density matrix

        if isinstance(H, FunctionType):
            H0 = H(0.0, H_args)
            N = H0.shape[0]
        elif isinstance(H, list):
            if isinstance(H[0], list):
                H0 = H[0][0]
                N = H0.shape[0]
            else:
                H0 = H[0]
                N = H0.shape[0]
        else:
            N = H.shape[0]

        u = zeros([N * N, N * N], dtype=complex)

        for n in range(0, N * N):
            psi0 = basis(N * N, n)
            rho0 = Qobj(vec2mat(psi0.full()))
            output = mesolve(H, rho0, [0, t], c_op_list, [], H_args, opt)
            u[:, n] = mat2vec(output.states[1].full()).T

    return Qobj(u)
Ejemplo n.º 8
0
def propagator(H, t, c_op_list, H_args=None, opt=None):
    """
    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.
    H_args : list/array/dictionary 
        Parameters to callback functions for time-dependent Hamiltonians.
    
    Returns
    -------
     a : qobj 
        Instance representing the propagator :math:`U(t)`.
    
    """

    if opt == None:
        opt = Odeoptions()
        opt.rhs_reuse = True

    tlist = [0, t] if isinstance(t,(int,float,np.int64,np.float64)) else t
    
    if len(c_op_list) == 0:
        # calculate propagator for the wave function

        if isinstance(H, types.FunctionType):
            H0 = H(0.0, H_args)
            N = H0.shape[0]
        elif isinstance(H, list):
            if isinstance(H[0], list):
                H0 = H[0][0]
                N = H0.shape[0]            
            else:
                H0 = H[0]
                N = H0.shape[0] 
        else:
            N = H.shape[0]

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

        for n in range(0, N):
            psi0 = basis(N, n)
            output = mesolve(H, psi0, tlist, [], [], H_args, opt)
            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], [], [], H_args, opt)
        #for n in range(0, N):
        #    u[:,n] = psi_t_list[n][1].full().T

    else:
        # calculate the propagator for the vector representation of the 
        # density matrix

        if isinstance(H, types.FunctionType):
            H0 = H(0.0, H_args)
            N = H0.shape[0]
        elif isinstance(H, list):
            if isinstance(H[0], list):
                H0 = H[0][0]
                N = H0.shape[0]            
            else:
                H0 = H[0]
                N = H0.shape[0]            
        else:
            N = H.shape[0]

        u = np.zeros([N*N, N*N, len(tlist)], dtype=complex)
        
        for n in range(0, N*N):
            psi0  = basis(N*N, n)
            rho0  = Qobj(vec2mat(psi0.full()))
            output = mesolve(H, rho0, tlist, c_op_list, [], H_args, opt)
            for k, t in enumerate(tlist):
                u[:,n,k] = mat2vec(output.states[k].full()).T

    if len(tlist) == 2:
        return Qobj(u[:,:,1])
    else:
        return [Qobj(u[:,:,k]) for k in range(len(tlist))]
Ejemplo n.º 9
0
def bloch_redfield_solve(R, ekets, rho0, tlist, e_ops=[], options=None):
    """
    Evolve the ODEs defined by Bloch-Redfield master equation. The 
    Bloch-Redfield tensor can be calculated by the function
    :func:`bloch_redfield_tensor`.
   
    Parameters
    ----------
    
    R : :class:`qutip.Qobj`
        Bloch-Redfield tensor.

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

    rho0 : :class:`qutip.Qobj`
        Initial density matrix.
                
    tlist : *list* / *array*    
        List of times for :math:`t`.
        
    e_ops : list of :class:`qutip.Qobj` / callback function
        List of operators for which to evaluate expectation values.
    
    options : :class:`qutip.Qdeoptions`
        Options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.Odedata`

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

    """

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

    if options.tidy:
        R.tidyup()

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

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

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

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

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

    #
    # start evolution
    #
    rho = Qobj(rho0)

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

        rho.data = vec2mat(r.y)

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

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

    return result_list
Ejemplo n.º 10
0
def bloch_redfield_solve(R, ekets, rho0, tlist, e_ops=[], opt=None):
    """
    Evolve the ODEs defined by Bloch-Redfeild master equation.
    """

    if opt == None:
        opt = Odeoptions()
        opt.nsteps = 2500  # 

    if opt.tidy:
        R.tidyup()

    #
    # check initial state
    #
    if isket(rho0):
        # Got a wave function as initial state: convert to density matrix.
        rho0 = rho0 * rho0.dag()
       
    #
    # prepare output array
    # m
    n_e_ops  = len(e_ops)
    n_tsteps = len(tlist)
    dt       = tlist[1]-tlist[0]

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


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

    #
    # setup integrator
    #
    initial_vector = mat2vec(rho0.full())
    r = scipy.integrate.ode(cyq_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, #nsteps=opt.nsteps,
                              #first_step=opt.first_step, min_step=opt.min_step,
                              max_step=opt.max_step)
    r.set_initial_value(initial_vector, tlist[0])

    #
    # start evolution
    #
    rho = Qobj(rho0)

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

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

        r.integrate(r.t + dt)
        t_idx += 1
          
    return result_list
Ejemplo n.º 11
0
def mesolve(H, rho0, tlist, c_ops, expt_ops, args={}, options=None):
    """
    Master equation evolution of a density matrix for a given Hamiltonian.

    Evolve the state vector or density matrix (`rho0`) using a given Hamiltonian
    (`H`) and an [optional] set of collapse operators (`c_op_list`),
    by integrating the set of ordinary differential equations that define the
    system. In the absense of collase operators the system is evolved according
    to the unitary evolution of the Hamiltonian.
    
    The output is either the state vector at arbitrary points in time (`tlist`),
    or the expectation values of the supplied operators (`expt_ops`). If 
    expt_ops is a callback function, it is invoked for each time in `tlist` 
    with time and the state as arguments, and the function does not use any
    return values.

    **Time-dependent operators**

    For problems with time-dependent problems `H` and `c_ops` can be callback
    functions that takes two arguments, time and `args`, and returns the 
    Hamiltonian or Liuovillian for the system at that point in time
    (*callback format*). 
    
    Alternatively, `H` and `c_ops` can be a specified in a nested-list format
    where each element in the list is a list of length 2, containing an
    operator (:class:`qutip.Qobj`) at the first element and where the 
    second element is either a string (*list string format*) or a callback
    function (*list callback format*) that evaluates to the time-dependent
    coefficient for the corresponding operator.
    
    
    *Examples*
    
        H = [[H0, 'sin(w*t)'], [H1, 'sin(2*w*t)']]
        
        H = [[H0, f0_t], [H1, f1_t]]
         
        where f0_t and f1_t are python functions with signature f_t(t, args).
    
    In the *list string format* and *list callback format*, the string
    expression and the callback function must evaluate to a real or complex
    number (coefficient for the corresponding operator).
    
    In all cases of time-dependent operators, `args` is a dictionary of
    parameters that is used when evaluating operators. It is passed to the
    callback functions as second argument
   
   
    .. note:: 
    
        On using callback function: mesolve transforms all :class:`qutip.Qobj`
        objects to sparse matrices before handing the problem to the integrator
        function. In order for your callback function to work correctly, pass
        all :class:`qutip.Qobj` objects that are used in constructing the
        Hamiltonian via args. odesolve will check for :class:`qutip.Qobj` in
        `args` and handle the conversion to sparse matrices. All other
        :class:`qutip.Qobj` objects that are not passed via `args` will be
        passed on to the integrator to scipy who will raise an NotImplemented
        exception.   
   
    Parameters
    ----------
    
    H : :class:`qutip.Qobj`
        system Hamiltonian, or a callback function for time-dependent Hamiltonians.
        
    rho0 : :class:`qutip.Qobj`
        initial density matrix or state vector (ket).
     
    tlist : *list* / *array*    
        list of times for :math:`t`.
        
    c_ops : list of :class:`qutip.Qobj`
        list of collapse operators.
    
    expt_ops : list of :class:`qutip.Qobj` / callback function
        list of operators for which to evaluate expectation values.
     
    args : *dictionary*
        dictionary of parameters for time-dependent Hamiltonians and collapse operators.
     
    options : :class:`qutip.Qdeoptions`
        with options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.Odedata`

        An instance of the class :class:`qutip.Odedata`, which contains either
        an *array* of expectation values for the times specified by `tlist`, or
        an *array* or state vectors or density matrices corresponding to the
        times in `tlist` [if `expt_ops` is an empty list], or
        nothing if a callback function was given inplace of operators for
        which to calculate the expectation values.
    
    """
    # check for type (if any) of time-dependent inputs
    n_const, n_func, n_str = _ode_checks(H, c_ops)

    if options == None:
        options = Odeoptions()

    if (not options.rhs_reuse) or (not odeconfig.tdfunc):
        #reset odeconfig collapse and time-dependence flags to default values
        _reset_odeconfig()
    #
    # dispatch the appropriate solver
    #
    if (c_ops and len(c_ops) > 0) or not isket(rho0):
        #
        # 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
                return _mesolve_const(H, rho0, tlist, c_ops, expt_ops, args,
                                      options)
            elif n_str > 0:
                # constant hamiltonian but time-dependent collapse operators in list string format
                return _mesolve_list_str_td([H], rho0, tlist, c_ops, expt_ops,
                                            args, options)
            elif n_func > 0:
                # constant hamiltonian but time-dependent collapse operators in list function format
                return _mesolve_list_func_td([H], rho0, tlist, c_ops, expt_ops,
                                             args, options)

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

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

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

    else:
        #
        # no collapse operators: unitary dynamics
        #
        if n_func > 0:
            return _wfsolve_list_func_td(H, rho0, tlist, expt_ops, args,
                                         options)
        elif n_str > 0:
            return _wfsolve_list_str_td(H, rho0, tlist, expt_ops, args,
                                        options)
        elif isinstance(H, types.FunctionType):
            return _wfsolve_func_td(H, rho0, tlist, expt_ops, args, options)
        else:
            return _wfsolve_const(H, rho0, tlist, expt_ops, args, options)
Ejemplo n.º 12
0
def bloch_redfield_solve(R, ekets, rho0, tlist, e_ops=[], options=None):
    """
    Evolve the ODEs defined by Bloch-Redfield master equation. The 
    Bloch-Redfield tensor can be calculated by the function
    :func:`bloch_redfield_tensor`.
   
    Parameters
    ----------
    
    R : :class:`qutip.Qobj`
        Bloch-Redfield tensor.

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

    rho0 : :class:`qutip.Qobj`
        Initial density matrix.
                
    tlist : *list* / *array*    
        List of times for :math:`t`.
        
    e_ops : list of :class:`qutip.Qobj` / callback function
        List of operators for which to evaluate expectation values.
    
    options : :class:`qutip.Qdeoptions`
        Options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.Odedata`

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

    """

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

    if options.tidy:
        R.tidyup()

    #
    # check initial state
    #
    if isket(rho0):
        # Got a wave function as initial state: convert to density matrix.
        rho0 = rho0 * rho0.dag()
       
    #
    # prepare output array
    # 
    n_e_ops  = len(e_ops)
    n_tsteps = len(tlist)
    dt       = tlist[1]-tlist[0]

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


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

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

    #
    # start evolution
    #
    rho = Qobj(rho0)

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

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

        r.integrate(r.t + dt)
        t_idx += 1
          
    return result_list
Ejemplo n.º 13
0
def brmesolve(H,
              psi0,
              tlist,
              c_ops,
              e_ops=[],
              spectra_cb=[],
              args={},
              options=Odeoptions()):
    """
    Solve the dynamics for the system using the Bloch-Redfeild master equation.

    .. note:: 
    
        This solver does not currently support time-dependent Hamiltonian or
        collapse operators.
   
    Parameters
    ----------
    
    H : :class:`qutip.Qobj`
        system Hamiltonian.
        
    rho0 / psi0: :class:`qutip.Qobj`
        initial density matrix or state vector (ket).
     
    tlist : *list* / *array*    
        list of times for :math:`t`.
        
    c_ops : list of :class:`qutip.Qobj`
        list of collapse operators.
    
    expt_ops : list of :class:`qutip.Qobj` / callback function
        list of operators for which to evaluate expectation values.
     
    args : *dictionary*
        dictionary of parameters for time-dependent Hamiltonians and collapse operators.
     
    options : :class:`qutip.Qdeoptions`
        with options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.Odedata`

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

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

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

    output = Odedata()
    output.times = tlist

    output.expect = bloch_redfield_solve(R, ekets, psi0, tlist, e_ops, options)

    return output
Ejemplo n.º 14
0
def rhs_generate(H,
                 psi0,
                 tlist,
                 c_ops,
                 e_ops,
                 ntraj=500,
                 args={},
                 options=Odeoptions(),
                 solver='me',
                 name=None):
    """
    Used to generate the Cython functions for solving the dynamics of a
    given system before using the parfor function.  
    
    Parameters
    ----------
    H : qobj
        System Hamiltonian.
    psi0 : qobj 
        Initial state vector
    tlist : array_like 
        Times at which results are recorded.
    ntraj : int 
        Number of trajectories to run.
    c_ops : array_like 
        ``list`` or ``array`` of collapse operators.
    e_ops : array_like 
        ``list`` or ``array`` of operators for calculating expectation values.
    args : dict
        Arguments for time-dependent Hamiltonian and collapse operator terms.
    options : Odeoptions
        Instance of ODE solver options.
    solver: str
        String indicating which solver "me" or "mc"
    name: str
        Name of generated RHS
    
    """
    _reset_odeconfig()  #clear odeconfig
    #------------------------
    # GENERATE MCSOLVER DATA
    #------------------------
    if solver == 'mc':
        odeconfig.tlist = tlist
        if isinstance(ntraj, (list, ndarray)):
            odeconfig.ntraj = sort(ntraj)[-1]
        else:
            odeconfig.ntraj = ntraj
        #check for type of time-dependence (if any)
        time_type, h_stuff, c_stuff = _ode_checks(H, c_ops, 'mc')
        h_terms = len(h_stuff[0]) + len(h_stuff[1]) + len(h_stuff[2])
        c_terms = len(c_stuff[0]) + len(c_stuff[1]) + len(c_stuff[2])
        #set time_type for use in multiprocessing
        odeconfig.tflag = time_type
        #check for collapse operators
        if c_terms > 0:
            odeconfig.cflag = 1
        else:
            odeconfig.cflag = 0
        #Configure data
        _mc_data_config(H, psi0, h_stuff, c_ops, c_stuff, args, e_ops, options)
        os.environ['CFLAGS'] = '-w'
        import pyximport
        pyximport.install(setup_args={'include_dirs': [numpy.get_include()]})
        if odeconfig.tflag in array([1, 11]):
            code = compile(
                'from ' + odeconfig.tdname +
                ' import cyq_td_ode_rhs,col_spmv,col_expect', '<string>',
                'exec')
            exec(code)
            odeconfig.tdfunc = cyq_td_ode_rhs
            odeconfig.colspmv = col_spmv
            odeconfig.colexpect = col_expect
        else:
            code = compile(
                'from ' + odeconfig.tdname + ' import cyq_td_ode_rhs',
                '<string>', 'exec')
            exec(code)
            odeconfig.tdfunc = cyq_td_ode_rhs
        try:
            os.remove(odeconfig.tdname + ".pyx")
        except:
            print("Error removing pyx file.  File not found.")

    #------------------------
    # GENERATE MESOLVER STUFF
    #------------------------
    elif solver == 'me':

        odeconfig.tdname = "rhs" + str(odeconfig.cgen_num)
        cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args)
        cgen.generate(odeconfig.tdname + ".pyx")
        os.environ['CFLAGS'] = '-O3 -w'
        import pyximport
        pyximport.install(setup_args={'include_dirs': [numpy.get_include()]})
        code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs',
                       '<string>', 'exec')
        exec(code)
        odeconfig.tdfunc = cyq_td_ode_rhs
Ejemplo n.º 15
0
def rhs_generate(H,c_ops,args={},options=Odeoptions(),name=None):
    """
    Generates the Cython functions needed for solving the dynamics of a
    given system using the mesolve function inside a parfor loop.  
    
    Parameters
    ----------
    H : qobj
        System Hamiltonian.
    c_ops : list
        ``list`` of collapse operators.
    args : dict
        Arguments for time-dependent Hamiltonian and collapse operator terms.
    options : Odeoptions
        Instance of ODE solver options.
    name: str
        Name of generated RHS
    
    Notes
    -----
    Using this function with any solver other than the mesolve function
    will result in an error.
    
    """
    _reset_odeconfig() #clear odeconfig
    if name:
        odeconfig.tdname=name
    else:
        odeconfig.tdname="rhs"+str(odeconfig.cgen_num)
    
    n_op = len(c_ops)

    Lconst = 0        

    Ldata = []
    Linds = []
    Lptrs = []
    Lcoeff = []
    
    # loop over all hamiltonian terms, convert to superoperator form and 
    # add the data of sparse matrix represenation to 
    for h_spec in H:
        if isinstance(h_spec, Qobj):
            h = h_spec
            Lconst += -1j*(spre(h) - spost(h)) 
        
        elif isinstance(h_spec, list): 
            h = h_spec[0]
            h_coeff = h_spec[1]

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

            Ldata.append(L.data.data)
            Linds.append(L.data.indices)
            Lptrs.append(L.data.indptr)
            Lcoeff.append(h_coeff)
            
        else:
            raise TypeError("Incorrect specification of time-dependent " + 
                             "Hamiltonian (expected string format)")
    
    # loop over all collapse operators        
    for c_spec in c_ops:
        if isinstance(c_spec, Qobj):
            c = c_spec
            cdc = c.dag() * c
            Lconst += spre(c) * spost(c.dag()) - 0.5 * spre(cdc) - 0.5 * spost(cdc) 

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

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

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

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

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


    # the total number of liouvillian terms (hamiltonian terms + collapse operators)      
    n_L_terms = len(Ldata)
    
    cgen=Codegen(h_terms=n_L_terms,h_tdterms=Lcoeff, args=args)
    cgen.generate(odeconfig.tdname+".pyx")
    os.environ['CFLAGS'] = '-O3 -w'
    import pyximport
    pyximport.install(setup_args={'include_dirs':[numpy.get_include()]})
    code = compile('from '+odeconfig.tdname+' import cyq_td_ode_rhs', '<string>', 'exec')
    exec(code)
    odeconfig.tdfunc=cyq_td_ode_rhs
    try:
        os.remove(odeconfig.tdname+".pyx")
    except:
        pass
            
            
            
            
            
            
Ejemplo n.º 16
0
def fmmesolve(H,
              rho0,
              tlist,
              c_ops,
              e_ops=[],
              spectra_cb=[],
              T=None,
              args={},
              options=Odeoptions()):
    """
    Solve the dynamics for the system using the Floquet-Markov master equation.  

    .. note:: 
    
        This solver currently does not support multiple collapse operators.
   
    Parameters
    ----------
    
    H : :class:`qutip.Qobj`
        system Hamiltonian.
        
    rho0 / psi0 : :class:`qutip.Qobj`
        initial density matrix or state vector (ket).
     
    tlist : *list* / *array*    
        list of times for :math:`t`.
        
    c_ops : list of :class:`qutip.Qobj`
        list of collapse operators.
    
    e_ops : list of :class:`qutip.Qobj` / callback function
        list of operators for which to evaluate expectation values.

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

    T : float
        The period of the time-dependence of the hamiltonian. The default value
        'None' indicates that the 'tlist' spans a single period of the driving.
     
    args : *dictionary*
        dictionary of parameters for time-dependent Hamiltonians and collapse operators.

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

        >>> temperature = 25e-3 # unit K
        >>> h = 6.626e-34
        >>> kB = 1.38e-23
        >>> args['w_th'] = temperature * (kB / h) * 2 * pi * 1e-9
     
    options : :class:`qutip.Odeoptions`
        options for the ODE solver.

    Returns
    -------

    output : :class:`qutip.Odedata`

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

    if T == None:
        T = max(tlist)

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

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

    kmax = 1

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

    # get w_th from args if it exists
    if args.has_key('w_th'):
        w_th = args['w_th']
    else:
        w_th = 0

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

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

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

    return floquet_markov_mesolve(R, f_modes_0, rho0, tlist, e_ops, options)
Ejemplo n.º 17
0
def floquet_markov_mesolve(R, ekets, rho0, tlist, e_ops, options=None):
    """
    Solve the dynamics for the system using the Floquet-Markov master equation.   
    """

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

    if opt.tidy:
        R.tidyup()

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

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

    output = Odedata()
    output.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:
            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 and the e_ops opterators to the
    # eigenbasis: from computational basis to the floquet basis
    #
    if ekets != None:
        rho0 = rho0.transform(ekets, True)
        if isinstance(e_ops, list):
            for n in np.arange(len(e_ops)):  # not working
                e_ops[n] = e_ops[n].transform(ekets)  #

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

    #
    # start evolution
    #
    rho = Qobj(rho0)

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

        rho.data = vec2mat(r.y)

        if expt_callback:
            # use callback method
            e_ops(t, Qobj(rho))
        else:
            # calculate all the expectation values, or output rho if no operators
            if n_expt_op == 0:
                output.states.append(Qobj(rho))  # copy psi/rho
            else:
                for m in range(0, n_expt_op):
                    output.expect[m][t_idx] = expect(e_ops[m],
                                                     rho)  # basis OK?

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

    return output
Ejemplo n.º 18
0
def mesolve(H, rho0, tlist, c_ops, expt_ops, args={}, options=None):
    """
    Master equation evolution of a density matrix for a given Hamiltonian.

    Evolve the state vector or density matrix (`rho0`) using a given Hamiltonian
    (`H`) and an [optional] set of collapse operators (`c_op_list`),
    by integrating the set of ordinary differential equations that define the
    system. In the absense of collase operators the system is evolved according
    to the unitary evolution of the Hamiltonian.
    
    The output is either the state vector at arbitrary points in time (`tlist`),
    or the expectation values of the supplied operators (`expt_ops`). If 
    expt_ops is a callback function, it is invoked for each time in `tlist` 
    with time and the state as arguments, and the function does not use any
    return values.

    **Time-dependent operators**

    For problems with time-dependent problems `H` and `c_ops` can be callback
    functions that takes two arguments, time and `args`, and returns the 
    Hamiltonian or Liuovillian for the system at that point in time
    (*callback format*). 
    
    Alternatively, `H` and `c_ops` can be a specified in a nested-list format
    where each element in the list is a list of length 2, containing an
    operator (:class:`qutip.Qobj`) at the first element and where the 
    second element is either a string (*list string format*) or a callback
    function (*list callback format*) that evaluates to the time-dependent
    coefficient for the corresponding operator.
    
    
    *Examples*
    
        H = [[H0, 'sin(w*t)'], [H1, 'sin(2*w*t)']]
        
        H = [[H0, f0_t], [H1, f1_t]]
         
        where f0_t and f1_t are python functions with signature f_t(t, args).
    
    In the *list string format* and *list callback format*, the string
    expression and the callback function must evaluate to a real or complex
    number (coefficient for the corresponding operator).
    
    In all cases of time-dependent operators, `args` is a dictionary of
    parameters that is used when evaluating operators. It is passed to the
    callback functions as second argument
   
   
    .. note:: 
    
        On using callback function: mesolve transforms all :class:`qutip.Qobj`
        objects to sparse matrices before handing the problem to the integrator
        function. In order for your callback function to work correctly, pass
        all :class:`qutip.Qobj` objects that are used in constructing the
        Hamiltonian via args. odesolve will check for :class:`qutip.Qobj` in
        `args` and handle the conversion to sparse matrices. All other
        :class:`qutip.Qobj` objects that are not passed via `args` will be
        passed on to the integrator to scipy who will raise an NotImplemented
        exception.   
   
    Parameters
    ----------
    
    H : :class:`qutip.Qobj`
        system Hamiltonian, or a callback function for time-dependent Hamiltonians.
        
    rho0 : :class:`qutip.Qobj`
        initial density matrix or state vector (ket).
     
    tlist : *list* / *array*    
        list of times for :math:`t`.
        
    c_ops : list of :class:`qutip.Qobj`
        list of collapse operators.
    
    expt_ops : list of :class:`qutip.Qobj` / callback function
        list of operators for which to evaluate expectation values.
     
    args : *dictionary*
        dictionary of parameters for time-dependent Hamiltonians and collapse operators.
     
    options : :class:`qutip.Qdeoptions`
        with options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.Odedata`

        An instance of the class :class:`qutip.Odedata`, which contains either
        an *array* of expectation values for the times specified by `tlist`, or
        an *array* or state vectors or density matrices corresponding to the
        times in `tlist` [if `expt_ops` is an empty list], or
        nothing if a callback function was given inplace of operators for
        which to calculate the expectation values.
    
    """
    
    # check for type (if any) of time-dependent inputs            
    n_const,n_func,n_str=_ode_checks(H,c_ops)

    if options == None:
        _reset_odeconfig()
        options = Odeoptions()
        options.max_step = max(tlist)/10.0 # take at least 10 steps.
    #
    # dispatch the appropriate solver
    #         
    if (c_ops and len(c_ops) > 0) or not isket(rho0):
        #
        # 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
                return mesolve_const(H, rho0, tlist, c_ops, expt_ops, args, options)
            elif n_str > 0:
                # constant hamiltonian but time-dependent collapse operators in list string format
                return mesolve_list_str_td([H], rho0, tlist, c_ops, expt_ops, args, options)     
            elif n_func > 0:
                # constant hamiltonian but time-dependent collapse operators in list function format
                return mesolve_list_func_td([H], rho0, tlist, c_ops, expt_ops, args, options)     
        
        if isinstance(H, FunctionType):
            # old style time-dependence: must have constant collapse operators
            if n_str > 0: # or n_func > 0:
                raise TypeError("Incorrect format: function-format Hamiltonian cannot be mixed with time-dependent collapse operators.")
            else:
                return mesolve_func_td(H, rho0, tlist, c_ops, expt_ops, args, options)
        
        if isinstance(H, list):
            # determine if we are dealing with list of [Qobj, string] or [Qobj, function]
            # style time-dependences (for pure python and cython, respectively)
            if n_func > 0:
                return mesolve_list_func_td(H, rho0, tlist, c_ops, expt_ops, args, options)
            else:
                return mesolve_list_str_td(H, rho0, tlist, c_ops, expt_ops, args, options)
                                   
        raise TypeError("Incorrect specification of Hamiltonian or collapse operators.")

    else:
        #
        # no collapse operators: unitary dynamics
        #
        if n_func > 0:
            return wfsolve_list_func_td(H, rho0, tlist, expt_ops, args, options)
        elif n_str > 0:
            return wfsolve_list_str_td(H, rho0, tlist, expt_ops, args, options)
        elif isinstance(H, FunctionType):
            return wfsolve_func_td(H, rho0, tlist, expt_ops, args, options)
        else:
            return wfsolve_const(H, rho0, tlist, expt_ops, args, options)
Ejemplo n.º 19
0
def mcsolve(H,
            psi0,
            tlist,
            c_ops,
            e_ops,
            ntraj=500,
            args={},
            options=Odeoptions()):
    """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 Odeoptions 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_op_list=[C0,[C1,C1_coeff]]
    
        args={'a':A,'w':W}
    
    or in String (Cython) format we could write::
    
        H=[H0,[H1,'sin(w*t)']]
    
        c_op_list=[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 : qobj
        System Hamiltonian.
    psi0 : qobj 
        Initial state vector
    tlist : array_like 
        Times at which results are recorded.
    ntraj : int 
        Number of trajectories to run.
    c_ops : array_like 
        ``list`` or ``array`` of collapse operators.
    e_ops : array_like 
        ``list`` or ``array`` of operators for calculating expectation values.
    args : dict
        Arguments for time-dependent Hamiltonian and collapse operator terms.
    options : Odeoptions
        Instance of ODE solver options.
    
    Returns
    -------
    results : Odedata    
        Object storing all results from simulation.
        
    """
    if psi0.type != 'ket':
        raise Exception("Initial state must be a state vector.")
    odeconfig.options = options
    #set num_cpus to the value given in qutip.settings if none in Odeoptions
    if not odeconfig.options.num_cpus:
        odeconfig.options.num_cpus = qutip.settings.num_cpus
    #set initial value data
    if options.tidy:
        odeconfig.psi0 = psi0.tidyup(options.atol).full()
    else:
        odeconfig.psi0 = psi0.full()
    odeconfig.psi0_dims = psi0.dims
    odeconfig.psi0_shape = psi0.shape
    #set general items
    odeconfig.tlist = tlist
    if isinstance(ntraj, (list, ndarray)):
        odeconfig.ntraj = sort(ntraj)[-1]
    else:
        odeconfig.ntraj = ntraj
    #----

    #----------------------------------------------
    # SETUP ODE DATA IF NONE EXISTS OR NOT REUSING
    #----------------------------------------------
    if (not options.rhs_reuse) or (not odeconfig.tdfunc):
        #reset odeconfig collapse and time-dependence flags to default values
        _reset_odeconfig()

        #check for type of time-dependence (if any)
        time_type, h_stuff, c_stuff = _ode_checks(H, c_ops, 'mc')
        h_terms = len(h_stuff[0]) + len(h_stuff[1]) + len(h_stuff[2])
        c_terms = len(c_stuff[0]) + len(c_stuff[1]) + len(c_stuff[2])
        #set time_type for use in multiprocessing
        odeconfig.tflag = time_type

        #-Check for PyObjC on Mac platforms
        if sys.platform == 'darwin':
            try:
                import Foundation
            except:
                odeconfig.options.gui = False

        #check if running in iPython and using Cython compiling (then no GUI to work around error)
        if odeconfig.options.gui and odeconfig.tflag in array([1, 10, 11]):
            try:
                __IPYTHON__
            except:
                pass
            else:
                odeconfig.options.gui = False
        if qutip.settings.qutip_gui == "NONE":
            odeconfig.options.gui = False

        #check for collapse operators
        if c_terms > 0:
            odeconfig.cflag = 1
        else:
            odeconfig.cflag = 0

        #Configure data
        _mc_data_config(H, psi0, h_stuff, c_ops, c_stuff, args, e_ops, options)
        if odeconfig.tflag in array([1, 10,
                                     11]):  #compile time-depdendent RHS code
            os.environ['CFLAGS'] = '-w'
            import pyximport
            pyximport.install(
                setup_args={'include_dirs': [numpy.get_include()]})
            if odeconfig.tflag in array([1, 11]):
                code = compile(
                    'from ' + odeconfig.tdname +
                    ' import cyq_td_ode_rhs,col_spmv,col_expect', '<string>',
                    'exec')
                exec(code, globals())
                odeconfig.tdfunc = cyq_td_ode_rhs
                odeconfig.colspmv = col_spmv
                odeconfig.colexpect = col_expect
            else:
                code = compile(
                    'from ' + odeconfig.tdname + ' import cyq_td_ode_rhs',
                    '<string>', 'exec')
                exec(code, globals())
                odeconfig.tdfunc = cyq_td_ode_rhs
            try:
                os.remove(odeconfig.tdname + ".pyx")
            except:
                print("Error removing pyx file.  File not found.")
        elif odeconfig.tflag == 0:
            odeconfig.tdfunc = cyq_ode_rhs
    else:  #setup args for new parameters when rhs_reuse=True and tdfunc is given
        #string based
        if odeconfig.tflag in array([1, 10, 11]):
            if any(args):
                odeconfig.c_args = []
                arg_items = args.items()
                for k in range(len(args)):
                    odeconfig.c_args.append(arg_items[k][1])
        #function based
        elif odeconfig.tflag in array([2, 3, 20, 22]):
            odeconfig.h_func_args = args

    #load monte-carlo class
    mc = MC_class()
    #RUN THE SIMULATION
    mc.run()

    #AFTER MCSOLVER IS DONE --------------------------------------

    #-------COLLECT AND RETURN OUTPUT DATA IN ODEDATA OBJECT --------------#
    output = Odedata()
    output.solver = 'mcsolve'
    #state vectors
    if any(mc.psi_out) and odeconfig.options.mc_avg:
        output.states = mc.psi_out
    #expectation values

    if any(
            mc.expect_out
    ) and odeconfig.cflag and odeconfig.options.mc_avg:  #averaging if multiple trajectories
        if isinstance(ntraj, int):
            output.expect = mean(mc.expect_out, axis=0)
        elif isinstance(ntraj, (list, ndarray)):
            output.expect = []
            for num in ntraj:
                expt_data = mean(mc.expect_out[:num], axis=0)
                data_list = []
                if any([op.isherm == False for op in e_ops]):
                    for k in range(len(e_ops)):
                        if e_ops[k].isherm:
                            data_list.append(real(expt_data[k]))
                        else:
                            data_list.append(expt_data[k])
                else:
                    data_list = [data for data in expt_data]
                output.expect.append(data_list)
    else:  #no averaging for single trajectory or if mc_avg flag (Odeoptions) is off
        output.expect = mc.expect_out

    #simulation parameters
    output.times = odeconfig.tlist
    output.num_expect = odeconfig.e_num
    output.num_collapse = odeconfig.c_num
    output.ntraj = odeconfig.ntraj
    output.col_times = mc.collapse_times_out
    output.col_which = mc.which_op_out
    return output
Ejemplo n.º 20
0
def propagator(H, t, c_op_list, H_args=None, opt=None):
    """
    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 
        Hamiltonian
        
    t : float 
        Time.
        
    c_op_list : list 
        List of qobj collapse operators.
        
    Other Parameters
    ----------------
    H_args : list/array/dictionary 
        Parameters to callback functions for time-dependent Hamiltonians.
    
    Returns
    -------
     a : qobj 
        Instance representing the propagator :math:`U(t)`.
    
    """

    if opt == None:
        opt = Odeoptions()
        opt.rhs_reuse = True

    if len(c_op_list) == 0:
        # calculate propagator for the wave function

        if isinstance(H, FunctionType):
            H0 = H(0.0, H_args)
            N = H0.shape[0]
        elif isinstance(H, list):
            if isinstance(H[0], list):
                H0 = H[0][0]
                N = H0.shape[0]            
            else:
                H0 = H[0]
                N = H0.shape[0] 
        else:
            N = H.shape[0]

        u = zeros([N, N], dtype=complex)

        for n in range(0, N):
            psi0 = basis(N, n)
            output = mesolve(H, psi0, [0, t], [], [], H_args, opt)
            u[:,n] = output.states[1].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], [], [], H_args, opt)
        #for n in range(0, N):
        #    u[:,n] = psi_t_list[n][1].full().T

    else:
        # calculate the propagator for the vector representation of the 
        # density matrix

        if isinstance(H, FunctionType):
            H0 = H(0.0, H_args)
            N = H0.shape[0]
        elif isinstance(H, list):
            if isinstance(H[0], list):
                H0 = H[0][0]
                N = H0.shape[0]            
            else:
                H0 = H[0]
                N = H0.shape[0]            
        else:
            N = H.shape[0]

        u = zeros([N*N, N*N], dtype=complex)
        
        for n in range(0, N*N):
            psi0  = basis(N*N, n)
            rho0  = Qobj(vec2mat(psi0.full()))
            output = mesolve(H, rho0, [0, t], c_op_list, [], H_args, opt)
            u[:,n] = mat2vec(output.states[1].full()).T

    return Qobj(u)
Ejemplo n.º 21
0
def odesolve(H, rho0, tlist, c_op_list, expt_ops, H_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 (`expt_ops`). 

    For problems with time-dependent Hamiltonians, `H` can be a callback function
    that takes two arguments, time and `H_args`, and returns the Hamiltonian
    at that point in time. `H_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.
    
    expt_ops : list of :class:`qutip.Qobj` / callback function
        list of operators for which to evaluate expectation values.
     
    H_args : *dictionary*
        dictionary of parameters for time-dependent Hamiltonians and collapse operators.
     
    options : :class:`qutip.Qdeoptions`
        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 H_args. odesolve will check for :class:`qutip.Qobj` in
    `H_args` and handle the conversion to sparse matrices. All other
    :class:`qutip.Qobj` objects that are not passed via `H_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.
        
    """

    if options == None:
        options = Odeoptions()

    if (c_op_list and len(c_op_list) > 0) or not isket(rho0):
        if isinstance(H, list):
            output = _mesolve_list_td(H, rho0, tlist, c_op_list, expt_ops,
                                      H_args, options)
        if isinstance(H, types.FunctionType):
            output = _mesolve_func_td(H, rho0, tlist, c_op_list, expt_ops,
                                      H_args, options)
        else:
            output = _mesolve_const(H, rho0, tlist, c_op_list, expt_ops,
                                    H_args, options)
    else:
        if isinstance(H, list):
            output = _wfsolve_list_td(H, rho0, tlist, expt_ops, H_args,
                                      options)
        if isinstance(H, types.FunctionType):
            output = _wfsolve_func_td(H, rho0, tlist, expt_ops, H_args,
                                      options)
        else:
            output = _wfsolve_const(H, rho0, tlist, expt_ops, H_args, options)

    if len(expt_ops) > 0:
        return output.expect
    else:
        return output.states