Эх сурвалжийг харах

Added/improved some simple rules for integrals.

Taddeus Kroes 14 жил өмнө
parent
commit
a7a2bfaac5

+ 31 - 1
src/rules/integrals.py

@@ -73,7 +73,7 @@ def match_integrate_variable_power(node):
 
     f, x = node[:2]
 
-    if f.is_power():
+    if f.is_power() and not f.negated:
         root, exponent = f
 
         if root == x and not exponent.contains(x):
@@ -113,18 +113,33 @@ MESSAGES[integrate_variable_exponent] = \
 
 def match_constant_integral(node):
     """
+    int x dx  ->  int x ^ 1 dx  # ->  x ^ 2 / 2 + c
     int c dx  ->  cx
     """
     assert node.is_op(OP_INT)
 
     fx, x = node[:2]
 
+    if fx == x:
+        return [P(node, single_variable_integral)]
+
     if not fx.contains(x):
         return [P(node, constant_integral)]
 
     return []
 
 
+def single_variable_integral(root, args):
+    """
+    int x dx  ->  int x ^ 1 dx  # ->  x ^ 2 / 2 + c
+    """
+    return integral(root[0] ** 1, *root[1:])
+
+
+MESSAGES[single_variable_integral] = _('Rewrite {0[0]} to {0[0]} ^ 1 and ' \
+        'apply the standard integral for {0[0]} ^ n.')
+
+
 def constant_integral(root, args):
     """
     int c dx  ->  cx
@@ -141,11 +156,15 @@ MESSAGES[constant_integral] = _('{0[0]} does not contain {0[1]}, so its ' \
 def match_factor_out_constant(node):
     """
     int cf(x) dx  ->  c int f(x) dx
+    int -f(x) dx  ->  -1 int f(x) dx
     """
     assert node.is_op(OP_INT)
 
     fx, x = node[:2]
 
+    if fx.negated:
+        return [P(node, split_negation_to_constant)]
+
     if not fx.is_op(OP_MUL):
         return []
 
@@ -159,6 +178,17 @@ def match_factor_out_constant(node):
     return p
 
 
+def split_negation_to_constant(root, args):
+    """
+    int -f(x) dx  ->  int -1 * f(x) dx  # =>*  -int f(x) dx
+    """
+    return integral(-L(1) * root[0].reduce_negation(), *root[1:])
+
+
+MESSAGES[split_negation_to_constant] = _('Write the negation of {0[0]} as an' \
+        ' explicit -1 and bring it outside of the integral.')
+
+
 def factor_out_constant(root, args):
     """
     int cf(x) dx  ->  c int f(x) dx

+ 38 - 13
tests/test_rules_integrals.py

@@ -1,11 +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, \
-        match_constant_integral, constant_integral, \
-        match_factor_out_constant, factor_out_constant, \
-        match_division_integral, division_integral, extend_division_integral, \
-        match_function_integral, logarithm_integral, sinus_integral, \
-        cosinus_integral
+        match_constant_integral, constant_integral, single_variable_integral, \
+        match_factor_out_constant, split_negation_to_constant, \
+        factor_out_constant, match_division_integral, division_integral, \
+        extend_division_integral, match_function_integral, \
+        logarithm_integral, sinus_integral, cosinus_integral
 from src.node import Scope
 from src.possibilities import Possibility as P
 from tests.rulestestcase import RulesTestCase, tree
@@ -41,9 +41,16 @@ class TestRulesIntegrals(RulesTestCase):
         self.assertEqual(solve_indef(root, ()), expect)
 
     def test_match_integrate_variable_power(self):
-        for root in tree('int x ^ n, int x ^ n'):
-            self.assertEqualPos(match_integrate_variable_power(root),
-                    [P(root, integrate_variable_root)])
+        root = tree('int x ^ n')
+        self.assertEqualPos(match_integrate_variable_power(root),
+                [P(root, integrate_variable_root)])
+
+        root = tree('int x ^ n')
+        self.assertEqualPos(match_integrate_variable_power(root),
+                [P(root, integrate_variable_root)])
+
+        root = tree('int -x ^ n')
+        self.assertEqualPos(match_integrate_variable_power(root), [])
 
         for root in tree('int g ^ x, int g ^ x'):
             self.assertEqualPos(match_integrate_variable_power(root),
@@ -58,11 +65,21 @@ class TestRulesIntegrals(RulesTestCase):
         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)])
+        root = tree('int x dx')
+        self.assertEqualPos(match_constant_integral(root),
+                [P(root, single_variable_integral)])
+
+        root = tree('int 2')
+        self.assertEqualPos(match_constant_integral(root),
+                [P(root, constant_integral)])
+
+        root = tree('int c dx')
+        self.assertEqualPos(match_constant_integral(root),
+                [P(root, constant_integral)])
+
+    def test_single_variable_integral(self):
+        root, expect = tree('int x, int x ^ 1')
+        self.assertEqual(single_variable_integral(root, ()), expect)
 
     def test_constant_integral(self):
         root, expect = tree('int 2, 2x + c')
@@ -76,6 +93,14 @@ class TestRulesIntegrals(RulesTestCase):
         self.assertEqualPos(match_factor_out_constant(root),
                 [P(root, factor_out_constant, (Scope(cx), c))])
 
+        root = tree('int -x2 dx')
+        self.assertEqualPos(match_factor_out_constant(root),
+                [P(root, split_negation_to_constant)])
+
+    def test_split_negation_to_constant(self):
+        root, expect = tree('int -x2 dx, int -1x2 dx')
+        self.assertEqual(split_negation_to_constant(root, ()), expect)
+
     def test_factor_out_constant(self):
         root, expect = tree('int cx2 dx, c int x2 dx')
         c, x2 = cx2 = root[0]