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

Improved elimination of terms in fraction (de)nominators.

parent 7e9c9993
No related branches found
No related tags found
No related merge requests found
......@@ -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)',
])
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