Esempio n. 1
0
def _smesolve_single_trajectory(L, dt, tlist, N_store, N_substeps, rho_t,
                                A_ops, e_ops, data, rhs, d1, d2):
    """
    Internal function. See smesolve.
    """

    dW = np.sqrt(dt) * scipy.randn(len(A_ops), N_store, N_substeps)

    states_list = []

    for t_idx, t in enumerate(tlist):

        if e_ops:
            for e_idx, e in enumerate(e_ops):
                # XXX: need to keep hilbert space structure
                data.expect[e_idx, t_idx] += expect(e, Qobj(vec2mat(rho_t)))
        else:
            states_list.append(Qobj(rho_t))  # dito

        for j in range(N_substeps):

            drho_t = spmv(L.data.data, L.data.indices, L.data.indptr,
                          rho_t) * dt

            for a_idx, A in enumerate(A_ops):

                drho_t += rhs(L.data, rho_t, A, dt, dW[a_idx, t_idx, j], d1,
                              d2)

            rho_t += drho_t

    return states_list
Esempio n. 2
0
def floquet_master_equation_tensor(Alist, f_energies):
    """
    Construct a tensor that represents the master equation in the floquet
    basis (with constant Hamiltonian and collapse operators).
    
    Simplest RWA approximation [Grifoni et al, Phys.Rep. 304 229 (1998)]

    Parameters
    ----------
    
    Alist : list
        A list of Floquet-Markov master equation rate matrices.

    f_energies : array
        The Floquet energies.
                
    Returns
    -------

    output : array

        The Floquet-Markov master equation tensor `R`.

    """

    if isinstance(Alist, list):
        # Alist can be a list of rate matrices corresponding
        # to different operators that couple to the environment
        N, M = np.shape(Alist[0])
    else:
        # or a simple rate matrix, in which case we put it in a list
        Alist = [Alist]
        N, M = np.shape(Alist[0])

    R = Qobj(scipy.sparse.csr_matrix((N * N, N * N)), [[N, N], [N, N]],
             [N * N, N * N])

    R.data = R.data.tolil()
    for I in range(N * N):
        a, b = vec2mat_index(N, I)
        for J in range(N * N):
            c, d = vec2mat_index(N, J)

            R.data[I, J] = -1.0j * (f_energies[a] -
                                    f_energies[b]) * (a == c) * (b == d)

            for A in Alist:
                s1 = s2 = 0
                for n in range(N):
                    s1 += A[a, n] * (n == c) * (n == d) - A[n, a] * (
                        a == c) * (a == d)
                    s2 += (A[n, a] + A[n, b]) * (a == c) * (b == d)

                dR = (a == b) * s1 - 0.5 * (1 - (a == b)) * s2

                if dR != 0.0:
                    R.data[I, J] += dR

    R.data = R.data.tocsr()
    return R
Esempio n. 3
0
def propagator_steadystate(U):
    """Find the steady state for successive applications of the propagator
    :math:`U`.
    
    Parameters
    ----------
    U : qobj 
        Operator representing the propagator.
    
    Returns
    ------- 
    a : qobj
        Instance representing the steady-state density matrix.
    
    """

    evals,evecs = la.eig(U.full())

    ev_min, ev_idx = _get_min_and_index(abs(evals-1.0))

    N = int(np.sqrt(len(evals)))
    evecs = evecs.T
    rho = Qobj(vec2mat(evecs[ev_idx]))
    rho = rho * (1.0/rho.tr())
    rho = 0.5*(rho+rho.dag()) #make sure rho is herm
    return rho
Esempio n. 4
0
def _ssesolve_single_trajectory(H, dt, tlist, N_store, N_substeps, psi_t,
                                A_ops, e_ops, data, rhs, d1, d2):
    """
    Internal function. See ssesolve.
    """
    #if debug: print inspect.stack()[0][3]

    dW = np.sqrt(dt) * scipy.randn(len(A_ops), N_store, N_substeps)

    states_list = []

    for t_idx, t in enumerate(tlist):

        if e_ops:
            for e_idx, e in enumerate(e_ops):
                data.expect[e_idx, t_idx] += expect(e, Qobj(psi_t))
        else:
            states_list.append(Qobj(psi_t))

        for j in range(N_substeps):

            dpsi_t = (-1.0j * dt) * (H.data * psi_t)

            for a_idx, A in enumerate(A_ops):

                dpsi_t += rhs(H.data, psi_t, A, dt, dW[a_idx, t_idx, j], d1,
                              d2)

            # increment and renormalize the wave function
            psi_t += dpsi_t
            psi_t /= norm(psi_t, 2)

    return states_list
Esempio n. 5
0
def floquet_master_equation_tensor(Alist, f_energies):
    """
    Construct a tensor that represents the master equation in the floquet
    basis (with constant Hamiltonian and collapse operators).
    
    Simplest RWA approximation [Grifoni et al, Phys.Rep. 304 229 (1998)]

    Parameters
    ----------
    
    Alist : list
        A list of Floquet-Markov master equation rate matrices.

    f_energies : array
        The Floquet energies.
                
    Returns
    -------

    output : array

        The Floquet-Markov master equation tensor `R`.

    """

    if isinstance(Alist, list):
        # Alist can be a list of rate matrices corresponding
        # to different operators that couple to the environment
        N, M = np.shape(Alist[0])
    else:
        # or a simple rate matrix, in which case we put it in a list
        Alist = [Alist]
        N, M = np.shape(Alist[0])
      
    R = Qobj(scipy.sparse.csr_matrix((N*N,N*N)), [[N,N], [N,N]], [N*N,N*N])

    R.data=R.data.tolil()      
    for I in range(N*N):
        a,b = vec2mat_index(N, I)
        for J in range(N*N):
            c,d = vec2mat_index(N, J)

            R.data[I,J] = - 1.0j * (f_energies[a]-f_energies[b]) * (a == c) * (b == d)
                    
            for A in Alist:               
                s1 = s2 = 0
                for n in range(N):
                    s1 += A[a,n] * (n == c) * (n == d) - A[n,a] * (a == c) * (a == d)
                    s2 += (A[n,a] + A[n,b]) * (a == c) * (b == d)
                       
                dR = (a == b) * s1 - 0.5 * (1 - (a == b)) * s2
                            
                if dR != 0.0:
                    R.data[I,J] += dR

    R.data=R.data.tocsr()
    return R                   
