Przeglądaj źródła

Corrected mixed up definite/indefinite integral references

Taddeus Kroes 13 lat temu
rodzic
commit
f5e26d068d
8 zmienionych plików z 65 dodań i 65 usunięć
  1. 0 2
      TODO
  2. 9 8
      src/node.py
  3. 2 2
      src/parser.py
  4. 4 4
      src/rules/__init__.py
  5. 20 20
      src/rules/integrals.py
  6. 4 4
      tests/test_node.py
  7. 8 8
      tests/test_parser.py
  8. 18 17
      tests/test_rules_integrals.py

+ 0 - 2
TODO

@@ -44,5 +44,3 @@
 
 - Missed rewrite possibility:
   (4x) / (2x ^ 2 - 2y ^ 2)  ->  (2x) / (x ^ 2 - y ^ 2)
-
-- "indefinite" / "definite" are sometimes confused in messges, fix that...

+ 9 - 8
src/node.py

@@ -50,7 +50,7 @@ NARY_OPERATORS = [OP_ADD, OP_SUB, OP_MUL, OP_AND, OP_OR]
 
 # N-ary (functions)
 OP_INT = 11
-OP_INT_INDEF = 12
+OP_INT_DEF = 12
 OP_COMMA = 13
 OP_SQRT = 14
 OP_DER = 15
@@ -125,7 +125,7 @@ OP_MAP = {
         }
 
 OP_VALUE_MAP = dict([(v, k) for k, v in OP_MAP.iteritems()])
-OP_VALUE_MAP[OP_INT_INDEF] = 'indef'
+OP_VALUE_MAP[OP_INT_DEF] = 'indef'
 OP_VALUE_MAP[OP_ABS] = '||'
 OP_VALUE_MAP[OP_DXDER] = 'd/d'
 OP_VALUE_MAP[OP_PARENS] = '()'
@@ -363,13 +363,13 @@ class ExpressionNode(Node, ExpressionBase):
         return self.value
 
     def is_postfix(self):
-        return self.op in (OP_PRIME, OP_INT_INDEF)
+        return self.op in (OP_PRIME, OP_INT_DEF)
 
     def __str__(self):  # pragma: nocover
         return generate_line(self)
 
     def custom_line(self):
-        if self.op == OP_INT_INDEF:
+        if self.op == OP_INT_DEF:
             Fx, a, b = self
             return bounds_str(ExpressionNode(OP_BRACKETS, Fx), a, b)
 
@@ -751,16 +751,17 @@ def der(f, x=None):
 
 def integral(*args):
     """
-    Create an integral node.
+    Create an integral node (may be definite or indefinite, depending on
+    whether there are bounds in `args`).
     """
     return ExpressionNode(OP_INT, *args)
 
 
-def indef(*args):
+def int_def(*args):
     """
-    Create an indefinite integral node.
+    Create a definite integral node (bracket notation).
     """
-    return ExpressionNode(OP_INT_INDEF, *args)
+    return ExpressionNode(OP_INT_DEF, *args)
 
 
 def eq(left, right):

+ 2 - 2
src/parser.py

@@ -31,7 +31,7 @@ from graph_drawing.line import pred
 from node import ExpressionNode as Node, \
         ExpressionLeaf as Leaf, OP_MAP, OP_DXDER, TOKEN_MAP, TYPE_OPERATOR, \
         OP_COMMA, OP_MUL, OP_POW, OP_LOG, OP_ADD, Scope, E, OP_ABS, \
-        DEFAULT_LOGARITHM_BASE, SPECIAL_TOKENS, OP_INT, OP_INT_INDEF, \
+        DEFAULT_LOGARITHM_BASE, SPECIAL_TOKENS, OP_INT, OP_INT_DEF, \
         INFINITY, OP_PRIME, OP_DIV
 from rules.utils import find_variable
 from rules.precedences import IMPLICIT_RULES
