示例#1
0
def _get_fermi_partitions(term: Term, spec: _AGPFSpec):
    """Given a term with a list of fermionic vectors, extract the various
    partitions of N, Pdag and P kind of terms.

    Assumes: All possible simplification and Pairing / SU2 extraction
    has been performed, i.e. all the indices are distinct.
    """

    vecs = term.vecs
    amp = term.amp
    fermi_indcs = []

    cr = spec.c_dag.base
    an = spec.c_.base

    # First extract all the indices of fermion operators
    for v in vecs:
        if v.base in (cr, an):
            fermi_indcs.append(v.indices[1])

    if len(fermi_indcs) == 0:
        # if there are no fermion operators, return the term as it is
        return [Term(sums=term.sums, amp=amp, vecs=vecs)]
    else:
        # if there are fermion operators, then get all the possible
        # partitions of indices
        deltas_partns = list(_generate_partitions(fermi_indcs))

    # get a list of even partitions, i.e. throw away partitions involving
    # odd number of indices
    evens = [
        all(
            len(deltas_partns[i][j]) % 2 == 0
            for j in range(len(deltas_partns[i])))
        for i in range(len(deltas_partns))
    ]

    # Now iterate through the list of partitions and form the deltas expression
    # for the amplitude
    delta_amp = Integer(0)

    for i in range(len(deltas_partns)):
        # if statement for even partitions
        if evens[i]:
            pt = deltas_partns[i]
        else:
            continue

        # Form the delta expressions
        delta_intmd = Integer(1)
        for i in range(len(pt)):
            delta_intmd *= _construct_deltas(pt[i])
            if i > 0:
                delta_intmd *= (1 - KroneckerDelta(pt[i][0], pt[i - 1][0]))
        delta_amp += delta_intmd

    new_amp = amp * delta_amp

    return [Term(sums=term.sums, amp=new_amp, vecs=vecs)]
示例#2
0
        def get_vev_of_term(term):
            """Return the vev mapping of the term"""
            vecs = term.vecs
            t_amp = term.amp
            pdag_cnt = 0
            p_cnt = 0
            n_cnt = 0

            pdag_indlist = []
            p_indlist = []
            n_indlist = []

            if len(vecs) == 0:
                return [Term(sums=term.sums, amp=t_amp, vecs=vecs)]

            for i in vecs:
                if i.base == pdag_:
                    pdag_cnt += 1
                    pdag_indlist.extend(list(i.indices))
                elif i.base == p_:
                    p_cnt += 1
                    p_indlist.extend(list(i.indices))
                elif i.base == num_:
                    n_cnt += 1
                    n_indlist.extend(list(i.indices))
                else:
                    return []

            if pdag_cnt != p_cnt:
                # The expression must have equal number of Pdag's and P_'s
                return []
            elif len(pdag_indlist) != len(set(pdag_indlist)):
                return []
            elif len(p_indlist) != len(set(p_indlist)):
                return []
            else:
                # Combining all the indices
                indcs = pdag_indlist
                indcs.extend(n_indlist)
                indcs.extend(p_indlist)

                # Counting the different number of indices in order
                # to select the right symbol 'asymb'
                idx1 = int(n_cnt)
                idx_ppdag = len(indcs) - n_cnt
                idx2 = int((idx_ppdag / 2))

                asymb = zlist[idx1][idx2]
                t_amp = t_amp * asymb[indcs]

            return [Term(sums=term.sums, amp=t_amp, vecs=())]
示例#3
0
 def _isAGP(self, term):
     """Returns True if the vectors in the term are generators of the AGP algebra, otherwise False"""
     vecs = term.vecs
     for v in vecs:
         if v.base not in (self.cartan, self.raise_, self.lower):
             raise ValueError('Unexpected generator of the AGP Algebra', v)
     return [Term(sums=term.sums, amp=term.amp, vecs=term.vecs)]
示例#4
0
 def _isUGA(self,term):
     """Function returns True if the vectors are uga generators, otherwise False"""
     vecs = term.vecs
     for v in vecs:
         if v.base!=self.uga:
             raise ValueError('Unexpected generator of the Unitary Group',v)
     return [Term(sums=term.sums, amp=term.amp, vecs=term.vecs)]
