negation.py 2.8 KB

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