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
08555af7
Commit
08555af7
authored
Apr 12, 2012
by
Taddeus Kroes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Applied most of the new fraction rules.
parent
7a9605a7
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
92 additions
and
223 deletions
+92
-223
src/rules/__init__.py
src/rules/__init__.py
+2
-2
src/rules/fractions.py
src/rules/fractions.py
+22
-115
src/rules/groups.py
src/rules/groups.py
+2
-3
tests/test_rules_fractions.py
tests/test_rules_fractions.py
+66
-103
No files found.
src/rules/__init__.py
View file @
08555af7
...
...
@@ -11,7 +11,7 @@ from .numerics import match_add_numerics, match_divide_numerics, \
match_raise_numerics
from
.fractions
import
match_constant_division
,
match_add_fractions
,
\
match_multiply_fractions
,
match_divide_fractions
,
\
match_e
qual_fraction_part
s
match_e
xtract_fraction_term
s
from
.negation
import
match_negated_factor
,
match_negate_polynome
,
\
match_negated_division
from
.sort
import
match_sort_multiplicants
...
...
@@ -39,7 +39,7 @@ RULES = {
match_factor_in_multiplicant
],
OP_DIV
:
[
match_subtract_exponents
,
match_divide_numerics
,
match_constant_division
,
match_divide_fractions
,
match_negated_division
,
match_e
qual_fraction_part
s
],
match_negated_division
,
match_e
xtract_fraction_term
s
],
OP_POW
:
[
match_multiply_exponents
,
match_duplicate_exponent
,
match_raised_fraction
,
match_remove_negative_exponent
,
match_exponent_to_root
,
match_extend_exponent
,
...
...
src/rules/fractions.py
View file @
08555af7
...
...
@@ -180,7 +180,7 @@ MESSAGES[constant_to_fraction] = \
def
match_multiply_fractions
(
node
):
"""
a / b * (c / d) -> ac / (bd)
a / b * c and
a, c in Z or (a = 1 and eval(
b) not in Z) -> ac / b
a / b * c and
(c in Z or eval(a /
b) not in Z) -> ac / b
"""
assert
node
.
is_op
(
OP_MUL
)
...
...
@@ -195,8 +195,9 @@ def match_multiply_fractions(node):
for
ab
,
c
in
product
(
fractions
,
others
):
a
,
b
=
ab
if
(
a
.
is_numeric
()
and
c
.
is_numeric
())
or
\
(
a
==
1
and
evals_to_numeric
(
b
)):
#if (a.is_numeric() and c.is_numeric()) or \
# (a == 1 and evals_to_numeric(b)):
if
c
.
is_numeric
()
or
not
evals_to_numeric
(
ab
):
p
.
append
(
P
(
node
,
multiply_with_fraction
,
(
scope
,
ab
,
c
)))
return
p
...
...
@@ -243,6 +244,9 @@ def match_divide_fractions(node):
Examples:
a / b / c -> a / (bc)
a / (b / c) -> ac / b
Note that:
a / b / (c / d) ->* ad / bd # chain test!
"""
assert
node
.
is_op
(
OP_DIV
)
...
...
@@ -262,9 +266,9 @@ def divide_fraction(root, args):
"""
a / b / c -> a / (bc)
"""
a
,
b
,
c
=
args
(
a
,
b
),
c
=
root
return
a
/
(
b
*
c
)
return
(
a
/
(
b
*
c
)).
negate
(
root
.
negated
)
MESSAGES
[
divide_fraction
]
=
_
(
'Move {3} to denominator of fraction {1} / {2}.'
)
...
...
@@ -274,36 +278,16 @@ def divide_by_fraction(root, args):
"""
a / (b / c) -> ac / b
"""
a
,
b
,
c
=
args
a
,
bc
=
root
b
,
c
=
bc
return
a
*
c
/
b
return
(
a
*
c
/
b
).
negate
(
root
.
negated
+
bc
.
negated
)
MESSAGES
[
divide_by_fraction
]
=
\
_
(
'Move {3} to nominator of fraction {1} / {2}.'
)
#def match_extract_divided_fractions(node):
# """
# Reduce divisions of fractions to a single fraction.
#
# Examples:
# a / b / c -> a / bc
# a / (b / c) -> ac / b
# # IMPLICIT: a / b / (c / d) ->* ad / bd -> validation test!
# """
# assert node.is_op(OP_DIV)
#
# nom, denom = node
# n_scope, d_scope = fraction_scopes(node)
# is_division = lambda n: n.is_op(OP_DIV)
# n_fractions, n_others = partition(is_division, n_scope)
# d_fractions, d_others = partition(is_division, d_scope)
#
#
# return []
def
fraction_scopes
(
node
):
"""
Get the multiplication scopes of the nominator and denominator of a
...
...
@@ -344,7 +328,7 @@ def is_power_combination(a, b):
return
a
==
b
def
match_e
qual_fraction_part
s
(
node
):
def
match_e
xtract_fraction_term
s
(
node
):
"""
Divide nominator and denominator by the same part.
...
...
@@ -357,6 +341,7 @@ def match_equal_fraction_parts(node):
#a ^ p * b / a -> a ^ p / a * b / 1
#a * b / a ^ q -> a / a ^ q * b / 1
"""
# TODO: ac / b -> a / b * c
assert
node
.
is_op
(
OP_DIV
)
nominator
,
denominator
=
node
...
...
@@ -369,31 +354,16 @@ def match_equal_fraction_parts(node):
# Look for matching parts in scopes
for
n
,
d
in
product
(
n_scope
,
d_scope
):
if
is_power_combination
(
n
,
d
):
p
.
append
(
P
(
N
,
extract_fraction_terms
,
(
n_scope
,
d_scope
,
n
,
d
)))
#for i, n in enumerate(n_scope):
# for j, d in enumerate(d_scope):
# if n.equals(d, ignore_negation=True):
# p.append(P(node, divide_fraction_parts,
# (negate(n, 0), n_scope, d_scope, i, j)))
# if n.is_op(OP_POW):
# a = n[0]
# if d == a or (d.is_op(OP_POW) and d[0] == a):
# # a ^ p * b / a -> a ^ p / a * b
# p.append(P(node, extract_divided_roots,
# (a, n_scope, d_scope, i, j)))
# elif d.is_op(OP_POW) and n == d[0]:
# # a * b / a ^ q -> a / a ^ q * b
# p.append(P(node, extract_divided_roots,
# (d[0], n_scope, d_scope, i, j)))
p
.
append
(
P
(
node
,
extract_fraction_terms
,
(
n_scope
,
d_scope
,
n
,
d
)))
return
p
def
extract_fraction_terms
(
root
,
args
):
"""
ab / a -> a / a * (b / 1)
a / (ba) -> a / a * (1 / b)
a * c / (ae) -> a / a * (c / e)
a ^ b * c / (a ^ d * e) -> a ^ b / a ^ d * (c / e)
"""
n_scope
,
d_scope
,
n
,
d
=
args
...
...
@@ -406,72 +376,9 @@ def extract_fraction_terms(root, args):
if
len
(
d_scope
)
==
1
:
d_scope
.
replace
(
d
,
L
(
1
))
else
:
d_scope
.
remove
(
n
)
d_scope
.
remove
(
d
)
return
n
/
d
*
(
n_scope
.
as_nary_node
()
/
d_scope
.
as_nary_node
())
#def remove_from_scopes(n_scope, d_scope, i, j):
# a_n, a_d = n_scope[i], d_scope[j]
#
# del n_scope[i]
# del d_scope[j]
#
# if not n_scope:
# # Last element of nominator scope, replace by 1
# nom = L(1)
# elif len(n_scope) == 1:
# # Only one element left, no multiplication
# nom = n_scope[0]
# else:
# # Still a multiplication
# nom = nary_node('*', n_scope)
#
# if not d_scope:
# denom = L(1)
# elif len(n_scope) == 1:
# denom = d_scope[0]
# else:
# denom = nary_node('*', d_scope)
#
# return a_n, a_d, nom, denom
#
#
#def divide_fraction_parts(root, args):
# """
# Divide nominator and denominator by the same part.
#
# Examples:
# ab / (ac) -> b / c
# ab / a -> b / 1
# a / (ab) -> 1 / b
# -ab / a -> -b / 1
# """
# a, n_scope, d_scope, i, j = args
# n, d = root
# a_n, a_d, nom, denom = remove_from_scopes(n_scope, d_scope, i, j)
#
# # Move negation of removed part to nominator and denominator
# return nom.negate(n.negated + a_n.negated) \
# / denom.negate(d.negated + a_d.negated)
#
#
#MESSAGES[divide_fraction_parts] = \
# _('Divide nominator and denominator in {0} by {1}.')
#
#
#def extract_divided_roots(root, args):
# """
# a ^ p * b / a ^ q -> a ^ p / a ^ q * b / 1
# a ^ p * b / a -> a ^ p / a * b / 1
# a * b / a ^ q -> a / a ^ q * b / 1
# """
# a, n_scope, d_scope, i, j = args
# n, d = root
# ap, aq, nom, denom = remove_from_scopes(n_scope, d_scope, i, j)
#
# return ap / aq * nom.negate(n.negated) / denom.negate(d.negated)
#
#
#MESSAGES[extract_divided_roots] = \
# _('Extract the root {1} from nominator and denominator in {0}.')
MESSAGES
[
extract_fraction_terms
]
=
_
(
'Extract {3} / {4} from fraction {0}.'
)
src/rules/groups.py
View file @
08555af7
from
itertools
import
combinations
from
.utils
import
evals_to_numeric
from
..node
import
ExpressionLeaf
as
Leaf
,
Scope
,
OP_ADD
,
OP_MUL
,
nary_node
,
\
negate
from
..possibilities
import
Possibility
as
P
,
MESSAGES
...
...
@@ -35,9 +36,7 @@ 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
():
if
evals_to_numeric
(
sub_node
):
others
=
[
n_scope
[
j
]
for
j
in
range
(
i
)
+
range
(
i
+
1
,
l
)]
if
len
(
others
)
==
1
:
...
...
tests/test_rules_fractions.py
View file @
08555af7
...
...
@@ -2,9 +2,9 @@ from src.rules.fractions import match_constant_division, division_by_one, \
division_of_zero
,
division_by_self
,
match_add_fractions
,
\
equalize_denominators
,
add_nominators
,
match_multiply_fractions
,
\
multiply_fractions
,
multiply_with_fraction
,
match_divide_fractions
,
\
divide_fraction
,
divide_by_fraction
,
match_e
qual_fraction_part
s
,
\
divide_fraction
,
divide_by_fraction
,
match_e
xtract_fraction_term
s
,
\
constant_to_fraction
,
extract_fraction_terms
from
src.node
import
Scope
from
src.node
import
ExpressionNode
as
N
,
Scope
,
OP_MUL
from
src.possibilities
import
Possibility
as
P
from
tests.rulestestcase
import
RulesTestCase
,
tree
...
...
@@ -181,119 +181,82 @@ class TestRulesFractions(RulesTestCase):
(
a
,
b
),
c
=
root
=
tree
(
'a / b / c'
)
self
.
assertEqual
(
divide_fraction
(
root
,
(
a
,
b
,
c
)),
a
/
(
b
*
c
))
(
a
,
b
),
c
=
root
=
tree
(
'-a / b / c'
)
self
.
assertEqual
(
divide_fraction
(
root
,
(
a
,
b
,
c
)),
-
(
a
/
(
b
*
c
)))
root
=
tree
(
'a / b / -c'
)
self
.
assertEqual
(
divide_fraction
(
root
,
(
a
,
b
,
c
)),
a
/
(
b
*
-
c
))
def
test_divide_by_fraction
(
self
):
a
,
(
b
,
c
)
=
root
=
tree
(
'a / (b / c)'
)
self
.
assertEqual
(
divide_by_fraction
(
root
,
(
a
,
b
,
c
)),
a
*
c
/
b
)
def
test_match_equal_fraction_parts
(
self
):
a
,
(
b
,
c
)
=
root
=
tree
(
'-a / (b / c)'
)
self
.
assertEqual
(
divide_by_fraction
(
root
,
(
a
,
b
,
c
)),
-
(
a
*
c
/
b
))
root
=
tree
(
'a / -(b / c)'
)
self
.
assertEqual
(
divide_by_fraction
(
root
,
(
a
,
b
,
c
)),
-
(
a
*
c
/
b
))
def
test_match_extract_fraction_terms
(
self
):
root
,
a
,
b
,
c
=
tree
(
'ab / (ca), a, b, c'
)
n
,
d
=
root
self
.
assertEqualPos
(
match_e
qual_fraction_part
s
(
root
),
self
.
assertEqualPos
(
match_e
xtract_fraction_term
s
(
root
),
[
P
(
root
,
extract_fraction_terms
,
(
Scope
(
n
),
Scope
(
d
),
a
,
a
))])
lscp
=
lambda
l
:
Scope
(
N
(
OP_MUL
,
l
))
n
,
d
=
root
=
tree
(
'ab / a'
)
self
.
assertEqualPos
(
match_e
qual_fraction_part
s
(
root
),
[
P
(
root
,
extract_fraction_terms
,
(
Scope
(
n
),
Scope
(
d
),
a
,
a
))])
self
.
assertEqualPos
(
match_e
xtract_fraction_term
s
(
root
),
[
P
(
root
,
extract_fraction_terms
,
(
Scope
(
n
),
lscp
(
d
),
a
,
a
))])
n
,
d
=
root
=
tree
(
'a / (ab)'
)
self
.
assertEqualPos
(
match_e
qual_fraction_part
s
(
root
),
[
P
(
root
,
extract_fraction_terms
,
(
Scope
(
n
),
Scope
(
d
),
a
,
a
))])
self
.
assertEqualPos
(
match_e
xtract_fraction_term
s
(
root
),
[
P
(
root
,
extract_fraction_terms
,
(
lscp
(
n
),
Scope
(
d
),
a
,
a
))])
n
,
d
=
root
=
tree
(
'abc / (cba)'
)
self
.
assertEqualPos
(
match_e
qual_fraction_part
s
(
root
),
[
P
(
root
,
extract_fraction_terms
,
(
Scope
(
n
),
s
cope
(
d
),
a
,
a
)),
P
(
root
,
extract_fraction_terms
,
(
Scope
(
n
),
s
cope
(
d
),
b
,
b
)),
P
(
root
,
extract_fraction_terms
,
(
Scope
(
n
),
s
cope
(
d
),
c
,
c
))])
self
.
assertEqualPos
(
match_e
xtract_fraction_term
s
(
root
),
[
P
(
root
,
extract_fraction_terms
,
(
Scope
(
n
),
S
cope
(
d
),
a
,
a
)),
P
(
root
,
extract_fraction_terms
,
(
Scope
(
n
),
S
cope
(
d
),
b
,
b
)),
P
(
root
,
extract_fraction_terms
,
(
Scope
(
n
),
S
cope
(
d
),
c
,
c
))])
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
),
[
p
(
root
,
extract_fraction_terms
,
(
a
,
[
ap
,
b
],
[
aq
],
0
,
0
))])
(
a
,
b
),
aq
=
root
=
tree
(
'a * b / a ^ q'
)
self
.
assertequalpos
(
match_equal_fraction_parts
(
root
),
[
p
(
root
,
extract_fraction_terms
,
(
a
,
[
a
,
b
],
[
aq
],
0
,
0
))])
(
ap
,
b
),
a
=
root
=
tree
(
'a ^ p * b / a'
)
self
.
assertequalpos
(
match_equal_fraction_parts
(
root
),
[
p
(
root
,
extract_fraction_terms
,
(
a
,
[
ap
,
b
],
[
a
],
0
,
0
))])
#def test_match_equal_fraction_parts(self):
# (a, b), (c, a) = root = tree('ab / (ca)')
# self.assertEqualPos(match_equal_fraction_parts(root),
# [P(root, divide_fraction_parts, (a, [a, b], [c, a], 0, 1))])
# (a, b), a = root = tree('ab / a')
# self.assertEqualPos(match_equal_fraction_parts(root),
# [P(root, divide_fraction_parts, (a, [a, b], [a], 0, 0))])
# a, (a, b) = root = tree('a / (ab)')
# self.assertEqualPos(match_equal_fraction_parts(root),
# [P(root, divide_fraction_parts, (a, [a], [a, b], 0, 0))])
# root = tree('abc / (cba)')
# ((a, b), c) = root[0]
# s0, s1 = [a, b, c], [c, b, a]
# self.assertEqualPos(match_equal_fraction_parts(root),
# [P(root, divide_fraction_parts, (a, s0, s1, 0, 2)),
# 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))])
# (ap, b), aq = root = tree('a ^ p * b / a ^ q')
# self.assertEqualPos(match_equal_fraction_parts(root),
# [P(root, extract_divided_roots, (a, [ap, b], [aq], 0, 0))])
# (a, b), aq = root = tree('a * b / a ^ q')
# self.assertEqualPos(match_equal_fraction_parts(root),
# [P(root, extract_divided_roots, (a, [a, b], [aq], 0, 0))])
# (ap, b), a = root = tree('a ^ p * b / a')
# self.assertEqualPos(match_equal_fraction_parts(root),
# [P(root, extract_divided_roots, (a, [ap, b], [a], 0, 0))])
#def test_divide_fraction_parts(self):
# (a, b), (c, a) = root = tree('ab / (ca)')
# result = divide_fraction_parts(root, (a, [a, b], [c, a], 0, 1))
# self.assertEqual(result, b / c)
# (a, b), a = root = tree('ab / a')
# result = divide_fraction_parts(root, (a, [a, b], [a], 0, 0))
# self.assertEqual(result, b / 1)
# root, l1 = tree('a / (ab), 1')
# a, (a, b) = root
# result = divide_fraction_parts(root, (a, [a], [a, b], 0, 0))
# self.assertEqual(result, l1 / b)
# root = tree('abc / (cba)')
# ((a, b), c) = root[0]
# result = divide_fraction_parts(root, (a, [a, b, c], [c, b, a], 0, 2))
# self.assertEqual(result, b * c / (c * b))
# result = divide_fraction_parts(root, (b, [a, b, c], [c, b, a], 1, 1))
# self.assertEqual(result, a * c / (c * a))
# 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('-ab / a')
# result = divide_fraction_parts(root, (a, [-a, b], [a], 0, 0))
# self.assertEqual(result, -b / 1)
#def test_extract_divided_roots(self):
# r, a = tree('a ^ p * b / a ^ q, a')
# ((a, p), b), (a, q) = (ap, b), aq = r
# self.assertEqual(extract_divided_roots(r, (a, [ap, b], [aq], 0, 0)),
# a ** p / a ** q * b / 1)
# r = tree('a * b / a ^ q, a')
# self.assertEqual(extract_divided_roots(r, (a, [a, b], [aq], 0, 0)),
# a / a ** q * b / 1)
# r = tree('a ^ p * b / a, a')
# self.assertEqual(extract_divided_roots(r, (a, [ap, b], [a], 0, 0)),
# a ** p / a * b / 1)
self
.
assertEqualPos
(
match_extract_fraction_terms
(
root
),
[])
(
ap
,
b
),
aq
=
n
,
d
=
root
=
tree
(
'a ^ p * b / a ^ q'
)
self
.
assertEqualPos
(
match_extract_fraction_terms
(
root
),
[
P
(
root
,
extract_fraction_terms
,
(
Scope
(
n
),
lscp
(
d
),
ap
,
aq
))])
(
a
,
b
),
aq
=
n
,
d
=
root
=
tree
(
'a * b / a ^ q'
)
self
.
assertEqualPos
(
match_extract_fraction_terms
(
root
),
[
P
(
root
,
extract_fraction_terms
,
(
Scope
(
n
),
lscp
(
d
),
a
,
aq
))])
(
ap
,
b
),
a
=
n
,
d
=
root
=
tree
(
'a ^ p * b / a'
)
self
.
assertEqualPos
(
match_extract_fraction_terms
(
root
),
[
P
(
root
,
extract_fraction_terms
,
(
Scope
(
n
),
lscp
(
d
),
ap
,
a
))])
def
test_extract_fraction_terms_basic
(
self
):
root
,
expect
=
tree
(
'ab / (ca), a / a * (b / c)'
)
n
,
d
=
root
self
.
assertEqual
(
extract_fraction_terms
(
root
,
(
Scope
(
n
),
Scope
(
d
),
n
[
0
],
d
[
1
])),
expect
)
def
test_extract_fraction_terms_leaf
(
self
):
root
,
expect
=
tree
(
'ba / a, a / a * (b / 1)'
)
n
,
d
=
root
self
.
assertEqual
(
extract_fraction_terms
(
root
,
(
Scope
(
n
),
Scope
(
N
(
OP_MUL
,
d
)),
n
[
1
],
d
)),
expect
)
root
,
expect
=
tree
(
'a / (ab), a / a * (1 / b)'
)
n
,
d
=
root
self
.
assertEqual
(
extract_fraction_terms
(
root
,
(
Scope
(
N
(
OP_MUL
,
n
)),
Scope
(
d
),
n
,
d
[
0
])),
expect
)
def
test_extract_fraction_terms_chain
(
self
):
self
.
assertRewrite
([
'a ^ 3 * 4 / (a ^ 2 * 5)'
,
'a ^ 3 / a ^ 2 * (4 / 5)'
,
'a ^ (3 - 2)(4 / 5)'
,
'a ^ 1 * (4 / 5)'
,
'a(4 / 5)'
,
# FIXME: '4 / 5 * a',
])
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