Skip to content
Snippets Groups Projects
Commit b6bd65db authored by Taddeus Kroes's avatar Taddeus Kroes
Browse files

Added some new rules for fractions.

parent 7c142aff
No related branches found
No related tags found
No related merge requests found
......@@ -10,7 +10,8 @@ from .numerics import match_add_numerics, match_divide_numerics, \
match_multiply_numerics, match_multiply_zero, match_multiply_one, \
match_raise_numerics
from .fractions import match_constant_division, match_add_constant_fractions, \
match_expand_and_add_fractions, match_multiply_fractions
match_expand_and_add_fractions, match_multiply_fractions, \
match_equal_fraction_parts
from .negation import match_negated_factor, match_negate_polynome, \
match_negated_division
from .sort import match_sort_multiplicants
......@@ -25,7 +26,8 @@ RULES = {
match_negated_factor, match_multiply_one,
match_sort_multiplicants, match_multiply_fractions],
OP_DIV: [match_subtract_exponents, match_divide_numerics,
match_constant_division, match_negated_division],
match_constant_division, match_negated_division,
match_equal_fraction_parts],
OP_POW: [match_multiply_exponents, match_duplicate_exponent,
match_raised_fraction, match_remove_negative_exponent,
match_exponent_to_root, match_extend_exponent,
......
from itertools import combinations, product
from .utils import least_common_multiple, partition
from ..node import ExpressionLeaf as L, Scope, negate, OP_DIV, OP_ADD, OP_MUL
from ..node import ExpressionLeaf as L, Scope, negate, OP_DIV, OP_ADD, \
OP_MUL, nary_node
from ..possibilities import Possibility as P, MESSAGES
from ..translate import _
......@@ -226,3 +227,84 @@ def multiply_with_fraction(root, args):
MESSAGES[multiply_with_fraction] = _('Multiply {2} with fraction {3}.')
def match_equal_fraction_parts(node):
"""
Divide nominator and denominator by the same part.
Examples:
ab / (ac) -> b / c
ab / a -> b / 1
a / (ab) -> 1 / b
"""
assert node.is_op(OP_DIV)
nominator, denominator = node
if nominator.is_op(OP_MUL):
n_scope = list(Scope(nominator))
else:
n_scope = [nominator]
if denominator.is_op(OP_MUL):
d_scope = list(Scope(denominator))
else:
d_scope = [denominator]
p = []
# Look for in scope
for i, n in enumerate(n_scope):
for j, d in enumerate(d_scope):
if n == d:
p.append(P(node, divide_fraction_parts,
(n, n_scope, d_scope, i, j)))
return p
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
"""
a, n_scope, d_scope, i, j = args
n, d = root
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 nom.negate(n.negated) / denom.negate(d.negated)
MESSAGES[divide_fraction_parts] = \
_('Divide nominator and denominator in {0} by {1}')
def match_multiplied_power_division(node):
"""
a ^ p * b / a ^ q -> a ^ p / a ^ q * b
"""
assert node.is_op(OP_DIV)
......@@ -64,8 +64,11 @@ class TestLeidenOefenopgaveV12(TestCase):
'aa ^ 6 / b ^ 3 * b ^ 2',
'a ^ (1 + 6) / b ^ 3 * b ^ 2',
'a ^ 7 / b ^ 3 * b ^ 2',
# FIXME: 'b ^ 2 * a ^ 7 / b ^ 3',
'b ^ 2 * a ^ 7 / b ^ 3',
# FIXME: 'b ^ 2 / b ^ 3 * a ^ 7',
# FIXME: 'b ^ (2 - 3) * a ^ 7',
# FIXME: 'b ^ 5 * a ^ 7',
# FIXME: 'a ^ 7 * b ^ 5',
])
def test_2_b(self):
......
from src.rules.fractions import match_constant_division, division_by_one, \
division_of_zero, division_by_self, match_add_constant_fractions, \
equalize_denominators, add_nominators, match_multiply_fractions, \
multiply_fractions, multiply_with_fraction
multiply_fractions, multiply_with_fraction, \
match_equal_fraction_parts, divide_fraction_parts
from src.node import Scope
from src.possibilities import Possibility as P
from tests.rulestestcase import RulesTestCase, tree
......@@ -144,3 +145,47 @@ class TestRulesFractions(RulesTestCase):
(ab, e), cd = root = tree('a / b * e * (c / d)')
self.assertEqual(multiply_fractions(root, (Scope(root), ab, cd)),
a * c / (b * d) * e)
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))])
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))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment