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