Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load rule set dynamically in KnowledgeEngine #35

Closed
FTholin opened this issue Jul 18, 2018 · 9 comments
Closed

Load rule set dynamically in KnowledgeEngine #35

FTholin opened this issue Jul 18, 2018 · 9 comments

Comments

@FTholin
Copy link

FTholin commented Jul 18, 2018

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

## Extern file 
  @Rule(Light(color='green'))
     def green_light(self):
        print("Walk")
    
     @Rule(Light(color='red'))
     def red_light(self):
         print("Don't walk")
###########################
from pyknow import *

class Light(Fact):
    """Info about the traffic light."""
    pass


class RobotCrossStreet(KnowledgeEngine):
  # no rules hardcoded 


if __name__ == '__main__':
    engine = RobotCrossStreet()
    engine.reset()
    engine.declare(Light(color="green"))
    engine.run()
@nilp0inter
Copy link
Contributor

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?

@FTholin
Copy link
Author

FTholin commented Jul 18, 2018

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.

@nilp0inter
Copy link
Contributor

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.

@nilp0inter
Copy link
Contributor

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

@FTholin
Copy link
Author

FTholin commented Jul 20, 2018

Thank you very much for these resources !
I'll study them with great attention.

@FTholin FTholin closed this as completed Jul 20, 2018
@FTholin FTholin reopened this Jul 25, 2018
@nilp0inter
Copy link
Contributor

Did you delete the comment after reopening the issue?

@FTholin FTholin closed this as completed Jul 30, 2018
@jclarte
Copy link

jclarte commented Sep 4, 2018

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

@nilp0inter
Copy link
Contributor

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.

@jclarte
Copy link

jclarte commented Sep 4, 2018

tyvm for the fast answer, it helped me a lot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants