def normalOrder(inTerm): "Returns a list of terms resulting from normal ordering the operators in inTerm." # if options.verbose: # print "converting to normal order: %s" %(str(inTerm)) # check that inTerm is a term if not isinstance(inTerm, term): raise TypeError, "inTerm must be of class term" # determine what types of operators the term contains has_creDesOps = False has_sfExOps = False for t in inTerm.tensors: if isinstance(t, creOp) or isinstance(t, desOp): has_creDesOps = True elif isinstance(t, sfExOp): has_sfExOps = True # If term has both creation/destruction operators and spin free excitation operators, # raise an error if has_creDesOps and has_sfExOps: raise RuntimeError, "Normal ordering not implemented when both creOp/desOp and sfExOp " + \ "tensors are present" # if the term is already normal ordered, return it unchanged elif inTerm.isNormalOrdered(): outTerms = [inTerm.copy()] # Normal ordering for creOp/desOp elif has_creDesOps: # Separate the cre/des operators from other tensors ops = [] nonOps = [] for t in inTerm.tensors: if isinstance(t, creOp) or isinstance(t, desOp): ops.append(t.copy()) else: nonOps.append(t.copy()) # Generate all contraction pairs contractionPairs = [] for i in range(len(ops)): iTerm = ops[i] for j in range(i+1,len(ops)): jTerm = ops[j] if isinstance(iTerm, desOp) and isinstance(jTerm, creOp): contractionPairs.append((i,j)); #print "contractionPairs\n", contractionPairs # Determine maximum contraction order creCount = 0 maxConOrder = 0 for i in range(len(ops)-1,-1,-1): iTerm = ops[i] if isinstance(iTerm, creOp): creCount +=1 elif isinstance(iTerm, desOp) and creCount > 0: maxConOrder += 1 creCount -= 1 del(creCount,iTerm) # Generate all contractions contractions = [] for i in range(maxConOrder+1): subCons = makeTuples(i,contractionPairs) j = 0 while j < len(subCons): creOpTags = [] desOpTags = [] for k in range(i): creOpTags.append(subCons[j][k][1]) desOpTags.append(subCons[j][k][0]) if allDifferent(creOpTags) and allDifferent(desOpTags): j += 1 else: del(subCons[j]) for j in range(len(subCons)): contractions.append(subCons[j]) del(subCons,creOpTags,desOpTags,contractionPairs) #print "contractions:\n", contractions # For each contraction, generate the resulting term outTerms = [] for contraction in contractions: conSign = 1 deltaFuncs = [] conIndeces = [] subOpString = [] subOpString.extend(ops) for conPair in contraction: index1 = ops[conPair[0]].indices[0] index2 = ops[conPair[1]].indices[0] deltaFuncs.append(kroneckerDelta([index1,index2])) subOpString[conPair[0]] = 'contracted' subOpString[conPair[1]] = 'contracted' for q in subOpString[conPair[0]+1:conPair[1]]: if not (q is 'contracted'): conSign *= -1 i = 0 while i < len(subOpString): if subOpString[i] is 'contracted': del(subOpString[i]) else: i += 1 (sortSign,sortedOps) = sortOps(subOpString) totalSign = conSign * sortSign outTensors = [] outTensors.extend(nonOps) outTensors.extend(deltaFuncs) outTensors.extend(sortedOps) outTerms.append( term(totalSign * inTerm.numConstant, inTerm.constants, outTensors) ) # Normal ordering for sfExOps elif has_sfExOps: # 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 n = len(sfExOp_list) # Set the original term, with all excitation operators moved to the end, as the # first iteration's input term iter_input_terms = [term(inTerm.numConstant, inTerm.constants, other_list + sfExOp_list)] # Successively normal order the last two excitation operators until each term # has only one exitation operator left (at which point the term is normal ordered) while n > 1: # Initialize the list to hold this iteration's output terms iter_output_terms = [] # For each of this iteration's input terms, produce all terms resulting from normal ordering # the last two excitation operators for t in iter_input_terms: # Make a list of the term's tensors that excludes the last two excitation operators tensors_except_last_two = [] tensors_except_last_two.extend(t.tensors[0:-2]) # Give short names for the last two excitation operators and their orders e1 = t.tensors[-2] e2 = t.tensors[-1] o1 = e1.order o2 = e2.order # Loop over the number of contractions for nc in range(min(o1,o2)+1): # Compute the order of excitation operator for the current number of contractions newOrder = o1 + o2 - nc # Compute all nc-tuples of index numbers from e1 and e2, as well as all permutations of # the order in which the tuples may be combined to form a contraction perms = [0] if nc > 0: perms = makePermutations(nc) tups1 = makeTuples(nc, range(o1)) tups2 = makeTuples(nc, range(o2)) # For each contraction, compute the resulting term for perm in perms: for tup1 in tups1: for tup2 in tups2: # Initialize the term's tensor list tensorList = [] tensorList.extend(tensors_except_last_two) # 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(tup1[perm[i]]) conPairs[1].append(tup2[i]) # 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 for i in range(o1): indexList[i] = e1.indices[i] # The usual one if i in conPairs[0]: i1 = i+o1 i2 = conPairs[1][conPairs[0].index(i)] ind1 = e1.indices[i1] ind2 = e2.indices[i2] tensorList.insert(0, kroneckerDelta([ind1,ind2])) indexList[i+newOrder] = e2.indices[o2+i2] else: indexList[i+newOrder] = e1.indices[i+o1] # Put the usual counterpart into indexList count = 0 # in case of that e1.indices[i] is not contracted for i in range(o2): if not (i in conPairs[1]): indexList[o1+count] = e2.indices[i] indexList[o1+count+newOrder] = e2.indices[i+o2] 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 tensorList.append(sfExOp(indexList)) # Add the resulting term to this iteration's list of output terms iter_output_terms.append(term(inTerm.numConstant, inTerm.constants, tensorList)) # Set this iteration's list of output terms as the next iteration's input terms iter_input_terms = iter_output_terms # Decrement the counter for the number of excitation operators n -= 1; #print "MADE OK!!!" # Set the return value as the final iteration's output terms outTerms = iter_output_terms else: raise RuntimeError, "Normal ordering function failed to choose what to do." # print "Terms after normal ordering:" # for t in outTerms: # print t 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
def combine_transpose(termList): """ Combines any terms in termList that are the transpose of each other. """ # record the starting time startTime = time.time() # ensure all terms are in canonical form for t in termList: if not t.isInCanonicalForm: if options.verbose: print "making canonical... %s" %(str(t)) t.makeCanonical() # if requested, print a greeting if options.verbose: print "" print "Checking for transpose equivalencies and combining..." # initialize counter variable count = 0 # loop over the terms j = 0 while j < len(termList): # if requested, print each term if options.verbose: print '%i %s' %(count, str(termList[j])) # increment the counter count += 1 # create a temporary term that is the transpose of the current term temp = termList[j].copy() creDes = [] for i in range(len(temp.tensors)-1,-1,-1): ten = temp.tensors[i] if isinstance(ten, creOp): creDes.append(desOp(temp.tensors.pop(i).indices[0])) if isinstance(ten, desOp): creDes.append(creOp(temp.tensors.pop(i).indices[0])) if isinstance(ten, sfExOp): ind_list = temp.tensors.pop(i).indices order = len(ind_list) / 2 creDes.append( sfExOp(ind_list[order:] + ind_list[0:order]) ) temp.tensors.extend(creDes) del(creDes) temp.isInCanonicalForm = False temp.makeCanonical() # Search the remaining terms for a term matching the transpose # of the current term. If a match is found, add the current term's # transpose to the matching term and delete the current term. for k in range(j+1,len(termList)): if temp.sameForm(termList[k]): termList[k].numConstant += temp.numConstant del(termList[j]) break else: j += 1 # if requested, print the elapsed time if options.verbose: print 'Transpose combination complete in %.3f seconds' %(time.time() - startTime) print ''
def SpinFree(inTerm): "" # check that inTerm is a term if not isinstance(inTerm, term): raise TypeError, "inTerm must be of class term" # determine what types of operators the term contains has_creDesOps = False has_sfExOps = False for t in inTerm.tensors: if isinstance(t, creOp) or isinstance(t, desOp): has_creDesOps = True elif isinstance(t, sfExOp): has_sfExOps = True # If not spin free excitation operators, # raise an error if not has_sfExOps: raise RuntimeError, "Present version of HFFermi can treat only sfExOp" if has_creDesOps and has_sfExOps: raise RuntimeError, "Present version of HFFermi can treat only sfExOp" # if the term is already normal ordered, return it unchanged elif not inTerm.isNormalOrdered(): raise RuntimeError, "HFFermi requires normal ordered operators" # Normal ordering for sfExOps elif has_sfExOps: # 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 n = len(sfExOp_list) if n != 1: raise RuntimeError, "terms should have single sfExOp" # obtain rm same index in Spin-Free Op sfExOp_tmp = sfExOp_list[0] const_tmp = inTerm.numConstant order_tmp = sfExOp_list[0].order spin_tmp = sfExOp_list[0].spin Dup = True while Dup: Dup = False for i in range(order_tmp): idxi = sfExOp_tmp.indices[order_tmp - i - 1] name_idxi = idxi.name for j in range(order_tmp): idxj = sfExOp_tmp.indices[j + order_tmp] name_idxj = idxj.name if name_idxi == name_idxj: Dup = True indices_tmp = [] for k in range(len(sfExOp_tmp.indices)): if k != order_tmp - i - 1: if k != j + order_tmp: indices_tmp.append( sfExOp_tmp.indices[k].copy()) sfExOp_tmp = sfExOp(indices_tmp, spin=spin_tmp) const_tmp *= (-1)**(j + order_tmp - (order_tmp - i - 1) + 1) order_tmp = sfExOp_tmp.order #print i, j, name_idxi, name_idxj, order_tmp, sfExOp_tmp break if Dup: break outTerm = term(const_tmp, inTerm.constants, other_list + [sfExOp_tmp]) else: raise RuntimeError, "HFFermi failed to choose what to do." return outTerm
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 normalOrder(inTerm): "Returns a list of terms resulting from normal ordering the operators in inTerm." # if options.verbose: # print "converting to normal order: %s" %(str(inTerm)) # check that inTerm is a term if not isinstance(inTerm, term): raise TypeError, "inTerm must be of class term" # determine what types of operators the term contains has_creDesOps = False has_sfExOps = False for t in inTerm.tensors: if isinstance(t, creOp) or isinstance(t, desOp): has_creDesOps = True elif isinstance(t, sfExOp): has_sfExOps = True # If term has both creation/destruction operators and spin free excitation operators, # raise an error if has_creDesOps and has_sfExOps: raise RuntimeError, "Normal ordering not implemented when both creOp/desOp and sfExOp " + \ "tensors are present" # if the term is already normal ordered, return it unchanged elif inTerm.isNormalOrdered(): outTerms = [inTerm.copy()] # Normal ordering for creOp/desOp elif has_creDesOps: # Separate the cre/des operators from other tensors ops = [] nonOps = [] for t in inTerm.tensors: if isinstance(t, creOp) or isinstance(t, desOp): ops.append(t.copy()) else: nonOps.append(t.copy()) # Generate all contraction pairs contractionPairs = [] for i in range(len(ops)): iTerm = ops[i] for j in range(i + 1, len(ops)): jTerm = ops[j] if isinstance(iTerm, desOp) and isinstance(jTerm, creOp): contractionPairs.append((i, j)) #print "contractionPairs\n", contractionPairs # Determine maximum contraction order creCount = 0 maxConOrder = 0 for i in range(len(ops) - 1, -1, -1): iTerm = ops[i] if isinstance(iTerm, creOp): creCount += 1 elif isinstance(iTerm, desOp) and creCount > 0: maxConOrder += 1 creCount -= 1 del (creCount, iTerm) # Generate all contractions contractions = [] for i in range(maxConOrder + 1): subCons = makeTuples(i, contractionPairs) j = 0 while j < len(subCons): creOpTags = [] desOpTags = [] for k in range(i): creOpTags.append(subCons[j][k][1]) desOpTags.append(subCons[j][k][0]) if allDifferent(creOpTags) and allDifferent(desOpTags): j += 1 else: del (subCons[j]) for j in range(len(subCons)): contractions.append(subCons[j]) del (subCons, creOpTags, desOpTags, contractionPairs) #print "contractions:\n", contractions # For each contraction, generate the resulting term outTerms = [] for contraction in contractions: conSign = 1 deltaFuncs = [] conIndeces = [] subOpString = [] subOpString.extend(ops) for conPair in contraction: index1 = ops[conPair[0]].indices[0] index2 = ops[conPair[1]].indices[0] deltaFuncs.append(kroneckerDelta([index1, index2])) subOpString[conPair[0]] = 'contracted' subOpString[conPair[1]] = 'contracted' for q in subOpString[conPair[0] + 1:conPair[1]]: if not (q is 'contracted'): conSign *= -1 i = 0 while i < len(subOpString): if subOpString[i] is 'contracted': del (subOpString[i]) else: i += 1 (sortSign, sortedOps) = sortOps(subOpString) totalSign = conSign * sortSign outTensors = [] outTensors.extend(nonOps) outTensors.extend(deltaFuncs) outTensors.extend(sortedOps) outTerms.append( term(totalSign * inTerm.numConstant, inTerm.constants, outTensors)) # Normal ordering for sfExOps elif has_sfExOps: # 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 n = len(sfExOp_list) # Set the original term, with all excitation operators moved to the end, as the # first iteration's input term iter_input_terms = [ term(inTerm.numConstant, inTerm.constants, other_list + sfExOp_list) ] # Successively normal order the last two excitation operators until each term # has only one exitation operator left (at which point the term is normal ordered) while n > 1: # Initialize the list to hold this iteration's output terms iter_output_terms = [] # For each of this iteration's input terms, produce all terms resulting from normal ordering # the last two excitation operators for t in iter_input_terms: # Make a list of the term's tensors that excludes the last two excitation operators tensors_except_last_two = [] tensors_except_last_two.extend(t.tensors[0:-2]) # Give short names for the last two excitation operators and their orders e1 = t.tensors[-2] e2 = t.tensors[-1] o1 = e1.order o2 = e2.order #lsh spin s1 = e1.spin s2 = e2.spin spin1f = s1[0][:] spin1e = s1[1][:] spin2f = s2[0][:] spin2e = s2[1][:] shift = max(max(spin1f), max(spin1e)) # Loop over the number of contractions for nc in range(min(o1, o2) + 1): # Compute the order of excitation operator for the current number of contractions newOrder = o1 + o2 - nc # Compute all nc-tuples of index numbers from e1 and e2, as well as all permutations of # the order in which the tuples may be combined to form a contraction perms = [0] if nc > 0: perms = makePermutations(nc) tups1 = makeTuples(nc, range(o1)) tups2 = makeTuples(nc, range(o2)) #print('perms=',perms) #print('tups1=',tups1) #print('tups2=',tups2) # For each contraction, compute the resulting term for perm in perms: for tup1 in tups1: for tup2 in tups2: # Initialize the term's tensor list tensorList = [] tensorList.extend(tensors_except_last_two) # 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(tup1[perm[i]]) conPairs[1].append(tup2[i]) # 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 for i in range(o1): indexList[i] = e1.indices[ i] # The usual one if i in conPairs[0]: i1 = i + o1 i2 = conPairs[1][conPairs[0].index(i)] ind1 = e1.indices[i1] ind2 = e2.indices[i2] tensorList.insert( 0, kroneckerDelta([ind1, ind2])) indexList[i + newOrder] = e2.indices[o2 + i2] else: indexList[i + newOrder] = e1.indices[ i + o1] # Put the usual counterpart into indexList count = 0 # in case of that e1.indices[i] is not contracted for i in range(o2): if not (i in conPairs[1]): indexList[o1 + count] = e2.indices[i] indexList[o1 + count + newOrder] = e2.indices[i + o2] count += 1 #lsh parity test #print 'conPairs=', conPairs parity_n = 0 o1_l = [i for i in range(o1)] o2_l = [i for i in range(o2)] for i in range(len(conPairs[0])): p1 = conPairs[0][i] p2 = conPairs[1][i] parity_n += o1_l.index(p1) #print 'parity = ', p1, p2, o1_l, o2_l, parity_n parity_n += o2_l.index(p2) #print 'parity = ', p1, p2, o1_l, o2_l, parity_n o1_l.remove(p1) o2_l.remove(p2) parity = (-1)**(parity_n) #parity *= 2**(len(conPairs[0])) #lsh spin test spin_dict = {} for i in range(len(conPairs[0])): p1 = conPairs[0][i] p2 = conPairs[1][i] spin_dict[spin2f[p2]] = spin1e[p1] spin_new_f = spin1f[:] #print 'spin 1 = ', spin_new_f for i in range(len(spin2f)): if i not in conPairs[1]: spin_new_f.append(spin2f[i] + shift + 1) #print 'spin 2 = ', spin_new_f spin_new_e = [] for i in range(len(spin1e)): if i not in conPairs[0]: spin_new_e.append(spin1e[i]) #print 'spin 3 = ', spin_new_e for i in spin2e: if i not in spin_dict: spin_new_e.append(i + shift + 1) else: spin_new_e.append(spin_dict[i]) #print 'spin 4 = ', spin_new_e # 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." #print 'spin= ', spin_new_f, spin_new_e # Add the new excitation operator to the tensor list tensorList.append( sfExOp(indexList, spin=[spin_new_f, spin_new_e])) # Add the resulting term to this iteration's list of output terms iter_output_terms.append( term(parity * inTerm.numConstant, inTerm.constants, tensorList)) # Set this iteration's list of output terms as the next iteration's input terms iter_input_terms = iter_output_terms # Decrement the counter for the number of excitation operators n -= 1 #print "MADE OK!!!" # Set the return value as the final iteration's output terms outTerms = iter_output_terms else: raise RuntimeError, "Normal ordering function failed to choose what to do." # print "Terms after normal ordering:" # for t in outTerms: # print t return outTerms