Commit 895c81d7 authored by Taddeus Kroes's avatar Taddeus Kroes

Added derivation rule for logarithm.

parent 0f086a69
from ..node import OP_ADD, OP_MUL, OP_DIV, OP_POW, OP_NEG, OP_SIN, OP_COS, \ 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 .groups import match_combine_groups
from .factors import match_expand from .factors import match_expand
from .powers import match_add_exponents, match_subtract_exponents, \ from .powers import match_add_exponents, match_subtract_exponents, \
...@@ -19,7 +19,7 @@ from .goniometry import match_add_quadrants, match_negated_parameter, \ ...@@ -19,7 +19,7 @@ from .goniometry import match_add_quadrants, match_negated_parameter, \
match_half_pi_subtraction, match_standard_radian match_half_pi_subtraction, match_standard_radian
from src.rules.derivatives import match_zero_derivative, \ from src.rules.derivatives import match_zero_derivative, \
match_one_derivative, match_variable_power, \ match_one_derivative, match_variable_power, \
match_const_deriv_multiplication match_const_deriv_multiplication, match_logarithm
RULES = { RULES = {
OP_ADD: [match_add_numerics, match_add_constant_fractions, OP_ADD: [match_add_numerics, match_add_constant_fractions,
...@@ -41,6 +41,7 @@ RULES = { ...@@ -41,6 +41,7 @@ RULES = {
OP_COS: [match_negated_parameter, match_half_pi_subtraction, OP_COS: [match_negated_parameter, match_half_pi_subtraction,
match_standard_radian], match_standard_radian],
OP_TAN: [match_standard_radian], OP_TAN: [match_standard_radian],
OP_DERIV: [match_zero_derivative, match_one_derivative, OP_DER: [match_zero_derivative, match_one_derivative,
match_variable_power, match_const_deriv_multiplication], match_variable_power, match_const_deriv_multiplication,
match_logarithm],
} }
...@@ -2,8 +2,8 @@ from itertools import combinations ...@@ -2,8 +2,8 @@ from itertools import combinations
from .utils import find_variables from .utils import find_variables
from .logarithmic import ln from .logarithmic import ln
from ..node import ExpressionNode as N, ExpressionLeaf as L, Scope, OP_DERIV, \ from ..node import ExpressionNode as N, ExpressionLeaf as L, Scope, OP_DER, \
OP_MUL OP_MUL, OP_LOG
from ..possibilities import Possibility as P, MESSAGES from ..possibilities import Possibility as P, MESSAGES
from ..translate import _ from ..translate import _
...@@ -58,7 +58,7 @@ def match_zero_derivative(node): ...@@ -58,7 +58,7 @@ def match_zero_derivative(node):
der(x, y) -> 0 der(x, y) -> 0
der(n) -> 0 der(n) -> 0
""" """
assert node.is_op(OP_DERIV) assert node.is_op(OP_DER)
variables = find_variables(node[0]) variables = find_variables(node[0])
var = get_derivation_variable(node, variables) var = get_derivation_variable(node, variables)
...@@ -74,7 +74,7 @@ def match_one_derivative(node): ...@@ -74,7 +74,7 @@ def match_one_derivative(node):
der(x) -> 1 # Implicit x der(x) -> 1 # Implicit x
der(x, x) -> 1 # Explicit x der(x, x) -> 1 # Explicit x
""" """
assert node.is_op(OP_DERIV) assert node.is_op(OP_DER)
var = get_derivation_variable(node) var = get_derivation_variable(node)
...@@ -110,7 +110,7 @@ def match_const_deriv_multiplication(node): ...@@ -110,7 +110,7 @@ def match_const_deriv_multiplication(node):
""" """
der(c * f(x), x) -> c * der(f(x), x) der(c * f(x), x) -> c * der(f(x), x)
""" """
assert node.is_op(OP_DERIV) assert node.is_op(OP_DER)
p = [] p = []
...@@ -146,7 +146,7 @@ def match_variable_power(node): ...@@ -146,7 +146,7 @@ def match_variable_power(node):
der(x ^ n, x) -> n * x ^ (n - 1) der(x ^ n, x) -> n * x ^ (n - 1)
der(f(x) ^ n) -> n * f(x) ^ (n - 1) * der(f(x)) # Chain rule 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(): if not node[0].is_power():
return [] return []
...@@ -199,3 +199,38 @@ def variable_exponent(root, args): ...@@ -199,3 +199,38 @@ def variable_exponent(root, args):
MESSAGES[variable_exponent] = \ MESSAGES[variable_exponent] = \
_('Apply standard derivative d/dx g ^ x = g ^ x * ln g.') _('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)).')
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 ..possibilities import Possibility as P, MESSAGES
from ..translate import _ from ..translate import _
...@@ -11,4 +11,4 @@ def log(exponent, base=10): ...@@ -11,4 +11,4 @@ def log(exponent, base=10):
def ln(exponent): def ln(exponent):
return N('ln', exponent) return log(exponent, base=E)
...@@ -2,7 +2,7 @@ from src.rules.derivatives import der, get_derivation_variable, \ ...@@ -2,7 +2,7 @@ from src.rules.derivatives import der, get_derivation_variable, \
match_zero_derivative, match_one_derivative, one_derivative, \ match_zero_derivative, match_one_derivative, one_derivative, \
zero_derivative, match_variable_power, variable_root, \ zero_derivative, match_variable_power, variable_root, \
variable_exponent, match_const_deriv_multiplication, \ 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.rules.logarithmic import ln
from src.node import Scope from src.node import Scope
from src.possibilities import Possibility as P from src.possibilities import Possibility as P
...@@ -109,3 +109,16 @@ class TestRulesDerivatives(RulesTestCase): ...@@ -109,3 +109,16 @@ class TestRulesDerivatives(RulesTestCase):
x, l3 = x3 x, l3 = x3
self.assertEqual(chain_rule(root, (x3, variable_exponent, ())), self.assertEqual(chain_rule(root, (x3, variable_exponent, ())),
l2 ** x3 * ln(l2) * der(x3)) 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)))
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment