1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
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>
8
<div><a><img alt="PyPy" height="110" id="pyimg" src="http://codespeak.net/pypy/img/py-web1.png" width="149"/></a></div>
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>
19
<h1><a id="the-problem" name="the-problem">The problem</a></h1>
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
27
<p>Currently, there is an implementation of computation spaces that is
28
sufficient enough for constraint solving. It uses :</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>
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>
46
<pre class="literal-block">
55
choice: return 0 or: return 1
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
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
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 -> foo : choice
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>
113
<p>The choice operator can be written straightforwardly in terms of
115
<pre class="literal-block">
121
from math import sqrt
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>
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>
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
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>
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
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
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
"provided by PyPy, stackless team"
189
class CompSpace(Microthread):
191
"""solver API"""
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)
204
def commit(self, choice):
205
"""tells the space which choice point to pick"""
208
"""returns a cloned computation space"""
212
extract solution values from an entailed space
213
furher calls to space methods will raise
217
"""distributor API"""
221
blocks until commit is called
222
returns the choice value that
223
was given to the commit call
228
mark the space as failed
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
237
def var(self, domain, name=None):
239
creates a possibly named contraint variable inside
240
the space, returns the variable object
243
def tell(self, constraint):
244
"""register a constraint"""
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
b'\\ No newline at end of file'