Skip to content

Commit

Permalink
Rete Net construction, upto canonical graph forms
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsekar committed Jul 30, 2021
1 parent b10a6fa commit f088379
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 0 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ pyyaml
backports.cached_property
jinja2
pydblite
frozendict
parameterized
65 changes: 65 additions & 0 deletions wc_rules/matcher/rete_net.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from pydblite import Base as dBase
from frozendict import frozendict
from ..utils.collections import subdict
from types import MethodType
from . import rete_node
from ..schema.entity import Entity

# Here, core refers to the "core element" of a rete-node.
# This may be an edge, a graph ,a pattern, a rule, etc.

class ReteNet:

methods = rete_node.initializers

def __init__(self):
self.nodes = dict()
self.channels = dBase(':memory:')
self.channels.create('source','target','chtype','misc')
self.configure()

def configure(self):
for method in self.__class__.methods:
self.bind_method(method)
return self

def add_node(self,node):
assert isinstance(node,rete_node.ReteNode)
if node.core not in self.nodes:
self.nodes[node.core] = node

# register node
return self

def add_channel(self,source,target,chtype,**kwargs):
assert isinstance(source,rete_node.ReteNode)
assert isinstance(target,rete_node.ReteNode)
kwargs = frozendict(kwargs) if kwargs else None
channel = dict(source=source,target=target,chtype=chtype,misc=kwargs)
if not self.channels(**channel):
self.channels.insert(**channel)

# register channel
return self

def bind_method(self,method):
m = MethodType(method, self)
assert method.__name__ not in dir(self)
setattr(self,method.__name__,m)
return self

def list_methods(self):
return [x for x in dir(self) if x[0:2]!='__' and isinstance(getattr(self,x),MethodType)]

def pprint(self):
s = []
for x in self.nodes:
s.append('Node '+str(x))
for channel in self.channels:
s.append(f"Channel {str(channel['source'].core)} -> {str(channel['target'].core)}, {channel['chtype']}, {channel['misc']}")
return '\n'.join(s)





67 changes: 67 additions & 0 deletions wc_rules/matcher/rete_node.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from ..schema.base import BaseClass
from collections import deque
from itertools import dropwhile

from ..graph.graph_partitioning import partition_canonical_form
from frozendict import frozendict

class ReteNode:

def __init__(self,core=None,**data):
self.core = core
self.data = frozendict(data) if data else None
self.slots = deque()
self.cache = None

def initialize_start(net):
net.add_node(ReteNode('start'))
return net

def initialize_base_subclass(net,_class):
classes = ['start'] + list(reversed(_class.__mro__[:_class.__mro__.index(BaseClass)]))
classpairs = [(c1,c2) for c1,c2 in zip(classes[:-1],classes[1:]) if c2 not in net.nodes]
for c1,c2 in classpairs:
net.add_node(ReteNode(c2))
n1,n2 = [net.nodes[x] for x in [c1,c2]]
net.add_channel(n1,n2,'passthrough')
return net

def initialize_single_edge(net,canonical_form,group):
assert len(canonical_form.edges)==1
_class = min(canonical_form.classes,key=lambda c: len(c.__mro__))
if _class not in net.nodes:
net.initialize_base_subclass(_class)
net.add_node(ReteNode(canonical_form,group=group))
n1,n2 = [net.nodes[x] for x in [_class,canonical_form]]
net.add_channel(n1,n2,'passthrough')
return net

def initialize_canonical_form(net,canonical_form,group):
if canonical_form in net.nodes:
return net
assert len(canonical_form.edges) >= 1
if len(canonical_form.edges)==1:
net.initialize_single_edge(canonical_form,group)
return net
net.add_node(ReteNode(canonical_form,group=group))
for mapping,labeling,grouping in partition_canonical_form(canonical_form,group):
net.initialize_canonical_form(labeling,grouping)
n1,n2 = [net.nodes[x] for x in [labeling,canonical_form]]
net.add_channel(n1,n2,'merge',mapping=mapping)
return net

def initialize_pattern(net,pattern,group):
return net

def initialize_rule(net,rule):
return net

def initialize_RBM(net,rbm):
return net

initializers = [
initialize_start,
initialize_base_subclass,
initialize_single_edge,
initialize_canonical_form
]

0 comments on commit f088379

Please sign in to comment.