Esempio n. 6
0
def swap(mask=None):
    """Quantum object representing the SWAP gate.
    
    Returns
    -------
    swap_gate : qobj
        Quantum object representation of SWAP gate
    
    Examples
    --------
    >>> swap()
    Quantum object: dims = [[2, 2], [2, 2]], shape = [4, 4], type = oper, isHerm = True
    Qobj data = 
    [[ 1.+0.j  0.+0.j  0.+0.j  0.+0.j]
     [ 0.+0.j  0.+0.j  1.+0.j  0.+0.j]
     [ 0.+0.j  1.+0.j  0.+0.j  0.+0.j]
     [ 0.+0.j  0.+0.j  0.+0.j  1.+0.j]]
         
    """
    if mask is None:
        uu = qstate('uu')
        ud = qstate('ud')
        du = qstate('du')
        dd = qstate('dd')
        Q = uu * uu.dag() + ud * du.dag() + du * ud.dag() + dd * dd.dag()
        return Qobj(Q)
    else:
        if sum(mask) != 2:
            raise ValueError("mask must only have two ones, rest zeros")

        dims = [2] * len(mask)
        idx, = where(mask)
        N = prod(dims)
        data = sp.lil_matrix((N, N))

        for s1 in state_number_enumerate(dims):
            i1 = state_number_index(dims, s1)

            if s1[idx[0]] == s1[idx[1]]:
                i2 = i1
            else:
                s2 = array(s1).copy()
                s2[idx[0]], s2[idx[1]] = s2[idx[1]], s2[idx[0]]
                i2 = state_number_index(dims, s2)

            data[i1, i2] = 1

        return Qobj(data, dims=[dims, dims], shape=[N, N])
Esempio n. 7
0
def ket2dm(Q):
    """Takes input ket or bra vector and returns density matrix 
    formed by outer product.
    
    Parameters
    ----------
    Q : qobj    
        Ket or bra type quantum object.
    
    Returns
    -------
    dm : qobj    
        Density matrix formed by outer product of `Q`.
    
    Examples
    --------    
    >>> x=basis(3,2)
    >>> ket2dm(x)
    Quantum object: dims = [[3], [3]], shape = [3, 3], type = oper, isHerm = True
    Qobj data = 
    [[ 0.+0.j  0.+0.j  0.+0.j]
     [ 0.+0.j  0.+0.j  0.+0.j]
     [ 0.+0.j  0.+0.j  1.+0.j]]
         
    """
    if Q.type=='ket':
        out=Q*Q.dag()
    elif Q.type=='bra':
        out=Q.dag()*Q
    else:
        raise TypeError("Input is not a ket or bra vector.")
    return Qobj(out)
Esempio n. 8
0
def thermal_dm(N, n):
    """Density matrix for a thermal state of n particles

    Parameters
    ----------
    N : int 
        Number of basis states in Hilbert space.
    
    n : float 
        Expectation value for number of particles in thermal state.
    
    Returns
    -------
    dm : qobj
        Thermal state density matrix.
    
    Examples
    --------
    >>> thermal_dm(5,1)
    Quantum object: dims = [[5], [5]], shape = [5, 5], type = oper, isHerm = True
    Qobj data = 
    [[ 0.50000+0.j  0.00000+0.j  0.00000+0.j  0.00000+0.j  0.00000+0.j]
     [ 0.00000+0.j  0.25000+0.j  0.00000+0.j  0.00000+0.j  0.00000+0.j]
     [ 0.00000+0.j  0.00000+0.j  0.12500+0.j  0.00000+0.j  0.00000+0.j]
     [ 0.00000+0.j  0.00000+0.j  0.00000+0.j  0.06250+0.j  0.00000+0.j]
     [ 0.00000+0.j  0.00000+0.j  0.00000+0.j  0.00000+0.j  0.03125+0.j]]
    
    """

    i=arange(N)  
    rm = sp.spdiags((1.0+n)**(-1.0)*(n/(1.0+n))**(i),0,N,N,format='csr') #populates diagonal terms (the only nonzero terms in matrix)
    return Qobj(rm)
Esempio n. 9
0
def phasegate(theta):
    """
    Returns quantum object representing the phase shift gate.
    
    Parameters
    ----------
    theta : float
        Phase rotation angle.
    
    Returns
    -------
    phase_gate : qobj
        Quantum object representation of phase shift gate.
    
    Examples
    --------    
    >>> phasegate(pi/4)
    Quantum object: dims = [[2], [2]], shape = [2, 2], type = oper, isHerm = False
    Qobj data = 
    [[ 1.00000000+0.j          0.00000000+0.j        ]
     [ 0.00000000+0.j          0.70710678+0.70710678j]]
        
    """
    u = qstate('u')
    d = qstate('d')
    Q = d * d.dag() + (exp(1.0j * theta) * u * u.dag())
    return Qobj(Q)