示例#5
0
def _subst_actv_vec_rdm (term: Term, rdm: IndexedBase, actv_range, op_parser, resolvers):
    parsed = [op_parser (vec, term) for vec in term.vecs]
    ranges = [try_resolve_range (p[2][0], dict(term.sums), resolvers.value) for p in parsed]
    inac_vecs = [vec for r, vec in zip (ranges, term.vecs) if not r==actv_range]
    actv_parsed = [p for r, p in zip (ranges, parsed) if r==actv_range]
    amp = term.amp
    if len (actv_parsed) > 0:
        actv_cr_idxs = sum([[p[2][0]] for p in actv_parsed if p[1]==CR], [])
        actv_an_idxs = sum([[p[2][0]] for p in reversed (actv_parsed) if p[1]==AN], [])
        actv_idxs = actv_cr_idxs + actv_an_idxs
        amp = amp * rdm[actv_idxs]
    return Term (term.sums, amp, inac_vecs)
示例#6
0
def _canonicalize_indices(term: Term, spec: _AGPFSpec):
    """Here, we canonicalize the free indices in the tensor expressions - that
    is replace the higher key indices with lower key ones everywhere
    """

    # get the new term and substs
    new_amp, substs = _try_simpl_unresolved_deltas(term.amp)

    # check for overlap in the dlists and unique_indices
    # if any of the maps contain two indices that are supposed to be unique,
    # it should return zero/empty term.
    unique_list = spec.unique_ind

    # New substitutions based on the chain of delta
    new_substs = {}

    if substs:
        dlists = _delta_map(substs)

        for s1 in dlists:
            s1_sorted = list(ordered(s1))
            j = 1
            while j < len(s1_sorted):
                new_substs[s1_sorted[j]] = s1_sorted[0]
                j += 1

            if not unique_list:
                continue

            for s2 in unique_list:
                if len(list(s1 & s2)) > 1:
                    return []
                else:
                    continue

    # construct the new term
    new_term = term.subst(new_substs)

    return [Term(sums=new_term.sums, amp=new_amp, vecs=new_term.vecs)]
示例#7
0
        def vev_of_term(term):
            """Return the VEV of a given term"""
            vecs = term.vecs
            t_amp = term.amp
            ind_list = []

            if len(vecs) == 0:
                return term
            elif all(v.base == ctan for v in vecs):
                for i in vecs:
                    if set(i.indices).issubset(set(ind_list)):
                        t_amp = t_amp * 2
                        # NOTE: This is only true when evaluating expectation over AGP,
                        # or any other seniority zero state
                    else:
                        ind_list.extend(list(i.indices))
            else:
                return []

            t_amp = t_amp * gam[ind_list]
            return [Term(sums=term.sums, amp=t_amp, vecs=())]
示例#8
0
        def get_vev_of_term(term):
            """Return the vev mapping of the term"""
            vecs = term.vecs
            t_amp = term.amp
            pdag_cnt = 0
            p_cnt = 0
            n_cnt = 0

            pdag_indlist = []
            p_indlist = []
            n_indlist = []

            if len(vecs) == 0:
                return [
                    Term(sums=term.sums, amp=t_amp * zlist[0][0], vecs=vecs)
                ]

            # Classify the indices into pdag, n, and p indicies
            for i in vecs:
                if i.base == pdag_:
                    pdag_indlist.extend(list(i.indices))
                elif i.base == p_:
                    p_indlist.extend(list(i.indices))
                elif i.base == num_:
                    n_indlist.extend(list(i.indices))
                else:
                    return []

            # Count the number of indices
            pdag_cnt = len(pdag_indlist)
            p_cnt = len(p_indlist)

            # First, we extract only the unique N indices
            unique_n_indlist = list(set(n_indlist))
            n_cnt = len(unique_n_indlist)

            # Introduce appropriate power of 2 in amplitude to include the effect
            #   of unique indices only  being considered in N
            ldiff = len(n_indlist) - len(unique_n_indlist)
            t_amp *= 2**(ldiff)

            if pdag_cnt != p_cnt:
                # The expression must have equal number of Pdag's and P_'s
                return []
            elif len(pdag_indlist) != len(set(pdag_indlist)):
                return []
            elif len(p_indlist) != len(set(p_indlist)):
                return []
            else:
                # Combining all the indices
                indcs = pdag_indlist
                indcs.extend(unique_n_indlist)
                indcs.extend(p_indlist)

                # Counting the different number of indices in order
                # to select the right symbol 'asymb'
                idx1 = int(n_cnt)
                idx_ppdag = len(indcs) - n_cnt
                idx2 = int((idx_ppdag / 2))

                asymb = zlist[idx1][idx2]
                t_amp = t_amp * asymb[indcs]

            return [Term(sums=term.sums, amp=t_amp, vecs=())]
