Exemplo n.º 1
0
def _heom_state_dictionaries(dims, excitations):
    """
    Return the number of states, and lookup-dictionaries for translating
    a state tuple to a state index, and vice versa, for a system with a given
    number of components and maximum number of excitations.
    Parameters
    ----------
    dims: list
        A list with the number of states in each sub-system.
    excitations : integer
        The maximum numbers of dimension
    Returns
    -------
    nstates, state2idx, idx2state: integer, dict, dict
        The number of states `nstates`, a dictionary for looking up state
        indices from a state tuple, and a dictionary for looking up state
        state tuples from state indices.
    """
    nstates = 0
    state2idx = {}
    idx2state = {}

    for state in state_number_enumerate(dims, excitations):
        state2idx[state] = nstates
        idx2state[nstates] = state
        nstates += 1
    return nstates, state2idx, idx2state
Exemplo n.º 2
0
    def __init__(self, exponents, max_depth):
        self.exponents = exponents
        self.max_depth = max_depth

        self.dims = [exp.dim or (max_depth + 1) for exp in self.exponents]
        self.vk = [exp.vk for exp in self.exponents]
        self.ck = [exp.ck for exp in self.exponents]
        self.ck2 = [exp.ck2 for exp in self.exponents]
        self.sigma_bar_k_offset = [
            exp.sigma_bar_k_offset for exp in self.exponents
        ]

        self.labels = list(state_number_enumerate(self.dims, max_depth))
        self._label_idx = {s: i for i, s in enumerate(self.labels)}
Exemplo n.º 3
0
def test_fock_state(dimensions, n_excitations):
    """
    Test Fock state creation agrees with the number operators implied by the
    existence of the ENR annihiliation operators.
    """
    number = [
        a.dag() * a for a in qutip.enr_destroy(dimensions, n_excitations)
    ]
    bases = list(qutip.state_number_enumerate(dimensions, n_excitations))
    n_samples = min((len(bases), 5))
    for basis in random.sample(bases, n_samples):
        state = qutip.enr_fock(dimensions, n_excitations, basis)
        for n, x in zip(number, basis):
            assert abs(n.matrix_element(state.dag(), state)) - x < 1e-10
Exemplo n.º 4
0
def test_enr_thermal_dm2():
    "Excitation-number-restricted state space: thermal density operator (II)"
    dims, excitations = [3, 4, 5], 2

    n_vec = 0.1

    rho = enr_thermal_dm(dims, excitations, n_vec)

    rho_ref = tensor([thermal_dm(d, n_vec) for idx, d in enumerate(dims)])
    gonners = [idx for idx, state in enumerate(state_number_enumerate(dims))
               if sum(state) > excitations]
    rho_ref = rho_ref.eliminate_states(gonners)
    rho_ref = rho_ref / rho_ref.tr()

    assert_(abs((rho.data - rho_ref.data).data).max() < 1e-12)
Exemplo n.º 5
0
def test_enr_thermal_dm2():
    "Excitation-number-restricted state space: thermal density operator (II)"
    dims, excitations = [3, 4, 5], 2

    n_vec = 0.1

    rho = enr_thermal_dm(dims, excitations, n_vec)

    rho_ref = tensor([thermal_dm(d, n_vec) for idx, d in enumerate(dims)])
    gonners = [idx for idx, state in enumerate(state_number_enumerate(dims))
               if sum(state) > excitations]
    rho_ref = rho_ref.eliminate_states(gonners)
    rho_ref = rho_ref / rho_ref.tr()

    assert_(abs((rho.data - rho_ref.data).data).max() < 1e-12)
Exemplo n.º 6
0
def _reference_dm(dimensions, n_excitations, nbars):
    """
    Get the reference density matrix using `Qobj.eliminate_states` explicitly,
    to compare to the direct ENR construction.
    """
    if np.isscalar(nbars):
        nbars = [nbars] * len(dimensions)
    out = qutip.tensor([
        qutip.thermal_dm(dimension, nbar)
        for dimension, nbar in zip(dimensions, nbars)
    ])
    eliminate = [
        i for i, state in enumerate(qutip.state_number_enumerate(dimensions))
        if sum(state) > n_excitations
    ]
    out = out.eliminate_states(eliminate)
    return out / out.tr()