Esempio n. 10
0
def num(N):
    """Quantum object for number operator.
    
    Parameters
    ----------
    N : int 
        The dimension of the Hilbert space.
    
    Returns
    -------
    oper: qobj
        Qobj for number operator.
    
    Examples
    --------
    >>> num(4)
    Quantum object: dims = [[4], [4]], shape = [4, 4], type = oper, isHerm = True
    Qobj data = 
    [[0 0 0 0]
     [0 1 0 0]
     [0 0 2 0]
     [0 0 0 3]]
    
    """
    data = sp.spdiags(np.arange(N), 0, N, N, format='csr')
    return Qobj(data)
Esempio n. 11
0
def qeye(N):
    """Identity operator
    
    Parameters
    ----------
    N : int 
        Dimension of Hilbert space.
    
    Returns
    ------- 
    oper : qobj    
        Identity operator Qobj.
    
    Examples
    --------    
    >>> qeye(3)
    Quantum object: dims = [[3], [3]], shape = [3, 3], type = oper, isHerm = True
    Qobj data = 
    [[ 1.  0.  0.]
     [ 0.  1.  0.]
     [ 0.  0.  1.]]  
    
    """
    N = int(N)
    if (not isinstance(N, int)) or N < 0:  #check if N is int and N>0
        raise ValueError("N must be integer N>=0")
    return Qobj(sp.eye(N, N, dtype=complex, format='csr'))
Esempio n. 12
0
def create(N):
    '''Creation (raising) operator.
    
    Parameters
    ----------
    N : int 
        Dimension of Hilbert space.
    
    Returns
    -------
    oper : qobj
        Qobj for raising operator.
    
    Examples
    --------    
    >>> create(4)
    Quantum object: dims = [[4], [4]], shape = [4, 4], type = oper, isHerm = False
    Qobj data = 
    [[ 0.00000000+0.j  0.00000000+0.j  0.00000000+0.j  0.00000000+0.j]
     [ 1.00000000+0.j  0.00000000+0.j  0.00000000+0.j  0.00000000+0.j]
     [ 0.00000000+0.j  1.41421356+0.j  0.00000000+0.j  0.00000000+0.j]
     [ 0.00000000+0.j  0.00000000+0.j  1.73205081+0.j  0.00000000+0.j]]
    
    '''
    if not isinstance(N, int):  #raise error if N not integer
        raise ValueError("Hilbert space dimension must be integer value")
    qo = destroy(N)  #create operator using destroy function
    qo.data = qo.data.T  #transpsoe data in Qobj
    return Qobj(qo)
Esempio n. 13
0
def cnot():
    """
    Quantum object representing the CNOT gate.
    
    Returns
    -------
    cnot_gate : qobj
        Quantum object representation of CNOT gate
    
    Examples
    --------  
    >>> cnot()
    Quantum object: dims = [[2, 2], [2, 2]], shape = [4, 4], type = oper, isHerm = True
    Qobj data = 
        [[ 1.+0.j  0.+0.j  0.+0.j  0.+0.j]
         [ 0.+0.j  1.+0.j  0.+0.j  0.+0.j]
         [ 0.+0.j  0.+0.j  0.+0.j  1.+0.j]
         [ 0.+0.j  0.+0.j  1.+0.j  0.+0.j]]
    
    """
    uu = qstate('uu')
    ud = qstate('ud')
    du = qstate('du')
    dd = qstate('dd')
    Q = dd * dd.dag() + du * du.dag() + uu * ud.dag() + ud * uu.dag()
    return Qobj(Q)
Esempio n. 14
0
def toffoli():
    """Quantum object representing the Toffoli gate.
    
    Returns
    -------
    toff_gate : qobj
        Quantum object representation of Toffoli gate.
    
    Examples
    --------    
    >>> toffoli()
    Quantum object: dims = [[2, 2, 2], [2, 2, 2]], shape = [8, 8], type = oper, isHerm = True
    Qobj data = 
        [[ 1.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j]
         [ 0.+0.j  1.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j]
         [ 0.+0.j  0.+0.j  1.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j]
         [ 0.+0.j  0.+0.j  0.+0.j  1.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j]
         [ 0.+0.j  0.+0.j  0.+0.j  0.+0.j  1.+0.j  0.+0.j  0.+0.j  0.+0.j]
         [ 0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  1.+0.j  0.+0.j  0.+0.j]
         [ 0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  1.+0.j]
         [ 0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j  1.+0.j  0.+0.j]]
         
         
    """
    uuu = qstate('uuu')
    uud = qstate('uud')
    udu = qstate('udu')
    udd = qstate('udd')
    duu = qstate('duu')
    dud = qstate('dud')
    ddu = qstate('ddu')
    ddd = qstate('ddd')
    Q = ddd*ddd.dag() + ddu*ddu.dag() + dud*dud.dag() + duu*duu.dag() + \
        udd*udd.dag() + udu*udu.dag() + uuu*uud.dag() + uud*uuu.dag()
    return Qobj(Q)
Esempio n. 15
0
def destroy(N):
    '''Destruction (lowering) operator.
    
    Parameters
    ----------
    N : int
        Dimension of Hilbert space.
    
    Returns
    -------
    oper : qobj    
        Qobj for lowering operator.
    
    Examples
    --------    
    >>> destroy(4)
    Quantum object: dims = [[4], [4]], shape = [4, 4], type = oper, isHerm = False
    Qobj data = 
    [[ 0.00000000+0.j  1.00000000+0.j  0.00000000+0.j  0.00000000+0.j]
     [ 0.00000000+0.j  0.00000000+0.j  1.41421356+0.j  0.00000000+0.j]
     [ 0.00000000+0.j  0.00000000+0.j  0.00000000+0.j  1.73205081+0.j]
     [ 0.00000000+0.j  0.00000000+0.j  0.00000000+0.j  0.00000000+0.j]]
         
    '''
    if not isinstance(N, int):  #raise error if N not integer
        raise ValueError("Hilbert space dimension must be integer value")
    return Qobj(sp.spdiags(np.sqrt(range(0, N)), 1, N, N, format='csr'))
