Files

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)