Explorar el Código

Applied negation checks to some fraction rules.

Taddeus Kroes hace 14 años
padre
commit
57dba53ee4
Se han modificado 4 ficheros con 37 adiciones y 17 borrados
  1. 8 4
      src/rules/fractions.py
  2. 4 4
      src/rules/numerics.py
  3. 8 0
      tests/test_rules_fractions.py
  4. 17 9
      tests/test_rules_numerics.py

+ 8 - 4
src/rules/fractions.py

@@ -2,7 +2,7 @@ from itertools import combinations, product
 
 from .utils import least_common_multiple, partition
 from ..node import ExpressionLeaf as L, Scope, negate, OP_DIV, OP_ADD, \
-        OP_MUL, nary_node
+        OP_MUL, nary_node, negate
 from ..possibilities import Possibility as P, MESSAGES
 from ..translate import _
 
@@ -255,9 +255,9 @@ def match_equal_fraction_parts(node):
     # Look for in scope
     for i, n in enumerate(n_scope):
         for j, d in enumerate(d_scope):
-            if n == d:
+            if n.equals(d, ignore_negation=True):
                 p.append(P(node, divide_fraction_parts,
-                           (n, n_scope, d_scope, i, j)))
+                           (negate(n, 0), n_scope, d_scope, i, j)))
 
     return p
 
@@ -270,9 +270,11 @@ def divide_fraction_parts(root, args):
     ab / (ac)  ->  b / c
     ab / a     ->  b / 1
     a / (ab)   ->  1 / b
+    -ab / a     ->  -b / 1
     """
     a, n_scope, d_scope, i, j = args
     n, d = root
+    a_n, a_d = n_scope[i], d_scope[j]
 
     del n_scope[i]
     del d_scope[j]
@@ -294,7 +296,9 @@ def divide_fraction_parts(root, args):
     else:
         denom = nary_node('*', d_scope)
 
-    return nom.negate(n.negated) / denom.negate(d.negated)
+    # Move negation of removed part to nominator and denominator
+    return nom.negate(n.negated + a_n.negated) \
+           / denom.negate(d.negated + a_d.negated)
 
 
 MESSAGES[divide_fraction_parts] = \

+ 4 - 4
src/rules/numerics.py

@@ -108,7 +108,7 @@ def match_divide_numerics(node):
         if not mod:
             # 6 / 2  ->  3
             # 3 / 2  ->  3 / 2
-            return [P(node, divide_numerics, (nv, dv))]
+            return [P(node, divide_numerics, (nv, dv, n.negated + d.negated))]
 
         gcd = greatest_common_divisor(nv, dv)
 
@@ -130,7 +130,7 @@ def match_divide_numerics(node):
         # 3.0 / 2  ->  1.5
         # 3 / 2.0  ->  1.5
         # 3.0 / 2.0  ->  1.5
-        return [P(node, divide_numerics, (nv, dv))]
+        return [P(node, divide_numerics, (nv, dv, n.negated + d.negated))]
 
     return []
 
@@ -146,9 +146,9 @@ def divide_numerics(root, args):
     3.0 / 2.0  ->  1.5
     3 / 1.0    ->  3
     """
-    n, d = args
+    n, d, negated = args
 
-    return Leaf(n / d)
+    return Leaf(n / d).negate(negated)
 
 
 MESSAGES[divide_numerics] = _('Divide constant {1} by constant {2}.')

+ 8 - 0
tests/test_rules_fractions.py

@@ -167,6 +167,10 @@ class TestRulesFractions(RulesTestCase):
                  P(root, divide_fraction_parts, (b, s0, s1, 1, 1)),
                  P(root, divide_fraction_parts, (c, s0, s1, 2, 0))])
 
+        root = tree('-a / a')
+        self.assertEqualPos(match_equal_fraction_parts(root),
+                [P(root, divide_fraction_parts, (a, [-a], [a], 0, 0))])
+
     def test_divide_fraction_parts(self):
         (a, b), (c, a) = root = tree('ab / (ca)')
         result = divide_fraction_parts(root, (a, [a, b], [c, a], 0, 1))
@@ -189,3 +193,7 @@ class TestRulesFractions(RulesTestCase):
         self.assertEqual(result, a * c / (c * a))
         result = divide_fraction_parts(root, (c, [a, b, c], [c, b, a], 2, 0))
         self.assertEqual(result, a * b / (b * a))
+
+        (a, b), a = root = tree('-ab / a')
+        result = divide_fraction_parts(root, (a, [-a, b], [a], 0, 0))
+        self.assertEqual(result, -b / 1)

+ 17 - 9
tests/test_rules_numerics.py

@@ -43,7 +43,12 @@ class TestRulesNumerics(RulesTestCase):
         root = i6 / i2
         possibilities = match_divide_numerics(root)
         self.assertEqualPos(possibilities,
-                [P(root, divide_numerics, (6, 2))])
+                [P(root, divide_numerics, (6, 2, 0))])
+
+        root = -i6 / i2
+        possibilities = match_divide_numerics(root)
+        self.assertEqualPos(possibilities,
+                [P(root, divide_numerics, (6, 2, 1))])
 
         root = i3 / i2
         possibilities = match_divide_numerics(root)
@@ -58,22 +63,22 @@ class TestRulesNumerics(RulesTestCase):
         root = f3 / i2
         possibilities = match_divide_numerics(root)
         self.assertEqualPos(possibilities,
-                [P(root, divide_numerics, (3.0, 2))])
+                [P(root, divide_numerics, (3.0, 2, 0))])
 
         root = i3 / f2
         possibilities = match_divide_numerics(root)
         self.assertEqualPos(possibilities,
-                [P(root, divide_numerics, (3, 2.0))])
+                [P(root, divide_numerics, (3, 2.0, 0))])
 
         root = f3 / f2
         possibilities = match_divide_numerics(root)
         self.assertEqualPos(possibilities,
-                [P(root, divide_numerics, (3.0, 2.0))])
+                [P(root, divide_numerics, (3.0, 2.0, 0))])
 
         root = i3 / f1
         possibilities = match_divide_numerics(root)
         self.assertEqualPos(possibilities,
-                [P(root, divide_numerics, (3, 1))])
+                [P(root, divide_numerics, (3, 1, 0))])
 
         root = a / b
         possibilities = match_divide_numerics(root)
@@ -82,10 +87,13 @@ class TestRulesNumerics(RulesTestCase):
     def test_divide_numerics(self):
         i2, i3, i6, f2, f3 = tree('2,3,6,2.0,3.0')
 
-        self.assertEqual(divide_numerics(i6 / i2, (6, 2)), 3)
-        self.assertEqual(divide_numerics(f3 / i2, (3.0, 2)), 1.5)
-        self.assertEqual(divide_numerics(i3 / f2, (3, 2.0)), 1.5)
-        self.assertEqual(divide_numerics(f3 / f2, (3.0, 2.0)), 1.5)
+        self.assertEqual(divide_numerics(i6 / i2, (6, 2, 0)), 3)
+        self.assertEqual(divide_numerics(f3 / i2, (3.0, 2, 0)), 1.5)
+        self.assertEqual(divide_numerics(i3 / f2, (3, 2.0, 0)), 1.5)
+        self.assertEqual(divide_numerics(f3 / f2, (3.0, 2.0, 0)), 1.5)
+
+        self.assertEqual(divide_numerics(i6 / i2, (6, 2, 1)), -3)
+        self.assertEqual(divide_numerics(i6 / i2, (6, 2, 2)), --i3)
 
     def test_reduce_fraction_constants(self):
         l1, l2 = tree('1,2')