示例#9
0
def _get_su2_vecs(term: Term, spec: _AGPFSpec):
    """Given a term with a list of vectors, extract the obvious BCS vectors
    NOTE: This bind function assumes that the term has already been simplified
    NOTE2: We just ignore the SP and SM terms in extracting su2
    """
    vecs = term.vecs
    amp = term.amp
    int_vecs = []
    new_vecs = []

    Pdag = spec.Pdag
    P = spec.P
    N = spec.N

    N_up = spec.Nup
    N_dn = spec.Ndn

    SP = spec.S_p
    SM = spec.S_m
    SZ = spec.S_z

    cr = (spec.c_dag.base, spec.c_dag.indices[0])
    an = (spec.c_.base, spec.c_.indices[0])

    # Get rid of the trivial case where no SU2 vector is possible.
    if len(vecs) <= 1:
        new_vecs = vecs
        return [Term(sums=term.sums, amp=amp, vecs=new_vecs)]

    # Now onto the more involved situations:
    # First, let us extract all the number and pair-annihilation operators
    i = 0
    while i < (len(vecs) - 1):

        v1 = (vecs[i].base, vecs[i].indices[0])
        v2 = (vecs[i + 1].base, vecs[i + 1].indices[0])

        if (v1 == cr):
            if (v2 == an):
                if (vecs[i].indices[1:] == vecs[i + 1].indices[1:]):
                    if vecs[i].indices[2] == SpinOneHalf.UP:
                        int_vecs.append(N_up[vecs[i].indices[1]])
                    elif vecs[i].indices[2] == SpinOneHalf.DOWN:
                        int_vecs.append(N_dn[vecs[i].indices[1]])
                    i += 2
                    continue
                # elif (vecs[i].indices[1] == vecs[i+1].indices[1]):
                #     if vecs[i].indices[2] == SpinOneHalf.UP:
                #         int_vecs.append(SP[vecs[i].indices[1]])
                #         i += 2
                #         continue
                #     else:
                #         int_vecs.append(SM[vecs[i].indices[1]])
                #         i += 2
                #         continue
                else:
                    int_vecs.append(vecs[i])
                    i += 1
                    continue
            elif (v2 == cr):
                # Do not consider the pair-creation operators yet
                int_vecs.append(vecs[i])
                i += 1
                continue
            else:
                raise ValueError('Input term is not simplified')

        elif (v1 == an):
            if (v2 == an):
                if (vecs[i].indices[1] == vecs[i + 1].indices[1]):
                    # if both annihilation, and have same lattice index,
                    #   then assuming the term is simplified, the spins
                    #    must be opposite (first one would be DOWN)
                    int_vecs.append(P[vecs[i].indices[1]])
                    i += 2
                    continue
                else:
                    int_vecs.append(vecs[i])
                    i += 1
                    continue
            else:
                int_vecs.append(vecs[i])
                i += 1
                continue
        else:
            int_vecs.append(vecs[i])
            i += 1
            continue

    # If the last two operators did not map, we are left with
    # the last fermion operator
    if i == len(vecs) - 1:
        int_vecs.append(vecs[i])

    # Now map all the pair-creation operators
    i = 0
    while i < (len(int_vecs) - 1):

        v1 = (int_vecs[i].base, int_vecs[i].indices[0])
        v2 = (int_vecs[i + 1].base, int_vecs[i + 1].indices[0])

        if (v1 == cr):
            if (v2 == cr):
                if (int_vecs[i].indices[1] == int_vecs[i + 1].indices[1]):
                    # if both creation, and have same lattice index,
                    #   then assuming term is simplified, the spins must be
                    #   opposite.
                    new_vecs.append(Pdag[int_vecs[i].indices[1]])
                    i += 2
                    continue
                else:
                    new_vecs.append(int_vecs[i])
                    i += 1
                    continue
            else:
                new_vecs.append(int_vecs[i])
                i += 1
                continue
                # raise ValueError('Input term is not simplified')
        else:
            new_vecs.append(int_vecs[i])
            i += 1
            continue

    # If the last two operators did not map, we are left with
    # the last fermion operator
    if i == len(int_vecs) - 1:
        new_vecs.append(int_vecs[i])

    return [Term(sums=term.sums, amp=amp, vecs=new_vecs)]