Jelajahi Sumber

Added rule that generates a quadrants addition.

Taddeus Kroes 14 tahun lalu
induk
melakukan
4c4344ae03
2 mengubah file dengan 36 tambahan dan 6 penghapusan
  1. 24 4
      src/rules/goniometry.py
  2. 12 2
      tests/test_rules_goniometry.py

+ 24 - 4
src/rules/goniometry.py

@@ -17,13 +17,18 @@ def match_add_quadrants(node):
     scope = Scope(node)
 
     for sin_q, cos_q in permutations(scope, 2):
-        if sin_q.is_power(2) and cos_q.is_power(2) \
-                and not sin_q.negated and not cos_q.negated:
+        if sin_q.is_power(2) and cos_q.is_power(2):
             s, c = sin_q[0], cos_q[0]
 
-            if s.is_op(OP_SIN) and c.is_op(OP_COS) and not s.negated \
-                    and not c.negated and s[0] == c[0]:
+            if not s.is_op(OP_SIN) or not c.is_op(OP_COS) or s.negated \
+                    or c.negated or s[0] != c[0]:
+                continue
+
+            if not sin_q.negated and not cos_q.negated:
                 p.append(P(node, add_quadrants, (scope, sin_q, cos_q)))
+            elif sin_q.negated == 1 and cos_q.negated == 1:
+                p.append(P(node, factor_out_quadrant_negation,
+                    (scope, sin_q, cos_q)))
 
     return p
 
@@ -42,6 +47,21 @@ def add_quadrants(root, args):
 MESSAGES[add_quadrants] = _('Add the sinus and cosinus quadrants to 1.')
 
 
+def factor_out_quadrant_negation(root, args):
+    """
+    -sin(t) ^ 2 - cos(t) ^ 2  ->  -(sin(t) ^ 2 + cos(t) ^ 2)  # ->  -1
+    """
+    scope, s, c = args
+    scope.replace(s, -(+s + +c))
+    scope.remove(c)
+
+    return scope.as_nary_node()
+
+
+MESSAGES[factor_out_quadrant_negation] = _('Factor out the negations of {2} ' \
+        'and {3} to be able to reduce the quadrant addition to 1.')
+
+
 def match_negated_parameter(node):
     """
     sin(-t)  ->  -sin(t)

+ 12 - 2
tests/test_rules_goniometry.py

@@ -1,7 +1,8 @@
 # vim: set fileencoding=utf-8 :
 from src.rules.goniometry import match_add_quadrants, add_quadrants, \
-        match_negated_parameter, negated_sinus_parameter, is_pi_frac, \
-        negated_cosinus_parameter, match_standard_radian, standard_radian
+        factor_out_quadrant_negation, match_negated_parameter, \
+        negated_sinus_parameter, is_pi_frac, negated_cosinus_parameter, \
+        match_standard_radian, standard_radian
 from src.node import PI, OP_SIN, OP_COS, OP_TAN, sin, cos, tan, Scope
 from src.possibilities import Possibility as P
 from tests.rulestestcase import RulesTestCase, tree
@@ -38,6 +39,10 @@ class TestRulesGoniometry(RulesTestCase):
         root = tree('sin(t) ^ 2 - cos(t) ^ 2')
         self.assertEqualPos(match_add_quadrants(root), [])
 
+        s, c = root = tree('-sin(t) ^ 2 - cos(t) ^ 2')
+        self.assertEqualPos(match_add_quadrants(root),
+                [P(root, factor_out_quadrant_negation, (Scope(root), s, c))])
+
     def test_add_quadrants(self):
         s, c = root = tree('sin(t) ^ 2 + cos(t) ^ 2')
         self.assertEqual(add_quadrants(root, (Scope(root), s, c)), 1)
@@ -46,6 +51,11 @@ class TestRulesGoniometry(RulesTestCase):
         (c, a), s = root
         self.assertEqual(add_quadrants(root, (Scope(root), s, c)), expect)
 
+    def test_factor_out_quadrant_negation(self):
+        r, e = tree('-sin(t) ^ 2 - cos(t) ^ 2, -(sin(t) ^ 2 + cos(t) ^ 2)')
+        s, c = r
+        self.assertEqual(factor_out_quadrant_negation(r, (Scope(r), s, c)), e)
+
     def test_match_negated_parameter(self):
         s, c = tree('sin -t, cos -t')
         t = s[0]