Skip to content
Snippets Groups Projects
Commit 76db9913 authored by Taddeus Kroes's avatar Taddeus Kroes
Browse files

Added rules that calculate logarithm exponents to see if a logarithm can be reduced to a number.

parent a0a12318
No related branches found
No related tags found
No related merge requests found
from itertools import combinations, product, ifilterfalse from itertools import combinations, product, ifilterfalse
import math
from .utils import find_variables, partition, divides, is_numeric_node from .utils import find_variables, partition, divides, is_numeric_node
from ..node import ExpressionLeaf as L, OP_LOG, OP_ADD, OP_MUL, OP_POW, \ from ..node import ExpressionLeaf as L, OP_LOG, OP_ADD, OP_MUL, OP_POW, \
...@@ -219,18 +220,29 @@ def match_factor_out_exponent(node): ...@@ -219,18 +220,29 @@ def match_factor_out_exponent(node):
This match simplifies a power with a variable in it to a multiplication: This match simplifies a power with a variable in it to a multiplication:
log(a ^ b) -> blog(a) log(a ^ b) -> blog(a)
log(a ^ -b) -> log((a ^ b) ^ -1) # =>* -log(a ^ b) log(a ^ -b) -> log((a ^ b) ^ -1) # =>* -log(a ^ b)
log(b, a) and a ** y = b with y in Z -> log(a ^ y, a) # =>* y
""" """
assert node.is_op(OP_LOG) assert node.is_op(OP_LOG)
p = [] p = []
exp, base = node
if node[0].is_power(): if exp.is_power():
a, b = node[0] a, b = exp
if b.negated: if b.negated:
p.append(P(node, split_negative_exponent)) p.append(P(node, split_negative_exponent))
p.append(P(node, factor_out_exponent)) if a == base:
p.append(P(node, factor_out_exponent_important))
else:
p.append(P(node, factor_out_exponent))
elif exp.is_numeric() and not exp.negated:
b, a = exp.value, base.value
y = int(round(math.log(b, a)))
if b == a ** y:
p.append(P(node, make_raised_base, (y,)))
return p return p
...@@ -257,7 +269,27 @@ def factor_out_exponent(root, args): ...@@ -257,7 +269,27 @@ def factor_out_exponent(root, args):
return b * log(a, base=base) return b * log(a, base=base)
MESSAGES[factor_out_exponent] = _('Factor out exponent {0[0][0]} from {0}.') MESSAGES[factor_out_exponent] = _('Factor out exponent {0[0][1]} from {0}.')
def factor_out_exponent_important(root, args):
return factor_out_exponent(root, args)
MESSAGES[factor_out_exponent_important] = MESSAGES[factor_out_exponent]
def make_raised_base(root, args):
"""
log(b, a) and b ** y = a with y in Z -> log(a ^ y, a) # =>* y
"""
exp, base = root
y = L(args[0])
return log(base.clone() ** y, base=base).negate(root.negated)
MESSAGES[make_raised_base] = _('Write {0[0]} as a power of {0[1]}.')
def match_factor_in_multiplicant(node): def match_factor_in_multiplicant(node):
......
from .factors import expand_double, expand_single from .factors import expand_double, expand_single
from .sort import move_constant from .sort import move_constant
from .numerics import reduce_fraction_constants from .numerics import reduce_fraction_constants, raise_numerics
from .logarithmic import factor_in_exponent_multiplicant, \ from .logarithmic import factor_in_exponent_multiplicant, \
factor_out_exponent, raised_base factor_out_exponent, raised_base, factor_out_exponent_important
from .derivatives import chain_rule from .derivatives import chain_rule
from .negation import double_negation, negated_factor, negated_nominator, \ from .negation import double_negation, negated_factor, negated_nominator, \
negated_denominator negated_denominator
...@@ -35,6 +35,8 @@ RELATIVE = [ ...@@ -35,6 +35,8 @@ RELATIVE = [
# Expand 'single' before 'double' to avoid unnessecary complexity # Expand 'single' before 'double' to avoid unnessecary complexity
(expand_single, expand_double), (expand_single, expand_double),
(factor_out_exponent_important, raise_numerics),
] ]
......
...@@ -6,7 +6,8 @@ from src.rules.logarithmic import log, match_constant_logarithm, \ ...@@ -6,7 +6,8 @@ from src.rules.logarithmic import log, match_constant_logarithm, \
factor_out_exponent, match_factor_in_multiplicant, \ factor_out_exponent, match_factor_in_multiplicant, \
factor_in_multiplicant, match_expand_terms, \ factor_in_multiplicant, match_expand_terms, \
expand_multiplication_terms, expand_division_terms, \ expand_multiplication_terms, expand_division_terms, \
factor_in_exponent_multiplicant factor_in_exponent_multiplicant, factor_out_exponent_important, \
make_raised_base
from src.node import Scope from src.node import Scope
from src.possibilities import Possibility as P from src.possibilities import Possibility as P
from tests.rulestestcase import RulesTestCase, tree from tests.rulestestcase import RulesTestCase, tree
...@@ -140,6 +141,27 @@ class TestRulesLogarithmic(RulesTestCase): ...@@ -140,6 +141,27 @@ class TestRulesLogarithmic(RulesTestCase):
[P(root, split_negative_exponent), [P(root, split_negative_exponent),
P(root, factor_out_exponent)]) P(root, factor_out_exponent)])
def test_match_factor_out_exponent_important(self):
root = tree('log(10 ^ 2)')
self.assertEqualPos(match_factor_out_exponent(root),
[P(root, factor_out_exponent_important)])
def test_match_factor_out_exponent_make_raised_base(self):
root = tree('log(100)')
self.assertEqualPos(match_factor_out_exponent(root),
[P(root, make_raised_base, (2,))])
root = tree('log(1000)')
self.assertEqualPos(match_factor_out_exponent(root),
[P(root, make_raised_base, (3,))])
root = tree('log_2(16)')
self.assertEqualPos(match_factor_out_exponent(root),
[P(root, make_raised_base, (4,))])
root = tree('log(99)')
self.assertEqualPos(match_factor_out_exponent(root), [])
def test_split_negative_exponent(self): def test_split_negative_exponent(self):
root, expect = tree('log(a ^ -b), log((a ^ b) ^ -1)') root, expect = tree('log(a ^ -b), log((a ^ b) ^ -1)')
self.assertEqual(split_negative_exponent(root, ()), expect) self.assertEqual(split_negative_exponent(root, ()), expect)
...@@ -148,6 +170,17 @@ class TestRulesLogarithmic(RulesTestCase): ...@@ -148,6 +170,17 @@ class TestRulesLogarithmic(RulesTestCase):
((a, l2), l10) = root = tree('log(a ^ 2)') ((a, l2), l10) = root = tree('log(a ^ 2)')
self.assertEqual(factor_out_exponent(root, ()), l2 * log(a)) self.assertEqual(factor_out_exponent(root, ()), l2 * log(a))
def test_make_raised_base(self):
root, expect = tree('log(1000), log(10 ^ 3)')
self.assertEqual(make_raised_base(root, (3,)), expect)
root, expect = tree('log_2(64), log_2(2 ^ 4)')
self.assertEqual(make_raised_base(root, (4,)), expect)
def test_factor_out_exponent_important(self):
((a, l2), l10) = root = tree('log(10 ^ 2)')
self.assertEqual(factor_out_exponent_important(root, ()), l2 * log(a))
def test_match_factor_in_multiplicant(self): def test_match_factor_in_multiplicant(self):
(l2, log_3) = root = tree('2log(3)') (l2, log_3) = root = tree('2log(3)')
self.assertEqualPos(match_factor_in_multiplicant(root), self.assertEqualPos(match_factor_in_multiplicant(root),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment