1"""A module providing information about the necessity of brackets"""
2
3from sympy.core.function import _coeff_isneg
4
5# Default precedence values for some basic types
6PRECEDENCE = {
7    "Lambda": 1,
8    "Xor": 10,
9    "Or": 20,
10    "And": 30,
11    "Relational": 35,
12    "Add": 40,
13    "Mul": 50,
14    "Pow": 60,
15    "Func": 70,
16    "Not": 100,
17    "Atom": 1000,
18    "BitwiseOr": 36,
19    "BitwiseXor": 37,
20    "BitwiseAnd": 38
21}
22
23# A dictionary assigning precedence values to certain classes. These values are
24# treated like they were inherited, so not every single class has to be named
25# here.
26# Do not use this with printers other than StrPrinter
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    "Pow": PRECEDENCE["Pow"],
35    "Relational": PRECEDENCE["Relational"],
36    "Sub": PRECEDENCE["Add"],
37    "Not": PRECEDENCE["Not"],
38    "Function" : PRECEDENCE["Func"],
39    "NegativeInfinity": PRECEDENCE["Add"],
40    "MatAdd": PRECEDENCE["Add"],
41    "MatPow": PRECEDENCE["Pow"],
42    "MatrixSolve": PRECEDENCE["Mul"],
43    "TensAdd": PRECEDENCE["Add"],
44    # As soon as `TensMul` is a subclass of `Mul`, remove this:
45    "TensMul": PRECEDENCE["Mul"],
46    "HadamardProduct": PRECEDENCE["Mul"],
47    "HadamardPower": PRECEDENCE["Pow"],
48    "KroneckerProduct": PRECEDENCE["Mul"],
49    "Equality": PRECEDENCE["Mul"],
50    "Unequality": PRECEDENCE["Mul"],
51}
52
53# Sometimes it's not enough to assign a fixed precedence value to a
54# class. Then a function can be inserted in this dictionary that takes
55# an instance of this class as argument and returns the appropriate
56# precedence value.
57
58# Precedence functions
59
60
61def precedence_Mul(item):
62    if _coeff_isneg(item):
63        return PRECEDENCE["Add"]
64    return PRECEDENCE["Mul"]
65
66
67def precedence_Rational(item):
68    if item.p < 0:
69        return PRECEDENCE["Add"]
70    return PRECEDENCE["Mul"]
71
72
73def precedence_Integer(item):
74    if item.p < 0:
75        return PRECEDENCE["Add"]
76    return PRECEDENCE["Atom"]
77
78
79def precedence_Float(item):
80    if item < 0:
81        return PRECEDENCE["Add"]
82    return PRECEDENCE["Atom"]
83
84
85def precedence_PolyElement(item):
86    if item.is_generator:
87        return PRECEDENCE["Atom"]
88    elif item.is_ground:
89        return precedence(item.coeff(1))
90    elif item.is_term:
91        return PRECEDENCE["Mul"]
92    else:
93        return PRECEDENCE["Add"]
94
95
96def precedence_FracElement(item):
97    if item.denom == 1:
98        return precedence_PolyElement(item.numer)
99    else:
100        return PRECEDENCE["Mul"]
101
102
103def precedence_UnevaluatedExpr(item):
104    return precedence(item.args[0])
105
106
107PRECEDENCE_FUNCTIONS = {
108    "Integer": precedence_Integer,
109    "Mul": precedence_Mul,
110    "Rational": precedence_Rational,
111    "Float": precedence_Float,
112    "PolyElement": precedence_PolyElement,
113    "FracElement": precedence_FracElement,
114    "UnevaluatedExpr": precedence_UnevaluatedExpr,
115}
116
117
118def precedence(item):
119    """Returns the precedence of a given object.
120
121    This is the precedence for StrPrinter.
122    """
123    if hasattr(item, "precedence"):
124        return item.precedence
125    try:
126        mro = item.__class__.__mro__
127    except AttributeError:
128        return PRECEDENCE["Atom"]
129    for i in mro:
130        n = i.__name__
131        if n in PRECEDENCE_FUNCTIONS:
132            return PRECEDENCE_FUNCTIONS[n](item)
133        elif n in PRECEDENCE_VALUES:
134            return PRECEDENCE_VALUES[n]
135    return PRECEDENCE["Atom"]
136
137
138PRECEDENCE_TRADITIONAL = PRECEDENCE.copy()
139PRECEDENCE_TRADITIONAL['Integral'] = PRECEDENCE["Mul"]
140PRECEDENCE_TRADITIONAL['Sum'] = PRECEDENCE["Mul"]
141PRECEDENCE_TRADITIONAL['Product'] = PRECEDENCE["Mul"]
142PRECEDENCE_TRADITIONAL['Limit'] = PRECEDENCE["Mul"]
143PRECEDENCE_TRADITIONAL['Derivative'] = PRECEDENCE["Mul"]
144PRECEDENCE_TRADITIONAL['TensorProduct'] = PRECEDENCE["Mul"]
145PRECEDENCE_TRADITIONAL['Transpose'] = PRECEDENCE["Pow"]
146PRECEDENCE_TRADITIONAL['Adjoint'] = PRECEDENCE["Pow"]
147PRECEDENCE_TRADITIONAL['Dot'] = PRECEDENCE["Mul"] - 1
148PRECEDENCE_TRADITIONAL['Cross'] = PRECEDENCE["Mul"] - 1
149PRECEDENCE_TRADITIONAL['Gradient'] = PRECEDENCE["Mul"] - 1
150PRECEDENCE_TRADITIONAL['Divergence'] = PRECEDENCE["Mul"] - 1
151PRECEDENCE_TRADITIONAL['Curl'] = PRECEDENCE["Mul"] - 1
152PRECEDENCE_TRADITIONAL['Laplacian'] = PRECEDENCE["Mul"] - 1
153PRECEDENCE_TRADITIONAL['Union'] = PRECEDENCE['Xor']
154PRECEDENCE_TRADITIONAL['Intersection'] = PRECEDENCE['Xor']
155PRECEDENCE_TRADITIONAL['Complement'] = PRECEDENCE['Xor']
156PRECEDENCE_TRADITIONAL['SymmetricDifference'] = PRECEDENCE['Xor']
157PRECEDENCE_TRADITIONAL['ProductSet'] = PRECEDENCE['Xor']
158
159
160def precedence_traditional(item):
161    """Returns the precedence of a given object according to the
162    traditional rules of mathematics.
163
164    This is the precedence for the LaTeX and pretty printer.
165    """
166    # Integral, Sum, Product, Limit have the precedence of Mul in LaTeX,
167    # the precedence of Atom for other printers:
168    from sympy.core.expr import UnevaluatedExpr
169
170    if isinstance(item, UnevaluatedExpr):
171        return precedence_traditional(item.args[0])
172
173    n = item.__class__.__name__
174    if n in PRECEDENCE_TRADITIONAL:
175        return PRECEDENCE_TRADITIONAL[n]
176
177    return precedence(item)
178