Просмотр исходного кода

Added rules for reducing integrals with constants.

Taddeus Kroes 14 лет назад
Родитель
Сommit
1952f7ba2e
3 измененных файлов с 96 добавлено и 7 удалено
  1. 4 3
      src/rules/__init__.py
  2. 64 3
      src/rules/integrals.py
  3. 28 1
      tests/test_rules_integrals.py

+ 4 - 3
src/rules/__init__.py

@@ -24,8 +24,8 @@ from src.rules.derivatives import match_zero_derivative, \
 from src.rules.logarithmic import match_constant_logarithm, \
         match_add_logarithms, match_raised_base, match_factor_out_exponent, \
         match_factor_in_multiplicant
-from src.rules.integrals import match_solve_indef, \
-        match_integrate_variable_power
+from src.rules.integrals import match_solve_indef, match_constant_integral, \
+        match_integrate_variable_power, match_factor_out_constant
 
 RULES = {
         OP_ADD: [match_add_numerics, match_add_constant_fractions,
@@ -55,6 +55,7 @@ RULES = {
                  match_logarithmic, match_goniometric, match_sum_product_rule,
                  match_quotient_rule],
         OP_LOG: [match_constant_logarithm, match_factor_out_exponent],
-        OP_INT: [match_integrate_variable_power],
+        OP_INT: [match_integrate_variable_power, match_constant_integral,
+                 match_factor_out_constant],
         OP_INT_INDEF: [match_solve_indef],
         }

+ 64 - 3
src/rules/integrals.py

@@ -2,7 +2,7 @@ from .utils import find_variables, infinity, replace_variable, find_variable
 from .logarithmic import ln
 #from .goniometry import sin, cos
 from ..node import ExpressionNode as N, ExpressionLeaf as L, OP_INT, \
-        OP_INT_INDEF
+        OP_INT_INDEF, OP_MUL, Scope
 from ..possibilities import Possibility as P, MESSAGES
 from ..translate import _
 
@@ -82,7 +82,7 @@ def solve_indef(root, args):
 
 def match_integrate_variable_power(node):
     """
-    int x ^ n dx  ->  x ^ (n + 1) / (n + 1) + c
+    int x ^ n dx  ->  x ^ (n + 1) / (n + 1)
     int g ^ x dx  ->  g ^ x / ln(g)
     """
     assert node.is_op(OP_INT)
@@ -103,7 +103,7 @@ def match_integrate_variable_power(node):
 
 def integrate_variable_root(root, args):
     """
-    int x ^ n dx  ->  x ^ (n + 1) / (n + 1) + c
+    int x ^ n dx  ->  x ^ (n + 1) / (n + 1)
     """
     x, n = root[0]
 
@@ -125,3 +125,64 @@ def integrate_variable_exponent(root, args):
 
 MESSAGES[integrate_variable_exponent] = \
         _('Apply standard integral int(g ^ x) = g ^ x / ln(g) + c.')
+
+
+def match_constant_integral(node):
+    """
+    int c dx  ->  cx
+    """
+    assert node.is_op(OP_INT)
+
+    fx, x = node[:2]
+
+    if not fx.contains(x):
+        return [P(node, constant_integral)]
+
+    return []
+
+
+def constant_integral(root, args):
+    """
+    int c dx  ->  cx
+    """
+    c, x = root[:2]
+
+    return solve_integral(root, c * x)
+
+
+MESSAGES[constant_integral] = _('{0[0]} does not contain {0[1]}, so its ' \
+        'integral over {0[1]} is its multiplication with {0[1]}.')
+
+
+def match_factor_out_constant(node):
+    """
+    int cf(x) dx  ->  c int f(x) dx
+    """
+    assert node.is_op(OP_INT)
+
+    fx, x = node[:2]
+
+    if not fx.is_op(OP_MUL):
+        return []
+
+    p = []
+    scope = Scope(fx)
+
+    for n in scope:
+        if not n.contains(x):
+            p.append(P(node, factor_out_constant, (scope, n)))
+
+    return p
+
+
+def factor_out_constant(root, args):
+    """
+    int cf(x) dx  ->  c int f(x) dx
+    """
+    scope, c = args
+    scope.remove(c)
+
+    return c * integral(scope.as_nary_node(), *root[1:])
+
+
+MESSAGES[factor_out_constant] = _('Factor out {2} from integral {0}.')

+ 28 - 1
tests/test_rules_integrals.py

@@ -1,8 +1,11 @@
 from src.rules.integrals import indef, choose_constant, solve_integral, \
         match_solve_indef, solve_indef, match_integrate_variable_power, \
-        integrate_variable_root, integrate_variable_exponent
+        integrate_variable_root, integrate_variable_exponent, \
+        match_constant_integral, constant_integral, \
+        match_factor_out_constant, factor_out_constant
 from src.rules.logarithmic import ln
 #from .goniometry import sin, cos
+from src.node import Scope
 from src.possibilities import Possibility as P
 from tests.rulestestcase import RulesTestCase, tree
 
@@ -52,3 +55,27 @@ class TestRulesIntegrals(RulesTestCase):
     def test_integrate_variable_exponent(self):
         root, expect = tree('int g ^ x, g ^ x / ln(g) + c')
         self.assertEqual(integrate_variable_exponent(root, ()), expect)
+
+    def test_match_constant_integral(self):
+        root0, root1 = tree('int 2, int c dx')
+        self.assertEqualPos(match_constant_integral(root0),
+                [P(root0, constant_integral)])
+        self.assertEqualPos(match_constant_integral(root1),
+                [P(root1, constant_integral)])
+
+    def test_constant_integral(self):
+        root, expect = tree('int 2, 2x + c')
+        self.assertEqual(constant_integral(root, ()), expect)
+
+        root, expect = tree('int_0^4 2, [2x + c]_0^4')
+        self.assertEqual(constant_integral(root, ()), expect)
+
+    def test_match_factor_out_constant(self):
+        root, c, cx = tree('int cx dx, c, cx')
+        self.assertEqualPos(match_factor_out_constant(root),
+                [P(root, factor_out_constant, (Scope(cx), c))])
+
+    def test_factor_out_constant(self):
+        root, expect = tree('int cx2 dx, c int x2 dx')
+        c, x2 = cx2 = root[0]
+        self.assertEqual(factor_out_constant(root, (Scope(cx2), c)), expect)