@@ -683,7 +683,7 @@ class Parser(BisonParser):
 
             lbnd.negated += len(values[1]) - 1
 
-            return Node(OP_INT_INDEF, values[0], lbnd, ubnd)
+            return Node(OP_INT_DEF, values[0], lbnd, ubnd)
 
         raise BisonSyntaxError('Unsupported option %d in target "%s".'
                                % (option, target))  # pragma: nocover

+ 4 - 4
src/rules/__init__.py

@@ -13,7 +13,7 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with TRS.  If not, see <http://www.gnu.org/licenses/>.
 from ..node import OP_ADD, OP_MUL, OP_DIV, OP_POW, OP_NEG, OP_SIN, OP_COS, \
-        OP_TAN, OP_DER, OP_LOG, OP_INT, OP_INT_INDEF, OP_EQ, OP_ABS, OP_SQRT, \
+        OP_TAN, OP_DER, OP_LOG, OP_INT, OP_INT_DEF, OP_EQ, OP_ABS, OP_SQRT, \
         OP_AND, OP_OR, OP_DXDER, OP_PRIME
 from .groups import match_combine_groups
 from .factors import match_expand
@@ -40,10 +40,10 @@ from .derivatives import match_zero_derivative, \
 from .logarithmic import match_constant_logarithm, \
         match_add_logarithms, match_raised_base, match_factor_out_exponent, \
         match_factor_in_multiplicant, match_expand_terms
-from .integrals import match_solve_indef, match_constant_integral, \
+from .integrals import match_solve_definite, match_constant_integral, \
         match_integrate_variable_power, match_factor_out_constant, \
         match_division_integral, match_function_integral, \
-        match_sum_rule_integral, match_remove_indef_constant
+        match_sum_rule_integral, match_remove_definite_constant
 from .lineq import match_move_term, match_multiple_equations, match_double_case
 from .absolute import match_factor_out_abs_term
 from .sqrt import match_reduce_sqrt
