178 lines
5.1 KiB
Python
178 lines
5.1 KiB
Python
|
"""A module providing information about the necessity of brackets"""
|
||
|
|
||
|
|
||
|
# Default precedence values for some basic types
|
||
|
PRECEDENCE = {
|
||
|
"Lambda": 1,
|
||
|
"Xor": 10,
|
||
|
"Or": 20,
|
||
|
"And": 30,
|
||
|
"Relational": 35,
|
||
|
"Add": 40,
|
||
|
"Mul": 50,
|
||
|
"Pow": 60,
|
||
|
"Func": 70,
|
||
|
"Not": 100,
|
||
|
"Atom": 1000,
|
||
|
"BitwiseOr": 36,
|
||
|
"BitwiseXor": 37,
|
||
|
"BitwiseAnd": 38
|
||
|
}
|
||
|
|
||
|
# A dictionary assigning precedence values to certain classes. These values are
|
||
|
# treated like they were inherited, so not every single class has to be named
|
||
|
# here.
|
||
|
# Do not use this with printers other than StrPrinter
|
||
|
PRECEDENCE_VALUES = {
|
||
|
"Equivalent": PRECEDENCE["Xor"],
|
||
|
"Xor": PRECEDENCE["Xor"],
|
||
|
"Implies": PRECEDENCE["Xor"],
|
||
|
"Or": PRECEDENCE["Or"],
|
||
|
"And": PRECEDENCE["And"],
|
||
|
"Add": PRECEDENCE["Add"],
|
||
|
"Pow": PRECEDENCE["Pow"],
|
||
|
"Relational": PRECEDENCE["Relational"],
|
||
|
"Sub": PRECEDENCE["Add"],
|
||
|
"Not": PRECEDENCE["Not"],
|
||
|
"Function" : PRECEDENCE["Func"],
|
||
|
"NegativeInfinity": PRECEDENCE["Add"],
|
||
|
"MatAdd": PRECEDENCE["Add"],
|
||
|
"MatPow": PRECEDENCE["Pow"],
|
||
|
"MatrixSolve": PRECEDENCE["Mul"],
|
||
|
"Mod": PRECEDENCE["Mul"],
|
||
|
"TensAdd": PRECEDENCE["Add"],
|
||
|
# As soon as `TensMul` is a subclass of `Mul`, remove this:
|
||
|
"TensMul": PRECEDENCE["Mul"],
|
||
|
"HadamardProduct": PRECEDENCE["Mul"],
|
||
|
"HadamardPower": PRECEDENCE["Pow"],
|
||
|
"KroneckerProduct": PRECEDENCE["Mul"],
|
||
|
"Equality": PRECEDENCE["Mul"],
|
||
|
"Unequality": PRECEDENCE["Mul"],
|
||
|
}
|
||
|
|
||
|
# Sometimes it's not enough to assign a fixed precedence value to a
|
||
|
# class. Then a function can be inserted in this dictionary that takes
|
||
|
# an instance of this class as argument and returns the appropriate
|
||
|
# precedence value.
|
||
|
|
||
|
# Precedence functions
|
||
|
|
||
|
|
||
|
def precedence_Mul(item):
|
||
|
if item.could_extract_minus_sign():
|
||
|
return PRECEDENCE["Add"]
|
||
|
return PRECEDENCE["Mul"]
|
||
|
|
||
|
|
||
|
def precedence_Rational(item):
|
||
|
if item.p < 0:
|
||
|
return PRECEDENCE["Add"]
|
||
|
return PRECEDENCE["Mul"]
|
||
|
|
||
|
|
||
|
def precedence_Integer(item):
|
||
|
if item.p < 0:
|
||
|
return PRECEDENCE["Add"]
|
||
|
return PRECEDENCE["Atom"]
|
||
|
|
||
|
|
||
|
def precedence_Float(item):
|
||
|
if item < 0:
|
||
|
return PRECEDENCE["Add"]
|
||
|
return PRECEDENCE["Atom"]
|
||
|
|
||
|
|
||
|
def precedence_PolyElement(item):
|
||
|
if item.is_generator:
|
||
|
return PRECEDENCE["Atom"]
|
||
|
elif item.is_ground:
|
||
|
return precedence(item.coeff(1))
|
||
|
elif item.is_term:
|
||
|
return PRECEDENCE["Mul"]
|
||
|
else:
|
||
|
return PRECEDENCE["Add"]
|
||
|
|
||
|
|
||
|
def precedence_FracElement(item):
|
||
|
if item.denom == 1:
|
||
|
return precedence_PolyElement(item.numer)
|
||
|
else:
|
||
|
return PRECEDENCE["Mul"]
|
||
|
|
||
|
|
||
|
def precedence_UnevaluatedExpr(item):
|
||
|
return precedence(item.args[0]) - 0.5
|
||
|
|
||
|
|
||
|
PRECEDENCE_FUNCTIONS = {
|
||
|
"Integer": precedence_Integer,
|
||
|
"Mul": precedence_Mul,
|
||
|
"Rational": precedence_Rational,
|
||
|
"Float": precedence_Float,
|
||
|
"PolyElement": precedence_PolyElement,
|
||
|
"FracElement": precedence_FracElement,
|
||
|
"UnevaluatedExpr": precedence_UnevaluatedExpr,
|
||
|
}
|
||
|
|
||
|
|
||
|
def precedence(item):
|
||
|
"""Returns the precedence of a given object.
|
||
|
|
||
|
This is the precedence for StrPrinter.
|
||
|
"""
|
||
|
if hasattr(item, "precedence"):
|
||
|
return item.precedence
|
||
|
try:
|
||
|
mro = item.__class__.__mro__
|
||
|
except AttributeError:
|
||
|
return PRECEDENCE["Atom"]
|
||
|
for i in mro:
|
||
|
n = i.__name__
|
||
|
if n in PRECEDENCE_FUNCTIONS:
|
||
|
return PRECEDENCE_FUNCTIONS[n](item)
|
||
|
elif n in PRECEDENCE_VALUES:
|
||
|
return PRECEDENCE_VALUES[n]
|
||
|
return PRECEDENCE["Atom"]
|
||
|
|
||
|
|
||
|
PRECEDENCE_TRADITIONAL = PRECEDENCE.copy()
|
||
|
PRECEDENCE_TRADITIONAL['Integral'] = PRECEDENCE["Mul"]
|
||
|
PRECEDENCE_TRADITIONAL['Sum'] = PRECEDENCE["Mul"]
|
||
|
PRECEDENCE_TRADITIONAL['Product'] = PRECEDENCE["Mul"]
|
||
|
PRECEDENCE_TRADITIONAL['Limit'] = PRECEDENCE["Mul"]
|
||
|
PRECEDENCE_TRADITIONAL['Derivative'] = PRECEDENCE["Mul"]
|
||
|
PRECEDENCE_TRADITIONAL['TensorProduct'] = PRECEDENCE["Mul"]
|
||
|
PRECEDENCE_TRADITIONAL['Transpose'] = PRECEDENCE["Pow"]
|
||
|
PRECEDENCE_TRADITIONAL['Adjoint'] = PRECEDENCE["Pow"]
|
||
|
PRECEDENCE_TRADITIONAL['Dot'] = PRECEDENCE["Mul"] - 1
|
||
|
PRECEDENCE_TRADITIONAL['Cross'] = PRECEDENCE["Mul"] - 1
|
||
|
PRECEDENCE_TRADITIONAL['Gradient'] = PRECEDENCE["Mul"] - 1
|
||
|
PRECEDENCE_TRADITIONAL['Divergence'] = PRECEDENCE["Mul"] - 1
|
||
|
PRECEDENCE_TRADITIONAL['Curl'] = PRECEDENCE["Mul"] - 1
|
||
|
PRECEDENCE_TRADITIONAL['Laplacian'] = PRECEDENCE["Mul"] - 1
|
||
|
PRECEDENCE_TRADITIONAL['Union'] = PRECEDENCE['Xor']
|
||
|
PRECEDENCE_TRADITIONAL['Intersection'] = PRECEDENCE['Xor']
|
||
|
PRECEDENCE_TRADITIONAL['Complement'] = PRECEDENCE['Xor']
|
||
|
PRECEDENCE_TRADITIONAL['SymmetricDifference'] = PRECEDENCE['Xor']
|
||
|
PRECEDENCE_TRADITIONAL['ProductSet'] = PRECEDENCE['Xor']
|
||
|
|
||
|
|
||
|
def precedence_traditional(item):
|
||
|
"""Returns the precedence of a given object according to the
|
||
|
traditional rules of mathematics.
|
||
|
|
||
|
This is the precedence for the LaTeX and pretty printer.
|
||
|
"""
|
||
|
# Integral, Sum, Product, Limit have the precedence of Mul in LaTeX,
|
||
|
# the precedence of Atom for other printers:
|
||
|
from sympy.core.expr import UnevaluatedExpr
|
||
|
|
||
|
if isinstance(item, UnevaluatedExpr):
|
||
|
return precedence_traditional(item.args[0])
|
||
|
|
||
|
n = item.__class__.__name__
|
||
|
if n in PRECEDENCE_TRADITIONAL:
|
||
|
return PRECEDENCE_TRADITIONAL[n]
|
||
|
|
||
|
return precedence(item)
|