Commit b05101ae authored by Taddeus Kroes's avatar Taddeus Kroes

Started implementing integrals.

parent 0a006952
...@@ -31,23 +31,24 @@ OP_MOD = 7 ...@@ -31,23 +31,24 @@ OP_MOD = 7
# N-ary (functions) # N-ary (functions)
OP_INT = 8 OP_INT = 8
OP_COMMA = 9 OP_INT_INDEF = 9
OP_SQRT = 10 OP_COMMA = 10
OP_DER = 11 OP_SQRT = 11
OP_LOG = 12 OP_DER = 12
OP_LOG = 13
# Goniometry # Goniometry
OP_SIN = 13 OP_SIN = 14
OP_COS = 14 OP_COS = 15
OP_TAN = 15 OP_TAN = 16
OP_SOLVE = 16 OP_SOLVE = 17
OP_EQ = 17 OP_EQ = 18
OP_POSSIBILITIES = 18 OP_POSSIBILITIES = 19
OP_HINT = 19 OP_HINT = 20
OP_REWRITE_ALL = 20 OP_REWRITE_ALL = 21
OP_REWRITE = 21 OP_REWRITE = 22
# Special identifiers # Special identifiers
PI = 'pi' PI = 'pi'
...@@ -102,7 +103,7 @@ TOKEN_MAP = { ...@@ -102,7 +103,7 @@ TOKEN_MAP = {
OP_SIN: 'FUNCTION', OP_SIN: 'FUNCTION',
OP_COS: 'FUNCTION', OP_COS: 'FUNCTION',
OP_TAN: 'FUNCTION', OP_TAN: 'FUNCTION',
OP_INT: 'FUNCTION', OP_INT: 'INTEGRAL',
OP_DER: 'FUNCTION', OP_DER: 'FUNCTION',
OP_SOLVE: 'FUNCTION', OP_SOLVE: 'FUNCTION',
OP_LOG: 'FUNCTION', OP_LOG: 'FUNCTION',
......
...@@ -17,7 +17,7 @@ from graph_drawing.graph import generate_graph ...@@ -17,7 +17,7 @@ from graph_drawing.graph import generate_graph
from node import ExpressionNode as Node, ExpressionLeaf as Leaf, OP_MAP, \ from node import ExpressionNode as Node, ExpressionLeaf as Leaf, OP_MAP, \
OP_DER, TOKEN_MAP, TYPE_OPERATOR, OP_COMMA, OP_NEG, OP_MUL, OP_DIV, \ OP_DER, TOKEN_MAP, TYPE_OPERATOR, OP_COMMA, OP_NEG, OP_MUL, OP_DIV, \
OP_LOG, OP_ADD, Scope, E, DEFAULT_LOGARITHM_BASE, OP_VALUE_MAP, \ OP_LOG, OP_ADD, Scope, E, DEFAULT_LOGARITHM_BASE, OP_VALUE_MAP, \
SPECIAL_TOKENS SPECIAL_TOKENS, OP_INT, OP_INT_INDEF
from rules import RULES from rules import RULES
from strategy import pick_suggestion from strategy import pick_suggestion
from possibilities import filter_duplicates, apply_suggestion from possibilities import filter_duplicates, apply_suggestion
...@@ -41,6 +41,20 @@ def combine(op, op_type, *nodes): ...@@ -41,6 +41,20 @@ def combine(op, op_type, *nodes):
return res return res
def find_integration_variable(exp):
if not exp.is_op(OP_MUL):
return exp
scope = Scope(exp)
if len(scope) < 3 or scope[-2] != 'd' or not scope[-1].is_identifier():
return exp
scope.nodes = scope[:-2]
return scope.as_nary_node()
class Parser(BisonParser): class Parser(BisonParser):
""" """
Implements the calculator parser. Grammar rules are defined in the method Implements the calculator parser. Grammar rules are defined in the method
...@@ -48,9 +62,8 @@ class Parser(BisonParser): ...@@ -48,9 +62,8 @@ class Parser(BisonParser):
""" """
# Words to be ignored by preprocessor # Words to be ignored by preprocessor
words = zip(*filter(lambda (s, op): TOKEN_MAP[op] == 'FUNCTION', \ words = tuple(filter(lambda w: len(w) > 1, OP_MAP.iterkeys())) \
OP_MAP.iteritems()))[0] \ + ('raise', 'graph')+ tuple(SPECIAL_TOKENS)
+ ('raise', 'graph') + tuple(SPECIAL_TOKENS)
# Output directory of generated pybison files, including a trailing slash. # Output directory of generated pybison files, including a trailing slash.
buildDirectory = PYBISON_BUILD + '/' buildDirectory = PYBISON_BUILD + '/'
...@@ -62,7 +75,7 @@ class Parser(BisonParser): ...@@ -62,7 +75,7 @@ class Parser(BisonParser):
# of tokens of the lex script. # of tokens of the lex script.
tokens = ['NUMBER', 'IDENTIFIER', 'NEWLINE', 'QUIT', 'RAISE', 'GRAPH', tokens = ['NUMBER', 'IDENTIFIER', 'NEWLINE', 'QUIT', 'RAISE', 'GRAPH',
'LPAREN', 'RPAREN', 'FUNCTION', 'FUNCTION_LPAREN', 'LBRACKET', 'LPAREN', 'RPAREN', 'FUNCTION', 'FUNCTION_LPAREN', 'LBRACKET',
'RBRACKET', 'APOSTROPH', 'DERIVATIVE'] \ 'RBRACKET', 'APOSTROPH', 'DERIVATIVE', 'SUB'] \
+ filter(lambda t: t != 'FUNCTION', TOKEN_MAP.values()) + filter(lambda t: t != 'FUNCTION', TOKEN_MAP.values())
# ------------------------------ # ------------------------------
...@@ -75,7 +88,7 @@ class Parser(BisonParser): ...@@ -75,7 +88,7 @@ class Parser(BisonParser):
('right', ('FUNCTION', 'DERIVATIVE')), ('right', ('FUNCTION', 'DERIVATIVE')),
('left', ('EQ', )), ('left', ('EQ', )),
('left', ('NEG', )), ('left', ('NEG', )),
('right', ('POW', )), ('right', ('POW', 'SUB')),
('right', ('FUNCTION_LPAREN', )), ('right', ('FUNCTION_LPAREN', )),
) )
...@@ -377,6 +390,7 @@ class Parser(BisonParser): ...@@ -377,6 +390,7 @@ class Parser(BisonParser):
| FUNCTION exp | FUNCTION exp
| DERIVATIVE exp | DERIVATIVE exp
| bracket_derivative | bracket_derivative
| integral
""" """
if option == 0: # rule: NEG exp if option == 0: # rule: NEG exp
...@@ -418,7 +432,7 @@ class Parser(BisonParser): ...@@ -418,7 +432,7 @@ class Parser(BisonParser):
# DERIVATIVE looks like 'd/d*x*' -> extract the 'x' # DERIVATIVE looks like 'd/d*x*' -> extract the 'x'
return Node(OP_DER, values[1], Leaf(values[0][-2])) return Node(OP_DER, values[1], Leaf(values[0][-2]))
if option == 4: # rule: bracket_derivative if option in (4, 5): # rule: bracket_derivative | integral
return values[0] return values[0]
raise BisonSyntaxError('Unsupported option %d in target "%s".' raise BisonSyntaxError('Unsupported option %d in target "%s".'
...@@ -439,6 +453,37 @@ class Parser(BisonParser): ...@@ -439,6 +453,37 @@ class Parser(BisonParser):
raise BisonSyntaxError('Unsupported option %d in target "%s".' raise BisonSyntaxError('Unsupported option %d in target "%s".'
% (option, target)) # pragma: nocover % (option, target)) # pragma: nocover
def on_integral(self, target, option, names, values):
"""
integral : INTEGRAL exp
"""
#| INTEGRAL SUB exp exp
#| LBRACKET exp RBRACKET SUB exp exp
if option == 0: # rule: INTEGRAL exp
fx, x = find_integration_variable(values[1])
return N(OP_INT, fx, x)
if option == 1: # rule: INTEGRAL SUB exp exp
if not values[2].is_power(): # pragma: nocover
raise BisonSyntaxError('No upper bound specified in "%s".'
% values[2])
lbnd, ubnd = values[2]
fx, x = find_integration_variable(values[3])
return N(OP_INT, fx, x, lbnd, ubnd)
if option == 2: # rule: LBRACKET exp RBRACKET SUB exp POWER exp
exp = values[1]
fx, x = find_integration_variable(values[1])
return N(OP_INT_INDEF, fx, x, values[4], values[6])
raise BisonSyntaxError('Unsupported option %d in target "%s".'
% (option, target)) # pragma: nocover
def on_binary(self, target, option, names, values): def on_binary(self, target, option, names, values):
""" """
binary : exp PLUS exp binary : exp PLUS exp
...@@ -541,6 +586,7 @@ class Parser(BisonParser): ...@@ -541,6 +586,7 @@ class Parser(BisonParser):
d[ ]*"/"[ ]*"d*"[a-z]"*" { returntoken(DERIVATIVE); } d[ ]*"/"[ ]*"d*"[a-z]"*" { returntoken(DERIVATIVE); }
[0-9]+"."?[0-9]* { returntoken(NUMBER); } [0-9]+"."?[0-9]* { returntoken(NUMBER); }
[a-zA-Z] { returntoken(IDENTIFIER); } [a-zA-Z] { returntoken(IDENTIFIER); }
"_" { returntoken(SUB); }
"(" { returntoken(LPAREN); } "(" { returntoken(LPAREN); }
")" { returntoken(RPAREN); } ")" { returntoken(RPAREN); }
"[" { returntoken(LBRACKET); } "[" { returntoken(LBRACKET); }
......
...@@ -37,6 +37,7 @@ def choose_constant(integral): ...@@ -37,6 +37,7 @@ def choose_constant(integral):
""" """
Choose a constant to be added to the antiderivative. Choose a constant to be added to the antiderivative.
""" """
# TODO: comments
occupied = find_variables(integral) occupied = find_variables(integral)
c = 'c' c = 'c'
i = 96 i = 96
......
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