Exemplo n.º 7
0
def _heom_number_enumerate(dims, excitations=None, state=None, idx=0):
    """
    An iterator that enumerate all the state number arrays (quantum numbers on
    the form [n1, n2, n3, ...]) for a system with dimensions given by dims.
    Example:
        >>> for state in state_number_enumerate([2,2]):
        >>>     print(state)
        [ 0.  0.]
        [ 0.  1.]
        [ 1.  0.]
        [ 1.  1.]
    Parameters
    ----------
    dims : list or array
        The quantum state dimensions array, as it would appear in a Qobj.
    state : list
        Current state in the iteration. Used internally.
    excitations : integer (None)
        Restrict state space to states with excitation numbers below or
        equal to this value.
    idx : integer
        Current index in the iteration. Used internally.
    Returns
    -------
    state_number : list
        Successive state number arrays that can be used in loops and other
        iterations, using standard state enumeration *by definition*.
    """

    if state is None:
        state = np.zeros(len(dims))

    if excitations and sum(state[0:idx]) > excitations:
        pass
    elif idx == len(dims):
        if excitations is None:
            yield np.array(state)
        else:
            yield tuple(state)

    else:
        for n in range(dims[idx]):
            state[idx] = n
            for s in state_number_enumerate(dims, excitations, state, idx + 1):
                yield s
Exemplo n.º 8
0
    def __init__(self, ops, states = [], state_labels = []):
        # -- Assertions --
        if isinstance(ops, Qobj): # Make ops list if given as Qobj
            self.ops = [ops]
        else:
            self.ops = ops
        assert isinstance(self.ops,list)
        if len(states) == 0:
            states = [ket(s,self.ops[0].dims[0]) for s in state_number_enumerate(self.ops[0].dims[0]) ]
        if state_labels:
            assert len(state_labels) == len(states)
        else:
            state_labels = [str(n) for n in range(len(states))]
        for state in states:
            assert state.isket

        # -- Initializing figure --
        self.fig = figure()
        self.ax = axes()
        self.fig.canvas.callbacks.connect('pick_event', self.on_pick)
        # -- Building level instances --
        self.levels = []
        self.deg_subspaces = []
        self.transitions = []

        for psi,label in zip(states,state_labels):
            E = expect(self.ops[0],psi)
            self.levels.append(level(E,psi,label))
        degeneracy_tol = (max([lvl.E for lvl in self.levels])-min([lvl.E for lvl in self.levels]))*0.5e-1
        lvls = self.levels.copy()
        while lvls:
            new_subspace = [lvl for lvl in lvls if abs(lvl.E-lvls[0].E)<degeneracy_tol]
            self.deg_subspaces.append(_subspace(new_subspace))
            for lvl in new_subspace:
                lvls.remove(lvl)
        # -- Building transition instances --
        min_strength = 1e-11*sum([lvl.E**2 for lvl in self.levels])
        for i in range(len(states)-1):
            for j in range(i+1,len(states)):
                strength = sum(oper.matrix_element(states[i],states[j]) for oper in self.ops)
                if abs(strength)>min_strength:
                    self.transitions.append(transition(strength, self.levels[i], self.levels[j]))
