Commit 0d06e0ae authored by Taddeus Kroes's avatar Taddeus Kroes

Implemented retrieval possibilities successfully.

parent 206246be
...@@ -93,25 +93,29 @@ class ExpressionNode(Node, ExpressionBase): ...@@ -93,25 +93,29 @@ class ExpressionNode(Node, ExpressionBase):
node.parent = self.parent node.parent = self.parent
self.parent = None self.parent = None
def get_order(self): def get_polynome(self):
if self.is_power() and self[0].is_identifier() and self[1].is_leaf(): """
# a ^ 3 Identifier nodes of all polynomes, tuple format is:
return (self[0].value, self[1].value, 1) (identifier, exponent, coefficient, literal_exponent)
"""
if not self.op & OP_MUL: if self.is_power():
# a ^ e
return (self[0], self[1], ExpressionLeaf(1), True)
if self.op != OP_MUL:
return return
for n0, n1 in [(0, 1), (1, 0)]: for n0, n1 in [(0, 1), (1, 0)]:
if self[n0].is_numeric(): if self[n0].is_numeric():
if self[n1].is_identifier(): if self[n1].is_identifier():
# 2 * a # c * a
return (self[n1].value, 1, self[n0].value) return (self[n1], ExpressionLeaf(1), self[n0], False)
elif self[n1].is_power(): elif self[n1].is_power():
# 2 * a ^ 3 # c * a ^ e
coeff, power = self coeff, power = self
root, exponent = power
if power[0].is_identifier() and power[1].is_leaf(): return (root, exponent, coeff, True)
return (power[0].value, power[1].value, coeff.value)
def get_scope(self): def get_scope(self):
"""""" """"""
...@@ -119,7 +123,7 @@ class ExpressionNode(Node, ExpressionBase): ...@@ -119,7 +123,7 @@ class ExpressionNode(Node, ExpressionBase):
#op = OP_ADD | OP_SUB if self.op & (OP_ADD | OP_SUB) else self.op #op = OP_ADD | OP_SUB if self.op & (OP_ADD | OP_SUB) else self.op
for child in self: for child in self:
if not child.is_leaf() and child.op & self.op: if not child.is_leaf() and child.op == self.op:
scope += child.get_scope() scope += child.get_scope()
else: else:
scope.append(child) scope.append(child)
...@@ -133,9 +137,13 @@ class ExpressionLeaf(Leaf, ExpressionBase): ...@@ -133,9 +137,13 @@ class ExpressionLeaf(Leaf, ExpressionBase):
self.type = TYPE_MAP[type(args[0])] self.type = TYPE_MAP[type(args[0])]
def get_order(self): def get_polynome(self):
if self.is_identifier(): """
return (self.value, 1, 1) Identifier nodes of all polynomes, tuple format is:
(identifier, exponent, coefficient, literal_exponent)
"""
# a = 1 * a ^ 1
return (self, ExpressionLeaf(1), ExpressionLeaf(1), False)
def replace(self, node): def replace(self, node):
if not hasattr(self, 'parent'): if not hasattr(self, 'parent'):
......
...@@ -11,9 +11,14 @@ class Possibility(object): ...@@ -11,9 +11,14 @@ class Possibility(object):
def __repr__(self): def __repr__(self):
return str(self) return str(self)
# TODO: Add unit tests
def __eq__(self, other): def __eq__(self, other):
self_arg0, self_arg1 = zip(*self.args)
other_arg0, other_arg1 = zip(*other.args)
return self.handler == other.handler \ return self.handler == other.handler \
and map(hash, self.args) == map(hash, other.args) and self_arg1 == other_arg1 \
and map(hash, self_arg0) == map(hash, other_arg0)
def filter_duplicates(items): def filter_duplicates(items):
......
...@@ -11,28 +11,25 @@ def match_expand(node): ...@@ -11,28 +11,25 @@ def match_expand(node):
a * (b + c) -> ab + ac a * (b + c) -> ab + ac
""" """
assert node.type == TYPE_OPERATOR assert node.type == TYPE_OPERATOR
assert node.op & OP_MUL assert node.op == OP_MUL
# TODO: fix!
return [] return []
p = []
# 'a' parts
left = []
# '(b + c)' parts p = []
right = [] a = []
bc = []
for n in node.get_scope(): for n in node.get_scope():
if node.type == TYPE_OPERATOR: if n.is_leaf():
if n.op & OP_ADD: a.append(n)
right.append(n) elif n.op == OP_ADD:
else: bc.append(n)
left.append(n)
if len(left) and len(right): if a and bc:
for l in left: for a_node in a:
for r in right: for bc_node in bc:
p.append(P(node, expand_single, l, r)) p.append(P(node, expand_single, a_node, bc_node))
return p return p
...@@ -64,83 +61,77 @@ def match_combine_factors(node): ...@@ -64,83 +61,77 @@ def match_combine_factors(node):
k0 * v ^ n + exp + k1 * v ^ n -> exp + (k0 + k1) * v ^ n k0 * v ^ n + exp + k1 * v ^ n -> exp + (k0 + k1) * v ^ n
""" """
assert node.type == TYPE_OPERATOR assert node.type == TYPE_OPERATOR
assert node.op & OP_ADD assert node.op == OP_ADD
p = [] p = []
# Collect all nodes that can be combined # Collect all nodes that can be combined:
# Numeric leaves # a ^ e = 1 * a ^ e
numerics = [] # c * a = c * a ^ 1
# c * a ^ e
# Identifier leaves of all orders, tuple format is; # a = 1 * a ^ 1
# (identifier, exponent, coefficient) #
orders = [] # Identifier nodes of all polynomes, tuple format is:
# (identifier, exponent, coefficient, literal_coefficient)
polys = []
for n in node.get_scope(): for n in node.get_scope():
if not n.is_leaf(): polynome = n.get_polynome()
order = n.get_order()
if order:
orders.append(order)
elif n.is_numeric():
numerics.append(n)
elif n.is_identifier():
orders.append((n.value, 1, 1))
if len(numerics) > 1:
for num0, num1 in combinations(numerics, 2):
p.append(P(node, combine_numerics, (num0, num1)))
if len(orders) > 1:
for order0, order1 in combinations(orders, 2):
id0, exponent0, coeff0 = order0
id1, exponent1, coeff1 = order1
if id0 == id1 and exponent0 == exponent1:
# Same identifier and exponent -> combine coefficients
args = order0 + (coeff1,)
p.append(P(node, combine_orders, args))
return p
if polynome:
polys.append((n, polynome))
def combine_numerics(root, args): # Each combination of powers of the same value and polynome can be added
""" if len(polys) >= 2:
Combine two numeric leaves in an n-ary plus. for left, right in combinations(polys, 2):
r0, e0, c0 = left[1][:3]
r1, e1, c1 = right[1][:3]
Example: if (r0.is_numeric() and r1.is_numeric() and e0 == e1 == Leaf(1)) \
>>> 3 + 4 -> 7 or (r0 == r1 and e0 == e1):
""" # Both numeric and same exponent -> combine coefficients and
others = list(set(root.get_scope()) - set(args)) # roots, or:
value = sum([n.value for n in args]) # Same identifier and exponent -> combine coefficients
p.append(P(node, combine_polynomes, (left, right)))
return nary_node('+', others + [Leaf(value)]) return p
def combine_orders(root, args): def combine_polynomes(root, args):
""" """
Combine two identifier multiplications of any order in an n-ary plus. Combine two identifier multiplications of any polynome in an n-ary plus.
Example: Example:
3x + 4x -> 7x c * a ^ b + d * a ^ b -> (c + d) * a ^ b
""" """
identifier, exponent, coeff0, coeff1, others = args left, right = args
nl, pl = left
nr, pr = right
c0, r0, e0 = pl
c1, r1, e1 = pr
coeff = coeff0 + coeff1 scope = root.get_scope()
if not exponent: if r0.is_numeric() and r1.is_numeric() and e0 == e1 == 1:
# a ^ 0 -> 1 new_root = Leaf(r0.value + r1.value)
ident = Leaf(1)
elif exponent == 1:
# a ^ 1 -> a
ident = Leaf(identifier)
else: else:
# a ^ n -> a ^ n new_root = r0
ident = Node('^', Leaf(identifier), Leaf(exponent))
if coeff == 1: if pl[3] or pr[3]:
combined = ident # literal a ^ 1 -> a ^ 1
power = Node('^', pl[0], pl[1])
else: else:
combined = Node('*', Leaf(coeff), ident) # nonliteral a ^ 1 -> a
power = pl[0]
# replacement: (c + d) * a ^ b
# a, b and c are from 'left', d is from 'right'.
replacement = Node('*', Node('+', pl[2], pr[2]), power)
# Replace the left node with the new expression
scope[scope.index(nl)] = replacement
# Remove the right node
scope.remove(nr)
return nary_node('+', others + [combined]) return nary_node('+', scope)
...@@ -51,23 +51,23 @@ class TestNode(unittest.TestCase): ...@@ -51,23 +51,23 @@ class TestNode(unittest.TestCase):
self.assertTrue(L(1.5).is_numeric()) self.assertTrue(L(1.5).is_numeric())
self.assertFalse(L('a').is_numeric()) self.assertFalse(L('a').is_numeric())
def test_get_order_identifier(self): def test_get_polynome_identifier(self):
self.assertEqual(L('a').get_order(), ('a', 1, 1)) self.assertEqual(L('a').get_polynome(), (L('a'), L(1), L(1), False))
def test_get_order_None(self): def test_get_polynome_None(self):
self.assertIsNone(L(1).get_order()) self.assertIsNone(N('+').get_polynome())
def test_get_order_power(self): def test_get_polynome_power(self):
power = N('^', L('a'), L(2)) power = N('^', L('a'), L(2))
self.assertEqual(power.get_order(), ('a', 2, 1)) self.assertEqual(power.get_polynome(), (L('a'), L(2), L(1), True))
def test_get_order_coefficient_exponent_int(self): def test_get_polynome_coefficient_exponent_int(self):
times = N('*', L(3), N('^', L('a'), L(2))) times = N('*', L(3), N('^', L('a'), L(2)))
self.assertEqual(times.get_order(), ('a', 2, 3)) self.assertEqual(times.get_polynome(), (L('a'), L(2), L(3), True))
def test_get_order_coefficient_exponent_id(self): def test_get_polynome_coefficient_exponent_id(self):
times = N('*', L(3), N('^', L('a'), L('b'))) times = N('*', L(3), N('^', L('a'), L('b')))
self.assertEqual(times.get_order(), ('a', 'b', 3)) self.assertEqual(times.get_polynome(), (L('a'), L('b'), L(3), True))
def test_get_scope_binary(self): def test_get_scope_binary(self):
plus = N('+', *self.l[:2]) plus = N('+', *self.l[:2])
......
import unittest
from src.node import ExpressionNode as N, ExpressionLeaf as L
from src.rules.poly import match_combine_factors, combine_polynomes
from src.possibilities import Possibility as P
from src.parser import Parser
from tests.parser import ParserWrapper
def tree(exp, **kwargs):
return ParserWrapper(Parser, **kwargs).run([exp])
class TestRulesPoly(unittest.TestCase):
#def test_match_combine_factors_numeric_combinations(self):
# l0, l1, l2 = L(1), L(2), L(2)
# plus = N('+', N('+', l0, l1), l2)
# p = match_combine_factors(plus)
# self.assertEqualPos(p, [P(plus, combine_polynomes, (l0, l1)),
# P(plus, combine_polynomes, (l0, l2)),
# P(plus, combine_polynomes, (l1, l2))])
def assertEqualPos(self, possibilities, expected):
self.assertEqual(len(possibilities), len(expected))
for p, e in zip(possibilities, expected):
self.assertEqual(p.root, e.root)
self.assertEqual(p, e)
def test_numeric(self):
l1, l2 = root = tree('1+2')
self.assertEqualPos(match_combine_factors(root),
[P(root, combine_polynomes, ((l1, (l1, l1, l1, False)),
(l2, (l2, l1, l1, False))))])
a1, a2 = root = tree('a+a')
self.assertEqualPos(match_combine_factors(root),
[P(root, combine_polynomes, ((a1, (a1, l1, l1, False)),
(a2, (a2, l1, l1, False))))])
a1, a2 = root = tree('a+2a')
self.assertEqualPos(match_combine_factors(root),
[P(root, combine_polynomes, ((a1, (a1, l1, l1, False)),
(a2, (a2[1], l1, l2, False))))])
a1, a2 = root = tree('a2+a2')
self.assertEqualPos(match_combine_factors(root),
[P(root, combine_polynomes, ((a1, (a1[0], l2, l1, True)),
(a2, (a2[0], l2, l1, True))))])
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