Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

[c237fe]: doc / html / logic_programming / rules / backward_chaining.html Maximize Restore History

Download this file

backward_chaining.html    350 lines (331 with data), 17.8 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Backward Chaining</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="../../stylesheets/pyke.css" type="text/css" />
</head>
<body>
<table id="page-table">
<thead class="head">
<tr id="header1"><th id="header" colspan="3">
&nbsp;
</th></tr>
<tr id="header2">
<th id="crumb-left"></th>
<th id="crumb-line">
<div id="nav">
<ul>
<li><a href="../../index.html">Home</a></li>
<li>&gt;</li>
<li><a href="../index.html">Logic Programming</a></li>
<li>&gt;</li>
<li><a href="index.html">Rules</a></li>
<li>&gt;</li>
<li>Backward Chaining</li>
</ul>
</div>
</th>
<th id="crumb-right"></th>
</tr>
</thead>
<tbody id="body">
<tr id="body-tr">
<td id="left-nav">
<div id="left-nav-div">
<div class="title-nav"><a href="../../index.html">Home</a></div><div class="nav-branch">
<div class="normal-nav"><a href="../../about_pyke/index.html">About Pyke</a></div>
<div class="title-nav"><a href="../index.html">Logic Programming</a></div><div class="nav-branch">
<div class="normal-nav"><a href="../statements.html">Statements</a></div>
<div class="normal-nav"><a href="../pattern_matching/index.html">Pattern Matching</a></div>
<div class="title-nav"><a href="index.html">Rules</a></div><div class="nav-branch">
<div class="normal-nav"><a href="forward_chaining.html">Forward Chaining</a></div>
<div class="normal-nav"><a href="backward_chaining.html">Backward Chaining</a></div>
</div>
<div class="normal-nav"><a href="../plans.html">Plans</a></div>
</div>
<div class="normal-nav"><a href="../../knowledge_bases/index.html">Knowledge Bases</a></div>
<div class="normal-nav"><a href="../../pyke_syntax/index.html">Pyke Syntax</a></div>
<div class="normal-nav"><a href="../../using_pyke.html">Using Pyke</a></div>
<div class="normal-nav"><a href="../../examples.html">Examples</a></div>
<div class="normal-nav"><a href="../../PyCon2008-paper.html">PyCon 2008 Paper</a></div>
</div>
</div>
<div id="icons">
<div id="project-page">
<a href="http://sourceforge.net/projects/pyke/">Pyke Project Page</a>
</div>
Please Make a Donation:<br />
<a href="http://sourceforge.net/donate/index.php?group_id=207724">
<img src="http://images.sourceforge.net/images/project-support.jpg"
width="88" height="32" border="0"
alt="Support This Project" /> </a> <br /><br />
Hosted by: <br />
<a href="http://sourceforge.net/projects/pyke">
<img src="http://sflogo.sourceforge.net/sflogo.php?group_id=207724&amp;type=14"
width="150" height="40"
alt="Get Python Knowledge Engine (PyKE) at SourceForge.net. Fast, secure and Free Open Source software downloads" /></a>
</div>
</td>
<td id="main-td">
<div id="main">
<a name="startcontent" id="startcontent"></a>
<div class="document" id="backward-chaining">
<h1 class="title">Backward Chaining</h1>
<p>Backward chaining <a class="reference external" href="index.html">rules</a> are processed when your program asks Pyke a <a class="reference external" href="../../knowledge_bases/question_bases.html">question</a>
(i.e., asks Pyke to <a class="reference external" href="../../using_pyke.html#proving-goals">prove</a> a specific <em>goal</em>). Pyke will only use <a class="reference external" href="../../using_pyke.html#setting-up-each-case">activated</a>
<a class="reference external" href="../../knowledge_bases/rule_bases.html">rule bases</a> to do the proof.</p>
<div class="section" id="overview-of-backward-chaining">
<h2>Overview of &quot;Backward-Chaining&quot;</h2>
<p>To do backward-chaining, Pyke finds rules whose <em>then</em> part matches the <em>goal</em>
(i.e., the question). Once it finds such a rule, it tries to (recursively)
prove all of the subgoals in the <em>if</em> part of that rule. Some of these
subgoals are matched against facts, and others are subgoals for other
backward-chaining rules. If all of the subgoals can be proven, the rule
succeeds and the original goal is proven. Otherwise, the rule fails, and Pyke
tries to find another rule whose <em>then</em> part matches the goal, and so on.</p>
<p>So Pyke ends up linking (or <em>chaining</em>) the <em>if</em> part of the first rule to the
<em>then</em> part of the next rule.</p>
<p>Reviewing:</p>
<ol class="arabic simple">
<li>Pyke starts by finding a rule whose <em>then</em> part matches the goal.</li>
<li>Pyke then proceeds to process the <em>if</em> part of that rule.</li>
<li>Which may link (or chain) to the <em>then</em> part of another rule.</li>
</ol>
<p>Since Pyke processes these rules from <em>then</em> to <em>if</em> to <em>then</em> to <em>if</em> in the
reverse manner that we normally think of using rules, it's called <em>backward</em>
chaining.</p>
<p>To make this more clear, Pyke has you write your backward-chaining rules
upside down by writing the <em>then</em> part first (since that's how it is
processed).</p>
</div>
<div class="section" id="use-when-rather-than-then-if">
<h2>&quot;Use&quot;, &quot;When&quot; Rather than &quot;Then&quot;, &quot;If&quot;</h2>
<p>But <em>then-if</em> rules sound confusing, so Pyke uses the words <strong>use</strong> and
<strong>when</strong> rather than <strong>then</strong> and <strong>if</strong>. You can then read the rule as &quot;use&quot;
this statement &quot;when&quot; these other statements can be proven.</p>
<div class="note">
<p class="first admonition-title">Note</p>
<p class="last">Unlike the <em>assert</em> clause in <a class="reference external" href="forward_chaining.html">forward-chaining</a> rules, Pyke only allows
one statement in the <em>use</em> clause.</p>
</div>
</div>
<div class="section" id="example">
<h2>Example</h2>
<p>Consider this example:</p>
<pre class="literal-block">
1 direct_father_son
2 use father_son($father, $son, ())
3 when
4 family.son_of($son, $father)
5 grand_father_son
6 use father_son($grand_father, $grand_son, (grand))
7 when
8 father_son($father, $grand_son, ())
9 father_son($grand_father, $father, ())
10 great_grand_father_son
11 use father_son($gg_father, $gg_son, (great, $prefix1, *$rest_prefixes))
12 when
13 father_son($father, $gg_son, ())
14 father_son($gg_father, $father, ($prefix1, *$rest_prefixes))
15 brothers
16 use brothers($brother1, $brother2)
17 when
18 father_son($father, $brother1, ())
19 father_son($father, $brother2, ())
20 check $brother1 != $brother2
21 uncle_nephew
22 use uncle_nephew($uncle, $nephew, $prefix)
23 when
24 brothers($uncle, $father)
25 father_son($father, $nephew, $prefix1)
26 $prefix = ('great',) * len($prefix1)
27 cousins
28 use cousins($cousin1, $cousin2, $distance, $removed)
29 when
30 uncle_nephew($uncle, $cousin1, $prefix1)
31 father_son($uncle, $cousin2, $prefix2)
32 $distance = min(len($prefixes1), len($prefixes2)) + 1
33 $removed = abs(len($prefixes1) - len($prefixes2))
</pre>
<div class="note">
<p class="first admonition-title">Note</p>
<p class="last">These <a class="reference external" href="index.html">rules</a> draw the same conclusions as the <a class="reference external" href="forward_chaining.html">forward-chaining</a> <a class="reference external" href="forward_chaining.html#example">example</a>,
with the addition of the <em>brothers</em>, <em>uncle_nephew</em> and <em>cousins</em> rules.</p>
</div>
<p>We can draw something similar to a function call graph with these rules:</p>
<div align="center" class="figure">
<img alt="../../images/bc_rules.png" src="../../images/bc_rules.png" style="width: 509.0px; height: 583.0px;" />
<p class="caption">Example Rules</p>
</div>
<p>These <a class="reference external" href="index.html">rules</a> are not used until you ask Pyke to <a class="reference external" href="../../using_pyke.html#proving-goals">prove</a> a goal.</p>
<p>The easiest way to do this is with <em>some_engine.prove_1</em> or
<em>some_engine.prove_n</em>. <a class="reference external" href="../../using_pyke.html#proving-goals">Prove_1</a> only returns the first proof found and
then stops (or raises <tt class="docutils literal"><span class="pre">pyke.knowledge_engine.CanNotProve</span></tt>). <a class="reference external" href="../../using_pyke.html#proving-goals">Prove_n</a>
returns a context manager for a generator that generates all possible proofs
(which, in some cases, might be infinite). In both cases, you pass a tuple
of data arguments and the number of variable arguments as the last two
parameters. The total number of arguments for the goal is the sum of the
length of the data arguments that you pass plus the number of variable
arguments that you specify.</p>
<p>Both functions return the variable bindings for the number of variable
arguments you specified as a tuple, along with the <a class="reference external" href="../plans.html">plan</a>.</p>
</div>
<div class="section" id="backtracking-with-backward-chaining-rules">
<h2>Backtracking with Backward-Chaining Rules</h2>
<p>For this example, these are the starting set of <tt class="docutils literal"><span class="pre">family</span></tt> facts:</p>
<pre class="literal-block">
1 son_of(tim, thomas)
2 son_of(fred, thomas)
3 son_of(bruce, thomas)
4 son_of(michael, bruce)
</pre>
<p>And we want to know who fred's nephews are. So we'd ask <tt class="docutils literal"><span class="pre">uncle_nephew(fred,</span>
<span class="pre">$nephew,</span> <span class="pre">$prefix)</span></tt>.</p>
<p>Here are the steps (in parenthesis) in the inferencing up until the first
failure is encountered (with the line number from the example preceding each
line):</p>
<pre class="literal-block">
(1) 22 use uncle_nephew(fred, $nephew, $prefix)
25 brothers(fred, $father)
(2) 25 use brothers(fred, $brother2)
18 father_son($father, fred, ())
(3) 2 use father_son($father, fred, ())
4 family.son_of(fred, $father)
19 father_son(thomas, $brother2, ())
(4) 2 use father_son(thomas, $son, ())
4 family.son_of($son, thomas)
20 check fred != tim
24 father_son(tim, $nephew, $prefix1)
(5.1) 2 use father_son(tim, $son, ())
4 family.son_of($son, tim) =&gt; FAILS
(5.2) 6 use father_son(tim, $grand_son, (grand))
8 father_son(tim, $grand_son, ())
2 use father_son(tim, $son, ())
4 family.son_of($son, tim) =&gt; FAILS
(5.3) 11 use father_son(tim, $gg_son, (great, $prefix1, *$rest_prefixes))
13 father_son(tim, $gg_son, ())
2 use father_son(tim, $son, ())
4 family.son_of($son, tim) =&gt; FAILS
</pre>
<p>Each rule invocation is numbered (in parenthesis) as a step number. Step 5
has tried 3 different rules and they have all failed (5.1, 5.2 and 5.3).</p>
<p>If you think of the rules as functions, the situation now looks like this
(the step numbers that succeeded circled in black, and steps that failed
circled in red):</p>
<div align="center" class="figure">
<img alt="../../images/bc_backtracking.png" src="../../images/bc_backtracking.png" style="width: 590.0px; height: 465.0px;" />
<p class="caption">We Need to Backtrack!</p>
</div>
<p>At this point, Pyke has hit a dead end and must backtrack. The way that
backtracking proceeds is to go back up the list of steps executed, combining
the steps from all rules into one list. Thus, when step 5 fails, Pyke backs
up to step 4 and tries to find another solution to that step.</p>
<p>If another solution is found, Pyke proceeds forward again from that point. If
no other solutions are found, Pyke backs up another step.</p>
<p>When Pyke goes back to step 4, the next solution binds <tt class="docutils literal"><span class="pre">$son</span></tt> to <tt class="docutils literal"><span class="pre">fred</span></tt>.
This fails the subsequent check in the <tt class="docutils literal"><span class="pre">brothers</span></tt> rule:</p>
<pre class="literal-block">
20 check $brother1 != $brother2
</pre>
<p>And so Pyke goes back to step 4 once again. The next solution binds <tt class="docutils literal"><span class="pre">$son</span></tt>
to <tt class="docutils literal"><span class="pre">bruce</span></tt>. This succeeds for <tt class="docutils literal"><span class="pre">brother</span></tt> and is passed down to
<tt class="docutils literal"><span class="pre">father_son</span></tt> which returns <tt class="docutils literal"><span class="pre">michael</span></tt> as <tt class="docutils literal"><span class="pre">fred's</span></tt> nephew.</p>
<p>Further backtracking reveals no other solutions.</p>
<div class="section" id="backtracking-summary">
<h3>Backtracking Summary</h3>
<p>Thus we see:</p>
<ol class="arabic simple">
<li>The <a class="reference external" href="index.html#backtracking">backtracking</a> algorithm: &quot;<strong>fail</strong> goes <em>up</em> (or <em>back</em>) while
<strong>success</strong> goes <em>down</em> (or <em>forward</em>)&quot; is not limited to the steps within a
<em>single</em> rule's <tt class="docutils literal"><span class="pre">when</span></tt> clause; but includes the <em>entire</em> chain of
inferencing from the very start of trying to prove the top level goal.</li>
<li>This execution model is not available within traditional programming
languages like Python.</li>
<li>The ability to go back to <em>any</em> point in the computation to try an
alternate solution is where backward-chaining systems get their power!</li>
</ol>
</div>
</div>
<div class="section" id="running-the-example">
<h2>Running the Example</h2>
<blockquote>
<pre class="doctest-block">
&gt;&gt;&gt; from pyke import knowledge_engine
&gt;&gt;&gt; engine = knowledge_engine.engine('doc.examples')
&gt;&gt;&gt; engine.assert_('family', 'son_of', ('tim', 'thomas'))
&gt;&gt;&gt; engine.assert_('family', 'son_of', ('fred', 'thomas'))
&gt;&gt;&gt; engine.assert_('family', 'son_of', ('bruce', 'thomas'))
&gt;&gt;&gt; engine.assert_('family', 'son_of', ('michael', 'bruce'))
&gt;&gt;&gt; engine.activate('bc_example')
</pre>
</blockquote>
<p>Nothing happens this time when we activate the rule base, because there are no
forward-chaining rules here.</p>
<p>We want to ask the question: &quot;Who are Fred's nephews?&quot;. This translates
into the Pyke statement: <tt class="docutils literal"><span class="pre">bc_example.uncle_nephew(fred,</span> <span class="pre">$v1,</span> <span class="pre">$v2)</span></tt>.</p>
<div class="note">
<p class="first admonition-title">Note</p>
<p class="last">Note that we're using the name of the rule base, <tt class="docutils literal"><span class="pre">bc_example</span></tt> rather than
the fact base, <tt class="docutils literal"><span class="pre">family</span></tt> here; because we expect this answer to come from
the <tt class="docutils literal"><span class="pre">bc_example</span></tt> rule base.</p>
</div>
<p>This is 'bc_example', 'uncle_nephew', with ('fred',) followed by 2 pattern
variables as arguments:</p>
<blockquote>
<pre class="doctest-block">
&gt;&gt;&gt; from __future__ import with_statement
&gt;&gt;&gt; with engine.prove_n('bc_example', 'uncle_nephew', ('fred',), 2) as gen:
... for vars, no_plan in gen:
... print(vars)
('michael', ())
</pre>
</blockquote>
<!-- ADD_LINKS MARKER -->
</div>
</div>
<!-- <div id="return-to-top">
<a href="#">Return to Top</a>
</div>
-->
</div>
</td>
<td id="right-nav">
<div id="right-nav-div">
<h3>More:</h3>
<div class="right-item"><a href="forward_chaining.html">Forward Chaining</a><p>Explanation of <em>forward-chaining rules</em> and how <em>forward-chaining</em>
works.</p>
</div>
<div class="right-item"><a href="backward_chaining.html">Backward Chaining</a><p>Explanation of <em>backward-chaining</em> rules, including how
<em>backward-chaining</em> and <em>backtracking</em> works.</p>
</div>
</div>
</td>
</tr>
</tbody>
<tfoot id="foot">
<tr id="foot2">
<td id="copyright" colspan="3">
Copyright &copy; 2007-2009 Bruce Frederiksen
</td>
</tr>
</tfoot>
</table>
<div id="last-modified">
Page last modified
Tue, Apr 21 2009.
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ?
"https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost +
"google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-6310805-1");
pageTracker._trackPageview();
} catch(err) {}
</script>
</body>
</html>