Exemplo n.º 9
0
def quantize_SHO(K, U, p, x, dims=[], taylor_order=4, x0=None, t_symbol=None):
    """A function that can quantize a sympy hamiltonian. Currently only in SHO/fock basis

    Parameters
    ----------
    K : sympy expression
        Sympy expression for the kinetic term
    U : sympy expression
        sympy expression for the potential
    p : iterable of sympy symbols
        Symbols representing the canonical momenta of the system
    x : iterable of sympy symbols
        Symbols representing the canonical position variables of the system
    dims : list of integers
        Specifies the desired dimension of each mode. Must be same length as x and p
    taylor_order : integer
        Specifies the order to which the taylor expansion will be carried out if the quantization method utilises, such an expansion.
    x0 : list of floats
        The point around which the taylor expansion of the potential wil be carried out.

    Returns
    -------
    operator_generator
        An operator generator that when called as instance(*params) return the hamiltonian for the system with given params. A parameter is defined as a symbol that appears in K or U but not in x or p.

    """
    # Preliminaries
    if not dims:
        dims = len(x) * [4]
    if x0 == None:
        x0 = np.zeros(len(x))

    # Taylor expansion
    T_U = au.taylor.taylor_sympy(f=U, x=x, x0=x0, N=taylor_order)
    T_K = au.taylor.taylor_sympy(f=K, x=p, x0=np.zeros(len(p)), N=2)

    # Effective mass and "spring constant"
    m = len(x) * [0]
    k = len(x) * [0]
    for coeff, powers in T_K:
        inds = np.nonzero(np.array(powers) == 2)[0]
        if len(inds) == 1:
            m[inds[0]] = 1 / (2 * coeff)
    for coeff, powers in T_U:
        inds = np.nonzero(np.array(powers) == 2)[0]
        if len(inds) == 1:
            k[inds[0]] = 2 * coeff

    # Constructing position and momentum operator
    x_ops = []
    p_ops = []
    padded_dims = [d + int(np.floor(taylor_order / 2)) for d in dims]
    for j, d in zip(range(len(k)), padded_dims):
        op = [qt.qeye(d) for d in padded_dims]
        op[j] = 1j * (qt.create(d) - qt.destroy(d)) / np.sqrt(2)
        p_ops.append(qt.tensor(op))
        op[j] = (qt.create(d) + qt.destroy(d)) / np.sqrt(2)
        x_ops.append(qt.tensor(op))
    terms = []

    # Calculating qutip operator and symbolic coefficient for each term
    P = 0  # This will be the projection operator that projects onto the subspace defined by dims
    for state in qt.state_number_enumerate(dims):
        P += qt.ket(state, dims) * qt.bra(state, padded_dims)
    for coeff, powers in T_K:
        op = qt.qeye(padded_dims)
        for kj, mj, p_op, pow in zip(k, m, p_ops, powers):
            if pow > 0:
                coeff *= (kj * mj)**(pow / 4)
                op *= p_op**pow
        terms.append((coeff, P * op * P.dag()))
    for coeff, powers in T_U:
        op = qt.qeye(padded_dims)
        for kj, mj, x_op, pow in zip(k, m, x_ops, powers):
            if pow > 0:
                coeff *= (kj * mj)**(-pow / 4)
                op *= x_op**pow
        terms.append((coeff, P * op * P.dag()))

    # Constructing opgen instance
    return au.td_symopgen(sym_terms=terms, t_symbol=t_symbol)
Exemplo n.º 10
0
    def filter(self, level=None, tags=None, dims=None, types=None):
        """
        Return a list of ADO labels for ADOs whose "excitations"
        match the given patterns.

        Each of the filter parameters (tags, dims, types) may be either
        unspecified (None) or a list. Unspecified parameters are excluded
        from the filtering.

        All specified filter parameters must be lists of the same length.
        Each position in the lists describes a particular excitation and
        any exponent that matches the filters may supply that excitation.
        The level of all labels returned is thus equal to the length of
        the filter parameter lists.

        Within a filter parameter list, items that are None represent
        wildcards and match any value of that exponent attribute

        Parameters
        ----------
        level : int
            The hierarchy depth to return ADOs from.

        tags : list of object or None
            Filter parameter that matches the ``.tag`` attribute of
            exponents.

        dims : list of int
            Filter parameter that matches the ``.dim`` attribute of
            exponents.

        types : list of BathExponent types or list of str
            Filter parameter that matches the ``.type`` attribute
            of exponents. Types may be supplied by name (e.g. "R", "I", "+")
            instead of by the actual type (e.g. ``BathExponent.types.R``).

        Returns
        -------
        list of tuple
            The ADO label for each ADO whose exponent excitations
            (i.e. label) match the given filters or level.
        """
        if types is not None:
            types = [
                t if t is None or isinstance(t, BathExponent.types) else
                BathExponent.types[t] for t in types
            ]
        filters = [("tag", tags), ("type", types), ("dim", dims)]
        filters = [(attr, f) for attr, f in filters if f is not None]
        n = max((len(f) for _, f in filters), default=0)
        if any(len(f) != n for _, f in filters):
            raise ValueError(
                "The tags, dims and types filters must all be the same length."
            )
        if n > self.max_depth:
            raise ValueError(
                f"The maximum depth for the hierarchy is {self.max_depth} but"
                f" {n} levels of excitation filters were given.")
        if level is None:
            if not filters:
                # fast path for when there are no excitation filters
                return self.labels[:]
        else:
            if not filters:
                # fast path for when there are no excitation filters
                return [label for label in self.labels if sum(label) == level]
            if level != n:
                raise ValueError(
                    f"The level parameter is {level} but {n} levels of"
                    " excitation filters were given.")

        filtered_dims = [1] * len(self.exponents)
        for lvl in range(n):
            level_filters = [(attr, f[lvl]) for attr, f in filters
                             if f[lvl] is not None]
            for j, exp in enumerate(self.exponents):
                if any(getattr(exp, attr) != f for attr, f in level_filters):
                    continue
                filtered_dims[j] += 1
                filtered_dims[j] = min(self.dims[j], filtered_dims[j])

        return [
            label for label in state_number_enumerate(filtered_dims, n)
            if sum(label) == n
        ]