Esempio n. 16
0
def iswap(mask=None):
    """Quantum object representing the iSWAP gate.
    
    Returns
    -------
    iswap_gate : qobj
        Quantum object representation of iSWAP gate
    
    Examples
    --------
    >>> iswap()
    Quantum object: dims = [[2, 2], [2, 2]], shape = [4, 4], type = oper, isHerm = False
    Qobj data =
    [[ 1.+0.j  0.+0.j  0.+0.j  0.+0.j]
     [ 0.+0.j  0.+0.j  0.+1.j  0.+0.j]
     [ 0.+0.j  0.+1.j  0.+0.j  0.+0.j]
     [ 0.+0.j  0.+0.j  0.+0.j  1.+0.j]]
    """
    if mask is None:
        return Qobj(array([[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0],
                           [0, 0, 0, 1]]),
                    dims=[[2, 2], [2, 2]])
    else:
        if sum(mask) != 2:
            raise ValueError("mask must only have two ones, rest zeros")

        dims = [2] * len(mask)
        idx, = where(mask)
        N = prod(dims)
        data = sp.lil_matrix((N, N), dtype=complex)

        for s1 in state_number_enumerate(dims):
            i1 = state_number_index(dims, s1)

            if s1[idx[0]] == s1[idx[1]]:
                i2 = i1
                val = 1.0
            else:
                s2 = s1.copy()
                s2[idx[0]], s2[idx[1]] = s2[idx[1]], s2[idx[0]]
                i2 = state_number_index(dims, s2)
                val = 1.0j

            data[i1, i2] = val

        return Qobj(data, dims=[dims, dims], shape=[N, N])
Esempio n. 17
0
def essolve(H, rho0, tlist, c_op_list, expt_op_list):
    """
    Evolution of a state vector or density matrix (`rho0`) for a given
    Hamiltonian (`H`) and set of collapse operators (`c_op_list`), by expressing
    the ODE as an exponential series. The output is either the state vector at
    arbitrary points in time (`tlist`), or the expectation values of the supplied
    operators (`expt_op_list`). 
   
    Parameters
    ----------
    H : qobj/function_type 
        System Hamiltonian.
    
    rho0 : qobj 
        Initial state density matrix.
    
    tlist : list/array
        ``list`` of times for :math:`t`.
    
    c_op_list : list 
        ``list`` of ``qobj`` collapse operators.
    
    expt_op_list : list
        ``list`` of ``qobj`` operators for which to evaluate expectation values.


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

    
    .. note:: This solver does not support time-dependent Hamiltonians.

    """
    n_expt_op = len(expt_op_list)
    n_tsteps  = len(tlist)

    # Calculate the Liouvillian
    if c_op_list == None or len(c_op_list) == 0:
        L = H
    else:
        L = liouvillian(H, c_op_list)

    es = ode2es(L, rho0)

    # evaluate the expectation values      
    if n_expt_op == 0:
        result_list = [Qobj() for k in range(n_tsteps)]
    else:
        result_list = np.zeros([n_expt_op, n_tsteps], dtype=complex)

    for n in range(0, n_expt_op):
        result_list[n,:] = esval(expect(expt_op_list[n],es),tlist)

    return result_list
Esempio n. 18
0
def basis(N,*args):
    """Generates the vector representation of a Fock state.
	
    Parameters
    ----------
    N : int 
        Number of Fock states in Hilbert space.
    
    args : int 
        ``int`` corresponding to desired number state, defaults
        to 0 if omitted.
    
    Returns
    -------
    state : qobj
      Qobj representing the requested number state ``|args>``.
    
    Examples
    --------        
    >>> basis(5,2)
    Quantum object: dims = [[5], [1]], shape = [5, 1], type = ket
    Qobj data = 
    [[ 0.+0.j]
     [ 0.+0.j]
     [ 1.+0.j]
     [ 0.+0.j]
     [ 0.+0.j]]
         
    Notes
    -----
    
    A subtle incompability with the quantum optics toolbox: In QuTiP::
 
        basis(N, 0) = ground state

    but in qotoolbox::

        basis(N, 1) = ground state
         
    """
    if (not isinstance(N,int)) or N<0:
        raise ValueError("N must be integer N>=0")
    if not any(args):#if no args then assume vacuum state 
        args=0
    if not isinstance(args,int):#if input arg!=0
        if not isinstance(args[0],int):
            raise ValueError("need integer for basis vector index")
        args=args[0]
    if args<0 or args>(N-1): #check if args is within bounds
        raise ValueError("basis vector index need to be in 0=<indx<=N-1")
    bas=sp.lil_matrix((N,1)) #column vector of zeros
    bas[args,0]=1 # 1 located at position args
    bas=bas.tocsr()
    return Qobj(bas)
Esempio n. 19
0
def sqrtiswap():
    """Quantum object representing the square root iSWAP gate.
    
    Returns
    -------
    sqrtiswap_gate : qobj
        Quantum object representation of square root iSWAP gate
    
    Examples
    --------
    >>> sqrtiswap()
    Quantum object: dims = [[2, 2], [2, 2]], shape = [4, 4], type = oper, isHerm = False
    Qobj data =
    [[ 1.00000000+0.j   0.00000000+0.j          0.00000000+0.j          0.00000000+0.j]
     [ 0.00000000+0.j   0.70710678+0.j          0.00000000-0.70710678j  0.00000000+0.j]
     [ 0.00000000+0.j   0.00000000-0.70710678j  0.70710678+0.j          0.00000000+0.j]
     [ 0.00000000+0.j   0.00000000+0.j          0.00000000+0.j          1.00000000+0.j]]    
    """
    return Qobj(array([[1,0,0,0], [0, 1/sqrt(2), -1j/sqrt(2), 0], [0, -1j/sqrt(2), 1/sqrt(2), 0], [0, 0, 0, 1]]), dims=[[2, 2], [2, 2]])
Esempio n. 20
0
def iswap():
    """Quantum object representing the iSWAP gate.
    
    Returns
    -------
    iswap_gate : qobj
        Quantum object representation of iSWAP gate
    
    Examples
    --------
    >>> iswap()
    Quantum object: dims = [[2, 2], [2, 2]], shape = [4, 4], type = oper, isHerm = False
    Qobj data =
    [[ 1.+0.j  0.+0.j  0.+0.j  0.+0.j]
     [ 0.+0.j  0.+0.j  0.+1.j  0.+0.j]
     [ 0.+0.j  0.+1.j  0.+0.j  0.+0.j]
     [ 0.+0.j  0.+0.j  0.+0.j  1.+0.j]]
    """
    return Qobj(array([[1,0,0,0], [0,0,1j,0], [0,1j,0,0], [0,0,0,1]]), dims=[[2, 2], [2, 2]])
Esempio n. 21
0
def snot():
    """Quantum object representing the SNOT (Hadamard) gate.
    
    Returns
    -------
    snot_gate : qobj
        Quantum object representation of SNOT (Hadamard) gate.
    
    Examples
    --------
    >>> snot()
    Quantum object: dims = [[2], [2]], shape = [2, 2], type = oper, isHerm = True
    Qobj data = 
    [[ 0.70710678+0.j  0.70710678+0.j]
     [ 0.70710678+0.j -0.70710678+0.j]]
         
    """
    u = qstate('u')
    d = qstate('d')
    Q = 1.0 / sqrt(2.0) * (d * d.dag() + u * d.dag() + d * u.dag() -
                           u * u.dag())
    return Qobj(Q)
Esempio n. 22
0
def thermal_dm(N, n, method='operator'):
    """Density matrix for a thermal state of n particles

    Parameters
    ----------
    N : int 
        Number of basis states in Hilbert space.
    
    n : float 
        Expectation value for number of particles in thermal state.
    
    method : string {'operator', 'analytic'}
        ``string`` that sets the method used to generate the
        thermal state probabilities 
    
    Returns
    -------
    dm : qobj
        Thermal state density matrix.
    
    Examples
    --------
    >>> thermal_dm(5,1)
    Quantum object: dims = [[5], [5]], shape = [5, 5], type = oper, isHerm = True
    Qobj data = 
    [[ 0.51612903  0.          0.          0.          0.        ]
     [ 0.          0.25806452  0.          0.          0.        ]
     [ 0.          0.          0.12903226  0.          0.        ]
     [ 0.          0.          0.          0.06451613  0.        ]
     [ 0.          0.          0.          0.          0.03225806]]
    
    
    >>> thermal_dm(5,1,'analytic')
    Quantum object: dims = [[5], [5]], shape = [5, 5], type = oper, isHerm = True
    Qobj data =
    [[ 0.5      0.       0.       0.       0.     ]
     [ 0.       0.25     0.       0.       0.     ]
     [ 0.       0.       0.125    0.       0.     ]
     [ 0.       0.       0.       0.0625   0.     ]
     [ 0.       0.       0.       0.       0.03125]]
    
    Notes
    -----
    The 'operator' method (default) generates
    the thermal state using the truncated number operator ``num(N)``. This
    is the method that should be used in computations. The
    'analytic' method uses the analytic coefficients derived in 
    an infinite Hilbert space. THE ANALYTIC FORM IS NOT NORMALIZED.
    
    """
    if n == 0:
        return fock_dm(N, 0)
    else:
        i = arange(N)
        if method == 'operator':
            beta = np.log(1.0 / n + 1.0)
            diags = np.exp(-beta * i)
            diags = diags / np.sum(diags)
            rm = sp.spdiags(
                diags, 0, N, N, format='csr'
            )  #populates diagonal terms using truncated operator expression
        elif method == 'analytic':
            rm = sp.spdiags(
                (1.0 + n)**(-1.0) * (n / (1.0 + n))**(i),
                0,
                N,
                N,
                format='csr')  #populates diagonal terms using analytic values
        else:
            raise ValueError(
                "'method' keyword argument must be 'operator' or 'analytic'")
    return Qobj(rm)
Esempio n. 23
0
def jmat(j, *args):
    """Higher-order spin operators:
    
    Parameters
    ----------
    j : float
        Spin of operator
    
    args : str 
        Which operator to return 'x','y','z','+','-'.
        If no args given, then output is ['x','y','z']
    
    Returns
    ------- 
    jmat : qobj/list
        ``qobj`` for requested spin operator(s).
        
    
    Examples
    --------
    >>> jmat(1)
    [ Quantum object: dims = [[3], [3]], shape = [3, 3], type = oper, isHerm = True
    Qobj data =
    [[ 0.          0.70710678  0.        ]
     [ 0.70710678  0.          0.70710678]
     [ 0.          0.70710678  0.        ]]
     Quantum object: dims = [[3], [3]], shape = [3, 3], type = oper, isHerm = True
    Qobj data =
    [[ 0.+0.j          0.+0.70710678j  0.+0.j        ]
     [ 0.-0.70710678j  0.+0.j          0.+0.70710678j]
     [ 0.+0.j          0.-0.70710678j  0.+0.j        ]]
     Quantum object: dims = [[3], [3]], shape = [3, 3], type = oper, isHerm = True
    Qobj data =
    [[ 1.  0.  0.]
     [ 0.  0.  0.]
     [ 0.  0. -1.]]]
    
    
    Notes
    -----
    If no 'args' input, then returns array of ['x','y','z'] operators.
        
    """
    if (scipy.fix(2 * j) != 2 * j) or (j < 0):
        raise TypeError('j must be a non-negative integer or half-integer')
    if not args:
        a1 = Qobj(0.5 * (jplus(j) + jplus(j).conj().T))
        a2 = Qobj(0.5 * 1j * (jplus(j) - jplus(j).conj().T))
        a3 = Qobj(jz(j))
        return np.array([a1, a2, a3])
    if args[0] == '+':
        A = jplus(j)
    elif args[0] == '-':
        A = jplus(j).conj().T
    elif args[0] == 'x':
        A = 0.5 * (jplus(j) + jplus(j).conj().T)
    elif args[0] == 'y':
        A = -0.5 * 1j * (jplus(j) - jplus(j).conj().T)
    elif args[0] == 'z':
        A = jz(j)
    else:
        raise TypeError('Invlaid type')
    return Qobj(A.tocsr())
Esempio n. 24
0
    def __init__(self, q=np.array([]), s=np.array([])):
        if isinstance(s, (int, float, complex)):
            s = np.array([s])
        if (not np.any(q)) and (len(s) == 0):
            self.ampl = np.array([])
            self.rates = np.array([])
            self.dims = [[1, 1]]
            self.shape = [1, 1]
        if np.any(q) and (len(s) == 0):
            if isinstance(q, eseries):
                self.ampl = q.ampl
                self.rates = q.rates
                self.dims = q.dims
                self.shape = q.shape
            elif isinstance(q, (np.ndarray, list)):
                ind = np.shape(q)
                num = ind[0]  #number of elements in q
                sh = np.array([Qobj(x).shape for x in q])
                if any(sh != sh[0]):
                    raise TypeError('All amplitudes must have same dimension.')
                self.ampl = np.array([x for x in q])
                self.rates = np.zeros(ind)
                self.dims = self.ampl[0].dims
                self.shape = self.ampl[0].shape
            elif isinstance(q, Qobj):
                qo = Qobj(q)
                self.ampl = np.array([qo])
                self.rates = np.array([0])
                self.dims = qo.dims
                self.shape = qo.shape
            else:
                self.ampl = np.array([q])
                self.rates = np.array([0])
                self.dims = [[1, 1]]
                self.shape = [1, 1]

        if np.any(q) and len(s) != 0:
            if isinstance(q, (np.ndarray, list)):
                ind = np.shape(q)
                num = ind[0]
                sh = np.array([Qobj(q[x]).shape for x in range(0, num)])
                if np.any(sh != sh[0]):
                    raise TypeError('All amplitudes must have same dimension.')
                self.ampl = np.array([Qobj(q[x]) for x in range(0, num)])
                self.dims = self.ampl[0].dims
                self.shape = self.ampl[0].shape
            else:
                num = 1
                self.ampl = np.array([Qobj(q)])
                self.dims = self.ampl[0].dims
                self.shape = self.ampl[0].shape
            if isinstance(s, (int, complex, float)):
                if num != 1:
                    raise TypeError(
                        'Number of rates must match number of members in object array.'
                    )
                self.rates = np.array([s])
            elif isinstance(s, (np.ndarray, list)):
                if len(s) != num:
                    raise TypeError(
                        'Number of rates must match number of members in object array.'
                    )
                self.rates = np.array(s)
        if len(self.ampl) != 0:
            zipped = list(
                zip(self.rates, self.ampl
                    ))  #combine arrays so that they can be sorted together
            zipped.sort()  #sort rates from lowest to highest
            rates, ampl = list(zip(*zipped))  #get back rates and ampl
            self.ampl = np.array(ampl)
            self.rates = np.array(rates)
Esempio n. 25
0
def floquet_modes(H, T, args=None, sort=False):
    """
    Calculate the initial Floquet modes Phi_alpha(0) for a driven system with
    period T.
    
    Returns a list of :class:`qutip.Qobj` instances representing the Floquet
    modes and a list of corresponding quasienergies, sorted by increasing
    quasienergy in the interval [-pi/T, pi/T]. The optional parameter `sort`
    decides if the output is to be sorted in increasing quasienergies or not.

    Parameters
    ----------
    
    H : :class:`qutip.Qobj`
        system Hamiltonian, time-dependent with period `T`
        
    args : dictionary
        dictionary with variables required to evaluate H
     
    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.
     
    Returns
    -------

    output : list of kets, list of quasi energies

        Two lists: the Floquet modes as kets and the quasi energies.

    """

    # get the unitary propagator
    U = propagator(H, T, [], args)

    # find the eigenstates for the propagator
    evals, evecs = la.eig(U.full())

    eargs = angle(evals)

    # make sure that the phase is in the interval [-pi, pi], so that the
    # quasi energy is in the interval [-pi/T, pi/T] where T is the period of the
    # driving.
    #eargs  += (eargs <= -2*pi) * (2*pi) + (eargs > 0) * (-2*pi)
    eargs += (eargs <= -pi) * (2 * pi) + (eargs > pi) * (-2 * pi)
    e_quasi = -eargs / T

    # sort by the quasi energy
    if sort == True:
        order = np.argsort(-e_quasi)
    else:
        order = list(range(len(evals)))

    # prepare a list of kets for the floquet states
    new_dims = [U.dims[0], [1] * len(U.dims[0])]
    new_shape = [U.shape[0], 1]
    kets_order = [
        Qobj(np.matrix(evecs[:, o]).T, dims=new_dims, shape=new_shape)
        for o in order
    ]

    return kets_order, e_quasi[order]
Esempio n. 26
0
def ode2es(L,rho0):
    """Creates an exponential series that describes the time evolution for the
    initial density matrix (or state vector) `rho0`, given the Liouvillian 
    (or Hamiltonian) `L`.
    
    Parameters
    ----------
    L : qobj
        Liouvillian of the system.
    
    rho0 : qobj
        Initial state vector or density matrix.
    
    Returns
    ------- 
    ode_series : eseries 
        ``eseries`` represention of the system dynamics.
    
    """

    if issuper(L):
 
        # check initial state
        if isket(rho0):
            # Got a wave function as initial state: convert to density matrix.
            rho0 = rho0 * rho0.dag()
    
        w, v = L.eigenstates()
        v=np.hstack([ket.full() for ket in v])
        # w[i]   = eigenvalue i
        # v[:,i] = eigenvector i
    
        rlen = prod(rho0.shape)
        r0 = mat2vec(rho0.full())
        v0 = la.solve(v,r0)
        vv = v * sp.spdiags(v0.T, 0, rlen, rlen)
    
        out = None
        for i in range(rlen):
            qo = Qobj(vec2mat(vv[:,i]), dims=rho0.dims, shape=rho0.shape)
            if out:
                out += eseries(qo, w[i])
            else:
                out  = eseries(qo, w[i])

    elif isoper(L):

        if not isket(rho0):
            raise TypeError('Second argument must be a ket if first is a Hamiltonian.')

        w, v = L.eigenstates()
        v=np.hstack([ket.full() for ket in v])
        # w[i]   = eigenvalue i
        # v[:,i] = eigenvector i

        rlen = prod(rho0.shape)
        r0 = rho0.full()
        v0 = la.solve(v,r0)
        vv = v * sp.spdiags(v0.T, 0, rlen, rlen)

        out = None
        for i in range(rlen):
            qo = Qobj(matrix(vv[:,i]).T, dims=rho0.dims, shape=rho0.shape)
            if out:
                out += eseries(qo, -1.0j * w[i])
            else:
                out  = eseries(qo, -1.0j * w[i])

    else:
        raise TypeError('First argument must be a Hamiltonian or Liouvillian.')
        
    return estidy(out)
Esempio n. 27
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
Esempio n. 28
0
def _generic_ode_solve(r, psi0, tlist, expt_ops, opt, state_vectorize, state_norm_func=None):
    """
    Internal function for solving ODEs.
    """
    
    #
    # prepare output array
    # 
    n_tsteps  = len(tlist)
    dt        = tlist[1]-tlist[0]
       
    output = Odedata()
    output.solver = "mesolve"
    output.times = tlist
        
    if isinstance(expt_ops, types.FunctionType):
        n_expt_op = 0
        expt_callback = True
        
    elif isinstance(expt_ops, list):
  
        n_expt_op = len(expt_ops)
        expt_callback = False

        if n_expt_op == 0:
            output.states = []
        else:
            output.expect = []
            output.num_expect = n_expt_op
            for op in expt_ops:
                if op.isherm and psi0.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")
   
    #
    # start evolution
    #
    psi = Qobj(psi0)

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

        if state_norm_func:
            psi.data = state_vectorize(r.y)
            state_norm = state_norm_func(psi.data)
            psi.data = psi.data / state_norm
            r.set_initial_value(r.y/state_norm, r.t)
        else:
            psi.data = state_vectorize(r.y)
    
        if expt_callback:
            # use callback method
            expt_ops(t, Qobj(psi))
        else:
            # calculate all the expectation values, or output rho if no operators
            if n_expt_op == 0:
                output.states.append(Qobj(psi)) # copy psi/rho
            else:
                for m in range(0, n_expt_op):
                    output.expect[m][t_idx] = expect(expt_ops[m], psi)

        r.integrate(r.t + dt)
        t_idx += 1
        
    if not opt.rhs_reuse and odeconfig.tdname != None:
        try:
            os.remove(odeconfig.tdname+".pyx")
        except:
            pass

    return output
Esempio n. 29
0
def tensor(*args):
    """Calculates the tensor product of input operators. 
    
    Parameters
    ----------
    args : array_like 
        ``list`` or ``array`` of quantum objects for tensor product.
        
    Returns
    --------
    obj : qobj
        A composite quantum object.
    
    Examples
    --------    
    >>> tensor([sigmax(), sigmax()])
    Quantum object: dims = [[2, 2], [2, 2]], shape = [4, 4], type = oper, isHerm = True
    Qobj data = 
    [[ 0.+0.j  0.+0.j  0.+0.j  1.+0.j]
     [ 0.+0.j  0.+0.j  1.+0.j  0.+0.j]
     [ 0.+0.j  1.+0.j  0.+0.j  0.+0.j]
     [ 1.+0.j  0.+0.j  0.+0.j  0.+0.j]]

    """
    if not args:
        raise TypeError("Requires at least one input argument")
    num_args = len(args)
    step = 0
    for n in range(num_args):
        if isinstance(args[n], Qobj):
            qos = args[n]
            if step == 0:
                dat = qos.data
                dim = qos.dims
                shp = qos.shape
                step = 1
            else:
                dat = sp.kron(dat, qos.data,
                              format='csr')  #sparse Kronecker product
                dim = [dim[0] + qos.dims[0],
                       dim[1] + qos.dims[1]]  #append dimensions of Qobjs
                shp = [dat.shape[0], dat.shape[1]]  #new shape of matrix

        elif isinstance(
                args[n],
            (list, ndarray)):  #checks if input is list/array of Qobjs
            qos = args[n]
            items = len(qos)  #number of inputs
            if not all([
                    isinstance(k, Qobj) for k in qos
            ]):  #raise error if one of the inputs is not a quantum object
                raise TypeError("One of inputs is not a quantum object")
            if items == 1:  # if only one Qobj, do nothing
                if step == 0:
                    dat = qos[0].data
                    dim = qos[0].dims
                    shp = qos[0].shape
                    step = 1
                else:
                    dat = sp.kron(dat, qos[0].data,
                                  format='csr')  #sparse Kronecker product
                    dim = [dim[0] + qos[0].dims[0], dim[1] + qos[0].dims[1]
                           ]  #append dimensions of Qobjs
                    shp = [dat.shape[0], dat.shape[1]]  #new shape of matrix
            elif items != 1:
                if step == 0:
                    dat = qos[0].data
                    dim = qos[0].dims
                    shp = qos[0].shape
                    step = 1
                for k in range(items - 1):  #cycle over all items
                    dat = sp.kron(dat, qos[k + 1].data,
                                  format='csr')  #sparse Kronecker product
                    dim = [
                        dim[0] + qos[k + 1].dims[0],
                        dim[1] + qos[k + 1].dims[1]
                    ]  #append dimensions of Qobjs
                    shp = [dat.shape[0], dat.shape[1]]  #new shape of matrix
    out = Qobj()
    out.data = dat
    out.dims = dim
    out.shape = shp
    if qutip.settings.auto_tidyup:
        return Qobj(out).tidyup()  #returns tidy Qobj
    else:
        return Qobj(out)
