Commit 0862806e authored by Taddeus Kroes's avatar Taddeus Kroes

Added a basic sorting rule and applied it to the existing unit tests.

parent d779bea2
......@@ -11,13 +11,15 @@ from .fractions import match_constant_division, match_add_constant_fractions, \
match_expand_and_add_fractions
from .negation import match_negated_factor, match_negate_polynome, \
match_negated_division
from .sort import match_sort_multiplicants
RULES = {
OP_ADD: [match_add_numerics, match_add_constant_fractions,
match_combine_groups],
OP_MUL: [match_multiply_numerics, match_expand, match_add_exponents,
match_expand_and_add_fractions, match_multiply_zero,
match_negated_factor, match_multiply_one],
match_negated_factor, match_multiply_one,
match_sort_multiplicants],
OP_DIV: [match_subtract_exponents, match_divide_numerics,
match_constant_division, match_negated_division],
OP_POW: [match_multiply_exponents, match_duplicate_exponent,
......
from itertools import product, combinations
from ..node import Scope, OP_ADD, OP_MUL
from ..possibilities import Possibility as P, MESSAGES
from ..translate import _
def match_sort_multiplicants(node):
"""
Sort multiplicant factors by swapping
x * 2 -> 2x
"""
assert node.is_op(OP_MUL)
p = []
scope = Scope(node)
for i, n in enumerate(scope[1:]):
left_nb = scope[i]
if n.is_numeric() and not left_nb.is_numeric():
p.append(P(node, move_constant, (scope, n, left_nb)))
return p
def move_constant(root, args):
scope, constant, destination = args
scope.replace(destination, constant * destination)
scope.remove(constant)
return scope.as_nary_node()
MESSAGES[move_constant] = \
_('Move constant {2} to the left of the multiplication {0}.')
......@@ -4,10 +4,10 @@ from tests.rulestestcase import RulesTestCase as TestCase, rewrite
class TestLeidenOefenopgave(TestCase):
def test_1_1(self):
for chain in [['-5(x2 - 3x + 6)', '-5(x ^ 2 - 3x) - 5 * 6',
'-5 * x ^ 2 - 5 * -3x - 5 * 6',
'-5 * x ^ 2 - -15x - 5 * 6',
'-5 * x ^ 2 + 15x - 5 * 6',
'-5 * x ^ 2 + 15x - 30',
'-5x ^ 2 - 5 * -3x - 5 * 6',
'-5x ^ 2 - -15x - 5 * 6',
'-5x ^ 2 + 15x - 5 * 6',
'-5x ^ 2 + 15x - 30',
],
]:
self.assertRewrite(chain)
......@@ -15,11 +15,11 @@ class TestLeidenOefenopgave(TestCase):
return
for exp, solution in [
('-5(x2 - 3x + 6)', '-30 + 15 * x - 5 * x ^ 2'),
('(x+1)^2', 'x ^ 2 + 2 * x + 1'),
('(x-1)^2', 'x ^ 2 - 2 * x + 1'),
('(2x+x)*x', '3 * x ^ 2'),
('-2(6x-4)^2*x', '-72 * x^3 + 96 * x ^ 2 + 32 * x'),
('-5(x2 - 3x + 6)', '-30 + 15x - 5x ^ 2'),
('(x+1)^2', 'x ^ 2 + 2x + 1'),
('(x-1)^2', 'x ^ 2 - 2x + 1'),
('(2x+x)*x', '3x ^ 2'),
('-2(6x-4)^2*x', '-72x ^ 3 + 96x ^ 2 + 32x'),
('(4x + 5) * -(5 - 4x)', '16x^2 - 25'),
]:
self.assertEqual(str(rewrite(exp)), solution)
......@@ -36,20 +36,21 @@ class TestLeidenOefenopgave(TestCase):
'(x ^ 2 + 2x + 1 * 1)(x + 1)',
'(x ^ 2 + 2x + 1)(x + 1)',
'(x ^ 2 + 2x)x + (x ^ 2 + 2x) * 1 + 1x + 1 * 1',
'x * x ^ 2 + x * 2x + (x ^ 2 + 2x) * 1 + 1x + 1 * 1',
'xx ^ 2 + x * 2x + (x ^ 2 + 2x) * 1 + 1x + 1 * 1',
'x ^ (1 + 2) + x * 2x + (x ^ 2 + 2x) * 1 + 1x + 1 * 1',
'x ^ 3 + x * 2x + (x ^ 2 + 2x) * 1 + 1x + 1 * 1',
'x ^ 3 + x ^ (1 + 1) * 2 + (x ^ 2 + 2x) * 1 + 1x + 1 * 1',
'x ^ 3 + x ^ 2 * 2 + (x ^ 2 + 2x) * 1 + 1x + 1 * 1',
'x ^ 3 + x ^ 2 * 2 + 1 * x ^ 2 + 1 * 2x + 1x + 1 * 1',
'x ^ 3 + x ^ 2 * 2 + x ^ 2 + 1 * 2x + 1x + 1 * 1',
'x ^ 3 + (2 + 1) * x ^ 2 + 1 * 2x + 1x + 1 * 1',
'x ^ 3 + 3 * x ^ 2 + 1 * 2x + 1x + 1 * 1',
'x ^ 3 + 3 * x ^ 2 + 2x + 1x + 1 * 1',
'x ^ 3 + 3 * x ^ 2 + 2x + x + 1 * 1',
'x ^ 3 + 3 * x ^ 2 + (2 + 1)x + 1 * 1',
'x ^ 3 + 3 * x ^ 2 + 3x + 1 * 1',
'x ^ 3 + 3 * x ^ 2 + 3x + 1',
'x ^ 3 + 2xx + (x ^ 2 + 2x) * 1 + 1x + 1 * 1',
'x ^ 3 + 2x ^ (1 + 1) + (x ^ 2 + 2x) * 1 + 1x + 1 * 1',
'x ^ 3 + 2x ^ 2 + (x ^ 2 + 2x) * 1 + 1x + 1 * 1',
'x ^ 3 + 2x ^ 2 + 1x ^ 2 + 1 * 2x + 1x + 1 * 1',
'x ^ 3 + 2x ^ 2 + x ^ 2 + 1 * 2x + 1x + 1 * 1',
'x ^ 3 + (2 + 1)x ^ 2 + 1 * 2x + 1x + 1 * 1',
'x ^ 3 + 3x ^ 2 + 1 * 2x + 1x + 1 * 1',
'x ^ 3 + 3x ^ 2 + 2x + 1x + 1 * 1',
'x ^ 3 + 3x ^ 2 + 2x + x + 1 * 1',
'x ^ 3 + 3x ^ 2 + (2 + 1)x + 1 * 1',
'x ^ 3 + 3x ^ 2 + 3x + 1 * 1',
'x ^ 3 + 3x ^ 2 + 3x + 1',
]
]:
self.assertRewrite(chain)
......@@ -115,7 +116,7 @@ class TestLeidenOefenopgave(TestCase):
def test_1_5(self):
self.assertRewrite(['(2x + x)x', '(2 + 1)xx', '3xx',
'3 * x ^ (1 + 1)', '3 * x ^ 2'])
'3x ^ (1 + 1)', '3x ^ 2'])
def test_1_7(self):
self.assertRewrite(['(4x + 5) * -(5 - 4x)',
......@@ -124,14 +125,14 @@ class TestLeidenOefenopgave(TestCase):
'4x * -5 + 4x * 4x + 5 * -5 + 5 * 4x',
'-20x + 4x * 4x + 5 * -5 + 5 * 4x',
'-20x + 16xx + 5 * -5 + 5 * 4x',
'-20x + 16 * x ^ (1 + 1) + 5 * -5 + 5 * 4x',
'-20x + 16 * x ^ 2 + 5 * -5 + 5 * 4x',
'-20x + 16 * x ^ 2 - 25 + 5 * 4x',
'-20x + 16 * x ^ 2 - 25 + 20x',
'(-20 + 20)x + 16 * x ^ 2 - 25',
'0x + 16 * x ^ 2 - 25',
'0 + 16 * x ^ 2 - 25',
'-25 + 16 * x ^ 2'])
'-20x + 16x ^ (1 + 1) + 5 * -5 + 5 * 4x',
'-20x + 16x ^ 2 + 5 * -5 + 5 * 4x',
'-20x + 16x ^ 2 - 25 + 5 * 4x',
'-20x + 16x ^ 2 - 25 + 20x',
'(-20 + 20)x + 16x ^ 2 - 25',
'0x + 16x ^ 2 - 25',
'0 + 16x ^ 2 - 25',
'-25 + 16x ^ 2'])
# FIXME: '16 * x ^ 2 - 25'])
def test_2(self):
......
......@@ -4,7 +4,7 @@ from tests.rulestestcase import RulesTestCase as TestCase, rewrite
class TestLeidenOefenopgaveV12(TestCase):
def test_1_e(self):
self.assertRewrite([
'-2(6x - 4) ^ 2 * x',
'-2(6x - 4) ^ 2x',
'-2(6x - 4)(6x - 4)x',
'(-2 * 6x - 2 * -4)(6x - 4)x',
'(-12x - 2 * -4)(6x - 4)x',
......@@ -12,26 +12,27 @@ class TestLeidenOefenopgaveV12(TestCase):
'(-12x + 8)(6x - 4)x',
'(-12x * 6x - 12x * -4 + 8 * 6x + 8 * -4)x',
'(-72xx - 12x * -4 + 8 * 6x + 8 * -4)x',
'(-72 * x ^ (1 + 1) - 12x * -4 + 8 * 6x + 8 * -4)x',
'(-72 * x ^ 2 - 12x * -4 + 8 * 6x + 8 * -4)x',
'(-72 * x ^ 2 - -48x + 8 * 6x + 8 * -4)x',
'(-72 * x ^ 2 + 48x + 8 * 6x + 8 * -4)x',
'(-72 * x ^ 2 + 48x + 48x + 8 * -4)x',
'(-72 * x ^ 2 + (1 + 1) * 48x + 8 * -4)x',
'(-72 * x ^ 2 + 2 * 48x + 8 * -4)x',
'(-72 * x ^ 2 + 96x + 8 * -4)x',
'(-72 * x ^ 2 + 96x - 32)x',
'x(-72 * x ^ 2 + 96x) + x * -32',
'x * -72 * x ^ 2 + x * 96x + x * -32',
'-x * 72 * x ^ 2 + x * 96x + x * -32',
'-(x ^ (1 + 2)) * 72 + x * 96x + x * -32',
'-(x ^ 3) * 72 + x * 96x + x * -32',
'-(x ^ 3) * 72 + x ^ (1 + 1) * 96 + x * -32',
'-(x ^ 3) * 72 + x ^ 2 * 96 + x * -32',
'-(x ^ 3) * 72 + x ^ 2 * 96 - x * 32',
'-(x ^ 3) * 72 + x ^ 2 * 96 - x * 32'])
# TODO: Should powers have a higher precedence than negation in
# printing?
# FIXME: '-72x ^ 3 + x ^ 2 * 96 - x * 32',
# FIXME: '-72x ^ 3 + 96x ^ 2 - x * 32',
# FIXME: '-72x ^ 3 + 96x ^ 2 - 32x'])
'(-72x ^ (1 + 1) - 12x * -4 + 8 * 6x + 8 * -4)x',
'(-72x ^ 2 - 12x * -4 + 8 * 6x + 8 * -4)x',
'(-72x ^ 2 - -48x + 8 * 6x + 8 * -4)x',
'(-72x ^ 2 + 48x + 8 * 6x + 8 * -4)x',
'(-72x ^ 2 + 48x + 48x + 8 * -4)x',
'(-72x ^ 2 + (1 + 1) * 48x + 8 * -4)x',
'(-72x ^ 2 + 2 * 48x + 8 * -4)x',
'(-72x ^ 2 + 96x + 8 * -4)x',
'(-72x ^ 2 + 96x - 32)x',
'x(-72x ^ 2 + 96x) + x * -32',
'x * -72x ^ 2 + x * 96x + x * -32',
'-x * 72x ^ 2 + x * 96x + x * -32',
'72 * -xx ^ 2 + x * 96x + x * -32',
'-72xx ^ 2 + x * 96x + x * -32',
'-72x ^ (1 + 2) + x * 96x + x * -32',
'-72x ^ 3 + x * 96x + x * -32',
'-72x ^ 3 + 96xx + x * -32',
'-72x ^ 3 + 96x ^ (1 + 1) + x * -32',
'-72x ^ 3 + 96x ^ 2 + x * -32',
'-72x ^ 3 + 96x ^ 2 - x * 32',
'-72x ^ 3 + 96x ^ 2 + 32 * -x',
'-72x ^ 3 + 96x ^ 2 - 32x'])
# TODO: Should powers have a higher precedence than negation
# while printing?
from src.rules.sort import match_sort_multiplicants, move_constant
from src.node import Scope
from src.possibilities import Possibility as P
from tests.rulestestcase import RulesTestCase, tree
class TestRulesSort(RulesTestCase):
def test_match_sort_multiplicants(self):
x, l2 = root = tree('x * 2')
possibilities = match_sort_multiplicants(root)
self.assertEqualPos(possibilities,
[P(root, move_constant, (Scope(root), l2, x))])
def test_move_constant(self):
x, l2 = root = tree('x * 2')
self.assertEqualNodes(move_constant(root, (Scope(root), l2, x)),
l2 * x)
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