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] = \ ...@@ -288,7 +288,7 @@ MESSAGES[divide_by_fraction] = \
_('Move {3} to nominator of fraction {1} / {2}.') _('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 Check if two nodes are powers that can be combined in a fraction, for
example: example:
...@@ -297,8 +297,6 @@ def is_power_combination(pair): ...@@ -297,8 +297,6 @@ def is_power_combination(pair):
a^2 and a^2 a^2 and a^2
a^2 and a a^2 and a
""" """
a, b = pair
if a.is_power(): if a.is_power():
a = a[0] a = a[0]
...@@ -358,8 +356,15 @@ def match_extract_fraction_terms(node): ...@@ -358,8 +356,15 @@ def match_extract_fraction_terms(node):
return p return p
# a ^ b * c / (a ^ d * e) # a ^ b * c / (a ^ d * e)
for n, d in filter(is_power_combination, product(n_scope, d_scope)): for n, d in product(n_scope, d_scope):
p.append(P(node, extract_fraction_terms, (n_scope, d_scope, n, d))) 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 return p
...@@ -379,9 +384,6 @@ MESSAGES[extract_nominator_term] = \ ...@@ -379,9 +384,6 @@ MESSAGES[extract_nominator_term] = \
def extract_fraction_terms(root, args): 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) a ^ b * c / (a ^ d * e) -> a ^ b / a ^ d * (c / e)
""" """
n_scope, d_scope, n, d = args n_scope, d_scope, n, d = args
...@@ -394,6 +396,27 @@ def extract_fraction_terms(root, args): ...@@ -394,6 +396,27 @@ def extract_fraction_terms(root, args):
MESSAGES[extract_fraction_terms] = _('Extract {3} / {4} from fraction {0}.') 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): def match_division_in_denominator(node):
""" """
a / (b / c + d) -> (ca) / (c(b / c + d)) a / (b / c + d) -> (ca) / (c(b / c + d))
......
...@@ -8,7 +8,7 @@ from .derivatives import chain_rule ...@@ -8,7 +8,7 @@ from .derivatives import chain_rule
from .negation import double_negation, negated_factor, negated_nominator, \ from .negation import double_negation, negated_factor, negated_nominator, \
negated_denominator, negated_zero negated_denominator, negated_zero
from .factors import expand_double, expand_single 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 add_nominators
from .integrals import factor_out_constant, integrate_variable_root from .integrals import factor_out_constant, integrate_variable_root
from .powers import remove_power_of_one from .powers import remove_power_of_one
...@@ -68,7 +68,7 @@ RELATIVE = [ ...@@ -68,7 +68,7 @@ RELATIVE = [
# Prevent cycles that are caused by multiplication reductions when # Prevent cycles that are caused by multiplication reductions when
# splitting up fractions # splitting up fractions
(extract_fraction_terms, multiply_numerics), (divide_fraction_by_term, multiply_numerics),
# Prevent useless swapping when solving multiple equations # Prevent useless swapping when solving multiple equations
(substitute_variable, swap_sides), (substitute_variable, swap_sides),
......
...@@ -173,8 +173,6 @@ class TestLeidenOefenopgave(TestCase): ...@@ -173,8 +173,6 @@ class TestLeidenOefenopgave(TestCase):
self.assertRewrite([ self.assertRewrite([
'(7/3)(3/5)', '(7/3)(3/5)',
'(7 * 3) / (3 * 5)', '(7 * 3) / (3 * 5)',
'3 / 3 * 7 / 5',
'1 * 7 / 5',
'7 / 5', '7 / 5',
]) ])
......
...@@ -4,7 +4,8 @@ from src.rules.fractions import match_constant_division, division_by_one, \ ...@@ -4,7 +4,8 @@ from src.rules.fractions import match_constant_division, division_by_one, \
multiply_fractions, multiply_with_fraction, match_divide_fractions, \ multiply_fractions, multiply_with_fraction, match_divide_fractions, \
divide_fraction, divide_by_fraction, match_extract_fraction_terms, \ divide_fraction, divide_by_fraction, match_extract_fraction_terms, \
constant_to_fraction, extract_nominator_term, 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.node import ExpressionNode as N, Scope, OP_MUL
from src.possibilities import Possibility as P from src.possibilities import Possibility as P
from tests.rulestestcase import RulesTestCase, tree from tests.rulestestcase import RulesTestCase, tree
...@@ -202,23 +203,23 @@ class TestRulesFractions(RulesTestCase): ...@@ -202,23 +203,23 @@ class TestRulesFractions(RulesTestCase):
root, a, b, c = tree('(ab) / (ca), a, b, c') root, a, b, c = tree('(ab) / (ca), a, b, c')
n, d = root n, d = root
self.assertEqualPos(match_extract_fraction_terms(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)) lscp = lambda l: Scope(N(OP_MUL, l))
n, d = root = tree('(ab) / a') n, d = root = tree('(ab) / a')
self.assertEqualPos(match_extract_fraction_terms(root), 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)') n, d = root = tree('a / (ab)')
self.assertEqualPos(match_extract_fraction_terms(root), 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)') n, d = root = tree('(abc) / (cba)')
self.assertEqualPos(match_extract_fraction_terms(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)),
P(root, extract_fraction_terms, (Scope(n), Scope(d), b, b)), P(root, divide_fraction_by_term, (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), c, c))])
root = tree('a / a') root = tree('a / a')
self.assertEqualPos(match_extract_fraction_terms(root), []) self.assertEqualPos(match_extract_fraction_terms(root), [])
...@@ -249,7 +250,7 @@ class TestRulesFractions(RulesTestCase): ...@@ -249,7 +250,7 @@ class TestRulesFractions(RulesTestCase):
n, d = root = tree('(2a) / 2') n, d = root = tree('(2a) / 2')
self.assertEqualPos(match_extract_fraction_terms(root), self.assertEqualPos(match_extract_fraction_terms(root),
[P(root, extract_nominator_term, (2, a)), [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): def test_extract_nominator_term(self):
root, expect = tree('(2a) / 3, 2 / 3 * a') root, expect = tree('(2a) / 3, 2 / 3 * a')
...@@ -286,6 +287,11 @@ class TestRulesFractions(RulesTestCase): ...@@ -286,6 +287,11 @@ class TestRulesFractions(RulesTestCase):
# FIXME: '4 / 5 * a', # 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): def test_match_division_in_denominator(self):
a, ((b, c), d) = root = tree('a / (b / c + d)') a, ((b, c), d) = root = tree('a / (b / c + d)')
self.assertEqualPos(match_division_in_denominator(root), self.assertEqualPos(match_division_in_denominator(root),
...@@ -312,8 +318,5 @@ class TestRulesFractions(RulesTestCase): ...@@ -312,8 +318,5 @@ class TestRulesFractions(RulesTestCase):
'(ab) / (a + a(-b / a))', '(ab) / (a + a(-b / a))',
'(ab) / (a - ab / a)', '(ab) / (a - ab / 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)', '(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