Esempio n. 30
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
Esempio n. 31
0
def tensor(*args):
    """Calculates the tensor product of input operators. 
    
    Parameters
    ----------
    args : array_like 
        ``list`` or ``array`` of quantum objects for tensor product.
        
    Returns
    --------
    obj : qobj
        A composite quantum object.
    
    Examples
    --------    
    >>> tensor([sigmax(), sigmax()])
    Quantum object: dims = [[2, 2], [2, 2]], shape = [4, 4], type = oper, isHerm = True
    Qobj data = 
    [[ 0.+0.j  0.+0.j  0.+0.j  1.+0.j]
     [ 0.+0.j  0.+0.j  1.+0.j  0.+0.j]
     [ 0.+0.j  1.+0.j  0.+0.j  0.+0.j]
     [ 1.+0.j  0.+0.j  0.+0.j  0.+0.j]]

    """
    if not args:
        raise TypeError("Requires at least one input argument")
    num_args=len(args)
    step=0
    for n in range(num_args):
        if isinstance(args[n],Qobj):
            qos=args[n]
            if step==0:
                dat=qos.data
                dim=qos.dims
                shp=qos.shape
                step=1
            else:
                dat=sp.kron(dat,qos.data, format='csr') #sparse Kronecker product
                dim=[dim[0]+qos.dims[0],dim[1]+qos.dims[1]] #append dimensions of Qobjs
                shp=[dat.shape[0],dat.shape[1]] #new shape of matrix
                
        elif isinstance(args[n],(list,ndarray)):#checks if input is list/array of Qobjs
            qos=args[n]
            items=len(qos) #number of inputs
            if not all([isinstance(k,Qobj) for k in qos]): #raise error if one of the inputs is not a quantum object
                raise TypeError("One of inputs is not a quantum object")
            if items==1:# if only one Qobj, do nothing
                if step==0: 
                    dat=qos[0].data
                    dim=qos[0].dims
                    shp=qos[0].shape
                    step=1
                else:
                    dat=sp.kron(dat,qos[0].data, format='csr') #sparse Kronecker product
                    dim=[dim[0]+qos[0].dims[0],dim[1]+qos[0].dims[1]] #append dimensions of Qobjs
                    shp=[dat.shape[0],dat.shape[1]] #new shape of matrix
            elif items!=1:
                if step==0:
                    dat=qos[0].data
                    dim=qos[0].dims
                    shp=qos[0].shape
                    step=1
                for k in range(items-1): #cycle over all items
                    dat=sp.kron(dat,qos[k+1].data, format='csr') #sparse Kronecker product
                    dim=[dim[0]+qos[k+1].dims[0],dim[1]+qos[k+1].dims[1]] #append dimensions of Qobjs
                    shp=[dat.shape[0],dat.shape[1]] #new shape of matrix
    out=Qobj()
    out.data=dat
    out.dims=dim
    out.shape=shp
    if qutip.settings.auto_tidyup:
        return Qobj(out).tidyup() #returns tidy Qobj
    else:
        return Qobj(out)
Esempio n. 32
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))]
Esempio n. 33
0
def _generic_ode_solve(r,
                       psi0,
                       tlist,
                       expt_ops,
                       opt,
                       state_vectorize,
                       state_norm_func=None):
    """
    Internal function for solving ODEs.
    """

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

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

    if isinstance(expt_ops, types.FunctionType):
        n_expt_op = 0
        expt_callback = True

    elif isinstance(expt_ops, list):

        n_expt_op = len(expt_ops)
        expt_callback = False

        if n_expt_op == 0:
            output.states = []
        else:
            output.expect = []
            output.num_expect = n_expt_op
            for op in expt_ops:
                if op.isherm and psi0.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")

    #
    # start evolution
    #
    psi = Qobj(psi0)

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

        if state_norm_func:
            psi.data = state_vectorize(r.y)
            state_norm = state_norm_func(psi.data)
            psi.data = psi.data / state_norm
            r.set_initial_value(r.y / state_norm, r.t)
        else:
            psi.data = state_vectorize(r.y)

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

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

    if not opt.rhs_reuse and odeconfig.tdname != None:
        try:
            os.remove(odeconfig.tdname + ".pyx")
        except:
            pass

    return output
Esempio n. 34
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
Esempio n. 35
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