The keyword pretty_indices used to be boolean, but is now a dict of lists containing letters to label the new dummy indices. This allows the user much better control over the resulting expression.
Docstring and doctests updated accordingly. --- sympy/physics/secondquant.py | 104 +++++++++++++++++++++++++++--------------- 1 files changed, 67 insertions(+), 37 deletions(-) diff --git a/sympy/physics/secondquant.py b/sympy/physics/secondquant.py index 6a5fa60..9285f83 100644 --- a/sympy/physics/secondquant.py +++ b/sympy/physics/secondquant.py @@ -2541,7 +2541,7 @@ def _substitute(expr, ordered_dummies, arg_iterator, **require): return result -def substitute_dummies(expr, new_indices=False, reverse_order=True, pretty_indices=True): +def substitute_dummies(expr, new_indices=False, reverse_order=True, pretty_indices={}): """ Collect terms by substitution of dummy variables. @@ -2551,19 +2551,22 @@ def substitute_dummies(expr, new_indices=False, reverse_order=True, pretty_indic The idea is to substitute all dummy variables consistently depending on position in the term. For each term, we collect a sequence of all dummy variables, where the order is determined by index position. These indices - are then substituted consistently in each term. E.g. + are then substituted consistently in each term. + + Examples + ======== >>> from sympy import symbols, Function >>> from sympy.physics.secondquant import substitute_dummies - >>> a,b = symbols('ab',dummy=True) - >>> c,d = symbols('cd',dummy=True) + >>> a,b,c,d = symbols('abcd',dummy=True, above_fermi=True) + >>> i,j = symbols('ij',dummy=True, below_fermi=True) >>> f = Function('f') >>> expr = f(a,b) + f(c,d); expr f(_a, _b) + f(_c, _d) - Since a, b, c and d are summation indices, this can be simplified to a - single summation term with a factor 2 + Since a, b, c and d are equivalent summation indices, the expression can be + simplified to a single term (for which the dummy indices are still summed over) >>> substitute_dummies(expr, reverse_order=False) 2*f(_a, _b) @@ -2577,37 +2580,67 @@ def substitute_dummies(expr, new_indices=False, reverse_order=True, pretty_indic >>> substitute_dummies(expr, reverse_order=True) 2*f(_b, _a) - """ + Controlling output + ================== - # pretty_indices = True # Prettier - # pretty_indices = False # Easier to debug + By default the dummy symbols that are already present in the expression + will be reused. However, if new_indices=True, new dummies will be + generated and inserted. + The keyword 'pretty_indices' can be used to control this generation of new + symbols. - if not pretty_indices: - def _i(number): - return 'i_'+str(number) - def _a(number): - return 'a_'+str(number) - def _p(number): - return 'p_'+str(number) + By default the new dummies will be generated on the form i_1, i_2, a_1, + etc. If you supply a dictionary with key:value pairs in the form: + { index_group: string_of_letters } + + The letters will be used as labels for the new dummy symbols. The + index_groups must be one of 'above', 'below' or 'general'. + + >>> expr = f(a,b,i,j) + >>> my_dummies = { 'above':'st','below':'uv' } + >>> substitute_dummies(expr, new_indices=True, pretty_indices=my_dummies) + f(_t, _s, _v, _u) + + If we run out of letters, or if there is no keyword for some index_group + the default dummy generator will be used as a fallback: + + >>> p,q = symbols('pq',dummy=True) # general indices + >>> expr = f(p,q) + >>> substitute_dummies(expr, new_indices=True, pretty_indices=my_dummies) + f(_p_1, _p_0) + + """ + + # setup the replacing dummies + if new_indices: + letters_above = pretty_indices.get('above',"") + letters_below = pretty_indices.get('below',"") + letters_general= pretty_indices.get('general',"") + len_above = len(letters_above) + len_below = len(letters_below) + len_general= len(letters_general) - else: def _i(number): - if number<5: - return "klmno"[number] - else: - return 'o_'+str(number-5) + try: + return letters_below[number] + except IndexError: + return 'i_'+str(number-len_below) + def _a(number): - if number<6: - return "cdefgh"[number] - else: - return 'h_'+str(number-6) + try: + return letters_above[number] + except IndexError: + return 'a_'+str(number-len_above) + def _p(number): - if number<7: - return "tuvwxyz"[number] - else: - return 'z_'+str(number-7) + try: + return letters_general[number] + except IndexError: + return 'p_'+str(number-len_general) + + # reverse iterator for use in _get_dummies() if reverse_order: @@ -2632,21 +2665,20 @@ def arg_iterator(seq): dummies = [ d for d in expr.atoms() if isinstance(d,Dummy) ] dummies.sort() + # generate lists with the dummies we will insert a = i = p = 0 for d in dummies: assum = d.assumptions0 assum["dummy"]=True + if assum.get("above_fermi"): - sym = _a(a) - a +=1 + if new_indices: sym = _a(a); a +=1 l1 = aboves elif assum.get("below_fermi"): - sym = _i(i) - i +=1 + if new_indices: sym = _i(i); i +=1 l1 = belows else: - sym = _p(p) - p +=1 + if new_indices: sym = _p(p); p +=1 l1 = generals if new_indices: @@ -2655,8 +2687,6 @@ def arg_iterator(seq): l1.append(d) - - cases = ( ({'above_fermi':True}, aboves), ({'below_fermi':True}, belows), -- 1.6.5 -- You received this message because you are subscribed to the Google Groups "sympy-patches" group. To post to this group, send email to sympy-patc...@googlegroups.com. To unsubscribe from this group, send email to sympy-patches+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sympy-patches?hl=en.