def test_Depth_update_agenda_asertion_order_affects_agenda_order_1(): from pyknow.strategies import Depth from pyknow.activation import Activation from pyknow.rule import Rule from pyknow.agenda import Agenda act1 = Activation(rule=Rule(), facts=(1, )) act2 = Activation(rule=Rule(), facts=(2, )) first = {act1, act2} act3 = Activation(rule=Rule(), facts=(3, )) act4 = Activation(rule=Rule(), facts=(4, )) second = {act3, act4} a = Agenda() st = Depth() st.update_agenda(a, first) st.update_agenda(a, second) left, right = set(list(a.activations)[:2]), set(list(a.activations)[2:]) assert left == second assert right == first
def test_Rule_get_activations_needs_factlist(data): from pyknow.rule import Rule r = Rule() with pytest.raises(ValueError): r.get_activations(data)
def test_Depth_update_agenda_different_salience(): from random import shuffle from pyknow.strategies import Depth from pyknow.activation import Activation from pyknow.rule import Rule from pyknow.agenda import Agenda act1 = Activation(rule=Rule(salience=1), facts=(1, )) act2 = Activation(rule=Rule(salience=2), facts=(2, )) act3 = Activation(rule=Rule(salience=3), facts=(3, )) act4 = Activation(rule=Rule(salience=4), facts=(4, )) acts = [act1, act2, act3, act4] shuffle(acts) st = Depth() a = Agenda() for act in acts: st.update_agenda(a, [act]) order = list(a.activations) assert (order.index(act4) < order.index(act3) < order.index(act2) < order.index(act1))
def test_Rule_empty_doesnt_match_empty_factlist(): from pyknow.rule import Rule from pyknow.factlist import FactList r = Rule() fl = FactList() assert r.get_activations(fl) == tuple()
def test_Rule_empty_doesnt_match_empty_factlist(): from pyknow.rule import Rule from pyknow.factlist import FactList r = Rule() fl = FactList() assert tuple(r.get_activations(fl)) == tuple()
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 r = Rule() fl = FactList() idx = fl.declare(InitialFact()) assert Activation(r, (0,)) in r.get_activations(fl)
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 test_Rule_multiple_criteria_generates_activation_with_matching_facts(): from pyknow.rule import Rule from pyknow.factlist import FactList from pyknow.fact import Fact, L r = Rule(Fact(a=L(1)), Fact(b=L(2))) fl = FactList() fl.declare(Fact(a=L(1))) fl.declare(Fact(b=L(2))) activations = list(r.get_activations(fl)) assert len(activations) == 1 assert {0, 1} == set(activations[0].facts)
def test_Rule_and_AND_nesting(): from pyknow.rule import Rule, AND from pyknow.factlist import FactList from pyknow.fact import Fact, L r = Rule(AND(Fact(a=L(2)), Fact(b=L(1)))) fl = FactList() fl.declare(Fact(a=L(2))) fl.declare(Fact(b=L(1))) activations = list(r.get_activations(fl)) assert len(activations) == 1 assert {0, 1} == set(activations[0].facts)
def test_Rule_simple_testce(): from pyknow.rule import Rule from pyknow.fact import Fact, T, L from pyknow.factlist import FactList r = Rule(Fact(a=T(lambda c, x: x.startswith('D')))) fl = FactList() fl.declare(Fact(a=L("David"))) fl.declare(Fact(a=L("Penelope"))) activations = list(r.get_activations(fl)) assert len(activations) == 1 assert {0} == set(activations[0].facts)
def test_Depth_update_agenda_activations_to_agenda(): from pyknow.strategies import Depth from pyknow.activation import Activation from pyknow.rule import Rule from pyknow.agenda import Agenda act1 = Activation(rule=Rule(), facts=(1, )) act2 = Activation(rule=Rule(), facts=(2, )) a = Agenda() st = Depth() st.update_agenda(a, {act1, act2}) assert act1 in a.activations assert act2 in a.activations
def test_Rule_with_empty_Fact_matches_all_Facts(): from pyknow.rule import Rule from pyknow.factlist import FactList from pyknow.fact import Fact from pyknow.activation import Activation r = Rule(Fact()) fl = FactList() fl.declare(Fact(something=True)) fl.declare(Fact(something=False)) fl.declare(Fact(something=3)) activations = r.get_activations(fl) assert len(activations) == 3 for i in range(3): assert Activation(r, (i, )) in activations
def test_activation_facts_only_tuple(): """ Check if activation facts are required to be a tuple """ from pyknow.activation import Activation from pyknow.rule import Rule import pytest with pytest.raises(ValueError): Activation(rule=Rule(), facts=list())
def test_Strategy_update_agenda_update_executed(strategy): from pyknow import strategies from pyknow.activation import Activation from pyknow.rule import Rule from pyknow.agenda import Agenda act1 = Activation(rule=Rule(), facts=(1, )) act2 = Activation(rule=Rule(), facts=(2, )) st = getattr(strategies, strategy)() a = Agenda() a.executed.add(act1) st.update_agenda(a, [act2]) assert act1 not in a.executed
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 test_Rule_with_empty_Fact_matches_all_Facts(): from pyknow.rule import Rule from pyknow.factlist import FactList from pyknow.fact import Fact, L from pyknow.activation import Activation r = Rule(Fact()) fl = FactList() fl.declare(Fact(something=L(True))) fl.declare(Fact(something=L(False))) fl.declare(Fact(something=L(3))) activations = list(r.get_activations(fl)) assert len(activations) == 3 for i in range(3): assert Activation(None, (i, )) in activations
def test_conflictsetchange_accepts_rule(): from pyknow.matchers.rete.nodes import ConflictSetNode from pyknow.rule import Rule # MUST NOT RAISE ConflictSetNode(Rule()) with pytest.raises(TypeError): ConflictSetNode('NOTARULE')
def test_conflictsetchange_valid_adds_to_memory(): from pyknow.fact import Fact from pyknow.matchers.rete.nodes import ConflictSetNode from pyknow.matchers.rete.token import Token, TokenInfo from pyknow.rule import Rule csn = ConflictSetNode(Rule()) f = Fact(test='data') f.__factid__ = 1 csn.activate(Token.valid(f, {'mycontextdata': 'data'})) assert TokenInfo([f], {'mycontextdata': 'data'}) in csn.memory
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 test_conflictsetchange_invalid_removes_from_memory(): from pyknow.fact import Fact from pyknow.matchers.rete.nodes import ConflictSetNode from pyknow.matchers.rete.token import Token, TokenInfo from pyknow.rule import Rule csn = ConflictSetNode(Rule()) csn.memory.append( TokenInfo([Fact(__factid__=1, test='data')], {'mycontextdata': 'data'})) csn.activate( Token.invalid(Fact(__factid__=1, test='data'), {'mycontextdata': 'data'})) assert not csn.memory
def test_retematcher_changes_return_activations_if_csn(): from pyknow.engine import KnowledgeEngine from pyknow.fact import Fact from pyknow.rule import Rule from pyknow.activation import Activation from pyknow.matchers.rete.nodes import ConflictSetNode from pyknow.matchers.rete import ReteMatcher matcher = ReteMatcher(KnowledgeEngine()) rule = Rule() csn = ConflictSetNode(rule) matcher.root_node.add_child(csn, csn.activate) added, removed = matcher.changes( adding=[Fact(__factid__=1), Fact(__factid__=2)]) assert len(added) == 2 assert all(isinstance(a, Activation) for a in added)
def test_conflictsetchange_get_activations_data(): from pyknow.matchers.rete.nodes import ConflictSetNode from pyknow.matchers.rete.token import Token from pyknow.rule import Rule from pyknow.fact import Fact from pyknow.activation import Activation rule = Rule() csn = ConflictSetNode(rule) csn.activate(Token.valid(Fact(__factid__=1, first=1), {'data': 'test'})) added, removed = csn.get_activations() assert len(added) == 1 assert len(removed) == 0 assert list(added)[0].rule is rule assert Fact(__factid__=1, first=1) in list(added)[0].facts assert list(added)[0].context == {'data': 'test'}
def test_Rule_decorator_raise_AttributeError_if_called_without_function(): from pyknow.rule import Rule with pytest.raises(AttributeError): Rule()()
def test_activation_has_facts(): """ Check if activation has facts property """ from pyknow.activation import Activation from pyknow.rule import Rule assert hasattr(Activation(rule=Rule(), facts=tuple()), 'facts')
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
def test_Rule_nesting_issubclass(): """ This actually tests that nesting a Rule is permitted. Rule nesting can be useful for meta-stuff, and """ from pyknow.rule import Rule from pyknow.factlist import FactList from pyknow.fact import Fact, L r1 = Rule(Fact(a=L(1)), Fact(b=L(2)), Fact(c=L(3))) r2 = Rule(Fact(a=L(1)), Rule(Fact(b=L(2)), Fact(c=L(3)))) r3 = Rule(Fact(a=L(1)), Rule(Fact(b=L(2)), Rule(Fact(c=L(3))))) r4 = Rule(Rule(Fact(a=L(1))), Rule(Fact(b=L(2))), Rule(Fact(c=L(3)))) r5 = Rule(Rule(Fact(a=L(1)), Fact(b=L(2)), Fact(c=L(3)))) fl = FactList() fl.declare(Fact(a=L(1))) fl.declare(Fact(b=L(2))) fl.declare(Fact(c=L(3))) for r in (r1, r2, r3, r4, r5): activations = list(r.get_activations(fl)) assert len(activations) == 1 assert {0, 1, 2} == set(activations[0].facts)
def test_Rule_multiple_criteria_generates_activation_with_matching_facts(): from pyknow.rule import Rule from pyknow.factlist import FactList from pyknow.fact import Fact r = Rule(Fact(a=1), Fact(b=2)) fl = FactList() fl.declare(Fact(a=1)) fl.declare(Fact(b=2)) activations = r.get_activations(fl) assert len(activations) == 1 assert {0, 1} == set(activations[0].facts)