Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 442 lines (351 sloc) 14.166 kB
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
1 SERESYE - Swarm oriented ERlang Expert SYstem Engine
2 ====================================================
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
3
4 Introduction
5 ------------
6
7 SERESYE is a Rete based rules engine written in Erlang, descended
8 directly from the Eresye project by Francesca Gangemi and Corrado
9 Santoro. In the following article we will describe how to use the
10 system.
11
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
12 As it is widely known, a rule-based system is composed by a
13 **knowledge base**, which stores a set of *facts* representing the
14 'universe of discourse' of a given application, and a set of
15 **production rules**, which are used to infer knowledge and/or reason
16 about the knowledge. A rule is activated when one or more facts match
17 the template(s) given in the rule declaration: in such a case, the
18 body of the rule contains a code that is thus executed
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
19
20 In SERESYE, *facts* are expressed by means of Erlang tuples or records,
21 while rules are written using standard Erlang function clauses, whose
22 declaration reports, in the clause head, the facts or fact templates
23 that have to be matched for the rule to be activated and executed.
24
25 For more information about SERESYE please refer to the paper docs directory.
26
27 For more information about rule-based inference engines and expert
28 systems, you can refer to the book: *S. Russell and
29 P. Norvig. **Artificial Intelligence: A Modern Approach/2E.** Prentice
30 Hall, 2003.*
31
32 To write an AI application with SERESYE the following steps have to be
33 performed:
34
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
35 1. Indentify your universe of discourse and determine the facts that
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
36 have to be used to represent such a world;
37
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
38 2. Indentify the rules that you need and write them by using, e.g.
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
39 first-order-logic predicates or even natural language;
40
41 3. Implement the system by writing your rules as Erlang function
42 clauses, according to the modality required by SERESYE.
43
44
45 The Application: the Domain of Relatives
46 ----------------------------------------
47
48 We will design a system able to derive new knowledge using some
49 inference rules and starting from a small set; as a sample
50 application, we chose the domain of relatives: we will start from some
51 base concepts, such as *parent*, *male* and *female*, and then, by
52 means of a proper set of rules, we will derive the concepts of
53 *mother*, *father*, *sister*, *brother*, *grandmother* and
54 *grandfather*.
55
56 According to the list above, we will first derive the facts that will be
57 used to represent our concepts. Given the set of relationships above, they
58 will be represented by means of the following facts:
59
60 <table border="1" align="center">
61 <thead>
62 <tr>
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
63 <td>#</td>
64 <td>Concept</td>
65 <td>Fact / Erlang tuple</td>
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
66 </tr>
67 </thead>
68 <tbody>
69 <tr>
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
70 <td>1</td>
71 <td>X is male</td>
72 <td><tt>{male, X}</tt></td>
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
73 </tr>
74 <tr>
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
75 <td>2</td>
76 <td>X is female</td>
77 <td><tt>{female, X}</tt></td>
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
78 </tr>
79 <tr>
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
80 <td>3</td>
81 <td>X is Y's parent</td>
82 <td><tt>{parent, X, Y}</tt></td>
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
83 </tr>
84 <tr>
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
85 <td>4</td>
86 <td>X is Y's mother</td>
87 <td><tt>{mother, X, Y}</tt></td>
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
88 </tr>
89 <tr>
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
90 <td>5</td>
91 <td>X is Y's father</td>
92 <td><tt>{father, X, Y}</tt></td>
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
93 </tr>
94 <tr>
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
95 <td>6</td>
96 <td>X is Y's sister</td>
97 <td><tt>{sister, X, Y}</tt></td>
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
98 </tr>
99 <tr>
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
100 <td>7</td>
101 <td>X is Y's brother</td>
102 <td><tt>{brother, X, Y}</tt></td>
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
103 </tr>
104 <tr>
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
105 <td>8</td>
106 <td>X is Y's grandmother</td>
107 <td><tt>{grandmother, X, Y}</tt></td>
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
108 </tr>
109 <tr>
aee8df8 Add 'deps/seresye/' from commit '5d6e626fc83f67e2a20d06ce2902c5702778…
Yurii Rashkovskii authored
110 <td>9</td>
111 <td>X is Y's grandfather</td>
112 <td><tt>{grandfather, X, Y}</tt></td>
39dc2e3 @ericbmerritt add initial project site
ericbmerritt authored
113 </tr>
114 </tbody>
115 </table>
116
117 Concepts 1, 2 and 3 will be used as a base to derive the other ones.
118
119 Deriving new concepts by means of rules
120 ---------------------------------------
121
122 #### Concept: mother
123
124 The rule to derive the concept of mother is quite
125 straightforward:
126
127 if X is female and X is Y's parent then X is Y's mother.
128
129 From the point of view of SERESYE, since knowledge is stored in the
130 *knowledge base* of the engine, the rule above is translated into the
131 following one: *if the facts {female, X} and {parent, X, Y} are
132 *asserted* in the knowledge base, then we assert the fact {mother, X,
133 Y}.
134
135 The rule *mother* can be thus written as follows:
136
137 %%
138 %% if (X is female) and (X is Y's parent) then (X is Y's mother)
139 %%
140 mother (Engine, {female, X}, {parent, X, Y}) ->
141 seresye:assert (Engine, {mother, X, Y}).
142
143
144 #### Concept: father
145
146 This concept can be easily derived by means of the following rule:
147
148 %%
149 %% if (X is male) and (X is Y's parent) then (X is Y's father)
150 %%
151 father (Engine, {male, X}, {parent, X, Y}) ->
152 seresye:assert (Engine, {father, X, Y}).
153
154
155 #### Concept: sister
156
157 This concept can be expressed by the following rule:
158
159 if Y and Z have the same parent and Z is female, then Z
160 is the Y's sister.
161
162 The SERESYE rule used to map this concept is:
163
164 %%
165 %% if (Y and Z have the same parent X) and (Z is female)
166 %% then (Z is Y's sister)
167 %%
168 sister (Engine, {parent, X, Y}, {parent, X, Z}, {female, Z}) when Y =/= Z ->
169 seresye:assert (Engine, {sister, Z, Y}).
170
171
172 Please note the guard, which is needed to ensure that when Y and Z are
173 bound to the same value, the rule is not activated (indeed this is
174 possible since the same fact can match both the first and second
175 'parent' pattern).
176
177 #### Concept: brother
178
179 Given the previous one, this concept is now quite simple to
180 implement:
181
182
183 %%
184 %% if (Y and Z have the same parent X) and (Z is male)
185 %% then (Z is Y's brother)
186 %%
187 brother (Engine, {parent, X, Y}, {parent, X, Z}, {male, Z}) when Y =/= Z ->
188 seresye:assert (Engine, {brother, Z, Y}).
189
190
191 #### Concepts: grandmother and grandfather
192
193 The former concept can be expressed by means of the rule:
194
195 if X is Y's mother and Y is Z's parent, then X is Z's
196 grandmother.</u>* The latter concept is now obvious.
197
198 Both can be implemented using the following SERESYE rules:
199
200 %%
201 %% if (X is Y's mother) and (Y is Z's parent)
202 %% then (X is Z's grandmother)
203 %%
204 grandmother (Engine, {mother, X, Y}, {parent, Y, Z}) ->
205 seresye:assert (Engine, {grandmother, X, Z}).
206
207 %%
208 %% if (X is Y's father) and (Y is Z's parent)
209 %% then (X is Z's grandfather)
210 %%
211 grandfather (Engine, {father, X, Y}, {parent, Y, Z}) ->
212 seresye:assert (Engine, {grandfather, X, Z}).
213
214
215 Instantiating the Engine and Populating the Knowledge Base
216 ----------------------------------------------------------
217
218 After writing the rules, we need to:
219
220 - define the rules to seresye
221 - instantiate the engine;
222 - populate the knowledge base with a set of initial facts.
223
224 We define the rules to SERESYE by defined a 'rules' attribute at the
225 start of the module.
226
227 %%%
228 %%% relatives.erl
229 %%%
230 -module (relatives).
231
232 -export([father/3, grandfather/3, grandmother/3,
233 mother/3, brother/4, sister/4, start/0]).
234
235 -rules([mother, father, brother, sister, grandfather,
236 grandmother]).
237
238 We continue on to instantiate the engine and popoulate the knowledge
239 base in the function *start* below:
240
241 start () ->
242 application:start(seresye) % Only if it is not already started
243 seresye:start(relatives),
244 seresye:add_rules(relatives, ?MODULE)
245
246 seresye:assert(relatives,
247 [{male, bob}, {male, corrado}, {male, mark}, {male, caesar},
248 {female, alice}, {female, sara}, {female, jane}, {female, anna},
249 {parent, jane, bob}, {parent, corrado, bob},
250 {parent, jane, mark}, {parent, corrado, mark},
251 {parent, jane, alice}, {parent, corrado, alice},
252 {parent, bob, caesar}, {parent, bob, anna},
253 {parent, sara, casear}, {parent, sara, anna}]),
254 ok.
255
256 As the listing reports, creating a new SERESYE engine implies to call
257 the function *seresye:start/1*, giving the name of the engine to be
258 created
259
260 Then, we have to add the rules to the engine by using the function
261 *seresye:add_rule/2*: it takes two arguments, the name of the engine
262 and a tuple representing the function in the form *{Module,
263 FuncName}*; obviously the function *Module:FuncName* must be
264 exported. Function *add_rule* has to be called for each rule that has
265 to be added; for this reason, the code above has an iteration over the
266 list of rules written before.
267
268 Finally, we populate the inference engine with a set of sample facts
269 by giving them, in a list, to the function *seresye:assert/2*. To test
270 our rules, we considered the relationships in the Figure below and
271 assert only the facts for *male*, *female* and *parent*.
272
273 Testing the application
274 -----------------------
275
276 The final complete code of our AI application is thus the following:
277
278
279 %%%
280 %%% relatives.erl
281 %%%
282 -module (relatives).
283 -export([father/3, grandfather/3, grandmother/3,
284 mother/3, brother/4, sister/4, start/0]).
285
286 %%
287 %% if (X is female) and (X is Y's parent) then (X is Y's mother)
288 %%
289 mother(Engine, {female, X}, {parent, X, Y}) ->
290 seresye:assert(Engine, {mother, X, Y}).
291
292 %%
293 %% if (X is male) and (X is Y's parent) then (X is Y's father)
294 %%
295 father(Engine, {male, X}, {parent, X, Y}) ->
296 seresye:assert(Engine, {father, X, Y}).
297
298 %%
299 %% if (Y and Z have the same parent X) and (Z is female)
300 %% then (Z is Y's sister)
301 %%
302 sister(Engine, {parent, X, Y}, {parent, X, Z}, {female, Z}) when Y =/= Z ->
303 seresye:assert(Engine, {sister, Z, Y}).
304
305 %%
306 %% if (Y and Z have the same parent X) and (Z is male)
307 %% then (Z is Y's brother)
308 %%
309 brother(Engine, {parent, X, Y}, {parent, X, Z}, {male, Z}) when Y =/= Z ->
310 seresye:assert(Engine, {brother, Z, Y}).
311
312 %%
313 %% if (X is Y's father) and (Y is Z's parent)
314 %% then (X is Z's grandfather)
315 %%
316 grandfather (Engine, {father, X, Y}, {parent, Y, Z}) ->
317 seresye:assert (Engine, {grandfather, X, Z}).
318
319 %%
320 %% if (X is Y's mother) and (Y is Z's parent)
321 %% then (X is Z's grandmother)
322 %%
323 grandmother(Engine, {mother, X, Y}, {parent, Y, Z}) ->
324 seresye:assert(Engine, {grandmother, X, Z}).
325
326 start () ->
327 application:start(seresye),
328 seresye:start (relatives),
329 seresye:add_rules(relatives, ?MODULE)
330
331 seresye:assert (relatives,
332 [{male, bob},
333 {male, corrado},
334 {male, mark},
335 {male, caesar},
336 {female, alice},
337 {female, sara},
338 {female, jane},
339 {female, anna},
340 {parent, jane, bob},
341 {parent, corrado, bob},
342 {parent, jane, mark},
343 {parent, corrado, mark},
344 {parent, jane, alice},
345 {parent, corrado, alice},
346 {parent, bob, caesar},
347 {parent, bob, anna},
348 {parent, sara, casear},
349 {parent, sara, anna}]),
350 ok.
351
352 Now it's time to test our application:
353
354
355 Erlang (BEAM) emulator version 5.5 [source] [async-threads:0] [hipe]
356
357 Eshell V5.5 (abort with ^G)
358 1> c(relatives).
359 {ok,relatives}
360 2> relatives:start().
361 ok
362 3>
363
364 Following the call to function *relatives:start/0*, the engine is
365 created and populated; if no errors occurred, the rules should have
366 been processed and the new facts derived. To check this, we can use
367 the function *seresye:get_kb/1*, which returns the list of facts
368 asserted into the knowledge base of a given engine:
369
370
371 4> seresye:get_kb(relatives).
372 [{brother,bob,mark},
373 {sister,alice,bob},
374 {sister,alice,mark},
375 {brother,bob,alice},
376 {brother,mark,alice},
377 {grandmother,jane,caesar},
378 {grandfather,corrado,caesar},
379 {grandmother,jane,anna},
380 {grandfather,corrado,anna},
381 {sister,anna,caesar},
382 {brother,caesar,anna},
383 {sister,anna,casear},
384 {mother,sara,anna},
385 {mother,sara,casear},
386 {parent,sara,anna},
387 {father,bob,anna},
388 {parent,sara,casear},
389 {father,bob,caesar},
390 {parent,bob,anna},
391 {father,corrado,alice},
392 {parent,bob,caesar},
393 {mother,jane,alice},
394 {parent,corrado,alice},
395 {father,corrado,mark},
396 {parent,jane,alice},
397 {mother,jane,mark},
398 {parent,corrado|...},
399 {brother|...},
400 {...}|...]
401 5>
402
403 The presence of facts representing concepts like *father*, *sister*,
404 etc., proves that the rules seems to be working as expected.
405
406 We can however query the knowledge base using specific fact templates.
407 For example, if we want to know who are Alice's brothers, we can use
408 the function *seresye:query_kb/2* as follows:
409
410
411 6> seresye:query_kb(relatives, {brother, '_', alice}).
412 [{brother,bob,alice},{brother,mark,alice}]
413 7>
414
415 The facts returned conform to the relationships depicted in the figure
416 above, thus proving that the rules written are really working.
417
418 As the example shows, function *seresye:query_kb/2* takes the engine
419 name as the first argument, while, for the second parameter, a tuple
420 has to be specified, representing the fact template to be matched; in
421 such a tuple, the atom *'_'* plays the role of a wildcard. However, to
422 specify a more complex matching, a *fun* can be used as a tuple
423 element; this *fun* has to return a boolean value which indicates if
424 the element matches the template. For example, to select both Alice's
425 and Anna's brothers, we can use the following function call:
426
427
428 7> seresye:query_kb(relatives, {brother, '_', fun (X) -> (X == alice) or (X == anna) end}).
429 [{brother,bob,alice},{brother,mark,alice},{brother,caesar,anna}]
430 8>
431
432
433 Conclusions
434 -----------
435
436 This HowTo not only shows how to use the SERESYE engine to write an AI
437 application, but also highlights the versatility of the Erlang language:
438 the characteristics of functional and symbolic programming, together with
439 the possibility of performing *introspection* of function declaration,
440 can be successfully exploited for application domains which are completely
441 new for Erlang but can surely be very interesting.
Something went wrong with that request. Please try again.