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

’EXISTS' cannot return accuracy results, influenced by the pattern order insider. #14

Open
AndrewChung-GitHub opened this issue Nov 25, 2019 · 9 comments
Assignees
Labels
question Further information is requested

Comments

@AndrewChung-GitHub
Copy link

AndrewChung-GitHub commented Nov 25, 2019

from experta import *


class Goal(Fact):
    pass


class Hero(Fact):
    name = Field(str)
    status = Field(str, default="unoccupied")


class KE(KnowledgeEngine):
    @DefFacts()
    def goal_and_heroes(self):
        yield Goal('save-the-day')
        yield Hero(name="Death Defying Man")
        yield Hero(name="Stupendous Man")
        yield Hero(name="Incredible Man")

    @Rule(
        Goal('save-the-day'),
        EXISTS(            # bugs: return results influenced by the patterns order
            Hero(name="Death Defying Man"),
            Hero(status='occupied'),
            # Hero(status='occupied'),
            # Hero(name="Death Defying Man")
        )
    )
    def save_the_day(self):
        print("The day is saved")


if __name__ == '__main__':
    ke = KE()
    ke.reset()
    watch('RULES')
    ke.run()

Result:

The day is saved
INFO:experta.watchers.RULES:FIRE 1 save_the_day: <f-1>, <f-0>

However, if I reverse the patterns order inEXISTS, the result would be empty.

@AndrewChung-GitHub AndrewChung-GitHub changed the title ’EXISTS' cannot return accuracy results, influenced by the insider pattern order. ’EXISTS' cannot return accuracy results, influenced by the pattern order insider. Nov 25, 2019
@nilp0inter
Copy link
Owner

Hi,

I am trying to reproduce the issue but in my tests the rule:

    @Rule(
        Goal('save-the-day'),
        EXISTS(
            Hero(name="Death Defying Man"),
            Hero(status='unoccupied'),
        )
    )
    def save_the_day(self):
        print("The day is saved")

and

    @Rule(
        Goal('save-the-day'),
        EXISTS(
            Hero(status='unoccupied'),
            Hero(name="Death Defying Man"),
        )
    )
    def save_the_day(self):
        print("The day is saved")

both yields the same result.

Which experta version are you using?

@AndrewChung-GitHub
Copy link
Author

experta.__version__

'1.9.4'

please take note I used Hero(status='occupied') nor 'unoccupied'. Due to Hero(status='occupied') hadn't be defined above, it didn't exist. Could you try again, thanks.

@nilp0inter
Copy link
Owner

Oh, I think I understand. The example is not very clear, but the behavior is correct.

Let me explain: In the definition of Hero the field status has a default value unoccupied. That means that any declared Hero fact that lacks the status field will have an implicit value of unoccupied.

This is why the rule in the original example matched and yours don't. The explicit version would be:

    @DefFacts()
    def goal_and_heroes(self):
        yield Goal('save-the-day')
        yield Hero(name="Death Defying Man", status="unoccupied")
        yield Hero(name="Stupendous Man", status="unoccupied")
        yield Hero(name="Incredible Man", status="unoccupied")

In your case the rule is not matching because there are no heroes with status="occupied".

@nilp0inter
Copy link
Owner

I modified the example to remove the implicit value. Please let me know if this way is more clear.

@AndrewChung-GitHub
Copy link
Author

Thanks for your quickly response, however, you may misunderstood my point.
My concern is on the function of 'EXIST', I think as long as there is one or more facts matching, it should continue to execute following actions. However, in this case, it yields different results.

@nilp0inter
Copy link
Owner

You are very welcome, thank you for using experta.

For EXISTS to match, there must be at least one instance of each fact inside the EXISTS clause. As you can see the rule is not satisfied because none of the declared facts has status="occupied" in it.

@AndrewChung-GitHub
Copy link
Author

yeah, indeed the facts status="occupied" didn't exist, but the fact Hero(name="Death Defying Man") always exists. Hence, I think no matter the order of these two patterns adjusted, the results should be the same and output the result of print("The day is saved").

@nilp0inter nilp0inter added the question Further information is requested label Nov 25, 2019
@nilp0inter nilp0inter self-assigned this Nov 25, 2019
@nilp0inter
Copy link
Owner

The behavior that you are describing is not the behavior of the EXISTS clause but the OR clause. Please try the OR clause to see if it meets your requirements.

Also, check #8 for another clause that can be helpful to you.

@AndrewChung-GitHub
Copy link
Author

Thanks for your patient explanations.

Yeah, I have not yet fully understood the function of "EXISTS", and fall into confusion about the descriptions in your reference file.

This CE receives a pattern and matches if one or more facts matches this pattern. This will match only once while one or more matching facts exists and will stop matching when there is no matching facts.

Could you give me more explanations and introductions on application scenarios?
Thanks again.

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

No branches or pull requests

2 participants