Ver código fonte

Added rule to multiply fractions.

Taddeus Kroes 14 anos atrás
pai
commit
eb087f2eb3
3 arquivos alterados com 53 adições e 3 exclusões
  1. 2 2
      src/rules/__init__.py
  2. 34 0
      src/rules/fractions.py
  3. 17 1
      tests/test_rules_fractions.py

+ 2 - 2
src/rules/__init__.py

@@ -10,7 +10,7 @@ from .numerics import match_add_numerics, match_divide_numerics, \
         match_multiply_numerics, match_multiply_zero, match_multiply_one, \
         match_raise_numerics
 from .fractions import match_constant_division, match_add_constant_fractions, \
-        match_expand_and_add_fractions
+        match_expand_and_add_fractions, match_multiply_fractions
 from .negation import match_negated_factor, match_negate_polynome, \
         match_negated_division
 from .sort import match_sort_multiplicants
@@ -23,7 +23,7 @@ RULES = {
         OP_MUL: [match_multiply_numerics, match_expand, match_add_exponents,
                  match_expand_and_add_fractions, match_multiply_zero,
                  match_negated_factor, match_multiply_one,
-                 match_sort_multiplicants],
+                 match_sort_multiplicants, match_multiply_fractions],
         OP_DIV: [match_subtract_exponents, match_divide_numerics,
                  match_constant_division, match_negated_division],
         OP_POW: [match_multiply_exponents, match_duplicate_exponent,

+ 34 - 0
src/rules/fractions.py

@@ -173,3 +173,37 @@ def match_expand_and_add_fractions(node):
     p = []
 
     return p
+
+
+def match_multiply_fractions(node):
+    """
+    a / b * (c / d)  ->  ac / (bd)
+    """
+    # TODO: is 'add' Appropriate when rewriting to "(a + (-d)) / * (b / c)"?
+    assert node.is_op(OP_MUL)
+
+    p = []
+    scope = Scope(node)
+    fractions = filter(lambda n: n.is_op(OP_DIV), scope)
+
+    for ab, cd in combinations(fractions, 2):
+        p.append(P(node, multiply_fractions, (scope, ab, cd)))
+
+    return p
+
+
+def multiply_fractions(root, args):
+    """
+    a / b * (c / d)  ->  ac / (bd)
+    """
+    scope, ab, cd = args
+    a, b = ab
+    c, d = cd
+
+    scope.replace(ab, a * c / (b * d))
+    scope.remove(cd)
+
+    return scope.as_nary_node()
+
+
+MESSAGES[multiply_fractions] = _('Multiply fractions {2} and {3}.')

+ 17 - 1
tests/test_rules_fractions.py

@@ -1,6 +1,7 @@
 from src.rules.fractions import match_constant_division, division_by_one, \
         division_of_zero, division_by_self, match_add_constant_fractions, \
-        equalize_denominators, add_nominators
+        equalize_denominators, add_nominators, match_multiply_fractions, \
+        multiply_fractions
 from src.node import Scope
 from src.possibilities import Possibility as P
 from tests.rulestestcase import RulesTestCase, tree
@@ -123,3 +124,18 @@ class TestRulesFractions(RulesTestCase):
 
         n0, n1 = root = a / -b + -c / -b
         self.assertEqualNodes(add_nominators(root, (n0, n1)), (a + -c) / -b)
+
+    def test_match_multiply_fractions(self):
+        (a, b), (c, d) = ab, cd = root = tree('a / b * (c / d)')
+
+        self.assertEqualPos(match_multiply_fractions(root),
+                [P(root, multiply_fractions, (Scope(root), ab, cd))])
+
+    def test_multiply_fractions(self):
+        (a, b), (c, d) = ab, cd = root = tree('a / b * (c / d)')
+        self.assertEqual(multiply_fractions(root, (Scope(root), ab, cd)),
+                         a * c / (b * d))
+
+        (ab, e), cd = root = tree('a / b * e * (c / d)')
+        self.assertEqual(multiply_fractions(root, (Scope(root), ab, cd)),
+                         a * c / (b * d) * e)