negation.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. from ..node import Scope, nary_node, OP_ADD, OP_MUL, OP_DIV
  2. from ..possibilities import Possibility as P, MESSAGES
  3. from ..translate import _
  4. def match_negated_factor(node):
  5. """
  6. This rule assures that negations in the scope of a multiplication are
  7. brought to the most left node in the multiplication's scope.
  8. Example:
  9. a * -b -> -(ab)
  10. """
  11. assert node.is_op(OP_MUL)
  12. p = []
  13. scope = Scope(node)
  14. # FIXME: The negation that is brought outside is assigned to the first
  15. # element in the scope during the next parsing step:
  16. # -ab -> -(ab), but -(ab) is printed as -ab
  17. for factor in scope[1:]:
  18. if factor.negated:
  19. p.append(P(node, negated_factor, (scope, factor)))
  20. return p
  21. def negated_factor(root, args):
  22. """
  23. a * -b -> -ab
  24. """
  25. scope, factor = args
  26. scope[0] = -scope[0]
  27. scope.replace(factor, +factor)
  28. return scope.as_nary_node()
  29. MESSAGES[negated_factor] = \
  30. _('Bring negation of {2} to the outside of the multiplication.')
  31. def match_negate_polynome(node):
  32. """
  33. --a -> a
  34. -(a + b) -> -a - b
  35. """
  36. assert node.negated
  37. p = []
  38. if node.negated == 2:
  39. # --a
  40. p.append(P(node, double_negation, ()))
  41. if node.is_op(OP_ADD):
  42. # -(a + b) -> -a - b
  43. p.append(P(node, negate_polynome, ()))
  44. return p
  45. def double_negation(root, args):
  46. """
  47. --a -> a
  48. """
  49. return root.reduce_negation(2)
  50. MESSAGES[double_negation] = _('Remove double negation in {0}.')
  51. def negate_polynome(root, args):
  52. """
  53. -(a + b) -> -a - b
  54. """
  55. scope = Scope(root)
  56. # Negate each group
  57. for i, n in enumerate(scope):
  58. scope[i] = -n
  59. return +scope.as_nary_node()
  60. MESSAGES[negate_polynome] = _('Apply negation to the polynome {0}.')
  61. #def negate_group(root, args):
  62. # """
  63. # -(a * -3c) -> a * 3c
  64. # -(a * ... * -b) -> ab
  65. # """
  66. # node, scope = args
  67. #
  68. # for i, n in enumerate(scope):
  69. # if n.negated:
  70. # scope[i] = n.reduce_negation()
  71. #
  72. # return nary_node('*', scope).reduce_negation()
  73. #
  74. #
  75. #MESSAGES[negate_polynome] = _('Apply negation to the subexpression {1[0]}.')
  76. def match_negated_division(node):
  77. """
  78. -a / -b -> a / b
  79. """
  80. assert node.is_op(OP_DIV)
  81. a, b = node
  82. if a.negated and b.negated:
  83. return [P(node, double_negated_division, ())]
  84. elif a.negated:
  85. return [P(node, single_negated_division, (+a, b))]
  86. elif b.negated:
  87. return [P(node, single_negated_division, (a, +b))]
  88. return []
  89. def single_negated_division(root, args):
  90. """
  91. -a / b -> -(a / b)
  92. a / -b -> -(a / b)
  93. """
  94. a, b = args
  95. # FIXME: "-a/b" results in "-(a/b)", which will cause a loop.
  96. return -(a / b)
  97. MESSAGES[single_negated_division] = \
  98. _('Bring negation outside of the division: -({1} / {2}).')
  99. def double_negated_division(root, args):
  100. """
  101. -a / -b -> a / b
  102. """
  103. a, b = root
  104. return +a / +b
  105. MESSAGES[double_negated_division] = \
  106. _('Eliminate top and bottom negation in {0}.')
  107. # TODO: negated multiplication: -a * -b = ab