Commit efc3c91b authored by Taddeus Kroes's avatar Taddeus Kroes

Added non-strict equivalence match.

parent b47f8fee
......@@ -220,7 +220,9 @@ class ExpressionNode(Node, ExpressionBase):
return (self[1], self[0], ExpressionLeaf(1))
def get_scope(self):
""""""
"""
Find all n nodes within the n-ary scope of this operator.
"""
scope = []
#op = OP_ADD | OP_SUB if self.op & (OP_ADD | OP_SUB) else self.op
......@@ -234,6 +236,41 @@ class ExpressionNode(Node, ExpressionBase):
return scope
def equals(self, other):
"""
Perform a non-strict equivalence check between two nodes:
- If the other node is a leaf, it cannot be equal to this node.
- If their operators differ, the nodes are not equal.
- If both nodes are additions or both are multiplications, match each
node in one scope to one in the other (an injective relationship).
Any difference in order of the scopes is irrelevant.
- If both nodes are divisions, the nominator and denominator have to be
non-strictly equal.
"""
if not other.is_op(self.op):
return False
if self.op in (OP_ADD, OP_MUL):
s0 = self.get_scope()
s1 = set(other.get_scope())
matched = set()
for n0 in s0:
found = False
for n1 in s1 - matched:
if n0.equals(n1):
found = True
matched.add(n1)
break
if not found:
return False
elif self.op == OP_DIV:
return self[0].equals(other[0]) and self[1].equals(other[1])
return True
class ExpressionLeaf(Leaf, ExpressionBase):
def __init__(self, *args, **kwargs):
......@@ -242,6 +279,9 @@ class ExpressionLeaf(Leaf, ExpressionBase):
self.type = TYPE_MAP[type(args[0])]
def __eq__(self, other):
"""
Check strict equivalence.
"""
other_type = type(other)
if other_type in TYPE_MAP:
......@@ -249,6 +289,13 @@ class ExpressionLeaf(Leaf, ExpressionBase):
return other.type == self.type and self.value == other.value
def equals(self, other):
"""
Check non-strict equivalence.
Between leaves, this is the same as strict equivalence.
"""
return self == other
def extract_polynome_properties(self):
"""
An expression leaf will return the polynome tuple (1, r, 1), where r is
......
import unittest
from src.node import ExpressionNode
from src.parser import Parser
from tests.parser import ParserWrapper
def tree(exp, **kwargs):
return ParserWrapper(Parser, **kwargs).run([exp])
class RulesTestCase(unittest.TestCase):
......
import unittest
from src.node import ExpressionNode as N, ExpressionLeaf as L
from tests.rulestestcase import tree
class TestNode(unittest.TestCase):
......@@ -88,3 +89,48 @@ class TestNode(unittest.TestCase):
def test_get_scope_nested_deep(self):
plus = N('+', N('+', N('+', *self.l[:2]), self.l[2]), self.l[3])
self.assertEqual(plus.get_scope(), self.l)
def test_equals_node_leaf(self):
a, b = plus = tree('a + b')
self.assertFalse(a.equals(plus))
self.assertFalse(plus.equals(a))
def test_equals_other_op(self):
plus, mul = tree('a + b, a * b')
self.assertFalse(plus.equals(mul))
def test_equals_add(self):
p0, p1, p2, p3 = tree('a + b,a + b,b + a, a + c')
self.assertTrue(p0.equals(p1))
self.assertTrue(p0.equals(p2))
self.assertFalse(p0.equals(p3))
self.assertFalse(p2.equals(p3))
def test_equals_mul(self):
m0, m1, m2, m3 = tree('a * b,a * b,b * a, a * c')
self.assertTrue(m0.equals(m1))
self.assertTrue(m0.equals(m2))
self.assertFalse(m0.equals(m3))
self.assertFalse(m2.equals(m3))
def test_equals_nary(self):
p0, p1, p2, p3, p4 = \
tree('a + b + c,a + c + b,b + a + c,b + c + a, a + b + d')
self.assertTrue(p0.equals(p1))
self.assertTrue(p0.equals(p2))
self.assertTrue(p0.equals(p3))
self.assertTrue(p1.equals(p2))
self.assertTrue(p1.equals(p3))
self.assertTrue(p2.equals(p3))
self.assertFalse(p2.equals(p4))
def test_equals_div(self):
d0, d1, d2 = tree('a / b,a / b,b / a')
self.assertTrue(d0.equals(d1))
self.assertFalse(d0.equals(d2))
......@@ -2,7 +2,7 @@ import unittest
from src.possibilities import MESSAGES, Possibility as P, filter_duplicates
from src.rules.numerics import add_numerics
from tests.test_rules_poly import tree
from tests.rulestestcase import tree
from src.parser import Parser
from tests.parser import ParserWrapper
......
from src.rules.factors import match_expand, expand_single, expand_double
from src.possibilities import Possibility as P
from tests.rulestestcase import RulesTestCase
from tests.test_rules_poly import tree
from tests.rulestestcase import RulesTestCase, tree
class TestRulesFactors(RulesTestCase):
......
......@@ -2,8 +2,7 @@ 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
from src.possibilities import Possibility as P
from tests.test_rules_poly import tree
from tests.rulestestcase import RulesTestCase
from tests.rulestestcase import RulesTestCase, tree
class TestRulesFractions(RulesTestCase):
......
from src.rules.groups import match_combine_groups
from src.possibilities import Possibility as P
from tests.rulestestcase import RulesTestCase, tree
class TestRulesGroups(RulesTestCase):
def test_(self):
pass
......@@ -2,8 +2,7 @@ from src.rules.numerics import add_numerics, match_divide_numerics, \
divide_numerics, match_multiply_numerics, multiply_numerics
from src.possibilities import Possibility as P
from src.node import ExpressionLeaf as L
from tests.rulestestcase import RulesTestCase
from tests.test_rules_poly import tree
from tests.rulestestcase import RulesTestCase, tree
class TestRulesNumerics(RulesTestCase):
......
from src.rules.poly import match_combine_polynomes, combine_polynomes
from src.rules.numerics import add_numerics
from src.possibilities import Possibility as P
from src.parser import Parser
from tests.parser import ParserWrapper
from tests.rulestestcase import RulesTestCase
def tree(exp, **kwargs):
return ParserWrapper(Parser, **kwargs).run([exp])
from tests.rulestestcase import RulesTestCase, tree
class TestRulesPoly(RulesTestCase):
......
......@@ -6,8 +6,7 @@ from src.rules.powers import match_add_exponents, add_exponents, \
match_exponent_to_root, exponent_to_root
from src.possibilities import Possibility as P
from src.node import ExpressionNode as N
from tests.test_rules_poly import tree
from tests.rulestestcase import RulesTestCase
from tests.rulestestcase import RulesTestCase, tree
class TestRulesPowers(RulesTestCase):
......
from src.node import ExpressionNode as N
from src.rules.utils import nary_node, is_prime, least_common_multiple
from tests.test_rules_poly import tree
from tests.rulestestcase import RulesTestCase
from tests.rulestestcase import RulesTestCase, tree
class TestRulesUtils(RulesTestCase):
......
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