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

Events and reasoning - can they work together? #82

Open
MobileSolutionsPL opened this issue May 12, 2017 · 4 comments
Open

Events and reasoning - can they work together? #82

MobileSolutionsPL opened this issue May 12, 2017 · 4 comments

Comments

@MobileSolutionsPL
Copy link

MobileSolutionsPL commented May 12, 2017

Hi!
I've noticed that when I try to mix fact reasoning with events, first event fired is disabling reasoner. I'm attaching sample code to picture the problem. Please check attached code and the console output.

The goal is to have kind of stateful object (true/false in the example) and the domain ontology model as a set of rules. I've decided to implement state as a fact, maybe it's wrong approach. Since events are immediately retracted facts, I've created another fact as a still temporary but persisted medium (at least persisted longer than an event). After an event is handled, the state changing fact is asserted.

I've tested events both from the @when_start method and as the curl invocation. Both are disabling the reasoner (or there is some kind of exception in the background, but it's not logged on the console)

Which is also noticed, I can't identify nothing as an atomic operation or transaction-like approach. I've thought that adding new fact should destabilize the state. Other operations should be freezed for the reasoning time or until the state is steady again. In the output setter-facts are one after another and after them the fact value is switching (I've got strong Java background, in Java I'd check the flush() method on the sysout to ensure that it's not a matter of standard output).

  • Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
    some fact is false
    some fact set true
    some fact set false
    some fact is true
    some fact is false
    *** switcher set important fact to :: true
    some fact set true

The example is really simplified :)

My source code at the end (sorry for the formatting, I don't know why it looks so weird...)

`from durable.lang import *
RULESET_NAME = 'reasoning-and-events'
with ruleset(RULESET_NAME):
#logger
@when_all(+m.subject)
def output(c):
print('{0} {1} {2}'.format(c.m.subject, c.m.predicate, c.m.object))

#init state
@when_start
def start(c):
    #some fact is set
    c.assert_fact(RULESET_NAME, { 'subject': 'some fact', 'predicate': 'is', 'object': 'false' })

    #state switcher fact
    c.assert_fact(RULESET_NAME, { 'subject': 'some fact', 'predicate': 'set', 'object': 'true' })
    c.assert_fact(RULESET_NAME, { 'subject': 'some fact', 'predicate': 'set', 'object': 'false' })

    #NOTE: after posting an event, reasoner seems to be disabled
    c.post(RULESET_NAME, {'sid': '997', 'event': {'category': 'switcher', 'value': 'true'}})


@when_all(c.importantFact << m.predicate=='is', c.actionFact << m.predicate=='set')
def changeState(c):
    c.retract_fact(c.importantFact)
    c.assert_fact({ 'subject': 'some fact', 'predicate': 'is', 'object': c.actionFact.object })
    c.retract_fact(c.actionFact)


@when_all(c.extEvent << m.event.category=='switcher')
def tempChanged(c):
    print '*** switcher set important fact to :: ',c.extEvent.event.value
    c.assert_fact(RULESET_NAME, { 'subject': 'some fact', 'predicate': 'set', 'object': c.extEvent.event.value })

run_all()`

@jruizgit
Copy link
Owner

Hi, thanks for posting the question. I tried your scenario and it works as I expected. I noticed you posted the event using 'sid': '997', which effectively executes the event under a different reasoning session. I wonder if this was intentional. Please try this code:

RULESET_NAME = 'reasoning-and-events'
with ruleset(RULESET_NAME):
    #logger
    @when_all(+m.subject)
    def output(c):
        print('{0} {1} {2} {3}'.format(c.m.subject, c.m.predicate, c.m.object, c.m.id))

    
    @when_all(c.importantFact << m.predicate == 'is', 
              c.actionFact << m.predicate == 'set')
    def changeState(c):
        print('observed {0} {1}'.format(c.importantFact.id, c.actionFact.id))
        c.retract_fact(c.importantFact)
        c.assert_fact({ 'subject': 'some fact', 'predicate': 'is', 'object': c.actionFact.object })
        c.retract_fact(c.actionFact)


    @when_all(c.extEvent << m.event.category == 'switcher')
    def tempChanged(c):
        print '*** switcher set important fact to :: ', c.extEvent.event.value
        c.assert_fact(RULESET_NAME, { 'subject': 'some fact', 'predicate': 'set', 'object': c.extEvent.event.value })


    #init state
    @when_start
    def start(c):
        #some fact is set
        c.assert_fact(RULESET_NAME, { 'subject': 'some fact', 'predicate': 'is', 'object': 'false' })

        #state switcher fact
        c.assert_fact(RULESET_NAME, { 'subject': 'some fact', 'predicate': 'set', 'object': 'true' })
        c.assert_fact(RULESET_NAME, { 'subject': 'some fact', 'predicate': 'set', 'object': 'false' })

        #NOTE: after posting an event, reasoner seems to be disabled
        c.post(RULESET_NAME, { 'event': {'category': 'switcher', 'value': 'true'}})


run_all()

@jruizgit
Copy link
Owner

One note on your question regarding atomicity: All actions are transactional and atomic. That is, if the process crashes in the middle of an action execution, no facts will be asserted nor retracted, no events will posted, the action will be retried when the process restarts. All actions related to the same reasoning session ('sid') are executed under the same logical thread, in other words only one action is executed at any given time, even when the action is asynchronous.

@MobileSolutionsPL
Copy link
Author

MobileSolutionsPL commented May 15, 2017

OK, it is not stopping the reasoner now, which is perfect :) the question now is if post or assert_fact methods are asynchronous? Is there an option to force reasoner to infer new facts in the synchronized way? Im posting my output with the sequence of output messages that I've expected them to appear:

In other words after asserting a fact I'd like to get an output of the reasoner and then set up another fact. Because in the middle of the calls the state is unstable and may cause my solution to fail. In this sequence the fact (state of the switcher) is being set to False before it is in the True state.

@jruizgit
Copy link
Owner

Hi, posting events and asserting facts only guarantees the data will be stored in the ruleset's beta nodes when the outcome is '0'. Scheduled actions are always dispatched asynchronous. Currently there are no no synchronization mechanisms other than two rulesets posting and reacting to events:

  1. ruleset 'a' posts an event to ruleset 'b'
  2. ruleset 'a' has a rule to react to ruleset 'b' reply

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

2 participants