Implemented a first and basic version of a Rete rule engine
This commit is contained in:
@@ -1093,3 +1093,37 @@ Blog
|
||||
""""""
|
||||
Hi, I have the feeling that I am almost there with the parsers part. I have
|
||||
|
||||
|
||||
|
||||
|
||||
2021-01-30
|
||||
**********
|
||||
|
||||
Blog
|
||||
""""""
|
||||
|
||||
It's been a very long time since I wrote in the blog. I guess I was too busy to spend some time on it.
|
||||
2020 was the year of the COVID 19. I guess that being contained with my son and my wife gave me other priorities.
|
||||
|
||||
Nevertheless, I kept on working on Sheerka.
|
||||
|
||||
One major achivement that I made was a demonstration of Sheerka to other people. I happened in mid September.
|
||||
I demonstrated how to declare numbers using the ExactParser and the BnfNodeParser. Even thought I did not explicitly
|
||||
mentionned theses names, my demo was far to technique. The impression I gave was that Sheerka was too complicated (in
|
||||
the sens of too technical too use). Unfortunately, that was the case.
|
||||
|
||||
Did the demo come too soon ? I guess so, in a certain way, but It really helped me to have a first feedback, even if it did
|
||||
not reward the months of hard works.
|
||||
|
||||
Where am I today ? It's impressive the admit that since that demon (in September) I did not implemented any major capability.
|
||||
Sheerka does not know much bettet that at this time
|
||||
|
||||
I did though work on :
|
||||
|
||||
* performances
|
||||
* debugger
|
||||
* simple version of the rule engine (that goes with the debuggger)
|
||||
|
||||
Actually almost FOUR months of work for technical benefit. There were some parts of the code that were rewritten.
|
||||
|
||||
I am a little bit sad, time flies so fast.
|
||||
@@ -26,6 +26,7 @@ There will be two types of documentation
|
||||
|
||||
tech/tech
|
||||
tech/debugger
|
||||
tech/rules
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -17,3 +17,119 @@ in an 'imperative' way.
|
||||
First, you need to enable the debugger. As it consumes resource, it is deactivated by default ::
|
||||
|
||||
set_debug()
|
||||
|
||||
|
||||
There are three types of objects that can be debugged :
|
||||
|
||||
* variables
|
||||
* concepts
|
||||
* rules
|
||||
|
||||
Debug Settings
|
||||
--------------
|
||||
|
||||
Path to object
|
||||
**************
|
||||
Whatever the type of object to be displayed, it lies within a method name, which is itself inside a service.
|
||||
|
||||
For example, the out_tree (the ast tree that contains what to print once an input is evaluated) is under the service
|
||||
'Out' and within the method 'create_out_tree'
|
||||
|
||||
The information regarding the evaluation of the rule #1 is under the service 'EvaluateRules', and within the method 'evaluate_rule'
|
||||
|
||||
Context id
|
||||
**********
|
||||
The same object may be requested several times. To distinguish different execution, the ExecutionContext id is used.
|
||||
When using the context id, you can precise if you want to debug a specific context, or a context and its children
|
||||
|
||||
Debug id
|
||||
********
|
||||
The debug id is supposed to regroup information of the same unit of processing together. For example, within the same context,
|
||||
if a specific piece of processing is called several times (because of a loop for example), they will share the same context id,
|
||||
but they will have different debug id.
|
||||
|
||||
Note that as of now, this does not
|
||||
work very well. This information need to be tuned.
|
||||
|
||||
Debug Variables
|
||||
---------------
|
||||
|
||||
Debugging variables let you see the content of variables, but also the execution flow of a piece of program.
|
||||
This execution flow gives a context to the variables
|
||||
|
||||
To activate variable debugging :
|
||||
|
||||
debug_var(<path_to_variable>, <context_id>, <debug_id>)
|
||||
|
||||
|
||||
With:
|
||||
|
||||
* path_to_variable
|
||||
* 'service_name' : Activates the debug logs for all methods of the service. The variable won't be shown
|
||||
* 'service_name.method_name' : Activates the debug logs for the specific method of the service, the variables won't be shown
|
||||
* 'service_name.method_name.variable_name' : Activates the display of a variable, within a specific method, for a specific service
|
||||
* 'service_name.*'
|
||||
|
||||
* context_id
|
||||
* context_id
|
||||
* 'context_id+' (context_id followed by the sign '+')
|
||||
|
||||
* debug_id
|
||||
* debug_id
|
||||
|
||||
Debug Rule
|
||||
---------------
|
||||
|
||||
Debugging rules let you see how the rules are evaluated, but also the execution flow of the evaluation.
|
||||
|
||||
To activate rule debugging :
|
||||
|
||||
debug_var(<path_to_rule>, <context_id>, <debug_id>)
|
||||
|
||||
|
||||
With:
|
||||
|
||||
* path_to_rule (when a string is given)
|
||||
* 'service_name' : Activates the debug logs for all methods of the service. The variable won't be shown
|
||||
* 'service_name.method_name' : Activates the debug logs for the specific method of the service, the variables won't be shown
|
||||
* 'service_name.method_name.rule_id' : Activates the debug of a specific rule, within a specific method, for a specific service
|
||||
* 'service_name.*'
|
||||
|
||||
* path_to_rule (when an integer is given)
|
||||
* rule_id
|
||||
|
||||
* context_id
|
||||
* context_id
|
||||
* 'context_id+' (context_id followed by the sign '+')
|
||||
|
||||
* debug_id
|
||||
* debug_id
|
||||
|
||||
|
||||
Debug Concept
|
||||
---------------
|
||||
|
||||
Debugging concept let you see how the concepts are evaluated, but also the execution flow of the evaluation.
|
||||
|
||||
To activate concept debugging :
|
||||
|
||||
debug_var(<path_to_concept>, <context_id>, <debug_id>)
|
||||
|
||||
|
||||
With:
|
||||
|
||||
* path_to_concept when a string is given
|
||||
* 'service_name' : Activates the debug logs for all methods of the service. The variable won't be shown
|
||||
* 'service_name.method_name' : Activates the debug logs for the specific method of the service, the variables won't be shown
|
||||
* 'service_name.method_name.concept_id' : Activates the debug of a specific concept, within a specific method, for a specific service
|
||||
* 'service_name.*'
|
||||
|
||||
* path_to_concept when an integer is given
|
||||
* concept_id
|
||||
|
||||
* context_id
|
||||
* context_id
|
||||
* 'context_id+' (context_id followed by the sign '+')
|
||||
|
||||
* debug_id
|
||||
* debug_id
|
||||
@@ -1,6 +1,16 @@
|
||||
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
|
||||
@@ -10,15 +20,18 @@ To define a new rule
|
||||
|
||||
::
|
||||
|
||||
> when <predicate> then <action>
|
||||
> when <predicate> then|print <action>
|
||||
|
||||
Rules can have name, so you can also use the syntax
|
||||
|
||||
::
|
||||
|
||||
> def rule <name> as when <predicate> then <action>
|
||||
> 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
|
||||
*********************
|
||||
|
||||
@@ -53,7 +66,7 @@ I am not an expert in rule engine. So I guess that the best way to figure out wh
|
||||
Use cases
|
||||
*********
|
||||
|
||||
I see the rules engine like the caching service or the logging service. It can be used anywhere in the code.
|
||||
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.
|
||||
@@ -92,9 +105,70 @@ In the predicate part, I need to control how expression are evaluated.
|
||||
|
||||
|
||||
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)
|
||||
Reference in New Issue
Block a user