소스 검색

Added negated division rewrite rules.

Taddeus Kroes 14 년 전
부모
커밋
998325838c
3개의 변경된 파일94개의 추가작업 그리고 3개의 파일을 삭제
  1. 2 2
      src/rules/__init__.py
  2. 48 1
      src/rules/negation.py
  3. 44 0
      tests/test_rules_negation.py

+ 2 - 2
src/rules/__init__.py

@@ -9,7 +9,7 @@ from .powers import match_add_exponents, match_subtract_exponents, \
 from .numerics import match_divide_numerics, match_multiply_numerics
 from .fractions import match_constant_division, match_add_constant_fractions, \
         match_expand_and_add_fractions
-from .negation import match_negate_group
+from .negation import match_negate_group, match_negated_division
 
 RULES = {
         OP_ADD: [match_add_constant_fractions, match_combine_polynomes, \
@@ -17,7 +17,7 @@ RULES = {
         OP_MUL: [match_multiply_numerics, match_expand, match_add_exponents, \
                  match_expand_and_add_fractions],
         OP_DIV: [match_subtract_exponents, match_divide_numerics, \
-                 match_constant_division],
+                 match_constant_division, match_negated_division],
         OP_POW: [match_multiply_exponents, match_duplicate_exponent, \
                  match_remove_negative_exponent, match_exponent_to_root, \
                  match_extend_exponent],

+ 48 - 1
src/rules/negation.py

@@ -1,4 +1,4 @@
-from ..node import OP_NEG, OP_ADD, OP_MUL, get_scope, nary_node
+from ..node import get_scope, nary_node, OP_NEG, OP_ADD, OP_MUL, OP_DIV
 from ..possibilities import Possibility as P, MESSAGES
 from ..translate import _
 
@@ -85,4 +85,51 @@ def double_negation(root, args):
     return node[0][0]
 
 
+def match_negated_division(node):
+    """
+    -a / -b  ->  a / b
+    """
+    assert node.is_op(OP_DIV)
+
+    a, b = node
+    a_neg = a.is_op(OP_NEG)
+    b_neg = b.is_op(OP_NEG)
+
+    if a_neg and b_neg:
+        return [P(node, double_negated_division, (node,))]
+    elif a_neg:
+        return [P(node, single_negated_division, (a[0], b))]
+    elif b_neg:
+        return [P(node, single_negated_division, (a, b[0]))]
+
+    return []
+
+
+def single_negated_division(root, args):
+    """
+    -a / b  ->  -(a / b)
+    a / -b  ->  -(a / b)
+    """
+    a, b = args
+
+    return -(a / b)
+
+
+MESSAGES[single_negated_division] = \
+        _('Bring negation outside of the division: -({1} / {2}).')
+
+
+def double_negated_division(root, args):
+    """
+    -a / -b  ->  a / b
+    """
+    a, b = root
+
+    return a[0] / b[0]
+
+
+MESSAGES[double_negated_division] = \
+        _('Eliminate top and bottom negation in {1}.')
+
+
 MESSAGES[double_negation] = _('Remove double negation in {1}.')

+ 44 - 0
tests/test_rules_negation.py

@@ -0,0 +1,44 @@
+
+from src.rules.negation import match_negated_division, \
+        single_negated_division, double_negated_division
+from src.possibilities import Possibility as P
+from tests.rulestestcase import RulesTestCase, tree
+
+
+class TestRulesNegation(RulesTestCase):
+
+    def test_match_negated_division_none(self):
+        self.assertEqual(match_negated_division(tree('1 / 2')), [])
+
+    def test_match_negated_division_single(self):
+        l1, l2 = root = tree('-1 / 2')
+        possibilities = match_negated_division(root)
+        self.assertEqualPos(possibilities,
+                [P(root, single_negated_division, (l1[0], l2))])
+
+        l1, l2 = root = tree('1 / -2')
+        possibilities = match_negated_division(root)
+        self.assertEqualPos(possibilities,
+                [P(root, single_negated_division, (l1, l2[0]))])
+
+    def test_match_negated_division_double(self):
+        root = tree('-1 / -2')
+
+        possibilities = match_negated_division(root)
+        self.assertEqualPos(possibilities,
+                [P(root, double_negated_division, (root,))])
+
+    def test_single_negated_division(self):
+        l1, l2 = root = tree('-1 / 2')
+        self.assertEqualNodes(single_negated_division(root, (l1[0], l2)),
+                              -(l1[0] / l2))
+
+        l1, l2 = root = tree('1 / -2')
+        self.assertEqualNodes(single_negated_division(root, (l1, l2[0])),
+                              -(l1 / l2[0]))
+
+    def test_double_negated_division(self):
+        l1, l2 = root = tree('-1 / -2')
+
+        self.assertEqualNodes(double_negated_division(root, (root,)),
+                              l1[0] / l2[0])