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

Added some more fraction rewrite rules.

parent f46cf729
No related branches found
No related tags found
No related merge requests found
......@@ -2,7 +2,7 @@ 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, nary_node, negate
OP_MUL, OP_POW, nary_node, negate
from ..possibilities import Possibility as P, MESSAGES
from ..translate import _
......@@ -235,6 +235,12 @@ def match_equal_fraction_parts(node):
ab / (ac) -> b / c
ab / a -> b / 1
a / (ab) -> 1 / b
If the same root appears in both nominator and denominator, extrct it so
that it can be reduced to a single power by power division rules.
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
"""
assert node.is_op(OP_DIV)
......@@ -252,28 +258,29 @@ def match_equal_fraction_parts(node):
p = []
# Look for in scope
# Look for matching parts in scopes
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)))
return p
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)))
def divide_fraction_parts(root, args):
"""
Divide nominator and denominator by the same part.
return p
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
def remove_from_scopes(n_scope, d_scope, i, j):
a_n, a_d = n_scope[i], d_scope[j]
del n_scope[i]
......@@ -296,17 +303,39 @@ def divide_fraction_parts(root, args):
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}')
_('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)
def extract_divided_roots(root, args):
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] = \
_('Extrct the root {1} from nominator and denominator in {0}.')
......@@ -2,7 +2,8 @@ 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, \
match_equal_fraction_parts, divide_fraction_parts
match_equal_fraction_parts, divide_fraction_parts, \
extract_divided_roots
from src.node import Scope
from src.possibilities import Possibility as P
from tests.rulestestcase import RulesTestCase, tree
......@@ -171,6 +172,18 @@ class TestRulesFractions(RulesTestCase):
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))
......@@ -197,3 +210,17 @@ class TestRulesFractions(RulesTestCase):
(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)
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