Parcourir la source

Added derivation rule for logarithm.

Taddeus Kroes il y a 14 ans
Parent
commit
895c81d751
4 fichiers modifiés avec 62 ajouts et 13 suppressions
  1. 5 4
      src/rules/__init__.py
  2. 41 6
      src/rules/derivatives.py
  3. 2 2
      src/rules/logarithmic.py
  4. 14 1
      tests/test_rules_derivatives.py

+ 5 - 4
src/rules/__init__.py

@@ -1,5 +1,5 @@
 from ..node import OP_ADD, OP_MUL, OP_DIV, OP_POW, OP_NEG, OP_SIN, OP_COS, \
-        OP_TAN, OP_DERIV
+        OP_TAN, OP_DER
 from .groups import match_combine_groups
 from .factors import match_expand
 from .powers import match_add_exponents, match_subtract_exponents, \
@@ -19,7 +19,7 @@ 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_const_deriv_multiplication, match_logarithm
 
 RULES = {
         OP_ADD: [match_add_numerics, match_add_constant_fractions,
@@ -41,6 +41,7 @@ RULES = {
         OP_COS: [match_negated_parameter, match_half_pi_subtraction,
                  match_standard_radian],
         OP_TAN: [match_standard_radian],
-        OP_DERIV: [match_zero_derivative, match_one_derivative,
-                   match_variable_power, match_const_deriv_multiplication],
+        OP_DER: [match_zero_derivative, match_one_derivative,
+                 match_variable_power, match_const_deriv_multiplication,
+                 match_logarithm],
         }

+ 41 - 6
src/rules/derivatives.py

@@ -2,8 +2,8 @@ from itertools import combinations
 
 from .utils import find_variables
 from .logarithmic import ln
-from ..node import ExpressionNode as N, ExpressionLeaf as L, Scope, OP_DERIV, \
-        OP_MUL
+from ..node import ExpressionNode as N, ExpressionLeaf as L, Scope, OP_DER, \
+        OP_MUL, OP_LOG
 from ..possibilities import Possibility as P, MESSAGES
 from ..translate import _
 
@@ -58,7 +58,7 @@ def match_zero_derivative(node):
     der(x, y)  ->  0
     der(n)     ->  0
     """
-    assert node.is_op(OP_DERIV)
+    assert node.is_op(OP_DER)
 
     variables = find_variables(node[0])
     var = get_derivation_variable(node, variables)
@@ -74,7 +74,7 @@ def match_one_derivative(node):
     der(x)     ->  1  # Implicit x
     der(x, x)  ->  1  # Explicit x
     """
-    assert node.is_op(OP_DERIV)
+    assert node.is_op(OP_DER)
 
     var = get_derivation_variable(node)
 
@@ -110,7 +110,7 @@ def match_const_deriv_multiplication(node):
     """
     der(c * f(x), x)  ->  c * der(f(x), x)
     """
-    assert node.is_op(OP_DERIV)
+    assert node.is_op(OP_DER)
 
     p = []
 
@@ -146,7 +146,7 @@ def match_variable_power(node):
     der(x ^ n, x)  ->  n * x ^ (n - 1)
     der(f(x) ^ n)  ->  n * f(x) ^ (n - 1) * der(f(x))  # Chain rule
     """
-    assert node.is_op(OP_DERIV)
+    assert node.is_op(OP_DER)
 
     if not node[0].is_power():
         return []
@@ -199,3 +199,38 @@ def variable_exponent(root, args):
 
 MESSAGES[variable_exponent] = \
         _('Apply standard derivative d/dx g ^ x = g ^ x * ln g.')
+
+
+def match_logarithm(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)
+    """
+    assert node.is_op(OP_DER)
+
+    x = get_derivation_variable(node)
+
+    if x and node[0].is_op(OP_LOG):
+        f = node[0][0]
+        x = L(x)
+
+        if f == x:
+            return [P(node, logarithm, ())]
+
+        if f.contains(x):
+            return [P(node, chain_rule, (f, logarithm, ()))]
+
+    return []
+
+
+def logarithm(root, args):
+    """
+    der(log(x, g), x)  ->  1 / (x * ln(g))
+    """
+    x, g = root[0]
+
+    return L(1) / (x * ln(g))
+
+
+MESSAGES[logarithm] = \
+        _('Apply standard derivative d/dx log(x, g) = 1 / (x * ln(g)).')

+ 2 - 2
src/rules/logarithmic.py

@@ -1,4 +1,4 @@
-from ..node import ExpressionNode as N, ExpressionLeaf as L, OP_LOG, OP_LN
+from ..node import ExpressionNode as N, ExpressionLeaf as L, OP_LOG, E
 from ..possibilities import Possibility as P, MESSAGES
 from ..translate import _
 
@@ -11,4 +11,4 @@ def log(exponent, base=10):
 
 
 def ln(exponent):
-    return N('ln', exponent)
+    return log(exponent, base=E)

+ 14 - 1
tests/test_rules_derivatives.py

@@ -2,7 +2,7 @@ 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
+        const_deriv_multiplication, chain_rule, match_logarithm, logarithm
 from src.rules.logarithmic import ln
 from src.node import Scope
 from src.possibilities import Possibility as P
@@ -109,3 +109,16 @@ class TestRulesDerivatives(RulesTestCase):
         x, l3 = x3
         self.assertEqual(chain_rule(root, (x3, variable_exponent, ())),
                           l2 ** x3 * ln(l2) * der(x3))
+
+    def test_match_logarithm(self):
+        root = tree('der(log(x))')
+        self.assertEqualPos(match_logarithm(root), [P(root, logarithm)])
+
+    def test_match_logarithm_chain_rule(self):
+        root, f = tree('der(log(x ^ 2)), x ^ 2')
+        self.assertEqualPos(match_logarithm(root),
+                [P(root, chain_rule, (f, logarithm, ()))])
+
+    def test_logarithm(self):
+        root, x, l1, l10 = tree('der(log(x)), x, 1, 10')
+        self.assertEqual(logarithm(root, ()), l1 / (x * ln(l10)))