class Parent(KnowledgeEngine): @Rule(Fact(initial=L(True))) def shouldnot_run(self): # pytest.set_trace() print("Ran") executions.append(4) @Rule(Fact(inherited=L(True))) def inherited(self): executions.append(2) @Rule(NOT(Fact(not_inherited=L(True)))) def not_inherited(self): executions.append(3)
class Test(KnowledgeEngine): """ Test KE """ @Rule(Fact(something=L(1)), Fact(something=L(2))) def rule1(self): """ First rule, something=1 and something=2""" nonlocal executions executions.append('rule1') @Rule(Fact(something=L(3))) def rule2(self): """ Second rule, only something=3 """ nonlocal executions executions.append('rule2')
def test_facts_produce_activations_that_are_Activations(): """ A fact produces activations that are Activation objects """ from pyknow.fact import Fact, L from pyknow.factlist import FactList from pyknow.match import Capturation from pyknow.activation import Activation flist = FactList() flist.declare(Fact(a=L(1))) caps = list(Fact(a=L(1)).get_activations(flist, Capturation())) assert len(caps) == 1 assert isinstance(caps[0], Activation) assert caps[0].facts == (0,)
def test_tree_NOT(): """ Test tree not """ from pyknow.tree import KETree from pyknow.engine import KnowledgeEngine from pyknow.rule import Rule, NOT from pyknow.fact import Fact, L executions = [] global executions class Child(KnowledgeEngine): @Rule(Fact(always_run=L(True))) def always_run(self): executions.append(1) self.parent.declare(Fact(inherited=L(True))) class Parent(KnowledgeEngine): @Rule(Fact(inherited=L(True))) def inherited(self): executions.append(2) @Rule(NOT(Fact(not_inherited=L(True)))) def not_inherited(self): executions.append(3) tree_ = { 'node': Parent(), 'children': [{ 'node': Child(), 'children': [] }, { 'node': Child(), 'children': [] }] } tree_['children'][0]['node'].deffacts(Fact(always_run=L(True))) # Parent does not inherit its children facts: tree_['children'][0]['node'].deffacts(Fact(not_inherited=L(True))) KETree(tree_).run_sequential() print(executions) assert len(executions) == 3
def test_ke_inheritance(): from pyknow.rule import Rule from pyknow.fact import Fact, L from pyknow.engine import KnowledgeEngine executed = False class Person(Fact): pass class Base(KnowledgeEngine): @Rule(Person(name=L('pepe'))) def is_pepe(self): self.declare(Person(drinks=L("coffee"))) class Test(Base): @Rule(Person(drinks=L("coffee"))) def drinks_coffee(self): nonlocal executed executed = True ke_ = Test() ke_.deffacts(Person(name=L('pepe'))) ke_.reset() ke_.run() assert executed
def test_rules_are_executed_once(to_declare_random): from random import shuffle from pyknow.engine import KnowledgeEngine from pyknow.rule import Rule from pyknow.fact import Fact, L executions = [] class Test(KnowledgeEngine): @Rule(Fact(something=L(1)), Fact(something=L(2))) def rule1(self): nonlocal executions executions.append('rule1') @Rule(Fact(something=L(3))) def rule2(self): nonlocal executions executions.append('rule2') ke = Test() to_declare = list(set(to_declare_random + [1, 2, 3])) shuffle(to_declare) print(to_declare) for i in to_declare: ke.deffacts(Fact(something=L(i))) ke.reset() ke.run() assert executions.count('rule1') == 1 assert executions.count('rule2') == 1
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_nested_declarations(): from pyknow.rule import Rule from pyknow.fact import Fact, L from pyknow.engine import KnowledgeEngine class Person(Fact): pass executed = False class Person_KE(KnowledgeEngine): @Rule(Person(name=L("David"))) def david(self): self.declare(Person(name=L("Pepe"))) @Rule(Person(name=L("Pepe"))) def pepe(self): nonlocal executed executed = True ke_ = Person_KE() ke_.deffacts(Person(name=L("David"))) ke_.reset() ke_.run() assert executed
def test_matching_different_number_of_arguments(): from pyknow.rule import Rule from pyknow.fact import Fact, L from pyknow.engine import KnowledgeEngine class Person(Fact): pass executed = False class Person_KE(KnowledgeEngine): @Rule(Person(name=L("David"))) def david(self): self.declare(Person(name=L("Pepe"), apellido=L("stuff"))) @Rule(Person(name=L("Pepe"))) def pepe(self): nonlocal executed executed = True ke_ = Person_KE() ke_.deffacts(Person(name=L("David"))) ke_.reset() ke_.run() assert executed
def test_or_notmatching_operator(): """ Test OR operator """ from pyknow.engine import KnowledgeEngine from pyknow.rule import Rule, OR from pyknow.fact import Fact, L class Test(KnowledgeEngine): """ Test KE """ @Rule(OR(Fact(something=L(1)), Fact(something=L(2)))) def rule1(self): """ First rule, something=1 and something=2""" pass static = ((1, 3), (1, 3, 5)) for test in static: ke_ = Test() ke_.reset() for val in test: ke_.deffacts(Fact(none=L(val))) ke_.reset() assert len(ke_.agenda.activations) == 0 ke_.run()
def test_V_resolve(): """ Test V Resolve """ from pyknow.fact import Fact, V, L key = "key_test" context = {key: True} not_fact = V(key) against_fact = Fact(**{key: L(True)}) assert not_fact.resolve(against_fact, key, context)
def test_N_resolve(): """ Test N Resolve """ from pyknow.fact import Fact, N, L key = "key_test" context = {key: True} not_fact = N(key) against_fact = Fact(**{key: L(False)}) assert not_fact.resolve(against_fact, key, context)
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_match_with_W_True(kwargs): assume('something' not in kwargs) from pyknow.fact import Fact, W, L f0 = Fact(**{a: L(b) for a, b in kwargs.items()}) f1 = Fact(something=W(False)) assert f1.matches(f0, {})
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_matching_captured_different_facts_AND(): from pyknow.rule import Rule from pyknow.fact import Fact, L, V, C from pyknow.engine import KnowledgeEngine class Person(Fact): pass executions = [] class Person_KE(KnowledgeEngine): @Rule(Person(name=C("name")), Person(surname=V('name'))) def same_name(self, name): nonlocal executions executions.append(name) ke_ = Person_KE() ke_.deffacts(Person(surname=L('surname'), name=L("NotAName"))) ke_.deffacts(Person(name=L('name'), surname=L("NotAName"))) ke_.reset() ke_.run() assert executions == ["NotAName"]
def test_and_N_negative(): from pyknow.rule import Rule from pyknow.fact import Fact, L, N, C from pyknow.engine import KnowledgeEngine class Person(Fact): pass executions = [] class Person_KE(KnowledgeEngine): @Rule(Person(name=L("name"), age=C('age')), Person(name=L("name"), age=N("age"))) def same_name(self, age): nonlocal executions executions.append(age) ke_ = Person_KE() ke_.deffacts(Person(name=L("name"), age=L(18))) ke_.deffacts(Person(name=L('name'), age=L(18))) ke_.reset() ke_.run() assert executions == []
def test_default_is_and(): """ Test that AND is the default operator """ from collections import defaultdict from pyknow.engine import KnowledgeEngine from pyknow.rule import Rule from pyknow.fact import Fact, L executions = [] class Test(KnowledgeEngine): """ Test KE """ @Rule(Fact(something=L(1)), Fact(something=L(2))) def rule1(self): """ First rule, something=1 and something=2""" nonlocal executions executions.append('rule1') @Rule(Fact(something=L(3))) def rule2(self): """ Second rule, only something=3 """ nonlocal executions executions.append('rule2') ke_ = Test() to_declare = [] for i in range(1, 10): to_declare.append(L(i)) to_declare = dict(enumerate(to_declare)) for k, n in to_declare.items(): ke_.deffacts(Fact(something=n)) ke_.reset() results = defaultdict(list) for activation in ke_.agenda.activations: results[''.join([str(to_declare[a - 1].resolve()) for a in activation.facts])].append(1) assert dict(results) == {'3': [1], '12': [1]} assert len(ke_.agenda.activations) == 2 ke_.run() assert executions.count('rule1') == 1 assert executions.count('rule2') == 1
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_KnowledgeEngine_get_activations_returns_activations(): from pyknow.engine import KnowledgeEngine from pyknow.rule import Rule from pyknow.fact import Fact, L class Test(KnowledgeEngine): # pylint: disable=too-few-public-methods @Rule(Fact(a=L(1))) def test(self): # pylint: disable=no-self-use pass ke = Test() ke.deffacts(Fact(a=L(1))) ke.reset() activations = list(ke.get_activations()) assert len(activations) == 1
class Base(KnowledgeEngine): @Rule(Person(name=L('pepe'))) def is_pepe(self): self.declare(Person(drinks=L("coffee")))
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_not_aggreation(): from pyknow.rule import Rule, NOT, AND from pyknow.fact import Fact, L, N, C from pyknow.engine import KnowledgeEngine class Person(Fact): pass class ConflictResolver(Fact): pass executions = [] class Person_KE(KnowledgeEngine): @Rule(NOT(ConflictResolver(resolved=L(True))), AND(Person(name=L("name"), age=C('age')), Person(name=L("name"), age=N("age")))) def same_name(self, age): nonlocal executions executions.append(age) ke_ = Person_KE() ke_.deffacts(Person(name=L("name"), age=L(18))) ke_.deffacts(Person(name=L('name'), age=L(19))) ke_.deffacts(ConflictResolver(resolved=L(True))) ke_.reset() ke_.run() assert executions == [] executions = [] ke_ = Person_KE() ke_.deffacts(Person(name=L("name"), age=L(18))) ke_.deffacts(Person(name=L('name'), age=L(19))) ke_.reset() ke_.run() assert executions == [19] executions = [] ke_ = Person_KE() ke_.deffacts(Person(name=L("name"), age=L(18))) ke_.deffacts(Person(name=L('name'), age=L(18))) ke_.reset() ke_.run() assert executions == [] ke_ = Person_KE() ke_.deffacts(Person(name=L("name"), age=L(18))) ke_.deffacts(Person(name=L('name'), age=L(18))) ke_.deffacts(ConflictResolver(resolved=L(True))) ke_.reset() ke_.run() assert executions == []
class Person_KE(KnowledgeEngine): @Rule(Person(name=L("name"), age=C('age')), Person(name=L("name"), age=N("age"))) def same_name(self, age): nonlocal executions executions.append(age)
def david(self): self.declare(Person(name=L("Pepe"), apellido=L("stuff")))
def david(self): self.declare(Person(name=L("Pepe")))
class Test(Base): @Rule(Person(drinks=L("coffee"))) def drinks_coffee(self): nonlocal executed executed = True
def is_pepe(self): self.declare(Person(drinks=L("coffee")))
class Test(KnowledgeEngine): # pylint: disable=too-few-public-methods @Rule(Fact(a=L(1))) def test(self): # pylint: disable=no-self-use pass