[pypy-svn] r29212 - pypy/dist/pypy/doc

auc at codespeak.net auc at codespeak.net
Fri Jun 23 12:27:54 CEST 2006


Author: auc
Date: Fri Jun 23 12:27:50 2006
New Revision: 29212

Added:
   pypy/dist/pypy/doc/howto-logicobjspace-0.9.html
Modified:
   pypy/dist/pypy/doc/howto-logicobjspace-0.9.txt
Log:
small links, + crude html version

Added: pypy/dist/pypy/doc/howto-logicobjspace-0.9.html
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/doc/howto-logicobjspace-0.9.html	Fri Jun 23 12:27:50 2006
@@ -0,0 +1,804 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!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" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
+<title>How to use the Logic Object space features of PyPy 0.9</title>
+<style type="text/css">
+
+/*
+:Author: David Goodger
+:Contact: goodger at users.sourceforge.net
+:Date: $Date: 2005-12-18 01:56:14 +0100 (Sun, 18 Dec 2005) $
+:Revision: $Revision: 4224 $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+*/
+
+/* used to remove borders from tables and images */
+.borderless, table.borderless td, table.borderless th {
+  border: 0 }
+
+table.borderless td, table.borderless th {
+  /* Override padding for "table.docutils td" with "! important".
+     The right padding separates the table cells. */
+  padding: 0 0.5em 0 0 ! important }
+
+.first {
+  /* Override more specific margin styles with "! important". */
+  margin-top: 0 ! important }
+
+.last, .with-subtitle {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+blockquote.epigraph {
+  margin: 2em 5em ; }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+  font-weight: bold }
+*/
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em ;
+  margin-right: 2em }
+
+div.footer, div.header {
+  clear: both;
+  font-size: smaller }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin-left: 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+  margin-top: 0.4em }
+
+h1.title {
+  text-align: center }
+
+h2.subtitle {
+  text-align: center }
+
+hr.docutils {
+  width: 75% }
+
+img.align-left {
+  clear: left }
+
+img.align-right {
+  clear: right }
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+span.section-subtitle {
+  /* font-size relative to parent (h1..h6 element) */
+  font-size: 80% }
+
+table.citation {
+  border-left: solid 1px gray;
+  margin-left: 1px }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid 1px black;
+  margin-left: 1px }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap ;
+  padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+tt.docutils {
+  background-color: #eeeeee }
+
+ul.auto-toc {
+  list-style-type: none }
+
+</style>
+</head>
+<body>
+<div class="document" id="how-to-use-the-logic-object-space-features-of-pypy-0-9">
+<h1 class="title">How to use the Logic Object space features of PyPy 0.9</h1>
+<div class="section">
+<h1><a id="outline" name="outline">Outline</a></h1>
+<p>This document gives some information about the content and usage of an
+extension of PyPy known as the Logic Objectspace (LO). The LO, when
+finished, will provide additional builtins that will allow to write:</p>
+<ul class="simple">
+<li>concurrent programs based on coroutines scheduled by dataflow logic
+variables,</li>
+<li>concurrent logic programs,</li>
+<li>concurrent constraint problems,</li>
+<li>new search &quot;engines&quot; to help solve logic/constraint programs.</li>
+</ul>
+<p>The 0.9 preview comes without logic programming; the constraint solver
+is only lightly tested, is not equipped with some specialized but
+important propagators for linear relations on numeric variables, and
+<em>might</em> support concurrency - but that would be an accident; the
+dataflow scheduling of coroutines is known to fail in at least one
+basic and important case.</p>
+<p>In this document, we skim over these topics, hoping to give enough
+information and examples for an uninformed user to understand what is
+going on and how to use the provided functionnality.</p>
+<p>To fire up a working PyPy with the LO, please type:</p>
+<pre class="literal-block">
+/root-of-pypy-dist/pypy/bin/py.py -o logic --usemodules=_stackless
+</pre>
+</div>
+<div class="section">
+<h1><a id="logic-variables-and-dataflow-synchronisation-of-coroutines" name="logic-variables-and-dataflow-synchronisation-of-coroutines">Logic Variables and Dataflow Synchronisation of Coroutines</a></h1>
+<div class="section">
+<h2><a id="logic-variables" name="logic-variables">Logic Variables</a></h2>
+<div class="section">
+<h3><a id="description-and-examples" name="description-and-examples">Description and examples</a></h3>
+<p>Logic variables are (should be, in an ideal LO) similar to Python
+variables in the following sense: they map names to values in a
+defined scope. But unlike normal Python variables, they have two
+states: free and bound. A bound logic variable is indistinguishable
+from a normal Python value, which it wraps. A free variable can only
+be bound once (it is also said to be a single-assignment variable). It
+is good practice to denote these variables with a beginning capital
+letter, so as to avoid confusion with normal variables.</p>
+<p>The following snippet creates a new logic variable and asserts its
+state:</p>
+<pre class="literal-block">
+X = newvar()
+assert is_free(X)
+assert not is_bound(X)
+</pre>
+<p>Logic variables can be bound thusly:</p>
+<pre class="literal-block">
+bind(X, 42)
+assert X / 2 == 24
+</pre>
+<p>The single-assignment property is easily checked:</p>
+<pre class="literal-block">
+bind(X, 'hello') # would raise a FailureException
+bind(X, 42)      # is admitted (it is a noop)
+</pre>
+<p>In the current state of the LO, a generic Exception will be raised.
+It is quite obvious from this that logic variables are really objects
+acting as boxes for python values. No syntactic extension to Python is
+provided yet to lessen this inconvenience.</p>
+<p>The bind operator is low-level. The more general operation that binds
+a logic variable is known as &quot;unification&quot;. Unify is an operator that
+takes two arbitrary data structures and tries to assert their
+equalness, much in the sense of the == operator, but with one
+important twist: unify mutates the state of the involved logic
+variables.</p>
+<p>Unifying structures devoid of logic variables, like:</p>
+<pre class="literal-block">
+unify([1, 2], [1, 2])
+unify(42, 43)
+</pre>
+<p>is equivalent to an assertion about their equalness, the difference
+being that a FailureException will be raised instead of an
+AssertionError, would the assertion be violated:</p>
+<pre class="literal-block">
+assert [1, 2] == [1, 2]
+assert 42 == 43
+</pre>
+<p>A basic example involving logic variables embedded into dictionnaries:</p>
+<pre class="literal-block">
+Z, W = newvar(), newvar()
+unify({'a': 42, 'b': Z},
+      {'a':  Z, 'b': W})
+assert Z == W == 42
+</pre>
+<p>Unifying one unbound variable with some value (a) means assigning the
+value to the variable (which then satisfies equalness), unifying two
+unbound variables (b) aliases them (they are constrained to reference
+the same -future- value).</p>
+<p>Assignment or aliasing of variables is provided underneath by the
+'bind' operator.</p>
+<p>An example involving custom data types:</p>
+<pre class="literal-block">
+class Foo(object):
+    def __init__(self, a):
+        self.a = a
+        self.b = newvar()
+
+f1 = Foo(newvar())
+f2 = Foo(42)
+unify(f1, f2)
+assert f1.a == f2.a == 42    # assert (a)
+assert alias_of(f1.b, f2.b)  # assert (b)
+unify(f2.b, 'foo')
+assert f1.b == f2.b == 'foo' # (b) is entailed indeed
+</pre>
+</div>
+<div class="section">
+<h3><a id="the-operators-table" name="the-operators-table">The operators table</a></h3>
+<p>Logic variables support the following operators (with their arity):</p>
+<p>Predicates</p>
+<blockquote>
+<dl class="docutils">
+<dt>is_free/1</dt>
+<dd>any -&gt; bool</dd>
+<dt>is_bound/1</dt>
+<dd>any -&gt; bool</dd>
+<dt>alias_of/2</dt>
+<dd>logic vars. -&gt; bool</dd>
+</dl>
+</blockquote>
+<p>Variable Creation</p>
+<blockquote>
+<dl class="docutils">
+<dt>newvar/0</dt>
+<dd>nothing -&gt; logic variable</dd>
+</dl>
+</blockquote>
+<p>Mutators</p>
+<blockquote>
+<dl class="docutils">
+<dt>bind/2</dt>
+<dd>logic var., any -&gt; None</dd>
+<dt>unify/2</dt>
+<dd>any, any -&gt; None</dd>
+</dl>
+</blockquote>
+</div>
+</div>
+<div class="section">
+<h2><a id="threads-and-dataflow-synchronisation" name="threads-and-dataflow-synchronisation">Threads and dataflow synchronisation</a></h2>
+<div class="section">
+<h3><a id="id1" name="id1">Description and examples</a></h3>
+<p>When a piece of code tries to access a free logic variable, the thread
+in which it runs is blocked (suspended) until the variable becomes
+bound. This behaviour is known as &quot;dataflow synchronization&quot; and
+mimics exactly the dataflow variables from the <a class="reference" href="http://www.mozart-oz.org">Oz programming
+language</a>. With respect to behaviour under concurrency conditions,
+logic variables come with two operators :</p>
+<ul class="simple">
+<li>wait: this suspends the current thread until the variable is bound,
+it returns the value otherwise (impl. note: in the logic
+objectspace, all operators make an implicit wait on their arguments)</li>
+<li>wait_needed: this suspends the current thread until the variable
+has received a wait message. It has to be used explicitly,
+typically by a producer thread that wants to produce data only when
+needed.</li>
+</ul>
+<p>In this context, binding a variable to a value will make runnable all
+threads blocked on this variable.</p>
+<p>Wait and wait_needed allow to write efficient lazy evaluating code.</p>
+<p>Using the &quot;uthread&quot; builtin (which spawns a coroutine and applies the
+2..n args to its first arg), here is how to implement a
+producer/consummer scheme:</p>
+<pre class="literal-block">
+def generate(n, limit):
+    if n &lt; limit:
+        return (n, generate(n + 1, limit))
+    return None
+
+def sum(L, a):
+    Head, Tail = newvar(), newvar()
+    unify(L, (Head, Tail))
+    if Tail != None:
+        return sum(Tail, Head + a)
+    return a + Head
+
+X = newvar()
+S = newvar()
+
+unify(S, uthread(sum, X, 0))
+unify(X, uthread(generate, 0, 10))
+
+assert S == 45
+</pre>
+<p>Note that this eagerly generates all elements before the first of them
+is consummed. Wait_needed helps write us a lazy version of the
+generator. But the consummer will be responsible of the termination,
+and thus must be adapted too:</p>
+<pre class="literal-block">
+def lgenerate(n, L):
+    &quot;&quot;&quot;lazy version of generate&quot;&quot;&quot;
+    wait_needed(L)
+    Tail = newvar()
+    bind(L, (n, Tail))
+    lgenerate(n+1, Tail)
+
+def lsum(L, a, limit):
+    &quot;&quot;&quot;this summer controls the generator&quot;&quot;&quot;
+    if limit &gt; 0:
+        Head, Tail = newvar(), newvar()
+        wait(L)
+        unify(L, (Head, Tail))
+        return lsum(Tail, a+Head, limit-1)
+    else:
+        return a
+
+Y = newvar()
+T = newvar()
+
+uthread(lgenerate, 0, Y)
+unify(T, uthread(lsum, Y, 0, 10))
+
+wait(T)
+assert T == 45
+</pre>
+<p>Please note that in the current LO, we deal with coroutines, not
+threads (thus we can't rely on preemtive scheduling to lessen the
+problem with the eager consummer/producer program). Also nested
+coroutines don't schedule properly yet. This impacts the ability to
+write a simple program like the following:</p>
+<pre class="literal-block">
+def sleep(X, Barrier):
+    wait(X)
+    bind(Barrier, True)
+
+def wait_two(X, Y):
+    Barrier = newvar()
+    uthread(sleep, X, Barrier)
+    uthread(sleep, Y, Barrier)
+    wait(Barrier)
+    if is_free(Y):
+        return 1
+    return 2
+
+X, Y = newvar(), newvar()
+o = uthread(wait_two, X, Y)
+unify(X, Y)
+unify(Y, 42)
+assert X == Y == 42
+assert o == 2
+</pre>
+<p>Finally, it must be noted that bind/unify and wait pair of operations
+are quite similar to send and synchronous receive primitives for
+inter-process communication.</p>
+</div>
+<div class="section">
+<h3><a id="id2" name="id2">The operators table</a></h3>
+<p>Blocking ops</p>
+<blockquote>
+<dl class="docutils">
+<dt>wait/1 # blocks if first arg. is a free logic var., til it becomes bound</dt>
+<dd>value -&gt; value</dd>
+<dt>wait_needed/1 # blocks until its arg. receives a wait</dt>
+<dd>logic var. -&gt; logic var.</dd>
+<dt>wait_two/2</dt>
+<dd>logic var., logic var. -&gt;  int in {1,2}</dd>
+</dl>
+</blockquote>
+<p>Coroutine spawning</p>
+<blockquote>
+<dl class="docutils">
+<dt>uthread/n | 1 &lt;= n</dt>
+<dd>callable, opt args. -&gt; logic var.</dd>
+</dl>
+</blockquote>
+</div>
+</div>
+</div>
+<div class="section">
+<h1><a id="constraint-programming" name="constraint-programming">Constraint Programming</a></h1>
+<p>The LO comes with a flexible, extensible constraint solver
+engine. While regular search strategies such as depth-first or
+breadth-first search are provided, you can write better, specialized
+strategies (an exemple would be best-search). We therein describe how
+to use the solver to specify and get the solutions of a constraint
+satisfaction problem, and then highlight how to extend the solver with
+new strategies.</p>
+<div class="section">
+<h2><a id="using-the-constraint-engine" name="using-the-constraint-engine">Using the constraint engine</a></h2>
+<div class="section">
+<h3><a id="specification-of-a-problem" name="specification-of-a-problem">Specification of a problem</a></h3>
+<p>A constraint satisfaction problem is defined by a triple (X, D, C)
+where X is a set of finite domain variables, D the set of domains
+associated with the variables in X, and C the set of constraints, or
+relations, that bind together the variables of X.</p>
+<p>Note that the constraint variables are NOT logic variables. Not yet
+anyway.</p>
+<p>So we basically need a way to declare variables, their domains and
+relations; and something to hold these together. The later is what we
+call a &quot;computation space&quot;. The notion of computation space is broad
+enough to encompass constraint and logic programming, but we use it
+there only as a box that holds the elements of our constraint
+satisfaction problem. Note that it is completely unrelated to the
+notion of object space (as in the logic object space).</p>
+<p>A problem is a one-argument procedure defined as follows:</p>
+<pre class="literal-block">
+def simple_problem(cs):
+    cs.var('x', FiniteDomain(['spam', 'egg', 'ham']))
+    cs.var('y', FiniteDomain([3, 4, 5]))
+</pre>
+<p>This snippet defines a couple of variables and their domains, on the
+'cs' argument which is indeed a computation space. Note that we didn't
+take a reference of the created variables. We can query the space to
+get these back if needed, and then complete the definition of our
+problem. Our problem, continued:</p>
+<pre class="literal-block">
+... x = cs.find_var('x')
+    y = cs.find_var('y')
+    cs.tell(make_expression([x,y], 'len(x) == y'))
+
+    return x, y
+</pre>
+<p>We must be careful to return the set of variables whose candidate
+values we are interested in. The rest should be sufficiently
+self-describing...</p>
+</div>
+<div class="section">
+<h3><a id="getting-solutions" name="getting-solutions">Getting solutions</a></h3>
+<p>Now to get and print solutions out of this, we must:</p>
+<pre class="literal-block">
+import solver
+cs = newspace()
+cs.define_problem(simple_problem)
+
+for sol in solver.solve(cs):
+    print sol
+</pre>
+<p>The builtin solve function returns a generator. You will note with
+pleasure how slow the search can be on a solver running on a Python
+interpreter written in Python, the later running on top of
+cpython... It is expected that the compiled version of PyPy + LO will
+provide decent performance.</p>
+</div>
+<div class="section">
+<h3><a id="table-of-operators" name="table-of-operators">Table of Operators</a></h3>
+<p>Note that below, &quot;variable/expression designators&quot; really are strings.</p>
+<p>Space creation</p>
+<blockquote>
+newspace/0</blockquote>
+<p>Finite domain creation</p>
+<blockquote>
+<dl class="docutils">
+<dt>FiniteDomain/1</dt>
+<dd>list of any -&gt; FiniteDomain</dd>
+</dl>
+</blockquote>
+<p>Expressions</p>
+<blockquote>
+<dl class="docutils">
+<dt>make_expression/2</dt>
+<dd>list of var. designators, expression designator -&gt; Expression</dd>
+<dt>AllDistinct/1</dt>
+<dd>list of var. designators -&gt; Expression</dd>
+</dl>
+</blockquote>
+<p>Space methods</p>
+<blockquote>
+<dl class="docutils">
+<dt>var/2</dt>
+<dd>var. designator, FiniteDomain -&gt; constraint variable instance</dd>
+<dt>find_var/1</dt>
+<dd>var. designator -&gt; constraint variable instance</dd>
+<dt>tell/1</dt>
+<dd>Expression -&gt; None</dd>
+<dt>define_problem/1</dt>
+<dd>procedure (space -&gt; tuple of constraint variables) -&gt; None</dd>
+</dl>
+</blockquote>
+</div>
+</div>
+<div class="section">
+<h2><a id="extending-the-search-engine" name="extending-the-search-engine">Extending the search engine</a></h2>
+<div class="section">
+<h3><a id="writing-a-solver" name="writing-a-solver">Writing a solver</a></h3>
+<p>Here we show how the additional builtin primitives allow you to write,
+in pure Python, a very basic solver that will search depth-first and
+return the first found solution.</p>
+<p>As we've seen, a CSP is encapsulated into a so-called &quot;computation
+space&quot;. The space object has additional methods that allow the solver
+implementor to drive the search. First, let us see some code driving a
+binary depth-first search:</p>
+<pre class="literal-block">
+1   def first_solution_dfs(space):
+2       status = space.ask()
+3       if status == 0:
+4           return None
+5       elif status == 1:
+6           return space.merge()
+7       else:
+8           new_space = space.clone()
+9           space.commit(1)
+10          outcome = first_solution_dfs(space)
+11          if outcome is None:
+13              new_space.commit(2)
+14              outcome = first_solution_dfs(new_space)
+15          return outcome
+</pre>
+<p>This recursive solver takes a space as argument, and returns the first
+solution or None. Let us examine it piece by piece and discover the
+basics of the solver protocol.</p>
+<p>The first thing to do is &quot;asking&quot; the space about its status. This may
+force the &quot;inside&quot; of the space to check that the values of the
+domains are compatibles with the constraints. Every inconsistent value
+is removed from the variable domains. This phase is called &quot;constraint
+propagation&quot;. It is crucial because it prunes as much as possible of
+the search space. Then, the call to ask returns a positive integer
+value which we call the space status; at this point, all (possibly
+concurrent) computations happening inside the space are terminated.</p>
+<p>Depending on the status value, either:</p>
+<ul class="simple">
+<li>the space is failed (status == 0), which means that there is no
+combination of values of the finite domains that can satisfy the
+constraints,</li>
+<li>one solution has been found (status == 1): there is exactly one
+valuation of the variables that satisfy the constraints,</li>
+<li>several branches of the search space can be taken (status represents
+the exact number of available alternatives, or branches).</li>
+</ul>
+<p>Now, we have written this toy solver as if there could be a maximum of
+two alternatives. This assumption holds for the simple_problem we
+defined above, where a binary &quot;distributor&quot; (see below for an
+explanation of this term) has been chosen automatically for us, but
+not in the general case. See the sources for a more general-purpose
+<a class="reference" href="../objspace/constraint/applevel/solver.py">solver</a> and more involved <a class="reference" href="../objspace/constraint/applevel/problems.py">sample problems</a> (currently, probably
+only conference_scheduling is up to date with the current API).</p>
+<p>In line 8, we take a clone of the space; nothing is shared between
+space and newspace (the clone). Having taken a clone, we now have two
+identical versions of the space that we got as parameter. This will
+allow us to explore the two alternatives. This step is done, line 9
+and 13, with the call to commit, each time with a different integer
+value representing the branch to be taken. The rest should be
+sufficiently self-describing.</p>
+<p>This shows the two important space methods used by a search engine:
+ask, which waits for the stability of the space and informs the solver
+of its status, and commit, which tells a space which road to take in
+case of a fork.</p>
+</div>
+<div class="section">
+<h3><a id="using-distributors" name="using-distributors">Using distributors</a></h3>
+<p>Now, earlier, we talked of a &quot;distributor&quot;: it is a program running in
+a computation space. It could be anything, and in fact, in the final
+version of the LO, it will be any Python program, augmented with calls
+to non-deterministic choice points. Each time a program embedded in a
+computation space reaches such a point, it blocks until some Deus ex
+machina makes the choice for him. Only a solver can be responsible for
+the actual choice (that is the reason for the name &quot;non
+deterministic&quot;: the decision does not belong to the embedded program,
+only to the solver that drives it).</p>
+<p>In the case of a CSP, the distributor is a simple piece of code, which
+works only after the propagation phase has reached a fixpoint. Its
+policy will determine the fanout, or branching factor, of the current
+computation space (or node in the abstract search space).</p>
+<p>Here are two examples of distribution strategies:</p>
+<ul class="simple">
+<li>take the variable with the biggest domain, and remove exactly one
+value from its domain; thus we always get two branches: one with the
+value removed, the other with only this value remaining,</li>
+<li>take a variable with a small domain, and keep only one value in the
+domain for each branch (in other words, we &quot;instantiate&quot; the
+variable); this makes for a branching factor equal to the size of
+the domain of the variable.</li>
+</ul>
+<p>There are a great many ways to distribute... Some of them perform
+better, depending on the caracteristics of the problem to be
+solved. But there is no absolutely better distribution strategy. Note
+that the second strategy given as example there is what is used (and
+hard-wired) in the MAC algorithm.</p>
+<p>Currently in the LO we have two builtin distributors:</p>
+<ul class="simple">
+<li>NaiveDistributor, which distributes domains by splitting the
+smallest domain in 2 new domains; the first new domain has a size of
+one, and the second has all the other values,</li>
+<li>SplitDistributor, which distributes domains by splitting the
+smallest domain in N equal parts (or as equal as possible).  If N is
+0, then the smallest domain is split in domains of size 1; a special
+case of this, DichotomyDistributor, for which N == 2, is also
+provided and is the default one.</li>
+</ul>
+<p>To explicitly specify a distributor for a constraint problem, you
+need to say, in the procedure that defines the problem:</p>
+<pre class="literal-block">
+cs.set_distributor(NaiveDistributor())
+</pre>
+<p>It is not possible currently to write distributors in pure Python;
+this is scheduled for PyPy version 1.</p>
+</div>
+<div class="section">
+<h3><a id="remaining-space-operators" name="remaining-space-operators">Remaining space operators</a></h3>
+<p>For solver writers</p>
+<blockquote>
+<dl class="docutils">
+<dt>ask/0</dt>
+<dd>nothing -&gt; a positive integer i</dd>
+<dt>commit/1</dt>
+<dd>integer in [1, i] -&gt; None</dd>
+<dt>merge/0</dt>
+<dd>nothing -&gt; list of values (solution)</dd>
+</dl>
+</blockquote>
+<p>For distributor writers</p>
+<blockquote>
+choose</blockquote>
+</div>
+</div>
+</div>
+</div>
+</body>
+</html>

Modified: pypy/dist/pypy/doc/howto-logicobjspace-0.9.txt
==============================================================================
--- pypy/dist/pypy/doc/howto-logicobjspace-0.9.txt	(original)
+++ pypy/dist/pypy/doc/howto-logicobjspace-0.9.txt	Fri Jun 23 12:27:50 2006
@@ -163,8 +163,8 @@
 When a piece of code tries to access a free logic variable, the thread
 in which it runs is blocked (suspended) until the variable becomes
 bound. This behaviour is known as "dataflow synchronization" and
-mimics exactly the dataflow variables from the Oz programming
-language. With respect to behaviour under concurrency conditions,
+mimics exactly the dataflow variables from the `Oz programming
+language`_. With respect to behaviour under concurrency conditions,
 logic variables come with two operators :
 
 * wait: this suspends the current thread until the variable is bound,
@@ -426,8 +426,8 @@
   15          return outcome
 
 This recursive solver takes a space as argument, and returns the first
-space containing a solution or None. Let us examine it piece by piece
-and discover the basics of the solver protocol.
+solution or None. Let us examine it piece by piece and discover the
+basics of the solver protocol.
 
 The first thing to do is "asking" the space about its status. This may
 force the "inside" of the space to check that the values of the
@@ -454,8 +454,9 @@
 two alternatives. This assumption holds for the simple_problem we
 defined above, where a binary "distributor" (see below for an
 explanation of this term) has been chosen automatically for us, but
-not in the general case. See the sources (applevel/solver.py) for a
-more general-purpose solver.
+not in the general case. See the sources for a more general-purpose
+`solver`_ and more involved `sample problems`_ (currently, probably
+only conference_scheduling is up to date with the current API).
 
 In line 8, we take a clone of the space; nothing is shared between
 space and newspace (the clone). Having taken a clone, we now have two
@@ -537,19 +538,15 @@
    integer in [1, i] -> None
 
  merge/0         
-   nothing -> list of values
+   nothing -> list of values (solution)
 
 For distributor writers
 
  choose
 
-Were to look
-------------
 
-See also:
+.. _`solver`: ../objspace/constraint/applevel/solver.py
+.. _`sample problems`: ../objspace/constraint/applevel/problems.py
+.. _`Oz programming language`: http://www.mozart-oz.org
 
-* pypy-dist/pypy/objspace/constraint/applevel for the existing solver
-  and some sample problems (I'm quite sure that the conference
-  scheduling problem is up to date wrt the current API, the others
-  likely lag behind).
 



More information about the Pypy-commit mailing list