Closed FTholin closed 6 years ago
There are several ways of doing this, but for recommending one we need to know more about your use case. What are you trying to accomplish by separating the rules from the engine declaration?
I would like to add more flexibility in my program in adding all rules in a text or json file for example. That would allow me to change rules or load what those I want easier. I hope my answer was enough to explain my problem. Thanks again.
PyKnow doesn't support rule externalization out of the box yet. But we are aware of this being a desirable feature and we have it in roadmap #25 . In the meanwhile you can check this already answered question about rule externalization #2 , the same principles may be applied to JSON instead of XML.
You may find also interesting the multiple-engine joining method using mixings applied here: https://github.com/buguroo/pyknow/blob/develop/docs/talks/Sistemas%20Expertos%20en%20Python%20con%20PyKnow%20-%20PyConES%202017/Descuentos.ipynb
Thank you very much for these resources ! I'll study them with great attention.
Did you delete the comment after reopening the issue?
Hello, i try to build up a KE with a specific rule as a goal setup, depending on external parameters. But the dynamic assertion of rule drive me crazy ! I tryed to setup the rule inside the init function, the Rule is returned by get_rules. A closer inspection show me some differences between a rule instancied "normally" and the dynamically added (in _wrapped_self). I assume there is some stuff on the KE side to be setup. My test code looks like following :
def set_goal(args):
def goal(self):
self.declare(Fact("GOAL"))
print("GOAL REACHED")
return Rule(args)(goal)
class OtherTestEngine(KnowledgeEngine):
rule1 = set_goal(Fact("A"))
def __init__(self, goal):
super().__init__()
self.rule2 = set_goal(goal)
test = OtherTestEngine(Fact("B"))
test.reset()
print(test.get_rules())
test.declare(Fact("A"))
print(test.facts)
test.run()
print(test.facts)
output :
[Rule(Fact('A'),) => <function set_goal.<locals>.goal at 0x7f7af48cc7b8>, Rule(Fact('B'),) => <function set_goal.<locals>.goal at 0x7f7af48c2840>]
<f-0>: InitialFact()
<f-1>: Fact('A')
GOAL REACHED
<f-0>: InitialFact()
<f-1>: Fact('A')
<f-2>: Fact('GOAL')
And,
test.reset()
test.declare(Fact("B"))
print(test.facts)
test.run()
print(test.facts)
output :
<f-0>: InitialFact()
<f-1>: Fact('B')
<f-0>: InitialFact()
<f-1>: Fact('B')
Do you have any suggestion about the way to fix that ?
EDIT : i got a dirty way to fix that
def solve_stuff(goal, facts):
class Engine(KnowledgeEngine):
rule1 = set_goal(goal)
@Rule(Fact("A"), Fact("B"))
def rule2(self):
self.declare(Fact("C"))
e = Engine()
e.reset()
for f in facts:
e.declare(f)
e.run()
return e
solution = solve_stuff(Fact("C"), [Fact("A"), Fact("B")])
output :
GOAL REACHED
Hi @bonzeye ,
thank you for reporting this, we lack some documentation about the behavior of the matcher and rule generation.
The key point here is WHEN the matcher generates the RETE network, it is done ONLY on KnowledgeEngine.__init__()
. So any rule not visible before your super().__init__()
will not be taken into account.
So, your code:
def set_goal(args):
def goal(self):
self.declare(Fact("GOAL"))
print("GOAL REACHED")
return Rule(args)(goal)
class OtherTestEngine(KnowledgeEngine):
rule1 = set_goal(Fact("A"))
def __init__(self, goal):
super().__init__()
self.rule2 = set_goal(goal)
will not work, but if you call __init__()
AFTER the rule creation it will:
class OtherTestEngine(KnowledgeEngine):
rule1 = set_goal(Fact("A"))
def __init__(self, goal):
self.rule2 = set_goal(goal)
super().__init__() # <-- AFTER the rule creation
Therefore, any code creating dynamic rules before __init__
will work and any code creating them after will not.
There are several ways of doing this and we have to document about it.
Additionally when we finish #25, the dynamic generation of rules will be less of a necessity.
tyvm for the fast answer, it helped me a lot.
Hi, I am new to PyKnow and I am attempting to make a functionnality that will allow me to load the set of Rules from an external file. I tried to use set_attr but without success the interpreter doesn't like the RULE decorator. Do you know a manner to do it properly ? Thank you in advance for your time and consideration