Selaa lähdekoodia

Implemented last of the standard derivatives.

Taddeus Kroes 14 vuotta sitten
vanhempi
sitoutus
0f16cb2ca3
3 muutettua tiedostoa jossa 120 lisäystä ja 16 poistoa
  1. 3 2
      src/rules/__init__.py
  2. 73 6
      src/rules/derivatives.py
  3. 44 8
      tests/test_rules_derivatives.py

+ 3 - 2
src/rules/__init__.py

@@ -19,7 +19,8 @@ from .goniometry import match_add_quadrants, match_negated_parameter, \
         match_half_pi_subtraction, match_standard_radian
 from src.rules.derivatives import match_zero_derivative, \
         match_one_derivative, match_variable_power, \
-        match_const_deriv_multiplication, match_logarithm
+        match_const_deriv_multiplication, match_logarithmic, \
+        match_goniometric
 
 RULES = {
         OP_ADD: [match_add_numerics, match_add_constant_fractions,
@@ -43,5 +44,5 @@ RULES = {
         OP_TAN: [match_standard_radian],
         OP_DER: [match_zero_derivative, match_one_derivative,
                  match_variable_power, match_const_deriv_multiplication,
-                 match_logarithm],
+                 match_logarithmic, match_goniometric],
         }

+ 73 - 6
src/rules/derivatives.py

@@ -2,8 +2,9 @@ from itertools import combinations
 
 from .utils import find_variables
 from .logarithmic import ln
+from .goniometry import sin, cos
 from ..node import ExpressionNode as N, ExpressionLeaf as L, Scope, OP_DER, \
-        OP_MUL, OP_LOG
+        OP_MUL, OP_LOG, OP_SIN, OP_COS, OP_TAN
 from ..possibilities import Possibility as P, MESSAGES
 from ..translate import _
 
@@ -201,7 +202,7 @@ MESSAGES[variable_exponent] = \
         _('Apply standard derivative d/dx g ^ x = g ^ x * ln g.')
 
 
-def match_logarithm(node):
+def match_logarithmic(node):
     """
     der(log(x, g), x)     ->  1 / (x * ln(g))
     der(log(f(x), g), x)  ->  1 / (f(x) * ln(g)) * der(f(x), x)
@@ -215,15 +216,15 @@ def match_logarithm(node):
         x = L(x)
 
         if f == x:
-            return [P(node, logarithm, ())]
+            return [P(node, logarithmic, ())]
 
         if f.contains(x):
-            return [P(node, chain_rule, (f, logarithm, ()))]
+            return [P(node, chain_rule, (f, logarithmic, ()))]
 
     return []
 
 
-def logarithm(root, args):
+def logarithmic(root, args):
     """
     der(log(x, g), x)  ->  1 / (x * ln(g))
     """
@@ -232,5 +233,71 @@ def logarithm(root, args):
     return L(1) / (x * ln(g))
 
 
-MESSAGES[logarithm] = \
+MESSAGES[logarithmic] = \
         _('Apply standard derivative d/dx log(x, g) = 1 / (x * ln(g)).')
+
+
+def match_goniometric(node):
+    """
+    der(sin(x), x)     ->  cos(x)
+    der(sin(f(x)), x)  ->  cos(f(x)) * der(f(x), x)
+    der(cos(x), x)     ->  -sin(x)
+    der(cos(f(x)), x)  ->  -sin(f(x)) * der(f(x), x)
+    der(tan(x), x)     ->  der(sin(x) / cos(x), x)
+    """
+    assert node.is_op(OP_DER)
+
+    x = get_derivation_variable(node)
+
+    if x and not node[0].is_leaf:
+        op = node[0].op
+
+        if op in (OP_SIN, OP_COS):
+            f = node[0][0]
+            x = L(x)
+            handler = sinus if op == OP_SIN else cosinus
+
+            if f == x:
+                return [P(node, handler)]
+
+            if f.contains(x):
+                return [P(node, chain_rule, (f, handler, ()))]
+
+        if op == OP_TAN:
+            return [P(node, tangens)]
+
+    return []
+
+
+def sinus(root, args):
+    """
+    der(sin(x), x)  ->  cos(x)
+    """
+    return cos(root[0][0])
+
+
+MESSAGES[sinus] = _('Apply standard derivative d/dx sin(x) = cos(x).')
+
+
+def cosinus(root, args):
+    """
+    der(cos(x), x)  ->  -sin(x)
+    """
+    return -sin(root[0][0])
+
+
+MESSAGES[cosinus] = _('Apply standard derivative d/dx cos(x) = -sin(x).')
+
+
+def tangens(root, args):
+    """
+    der(tan(x), x)  ->  der(sin(x) / cos(x), x)
+    """
+    f = root[0][0]
+    x = root[1] if len(root) > 1 else None
+
+    return der(sin(f) / cos(f), x)
+
+
+MESSAGES[tangens] = \
+        _('Convert the tanges to a division and apply the product rule.')

+ 44 - 8
tests/test_rules_derivatives.py

@@ -2,8 +2,10 @@ from src.rules.derivatives import der, get_derivation_variable, \
         match_zero_derivative, match_one_derivative, one_derivative, \
         zero_derivative, match_variable_power, variable_root, \
         variable_exponent, match_const_deriv_multiplication, \
-        const_deriv_multiplication, chain_rule, match_logarithm, logarithm
+        const_deriv_multiplication, chain_rule, match_logarithmic, \
+        logarithmic, match_goniometric, sinus, cosinus, tangens
 from src.rules.logarithmic import ln
+from src.rules.goniometry import sin, cos
 from src.node import Scope
 from src.possibilities import Possibility as P
 from tests.rulestestcase import RulesTestCase, tree
@@ -110,15 +112,49 @@ class TestRulesDerivatives(RulesTestCase):
         self.assertEqual(chain_rule(root, (x3, variable_exponent, ())),
                           l2 ** x3 * ln(l2) * der(x3))
 
-    def test_match_logarithm(self):
+    def test_match_logarithmic(self):
         root = tree('der(log(x))')
-        self.assertEqualPos(match_logarithm(root), [P(root, logarithm)])
+        self.assertEqualPos(match_logarithmic(root), [P(root, logarithmic)])
 
-    def test_match_logarithm_chain_rule(self):
+    def test_match_logarithmic_chain_rule(self):
         root, f = tree('der(log(x ^ 2)), x ^ 2')
-        self.assertEqualPos(match_logarithm(root),
-                [P(root, chain_rule, (f, logarithm, ()))])
+        self.assertEqualPos(match_logarithmic(root),
+                [P(root, chain_rule, (f, logarithmic, ()))])
 
-    def test_logarithm(self):
+    def test_logarithmic(self):
         root, x, l1, l10 = tree('der(log(x)), x, 1, 10')
-        self.assertEqual(logarithm(root, ()), l1 / (x * ln(l10)))
+        self.assertEqual(logarithmic(root, ()), l1 / (x * ln(l10)))
+
+    def test_match_goniometric(self):
+        root = tree('der(sin(x))')
+        self.assertEqualPos(match_goniometric(root), [P(root, sinus)])
+
+        root = tree('der(cos(x))')
+        self.assertEqualPos(match_goniometric(root), [P(root, cosinus)])
+
+        root = tree('der(tan(x))')
+        self.assertEqualPos(match_goniometric(root), [P(root, tangens)])
+
+    def test_match_goniometric_chain_rule(self):
+        root, x2 = tree('der(sin(x ^ 2)), x ^ 2')
+        self.assertEqualPos(match_goniometric(root),
+                [P(root, chain_rule, (x2, sinus, ()))])
+
+        root = tree('der(cos(x ^ 2))')
+        self.assertEqualPos(match_goniometric(root),
+                [P(root, chain_rule, (x2, cosinus, ()))])
+
+    def test_sinus(self):
+        root, x = tree('der(sin(x)), x')
+        self.assertEqual(sinus(root, ()), cos(x))
+
+    def test_cosinus(self):
+        root, x = tree('der(cos(x)), x')
+        self.assertEqual(cosinus(root, ()), -sin(x))
+
+    def test_tangens(self):
+        root, x = tree('der(tan(x), x), x')
+        self.assertEqual(tangens(root, ()), der(sin(x) / cos(x), x))
+
+        root = tree('der(tan(x))')
+        self.assertEqual(tangens(root, ()), der(sin(x) / cos(x)))