Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
T
trs
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Taddeüs Kroes
trs
Commits
42662f45
Commit
42662f45
authored
Apr 09, 2012
by
Taddeus Kroes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Changed negation precedence to that of subtraction and modified rules+tests correspondingly.
parent
a9858f37
Changes
25
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
371 additions
and
331 deletions
+371
-331
external/graph_drawing
external/graph_drawing
+1
-1
src/node.py
src/node.py
+20
-2
src/parser.py
src/parser.py
+15
-29
src/rules/factors.py
src/rules/factors.py
+15
-15
src/rules/fractions.py
src/rules/fractions.py
+5
-1
src/rules/groups.py
src/rules/groups.py
+12
-4
src/rules/lineq.py
src/rules/lineq.py
+1
-1
src/rules/negation.py
src/rules/negation.py
+52
-54
src/rules/numerics.py
src/rules/numerics.py
+13
-28
src/strategy.py
src/strategy.py
+3
-3
tests/parser.py
tests/parser.py
+10
-5
tests/test_b1_ch08.py
tests/test_b1_ch08.py
+4
-4
tests/test_b1_ch10.py
tests/test_b1_ch10.py
+4
-4
tests/test_leiden_oefenopgave.py
tests/test_leiden_oefenopgave.py
+37
-31
tests/test_leiden_oefenopgave_v12.py
tests/test_leiden_oefenopgave_v12.py
+46
-39
tests/test_node.py
tests/test_node.py
+11
-1
tests/test_parser.py
tests/test_parser.py
+0
-8
tests/test_rewrite.py
tests/test_rewrite.py
+16
-4
tests/test_rules_factors.py
tests/test_rules_factors.py
+14
-17
tests/test_rules_fractions.py
tests/test_rules_fractions.py
+3
-4
tests/test_rules_groups.py
tests/test_rules_groups.py
+7
-1
tests/test_rules_integrals.py
tests/test_rules_integrals.py
+1
-1
tests/test_rules_lineq.py
tests/test_rules_lineq.py
+10
-7
tests/test_rules_negation.py
tests/test_rules_negation.py
+47
-30
tests/test_rules_numerics.py
tests/test_rules_numerics.py
+24
-37
No files found.
graph_drawing
@
ade1a950
Subproject commit
70714ec0339bb043dcd92a9f233d83347ac0ae
95
Subproject commit
ade1a95046e5539a4f11535892061e05b7c23b
95
src/node.py
View file @
42662f45
...
...
@@ -359,7 +359,7 @@ class ExpressionNode(Node, ExpressionBase):
self.nodes[self.nodes.index(old_child)] = new_child
def graph(self): # pragma: nocover
return generate_graph(
self
)
return generate_graph(
negation_to_node(self)
)
def extract_polynome_properties(self):
"""
...
...
@@ -602,7 +602,7 @@ def get_scope(node):
scope = []
for child in node:
if child.is_op(node.op):
if child.is_op(node.op)
and not child.negated
:
scope += get_scope(child)
else:
scope.append(child)
...
...
@@ -698,3 +698,21 @@ def eq(left, right):
Create an equality operator node.
"""
return ExpressionNode(OP_EQ, left, right)
def negation_to_node(node):
"""
Recursively replace negation flags inside a node by explicit unary negation
nodes.
"""
if node.negated:
negations = node.negated
node = negate(node, 0)
for i in range(negations):
node = ExpressionNode('
-
', node)
if node.is_leaf:
return node
return ExpressionNode(node.op, *map(negation_to_node, node))
src/parser.py
View file @
42662f45
...
...
@@ -18,7 +18,7 @@ from node import ExpressionBase, ExpressionNode as Node, \
ExpressionLeaf
as
Leaf
,
OP_MAP
,
OP_DER
,
TOKEN_MAP
,
TYPE_OPERATOR
,
\
OP_COMMA
,
OP_NEG
,
OP_MUL
,
OP_DIV
,
OP_POW
,
OP_LOG
,
OP_ADD
,
Scope
,
E
,
\
DEFAULT_LOGARITHM_BASE
,
OP_VALUE_MAP
,
SPECIAL_TOKENS
,
OP_INT
,
\
OP_INT_INDEF
,
OP_ABS
OP_INT_INDEF
,
OP_ABS
,
OP_NEG
,
negation_to_node
from
rules
import
RULES
from
rules.utils
import
find_variable
from
strategy
import
pick_suggestion
...
...
@@ -90,10 +90,10 @@ class Parser(BisonParser):
(
'left'
,
(
'OR'
,
)),
(
'left'
,
(
'AND'
,
)),
(
'left'
,
(
'EQ'
,
)),
(
'left'
,
(
'MINUS'
,
'PLUS'
)),
(
'left'
,
(
'MINUS'
,
'PLUS'
,
'NEG'
)),
(
'left'
,
(
'TIMES'
,
'DIVIDE'
)),
(
'right'
,
(
'FUNCTION'
,
)),
(
'left'
,
(
'NEG'
,
)),
#
('left', ('NEG', )),
(
'right'
,
(
'POW'
,
)),
(
'left'
,
(
'SUB'
,
)),
(
'right'
,
(
'FUNCTION_LPAREN'
,
)),
...
...
@@ -245,13 +245,12 @@ class Parser(BisonParser):
if not retval.negated and retval.type != TYPE_OPERATOR:
return retval
if retval.type == TYPE_OPERATOR and retval.op in RULES:
handlers = RULES[retval.op]
else:
handlers = []
if retval.negated:
handlers = RULES[OP_NEG]
elif retval.type == TYPE_OPERATOR and retval.op in RULES:
handlers = RULES[retval.op]
else:
return retval
for handler in handlers:
possibilities = handler(retval)
...
...
@@ -360,7 +359,7 @@ class Parser(BisonParser):
"""
if
option
==
0
:
print
generate_graph
(
values
[
1
]
)
print
generate_graph
(
negation_to_node
(
values
[
1
])
)
return
values
[
1
]
raise
BisonSyntaxError
(
'Unsupported option %d in target "%s".'
...
...
@@ -396,7 +395,7 @@ class Parser(BisonParser):
def
on_unary
(
self
,
target
,
option
,
names
,
values
):
"""
unary : MINUS exp
%prec NEG
unary : MINUS exp
| FUNCTION_LPAREN exp RPAREN
| FUNCTION exp
| DERIVATIVE exp
...
...
@@ -408,16 +407,9 @@ class Parser(BisonParser):
"""
if
option
==
0
:
# rule: NEG exp
node
=
values
[
1
]
# Add negation to the left-most child
if
node
.
is_leaf
or
(
node
.
op
!=
OP_MUL
and
node
.
op
!=
OP_DIV
):
node
.
negated
+=
1
else
:
child
=
Scope
(
node
)[
0
]
child
.
negated
+=
1
values
[
1
].
negated
+=
1
return
node
return
values
[
1
]
if
option
in
(
1
,
2
):
# rule: FUNCTION_LPAREN exp RPAREN | FUNCTION exp
op
=
values
[
0
].
split
(
' '
,
1
)[
0
]
...
...
@@ -542,19 +534,13 @@ class Parser(BisonParser):
return
Node
(
values
[
1
],
values
[
0
],
values
[
2
])
if
option
==
6
:
# rule: exp MINUS exp
node
=
values
[
2
]
# Add negation to the left-most child
if
node
.
is_leaf
or
(
node
.
op
!=
OP_MUL
and
node
.
op
!=
OP_DIV
):
node
.
negated
+=
1
else
:
node
=
Scope
(
node
)[
0
]
node
.
negated
+=
1
right
=
values
[
2
]
right
.
negated
+=
1
# Explicit call the hook handler on the created unary negation.
self
.
hook_handler
(
'
binary'
,
3
,
names
,
values
,
node
)
self
.
hook_handler
(
'
unary'
,
0
,
names
,
values
,
right
)
return
Node
(
OP_ADD
,
values
[
0
],
values
[
2
]
)
return
Node
(
OP_ADD
,
values
[
0
],
right
)
if
option
==
7
:
# rule: power
return
Node
(
OP_POW
,
*
values
[
0
])
...
...
src/rules/factors.py
View file @
42662f45
...
...
@@ -7,17 +7,18 @@ from ..translate import _
def
match_expand
(
node
):
"""
a
* (b + c) ->
ab + ac
(b + c)
* a ->
ab + ac
(a + b)
* (c + d) ->
ac + ad + bc + bd
a
(b + c) ->
ab + ac
(b + c)
a ->
ab + ac
(a + b)
(c + d) ->
ac + ad + bc + bd
"""
assert
node
.
is_op
(
OP_MUL
)
p
=
[]
leaves
=
[]
additions
=
[]
scope
=
Scope
(
node
)
for
n
in
Scope
(
node
)
:
for
n
in
scope
:
if
n
.
is_leaf
:
leaves
.
append
(
n
)
elif
n
.
op
==
OP_ADD
:
...
...
@@ -27,11 +28,11 @@ def match_expand(node):
additions
.
append
(
n
)
for
args
in
product
(
leaves
,
additions
):
p
.
append
(
P
(
node
,
expand_single
,
args
))
for
l
,
a
in
product
(
leaves
,
additions
):
p
.
append
(
P
(
node
,
expand_single
,
(
scope
,
l
,
a
)
))
for
a
rgs
in
combinations
(
additions
,
2
):
p
.
append
(
P
(
node
,
expand_double
,
args
))
for
a
0
,
a1
in
combinations
(
additions
,
2
):
p
.
append
(
P
(
node
,
expand_double
,
(
scope
,
a0
,
a1
)
))
return
p
...
...
@@ -41,12 +42,11 @@ def expand_single(root, args):
Combine a leaf (a) multiplied with an addition of two expressions
(b + c) to an addition of two multiplications.
a
* (b + c) ->
ab + ac
(b + c)
* a ->
ab + ac
a
(b + c) ->
ab + ac
(b + c)
a ->
ab + ac
"""
a
,
bc
=
args
scope
,
a
,
bc
=
args
b
,
c
=
bc
scope
=
Scope
(
root
)
# Replace 'a' with the new expression
scope
.
replace
(
a
,
a
*
b
+
a
*
c
)
...
...
@@ -64,10 +64,10 @@ def expand_double(root, args):
"""
Rewrite two multiplied additions to an addition of four multiplications.
(a + b)
* (c + d) ->
ac + ad + bc + bd
(a + b)
(c + d) ->
ac + ad + bc + bd
"""
(
a
,
b
),
(
c
,
d
)
=
ab
,
cd
=
args
scope
=
Scope
(
root
)
scope
,
ab
,
cd
=
args
(
a
,
b
),
(
c
,
d
)
=
ab
,
cd
# Replace 'a + b' with the new expression
scope
.
replace
(
ab
,
a
*
c
+
a
*
d
+
b
*
c
+
b
*
d
)
...
...
src/rules/fractions.py
View file @
42662f45
...
...
@@ -126,7 +126,8 @@ def equalize_denominators(root, args):
else
:
nom
=
L
(
mult
)
*
n
scope
.
replace
(
fraction
,
negate
(
nom
/
L
(
d
.
value
*
mult
),
n
.
negated
))
scope
.
replace
(
fraction
,
negate
(
nom
/
L
(
d
.
value
*
mult
),
fraction
.
negated
))
return
scope
.
as_nary_node
()
...
...
@@ -338,6 +339,9 @@ def match_equal_fraction_parts(node):
n_scope
,
d_scope
=
fraction_scopes
(
node
)
p
=
[]
if
len
(
n_scope
)
==
1
and
len
(
d_scope
)
==
1
:
return
p
# Look for matching parts in scopes
for
i
,
n
in
enumerate
(
n_scope
):
for
j
,
d
in
enumerate
(
d_scope
):
...
...
src/rules/groups.py
View file @
42662f45
...
...
@@ -26,7 +26,7 @@ def match_combine_groups(node):
for
n
in
scope
:
if
not
n
.
is_numeric
():
groups
.
append
((
Leaf
(
1
),
n
,
n
))
groups
.
append
((
Leaf
(
1
),
n
,
n
,
True
))
# Each number multiplication yields a group, multiple occurences of
# the same group can be replaced by a single one
...
...
@@ -35,17 +35,25 @@ def match_combine_groups(node):
l
=
len
(
n_scope
)
for
i
,
sub_node
in
enumerate
(
n_scope
):
# TODO: use utitlity function evals_to_numeric
#if evals_to_numeric(sub_node):
if
sub_node
.
is_numeric
():
others
=
[
n_scope
[
j
]
for
j
in
range
(
i
)
+
range
(
i
+
1
,
l
)]
if
len
(
others
)
==
1
:
g
=
others
[
0
]
else
:
g
=
nary_node
(
'*'
,
others
)
g
=
nary_node
(
OP_MUL
,
others
)
groups
.
append
((
sub_node
,
g
,
n
))
groups
.
append
((
sub_node
,
g
,
n
,
False
))
for
(
c0
,
g0
,
n0
,
root0
),
(
c1
,
g1
,
n1
,
root1
)
in
combinations
(
groups
,
2
):
if
not
root0
:
c0
=
c0
.
negate
(
n0
.
negated
)
if
not
root1
:
c1
=
c1
.
negate
(
n1
.
negated
)
for
(
c0
,
g0
,
n0
),
(
c1
,
g1
,
n1
)
in
combinations
(
groups
,
2
):
if
g0
.
equals
(
g1
):
p
.
append
(
P
(
node
,
combine_groups
,
(
scope
,
c0
,
g0
,
n0
,
c1
,
g1
,
n1
)))
elif
g0
.
equals
(
g1
,
ignore_negation
=
True
):
...
...
src/rules/lineq.py
View file @
42662f45
...
...
@@ -23,7 +23,7 @@ def match_move_term(node):
# Multiplication
x / a = b -> x / a * a = b * a # =>* x = a * b
a / x = b -> a / x * x = b * x # =>* x = a / b
-x = b -> -x * -1 = b * -1 # =>* x = -b
-x = b -> -x * -1 = b * -1
# =>* x = -b
"""
assert
node
.
is_op
(
OP_EQ
)
...
...
src/rules/negation.py
View file @
42662f45
...
...
@@ -6,9 +6,10 @@ from ..translate import _
def
match_negated_factor
(
node
):
"""
This rule assures that negations in the scope of a multiplication are
brought to the m
ost left node in the multiplication's scope
.
brought to the m
ultiplication itself
.
Example:
Examples:
(-a)b -> -ab
a * -b -> -ab
"""
assert
node
.
is_op
(
OP_MUL
)
...
...
@@ -16,10 +17,7 @@ def match_negated_factor(node):
p
=
[]
scope
=
Scope
(
node
)
# FIXME: The negation that is brought outside is assigned to the first
# element in the scope during the next parsing step:
# -ab -> -(ab), but -(ab) is printed as -ab
for
factor
in
scope
[
1
:]:
for
factor
in
scope
:
if
factor
.
negated
:
p
.
append
(
P
(
node
,
negated_factor
,
(
scope
,
factor
)))
...
...
@@ -28,13 +26,13 @@ def match_negated_factor(node):
def
negated_factor
(
root
,
args
):
"""
(-a)b -> -ab
a * -b -> -ab
"""
scope
,
factor
=
args
scope
[
0
]
=
-
scope
[
0
]
scope
.
replace
(
factor
,
+
factor
)
return
scope
.
as_nary_node
()
return
-
scope
.
as_nary_node
()
MESSAGES
[
negated_factor
]
=
\
...
...
@@ -44,27 +42,33 @@ MESSAGES[negated_factor] = \
def
match_negate_polynome
(
node
):
"""
--a -> a
----a -> --a
-(a + b) -> -a - b
-0 -> 0
"""
#print 'match_negate_polynome:', node, node.negated
assert
node
.
negated
,
str
(
node
.
negated
)
+
'; '
+
str
(
node
)
p
=
[]
if
no
de
.
negated
==
2
:
# --a
p
.
append
(
P
(
node
,
double_negation
,
()
))
if
no
t
(
node
.
negated
&
1
)
:
# --a
, ----a
p
.
append
(
P
(
node
,
double_negation
))
if
node
.
is_op
(
OP_ADD
):
if
node
==
0
or
node
==
0.0
:
# -0
p
.
append
(
P
(
node
,
negated_zero
))
elif
node
.
is_op
(
OP_ADD
):
# -(a + b) -> -a - b
p
.
append
(
P
(
node
,
negate_polynome
,
()
))
p
.
append
(
P
(
node
,
negate_polynome
))
return
p
def
double_negation
(
root
,
args
):
"""
--a -> a
--a -> a
----a -> --a
...
"""
return
root
.
reduce_negation
(
2
)
...
...
@@ -72,6 +76,16 @@ def double_negation(root, args):
MESSAGES
[
double_negation
]
=
_
(
'Remove double negation in {0}.'
)
def
negated_zero
(
root
,
args
):
"""
-0 -> 0
"""
return
root
.
reduce_negation
()
MESSAGES
[
negated_zero
]
=
_
(
'Remove negation from zero.'
)
def
negate_polynome
(
root
,
args
):
"""
-(a + b) -> -a - b
...
...
@@ -88,65 +102,49 @@ def negate_polynome(root, args):
MESSAGES
[
negate_polynome
]
=
_
(
'Apply negation to the polynome {0}.'
)
#def negate_group(root, args):
# """
# -(a * -3c) -> a * 3c
# -(a * ... * -b) -> ab
# """
# node, scope = args
#
# for i, n in enumerate(scope):
# if n.negated:
# scope[i] = n.reduce_negation()
#
# return nary_node('*', scope).reduce_negation()
#
#
#MESSAGES[negate_polynome] = _('Apply negation to the subexpression {1[0]}.')
def
match_negated_division
(
node
):
"""
-a / -b -> a / b
(-a) / b -> -a / b
a / (-b) -> -a / b
Note that:
(-a) / (-b) -> -a / (-b) -> --a / b -> a / b
"""
assert
node
.
is_op
(
OP_DIV
)
a
,
b
=
node
p
=
[]
if
a
.
negated
and
b
.
negated
:
return
[
P
(
node
,
double_negated_division
,
())]
elif
b
.
negated
:
return
[
P
(
node
,
single_negated_division
,
(
a
,
+
b
))]
if
a
.
negated
:
p
.
append
(
P
(
node
,
negated_nominator
))
return
[]
if
b
.
negated
:
p
.
append
(
P
(
node
,
negated_denominator
))
return
p
def
single_negated_division
(
root
,
args
):
def
negated_nominator
(
root
,
args
):
"""
a / -
b -> -a / b
(-a) /
b -> -a / b
"""
a
,
b
=
args
# FIXME: "-a/b" results in "-(a/b)", which will cause a loop.
a
,
b
=
root
return
-
a
/
b
return
-
(
+
a
/
b
).
negate
(
root
.
negated
)
MESSAGES
[
single_negated_division
]
=
\
_
(
'Bring n
egation outside of the division: -{1} / {2}
.'
)
MESSAGES
[
negated_nominator
]
=
\
_
(
'Bring n
ominator negation in {0} outside to the fraction itself
.'
)
def
double_negated_division
(
root
,
args
):
def
negated_denominator
(
root
,
args
):
"""
-a / -b ->
a / b
a / (-b) -> -
a / b
"""
a
,
b
=
root
return
+
a
/
+
b
MESSAGES
[
double_negated_division
]
=
\
_
(
'Eliminate top and bottom negation in {0}.'
)
return
-
(
a
/
+
b
).
negate
(
root
.
negated
)
# TODO: negated multiplication: -a * -b = ab
MESSAGES
[
negated_denominator
]
=
\
_
(
'Bring denominator negation in {0} outside to the fraction itself.'
)
src/rules/numerics.py
View file @
42662f45
...
...
@@ -99,6 +99,10 @@ def match_divide_numerics(node):
assert
node
.
is_op
(
OP_DIV
)
n
,
d
=
node
if
n
.
negated
or
d
.
negated
:
return
[]
nv
,
dv
=
n
.
value
,
d
.
value
if
n
.
is_int
()
and
d
.
is_int
():
...
...
@@ -107,20 +111,18 @@ def match_divide_numerics(node):
if
not
mod
:
# 6 / 2 -> 3
# 3 / 2 -> 3 / 2
return
[
P
(
node
,
divide_numerics
,
(
nv
,
dv
,
n
.
negated
+
d
.
negated
)
)]
return
[
P
(
node
,
divide_numerics
)]
gcd
=
greatest_common_divisor
(
nv
,
dv
)
if
1
<
gcd
<=
nv
:
# 2 / 4 -> 1 / 2
# TODO: Test with negations!
return
[
P
(
node
,
reduce_fraction_constants
,
(
gcd
,))]
if
nv
>
dv
:
# 4 / 3 -> 1 + 1 / 3
# TODO: Test with negations!
return
[
P
(
node
,
fraction_to_int_fraction
,
((
nv
-
mod
)
/
dv
,
mod
,
dv
))]
#if nv > dv:
# # 4 / 3 -> 1 + 1 / 3
# return [P(node, fraction_to_int_fraction,
# ((nv - mod) / dv, mod, dv))]
elif
n
.
is_numeric
()
and
d
.
is_numeric
():
if
d
==
1.0
:
# 3 / 1.0 -> 3
...
...
@@ -129,7 +131,7 @@ def match_divide_numerics(node):
# 3.0 / 2 -> 1.5
# 3 / 2.0 -> 1.5
# 3.0 / 2.0 -> 1.5
return
[
P
(
node
,
divide_numerics
,
(
nv
,
dv
,
n
.
negated
+
d
.
negated
)
)]
return
[
P
(
node
,
divide_numerics
)]
return
[]
...
...
@@ -145,9 +147,9 @@ def divide_numerics(root, args):
3.0 / 2.0 -> 1.5
3 / 1.0 -> 3
"""
n
,
d
,
negated
=
args
n
,
d
=
root
return
Leaf
(
n
/
d
).
negate
(
negated
)
return
Leaf
(
n
.
value
/
d
.
value
).
negate
(
root
.
negated
)
MESSAGES
[
divide_numerics
]
=
_
(
'Divide constant {1} by constant {2}.'
)
...
...
@@ -164,29 +166,12 @@ def reduce_fraction_constants(root, args):
gcd
=
args
[
0
]
a
,
b
=
root
return
Leaf
(
a
.
value
/
gcd
).
negate
(
a
.
negated
)
\
/
Leaf
(
b
.
value
/
gcd
).
negate
(
b
.
negated
)
return
Leaf
(
a
.
value
/
gcd
)
/
Leaf
(
b
.
value
/
gcd
)
MESSAGES
[
reduce_fraction_constants
]
=
_
(
'Simplify fraction {0}.'
)
def
fraction_to_int_fraction
(
root
,
args
):
"""
Combine two divided integer into an integer with a fraction.
Examples:
4 / 3 -> 1 + 1 / 3
"""
integer
,
nominator
,
denominator
=
map
(
Leaf
,
args
)
return
integer
+
nominator
/
denominator
MESSAGES
[
fraction_to_int_fraction
]
=
_
(
'Expand fraction with nominator greater'
' than denominator {0} to an integer plus a fraction.'
)
def
match_multiply_zero
(
node
):
"""
a * 0 -> 0
...
...
src/strategy.py
View file @
42662f45
from
rules.sort
import
move_constant
from
rules.numerics
import
reduce_fraction_constants
,
fraction_to_int_fraction
from
rules.numerics
import
reduce_fraction_constants
from
rules.logarithmic
import
factor_in_exponent_multiplicant
...
...
@@ -9,8 +9,8 @@ def pick_suggestion(possibilities):
# TODO: pick the best suggestion.
for
suggestion
,
p
in
enumerate
(
possibilities
+
[
None
]):
if
p
and
p
.
handler
not
in
[
move_constant
,
fraction_to_int_fraction
,
reduce_fraction_constants
,
factor_in_exponent_multiplicant
]:
if
p
and
p
.
handler
not
in
[
move_constant
,
reduce_fraction_constants
,
factor_in_exponent_multiplicant
]:
break
if
not
p
:
...
...
tests/parser.py
View file @
42662f45
...
...
@@ -2,6 +2,11 @@ import sys
from
external.graph_drawing.graph
import
generate_graph
from
external.graph_drawing.line
import
generate_line
from
src.node
import
negation_to_node
def
create_graph
(
node
):
return
generate_graph
(
negation_to_node
(
node
))
class
ParserWrapper
(
object
):
...
...
@@ -90,9 +95,9 @@ def run_expressions(base_class, expressions, fail=True, silent=False,
if
not
silent
and
hasattr
(
res
,
'nodes'
):
print
>>
sys
.
stderr
,
'result graph:'
print
>>
sys
.
stderr
,
gener
ate_graph
(
res
)
print
>>
sys
.
stderr
,
cre
ate_graph
(
res
)
print
>>
sys
.
stderr
,
'expected graph:'
print
>>
sys
.
stderr
,
gener
ate_graph
(
out
)
print
>>
sys
.
stderr
,
cre
ate_graph
(
out
)
if
fail
:
raise
...
...
@@ -114,16 +119,16 @@ def apply_expressions(base_class, expressions, fail=True, silent=False,
if
not
silent
and
hasattr
(
res
,
'nodes'
):
print
>>
sys
.
stderr
,
'result graph:'
print
>>
sys
.
stderr
,
gener
ate_graph
(
res
)
print
>>
sys
.
stderr
,
cre
ate_graph
(
res
)
print
>>
sys
.
stderr
,
'expected graph:'
print
>>
sys
.
stderr
,
gener
ate_graph
(
out
)
print
>>
sys
.
stderr
,
cre
ate_graph
(
out
)
if
fail
:
raise
def
graph
(
parser
,
*
exp
,
**
kwargs
):
return
gener
ate_graph
(
ParserWrapper
(
parser
,
**
kwargs
).
run
(
exp
))
return
cre
ate_graph
(
ParserWrapper
(
parser
,
**
kwargs
).
run
(
exp
))
def
line
(
parser
,
*
exp
,
**
kwargs
):
...
...
tests/test_b1_ch08.py
View file @
42662f45
...
...
@@ -10,10 +10,10 @@ class TestB1Ch08(unittest.TestCase):
def
test_diagnostic_test_parser
(
self
):
run_expressions
(
Parser
,
[
(
'6*5^2'
,
L
(
6
)
*
L
(
5
)
**
2
),
(
'-5*(-3)^2'
,
(
-
L
(
5
))
*
(
-
L
(
3
))
**
2
),
(
'7p-3p'
,
L
(
7
)
*
'p'
+
(
-
L
(
3
)
*
'p'
)),
(
'-5a*-6'
,
(
-
L
(
5
))
*
'a'
*
(
-
L
(
6
))),
(
'3a-8--5-2a'
,
L
(
3
)
*
'a'
+
-
L
(
8
)
+
(
--
L
(
5
))
+
(
-
L
(
2
)
*
'a'
)),
(
'-5*(-3)^2'
,
-
(
L
(
5
)
*
(
-
L
(
3
))
**
2
)
),
(
'7p-3p'
,
L
(
7
)
*
'p'
+
-
(
L
(
3
)
*
'p'
)),
(
'-5a*-6'
,
-
(
L
(
5
)
*
'a'
*
-
L
(
6
))),
(
'3a-8--5-2a'
,
L
(
3
)
*
'a'
+
-
L
(
8
)
+
--
(
L
(
5
))
+
-
(
L
(
2
)
*
'a'
)),
])
def
test_diagnostic_test_application
(
self
):
...
...
tests/test_b1_ch10.py
View file @
42662f45
...
...
@@ -9,12 +9,12 @@ class TestB1Ch10(unittest.TestCase):
def
test_diagnostic_test
(
self
):
run_expressions
(
Parser
,
[
(
'5(a-2b)'
,
L
(
5
)
*
(
L
(
'a'
)
+
(
-
L
(
2
)
*
'b'
))),
(
'5(a-2b)'
,
L
(
5
)
*
(
L
(
'a'
)
+
-
(
L
(
2
)
*
'b'
))),
(
'-(3a+6b)'
,
-
(
L
(
3
)
*
L
(
'a'
)
+
L
(
6
)
*
'b'
)),
(
'18-(a-12)'
,
L
(
18
)
+
-
(
L
(
'a'
)
+
-
L
(
12
))),
(
'-p-q+5(p-q)-3q-2(p-q)'
,
-
L
(
'p'
)
+
-
L
(
'q'
)
+
L
(
5
)
*
(
L
(
'p'
)
+
-
L
(
'q'
))
+
(
-
L
(
3
)
*
'q'
)
\
+
(
-
L
(
2
)
*
(
L
(
'p'
)
+
-
L
(
'q'
)))
-
L
(
'p'
)
+
-
L
(
'q'
)
+
L
(
5
)
*
(
L
(
'p'
)
+
-
L
(
'q'
))
+
-
(
L
(
3
)
*
'q'
)
\
+
-
(
L
(
2
)
*
(
L
(
'p'
)
+
-
L
(
'q'
)))
),
(
'(2+3/7)^4'
,
N
(
'^'
,
N
(
'+'
,
L
(
2
),
N
(
'/'
,
L
(
3
),
L
(
7
))),
L
(
4
))
...
...
@@ -28,7 +28,7 @@ class TestB1Ch10(unittest.TestCase):
)
),
(
'-x3*-2x5'
,
-
(
L
(
'x'
)
**
L
(
3
)
)
*
-
L
(
2
)
*
L
(
'x'
)
**
L
(
5
)
-
(
L
(
'x'
)
**
L
(
3
)
*
-
(
L
(
2
)
*
L
(
'x'
)
**
L
(
5
))
)
),
(
'(7x2y3)^2/(7x2y3)'
,
N
(
'/'
,
...
...
tests/test_leiden_oefenopgave.py
View file @
42662f45
...
...
@@ -3,15 +3,16 @@ from tests.rulestestcase import RulesTestCase as TestCase, rewrite
class
TestLeidenOefenopgave
(
TestCase
):
def
test_1_1
(
self
):
for
chain
in
[[
'-5(x2 - 3x + 6)'
,
'-5(x ^ 2 - 3x) - 5 * 6'
,
'-5x ^ 2 - 5 * -3x - 5 * 6'
,
'-5x ^ 2 - -15x - 5 * 6'
,
'-5x ^ 2 + 15x - 5 * 6'
,
'-5x ^ 2 + 15x - 30'
,
],
]:
self
.
assertRewrite
(
chain
)
self
.
assertRewrite
([
'-5(x2 - 3x + 6)'
,
'-(5(x ^ 2 - 3x) + 5 * 6)'
,
'-(5x ^ 2 + 5(-3x) + 5 * 6)'
,
'-(5x ^ 2 - 5 * 3x + 5 * 6)'
,
'-(5x ^ 2 - 15x + 5 * 6)'
,
'-(5x ^ 2 - 15x + 30)'
,
'-5x ^ 2 - -15x - 30'
,
'-5x ^ 2 + 15x - 30'
,
])
return
for
exp
,
solution
in
[
...
...
@@ -70,16 +71,18 @@ class TestLeidenOefenopgave(TestCase):
def
test_1_4
(
self
):
# (x-1)^2 -> x^2 - 2x + 1
self
.
assertRewrite
([
'(x-1)^2'
,
'(x - 1)(x - 1)'
,
'xx + x * -1 - 1x - 1 * -1'
,
'x ^ (1 + 1) + x * -1 - 1x - 1 * -1'
,
'x ^ 2 + x * -1 - 1x - 1 * -1'
,
'x ^ 2 - x * 1 - 1x - 1 * -1'
,
'x ^ 2 - x - 1x - 1 * -1'
,
'x ^ 2 - x - x - 1 * -1'
,
'x ^ 2 + (1 + 1) * -x - 1 * -1'
,
'x ^ 2 + 2 * -x - 1 * -1'
,
'x ^ 2 - 2x - 1 * -1'
,
'(x - 1) ^ 2'
,
'(x - 1)(x - 1)'
,
'xx + x(-1) + (-1)x + (-1)(-1)'
,
'x ^ (1 + 1) + x(-1) + (-1)x + (-1)(-1)'
,
'x ^ 2 + x(-1) + (-1)x + (-1)(-1)'
,
'x ^ 2 - x * 1 + (-1)x + (-1)(-1)'
,
'x ^ 2 - x + (-1)x + (-1)(-1)'
,
'x ^ 2 - x - 1x + (-1)(-1)'
,
'x ^ 2 - x - x + (-1)(-1)'
,
'x ^ 2 + (1 + 1)(-x) + (-1)(-1)'
,
'x ^ 2 + 2(-x) + (-1)(-1)'
,
'x ^ 2 - 2x + (-1)(-1)'
,
'x ^ 2 - 2x - -1'
,
'x ^ 2 - 2x + 1'
,
])
...
...
@@ -101,20 +104,20 @@ class TestLeidenOefenopgave(TestCase):
'-x * 1 - 1x'
,
'-x - 1x'
,
'-x - x'
,
'(1 + 1)
* -x
'
,
'2
* -x
'
,
'(1 + 1)
(-x)
'
,
'2
(-x)
'
,
'-2x'
,
])
def
test_1_4_3
(
self
):
self
.
assertRewrite
([
'x * -1 + x * -1'
,
'-x * 1 + x
* -1
'
,
'-x + x
* -1
'
,
'-x * 1 + x
(-1)
'
,
'-x + x
(-1)
'
,
'-x - x * 1'
,
'-x - x'
,
'(1 + 1)
* -x
'
,
'2
* -x
'
,
'(1 + 1)
(-x)
'
,
'2
(-x)
'
,
'-2x'
,
])
...
...
@@ -132,14 +135,16 @@ class TestLeidenOefenopgave(TestCase):
'(4x + 5) * -(5 - 4x)'
,
'(4x + 5)(-5 - -4x)'
,
'(4x + 5)(-5 + 4x)'
,
'4x * -5 + 4x * 4x + 5 * -5 + 5 * 4x'
,
'-20x + 4x * 4x + 5 * -5 + 5 * 4x'
,
'-20x + 16xx + 5 * -5 + 5 * 4x'
,
'-20x + 16x ^ (1 + 1) + 5 * -5 + 5 * 4x'
,
'-20x + 16x ^ 2 + 5 * -5 + 5 * 4x'
,
'4x(-5) + 4x * 4x + 5(-5) + 5 * 4x'
,
'(-20)x + 4x * 4x + 5(-5) + 5 * 4x'
,
'-20x + 4x * 4x + 5(-5) + 5 * 4x'
,
'-20x + 16xx + 5(-5) + 5 * 4x'
,
'-20x + 16x ^ (1 + 1) + 5(-5) + 5 * 4x'
,
'-20x + 16x ^ 2 + 5(-5) + 5 * 4x'
,
'-20x + 16x ^ 2 - 25 + 5 * 4x'
,
'-20x + 16x ^ 2 - 25 + 20x'
,
'(-20 + 20)x + 16x ^ 2 - 25'
,
'(-1 + 1)20x + 16x ^ 2 - 25'
,
'0 * 20x + 16x ^ 2 - 25'
,
'0x + 16x ^ 2 - 25'
,
'0 + 16x ^ 2 - 25'
,
'16x ^ 2 - 25'
,
...
...
@@ -164,6 +169,7 @@ class TestLeidenOefenopgave(TestCase):
'2/7 - 4/11'
,
'22 / 77 - 28 / 77'
,
'(22 - 28) / 77'
,
'(-6) / 77'
,
'-6 / 77'
,
])
...
...
tests/test_leiden_oefenopgave_v12.py
View file @
42662f45
...
...
@@ -3,51 +3,58 @@ from tests.rulestestcase import RulesTestCase as TestCase
class
TestLeidenOefenopgaveV12
(
TestCase
):
def
test_1_a
(
self
):
self
.
assertRewrite
([
'-5(x2 - 3x + 6)'
,
'-5(x ^ 2 - 3x) - 5 * 6'
,
'-5x ^ 2 - 5 * -3x - 5 * 6'
,
'-5x ^ 2 - -15x - 5 * 6'
,
'-5x ^ 2 + 15x - 5 * 6'
,
'-5x ^ 2 + 15x - 30'
])
self
.
assertRewrite
([
'-5(x2 - 3x + 6)'
,
'-(5(x ^ 2 - 3x) + 5 * 6)'
,
'-(5x ^ 2 + 5(-3x) + 5 * 6)'
,
'-(5x ^ 2 - 5 * 3x + 5 * 6)'
,
'-(5x ^ 2 - 15x + 5 * 6)'
,
'-(5x ^ 2 - 15x + 30)'
,
'-5x ^ 2 - -15x - 30'
,
'-5x ^ 2 + 15x - 30'
,
])
def
test_1_d
(
self
):
self
.
assertRewrite
([
'(2x + x)x'
,
'(2 + 1)xx'
,
'3xx'
,
'3x ^ (1 + 1)'
,
'3x ^ 2'
])
self
.
assertRewrite
([
'(2x + x)x'
,
'(2 + 1)xx'
,
'3xx'
,
'3x ^ (1 + 1)'
,
'3x ^ 2'
,
])
def
test_1_e
(
self
):
self
.
assertRewrite
([
'-2(6x - 4) ^ 2x'
,
'-2(6x - 4)(6x - 4)x'
,
'(-2 * 6x - 2 * -4)(6x - 4)x'
,
'(-12x - 2 * -4)(6x - 4)x'
,
'(-12x - -8)(6x - 4)x'
,
'(-12x + 8)(6x - 4)x'
,
'(-12x * 6x - 12x * -4 + 8 * 6x + 8 * -4)x'
,
'(-72xx - 12x * -4 + 8 * 6x + 8 * -4)x'
,
'(-72x ^ (1 + 1) - 12x * -4 + 8 * 6x + 8 * -4)x'
,
'(-72x ^ 2 - 12x * -4 + 8 * 6x + 8 * -4)x'
,
'(-72x ^ 2 - -48x + 8 * 6x + 8 * -4)x'
,
'(-72x ^ 2 + 48x + 8 * 6x + 8 * -4)x'
,
'(-72x ^ 2 + 48x + 48x + 8 * -4)x'
,
'(-72x ^ 2 + (1 + 1)48x + 8 * -4)x'
,
'(-72x ^ 2 + 2 * 48x + 8 * -4)x'
,
'(-72x ^ 2 + 96x + 8 * -4)x'
,
'(-72x ^ 2 + 96x - 32)x'
,
'x(-72x ^ 2 + 96x) + x * -32'
,
'x * -72x ^ 2 + x * 96x + x * -32'
,
'-x * 72x ^ 2 + x * 96x + x * -32'
,
'-x ^ (1 + 2)72 + x * 96x + x * -32'
,
'-x ^ 3 * 72 + x * 96x + x * -32'
,
'-x ^ 3 * 72 + x ^ (1 + 1)96 + x * -32'
,
'-x ^ 3 * 72 + x ^ 2 * 96 + x * -32'
,
'-(2 * 6x + 2(-4))(6x - 4)x'
,
'-(12x + 2(-4))(6x - 4)x'
,
'-(12x - 8)(6x - 4)x'
,
'-(12x * 6x + 12x(-4) + (-8)6x + (-8)(-4))x'
,
'-(72xx + 12x(-4) + (-8)6x + (-8)(-4))x'
,
'-(72x ^ (1 + 1) + 12x(-4) + (-8)6x + (-8)(-4))x'
,
'-(72x ^ 2 + 12x(-4) + (-8)6x + (-8)(-4))x'
,
'-(72x ^ 2 + (-48)x + (-8)6x + (-8)(-4))x'
,
'-(72x ^ 2 - 48x + (-8)6x + (-8)(-4))x'
,
'-(72x ^ 2 - 48x + (-48)x + (-8)(-4))x'
,
'-(72x ^ 2 - 48x - 48x + (-8)(-4))x'
,
'-(72x ^ 2 + (1 + 1)(-48x) + (-8)(-4))x'
,
'-(72x ^ 2 + 2(-48x) + (-8)(-4))x'
,
'-(72x ^ 2 - 2 * 48x + (-8)(-4))x'
,
'-(72x ^ 2 - 96x + (-8)(-4))x'
,
'-(72x ^ 2 - 96x - -32)x'
,
'-(72x ^ 2 - 96x + 32)x'
,
'-(x(72x ^ 2 - 96x) + x * 32)'
,
'-(x * 72x ^ 2 + x(-96x) + x * 32)'
,
'-(x ^ (1 + 2)72 + x(-96x) + x * 32)'
,
'-(x ^ 3 * 72 + x(-96x) + x * 32)'
,
'-(x ^ 3 * 72 - x * 96x + x * 32)'
,
'-(x ^ 3 * 72 - x ^ (1 + 1)96 + x * 32)'
,
'-(x ^ 3 * 72 - x ^ 2 * 96 + x * 32)'
,
'-x ^ 3 * 72 - -x ^ 2 * 96 - x * 32'
,
'-x ^ 3 * 72 + x ^ 2 * 96 - x * 32'
,
'72 * -x ^ 3 + x ^ 2 * 96 - x * 32'
,
'-72x ^ 3 + x ^ 2 * 96 - x * 32'
,
'-72x ^ 3 + 96x ^ 2 - x * 32'
,
'-72x ^ 3 + 96x ^ 2 + 32 * -x'
,
'-72x ^ 3 + 96x ^ 2 - 32x'
,
])
...
...
@@ -67,7 +74,7 @@ class TestLeidenOefenopgaveV12(TestCase):
'b ^ 2 * a ^ 7 / b ^ 3'
,
'b ^ 2 / b ^ 3 * a ^ 7 / 1'
,
'b ^ (2 - 3)a ^ 7 / 1'
,
'b ^
-1 *
a ^ 7 / 1'
,
'b ^
(-1)
a ^ 7 / 1'
,
'1 / b ^ 1 * a ^ 7 / 1'
,
'1 / b * a ^ 7 / 1'
,
'a ^ 7 * 1 / b / 1'
,
...
...
@@ -105,9 +112,9 @@ class TestLeidenOefenopgaveV12(TestCase):
def
test_2_f
(
self
):
self
.
assertRewrite
([
'(4b) ^ -2'
,
'4 ^
-2 * b ^ -2
'
,
'1 / 4 ^ 2 * b ^
-2
'
,
'1 / 16 * b ^
-2
'
,
'4 ^
(-2)b ^ (-2)
'
,
'1 / 4 ^ 2 * b ^
(-2)
'
,
'1 / 16 * b ^
(-2)
'
,
'1 / 16 * (1 / b ^ 2)'
,
'1 * 1 / (16b ^ 2)'
,
'1 / (16b ^ 2)'
,
...
...
tests/test_node.py
View file @
42662f45
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
,
indef
,
eq
,
negation_to_node
from
tests.rulestestcase
import
RulesTestCase
,
tree
...
...
@@ -106,6 +106,10 @@ class TestNode(RulesTestCase):
plus
=
N
(
'+'
,
N
(
'+'
,
N
(
'+'
,
*
self
.
l
[:
2
]),
self
.
l
[
2
]),
self
.
l
[
3
])
self
.
assertEqual
(
get_scope
(
plus
),
self
.
l
)
def
test_get_scope_negation
(
self
):
root
,
a
,
b
,
cd
=
tree
(
'a * b * -cd, a, b, -cd'
)
self
.
assertEqual
(
get_scope
(
root
),
[
a
,
b
,
cd
])
def
test_equals_node_leaf
(
self
):
a
,
b
=
plus
=
tree
(
'a + b'
)
...
...
@@ -296,3 +300,9 @@ class TestNode(RulesTestCase):
def
test_eq
(
self
):
x
,
a
,
b
,
expect
=
tree
(
'x, a, b, x + a = b'
)
self
.
assertEqual
(
eq
(
x
+
a
,
b
),
expect
)
def
test_negation_to_node
(
self
):
a
=
tree
(
'a'
)
self
.
assertEqual
(
negation_to_node
(
-
a
),
N
(
'-'
,
a
))
self
.
assertEqual
(
negation_to_node
(
-
(
a
+
1
)),
N
(
'-'
,
a
+
1
))
self
.
assertEqual
(
negation_to_node
(
-
(
a
-
1
)),
N
(
'-'
,
a
+
N
(
'-'
,
1
)))
tests/test_parser.py
View file @
42662f45
...
...
@@ -63,14 +63,6 @@ class TestParser(unittest.TestCase):
# FIXME: self.assertEqual(tree('a|b|'), tree('a * |b|'))
# FIXME: self.assertEqual(tree('|a|b'), tree('|a| * b'))
def
test_moved_negation
(
self
):
a
,
b
=
tree
(
'a,b'
)
self
.
assertEqual
(
tree
(
'-ab'
),
(
-
a
)
*
b
)
self
.
assertEqual
(
tree
(
'-(ab)'
),
(
-
a
)
*
b
)
self
.
assertEqual
(
tree
(
'-a / b'
),
(
-
a
)
/
b
)
self
.
assertEqual
(
tree
(
'-(a / b)'
),
(
-
a
)
/
b
)
def
test_functions
(
self
):
x
=
tree
(
'x'
)
...
...
tests/test_rewrite.py
View file @
42662f45
...
...
@@ -4,11 +4,23 @@ from tests.rulestestcase import RulesTestCase as TestCase
class
TestRewrite
(
TestCase
):
def
test_addition_rewrite
(
self
):
self
.
assertRewrite
([
'2 + 3 + 4'
,
'5 + 4'
,
'9'
])
self
.
assertRewrite
([
'2 + 3 + 4'
,
'5 + 4'
,
'9'
,
])
def
test_addition_identifiers_rewrite
(
self
):
self
.
assertRewrite
([
'2 + 3a + 4'
,
'6 + 3a'
])
self
.
assertRewrite
([
'2 + 3a + 4'
,
'6 + 3a'
,
])
def
test_division_rewrite
(
self
):
self
.
assertRewrite
([
'2/7 - 4/11'
,
'22 / 77 - 28 / 77'
,
'(22 - 28) / 77'
,
'-6 / 77'
])
self
.
assertRewrite
([
'2/7 - 4/11'
,
'22 / 77 - 28 / 77'
,
'(22 - 28) / 77'
,
'(-6) / 77'
,
'-6 / 77'
,
])
tests/test_rules_factors.py
View file @
42662f45
from
src.rules.factors
import
match_expand
,
expand_single
,
expand_double
from
src.node
import
Scope
from
src.possibilities
import
Possibility
as
P
from
tests.rulestestcase
import
RulesTestCase
,
tree
...
...
@@ -10,45 +11,41 @@ class TestRulesFactors(RulesTestCase):
b
,
c
=
bc
root
=
a
*
bc
possibilities
=
match_expand
(
root
)
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
expand_single
,
(
a
,
bc
))])
self
.
assertEqualPos
(
match_expand
(
root
),
[
P
(
root
,
expand_single
,
(
Scope
(
root
),
a
,
bc
))])
root
=
bc
*
a
possibilities
=
match_expand
(
root
)
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
expand_single
,
(
a
,
bc
))])
self
.
assertEqualPos
(
match_expand
(
root
),
[
P
(
root
,
expand_single
,
(
Scope
(
root
),
a
,
bc
))])
root
=
a
*
d
*
bc
possibilities
=
match_expand
(
root
)
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
expand_single
,
(
a
,
bc
)),
P
(
root
,
expand_single
,
(
d
,
bc
))])
self
.
assertEqualPos
(
match_expand
(
root
),
[
P
(
root
,
expand_single
,
(
Scope
(
root
),
a
,
bc
)),
P
(
root
,
expand_single
,
(
Scope
(
root
),
d
,
bc
))])
ab
,
cd
=
root
=
(
a
+
b
)
*
(
c
+
d
)
possibilities
=
match_expand
(
root
)
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
expand_double
,
(
ab
,
cd
))])
self
.
assertEqualPos
(
match_expand
(
root
),
[
P
(
root
,
expand_double
,
(
Scope
(
root
),
ab
,
cd
))])
def
test_expand_single
(
self
):
a
,
b
,
c
,
d
=
tree
(
'a,b,c,d'
)
bc
=
b
+
c
root
=
a
*
bc
self
.
assertEqualNodes
(
expand_single
(
root
,
(
a
,
bc
)),
self
.
assertEqualNodes
(
expand_single
(
root
,
(
Scope
(
root
),
a
,
bc
)),
a
*
b
+
a
*
c
)
root
=
a
*
d
*
bc
self
.
assertEqualNodes
(
expand_single
(
root
,
(
a
,
bc
)),
self
.
assertEqualNodes
(
expand_single
(
root
,
(
Scope
(
root
),
a
,
bc
)),
(
a
*
b
+
a
*
c
)
*
d
)
def
test_expand_double
(
self
):
(
a
,
b
),
(
c
,
d
)
=
ab
,
cd
=
tree
(
'a + b,c + d'
)
root
=
ab
*
cd
self
.
assertEqualNodes
(
expand_double
(
root
,
(
ab
,
cd
)),
self
.
assertEqualNodes
(
expand_double
(
root
,
(
Scope
(
root
),
ab
,
cd
)),
a
*
c
+
a
*
d
+
b
*
c
+
b
*
d
)
root
=
a
*
ab
*
b
*
cd
*
c
self
.
assertEqualNodes
(
expand_double
(
root
,
(
ab
,
cd
)),
self
.
assertEqualNodes
(
expand_double
(
root
,
(
Scope
(
root
),
ab
,
cd
)),
a
*
(
a
*
c
+
a
*
d
+
b
*
c
+
b
*
d
)
*
b
*
c
)
tests/test_rules_fractions.py
View file @
42662f45
...
...
@@ -185,9 +185,8 @@ class TestRulesFractions(RulesTestCase):
P
(
root
,
divide_fraction_parts
,
(
b
,
s0
,
s1
,
1
,
1
)),
P
(
root
,
divide_fraction_parts
,
(
c
,
s0
,
s1
,
2
,
0
))])
root
=
tree
(
'-a / a'
)
self
.
assertEqualPos
(
match_equal_fraction_parts
(
root
),
[
P
(
root
,
divide_fraction_parts
,
(
a
,
[
-
a
],
[
a
],
0
,
0
))])
root
=
tree
(
'a / a'
)
self
.
assertEqualPos
(
match_equal_fraction_parts
(
root
),
[])
(
ap
,
b
),
aq
=
root
=
tree
(
'a ^ p * b / a ^ q'
)
self
.
assertEqualPos
(
match_equal_fraction_parts
(
root
),
...
...
@@ -224,7 +223,7 @@ class TestRulesFractions(RulesTestCase):
result
=
divide_fraction_parts
(
root
,
(
c
,
[
a
,
b
,
c
],
[
c
,
b
,
a
],
2
,
0
))
self
.
assertEqual
(
result
,
a
*
b
/
(
b
*
a
))
(
a
,
b
),
a
=
root
=
tree
(
'
-a
b / a'
)
(
a
,
b
),
a
=
root
=
tree
(
'
(-a)
b / a'
)
result
=
divide_fraction_parts
(
root
,
(
a
,
[
-
a
,
b
],
[
a
],
0
,
0
))
self
.
assertEqual
(
result
,
-
b
/
1
)
...
...
tests/test_rules_groups.py
View file @
42662f45
...
...
@@ -95,7 +95,13 @@ class TestRulesGroups(RulesTestCase):
root
,
l1
=
tree
(
'ab + b + ba,1'
)
abb
,
ba
=
root
ab
,
b
=
abb
self
.
assertEqualNodes
(
combine_groups
(
root
,
(
Scope
(
root
),
l1
,
ab
,
ab
,
l1
,
ba
,
ba
)),
(
l1
+
1
)
*
ab
+
b
)
def
test_combine_groups_negation
(
self
):
root
,
expect
=
tree
(
'3a - 2a, -(3 + 2)a'
)
(
l3
,
a0
),
(
l2
,
a1
)
=
n0
,
n1
=
root
self
.
assertEqualNodes
(
combine_groups
(
root
,
(
Scope
(
root
),
l3
,
a0
,
n0
,
l2
,
a1
,
n1
)),
expect
)
tests/test_rules_integrals.py
View file @
42662f45
...
...
@@ -98,7 +98,7 @@ class TestRulesIntegrals(RulesTestCase):
[
P
(
root
,
split_negation_to_constant
)])
def
test_split_negation_to_constant
(
self
):
root
,
expect
=
tree
(
'int -x2 dx, int
-1
x2 dx'
)
root
,
expect
=
tree
(
'int -x2 dx, int
(-1)
x2 dx'
)
self
.
assertEqual
(
split_negation_to_constant
(
root
,
()),
expect
)
def
test_factor_out_constant
(
self
):
...
...
tests/test_rules_lineq.py
View file @
42662f45
...
...
@@ -69,12 +69,14 @@ class TestRulesLineq(RulesTestCase):
'(2 + 3)x = -3x - 5 - -3x'
,
'5x = -3x - 5 - -3x'
,
'5x = -3x - 5 + 3x'
,
'5x = (-3 + 3)x - 5'
,
'5x = (-1 + 1)3x - 5'
,
'5x = 0 * 3x - 5'
,
'5x = 0x - 5'
,
'5x = 0 - 5'
,
'5x = -5'
,
'5x / 5 = -5 / 5'
,
'x / 1 = -5 / 5'
,
'5x / 5 = (-5) / 5'
,
'x / 1 = (-5) / 5'
,
'x = (-5) / 5'
,
'x = -5 / 5'
,
'x = -1'
,
])
...
...
@@ -82,10 +84,11 @@ class TestRulesLineq(RulesTestCase):
def
test_match_move_term_chain_advanced
(
self
):
self
.
assertRewrite
([
'-x = a'
,
'-x * -1 = a * -1'
,
'--x * 1 = a * -1'
,
'x * 1 = a * -1'
,
'x = a * -1'
,
'(-x)(-1) = a(-1)'
,
'-x(-1) = a(-1)'
,
'--x * 1 = a(-1)'
,
'--x = a(-1)'
,
'x = a(-1)'
,
'x = -a * 1'
,
'x = -a'
,
])
tests/test_rules_negation.py
View file @
42662f45
from
src.rules.negation
import
match_negated_factor
,
negated_factor
,
\
match_negate_polynome
,
negate_polynome
,
double_negation
,
\
match_negated_division
,
single_negated_division
,
\
double_negated_division
match_negate_polynome
,
negate_polynome
,
negated_zero
,
\
double_negation
,
match_negated_division
,
negated_nominator
,
\
negated_denominator
from
src.node
import
Scope
from
src.possibilities
import
Possibility
as
P
from
tests.rulestestcase
import
RulesTestCase
,
tree
...
...
@@ -14,7 +14,7 @@ class TestRulesNegation(RulesTestCase):
self
.
assertEqualPos
(
match_negated_factor
(
root
),
[
P
(
root
,
negated_factor
,
(
Scope
(
root
),
b
))])
(
a
,
b
),
c
=
root
=
tree
(
'a *
-b
* -c'
)
(
a
,
b
),
c
=
root
=
tree
(
'a *
(-b)
* -c'
)
scope
=
Scope
(
root
)
self
.
assertEqualPos
(
match_negated_factor
(
root
),
[
P
(
root
,
negated_factor
,
(
scope
,
b
)),
...
...
@@ -22,34 +22,44 @@ class TestRulesNegation(RulesTestCase):
def
test_negated_factor
(
self
):
a
,
b
=
root
=
tree
(
'a * -b'
)
self
.
assertEqualNodes
(
negated_factor
(
root
,
(
Scope
(
root
),
b
)),
-
a
*
+
b
)
self
.
assertEqual
(
negated_factor
(
root
,
(
Scope
(
root
),
b
)),
-
(
a
*
+
b
))
(
a
,
b
),
c
=
root
=
tree
(
'a * -b * -c'
)
self
.
assertEqualNodes
(
negated_factor
(
root
,
(
Scope
(
root
),
b
)),
-
a
*
+
b
*
c
)
self
.
assertEqualNodes
(
negated_factor
(
root
,
(
Scope
(
root
),
c
)),
-
a
*
b
*
+
c
)
(
a
,
b
),
c
=
root
=
tree
(
'a * (-b) * -c'
)
self
.
assertEqual
(
negated_factor
(
root
,
(
Scope
(
root
),
b
)),
-
(
a
*
+
b
*
c
))
self
.
assertEqual
(
negated_factor
(
root
,
(
Scope
(
root
),
c
)),
-
(
a
*
b
*
+
c
))
def
test_match_negate_polynome
(
self
):
root
=
tree
(
'--a'
)
self
.
assertEqualPos
(
match_negate_polynome
(
root
),
[
P
(
root
,
double_negation
,
())])
[
P
(
root
,
double_negation
)])
root
=
tree
(
'-0'
)
self
.
assertEqualPos
(
match_negate_polynome
(
root
),
[
P
(
root
,
negated_zero
)])
root
=
tree
(
'--0'
)
self
.
assertEqualPos
(
match_negate_polynome
(
root
),
[
P
(
root
,
double_negation
),
P
(
root
,
negated_zero
)])
root
=
tree
(
'-(a + b)'
)
self
.
assertEqualPos
(
match_negate_polynome
(
root
),
[
P
(
root
,
negate_polynome
,
()
)])
[
P
(
root
,
negate_polynome
)])
def
test_double_negation
(
self
):
root
=
tree
(
'--a'
)
self
.
assertEqualNodes
(
double_negation
(
root
,
()),
++
root
)
self
.
assertEqual
(
double_negation
(
root
,
()),
++
root
)
def
test_negated_zero
(
self
):
root
=
tree
(
'-0'
)
self
.
assertEqual
(
negated_zero
(
root
,
()),
0
)
def
test_negate_polynome
(
self
):
a
,
b
=
root
=
tree
(
'-(a + b)'
)
self
.
assertEqual
Nodes
(
negate_polynome
(
root
,
()),
-
a
+
-
b
)
self
.
assertEqual
(
negate_polynome
(
root
,
()),
-
a
+
-
b
)
a
,
b
=
root
=
tree
(
'-(a - b)'
)
self
.
assertEqual
Nodes
(
negate_polynome
(
root
,
()),
-
a
+
-
b
)
self
.
assertEqual
(
negate_polynome
(
root
,
()),
-
a
+
-
b
)
def
test_match_negated_division_none
(
self
):
self
.
assertEqual
(
match_negated_division
(
tree
(
'1 / 2'
)),
[])
...
...
@@ -58,25 +68,32 @@ class TestRulesNegation(RulesTestCase):
l1
,
l2
=
root
=
tree
(
'-1 / 2'
)
self
.
assertEqualPos
(
match_negated_division
(
root
),
[])
l1
,
l2
=
root
=
tree
(
'(-1) / 2'
)
self
.
assertEqualPos
(
match_negated_division
(
root
),
[
P
(
root
,
negated_nominator
)])
l1
,
l2
=
root
=
tree
(
'1 / -2'
)
possibilities
=
match_negated_division
(
root
)
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
single_negated_division
,
(
l1
,
+
l2
))])
self
.
assertEqualPos
(
match_negated_division
(
root
),
[
P
(
root
,
negated_denominator
)])
def
test_match_negated_division_double
(
self
):
root
=
tree
(
'-1 / -2'
)
root
=
tree
(
'(-1) / -2'
)
self
.
assertEqualPos
(
match_negated_division
(
root
),
[
P
(
root
,
negated_nominator
),
P
(
root
,
negated_denominator
)])
possibilities
=
match_negated_division
(
root
)
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
double_negated_division
,
())]
)
def
test_negated_nominator
(
self
):
l1
,
l2
=
root
=
tree
(
'(-1) / 2'
)
self
.
assertEqual
(
negated_nominator
(
root
,
()),
-
(
+
l1
/
l2
)
)
def
test_
single_negated_division
(
self
):
def
test_
negated_denominator
(
self
):
l1
,
l2
=
root
=
tree
(
'1 / -2'
)
self
.
assertEqualNodes
(
single_negated_division
(
root
,
(
l1
,
+
l2
)),
-
l1
/
+
l2
)
self
.
assertEqual
(
negated_denominator
(
root
,
()),
-
(
l1
/
+
l2
))
def
test_double_negated_division
(
self
):
l1
,
l2
=
root
=
tree
(
'-1 / -2'
)
self
.
assertEqualNodes
(
double_negated_division
(
root
,
()),
+
l1
/
+
l2
)
self
.
assertRewrite
([
'(-a) / (-b)'
,
'-a / (-b)'
,
'--a / b'
,
'a / b'
,
])
tests/test_rules_numerics.py
View file @
42662f45
from
src.rules.numerics
import
match_add_numerics
,
add_numerics
,
\
match_divide_numerics
,
divide_numerics
,
reduce_fraction_constants
,
\
fraction_to_int_fraction
,
match_multiply_numerics
,
multiply_numerics
,
\
match_multiply_numerics
,
multiply_numerics
,
\
raise_numerics
from
src.node
import
ExpressionLeaf
as
L
,
Scope
from
src.possibilities
import
Possibility
as
P
...
...
@@ -42,67 +42,54 @@ class TestRulesNumerics(RulesTestCase):
root
=
i6
/
i2
possibilities
=
match_divide_numerics
(
root
)
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
divide_numerics
,
(
6
,
2
,
0
))])
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
divide_numerics
)])
root
=
-
i6
/
i2
possibilities
=
match_divide_numerics
(
root
)
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
divide_numerics
,
(
6
,
2
,
1
))])
self
.
assertEqualPos
(
match_divide_numerics
(
root
),
[])
root
=
i3
/
i2
possibilities
=
match_divide_numerics
(
root
)
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
fraction_to_int_fraction
,
(
1
,
1
,
2
))])
root
=
i6
/
-
i2
self
.
assertEqualPos
(
match_divide_numerics
(
root
),
[])
root
=
i2
/
i4
possibilities
=
match_divide_numerics
(
root
)
self
.
assertEqualPos
(
possibilities
,
self
.
assertEqualPos
(
match_divide_numerics
(
root
),
[
P
(
root
,
reduce_fraction_constants
,
(
2
,))])
root
=
f3
/
i2
possibilities
=
match_divide_numerics
(
root
)
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
divide_numerics
,
(
3.0
,
2
,
0
))])
self
.
assertEqualPos
(
match_divide_numerics
(
root
),
[
P
(
root
,
divide_numerics
)])
root
=
i3
/
f2
possibilities
=
match_divide_numerics
(
root
)
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
divide_numerics
,
(
3
,
2.0
,
0
))])
self
.
assertEqualPos
(
match_divide_numerics
(
root
),
[
P
(
root
,
divide_numerics
)])
root
=
f3
/
f2
possibilities
=
match_divide_numerics
(
root
)
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
divide_numerics
,
(
3.0
,
2.0
,
0
))])
self
.
assertEqualPos
(
match_divide_numerics
(
root
),
[
P
(
root
,
divide_numerics
)])
root
=
i3
/
f1
possibilities
=
match_divide_numerics
(
root
)
self
.
assertEqualPos
(
possibilities
,
[
P
(
root
,
divide_numerics
,
(
3
,
1
,
0
))])
self
.
assertEqualPos
(
match_divide_numerics
(
root
),
[
P
(
root
,
divide_numerics
)])
root
=
a
/
b
possibilities
=
match_divide_numerics
(
root
)
self
.
assertEqualPos
(
possibilities
,
[])
self
.
assertEqualPos
(
match_divide_numerics
(
root
),
[])
def
test_divide_numerics
(
self
):
i2
,
i3
,
i6
,
f2
,
f3
=
tree
(
'2,3,6,2.0,3.0'
)
self
.
assertEqual
(
divide_numerics
(
i6
/
i2
,
(
6
,
2
,
0
)),
3
)
self
.
assertEqual
(
divide_numerics
(
f3
/
i2
,
(
3.0
,
2
,
0
)),
1.5
)
self
.
assertEqual
(
divide_numerics
(
i3
/
f2
,
(
3
,
2.0
,
0
)),
1.5
)
self
.
assertEqual
(
divide_numerics
(
f3
/
f2
,
(
3.0
,
2.0
,
0
)),
1.5
)
self
.
assertEqual
(
divide_numerics
(
i6
/
i2
,
(
6
,
2
,
1
)),
-
3
)
self
.
assertEqual
(
divide_numerics
(
i6
/
i2
,
(
6
,
2
,
2
)),
--
i3
)
self
.
assertEqual
(
divide_numerics
(
i6
/
i2
,
()),
3
)
self
.
assertEqual
(
divide_numerics
(
f3
/
i2
,
()),
1.5
)
self
.
assertEqual
(
divide_numerics
(
i3
/
f2
,
()),
1.5
)
self
.
assertEqual
(
divide_numerics
(
f3
/
f2
,
()),
1.5
)
self
.
assertEqual
(
divide_numerics
(
-
(
i6
/
i2
),
()),
-
i3
)
def
test_reduce_fraction_constants
(
self
):
l1
,
l2
=
tree
(
'1,2'
)
self
.
assertEqual
(
reduce_fraction_constants
(
l2
/
4
,
(
2
,)),
l1
/
l2
)
def
test_fraction_to_int_fraction
(
self
):
l1
,
l4
=
tree
(
'1,4'
)
self
.
assertEqual
(
fraction_to_int_fraction
(
l4
/
3
,
(
1
,
1
,
3
)),
l1
+
l1
/
3
)
#
def test_fraction_to_int_fraction(self):
#
l1, l4 = tree('1,4')
#
self.assertEqual(fraction_to_int_fraction(l4 / 3, (1, 1, 3)),
#
l1 + l1 / 3)
def
test_match_multiply_numerics
(
self
):
i2
,
i3
,
i6
,
f2
,
f3
,
f6
=
tree
(
'2,3,6,2.0,3.0,6.0'
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment