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
5ac16510
Commit
5ac16510
authored
Sep 13, 2012
by
Taddeüs Kroes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added rule 'a/b + c/d -> ad/(bd) + bc/(bd) -> (ad + bc)/(bd)' and some helper rules.
parent
6c30a8e6
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
118 additions
and
23 deletions
+118
-23
TODO
TODO
+0
-3
src/node.py
src/node.py
+1
-1
src/rules/__init__.py
src/rules/__init__.py
+6
-3
src/rules/fractions.py
src/rules/fractions.py
+71
-1
tests/test_rules_fractions.py
tests/test_rules_fractions.py
+40
-15
No files found.
TODO
View file @
5ac16510
...
@@ -26,9 +26,6 @@
...
@@ -26,9 +26,6 @@
- "sin^2 x" is supported by parser, but not yet by line printer.
- "sin^2 x" is supported by parser, but not yet by line printer.
- 1/x + 2/(x+1) -> (3x + 1) / (x(x + 1)):
a/b + c/d -> ad/(bd) + bc/(bd) -> (ad + bc)/(bd)
#- To work 100% correctly, POW and SUB (^ and _) should have a precedence equal
#- To work 100% correctly, POW and SUB (^ and _) should have a precedence equal
# to INTEGRAL when used for integral bounds.
# to INTEGRAL when used for integral bounds.
...
...
src/node.py
View file @
5ac16510
...
@@ -659,7 +659,7 @@ def negate(node, n=1, clone=False):
...
@@ -659,7 +659,7 @@ def negate(node, n=1, clone=False):
Negate the given node n times. If clone is set to true, return a new node
Negate the given node n times. If clone is set to true, return a new node
so that the original node is not altered.
so that the original node is not altered.
"""
"""
assert
n
>=
0
#
assert n >= 0
if
clone
:
if
clone
:
node
=
node
.
clone
()
node
=
node
.
clone
()
...
...
src/rules/__init__.py
View file @
5ac16510
...
@@ -25,7 +25,8 @@ from .numerics import match_add_numerics, match_divide_numerics, \
...
@@ -25,7 +25,8 @@ from .numerics import match_add_numerics, match_divide_numerics, \
match_multiply_numerics
,
match_raise_numerics
match_multiply_numerics
,
match_raise_numerics
from
.fractions
import
match_constant_division
,
match_add_fractions
,
\
from
.fractions
import
match_constant_division
,
match_add_fractions
,
\
match_multiply_fractions
,
match_divide_fractions
,
\
match_multiply_fractions
,
match_divide_fractions
,
\
match_extract_fraction_terms
,
match_division_in_denominator
match_extract_fraction_terms
,
match_division_in_denominator
,
\
match_combine_fractions
,
match_remove_division_negation
from
.negation
import
match_negated_factor
,
match_negate_polynome
,
\
from
.negation
import
match_negated_factor
,
match_negate_polynome
,
\
match_negated_division
match_negated_division
from
.sort
import
match_sort_polynome
,
match_sort_monomial
from
.sort
import
match_sort_polynome
,
match_sort_monomial
...
@@ -50,14 +51,16 @@ from .sqrt import match_reduce_sqrt
...
@@ -50,14 +51,16 @@ from .sqrt import match_reduce_sqrt
RULES
=
{
RULES
=
{
OP_ADD
:
[
match_add_numerics
,
match_add_fractions
,
OP_ADD
:
[
match_add_numerics
,
match_add_fractions
,
match_combine_groups
,
match_add_quadrants
,
match_combine_groups
,
match_add_quadrants
,
match_add_logarithms
,
match_sort_polynome
],
match_add_logarithms
,
match_sort_polynome
,
match_combine_fractions
],
OP_MUL
:
[
match_multiply_numerics
,
match_expand
,
match_add_exponents
,
OP_MUL
:
[
match_multiply_numerics
,
match_expand
,
match_add_exponents
,
match_negated_factor
,
match_multiply_fractions
,
match_negated_factor
,
match_multiply_fractions
,
match_factor_in_multiplicant
,
match_sort_monomial
],
match_factor_in_multiplicant
,
match_sort_monomial
],
OP_DIV
:
[
match_subtract_exponents
,
match_divide_numerics
,
OP_DIV
:
[
match_subtract_exponents
,
match_divide_numerics
,
match_constant_division
,
match_divide_fractions
,
match_constant_division
,
match_divide_fractions
,
match_negated_division
,
match_extract_fraction_terms
,
match_negated_division
,
match_extract_fraction_terms
,
match_division_in_denominator
],
match_division_in_denominator
,
match_remove_division_negation
],
OP_POW
:
[
match_multiply_exponents
,
match_duplicate_exponent
,
OP_POW
:
[
match_multiply_exponents
,
match_duplicate_exponent
,
match_raised_fraction
,
match_remove_negative_child
,
match_raised_fraction
,
match_remove_negative_child
,
match_exponent_to_root
,
match_extend_exponent
,
match_exponent_to_root
,
match_extend_exponent
,
...
...
src/rules/fractions.py
View file @
5ac16510
...
@@ -20,6 +20,7 @@ from ..node import ExpressionNode as N, ExpressionLeaf as L, Scope, OP_DIV, \
...
@@ -20,6 +20,7 @@ from ..node import ExpressionNode as N, ExpressionLeaf as L, Scope, OP_DIV, \
OP_ADD
,
OP_MUL
,
negate
OP_ADD
,
OP_MUL
,
negate
from
..possibilities
import
Possibility
as
P
,
MESSAGES
from
..possibilities
import
Possibility
as
P
,
MESSAGES
from
..translate
import
_
from
..translate
import
_
from
.negation
import
negate_polynome
def
match_constant_division
(
node
):
def
match_constant_division
(
node
):
...
@@ -300,7 +301,7 @@ def divide_by_fraction(root, args):
...
@@ -300,7 +301,7 @@ def divide_by_fraction(root, args):
MESSAGES
[
divide_by_fraction
]
=
\
MESSAGES
[
divide_by_fraction
]
=
\
_
(
'Move {3} to nominator of fraction `{1} / {2}`.'
)
_
(
'Move {3} to
the
nominator of fraction `{1} / {2}`.'
)
def
is_power_combination
(
a
,
b
):
def
is_power_combination
(
a
,
b
):
...
@@ -464,3 +465,72 @@ def multiply_with_term(root, args):
...
@@ -464,3 +465,72 @@ def multiply_with_term(root, args):
MESSAGES
[
multiply_with_term
]
=
\
MESSAGES
[
multiply_with_term
]
=
\
_
(
'Multiply nominator and denominator of {0} with {1}.'
)
_
(
'Multiply nominator and denominator of {0} with {1}.'
)
def
match_combine_fractions
(
node
):
"""
a/b + c/d -> ad/(bd) + bc/(bd) # -> (ad + bc)/(bd)
"""
assert
node
.
is_op
(
OP_ADD
)
scope
=
Scope
(
node
)
fractions
=
[
n
for
n
in
scope
if
n
.
is_op
(
OP_DIV
)]
p
=
[]
for
left
,
right
in
combinations
(
fractions
,
2
):
p
.
append
(
P
(
node
,
combine_fractions
,
(
scope
,
left
,
right
)))
return
p
def
combine_fractions
(
root
,
args
):
"""
a/b + c/d -> ad/(bd) + bc/(bd)
"""
scope
,
ab
,
cd
=
args
(
a
,
b
),
(
c
,
d
)
=
ab
,
cd
a
=
negate
(
a
,
ab
.
negated
)
d
=
negate
(
d
,
cd
.
negated
)
scope
.
replace
(
ab
,
a
*
d
/
(
b
*
d
)
+
b
*
c
/
(
b
*
d
))
scope
.
remove
(
cd
)
return
scope
.
as_nary_node
()
MESSAGES
[
combine_fractions
]
=
_
(
'Combine fraction {2} and {3}.'
)
def
match_remove_division_negation
(
node
):
"""
-a / (-b + c) -> a / (--b - c)
"""
assert
node
.
is_op
(
OP_DIV
)
nom
,
denom
=
node
if
node
.
negated
:
if
nom
.
is_op
(
OP_ADD
)
and
any
([
n
.
negated
for
n
in
Scope
(
nom
)]):
return
[
P
(
node
,
remove_division_negation
,
(
True
,
nom
))]
if
denom
.
is_op
(
OP_ADD
)
and
any
([
n
.
negated
for
n
in
Scope
(
denom
)]):
return
[
P
(
node
,
remove_division_negation
,
(
False
,
denom
))]
return
[]
def
remove_division_negation
(
root
,
args
):
"""
-a / (-b + c) -> a / (--b - c)
"""
nom
,
denom
=
root
if
args
[
0
]:
nom
=
negate_polynome
(
nom
,
())
else
:
denom
=
negate_polynome
(
denom
,
())
return
negate
(
nom
/
denom
,
root
.
negated
-
1
)
MESSAGES
[
remove_division_negation
]
=
\
_
(
'Move negation from fraction {0} to polynome {2}.'
)
tests/test_rules_fractions.py
View file @
5ac16510
...
@@ -19,7 +19,8 @@ from src.rules.fractions import match_constant_division, division_by_one, \
...
@@ -19,7 +19,8 @@ from src.rules.fractions import match_constant_division, division_by_one, \
divide_fraction
,
divide_by_fraction
,
match_extract_fraction_terms
,
\
divide_fraction
,
divide_by_fraction
,
match_extract_fraction_terms
,
\
constant_to_fraction
,
extract_nominator_term
,
extract_fraction_terms
,
\
constant_to_fraction
,
extract_nominator_term
,
extract_fraction_terms
,
\
match_division_in_denominator
,
multiply_with_term
,
\
match_division_in_denominator
,
multiply_with_term
,
\
divide_fraction_by_term
divide_fraction_by_term
,
match_combine_fractions
,
combine_fractions
,
\
match_remove_division_negation
,
remove_division_negation
from
src.node
import
ExpressionNode
as
N
,
Scope
,
OP_MUL
from
src.node
import
ExpressionNode
as
N
,
Scope
,
OP_MUL
from
src.possibilities
import
Possibility
as
P
from
src.possibilities
import
Possibility
as
P
from
tests.rulestestcase
import
RulesTestCase
,
tree
from
tests.rulestestcase
import
RulesTestCase
,
tree
...
@@ -318,19 +319,43 @@ class TestRulesFractions(RulesTestCase):
...
@@ -318,19 +319,43 @@ class TestRulesFractions(RulesTestCase):
def
test_multiply_with_term_chain
(
self
):
def
test_multiply_with_term_chain
(
self
):
self
.
assertRewrite
([
self
.
assertRewrite
([
'1 / (1 / b - 1 / a)'
,
'1 / (1 / b - 1 / a)'
,
'(b * 1) / (b(1 / b - 1 / a))'
,
'1 / ((1 * -a) / (b * -a) + (b * 1) / (b * -a))'
,
'b / (b(1 / b - 1 / a))'
,
'1 / ((1 * -a + b * 1) / (b * -a))'
,
'b / (b * 1 / b + b * -1 / a)'
,
'1 / ((-a + b * 1) / (b * -a))'
,
'b / (b * 1 / b - b * 1 / a)'
,
'1 / ((-a + b) / (b * -a))'
,
'b / ((b * 1) / b - b * 1 / a)'
,
'1 / ((-a + b) / (-ba))'
,
'b / (b / b - b * 1 / a)'
,
'1 / (-(-a + b) / (ba))'
,
'b / (1 - b * 1 / a)'
,
'1 / ((--a - b) / (ba))'
,
'b / (1 - (b * 1) / a)'
,
'1 / ((a - b) / (ba))'
,
'b / (1 - b / a)'
,
'(1ba) / (a - b)'
,
'(ab) / (a(1 - b / a))'
,
'(ba) / (a - b)'
,
'(ab) / (a * 1 + a * -b / a)'
,
'(ab) / (a + a * -b / a)'
,
'(ab) / (a - a b / a)'
,
'(ab) / (a - (ab) / a)'
,
'(ab) / (a - b)'
,
'(ab) / (a - b)'
,
])
])
def
test_match_combine_fractions
(
self
):
ab
,
cd
=
root
=
tree
(
'a / b + c / d'
)
self
.
assertEqualPos
(
match_combine_fractions
(
root
),
[
P
(
root
,
combine_fractions
,
(
Scope
(
root
),
ab
,
cd
))])
def
test_combine_fractions
(
self
):
(
a
,
b
),
(
c
,
d
)
=
ab
,
cd
=
root
=
tree
(
'a / b + c / d'
)
self
.
assertEqual
(
combine_fractions
(
root
,
(
Scope
(
root
),
ab
,
cd
)),
a
*
d
/
(
b
*
d
)
+
b
*
c
/
(
b
*
d
))
def
test_match_remove_division_negation
(
self
):
root
=
tree
(
'-(-a + b) / c'
)
self
.
assertEqualPos
(
match_remove_division_negation
(
root
),
[
P
(
root
,
remove_division_negation
,
(
True
,
root
[
0
]))])
root
=
tree
(
'-a / (-b + c)'
)
self
.
assertEqualPos
(
match_remove_division_negation
(
root
),
[
P
(
root
,
remove_division_negation
,
(
False
,
root
[
1
]))])
def
test_remove_division_negation
(
self
):
(
a
,
b
),
c
=
root
=
tree
(
'-(-a + b) / c'
)
self
.
assertEqual
(
remove_division_negation
(
root
,
(
True
,
root
[
0
])),
(
-
a
-
b
)
/
c
)
a
,
(
b
,
c
)
=
root
=
tree
(
'-a / (-b + c)'
)
self
.
assertEqual
(
remove_division_negation
(
root
,
(
False
,
root
[
1
])),
+
a
/
(
-
b
-
c
))
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