Skip to content
Open
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
37 changes: 16 additions & 21 deletions lib/Rete/Network.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,34 +135,29 @@ def __init__(self, items=None, skipBNodes=False):
else:
self._l = []

def _hashRulePattern(self, item):
"""
Generates a unique hash for RDF triples and N3 builtin invokations. The
hash function consists of the hash of the terms concatenated in order
"""
if isinstance(item, tuple):
return reduce(lambda x, y: x + y, [
i for i in item
if not self.skipBNodes or not isinstance(i, BNode)
])
elif isinstance(item, N3Builtin):
return reduce(lambda x, y: x + y, [item.argument, item.result])

def __len__(self):
return len(self._l)

def __getslice__(self, beginIdx, endIdx):
return HashablePatternList(self._l[beginIdx:endIdx])

def __hash__(self):
if self._l:
_concatPattern = [pattern and self._hashRulePattern(pattern) or "None" for pattern in self._l]
#nulify the impact of order in patterns
_concatPattern.sort()
return hash(reduce(lambda x, y: x + y, _concatPattern))
else:
return hash(None)

out = []
for item in self._l:
if not item:
out.append('None')
elif isinstance(item, tuple):
out.extend([i for i in item
if not self.skipBNodes or not isinstance(i, BNode)])
elif isinstance(item, N3Builtin):
out.extend([item.argument, item.result])
else:
raise NotImplementedError("don't know how to hash %r" % item)

#nulify the impact of order in patterns
out.sort()
return hash(tuple(out))

def __add__(self, other):
assert isinstance(other, HashablePatternList), other
return HashablePatternList(self._l + other._l)
Expand Down
30 changes: 30 additions & 0 deletions test/test_network_pattern_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import unittest
import logging
logging.basicConfig(level=logging.DEBUG)

from FuXi.Rete.Network import HashablePatternList
from rdflib import URIRef, Literal
import rdflib.term

class TestHashablePatternList(unittest.TestCase):
def setUp(self):
super(TestHashablePatternList, self).setUp()

self.oldWarning = rdflib.term._LOGGER.warning
def stopOnWarning(msg):
raise ValueError("this warning was logged: %s" % msg)
rdflib.term._LOGGER.warning = stopOnWarning

def tearDown(self):
super(TestHashablePatternList, self).tearDown()
rdflib.term._LOGGER.warning = self.oldWarning

def testCombineUriAndLiteral(self):
# This is a simplified version of input that happens in real usage with a rule like this:
# { ?c :p1 ?uri . } => { ?c :p2 (" " ?uri) . } .
hpl = HashablePatternList(items=[(URIRef('http://example.com/'),),
(Literal(' '),)])
hash(hpl)

if __name__ == '__main__':
unittest.main()