~ubuntu-branches/ubuntu/karmic/pypy/karmic

« back to all changes in this revision

Viewing changes to pypy/doc/discussion/logic-plan.html

  • Committer: Bazaar Package Importer
  • Author(s): Alexandre Fayolle
  • Date: 2007-04-13 09:33:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070413093309-yoojh4jcoocu2krz
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
2
<html>
 
3
  <head>
 
4
    <title>PyPy[logic-plan] </title>
 
5
    <meta content="text/html;charset=ISO-8859-1" name="Content-Type"/>
 
6
    <link href="style.css" media="screen" rel="stylesheet" type="text/css"/></head>
 
7
  <body>
 
8
    <div><a><img alt="PyPy" height="110" id="pyimg" src="http://codespeak.net/pypy/img/py-web1.png" width="149"/></a></div>
 
9
    <div id="metaspace">
 
10
      <div class="project_title">PyPy[logic-plan] </div>
 
11
      <div id="menubar"><a class="menu" href="http://codespeak.net/pypy/dist/pypy/doc/news.html">news</a> <a class="menu" href="../getting-started.html">getting-started</a> <a class="menu" href="../index.html">documentation</a> <a class="menu" href="https://codespeak.net/viewvc/pypy/dist/">svn</a> <a class="menu" href="https://codespeak.net/issue/pypy-dev/">issues</a><a class="menu" href="../contact.html">contact</a> <a class="menu" href="http://pypy.org/">EU/project</a>  </div></div>
 
12
    <div id="contentspace">
 
13
      <div id="docinfoline">
 
14
        <div style="float: right; font-style: italic;"> </div></div>
 
15
<div class="document" id="some-ideas-about-implementation-of-logic-programming">
 
16
<h1 class="title">Some ideas about implementation of Logic Programming</h1>
 
17
 
 
18
<div class="section">
 
19
<h1><a id="the-problem" name="the-problem">The problem</a></h1>
 
20
<div class="section">
 
21
<h2><a id="basics" name="basics">Basics</a></h2>
 
22
<p>Logic and contraint programming as envisionned in PyPy draws heavily
 
23
on the Computation Space concept present in the Oz language.</p>
 
24
<p>Computation spaces provide an infrastructure and API that allows
 
25
seamless integration of concurrent constraint and logic programming in
 
26
the language.</p>
 
27
<p>Currently, there is an implementation of computation spaces that is
 
28
sufficient enough for constraint solving. It uses :</p>
 
29
<p>ask()
 
30
clone()
 
31
commit()</p>
 
32
<p>in straightforward ways. This space is merely a constraint store for
 
33
finite domain constraint variables. It does not really support
 
34
execution of arbitrary computations 'inside' the space ; only
 
35
constraint propagation, i.e. a fixed interrpeter-level algorithm, is
 
