def decomp_4rdm_to_3rdm_sf(d4, d1, d2, d2_hom, d2_het, d3): """ Returns the list of terms composing the decomposition of the 4 body spin free rdm d4 in terms of one, two, and three body rdms" """ # This decomposition assumes the density matrices correspond to a spin averaged ensemble state. # d4 -- Spin free 4rdm to be decomposed # d1 -- One body spin free rdm # d2 -- Two body spin free rdm # d2_hom -- Sum of all alpha and all beta two body rdms. The "homogeneous spin" 2rdm. # d2_het -- Sum of abab and baba two body rdms. The "heterogeneous spin" 2rdm. # d3 -- Three body spin free rdm # Note that d2 = d2_hom + d2_het # Check input if ( not isinstance(d4, tensor) ) or (len(d4.indices) != 8): raise TypeError, "d4 must be a tensor with 8 indices" if ( not isinstance(d1, tensor) ) or (len(d1.indices) != 2): raise TypeError, "d1 must be a tensor with 2 indices" if ( not isinstance(d2, tensor) ) or (len(d2.indices) != 4): raise TypeError, "d2 must be a tensor with 4 indices" if ( not isinstance(d2_hom, tensor) ) or (len(d2_hom.indices) != 4): raise TypeError, "d2_hom must be a tensor with 4 indices" if ( not isinstance(d2_het, tensor) ) or (len(d2_het.indices) != 4): raise TypeError, "d2_het must be a tensor with 4 indices" if ( not isinstance(d3, tensor) ) or (len(d3.indices) != 6): raise TypeError, "d3 must be a tensor with 6 indices" # Initialize the return value decomp = [] # Compute terms from the sum involving the 3-body cumulant for p in range(4): ti = range(4) del(ti[p]) ti.insert(0,p) for q in range(4): bi = range(4) del(bi[q]) bi.insert(0,q) for i in range(1,4): for j in range(1,4): if i != j and ti[i] == bi[j]: temp = bi[i] bi[i] = bi[j] bi[j] = temp # Determine the number of index permutations n_perm = get_num_perms(ti,bi) # Determine the sign sign = (-1)**n_perm # Create the 1RDM 3RDM term bj = [i+4 for i in bi] coeff = sign * (0.5)**n_perm d1_copy_0 = d1.copy() d1_copy_0.indices = [d4.indices[i] for i in (ti[0:1] + bj[0:1])] d3_copy_0 = d3.copy() d3_copy_0.indices = [d4.indices[i] for i in (ti[1:4] + bj[1:4])] decomp.append(term(coeff, [], [d1_copy_0, d3_copy_0])) # Create terms not involving the 3RDM d3_decomp = decomp_3rdm_to_2rdm_sf(d3_copy_0, d1, d2) for t in d3_decomp: coeff = (-1) * sign * (0.5)**n_perm * t.numConstant decomp.append(term(coeff, [], [d1_copy_0] + t.tensors)) # Compute terms from the sum involving two 2-body cumulants for p in range(1): for q in range(p+1,4): ti = [p,q] for i in range(4): if not (i in ti): ti.append(i) for r in range(4): for s in range(r+1,4): if s == p or r == q: bi = [s,r] else: bi = [r,s] temp = range(4) del temp[s] del temp[r] if temp[0] == ti[3] or temp[1] == ti[2]: temp = [temp[1], temp[0]] bi += temp # Determine the number of index permutations n_perm = get_num_perms(ti,bi) # Determine the sign sign = (-1)**n_perm # Create 2RDM 2RDM term bj = [i+4 for i in bi] if n_perm < 2: coeff = sign * (0.5)**n_perm d2_copy_0 = d2.copy() d2_copy_0.indices = [d4.indices[i] for i in (ti[0:2] + bj[0:2])] d2_copy_1 = d2.copy() d2_copy_1.indices = [d4.indices[i] for i in (ti[2:4] + bj[2:4])] decomp.append(term(coeff, [], [d2_copy_0, d2_copy_1])) elif n_perm == 2: coeff = sign * 0.5 d2_hom_copy_0 = d2_hom.copy() d2_hom_copy_0.indices = [d4.indices[i] for i in (ti[0:2] + bj[0:2])] d2_hom_copy_1 = d2_hom.copy() d2_hom_copy_1.indices = [d4.indices[i] for i in (ti[2:4] + bj[2:4])] decomp.append(term(coeff, [], [d2_hom_copy_0, d2_hom_copy_1])) d2_het_copy_0 = d2_het.copy() d2_het_copy_0.indices = [d4.indices[i] for i in (ti[0:2] + bj[0:2])] d2_het_copy_1 = d2_het.copy() d2_het_copy_1.indices = [d4.indices[i] for i in (ti[2:4] + bj[2:4])] decomp.append(term(coeff, [], [d2_het_copy_0, d2_het_copy_1])) d2_het_copy_0 = d2_het.copy() d2_het_copy_0.indices = [d4.indices[i] for i in (ti[0:2] + [bj[1], bj[0]])] d2_het_copy_1 = d2_het.copy() d2_het_copy_1.indices = [d4.indices[i] for i in (ti[2:4] + [bj[3], bj[2]])] decomp.append(term(coeff, [], [d2_het_copy_0, d2_het_copy_1])) else: raise RuntimeError, "Did not expect a term with %i permutations" %n_perm # Create 'un-permuted' 2RDM 1RDM 1RDM terms coeff = sign * (-1) * (0.5)**n_perm d2_copy_0 = d2.copy() d2_copy_0.indices = [d4.indices[i] for i in (ti[0:2] + bj[0:2])] d1_copy_0 = d1.copy() d1_copy_0.indices = [d4.indices[i] for i in (ti[2:3] + bj[2:3])] d1_copy_1 = d1.copy() d1_copy_1.indices = [d4.indices[i] for i in (ti[3:4] + bj[3:4])] decomp.append(term(coeff, [], [d2_copy_0, d1_copy_0, d1_copy_1])) d2_copy_0 = d2.copy() d2_copy_0.indices = [d4.indices[i] for i in (ti[2:4] + bj[2:4])] d1_copy_0 = d1.copy() d1_copy_0.indices = [d4.indices[i] for i in (ti[0:1] + bj[0:1])] d1_copy_1 = d1.copy() d1_copy_1.indices = [d4.indices[i] for i in (ti[1:2] + bj[1:2])] decomp.append(term(coeff, [], [d2_copy_0, d1_copy_0, d1_copy_1])) # Create 'permuted' 2RDM 1RDM 1RDM terms if n_perm < 2: bj = bi[0:2] + bi[3:4] + bi[2:3] n_perm = get_num_perms(ti,bj) bj = [i+4 for i in bj] coeff = sign * (0.5)**n_perm d2_copy_0 = d2.copy() d2_copy_0.indices = [d4.indices[i] for i in (ti[0:2] + bj[0:2])] d1_copy_0 = d1.copy() d1_copy_0.indices = [d4.indices[i] for i in (ti[2:3] + bj[2:3])] d1_copy_1 = d1.copy() d1_copy_1.indices = [d4.indices[i] for i in (ti[3:4] + bj[3:4])] decomp.append(term(coeff, [], [d2_copy_0, d1_copy_0, d1_copy_1])) bj = bi[1:2] + bi[0:1] + bi[2:4] n_perm = get_num_perms(ti,bj) bj = [i+4 for i in bj] coeff = sign * (0.5)**n_perm d2_copy_0 = d2.copy() d2_copy_0.indices = [d4.indices[i] for i in (ti[2:4] + bj[2:4])] d1_copy_0 = d1.copy() d1_copy_0.indices = [d4.indices[i] for i in (ti[0:1] + bj[0:1])] d1_copy_1 = d1.copy() d1_copy_1.indices = [d4.indices[i] for i in (ti[1:2] + bj[1:2])] decomp.append(term(coeff, [], [d2_copy_0, d1_copy_0, d1_copy_1])) elif n_perm == 2: bj = bi[1:2] + bi[0:1] + bi[3:4] + bi[2:3] n_perm = get_num_perms(ti,bj) bj = [i+4 for i in bj] coeff = sign * (-1) * (0.5)**n_perm d2_copy_0 = d2.copy() d2_copy_0.indices = [d4.indices[i] for i in (ti[0:2] + bj[0:2])] d1_copy_0 = d1.copy() d1_copy_0.indices = [d4.indices[i] for i in (ti[2:3] + bj[2:3])] d1_copy_1 = d1.copy() d1_copy_1.indices = [d4.indices[i] for i in (ti[3:4] + bj[3:4])] decomp.append(term(coeff, [], [d2_copy_0, d1_copy_0, d1_copy_1])) d2_copy_0 = d2.copy() d2_copy_0.indices = [d4.indices[i] for i in (ti[2:4] + bj[2:4])] d1_copy_0 = d1.copy() d1_copy_0.indices = [d4.indices[i] for i in (ti[0:1] + bj[0:1])] d1_copy_1 = d1.copy() d1_copy_1.indices = [d4.indices[i] for i in (ti[1:2] + bj[1:2])] decomp.append(term(coeff, [], [d2_copy_0, d1_copy_0, d1_copy_1])) else: raise RuntimeError, "Did not expect a term with %i permutations" %n_perm # Create 1RDM 1RDM 1RDM 1RDM terms bj = [i for i in bi] n_perm = get_num_perms(ti,bj) bj = [i+4 for i in bj] coeff = sign * (0.5)**n_perm d1_copies = [] for j in range(4): d1_copies.append(d1.copy()) d1_copies[-1].indices = [d4.indices[i] for i in (ti[j:j+1] + bj[j:j+1])] decomp.append(term(coeff, [], d1_copies)) bj = bi[0:2] + bi[3:4] + bi[2:3] n_perm = get_num_perms(ti,bj) bj = [i+4 for i in bj] coeff = sign * (-1) * (0.5)**n_perm d1_copies = [] for j in range(4): d1_copies.append(d1.copy()) d1_copies[-1].indices = [d4.indices[i] for i in (ti[j:j+1] + bj[j:j+1])] decomp.append(term(coeff, [], d1_copies)) bj = bi[1:2] + bi[0:1] + bi[2:4] n_perm = get_num_perms(ti,bj) bj = [i+4 for i in bj] coeff = sign * (-1) * (0.5)**n_perm d1_copies = [] for j in range(4): d1_copies.append(d1.copy()) d1_copies[-1].indices = [d4.indices[i] for i in (ti[j:j+1] + bj[j:j+1])] decomp.append(term(coeff, [], d1_copies)) bj = bi[1:2] + bi[0:1] + bi[3:4] + bi[2:3] n_perm = get_num_perms(ti,bj) bj = [i+4 for i in bj] coeff = sign * (0.5)**n_perm d1_copies = [] for j in range(4): d1_copies.append(d1.copy()) d1_copies[-1].indices = [d4.indices[i] for i in (ti[j:j+1] + bj[j:j+1])] decomp.append(term(coeff, [], d1_copies)) # Compute terms from the sum involving one 2-body cumulant for p in range(4): for q in range(p+1,4): ti = [p,q] for i in range(4): if not (i in ti): ti.append(i) for r in range(4): for s in range(4): if r == s: continue bi = [r,s] temp = range(4) del temp[max(r,s)] del temp[min(r,s)] if temp[0] == ti[3] or temp[1] == ti[2]: temp = [temp[1], temp[0]] bi += temp # Determine the number of index permutations n_perm = get_num_perms(ti,bi) # Determine the sign sign = (-1)**n_perm # Compute 1RDM 1RDM 2RDM term coeff = 1 bj = [i for i in bi] pairs_rdm1 = [ [ti[i],bj[i]] for i in range(2)] pairs_rdm2 = [ [bj[i],ti[i]] for i in range(2,4)] for pair in pairs_rdm2: if pair[0] == pair[1]: pairs_rdm2 = [] break for pair in pairs_rdm2: if not (pair in pairs_rdm1): #print "swapping bj[2] and bj[3]" (bj[3],bj[2]) = (bj[2],bj[3]) coeff *= -1 break n_perm = get_num_perms(ti,bj) bj = [i+4 for i in bj] coeff *= sign * (0.5)**n_perm d1_copy_0 = d1.copy() d1_copy_0.indices = [d4.indices[i] for i in (ti[0:1] + bj[0:1])] d1_copy_1 = d1.copy() d1_copy_1.indices = [d4.indices[i] for i in (ti[1:2] + bj[1:2])] d2_copy_0 = d2.copy() d2_copy_0.indices = [d4.indices[i] for i in (ti[2:4] + bj[2:4])] decomp.append(term(coeff, [], [d1_copy_0, d1_copy_1, d2_copy_0])) # Compute 'un-permuted' 1RDM 1RDM 1RDM 1RDM term bj = [i for i in bi] n_perm = get_num_perms(ti,bj) bj = [i+4 for i in bj] coeff = sign * (-1) * (0.5)**n_perm d1_copies = [] for j in range(4): d1_copies.append(d1.copy()) d1_copies[-1].indices = [d4.indices[i] for i in (ti[j:j+1] + bj[j:j+1])] decomp.append(term(coeff, [], d1_copies)) # Compute 'permuted' 1RDM 1RDM 1RDM 1RDM term bj = bi[0:2] + bi[3:4] + bi[2:3] n_perm = get_num_perms(ti,bj) bj = [i+4 for i in bj] coeff = sign * (0.5)**n_perm d1_copies = [] for j in range(4): d1_copies.append(d1.copy()) d1_copies[-1].indices = [d4.indices[i] for i in (ti[j:j+1] + bj[j:j+1])] decomp.append(term(coeff, [], d1_copies)) # Compute terms from the sum involving only one particle density matrices ti = range(4) for bi in makePermutations(4): # Determine the number of permutations n_perm = get_num_perms(ti,bi) # Determine the sign sign = (-1)**n_perm # Compute 1RDM 1RDM 1RDM 1RDM term bj = [i+4 for i in bi] coeff = sign * (0.5)**n_perm d1_copies = [] for j in range(4): d1_copies.append(d1.copy()) d1_copies[-1].indices = [d4.indices[i] for i in (ti[j:j+1] + bj[j:j+1])] decomp.append(term(coeff, [], d1_copies)) # Combine like terms for t in decomp: t.tensors.sort() decomp.sort() i = 0 while i < len(decomp)-1: if decomp[i].tensors == decomp[i+1].tensors: decomp[i+1].numConstant += decomp[i].numConstant del(decomp[i]) else: i += 1 termChop(decomp) # Return the decomposition return decomp
def decomp_3rdm_to_2rdm_sf(d3, d1, d2, indexOrder = '1212'): """ Returns the list of terms composing the decomposition of the 3 body spin free rdm d3 in terms of one and two body rdms" """ if ( not isinstance(d1, tensor) ) or (len(d1.indices) != 2): raise TypeError, "d1 must be a tensor with 2 indices" if ( not isinstance(d2, tensor) ) or (len(d2.indices) != 4): raise TypeError, "d2 must be a tensor with 4 indices" if ( not isinstance(d3, tensor) ) or (len(d3.indices) != 6): raise TypeError, "d3 must be a tensor with 6 indices" # sort the 3-body RDM's indices into 1212 ordering d3_indices = [] if indexOrder == '1212': d3_indices.extend(d3.indices) elif indexOrder == '1122': for i in range(3): d3_indices.append(d3.indices[2*i]) for i in range(3): d3_indices.append(d3.indices[2*i+1]) else: raise ValueError, "unexpected indexOrder parameter: %s" %(indexOrder) decomp = [] # Prepare terms from sum (-1)^p %gamma^{i_1}_{i_4} %lambda^{i_2`i_3}_{i_5`i_6} for p0 in range(3): temp = range(3) del temp[p0] p1 = temp[0] p2 = temp[1] ti = [p0, p1, p2] for q0 in range(3): temp = range(3) del temp[q0] q1 = temp[0] q2 = temp[1] if q1 == p2 or q2 == p1: bi = [q0, q2, q1] else: bi = [q0, q1, q2] # determine the sign of the term based on the number of index permutations n_perm = get_num_perms(ti,bi) if n_perm > 1: raise ValueError, "n_perm = %i which is > 1. This was unexpected." %n_perm sign = (-1)**n_perm # create the 1RDM 2RDM term bj = [i for i in bi] n_perm = get_num_perms(ti,bj) coeff = sign * (0.5)**n_perm bj = [i+3 for i in bj] d1_copy_0 = d1.copy() d1_copy_0.indices = [d3_indices[i] for i in (ti[0:1] + bj[0:1])] d2_copy_0 = d2.copy() d2_copy_0.indices = [d3_indices[i] for i in (ti[1:3] + bj[1:3])] decomp.append(term(coeff, [], [d1_copy_0, d2_copy_0])) # create the 1RDM 1RDM 1RDM terms bj = [i for i in bi] n_perm = get_num_perms(ti,bj) coeff = sign * (-1) * (0.5)**n_perm bj = [i+3 for i in bj] d1_copies = [] for j in range(3): d1_copies.append(d1.copy()) d1_copies[-1].indices = [d3_indices[i] for i in (ti[j:j+1] + bj[j:j+1])] decomp.append(term(coeff, [], d1_copies)) bj = bi[0:1] + bi[2:3] + bi[1:2] n_perm = get_num_perms(ti,bj) coeff = sign * (0.5)**n_perm bj = [i+3 for i in bj] d1_copies = [] for j in range(3): d1_copies.append(d1.copy()) d1_copies[-1].indices = [d3_indices[i] for i in (ti[j:j+1] + bj[j:j+1])] decomp.append(term(coeff, [], d1_copies)) # Compute terms from the sum involving only one particle density matrices ti = range(3) for bi in makePermutations(3): # Determine the number of permutations n_perm = get_num_perms(ti,bi) # Determine the sign sign = (-1)**n_perm # Compute 1RDM 1RDM 1RDM 1RDM term bj = [i+3 for i in bi] coeff = sign * (0.5)**n_perm d1_copies = [] for j in range(3): d1_copies.append(d1.copy()) d1_copies[-1].indices = [d3_indices[i] for i in (ti[j:j+1] + bj[j:j+1])] decomp.append(term(coeff, [], d1_copies)) # Combine like terms for t in decomp: t.tensors.sort() decomp.sort() i = 0 while i < len(decomp)-1: if decomp[i].tensors == decomp[i+1].tensors: decomp[i+1].numConstant += decomp[i].numConstant del(decomp[i]) else: i += 1 termChop(decomp) # if original ordering was 1122, convert back to it if indexOrder == '1122': for t in decomp: for ten in t.tensors: if ten.name == d2.name: ten.indices = [ten.indices[0], ten.indices[2], ten.indices[1], ten.indices[3]] # Return the decomposition return decomp
def contractCoreOps_sf(inTerm): "Returns a list of terms resulting from normal ordering the operators in inTerm." # check that inTerm is a term if not isinstance(inTerm, term): raise TypeError, "inTerm must be of class term" # Make separate lists of the spin free excitation operators and other tensors sfExOp_list = [] other_list = [] for t in inTerm.tensors: if isinstance(t, sfExOp): sfExOp_list.append(t.copy()) else: other_list.append(t.copy()) # Initialize n, the number of remaining spin free excitation operators if len(sfExOp_list) != 1: raise RuntimeError, "terms should have single sfExOp" # Give short names for the excitation operator and their order e1 = sfExOp_list[0] o1 = e1.order # list of offset of "core" type indices cIndsCre = [] cIndsDes = [] for i in range(o1): if e1.indices[i].indType == (options.core_type,): cIndsCre.append(i) if e1.indices[i+o1].indType == (options.core_type,): cIndsDes.append(i+o1) # all the "core" type indices should be contracted nc = len(cIndsCre) outTerms = [] if nc != len(cIndsDes): outTerms.append(term(0.0, [], [])) return outTerms if nc == 0: outTerms = [inTerm.copy()] return outTerms newOrder = o1 - nc # For each contraction, compute the resulting term perms = makePermutations(nc) for perm in perms: # Compute the pairs of indices to be contracted # Example: (conPairs[0][p], conPairs[1][p]) is the pth contraction pair. conPairs = [[],[]] for i in range(nc): conPairs[0].append(cIndsCre[perm[i]]) conPairs[1].append(cIndsDes[i]) # evaluate constant prefactor prefactor = 1 inds = [] for i in range(nc): if i not in inds: inds.append(i) i0 = conPairs[0][i] i1 = conPairs[1][i] - o1 if i1 == i0: prefactor *= 2 continue #old if i1 in conPairs[0]: #old inds.append(conPairs[0].index(i1)) #old i2 = conPairs[1][conPairs[0].index(i1)] - o1 #old if i2 == i0: #old prefactor *= 2 #old continue #old if i2 in conPairs[0]: #old inds.append(conPairs[0].index(i2)) #old i3 = conPairs[1][conPairs[0].index(i2)] - o1 #old if i3 == i0: #old prefactor *= 2 #old continue #old if i3 in conPairs[0]: #old inds.append(conPairs[0].index(i3)) #old i4 = conPairs[1][conPairs[0].index(i3)] - o1 #old if i4 == i0: #old prefactor *= 2 #old continue #old else: #old raise RuntimeError, "NYI:recursive algorithm1" while i1 in conPairs[0]: inds.append(conPairs[0].index(i1)) i1 = conPairs[1][conPairs[0].index(i1)] - o1 if i1 == i0: prefactor *= 2 break # # Initialize the term's tensor list tensorList = other_list[:] # Initialize the index list for the new excitation operator indexList = [False] * (2*newOrder) # Populate the index list for the new excitation operator # Also, create a kronecker delta function for each contraction pair count = 0 for i1 in range(o1): if i1 in conPairs[0]:#create a kronecker delta i2 = conPairs[1][conPairs[0].index(i1)] ind1 = e1.indices[i1] ind2 = e1.indices[i2] tensorList.insert(0, kroneckerDelta([ind1,ind2])) else: #insert a pair of indices indexList[count] = e1.indices[i1] i2 = i1+o1 #old if i2 in conPairs[1]: #old i2 = conPairs[0][conPairs[1].index(i2)] + o1 #old if i2 in conPairs[1]: #old i2 = conPairs[0][conPairs[1].index(i2)] + o1 #old if i2 in conPairs[1]: #old i2 = conPairs[0][conPairs[1].index(i2)] + o1 #old if i2 in conPairs[1]: #old i2 = conPairs[0][conPairs[1].index(i2)] + o1 #old if i2 in conPairs[1]: #old raise RuntimeError, "NYI:recursive algorithm2" #old else: #old indexList[count+newOrder] = e1.indices[i2] #old else: #old indexList[count+newOrder] = e1.indices[i2] #old else: #old indexList[count+newOrder] = e1.indices[i2] #old else: #old indexList[count+newOrder] = e1.indices[i2] while i2 in conPairs[1]: i2 = conPairs[0][conPairs[1].index(i2)] + o1 else: indexList[count+newOrder] = e1.indices[i2] # count += 1 # Ensure that all slots in the index list have been filled for ind in indexList: if ind is False: raise RuntimeError, "There is at least one unassigned index in the new spin free operator." # Add the new excitation operator to the tensor list if len(indexList) != 0: tensorList.append(sfExOp(indexList)) # Determine the sign indPairs = [[],[]] for i in range(o1): indPairs[0].append(i) if i in conPairs[0]: indPairs[1].append(conPairs[1][conPairs[0].index(i)]-o1) else: a = e1.indices[i] b = indexList[indexList.index(a)+newOrder] #indPairs[1].append(e1.indices.index(b)-o1)#is not correct when there are duplicate indices indPairs[1].append(e1.indices[o1:2*o1].index(b)) #for i in range(o1): indPairs[1].index(i) n_perm = get_num_perms(indPairs[0], indPairs[1]) sign = (-1)**n_perm # Add the resulting term to this iteration's list of output terms #print term(sign*prefactor*inTerm.numConstant, inTerm.constants, tensorList) #print "-------------------------------------------------------------------" outTerms.append(term(sign*prefactor*inTerm.numConstant, inTerm.constants, tensorList)) return outTerms
def decomp_3op_to_2op_2rdm_sf(op, d1, d2, indexOrder = '1212'): """ Returns the list of terms composing the decomposition of the 3 body sfExOp op in terms of one and two body operators" """ # Check input if ( not isinstance(op, sfExOp) ) or (op.order != 3): raise TypeError, "op must be a 3-particle sfExOp" if ( not isinstance(d1, tensor) ) or (len(d1.indices) != 2): raise TypeError, "d1 must be a tensor with 2 indices" if ( not isinstance(d2, tensor) ) or (len(d2.indices) != 4): raise TypeError, "d2 must be a tensor with 4 indices" if indexOrder != '1212' and indexOrder != '1122': raise ValueError, "indexOrder must be '1212' or '1122'" # Initialize the return value decomp = [] # Loop over the nine index permutations used in the decomposition for p0 in range(3): # Compute the top indices temp = range(3) del temp[p0] p1 = temp[0] p2 = temp[1] ti = [p0, p1, p2] for q0 in range(3): # Compute the bottom indices, remembering that the second and third index pairs # should retain original pairing as much as possible. temp = range(3) del temp[q0] q1 = temp[0] q2 = temp[1] if q1 == p2 or q2 == p1: bi = [q0, q2, q1] else: bi = [q0, q1, q2] # Determine the number of permutations from original pairing n_perms = get_num_perms(ti,bi) # Shift bi to match the bottom indices of op bi = [i+op.order for i in bi] # Create 1RDM 2op term d1_copy = d1.copy() d1_copy.indices = [op.indices[ti[0]], op.indices[bi[0]]] indexList = [op.indices[i] for i in ti[1:]] + [op.indices[i] for i in bi[1:]] decomp.append( term( (-0.5)**n_perms, [], [d1_copy, sfExOp(indexList)] ) ) # Create 2RDM 1op term d2_copy = d2.copy() d2_copy.indices = [op.indices[i] for i in ti[1:]] + [op.indices[i] for i in bi[1:]] if indexOrder == '1122': d2_copy.indices = [d2_copy.indices[0], d2_copy.indices[2], d2_copy.indices[1], d2_copy.indices[3]] indexList = [op.indices[ti[0]], op.indices[bi[0]]] decomp.append( term( (-0.5)**n_perms, [], [d2_copy, sfExOp(indexList)] ) ) # Create 1RDM 1RDM 1op terms d1_copy = d1.copy() d1_copy.indices = [op.indices[ti[1]], op.indices[bi[1]]] d1_copy_2 = d1.copy() d1_copy_2.indices = [op.indices[ti[2]], op.indices[bi[2]]] indexList = [op.indices[ti[0]], op.indices[bi[0]]] decomp.append( term( -2 * (-0.5)**n_perms, [], [d1_copy, d1_copy_2, sfExOp(indexList)] ) ) d1_copy = d1.copy() d1_copy.indices = [op.indices[ti[2]], op.indices[bi[1]]] d1_copy_2 = d1.copy() d1_copy_2.indices = [op.indices[ti[1]], op.indices[bi[2]]] indexList = [op.indices[ti[0]], op.indices[bi[0]]] decomp.append( term( (-0.5)**n_perms, [], [d1_copy, d1_copy_2, sfExOp(indexList)] ) ) # Create 1RDM 2RDM term d1_copy = d1.copy() d1_copy.indices = [op.indices[ti[0]], op.indices[bi[0]]] d2_copy = d2.copy() d2_copy.indices = [op.indices[i] for i in ti[1:]] + [op.indices[i] for i in bi[1:]] if indexOrder == '1122': d2_copy.indices = [d2_copy.indices[0], d2_copy.indices[2], d2_copy.indices[1], d2_copy.indices[3]] decomp.append( term( - (-0.5)**n_perms, [], [d1_copy, d2_copy] ) ) # Create 1RDM 1RDM 1RDM terms d1_copy = d1.copy() d1_copy.indices = [op.indices[ti[0]], op.indices[bi[0]]] d1_copy_2 = d1.copy() d1_copy_2.indices = [op.indices[ti[1]], op.indices[bi[1]]] d1_copy_3 = d1.copy() d1_copy_3.indices = [op.indices[ti[2]], op.indices[bi[2]]] decomp.append( term( (4.0 / 3.0) * (-0.5)**n_perms, [], [d1_copy, d1_copy_2, d1_copy_3] ) ) d1_copy = d1.copy() d1_copy.indices = [op.indices[ti[0]], op.indices[bi[0]]] d1_copy_2 = d1.copy() d1_copy_2.indices = [op.indices[ti[2]], op.indices[bi[1]]] d1_copy_3 = d1.copy() d1_copy_3.indices = [op.indices[ti[1]], op.indices[bi[2]]] decomp.append( term( (-2.0 / 3.0) * (-0.5)**n_perms, [], [d1_copy, d1_copy_2, d1_copy_3] ) ) # Return the decomposition return decomp
def contractCoreOps_sf(inTerm): "Returns a list of terms resulting from normal ordering the operators in inTerm." # check that inTerm is a term if not isinstance(inTerm, term): raise TypeError, "inTerm must be of class term" # Make separate lists of the spin free excitation operators and other tensors sfExOp_list = [] other_list = [] for t in inTerm.tensors: if isinstance(t, sfExOp): sfExOp_list.append(t.copy()) else: other_list.append(t.copy()) # Initialize n, the number of remaining spin free excitation operators if len(sfExOp_list) != 1: raise RuntimeError, "terms should have single sfExOp" # Give short names for the excitation operator and their order e1 = sfExOp_list[0] o1 = e1.order # list of offset of "core" type indices cIndsCre = [] cIndsDes = [] for i in range(o1): if e1.indices[i].indType == (options.core_type, ): cIndsCre.append(i) if e1.indices[i + o1].indType == (options.core_type, ): cIndsDes.append(i + o1) # all the "core" type indices should be contracted nc = len(cIndsCre) outTerms = [] if nc != len(cIndsDes): outTerms.append(term(0.0, [], [])) return outTerms if nc == 0: outTerms = [inTerm.copy()] return outTerms newOrder = o1 - nc # For each contraction, compute the resulting term perms = makePermutations(nc) for perm in perms: # Compute the pairs of indices to be contracted # Example: (conPairs[0][p], conPairs[1][p]) is the pth contraction pair. conPairs = [[], []] for i in range(nc): conPairs[0].append(cIndsCre[perm[i]]) conPairs[1].append(cIndsDes[i]) # evaluate constant prefactor prefactor = 1 inds = [] for i in range(nc): if i not in inds: inds.append(i) i0 = conPairs[0][i] i1 = conPairs[1][i] - o1 if i1 == i0: prefactor *= 2 continue #old if i1 in conPairs[0]: #old inds.append(conPairs[0].index(i1)) #old i2 = conPairs[1][conPairs[0].index(i1)] - o1 #old if i2 == i0: #old prefactor *= 2 #old continue #old if i2 in conPairs[0]: #old inds.append(conPairs[0].index(i2)) #old i3 = conPairs[1][conPairs[0].index(i2)] - o1 #old if i3 == i0: #old prefactor *= 2 #old continue #old if i3 in conPairs[0]: #old inds.append(conPairs[0].index(i3)) #old i4 = conPairs[1][conPairs[0].index(i3)] - o1 #old if i4 == i0: #old prefactor *= 2 #old continue #old else: #old raise RuntimeError, "NYI:recursive algorithm1" while i1 in conPairs[0]: inds.append(conPairs[0].index(i1)) i1 = conPairs[1][conPairs[0].index(i1)] - o1 if i1 == i0: prefactor *= 2 break # # Initialize the term's tensor list tensorList = other_list[:] # Initialize the index list for the new excitation operator indexList = [False] * (2 * newOrder) # Populate the index list for the new excitation operator # Also, create a kronecker delta function for each contraction pair count = 0 for i1 in range(o1): if i1 in conPairs[0]: #create a kronecker delta i2 = conPairs[1][conPairs[0].index(i1)] ind1 = e1.indices[i1] ind2 = e1.indices[i2] tensorList.insert(0, kroneckerDelta([ind1, ind2])) else: #insert a pair of indices indexList[count] = e1.indices[i1] i2 = i1 + o1 #old if i2 in conPairs[1]: #old i2 = conPairs[0][conPairs[1].index(i2)] + o1 #old if i2 in conPairs[1]: #old i2 = conPairs[0][conPairs[1].index(i2)] + o1 #old if i2 in conPairs[1]: #old i2 = conPairs[0][conPairs[1].index(i2)] + o1 #old if i2 in conPairs[1]: #old i2 = conPairs[0][conPairs[1].index(i2)] + o1 #old if i2 in conPairs[1]: #old raise RuntimeError, "NYI:recursive algorithm2" #old else: #old indexList[count+newOrder] = e1.indices[i2] #old else: #old indexList[count+newOrder] = e1.indices[i2] #old else: #old indexList[count+newOrder] = e1.indices[i2] #old else: #old indexList[count+newOrder] = e1.indices[i2] while i2 in conPairs[1]: i2 = conPairs[0][conPairs[1].index(i2)] + o1 else: indexList[count + newOrder] = e1.indices[i2] # count += 1 # Ensure that all slots in the index list have been filled for ind in indexList: if ind is False: raise RuntimeError, "There is at least one unassigned index in the new spin free operator." # Add the new excitation operator to the tensor list if len(indexList) != 0: tensorList.append(sfExOp(indexList)) # Determine the sign indPairs = [[], []] for i in range(o1): indPairs[0].append(i) if i in conPairs[0]: indPairs[1].append(conPairs[1][conPairs[0].index(i)] - o1) else: a = e1.indices[i] b = indexList[indexList.index(a) + newOrder] #indPairs[1].append(e1.indices.index(b)-o1)#is not correct when there are duplicate indices indPairs[1].append(e1.indices[o1:2 * o1].index(b)) #for i in range(o1): indPairs[1].index(i) n_perm = get_num_perms(indPairs[0], indPairs[1]) sign = (-1)**n_perm # Add the resulting term to this iteration's list of output terms #print term(sign*prefactor*inTerm.numConstant, inTerm.constants, tensorList) #print "-------------------------------------------------------------------" outTerms.append( term(sign * prefactor * inTerm.numConstant, inTerm.constants, tensorList)) return outTerms