Exemplo n.º 11
0
    [3], [4]) + 20 * qt.ket([0], [4]) * qt.bra([0], [4])


def process(rho, tlist):
    res = qt.mesolve(H, rho, tlist)
    return [
        transform_state_unitary(rho, U_target, inverse=True)
        for rho in res.states
    ]


tlist = np.linspace(0, np.pi / (2 * np.sqrt(2)), 10)
F_av = average_fidelity(process, subspace_basis, tlist)
print(F_av, '\n')
# One qubit doing nothing in interaction pic but simulated in schrodinger
subspace_basis = [qt.ket(seq, [2]) for seq in qt.state_number_enumerate([2])]
H0 = qt.sigmaz()


def U_target(t):
    return qt.qeye(2) * (-1j * H0 * t).expm()


def process(rho, tlist):
    res = qt.mesolve(H0, rho, tlist)
    return [
        transform_state_unitary(rho, U_target(t), inverse=True)
        for rho, t in zip(res.states, tlist)
    ]

Exemplo n.º 12
0
def hsolve(H, psi0, tlist, Q, gam, lam0, Nc, N, w_th, options=None):
    """
    Function to solve for an open quantum system using the
    hierarchy model.

    Parameters
    ----------
    H: Qobj
        The system hamiltonian.
    psi0: Qobj
        Initial state of the system.
    tlist: List.
        Time over which system evolves.
    Q: Qobj
        The coupling between system and bath.
    gam: Float
        Bath cutoff frequency.
    lam0: Float
        Coupling strength.
    Nc: Integer
        Cutoff parameter.
    N: Integer
        Number of matsubara terms.
    w_th: Float
        Temperature.
    options : :class:`qutip.Options`
        With options for the solver.

    Returns
    -------
    output: Result
        System evolution.
    """
    if options is None:
        options = Options()

    # Set up terms of the matsubara and tanimura boundaries

    # Parameters and hamiltonian
    hbar = 1.
    kb = 1.

    # Set by system
    dimensions = dims(H)
    Nsup = dimensions[0][0] * dimensions[0][0]
    unit = qeye(dimensions[0])

    # Ntot is the total number of ancillary elements in the hierarchy
    Ntot = int(round(factorial(Nc+N) / (factorial(Nc) * factorial(N))))
    c0 = (lam0 * gam * (_cot(gam * hbar / (2. * kb * w_th)) - (1j))) / hbar
    LD1 = (-2. * spre(Q) * spost(Q.dag()) + spre(Q.dag()*Q) + spost(Q.dag()*Q))
    pref = ((2. * lam0 * kb * w_th / (gam * hbar)) - 1j * lam0) / hbar
    gj = 2 * np.pi * kb * w_th / hbar
    L12 = -pref * LD1 + (c0 / gam) * LD1

    for i1 in range(1, N):
        num = (4 * lam0 * gam * kb * w_th * i1 * gj/((i1 * gj)**2 - gam**2))
        ci = num / (hbar**2)
        L12 = L12 + (ci / gj) * LD1

    # Setup liouvillian

    L = liouvillian(H, [L12])
    Ltot = L.data
    unit = sp.eye(Ntot,format='csr')
    Lbig = sp.kron(unit, Ltot)
    rho0big1 = np.zeros((Nsup * Ntot), dtype=complex)

    # Prepare initial state:

    rhotemp = mat2vec(np.array(psi0.full(), dtype=complex))

    for idx, element in enumerate(rhotemp):
        rho0big1[idx] = element[0]
    
    nstates, state2idx, idx2state = enr_state_dictionaries([Nc+1]*(N), Nc)
    for nlabelt in state_number_enumerate([Nc+1]*(N), Nc):
        nlabel = list(nlabelt)
        ntotalcheck = 0
        for ncheck in range(N):
            ntotalcheck = ntotalcheck + nlabel[ncheck]
        current_pos = int(round(state2idx[tuple(nlabel)]))
        Ltemp = sp.lil_matrix((Ntot, Ntot))
        Ltemp[current_pos, current_pos] = 1
        Ltemp.tocsr()
        Lbig = Lbig + sp.kron(Ltemp, (-nlabel[0] * gam * spre(unit).data))

        for kcount in range(1, N):
            counts = -nlabel[kcount] * kcount * gj * spre(unit).data
            Lbig = Lbig + sp.kron(Ltemp, counts)

        for kcount in range(N):
            if nlabel[kcount] >= 1:
                # find the position of the neighbour
                nlabeltemp = copy(nlabel)
                nlabel[kcount] = nlabel[kcount] - 1
                current_pos2 = int(round(state2idx[tuple(nlabel)]))
                Ltemp = sp.lil_matrix((Ntot, Ntot))
                Ltemp[current_pos, current_pos2] = 1
                Ltemp.tocsr()
                # renormalized version:
                ci = (4 * lam0 * gam * kb * w_th * kcount
                      * gj/((kcount * gj)**2 - gam**2)) / (hbar**2)
                if kcount == 0:
                    Lbig = Lbig + sp.kron(Ltemp, (-1j
                                          * (np.sqrt(nlabeltemp[kcount]
                                             / abs(c0)))
                                          * ((c0) * spre(Q).data
                                             - (np.conj(c0))
                                             * spost(Q).data)))
                if kcount > 0:
                    ci = (4 * lam0 * gam * kb * w_th * kcount
                          * gj/((kcount * gj)**2 - gam**2)) / (hbar**2)
                    Lbig = Lbig + sp.kron(Ltemp, (-1j
                                          * (np.sqrt(nlabeltemp[kcount]
                                             / abs(ci)))
                                          * ((ci) * spre(Q).data
                                             - (np.conj(ci))
                                             * spost(Q).data)))
                nlabel = copy(nlabeltemp)

        for kcount in range(N):
            if ntotalcheck <= (Nc-1):
                nlabeltemp = copy(nlabel)
                nlabel[kcount] = nlabel[kcount] + 1
                current_pos3 = int(round(state2idx[tuple(nlabel)]))
            if current_pos3 <= (Ntot):
                Ltemp = sp.lil_matrix((Ntot, Ntot))
                Ltemp[current_pos, current_pos3] = 1
                Ltemp.tocsr()
            # renormalized
                if kcount == 0:
                    Lbig = Lbig + sp.kron(Ltemp, -1j
                                          * (np.sqrt((nlabeltemp[kcount]+1)
                                             * abs(c0)))
                                          * (spre(Q) - spost(Q)).data)
                if kcount > 0:
                    ci = (4 * lam0 * gam * kb * w_th * kcount
                          * gj/((kcount * gj)**2 - gam**2)) / (hbar**2)
                    Lbig = Lbig + sp.kron(Ltemp, -1j
                                          * (np.sqrt((nlabeltemp[kcount]+1)
                                             * abs(ci)))
                                          * (spre(Q) - spost(Q)).data)
            nlabel = copy(nlabeltemp)

    output = []
    for element in rhotemp:
        output.append([])
    r = scipy.integrate.ode(cy_ode_rhs)
    Lbig2 = Lbig.tocsr()
    r.set_f_params(Lbig2.data, Lbig2.indices, Lbig2.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(rho0big1, tlist[0])
    dt = tlist[1] - tlist[0]

    for t_idx, t in enumerate(tlist):
        r.integrate(r.t + dt)
        for idx, element in enumerate(rhotemp):
            output[idx].append(r.y[idx])

    return output