36
triggered on commit() calls. [note: don't look at the current code ...]</p>
 
37
</div>
 
38
<div class="section">
 
39
<h2><a id="choice-points" name="choice-points">Choice points</a></h2>
 
40
<p>For logic programming we need more. Basically a 'logic program' is a
 
41
standard Python program augmented with the 'choice' operator. The
 
42
program's entry point must be a zero arity procedure. Any program
 
43
whose execution path contains a 'choice' is a logic, or relational (in
 
44
Oz parlance) program.</p>
 
45
<p>For instance:</p>
 
46
<pre class="literal-block">
 
47
def foo():
 
48
    choice:
 
49
        return bar()
 
50
    or:
 
51
        from math import sqrt
 
52
        return sqrt(4)
 
53
 
 
54
def bar():
 
55
   choice: return 0 or: return 1
 
56
 
 
57
def entry_point():
 
58
    a = foo()
 
59
    if a &lt; 2:
 
60
       fail()
 
61
    return a
 
62
</pre>
 
63
<p>What should happen when we encounter a choice ? One of the choice
 
64
points ought to be chosen 'non-deterministically'. That means that the
 
65
decision to choose does not belong to the program istelf (it is not an
 
66
'if clause' depending on the internal state of the program) but to
 
67
some external entity having interest in the program outcomes depending
 
68
on the various choices that can be made in a choice-littered program.</p>
 
69
<p>Such an entity is typically a 'solver' exploring the space of the
 
70
program outcomes. The solver can use a variety of search strategies,
 
71
for instance depth-first, breadth-first, discrepancy search,
 
72
best-search, A* ... It can provide just one solution or some or all of
 
73
them.</p>
 
74
<p>Thus the program and the methods to extract information from it are
 
75
truly independant, contrarily to Prolog programs which are hard-wired
 
76
for depth-first exploration (and do not support concurrency, at least
 
77
not easily).</p>
 
78
</div>
 
79
<div class="section">
 
80
<h2><a id="choice-continued" name="choice-continued">Choice, continued</a></h2>
 
81
<p>The above program contains just one choice point. If given to a depth
 
82
first search solver, it will produce three spaces : the two first
 
83
spaces will be failed and thus discarded, the third will be a solution
 
84
space and ready to be later merged. We leave the semantics of space
 
85
merging for another day.</p>
 
86
<p>Pardon the silly ascii art:</p>
 
87
<pre class="literal-block">
 
88
entry_point -&gt; foo : choice
 
89
                      /\
 
90
                     /  \
 
91
                    /    2 (solution)
 
92
           bar : choice
 
93
                  /\
 
94
                 /  \
 
95
                /    \
 
96
               0      1
 
97
          (failure)(failure)
 
98
</pre>
 
99
</div>
 
100
<div class="section">
 
101
<h2><a id="search-and-spaces" name="search-and-spaces">Search and spaces</a></h2>
 
102
<p>To allow this de-coupling between program execution and search
 
103
strategy, the computation space comes handily. Basically, choices are
 
104
made, and program branches are taken, in speculative computations
 
105
which are embedded, or encapsulated in the so-called computation
 
106
space, and thus do not affect the whole program, nor each other, until
 
107
some outcome (failure, values, updated speculative world) is
 
108
considered and eventually merged back into the parent world (which
 
109
could be the 'top-level' space, aka normal Python world, or another
 
110
speculative space).</p>
 
111
<p>For this we need another method of spaces :</p>
 
112
<p>choose()</p>
 
113
<p>The choice operator can be written straightforwardly in terms of
 
114
choose:</p>
 
115
<pre class="literal-block">
 
116
def foo():
 
117
    choice = choose(3)
 
118
    if choice == 1:
 
119
        return 1
 
120
    elif choice == 2:
 
121
        from math import sqrt
 
122
        return sqrt(4)
 
123
    else: # choice == 3
 
124
        return 3
 
125
</pre>
 
126
<p>Choose is more general than choice since the number of branches can be
 
127
determined at runtime. Conversely, choice is a special case of choose
 
128
where the number of branches is statically determined. It is thus
 
129
possible to provide syntactic sugar for it.</p>
 
130
<p>It is important to see the relationship between ask(), choose() and
 
131
commit(). Ask and commit are used by the search engine running in the
 
132
top-level space, in its own thread, as follows :</p>
 
133
<p>ask() wait for the space to be 'stable', which means that the program
 
134
running inside is blocked on a choose() call. It returns precisely the
 
135
value provided by choose, thus notifying the search engine about the
 
136
number of available choice points. The search engine can then,
 
137
depending on its strategy, commit() the space to one of its branches,
 
138
thus unblocking the choose() call and giving a return value which
 
139
represent the branch to be taken. The program encapsulated in the
 
140
space can thus run until :</p>
 
141
<ul class="simple">
 
142
<li>it encounters another choice point,</li>
 
143
<li>it fails (by way of explicitly calling the fail() operator, or
 
144
raising an uncatched exception up to its entry point),</li>
 
145
<li>properly terminating, thus being a candidate 'satisfying' solution
 
146
to the problem it stands for.</li>
 
147
</ul>
 
148
<p>Commit and choose allow a disciplined communication between the world
 
149
of the search engine (the normal Python world) and the speculative
 
150
computation embedded in the space. Of course the search and the
 
151
embedded computation run in different threads. We need at least one
 
152
thread for the search engine and one per space for this scheme to
 
153
work.</p>
 
154
</div>
 
155
<div class="section">
 
156
<h2><a id="cloning" name="cloning">Cloning</a></h2>
 
157
<p>The problematic thing for us is what happens before we commit to a
 
158
specific choice point. Since the are many of them, the solver
 
159
typically needs to take a snapshot of the current computation space so
 
160
as to be able to later try the other choice points (possibly all of
 
161
them if it has been asked to enumerate all solutions of a relational
 
162
or constraint program).</p>
 
163
<p>Taking a snapshot, aka cloning, is easy when the space is merely a
 
164
constraint store. It is more involved when it comes to snapshotting a
 
165
whole tree of threads. It is akin to saving and making copies of the
 
166
current continuation (up to some thread frame).</p>
 
167
</div>
 
168
</div>
 
169
<div class="section">
 
170
<h1><a id="solutions-or-ideas-in-the-direction-of" name="solutions-or-ideas-in-the-direction-of">Solutions, or ideas in the direction of</a></h1>
 
171
<div class="section">
 
172
<h2><a id="copying-collector" name="copying-collector">Copying collector</a></h2>
 
173
<p>In Mozart computation space cloning is implemented by leveraging the
 
174
copying garbage collector. There is basically a switch on the GC entry
 
175
point which tells whether it is asked to really do GC or just clone a
 
176
space.</p>
 
177
</div>
 
178
<div class="section">
 
179
<h2><a id="thread-cloning" name="thread-cloning">Thread cloning</a></h2>
 
180
<p>It is expected that PyPy coroutines/greenlets/microthreads be at some
 
181
point picklable. One could implement clone() using the thread pickling
 
182
machinery.</p>
 
183
<p>Such is the abstract interface of computation spaces (the
 
184
inherit-from-threads part is a bit speculative):</p>
 
185
<pre class="literal-block">
 
186
class MicroThread ...
 
187
     &quot;provided by PyPy, stackless team&quot;
 
188
 
 
189
class CompSpace(Microthread):
 
190
 
 
191
     &quot;&quot;&quot;solver API&quot;&quot;&quot;
 
192
 
 
193
     def ask(self):
 
194
         &quot;&quot;&quot;
 
195
         blocks until the space is stable, which means that
 
196
         the embedded computation has reached a fixpoint
 
197
         returns int in [0,1,n]
 
198
            0 : space is failed (further calls to the
 
199
                                 space raise an exception)
 
200
            1 : space is entailed (solution found)
 
201
            n : space is distributable (n choice points)
 
202
         &quot;&quot;&quot;
 
203
 
 
204
     def commit(self, choice):
 
205
         &quot;&quot;&quot;tells the space which choice point to pick&quot;&quot;&quot;
 
206
 
 
207
     def clone(self):
 
208
         &quot;&quot;&quot;returns a cloned computation space&quot;&quot;&quot;
 
209
 
 
210
     def merge(self):
 
211
         &quot;&quot;&quot;
 
212
         extract solution values from an entailed space
 
213
         furher calls to space methods will raise
 
214
         an exception
 
215
         &quot;&quot;&quot;
 
216
 
 
217
     &quot;&quot;&quot;distributor API&quot;&quot;&quot;
 
218
 
 
219
     def choose(self):
 
220
         &quot;&quot;&quot;
 
221
         blocks until commit is called
 
222
         returns the choice value that
 
223
         was given to the commit call
 
224
         &quot;&quot;&quot;
 
225
 
 
226
     def fail(self):
 
227
         &quot;&quot;&quot;
 
228
         mark the space as failed
 
229
         &quot;&quot;&quot;
 
230
 
 
231
     &quot;&quot;&quot;
 
232
     constraint stuff : a space acts as/contains a constraint
 
233
     store which holds : logic variables, constraint variables
 
234
     (logic vars augmented with finite domains), constraints
 
235
     &quot;&quot;&quot;
 
236
 
 
237
     def var(self, domain, name=None):
 
238
         &quot;&quot;&quot;
 
239
         creates a possibly named contraint variable inside
 
240
         the space, returns the variable object
 
241
         &quot;&quot;&quot;
 
242
 
 
243
     def tell(self, constraint):
 
244
         &quot;&quot;&quot;register a constraint&quot;&quot;&quot;
 
245
</pre>
 
246
<p>Programs runing in a computation spaces should not be allowed to alter
 
247
the top-level space (i.e interaction with the global program state and
 
248
outside world).</p>
 
249
</div>
 
250
</div>
 
251
</div>
 
252
</div></body></html>
 
 
b'\\ No newline at end of file'