Răsfoiți Sursa

Added rules for integrals of fractions.

Taddeus Kroes 14 ani în urmă
părinte
comite
fa682fe014
3 a modificat fișierele cu 73 adăugiri și 5 ștergeri
  1. 3 2
      src/rules/__init__.py
  2. 45 2
      src/rules/integrals.py
  3. 25 1
      tests/test_rules_integrals.py

+ 3 - 2
src/rules/__init__.py

@@ -25,7 +25,8 @@ 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_constant_integral, \
-        match_integrate_variable_power, match_factor_out_constant
+        match_integrate_variable_power, match_factor_out_constant, \
+        match_division_integral
 
 RULES = {
         OP_ADD: [match_add_numerics, match_add_constant_fractions,
@@ -56,6 +57,6 @@ RULES = {
                  match_quotient_rule],
         OP_LOG: [match_constant_logarithm, match_factor_out_exponent],
         OP_INT: [match_integrate_variable_power, match_constant_integral,
-                 match_factor_out_constant],
+                 match_factor_out_constant, match_division_integral],
         OP_INT_INDEF: [match_solve_indef],
         }

+ 45 - 2
src/rules/integrals.py

@@ -1,8 +1,9 @@
-from .utils import find_variables, infinity, replace_variable, find_variable
+from .utils import find_variables, infinity, replace_variable, find_variable, \
+        absolute
 from .logarithmic import ln
 #from .goniometry import sin, cos
 from ..node import ExpressionNode as N, ExpressionLeaf as L, OP_INT, \
-        OP_INT_INDEF, OP_MUL, Scope
+        OP_INT_INDEF, OP_MUL, OP_DIV, Scope
 from ..possibilities import Possibility as P, MESSAGES
 from ..translate import _
 
@@ -186,3 +187,45 @@ def factor_out_constant(root, args):
 
 
 MESSAGES[factor_out_constant] = _('Factor out {2} from integral {0}.')
+
+
+def match_division_integral(node):
+    """
+    int 1 / x dx  ->  ln|x|
+    int a / x dx  ->  int a(1 / x) dx  # -> a int 1 / x dx  ->  aln|x|
+    """
+    assert node.is_op(OP_INT)
+
+    fx, x = node[:2]
+
+    if fx.is_op(OP_DIV) and fx[1] == x:
+        if fx[0] == 1:
+            return [P(node, division_integral)]
+
+        return [P(node, extend_division_integral)]
+
+    return []
+
+
+def division_integral(root, args):
+    """
+    int 1 / x dx  ->  ln|x|
+    """
+    return solve_integral(root, ln(absolute(root[0][1])))
+
+
+MESSAGES[division_integral] = \
+        _('1 / {0[1]} has the standard ant-derivative ln|{0[1]}|.')
+
+
+def extend_division_integral(root, args):
+    """
+    int a / x dx  ->  int a(1 / x) dx  # -> a int 1 / x dx  ->  aln|x|
+    """
+    a, x = root[0]
+
+    return integral(a * (L(1) / x), *root[1:])
+
+
+MESSAGES[extend_division_integral] = _('Bring nominator {0[0][0]} out of the' \
+        ' fraction to obtain a standard 1 / {0[0][1]} integral.')

+ 25 - 1
tests/test_rules_integrals.py

@@ -2,7 +2,8 @@ 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_factor_out_constant, factor_out_constant, \
+        match_division_integral, division_integral, extend_division_integral
 from src.rules.logarithmic import ln
 #from .goniometry import sin, cos
 from src.node import Scope
@@ -79,3 +80,26 @@ class TestRulesIntegrals(RulesTestCase):
         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)
+
+    def test_match_division_integral(self):
+        root0, root1 = tree('int 1 / x, int 2 / x')
+        self.assertEqualPos(match_division_integral(root0),
+                [P(root0, division_integral)])
+        self.assertEqualPos(match_division_integral(root1),
+                [P(root1, extend_division_integral)])
+
+    def test_division_integral(self):
+        root, expect = tree('int 1 / x dx, ln|x| + c')
+        self.assertEqual(division_integral(root, ()), expect)
+
+    def test_extend_division_integral(self):
+        root, expect = tree('int a / x dx, int a(1 / x) dx')
+        self.assertEqual(extend_division_integral(root, ()), expect)
+
+    def test_match_division_integral_chain(self):
+        self.assertRewrite([
+            'int a / x',
+            'int a(1 / x) dx',
+            # FIXME: 'a int 1 / x dx',  # fix with strategy
+            # FIXME: 'aln|x| + c',
+        ])