Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions ppp_libmodule/simplification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import operator
import itertools

from ppp_datamodel.nodes import Resource
from ppp_datamodel.nodes.list_operators import *

__all__ = ['simplify']

def partition(pred, list_):
# Partition the items in lists / non-lists
list_ = [x for x in list_ if x]
lists = filter(pred, list_)
not_lists = itertools.filterfalse(pred, list_)
return (lists, not_lists)

def simplify_union(tree):
# Trivial cases
if len(tree.list) == 0:
return List([])
elif len(tree.list) == 1:
return tree.list[0]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that these cases are handled by the following code


(lists, non_lists) = partition(lambda x:isinstance(x, List), tree.list)
# Make union of lists
lists = map(operator.attrgetter('list'), lists)
lists = list(set(itertools.chain(*lists)))

non_lists = list(non_lists)
if non_lists: # If there are non-lists (eg. triples)
all_ = non_lists
all_.append(List(lists))
return Union(all_)
else: # If there are only lists
return List(lists)

def simplify_intersection(tree):
# Trivial cases
if len(tree.list) == 0:
return tree
elif len(tree.list) == 1:
return tree.list[0]

(lists, non_lists) = partition(lambda x:isinstance(x, List), tree.list)
# Make intersection of lists
lists = list(map(set, map(operator.attrgetter('list'), lists)))
lists = list(lists[0].intersection(*lists[1:]))

non_lists = list(non_lists)
if non_lists: # If there are non-lists (eg. triples)
all_ = non_lists
all_.append(List(lists))
return Intersection(all_)
else: # If there are only lists
return List(lists)


predicates = {
Union: simplify_union,
Intersection: simplify_intersection,
}

def predicate(tree):
for (cls, f) in predicates.items():
if isinstance(tree, cls):
return f(tree)
return tree

def simplify(tree):
return tree.traverse(predicate)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
'Topic :: Software Development :: Libraries',
],
install_requires=[
'ppp_datamodel>=0.5.2,<0.6',
'ppp_datamodel>=0.5.22,<0.6',
],
packages=[
'ppp_libmodule',
Expand Down
42 changes: 42 additions & 0 deletions tests/test_simplification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import unittest

from ppp_datamodel.nodes import Triple as T
from ppp_datamodel.nodes import Missing as M
from ppp_datamodel.nodes import Resource as R
from ppp_datamodel.nodes.list_operators import *
from ppp_libmodule.simplification import simplify


class SimplificationTestCase(unittest.TestCase):
def testUnionTrivial(self):
self.assertEqual(simplify(Union([])), List([]))
self.assertEqual(simplify(Union([List([R('a')])])),
List([R('a')]))
def testUnionResourceLists(self):
t = Union([List([R('a'), R('b')]), List([R('c')])])
t = simplify(t)
self.assertIsInstance(t, List)
self.assertEqual(set(t.list), {R('a'), R('b'), R('c')})
def testUnionMixed(self):
t = Union([List([R('a'), R('b')]), T(M(), M(), M())])
t = simplify(t)
self.assertIsInstance(t, Union)
self.assertEqual(t.list[0], T(M(), M(), M()))
self.assertIsInstance(t.list[1], List)
self.assertEqual(set(t.list[1].list), {R('a'), R('b')})

def testIntersectionTrivial(self):
self.assertEqual(simplify(Intersection([])), Intersection([]))
self.assertEqual(simplify(Intersection([List([R('a')])])),
List([R('a')]))
def testIntersectionResourceLists(self):
t = Intersection([List([R('a'), R('b')]), List([R('c'), R('a')])])
t = simplify(t)
self.assertEqual(t, List([R('a')]))
def testIntersectionMixed(self):
t = Intersection([List([R('a'), R('b')]), List([R('c'), R('a')]),
T(M(), M(), M())])
t = simplify(t)
self.assertIsInstance(t, Intersection)
self.assertEqual(t.list[0], T(M(), M(), M()))
self.assertEqual(t.list[1], List([R('a')]))