174 lines
5.8 KiB
ReStructuredText
174 lines
5.8 KiB
ReStructuredText
Rules
|
|
========
|
|
|
|
Abstract
|
|
****************
|
|
As I previously explain, there are two main categories of object to make Sheerka come to life :
|
|
* the concepts
|
|
* the rules
|
|
|
|
When the purpose of the concepts is to connect Sheerka with the outside world (our world),
|
|
The purpose of the rules is to define how to react in different situation.
|
|
|
|
The combination of the two, the concepts and the rules, brings the intelligence.
|
|
|
|
|
|
Basic definition
|
|
****************
|
|
To define a new rule
|
|
|
|
|
|
::
|
|
|
|
> when <predicate> then|print <action>
|
|
|
|
Rules can have name, so you can also use the syntax
|
|
|
|
::
|
|
|
|
> def rule <name> as when <predicate> then|print <action>
|
|
|
|
|
|
You can define action rule (using then) or display rule (using print). As of today, the two
|
|
sets of rules are different, but they may be merged if no notable difference is found.
|
|
|
|
Existing rule engines
|
|
*********************
|
|
|
|
I am not quite sure yet about the implementation. I have started to search on the net to see if
|
|
I can found some interesting implementation that I can use.
|
|
|
|
I found:
|
|
|
|
* Durable Rules Engine : https://github.com/jruizgit/rules
|
|
|
|
Python implementation, with the rule engine written in C (or C++) to be faster. A good candidate
|
|
|
|
* PyKE : http://pyke.sourceforge.net/knowledge_bases/rule_bases.html
|
|
|
|
Another Python implementation of the rule engine
|
|
|
|
* Business-rules : https://github.com/venmo/business-rules
|
|
|
|
* Intellect : https://github.com/nemonik/Intellect
|
|
|
|
* CLIPS : http://www.clipsrules.net/
|
|
|
|
A standard. Run on a separate server. I need to check how it can be embedded, or dockerized
|
|
|
|
* And of course drools : https://www.drools.org/
|
|
|
|
Another standard
|
|
|
|
I am not an expert in rule engine. So I guess that the best way to figure out what engine to use it to list what are the feature that I need.
|
|
|
|
|
|
Use cases
|
|
*********
|
|
|
|
I see the rules engine like the caching service or the logging service, in the way as it can be used anywhere in the code.
|
|
It's not just a global feature of Sheerka. It's another way of achieving common task.
|
|
|
|
For example, in the print service, I want to print all the failed ``ReturnValueConcept`` in red.
|
|
Doing it in an imperative way (ie coding this functionality) is
|
|
|
|
1. Intrusive in the code. I need to understand what code and where to put it
|
|
2. Not straightforward : if I want to that all successful ``ReturnValueConcept`` in green, chances are that I will have to rewrite some code
|
|
|
|
So It has to be declarative. With an engine that takes these declarations and correctly paint the outputs.
|
|
And a declarative system that accepts conditions is (I guess) a rule engine.
|
|
|
|
So let's try something like:
|
|
|
|
::
|
|
|
|
> when action==Print and obj==ReturnValueConcept and obj.status then print_the_status_in_red()
|
|
|
|
We immediately see that the rule engine will have to be aware of the current system.
|
|
So the chosen rule engine will have to manage state or facts. I haven't checked all the listed one, but I am quite sure that they all do,
|
|
as it's the minimum requirement for a rule engine.
|
|
|
|
I also need two types of rules.
|
|
|
|
* permanent rules
|
|
It will be triggered as long as the system allows it
|
|
|
|
* one use rule:
|
|
it will be triggered only once
|
|
|
|
If I take my example to color the status of the ``ReturnValueConcept``, it may be a permanent rule,
|
|
that will apply to any output, or it can be something that is specific to the current execution context.
|
|
|
|
|
|
In the predicate part, I need to control how expression are evaluated.
|
|
For example in the expression ``action==Print``, Print can be a string ('Print'), a builtin concept (``BuiltinConcepts.PRINT``) or even another concept
|
|
|
|
|
|
In the predicate part, as well as in the action part, I must be able to used other concepts
|
|
For example, if I have the following concept already defined ::
|
|
|
|
> def concept status is not ok as <whatever suits>
|
|
> def concept paint in red as <whatever suits>
|
|
|
|
|
|
then I must be able to use ::
|
|
|
|
> when status is not ok then paint in red
|
|
|
|
|
|
Execution rules
|
|
***************
|
|
|
|
The first rule that I would like to define is the 'hello sheerka' rule. The principle is simple, if I enter 'hello sheerka', Sheerka should respond 'hello kodjo'
|
|
|
|
First proposal ::
|
|
|
|
> def greetings as hello x where x
|
|
> when greetings and greetings.x == Sheerka then 'hello kodjo'
|
|
|
|
|
|
Note that in this example, greetings is used name of concept when it is recognized, but also
|
|
as a name of variable in the test.
|
|
|
|
Why not ? ::
|
|
|
|
> def greetings as hello x where x
|
|
> when hello Sheerka then 'hello kodjo'
|
|
|
|
which is different from ::
|
|
|
|
> def greetings as hello x where x
|
|
> when 'hello Sheerka' then 'hello kodjo'
|
|
|
|
In the first version, I supposed that the concept 'greetings' is recognized
|
|
|
|
A more advanced version for the action part will be ::
|
|
|
|
> when greetings and greetings.x == Sheerka then answer(call_concept('greetings', __user))
|
|
|
|
I said earlier that I would like the rule engine to be called whenever I want. So now,
|
|
there is the important question of when calling the rule.
|
|
|
|
A rule like ``when greetings and greetings.x == Sheerka then 'hello kodjo'`` must be called after than
|
|
the concept ``greetings`` is recognized. But Should I call it before or after the 'Print' ?
|
|
|
|
And should I consider the response as a new event, this time triggerd by Sheerka, rather than by a user ?
|
|
|
|
|
|
Implementation
|
|
***************
|
|
|
|
The 'implementation' deals with how the rules are evaluated. I have two engines.
|
|
|
|
The first one, within the class ``SheerkaEvaluateRule`` is a simple and naive implementation.
|
|
It sorts the rule by priorities and evaluate them one after the other. Once rule matches the available data (the bag)
|
|
the algorithm stops.
|
|
|
|
The other implementation is more sophisticated. It's an implementation of the 'Rete'
|
|
algorithm (https://en.wikipedia.org/wiki/Rete_algorithm).
|
|
|
|
.. _phD: https://fr.wikipedia.org/wiki/Ulysse_31
|
|
.. _PyRete: https://github.com/cmaclell/py_rete
|
|
|
|
My work is based on PyRete_ wich it is itself a Python implementation of
|
|
the phD_ of Doorenbos (1995) |