precedence.py 5.1 KB

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