class Test(KnowledgeEngine): @Rule(InitialFact()) def rule1(self): pass @Rule(InitialFact()) def rule2(self): pass
def _(exp): dnf_rule = dnf(exp) prep_rule = dnf_rule.new_conditions(*[prepare_rule(e) for e in dnf_rule]) if not prep_rule: return prep_rule.new_conditions(InitialFact()) elif isinstance(prep_rule[0], NOT) or len(extract_facts(prep_rule)) == 0: return prep_rule.new_conditions(InitialFact(), *prep_rule) else: return dnf(prep_rule)
def __init__(self, *conds, salience=0): if not conds: conds = (InitialFact(), ) self.__fn = None self._conds = conds self.salience = salience RULE_WATCHER.debug("Initialized rule with conds %s", conds)
def _(exp): or_exp = [] for e in exp: if isinstance(e, NOT): or_exp.append(AND(InitialFact(), e)) elif isinstance(e, AND): or_exp.append(prepare_rule(e)) else: or_exp.append(e) return OR(*or_exp)
def test_Rule_with_only_one_NOT_match_InitialFact_if_fact_is_not_present(): from pyknow.rule import NOT, Rule from pyknow.factlist import FactList from pyknow.fact import Fact, InitialFact, L from pyknow.match import Capturation r = Rule(NOT(Fact(something=L(True)))) fl = FactList() fl.declare(InitialFact()) assert next(r.get_activations(fl, Capturation()), None) is not None
def test_Rule_empty_matches_with_initial_fact(): from pyknow.rule import Rule from pyknow.factlist import FactList from pyknow.fact import InitialFact from pyknow.activation import Activation from pyknow.match import Capturation r = Rule() fl = FactList() fl.declare(InitialFact()) assert Activation(None, (0, )) in list(r.get_activations(fl, Capturation()))
def reset(self): """ Performs a reset as per CLIPS behaviour (resets the agenda and factlist and declares InitialFact()) .. note:: If persistent facts have been added, they'll be re-declared. """ self.agenda = Agenda() self.facts = FactList() self.__declare(InitialFact()) self.load_initial_facts() self.strategy.update_agenda(self.agenda, self.get_activations())
def test_Rule_and_NOT_nesting(): from pyknow.rule import Rule, NOT from pyknow.factlist import FactList from pyknow.fact import Fact, InitialFact, L r = Rule(Fact(a=L(1)), NOT(Fact(b=L(2)))) fl = FactList() fl.declare(InitialFact()) fl.declare(Fact(a=L(1))) activations = list(r.get_activations(fl)) assert len(activations) == 1 assert {0, 1} == set(activations[0].facts)
def test_rule_with_NOT_testce(): from pyknow.rule import Rule, NOT from pyknow.factlist import FactList from pyknow.fact import Fact, InitialFact, L, T r = Rule(Fact(a=L(1)), NOT(Fact(b=T(lambda c, x: x.startswith('D'))))) fl = FactList() fl.declare(InitialFact()) fl.declare(Fact(a=L(1))) activations = r.get_activations(fl) assert len(list(activations)) == 1 fl.declare(Fact(b=L('David'))) activations = r.get_activations(fl) assert len(list(activations)) == 0 fl = FactList() fl.declare(InitialFact()) fl.declare(Fact(a=L(1))) fl.declare(Fact(b=L('Penelope'))) activations = r.get_activations(fl) assert len(list(activations)) == 1
def _(elem): # Create new nodes condition_node = _wire_rule(elem[0]) initial_fact_node = _wire_rule(InitialFact()) not_node_1 = NotNode(SameContextCheck()) not_node_2 = NotNode(SameContextCheck()) # NotNode1 condition_node.add_child(not_node_1, not_node_1.activate_right) initial_fact_node.add_child(not_node_1, not_node_1.activate_left) # NotNode2 initial_fact_node.add_child(not_node_2, not_node_2.activate_left) not_node_1.add_child(not_node_2, not_node_2.activate_right) return not_node_2
def test_Rule_with_NOT_DEFINED(): from pyknow.rule import Rule, NOT from pyknow.factlist import FactList from pyknow.fact import Fact, InitialFact, L, W r = Rule(Fact(a=L(1)), NOT(Fact(b=W(True)))) fl = FactList() fl.declare(InitialFact()) fl.declare(Fact(a=L(1))) activations = r.get_activations(fl) assert len(list(activations)) == 1 fl.declare(Fact(b=L('SOMETHING'))) activations = r.get_activations(fl) assert len(list(activations)) == 0
def _(elem): leader = elem[0] followers = elem[1:] initial_fact_node = _wire_rule(InitialFact()) leader_node = _wire_rule(leader) followers_node = _wire_rule(AND(*followers)) not_node_1 = NotNode(SameContextCheck()) not_node_2 = NotNode(SameContextCheck()) # NotNode1 followers_node.add_child(not_node_1, not_node_1.activate_right) leader_node.add_child(not_node_1, not_node_1.activate_left) # NotNode2 not_node_1.add_child(not_node_2, not_node_2.activate_right) initial_fact_node.add_child(not_node_2, not_node_2.activate_left) return not_node_2
def _(exp): if isinstance(exp[0], NOT): return AND(InitialFact(), *exp) else: return exp
def _declare_initial_fact(self): yield InitialFact()
def build_alpha_part(ruleset, root_node): """ Given a set of already adapted rules, build the alpha part of the RETE network starting at `root_node`. """ # Adds a dummy rule with InitialFact as LHS for always generate # the alpha part matching InitialFact(). This is needed for the # CE using InitialFact ruleset = ruleset.copy() ruleset.add(Rule(InitialFact())) # Generate a dictionary with rules and the set of facts of the # rule. rule_facts = {rule: extract_facts(rule) for rule in ruleset} # For each fact build a list of checker function capable of # check for each part in the fact. fact_checks = { fact: set(generate_checks(fact)) for fact in chain.from_iterable(rule_facts.values()) } # Make a ranking of the most used checks check_rank = Counter(chain.from_iterable(fact_checks.values())) def weighted_check_sort(check): """Sort check by its type and number of times seen.""" if isinstance(check, TypeCheck): return (float('inf'), hash(check)) elif isinstance(check, FactCapture): return (float('-inf'), hash(check)) elif isinstance(check, FeatureCheck): return (check_rank[check], hash(check)) else: raise TypeError("Unknown check type.") # pragma: no cover def weighted_rule_sort(rule): """Sort rules by the average weight of its checks.""" total = 0 for fact in rule_facts[rule]: for check in fact_checks[fact]: total += check_rank[check] return total / len(rule_facts[rule]) sorted_rules = sorted(ruleset, key=weighted_rule_sort, reverse=True) fact_terminal_nodes = dict() # For rule in rank order and for each rule fact also in rank # order, build the alpha brank looking for an existing node # first. for rule in sorted_rules: for fact in rule_facts[rule]: current_node = root_node fact_sorted_checks = sorted(fact_checks[fact], key=weighted_check_sort, reverse=True) for check in fact_sorted_checks: # Look for a child node with the given check in the # current parent node. for child in current_node.children: if child.node.matcher is check: current_node = child.node break else: # Create a new node and append as child new_node = FeatureTesterNode(check) current_node.add_child(new_node, new_node.activate) current_node = new_node fact_terminal_nodes[fact] = current_node # Return this dictionary containing the last alpha node for each # fact. return fact_terminal_nodes