@@ -82,7 +82,7 @@ RULES = {
         OP_INT: [match_integrate_variable_power, match_constant_integral,
                  match_factor_out_constant, match_division_integral,
                  match_function_integral, match_sum_rule_integral],
-        OP_INT_INDEF: [match_remove_indef_constant, match_solve_indef],
+        OP_INT_DEF: [match_remove_definite_constant, match_solve_definite],
         OP_EQ: [match_move_term],
         OP_ABS: [match_factor_out_abs_term],
         OP_SQRT: [match_reduce_sqrt],

+ 20 - 20
src/rules/integrals.py

@@ -13,8 +13,8 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with TRS.  If not, see <http://www.gnu.org/licenses/>.
 from .utils import find_variables, substitute, find_variable
-from ..node import ExpressionLeaf as L, OP_INT, OP_INT_INDEF, OP_MUL, OP_DIV, \
-        OP_LOG, OP_SIN, OP_COS, Scope, sin, cos, ln, integral, indef, \
+from ..node import ExpressionLeaf as L, OP_INT, OP_INT_DEF, OP_MUL, OP_DIV, \
+        OP_LOG, OP_SIN, OP_COS, Scope, sin, cos, ln, integral, int_def, \
         absolute, OP_ADD, negate
 from ..possibilities import Possibility as P, MESSAGES
 from ..translate import _
@@ -43,10 +43,10 @@ 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.
-    - Given a lower bound a and upper bound b, the solution is the indefinite
+    - Given a lower bound a and upper bound b, the solution is the definite
       integral [F(x)]_a^b. If F(x) contains multiple variables so that the 'x'
-      is not identified by 'find_variable(F)' (which is used by the indefinite
-      integral), skip the reduction of the indefinite integral and return the
+      is not identified by 'find_variable(F)' (which is used by the definite
+      integral), skip the reduction of the definite integral and return the
       solution F(b) - F(a).
     """
     F += choose_constant(integral)
@@ -59,21 +59,21 @@ def solve_integral(integral, F):
         if x != find_variable(F):
             solution = substitute(F, x, ubnd) - substitute(F, x, lbnd)
         else:
-            solution = indef(F, lbnd, ubnd)
+            solution = int_def(F, lbnd, ubnd)
 
     return negate(solution, integral.negated)
 
 
-def match_solve_indef(node):
+def match_solve_definite(node):
     """
     [F(x)]_a^b  ->  F(b) - F(a)
     """
-    assert node.is_op(OP_INT_INDEF)
+    assert node.is_op(OP_INT_DEF)
 
-    return [P(node, solve_indef)]
+    return [P(node, solve_definite)]
 
 
-def solve_indef(root, args):
+def solve_definite(root, args):
     """
     [F(x)]_a^b  ->  F(b) - F(a)
     """
@@ -83,12 +83,12 @@ def solve_indef(root, args):
     return negate(substitute(Fx, x, b) - substitute(Fx, x, a), root.negated)
 
 
-def solve_indef_msg(root, args):  # pragma: nocover
-    return _('Solve indefinite integral {0} using substitution ' \
+def solve_definite_msg(root, args):  # pragma: nocover
+    return _('Solve definite integral {0} using substitution ' \
              'of `%s` with {0[2]} and {0[1]}.' % find_variable(root[0]))
 
 
-MESSAGES[solve_indef] = solve_indef_msg
+MESSAGES[solve_definite] = solve_definite_msg
 
 
 def match_integrate_variable_power(node):
@@ -363,11 +363,11 @@ def sum_rule_integral(root, args):
 MESSAGES[sum_rule_integral] = _('Apply the sum rule to {0}.')
 
 
-def match_remove_indef_constant(node):
+def match_remove_definite_constant(node):
     """
     [f(x) + c]_a^b  ->  [f(x)]_a^b
     """
-    assert node.is_op(OP_INT_INDEF)
+    assert node.is_op(OP_INT_DEF)
 
     if not node[0].is_op(OP_ADD):
         return []
@@ -376,10 +376,10 @@ def match_remove_indef_constant(node):
     x = find_variable(node[0])
     constants = [n for n in scope if not n.contains(x)]
 
-    return [P(node, remove_indef_constant, (scope, c)) for c in constants]
+    return [P(node, remove_definite_constant, (scope, c)) for c in constants]
 
 
-def remove_indef_constant(root, args):
+def remove_definite_constant(root, args):
     """
     [f(x) + c]_a^b  ->  [f(x)]_a^b
     """
@@ -388,8 +388,8 @@ def remove_indef_constant(root, args):
     Fx = scope.as_nary_node()
     a, b = root[1:]
 
-    return negate(indef(Fx, a, b), root.negated)
+    return negate(int_def(Fx, a, b), root.negated)
 
 
-MESSAGES[remove_indef_constant] = \
-        _('Remove constant {2} from indefinite integral.')
+MESSAGES[remove_definite_constant] = \
+        _('Remove constant {2} from definite integral.')

+ 4 - 4
tests/test_node.py

@@ -14,7 +14,7 @@
 # along with TRS.  If not, see <http://www.gnu.org/licenses/>.
 from src.node import ExpressionNode as N, ExpressionLeaf as L, Scope, \
         nary_node, get_scope, OP_ADD, infinity, absolute, sin, cos, tan, log, \
-        ln, der, integral, indef, eq
+        ln, der, integral, int_def, eq
 from tests.rulestestcase import RulesTestCase, tree
 
 
@@ -259,7 +259,7 @@ class TestNode(RulesTestCase):
         self.assertEqual(str(tree('int_(a-b)^(a+b) x ^ 2')),
                          'int_(a - b)^(a + b) x ^ 2 dx')
 
-    def test_construct_function_indef(self):
+    def test_construct_function_int_def(self):
         self.assertEqual(str(tree('[x ^ 2]_a^b')), '[x ^ 2]_a^b')
         self.assertEqual(str(tree('[x ^ 2]_(a-b)^(a+b)')),
                          '[x ^ 2]_(a - b)^(a + b)')
@@ -318,9 +318,9 @@ class TestNode(RulesTestCase):
         self.assertEqual(integral(x2, x, a, b), tree('int_a^b x^2 dx'))
         self.assertEqual(integral(x2, y, a, b), tree('int_a^b x^2 dy'))
 
-    def test_indef(self):
+    def test_int_def(self):
         x2, a, b, expect = tree('x ^ 2, a, b, [x ^ 2]_a^b')
-        self.assertEqual(indef(x2, a, b), expect)
+        self.assertEqual(int_def(x2, a, b), expect)
 
     def test_eq(self):
         x, a, b, expect = tree('x, a, b, x + a = b')

+ 8 - 8
tests/test_parser.py

@@ -15,7 +15,7 @@
 # along with TRS.  If not, see <http://www.gnu.org/licenses/>.
 from src.parser import Parser, find_possibilities
 from src.node import ExpressionNode as Node, ExpressionLeaf as Leaf, \
-        SPECIAL_TOKENS, sin, cos, der, log, ln, integral, indef, absolute, \
+        SPECIAL_TOKENS, sin, cos, der, log, ln, integral, int_def, absolute, \
         Scope
 from src.possibilities import Possibility as P
 from src.rules.numerics import add_numerics
@@ -178,15 +178,15 @@ class TestParser(RulesTestCase):
         self.assertEqual(tree('int_(-a)^b x dx'), integral(x, x, -a, b))
         self.assertEqual(tree('int_-a^b x^2 dx'), integral(x ** 2, x, -a, b))
 
-    def test_indefinite_integral(self):
+    def test_int_definite_integral(self):
         x2, a, b, oo, l2 = tree('x ^ 2, a, b, oo, 2')
 
-        self.assertEqual(tree('(x ^ 2)_a'), indef(x2, a, oo))
-        self.assertEqual(tree('(x ^ 2)_a^b'), indef(x2, a, b))
-        self.assertEqual(tree('(x ^ 2)_-a^b'), indef(x2, -a, b))
-        self.assertEqual(tree('(x ^ 2)_-a^-b'), indef(x2, -a, -b))
-        self.assertNotEqual(tree('(x ^ 2)_-2a^b'), indef(x2, -(l2 * a), b))
-        self.assertEqual(tree('(x ^ 2)_(-2a)^b'), indef(x2, -(l2 * a), b))
+        self.assertEqual(tree('(x ^ 2)_a'), int_def(x2, a, oo))
+        self.assertEqual(tree('(x ^ 2)_a^b'), int_def(x2, a, b))
+        self.assertEqual(tree('(x ^ 2)_-a^b'), int_def(x2, -a, b))
+        self.assertEqual(tree('(x ^ 2)_-a^-b'), int_def(x2, -a, -b))
+        self.assertNotEqual(tree('(x ^ 2)_-2a^b'), int_def(x2, -(l2 * a), b))
+        self.assertEqual(tree('(x ^ 2)_(-2a)^b'), int_def(x2, -(l2 * a), b))
 
     def test_absolute_value(self):
         x = tree('x')

+ 18 - 17
tests/test_rules_integrals.py

@@ -12,8 +12,8 @@
 #
 # You should have received a copy of the GNU Affero General Public License
 # along with TRS.  If not, see <http://www.gnu.org/licenses/>.
-from src.rules.integrals import indef, choose_constant, solve_integral, \
-        match_solve_indef, solve_indef, match_integrate_variable_power, \
+from src.rules.integrals import choose_constant, solve_integral, \
+        match_solve_definite, solve_definite, match_integrate_variable_power, \
         integrate_variable_root, integrate_variable_exponent, \
         match_constant_integral, constant_integral, single_variable_integral, \
         match_factor_out_constant, factor_out_integral_negation, \
@@ -21,8 +21,8 @@ from src.rules.integrals import indef, choose_constant, solve_integral, \
         extend_division_integral, match_function_integral, \
         logarithm_integral, sinus_integral, cosinus_integral, \
         match_sum_rule_integral, sum_rule_integral, \
-        match_remove_indef_constant, remove_indef_constant
-from src.node import Scope
+        match_remove_definite_constant, remove_definite_constant
+from src.node import Scope, int_def
 from src.possibilities import Possibility as P
 from tests.rulestestcase import RulesTestCase, tree
 
@@ -35,26 +35,27 @@ class TestRulesIntegrals(RulesTestCase):
         self.assertEqual(choose_constant(tree('int x ^ c')), a)
         self.assertEqual(choose_constant(tree('int a ^ c da')), b)
 
-    def test_match_solve_indef(self):
+    def test_match_solve_definite(self):
         root = tree('[x ^ 2]_a^b')
-        self.assertEqualPos(match_solve_indef(root), [P(root, solve_indef)])
+        self.assertEqualPos(match_solve_definite(root),
+                            [P(root, solve_definite)])
 
     def test_solve_integral(self):
         root, F, Fc = tree('int x ^ 2 dx, 1 / 3 x ^ 3, 1 / 3 x ^ 3 + C')
         self.assertEqual(solve_integral(root, F), Fc)
         x2, x, a, b = root = tree('int_a^b x ^ 2 dx')
-        self.assertEqual(solve_integral(root, F), indef(Fc, a, b))
+        self.assertEqual(solve_integral(root, F), int_def(Fc, a, b))
 
-    def test_solve_integral_skip_indef(self):
+    def test_solve_integral_skip_definite(self):
         root, x, C, l1 = tree('int_a^b y ^ x dy, x, C, 1')
         F = tree('1 / (x + 1)y ^ (x + 1)')
         y, a, b = root[1:4]
         Fx = lambda y: l1 / (x + 1) * y ** (x + 1) + C
         self.assertEqual(solve_integral(root, F), Fx(b) - Fx(a))
 
-    def test_solve_indef(self):
+    def test_solve_definite(self):
         root, expect = tree('[x ^ 2]_a^b, b ^ 2 - a ^ 2')
-        self.assertEqual(solve_indef(root, ()), expect)
+        self.assertEqual(solve_definite(root, ()), expect)
 
     def test_match_integrate_variable_power(self):
         root = tree('int x ^ n')
@@ -195,18 +196,18 @@ class TestRulesIntegrals(RulesTestCase):
         self.assertEqual(sum_rule_integral(root, (Scope(root[0]), h)),
                          tree('int 4x dx + int (2x + 3x) dx'))
 
-    def test_match_remove_indef_constant(self):
+    def test_match_remove_definite_constant(self):
         Fx, a, b = root = tree('[2x + C]_a^b')
-        self.assertEqualPos(match_remove_indef_constant(root),
-                [P(root, remove_indef_constant, (Scope(Fx), Fx[1]))])
+        self.assertEqualPos(match_remove_definite_constant(root),
+                [P(root, remove_definite_constant, (Scope(Fx), Fx[1]))])
 
         Fx, a, b = root = tree('[2x + x]_a^b')
-        self.assertEqualPos(match_remove_indef_constant(root), [])
+        self.assertEqualPos(match_remove_definite_constant(root), [])
 
         Fx, a, b = root = tree('[2x]_a^b')
-        self.assertEqualPos(match_remove_indef_constant(root), [])
+        self.assertEqualPos(match_remove_definite_constant(root), [])
 
-    def test_remove_indef_constant(self):
+    def test_remove_definite_constant(self):
         root, e = tree('[2x + C]_a^b, [2x]_a^b')
         Fx = root[0]
-        self.assertEqual(remove_indef_constant(root, (Scope(Fx), Fx[1])), e)
+        self.assertEqual(remove_definite_constant(root, (Scope(Fx), Fx[1])), e)