Commit 3d3792c3 authored by Taddeus Kroes's avatar Taddeus Kroes

Improved elimination of terms in fraction (de)nominators.

parent 7e9c9993
......@@ -288,7 +288,7 @@ MESSAGES[divide_by_fraction] = \
_('Move {3} to nominator of fraction {1} / {2}.')
def is_power_combination(pair):
def is_power_combination(a, b):
"""
Check if two nodes are powers that can be combined in a fraction, for
example:
......@@ -297,8 +297,6 @@ def is_power_combination(pair):
a^2 and a^2
a^2 and a
"""
a, b = pair
if a.is_power():
a = a[0]
......@@ -358,8 +356,15 @@ def match_extract_fraction_terms(node):
return p
# a ^ b * c / (a ^ d * e)
for n, d in filter(is_power_combination, product(n_scope, d_scope)):
p.append(P(node, extract_fraction_terms, (n_scope, d_scope, n, d)))
for n, d in product(n_scope, d_scope):
if n == d:
handler = divide_fraction_by_term
elif is_power_combination(n, d):
handler = extract_fraction_terms
else:
continue
p.append(P(node, handler, (n_scope, d_scope, n, d)))
return p
......@@ -379,9 +384,6 @@ MESSAGES[extract_nominator_term] = \
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
......@@ -394,6 +396,27 @@ def extract_fraction_terms(root, args):
MESSAGES[extract_fraction_terms] = _('Extract {3} / {4} from fraction {0}.')
def divide_fraction_by_term(root, args):
"""
ab / a -> b
a / (ba) -> 1 / b
a * c / (ae) -> c / e
"""
n_scope, d_scope, n, d = args
nom = remove_from_mult_scope(n_scope, n)
d_scope.remove(d)
if not len(d_scope):
return negate(nom, root.negated)
return negate(nom / d_scope.as_nary_node(), root.negated)
MESSAGES[divide_fraction_by_term] = \
_('Divide nominator and denominator od {0} by {2}.')
def match_division_in_denominator(node):
"""
a / (b / c + d) -> (ca) / (c(b / c + d))
......
......@@ -8,7 +8,7 @@ from .derivatives import chain_rule
from .negation import double_negation, negated_factor, negated_nominator, \
negated_denominator, negated_zero
from .factors import expand_double, expand_single
from .fractions import multiply_with_fraction, extract_fraction_terms, \
from .fractions import multiply_with_fraction, divide_fraction_by_term, \
add_nominators
from .integrals import factor_out_constant, integrate_variable_root
from .powers import remove_power_of_one
......@@ -68,7 +68,7 @@ RELATIVE = [
# Prevent cycles that are caused by multiplication reductions when
# splitting up fractions
(extract_fraction_terms, multiply_numerics),
(divide_fraction_by_term, multiply_numerics),
# Prevent useless swapping when solving multiple equations
(substitute_variable, swap_sides),
......
......@@ -173,8 +173,6 @@ class TestLeidenOefenopgave(TestCase):
self.assertRewrite([
'(7/3)(3/5)',
'(7 * 3) / (3 * 5)',
'3 / 3 * 7 / 5',
'1 * 7 / 5',
'7 / 5',
])
......
......@@ -4,7 +4,8 @@ from src.rules.fractions import match_constant_division, division_by_one, \
multiply_fractions, multiply_with_fraction, match_divide_fractions, \
divide_fraction, divide_by_fraction, match_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
from src.node import ExpressionNode as N, Scope, OP_MUL
from src.possibilities import Possibility as P
from tests.rulestestcase import RulesTestCase, tree
......@@ -202,23 +203,23 @@ class TestRulesFractions(RulesTestCase):
root, a, b, c = tree('(ab) / (ca), a, b, c')
n, d = root
self.assertEqualPos(match_extract_fraction_terms(root),
[P(root, extract_fraction_terms, (Scope(n), Scope(d), a, a))])
[P(root, divide_fraction_by_term, (Scope(n), Scope(d), a, a))])
lscp = lambda l: Scope(N(OP_MUL, l))
n, d = root = tree('(ab) / a')
self.assertEqualPos(match_extract_fraction_terms(root),
[P(root, extract_fraction_terms, (Scope(n), lscp(d), a, a))])
[P(root, divide_fraction_by_term, (Scope(n), lscp(d), a, a))])
n, d = root = tree('a / (ab)')
self.assertEqualPos(match_extract_fraction_terms(root),
[P(root, extract_fraction_terms, (lscp(n), Scope(d), a, a))])
[P(root, divide_fraction_by_term, (lscp(n), Scope(d), a, a))])
n, d = root = tree('(abc) / (cba)')
self.assertEqualPos(match_extract_fraction_terms(root),
[P(root, extract_fraction_terms, (Scope(n), Scope(d), a, a)),
P(root, extract_fraction_terms, (Scope(n), Scope(d), b, b)),
P(root, extract_fraction_terms, (Scope(n), Scope(d), c, c))])
[P(root, divide_fraction_by_term, (Scope(n), Scope(d), a, a)),
P(root, divide_fraction_by_term, (Scope(n), Scope(d), b, b)),
P(root, divide_fraction_by_term, (Scope(n), Scope(d), c, c))])
root = tree('a / a')
self.assertEqualPos(match_extract_fraction_terms(root), [])
......@@ -249,7 +250,7 @@ class TestRulesFractions(RulesTestCase):
n, d = root = tree('(2a) / 2')
self.assertEqualPos(match_extract_fraction_terms(root),
[P(root, extract_nominator_term, (2, a)),
P(root, extract_fraction_terms, (Scope(n), lscp(d), 2, 2))])
P(root, divide_fraction_by_term, (Scope(n), lscp(d), 2, 2))])
def test_extract_nominator_term(self):
root, expect = tree('(2a) / 3, 2 / 3 * a')
......@@ -286,6 +287,11 @@ class TestRulesFractions(RulesTestCase):
# FIXME: '4 / 5 * a',
])
def test_divide_fraction_by_term(self):
(ab, a), expect = root = tree('(ab) / a, b')
args = Scope(ab), Scope(N(OP_MUL, a)), ab[0], a
self.assertEqual(divide_fraction_by_term(root, args), expect)
def test_match_division_in_denominator(self):
a, ((b, c), d) = root = tree('a / (b / c + d)')
self.assertEqualPos(match_division_in_denominator(root),
......@@ -312,8 +318,5 @@ class TestRulesFractions(RulesTestCase):
'(ab) / (a + a(-b / a))',
'(ab) / (a - ab / a)',
'(ab) / (a - (ab) / a)',
'(ab) / (a - a / a * b / 1)',
'(ab) / (a - 1b / 1)',
'(ab) / (a - 1b)',
'(ab) / (a - b)',
])
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment