Source code for sympy.galgebra.precedence

# sympy/galgebra/precedence.py

"""
precedence.py converts a string to a multivector expression where the
user can control the precedence of the of the multivector operators so
that one does not need to put parenthesis around every multivector
operation.  The default precedence used (high to low) is <,>, and | have
an have the highest precedence, then comes ^, and finally *.
"""

from __future__ import print_function

import re as regrep

op_cntrct = regrep.compile(r'(([A-Za-z0-9\_\#]+)(\||<|>)([A-Za-z0-9\_\#]+))')
op_wedge = regrep.compile(r'(([A-Za-z0-9\_\#]+)[\^]{1}([A-Za-z0-9\_\#]+)([\^]{1}([A-Za-z0-9\_\#]+))*)')
ops = r'[\^\|\<\>]+'
ops_search = regrep.compile(r'(\^|\||<|>)+')
parse_paren_calls = 0
global_dict = {}
op_dict = {}
op_lst = []

OPS = {'<>|': r'(([A-Za-z0-9\_\#]+)(\||<|>)([A-Za-z0-9\_\#]+))',
       '^': r'(([A-Za-z0-9\_\#]+)[\^]{1}([A-Za-z0-9\_\#]+)([\^]{1}([A-Za-z0-9\_\#]+))*)',
       '*': r'(([A-Za-z0-9\_\#]+)[\*]{1}([A-Za-z0-9\_\#]+)([\*]{1}([A-Za-z0-9\_\#]+))*)'}


[docs]def define_precedence(gd, op_ord='<>|,^,*'): # Default is Doran and Lasenby convention global global_dict, op_dict, op_lst global_dict = gd op_lst = op_ord.split(',') op_dict = {} for op in op_lst: op_dict[op] = regrep.compile(OPS[op]) return
[docs]def contains_interval(interval1, interval2): # interval1 inside interval2 if interval1[0] > interval2[0] and interval1[1] < interval2[1]: return True else: return False
[docs]def parse_paren(line): global parse_paren_calls parse_paren_calls += 1 if ('(' not in line) or (')' not in line): return [[[line]]] level = 0 max_level = 0 ich = 0 paren_lst = [] for ch in line: if ch == '(': level += 1 paren_lst.append([level, ich]) if ch == ')': if level < 1: raise ValueError('Mismathed Parenthesis in: ' + line + '\n') paren_lst.reverse() iparen = 0 for elem in paren_lst: if elem[0] == level: paren_lst[iparen].append(ich) break iparen += 1 paren_lst.reverse() level -= 1 max_level = max(max_level, level) ich += 1 if level != 0: raise ValueError('Mismatched Parenthesis in: ' + line + '\n') if max_level > 0: level_lst = [] for x in range(max_level + 1): level_lst.append([]) for group in paren_lst: level_lst[group[0]].append(group[1:]) ilevel = max_level while ilevel > 1: level = level_lst[ilevel] level_down = level_lst[ilevel - 1] igroup = 0 for group in level: igroup_down = 0 for group_down in level_down: if contains_interval(group, group_down): level_lst[ilevel][igroup].append(igroup_down) igroup_down += 1 igroup += 1 ilevel -= 1 ilevel = 1 for level in level_lst[1:]: igroup = 0 for group in level: token = '#' + str(parse_paren_calls) + '_' + str(ilevel) + '_' + str(igroup) + '#' level_lst[ilevel][igroup].append(line[group[0]:group[1] + 1]) level_lst[ilevel][igroup].append(token) igroup += 1 ilevel += 1 ilevel = 1 for level in level_lst[1:]: igroup = 0 for group in level: group.append(group[-2]) level_lst[ilevel][igroup] = group igroup += 1 ilevel += 1 ilevel = max_level while ilevel > 1: igroup = 0 for group in level_lst[ilevel]: group_down = level_lst[ilevel - 1][group[2]] replace_text = group_down[-1].replace(group[-3], group[-2]) level_lst[ilevel - 1][group[2]][-1] = replace_text igroup += 1 ilevel -= 1 for group in level_lst[1]: line = line.replace(group[2], group[3]) ilevel = 1 level_lst[0] = [[line]] return level_lst
[docs]def unparse_paren(level_lst): line = level_lst[0][0][0] for level in level_lst[1:]: for group in level: new_string = group[-1] if new_string[:2] == '((' and new_string[-2:] == '))': new_string = new_string[1:-1] line = line.replace(group[-2], new_string) return line
[docs]def sub_paren(s): string = s.group(0) return '(%s)' % string
[docs]def add_paren(line, re_exprs): paren_flg = False if (line[0] == '(') and (line[-1] == ')'): paren_flg = True line = line[1:-1] if ('(' in line) or (')' in line): line_levels = parse_paren(line) ilevel = 0 for level in line_levels: igroup = 0 for group in level: group[-1] = regrep.sub(re_exprs, sub_paren, group[-1]) line_levels[ilevel][igroup] = group igroup += 1 ilevel += 1 line = unparse_paren(line_levels) else: line = regrep.sub(re_exprs, sub_paren, line) if paren_flg: line = '(' + line + ')' return line
[docs]def parse_line(line): global op_lst, op_dict line = line.replace(' ', '') level_lst = parse_paren(line) ilevel = 0 for level in level_lst: igroup = 0 for group in level: string = group[-1] for op in op_lst: string = add_paren(string, op_dict[op]) level_lst[ilevel][igroup][-1] = string igroup += 1 ilevel += 1 line = unparse_paren(level_lst) return line
[docs]def GAeval(s, pstr=False): seval = parse_line(s) if pstr: print(s) print(seval) return eval(seval, global_dict)