def attachBetaNodes(self,patternIterator,lastBetaNodePattern=None): """ The second 'pass' in the Rete network compilation algorithm: Attaches Beta nodes to the alpha nodes associated with all the patterns in a rule's LHS recursively towards a 'root' Beta node - the terminal node for the rule. This root / terminal node is returned """ try: nextPattern = patternIterator.next() except StopIteration: assert lastBetaNodePattern if lastBetaNodePattern: return self.nodes[lastBetaNodePattern] else: assert len(self.universalTruths),"should be empty LHSs" terminalNode = BetaNode(None,None,aPassThru=True) self.nodes[HashablePatternList([None])] = terminalNode return terminalNode#raise Exception("Ehh. Why are we here?") if lastBetaNodePattern: firstNode = self.nodes[lastBetaNodePattern] secondNode = self.nodes[nextPattern] newBNodePattern = lastBetaNodePattern + nextPattern newBetaNode = BetaNode(firstNode,secondNode) self.nodes[newBNodePattern] = newBetaNode else: firstNode = self.nodes[nextPattern] oldAnchor = self.nodes.get(HashablePatternList([None])+nextPattern) if not oldAnchor: if isinstance(firstNode,AlphaNode): newfirstNode = BetaNode(None,firstNode,aPassThru=True) newfirstNode.connectIncomingNodes(None,firstNode) self.nodes[HashablePatternList([None])+nextPattern] = newfirstNode else: newfirstNode = firstNode else: newfirstNode = oldAnchor firstNode = newfirstNode secondPattern = patternIterator.next() secondNode = self.nodes[secondPattern] newBetaNode = BetaNode(firstNode,secondNode) newBNodePattern = HashablePatternList([None]) + nextPattern + secondPattern self.nodes[newBNodePattern] = newBetaNode newBetaNode.connectIncomingNodes(firstNode,secondNode) return self.attachBetaNodes(patternIterator,newBNodePattern)
def buildNetwork(self,lhsIterator,rhsIterator,rule,aFilter=False): """ Takes an iterator of triples in the LHS of an N3 rule and an iterator of the RHS and extends the Rete network, building / reusing Alpha and Beta nodes along the way (via a dictionary mapping of patterns to the built nodes) """ matchedPatterns = HashablePatternList() attachedPatterns = [] hasBuiltin = False LHS = [] while True: try: currentPattern = lhsIterator.next() #The LHS isn't done yet, stow away the current pattern #We need to convert the Uniterm into a triple if isinstance(currentPattern,Uniterm): currentPattern = currentPattern.toRDFTuple() LHS.append(currentPattern) except StopIteration: #The LHS is done, need to initiate second pass to recursively build join / beta #nodes towards a terminal node #We need to convert the Uniterm into a triple consequents = [isinstance(fact,Uniterm) and fact.toRDFTuple() or fact for fact in rhsIterator] if matchedPatterns and matchedPatterns in self.nodes: attachedPatterns.append(matchedPatterns) elif matchedPatterns: rt = self._findPatterns(matchedPatterns) attachedPatterns.extend(rt) if len(attachedPatterns) == 1: node = self.nodes[attachedPatterns[0]] if isinstance(node,BetaNode): terminalNode = node else: paddedLHSPattern = HashablePatternList([None])+attachedPatterns[0] terminalNode = self.nodes.get(paddedLHSPattern) if terminalNode is None: #New terminal node terminalNode = BetaNode(None,node,aPassThru=True) self.nodes[paddedLHSPattern] = terminalNode node.connectToBetaNode(terminalNode,RIGHT_MEMORY) terminalNode.consequent.update(consequents) terminalNode.rules.add(rule) terminalNode.antecedent = rule.formula.body terminalNode.network = self terminalNode.headAtoms.update(rule.formula.head) terminalNode.filter = aFilter self.terminalNodes.add(terminalNode) else: moveToEnd = [] endIdx = len(attachedPatterns) - 1 finalPatternList = [] for idx,pattern in enumerate(attachedPatterns): assert isinstance(pattern,HashablePatternList),repr(pattern) currNode = self.nodes[pattern] if (isinstance(currNode,BuiltInAlphaNode) or isinstance(currNode,BetaNode) and currNode.fedByBuiltin): moveToEnd.append(pattern) else: finalPatternList.append(pattern) terminalNode = self.attachBetaNodes(chain(finalPatternList,moveToEnd)) terminalNode.consequent.update(consequents) terminalNode.rules.add(rule) terminalNode.antecedent = rule.formula.body terminalNode.network = self terminalNode.headAtoms.update(rule.formula.head) terminalNode.filter = aFilter self.terminalNodes.add(terminalNode) self._resetinstanciationStats() #self.checkDuplicateRules() return terminalNode if HashablePatternList([currentPattern]) in self.nodes: #Current pattern matches an existing alpha node matchedPatterns.append(currentPattern) elif matchedPatterns in self.nodes: #preceding patterns match an existing join/beta node newNode = self.createAlphaNode(currentPattern) if len(matchedPatterns) == 1 and HashablePatternList([None])+matchedPatterns in self.nodes: existingNode = self.nodes[HashablePatternList([None])+matchedPatterns] newBetaNode = BetaNode(existingNode,newNode) self.nodes[HashablePatternList([None])+matchedPatterns+HashablePatternList([currentPattern])] = newBetaNode matchedPatterns = HashablePatternList([None])+matchedPatterns+HashablePatternList([currentPattern]) else: existingNode = self.nodes[matchedPatterns] newBetaNode = BetaNode(existingNode,newNode) self.nodes[matchedPatterns+HashablePatternList([currentPattern])] = newBetaNode matchedPatterns.append(currentPattern) self.nodes[HashablePatternList([currentPattern])] = newNode newBetaNode.connectIncomingNodes(existingNode,newNode) #Extend the match list with the current pattern and add it #to the list of attached patterns for the second pass attachedPatterns.append(matchedPatterns) matchedPatterns = HashablePatternList() else: #The current pattern is not in the network and the match list isn't #either. Add an alpha node newNode = self.createAlphaNode(currentPattern) self.nodes[HashablePatternList([currentPattern])] = newNode #Add to list of attached patterns for the second pass attachedPatterns.append(HashablePatternList([currentPattern]))