1"""A module providing information about the necessity of brackets""" 2 3from ..core.function import _coeff_isneg 4 5 6#: Default precedence values for some basic types. 7PRECEDENCE = { 8 'Lambda': 1, 9 'Xor': 10, 10 'Or': 20, 11 'And': 30, 12 'Relational': 35, 13 'Add': 40, 14 'Mul': 50, 15 'Mod': 50, 16 'Pow': 60, 17 'Func': 70, 18 'Not': 100, 19 'Atom': 1000, 20 'BitwiseOr': 36, 21 'BitwiseAnd': 38, 22} 23 24#: A dictionary assigning precedence values to certain classes. These values 25#: are treated like they were inherited, so not every single class has to 26#: be named here. 27PRECEDENCE_VALUES = { 28 'Equivalent': PRECEDENCE['Xor'], 29 'Xor': PRECEDENCE['Xor'], 30 'Implies': PRECEDENCE['Xor'], 31 'Or': PRECEDENCE['Or'], 32 'And': PRECEDENCE['And'], 33 'Add': PRECEDENCE['Add'], 34 'Mod': PRECEDENCE['Mod'], 35 'Pow': PRECEDENCE['Pow'], 36 'Relational': PRECEDENCE['Relational'], 37 'Sub': PRECEDENCE['Add'], 38 'Not': PRECEDENCE['Not'], 39 'factorial': PRECEDENCE['Func'], 40 'factorial2': PRECEDENCE['Func'], 41 'Function': PRECEDENCE['Func'], 42 'NegativeInfinity': PRECEDENCE['Add'], 43 'MatAdd': PRECEDENCE['Add'], 44 'MatMul': PRECEDENCE['Mul'], 45 'MatPow': PRECEDENCE['Pow'], 46 'HadamardProduct': PRECEDENCE['Mul'], 47 'Fraction': PRECEDENCE['Atom'], 48 'Equality': PRECEDENCE['Mul'], 49 'Unequality': PRECEDENCE['Mul'], 50} 51 52# Sometimes it's not enough to assign a fixed precedence value to a 53# class. Then a function can be inserted in this dictionary that takes 54# an instance of this class as argument and returns the appropriate 55# precedence value. 56 57# Precedence functions 58 59 60def precedence_Mul(item): 61 if _coeff_isneg(item): 62 return PRECEDENCE['Add'] 63 return PRECEDENCE['Mul'] 64 65 66def precedence_Rational(item): 67 if item.numerator < 0: 68 return PRECEDENCE['Add'] 69 return PRECEDENCE['Mul'] 70 71 72def precedence_Integer(item): 73 if item.numerator < 0: 74 return PRECEDENCE['Add'] 75 return PRECEDENCE['Atom'] 76 77 78def precedence_Float(item): 79 if item < 0: 80 return PRECEDENCE['Add'] 81 return PRECEDENCE['Atom'] 82 83 84def precedence_PolyElement(item): 85 if item.is_generator: 86 return PRECEDENCE['Atom'] 87 elif item.is_ground: 88 return precedence(item[1]) 89 elif item.is_term: 90 return PRECEDENCE['Mul'] 91 else: 92 return PRECEDENCE['Add'] 93 94 95def precedence_FracElement(item): 96 if item.denominator == 1: 97 return precedence_PolyElement(item.numerator) 98 else: 99 return PRECEDENCE['Mul'] 100 101 102#: Sometimes it's not enough to assign a fixed precedence value to a class. Then 103#: a function can be inserted in this dictionary that takes an instance of this 104#: class as argument and returns the appropriate precedence value. 105PRECEDENCE_FUNCTIONS = { 106 'Integer': precedence_Integer, 107 'Mul': precedence_Mul, 108 'Rational': precedence_Rational, 109 'Float': precedence_Float, 110 'PolyElement': precedence_PolyElement, 111 'FracElement': precedence_FracElement, 112} 113 114 115def precedence(item): 116 """ 117 Returns the precedence of a given object. 118 """ 119 mro = item.__class__.__mro__ 120 for i in mro: 121 n = i.__name__ 122 if n in PRECEDENCE_FUNCTIONS: 123 return PRECEDENCE_FUNCTIONS[n](item) 124 elif n in PRECEDENCE_VALUES: 125 return PRECEDENCE_VALUES[n] 126 return PRECEDENCE['Atom'] 127