Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
T
trs
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Taddeüs Kroes
trs
Commits
08555af7
Commit
08555af7
authored
13 years ago
by
Taddeus Kroes
Browse files
Options
Downloads
Patches
Plain Diff
Applied most of the new fraction rules.
parent
7a9605a7
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
src/rules/__init__.py
+2
-2
2 additions, 2 deletions
src/rules/__init__.py
src/rules/fractions.py
+22
-115
22 additions, 115 deletions
src/rules/fractions.py
src/rules/groups.py
+2
-3
2 additions, 3 deletions
src/rules/groups.py
tests/test_rules_fractions.py
+66
-103
66 additions, 103 deletions
tests/test_rules_fractions.py
with
92 additions
and
223 deletions
src/rules/__init__.py
+
2
−
2
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
,
...
...
This diff is collapsed.
Click to expand it.
src/rules/fractions.py
+
22
−
115
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
)
...
...
@@ -260,11 +264,11 @@ def match_divide_fractions(node):
def
divide_fraction
(
root
,
args
):
"""
a / b / c
-> a / (bc)
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}.
'
)
...
...
@@ -272,38 +276,18 @@ MESSAGES[divide_fraction] = _('Move {3} to denominator of fraction {1} / {2}.')
def
divide_by_fraction
(
root
,
args
):
"""
a / (b / c)
-> ac / b
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}.
'
)
This diff is collapsed.
Click to expand it.
src/rules/groups.py
+
2
−
3
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
:
...
...
This diff is collapsed.
Click to expand it.
tests/test_rules_fractions.py
+
66
−
103
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',
])
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment