Commit 76db9913 authored by Taddeus Kroes's avatar Taddeus Kroes

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

parent a0a12318
from itertools import combinations, product, ifilterfalse
import math
from .utils import find_variables, partition, divides, is_numeric_node
from ..node import ExpressionLeaf as L, OP_LOG, OP_ADD, OP_MUL, OP_POW, \
......@@ -219,18 +220,29 @@ def match_factor_out_exponent(node):
This match simplifies a power with a variable in it to a multiplication:
log(a ^ b) -> blog(a)
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)
p = []
exp, base = node
if node[0].is_power():
a, b = node[0]
if exp.is_power():
a, b = exp
if b.negated:
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
......@@ -257,7 +269,27 @@ def factor_out_exponent(root, args):
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):
......
from .factors import expand_double, expand_single
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, \
factor_out_exponent, raised_base
factor_out_exponent, raised_base, factor_out_exponent_important
from .derivatives import chain_rule
from .negation import double_negation, negated_factor, negated_nominator, \
negated_denominator
......@@ -35,6 +35,8 @@ RELATIVE = [
# Expand 'single' before 'double' to avoid unnessecary complexity
(expand_single, expand_double),
(factor_out_exponent_important, raise_numerics),
]
......
......@@ -6,7 +6,8 @@ from src.rules.logarithmic import log, match_constant_logarithm, \
factor_out_exponent, match_factor_in_multiplicant, \
factor_in_multiplicant, match_expand_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.possibilities import Possibility as P
from tests.rulestestcase import RulesTestCase, tree
......@@ -140,6 +141,27 @@ class TestRulesLogarithmic(RulesTestCase):
[P(root, split_negative_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):
root, expect = tree('log(a ^ -b), log((a ^ b) ^ -1)')
self.assertEqual(split_negative_exponent(root, ()), expect)
......@@ -148,6 +170,17 @@ class TestRulesLogarithmic(RulesTestCase):
((a, l2), l10) = root = tree('log(a ^ 2)')
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):
(l2, log_3) = root = tree('2log(3)')
self.assertEqualPos(match_factor_in_multiplicant(root),
......
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