Commit 47c00a91 authored by Taddeus Kroes's avatar Taddeus Kroes

Added the basics for integral rewrite rules.

parent c19155e6
from .utils import find_variables, first_sorted_variable, infinity, \
replace_variable
from .logarithmic import ln
#from .goniometry import sin, cos
from ..node import ExpressionLeaf as L, OP_INT
from ..possibilities import Possibility as P, MESSAGES
from ..translate import _
#def ader(f, x=None):
# """
# Anti-derivative.
# """
# return N(OP_INT, f, x)
def integral_params(integral):
"""
Get integral parameters:
- If f(x) and x are both specified, return them.
- If only f(x) is specified, find x.
"""
if len(integral) > 1:
assert integral[1].is_identifier()
return tuple(integral[:2])
f = integral[0]
variables = find_variables(integral)
if not len(variables):
return f, None
return f, L(first_sorted_variable(variables))
def choose_constant(integral):
"""
Choose a constant to be added to the antiderivative.
"""
occupied = find_variables(integral)
c = 'c'
i = 96
while c in occupied:
i += 2 if i == 98 else 1
c = chr(i)
return L(c)
def solve_integral(integral, F):
"""
Solve an integral given its anti-derivative F:
- First, finish the anti-derivative by adding a constant.
- If no bounds are specified, return the anti-derivative.
- If only a lower bound is specified, set the upper bound to infinity.
- Given a lower bound a and upper bound b, the solution is F(b) - F(a).
"""
F += choose_constant(integral)
if len(integral) < 3:
return F
x = integral[1]
lower = integral[2]
upper = infinity() if len(integral) < 4 else integral[3]
# TODO: add notation [F(x)]_a^b
return replace_variable(F, x, lower) - replace_variable(F, x, upper)
def match_integrate_variable_power(node):
"""
int(x ^ n, x) -> x ^ (n + 1) / (n + 1) + c
int(g ^ x, x) -> g ^ x / ln(g)
"""
assert node.is_op(OP_INT)
f, x = integral_params(node)
if f.is_power():
root, exponent = f
if root == x and not exponent.contains(x):
return [P(node, integrate_variable_root)]
if exponent == x and not root.contains(x):
return [P(node, integrate_variable_exponent)]
return []
def integrate_variable_root(root, args):
"""
int(x ^ n, x) -> x ^ (n + 1) / (n + 1) + c
"""
x, n = root[0]
return solve_integral(root, x ** (n + 1) / (n + 1))
MESSAGES[integrate_variable_root] = \
_('Apply standard integral int(x ^ n) = x ^ (n + 1) / (n + 1) + c.')
def integrate_variable_exponent(root, args):
"""
int(g ^ x, x) -> g ^ x / ln(g)
"""
g, x = root[0]
return solve_integral(root, g ** x / ln(g))
MESSAGES[integrate_variable_exponent] = \
_('Apply standard integral int(g ^ x) = g ^ x / ln(g) + c.')
from src.rules.integrals import integral_params, choose_constant, \
match_integrate_variable_power, integrate_variable_root, \
integrate_variable_exponent
from src.rules.logarithmic import ln
#from .goniometry import sin, cos
from src.possibilities import Possibility as P
from tests.rulestestcase import RulesTestCase, tree
class TestRulesIntegrals(RulesTestCase):
def test_integral_params(self):
f, x = root = tree('int(fx, x)')
self.assertEqual(integral_params(root), (f, x))
root = tree('int(fx)')
self.assertEqual(integral_params(root), (f, x))
root = tree('int(3)')
self.assertEqual(integral_params(root), (3, None))
def test_choose_constant(self):
a, b, c = tree('a, b, c')
self.assertEqual(choose_constant(tree('int(x ^ n, x)')), c)
self.assertEqual(choose_constant(tree('int(x ^ c, x)')), a)
self.assertEqual(choose_constant(tree('int(a ^ c, a)')), b)
def test_match_integrate_variable_power(self):
for root in tree('int(x ^ n, x), int(x ^ n)'):
self.assertEqualPos(match_integrate_variable_power(root),
[P(root, integrate_variable_root)])
for root in tree('int(g ^ x, x), int(g ^ x)'):
self.assertEqualPos(match_integrate_variable_power(root),
[P(root, integrate_variable_exponent)])
def test_integrate_variable_root(self):
((x, n),), c = root, c = tree('int(x ^ n), c')
self.assertEqual(integrate_variable_root(root, ()),
x ** (n + 1) / (n + 1) + c)
def test_integrate_variable_exponent(self):
((g, x),), c = root, c = tree('int(g ^ x), c')
self.assertEqual(integrate_variable_exponent(root, ()),
g ** x / ln(g) + c)
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