A little more bit o' docs.

This commit is contained in:
Simon Forman 2018-07-14 12:29:25 -07:00
parent 41b39e5977
commit 54491f0da2
20 changed files with 1702 additions and 131 deletions

View File

@ -367,10 +367,6 @@
"metadata": {},
"outputs": [],
"source": [
"# This is the straightforward version with no \"compaction\".\n",
"# It works fine, but does waaaay too much work because the\n",
"# expressions grow each derivation.\n",
"\n",
"def D(symbol):\n",
"\n",
" def derv(R):\n",

View File

@ -23,7 +23,7 @@ $(docs_rst): %.rst : %.ipynb
python -m nbconvert --to rst $<
move_us = Generator_Programs.rst Newton-Raphson.rst Ordered_Binary_Trees.rst Quadratic.rst Recursion_Combinators.rst Replacing.rst Treestep.rst Types.rst Zipper.rst
move_us = Derivatives_of_Regular_Expressions.rst Generator_Programs.rst Newton-Raphson.rst Ordered_Binary_Trees.rst Quadratic.rst Recursion_Combinators.rst Replacing.rst The_Four_Operations.rst Treestep.rst TypeChecking.rst Types.rst Zipper.rst
mov: $(move_us)
cp -v $? ./sphinx_docs/notebooks/

View File

@ -104,7 +104,7 @@
<span class="p">(</span><span class="s1">&#39;pred&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;--&#39;</span><span class="p">]),</span>
<span class="p">(</span><span class="s1">&#39;rolldown&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;roll&lt;&#39;</span><span class="p">]),</span>
<span class="p">(</span><span class="s1">&#39;rollup&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;roll&gt;&#39;</span><span class="p">]),</span>
<span class="p">(</span><span class="s1">&#39;id&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;&#39;</span><span class="p">]),</span>
<span class="p">(</span><span class="s1">&#39;id&#39;</span><span class="p">,</span> <span class="p">[</span><span class="sa">u</span><span class="s1">&#39;&#39;</span><span class="p">]),</span>
<span class="p">)</span>
@ -141,7 +141,8 @@
<span class="s1">run == [] swap infra</span>
<span class="s1">sqr == dup mul</span>
<span class="s1">size == 0 swap [pop ++] step</span>
<span class="s1">cleave == [i] app2 [popd] dip</span>
<span class="s1">fork == [i] app2</span>
<span class="s1">cleave == fork [popd] dip</span>
<span class="s1">average == [sum 1.0 *] [size] cleave /</span>
<span class="s1">gcd == 1 [tuck modulus dup 0 &gt;] loop pop</span>
<span class="s1">least_fraction == dup [gcd] infra [div] concat map</span>
@ -157,8 +158,9 @@
<span class="s1">step_zero == 0 roll&gt; step</span>
<span class="s1">codireco == cons dip rest cons</span>
<span class="s1">make_generator == [codireco] ccons</span>
<span class="s1">ifte == [nullary not] dipd branch</span>
<span class="s1">&#39;&#39;&#39;</span>
<span class="c1"># ifte == [nullary not] dipd branch</span>
<span class="c1"># </span>
<span class="c1"># ifte == [nullary] dipd swap branch</span>
<span class="c1"># genrec == [[genrec] cons cons cons cons] nullary swons concat ifte</span>
@ -510,6 +512,8 @@
<span class="sd">&#39;&#39;&#39;Clear everything from the stack.</span>
<span class="sd"> ::</span>
<span class="sd"> clear == stack [pop stack] loop</span>
<span class="sd"> ... clear</span>
<span class="sd"> ---------------</span>
@ -991,32 +995,32 @@
<span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">concat</span><span class="p">(</span><span class="n">then</span> <span class="k">if</span> <span class="n">flag</span> <span class="k">else</span> <span class="n">else_</span><span class="p">,</span> <span class="n">expression</span><span class="p">),</span> <span class="n">dictionary</span></div>
<div class="viewcode-block" id="ifte"><a class="viewcode-back" href="../../library.html#joy.library.ifte">[docs]</a><span class="nd">@inscribe</span>
<span class="nd">@FunctionWrapper</span>
<span class="k">def</span> <span class="nf">ifte</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">dictionary</span><span class="p">):</span>
<span class="sd">&#39;&#39;&#39;</span>
<span class="sd"> If-Then-Else Combinator</span>
<span class="sd"> ::</span>
<span class="sd"> ... [if] [then] [else] ifte</span>
<span class="sd"> ---------------------------------------------------</span>
<span class="sd"> ... [[else] [then]] [...] [if] infra select i</span>
<span class="sd"> ... [if] [then] [else] ifte</span>
<span class="sd"> -------------------------------------------------------</span>
<span class="sd"> ... [else] [then] [...] [if] infra first choice i</span>
<span class="sd"> Has the effect of grabbing a copy of the stack on which to run the</span>
<span class="sd"> if-part using infra.</span>
<span class="sd"> &#39;&#39;&#39;</span>
<span class="p">(</span><span class="n">else_</span><span class="p">,</span> <span class="p">(</span><span class="n">then</span><span class="p">,</span> <span class="p">(</span><span class="n">if_</span><span class="p">,</span> <span class="n">stack</span><span class="p">)))</span> <span class="o">=</span> <span class="n">stack</span>
<span class="n">expression</span> <span class="o">=</span> <span class="p">(</span><span class="n">S_infra</span><span class="p">,</span> <span class="p">(</span><span class="n">S_first</span><span class="p">,</span> <span class="p">(</span><span class="n">S_choice</span><span class="p">,</span> <span class="p">(</span><span class="n">S_i</span><span class="p">,</span> <span class="n">expression</span><span class="p">))))</span>
<span class="n">stack</span> <span class="o">=</span> <span class="p">(</span><span class="n">if_</span><span class="p">,</span> <span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="p">(</span><span class="n">then</span><span class="p">,</span> <span class="p">(</span><span class="n">else_</span><span class="p">,</span> <span class="n">stack</span><span class="p">))))</span>
<span class="k">return</span> <span class="n">stack</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">dictionary</span></div>
<span class="c1">##@inscribe</span>
<span class="c1">##@FunctionWrapper</span>
<span class="c1">##def ifte(stack, expression, dictionary):</span>
<span class="c1">## &#39;&#39;&#39;</span>
<span class="c1">## If-Then-Else Combinator</span>
<span class="c1">## ::</span>
<span class="c1">##</span>
<span class="c1">## ... [if] [then] [else] ifte</span>
<span class="c1">## ---------------------------------------------------</span>
<span class="c1">## ... [[else] [then]] [...] [if] infra select i</span>
<span class="c1">##</span>
<span class="c1">##</span>
<span class="c1">##</span>
<span class="c1">##</span>
<span class="c1">## ... [if] [then] [else] ifte</span>
<span class="c1">## -------------------------------------------------------</span>
<span class="c1">## ... [else] [then] [...] [if] infra first choice i</span>
<span class="c1">##</span>
<span class="c1">##</span>
<span class="c1">## Has the effect of grabbing a copy of the stack on which to run the</span>
<span class="c1">## if-part using infra.</span>
<span class="c1">## &#39;&#39;&#39;</span>
<span class="c1">## (else_, (then, (if_, stack))) = stack</span>
<span class="c1">## expression = (S_infra, (S_first, (S_choice, (S_i, expression))))</span>
<span class="c1">## stack = (if_, (stack, (then, (else_, stack))))</span>
<span class="c1">## return stack, expression, dictionary</span>
<div class="viewcode-block" id="cond"><a class="viewcode-back" href="../../library.html#joy.library.cond">[docs]</a><span class="nd">@inscribe</span>

View File

@ -75,16 +75,14 @@
</li>
</ul></li>
<li><a href="library.html#joy.library.add_aliases">add_aliases() (in module joy.library)</a>
</li>
<li><a href="library.html#joy.library.DefinitionWrapper.add_def">add_def() (joy.library.DefinitionWrapper class method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="library.html#joy.library.DefinitionWrapper.add_def">add_def() (joy.library.DefinitionWrapper class method)</a>
</li>
<li><a href="library.html#joy.library.DefinitionWrapper.add_definitions">add_definitions() (joy.library.DefinitionWrapper class method)</a>
</li>
<li><a href="types.html#joy.utils.types.AnyJoyType">AnyJoyType (class in joy.utils.types)</a>
</li>
<li><a href="types.html#joy.utils.polytypes.AnyStarJoyType">AnyStarJoyType (class in joy.utils.polytypes)</a>
</li>
<li><a href="library.html#joy.library.app1">app1() (in module joy.library)</a>
</li>
@ -245,8 +243,6 @@
<li><a href="library.html#joy.library.i">i() (in module joy.library)</a>
</li>
<li><a href="library.html#joy.library.id_">id_() (in module joy.library)</a>
</li>
<li><a href="library.html#joy.library.ifte">ifte() (in module joy.library)</a>
</li>
<li><a href="types.html#joy.utils.polytypes.infer">infer() (in module joy.utils.polytypes)</a>
</li>
@ -300,16 +296,8 @@
<h2 id="K">K</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="types.html#joy.utils.polytypes.AnyStarJoyType.kind">kind (joy.utils.polytypes.AnyStarJoyType attribute)</a>
<ul>
<li><a href="types.html#joy.utils.polytypes.KleeneStar.kind">(joy.utils.polytypes.KleeneStar attribute)</a>
<li><a href="types.html#joy.utils.polytypes.KleeneStar.kind">kind (joy.utils.polytypes.KleeneStar attribute)</a>
</li>
<li><a href="types.html#joy.utils.polytypes.NumberStarJoyType.kind">(joy.utils.polytypes.NumberStarJoyType attribute)</a>
</li>
<li><a href="types.html#joy.utils.polytypes.StackStarJoyType.kind">(joy.utils.polytypes.StackStarJoyType attribute)</a>
</li>
</ul></li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="types.html#joy.utils.polytypes.KleeneStar">KleeneStar (class in joy.utils.polytypes)</a>
@ -349,10 +337,6 @@
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="types.html#joy.utils.types.NumberJoyType">NumberJoyType (class in joy.utils.types)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="types.html#joy.utils.polytypes.NumberStarJoyType">NumberStarJoyType (class in joy.utils.polytypes)</a>
</li>
</ul></td>
</tr></table>
@ -450,8 +434,6 @@
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="types.html#joy.utils.polytypes.StackStarJoyType">StackStarJoyType (class in joy.utils.polytypes)</a>
</li>
<li><a href="library.html#joy.library.step">step() (in module joy.library)</a>
</li>
<li><a href="library.html#joy.utils.generated_library.stuncons">stuncons() (in module joy.utils.generated_library)</a>

View File

@ -140,7 +140,7 @@ interesting aspects. Its quite a treasure trove.</p>
<li class="toctree-l2"><a class="reference internal" href="notebooks/Developing.html">Developing a Program in Joy</a></li>
<li class="toctree-l2"><a class="reference internal" href="notebooks/Quadratic.html">Quadratic formula</a></li>
<li class="toctree-l2"><a class="reference internal" href="notebooks/Replacing.html">Replacing Functions in the Dictionary</a></li>
<li class="toctree-l2"><a class="reference internal" href="notebooks/Recursion_Combinators.html">Recursive Combinators</a></li>
<li class="toctree-l2"><a class="reference internal" href="notebooks/Recursion_Combinators.html">Recursion Combinators</a></li>
<li class="toctree-l2"><a class="reference internal" href="notebooks/Ordered_Binary_Trees.html">Treating Trees I: Ordered Binary Trees</a></li>
<li class="toctree-l2"><a class="reference internal" href="notebooks/Treestep.html">Treating Trees II: <code class="docutils literal notranslate"><span class="pre">treestep</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="notebooks/Generator_Programs.html">Using <code class="docutils literal notranslate"><span class="pre">x</span></code> to Generate Values</a></li>

View File

@ -187,7 +187,9 @@ Boolean value (so empty string, zero, etc. are counted as false, etc.)</p>
<dt id="joy.library.clear">
<code class="descclassname">joy.library.</code><code class="descname">clear</code><span class="sig-paren">(</span><em>stack</em>, <em>expression</em>, <em>dictionary</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/library.html#clear"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.library.clear" title="Permalink to this definition"></a></dt>
<dd><p>Clear everything from the stack.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="o">...</span> <span class="n">clear</span>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">clear</span> <span class="o">==</span> <span class="n">stack</span> <span class="p">[</span><span class="n">pop</span> <span class="n">stack</span><span class="p">]</span> <span class="n">loop</span>
<span class="o">...</span> <span class="n">clear</span>
<span class="o">---------------</span>
</pre></div>
</div>
@ -403,26 +405,6 @@ onto the pending expression for evaluation.</p>
<dd><p>The identity function.</p>
</dd></dl>
<dl class="function">
<dt id="joy.library.ifte">
<code class="descclassname">joy.library.</code><code class="descname">ifte</code><span class="sig-paren">(</span><em>stack</em>, <em>expression</em>, <em>dictionary</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/library.html#ifte"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.library.ifte" title="Permalink to this definition"></a></dt>
<dd><p>If-Then-Else Combinator</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="o">...</span> <span class="p">[</span><span class="k">if</span><span class="p">]</span> <span class="p">[</span><span class="n">then</span><span class="p">]</span> <span class="p">[</span><span class="k">else</span><span class="p">]</span> <span class="n">ifte</span>
<span class="o">---------------------------------------------------</span>
<span class="o">...</span> <span class="p">[[</span><span class="k">else</span><span class="p">]</span> <span class="p">[</span><span class="n">then</span><span class="p">]]</span> <span class="p">[</span><span class="o">...</span><span class="p">]</span> <span class="p">[</span><span class="k">if</span><span class="p">]</span> <span class="n">infra</span> <span class="n">select</span> <span class="n">i</span>
<span class="o">...</span> <span class="p">[</span><span class="k">if</span><span class="p">]</span> <span class="p">[</span><span class="n">then</span><span class="p">]</span> <span class="p">[</span><span class="k">else</span><span class="p">]</span> <span class="n">ifte</span>
<span class="o">-------------------------------------------------------</span>
<span class="o">...</span> <span class="p">[</span><span class="k">else</span><span class="p">]</span> <span class="p">[</span><span class="n">then</span><span class="p">]</span> <span class="p">[</span><span class="o">...</span><span class="p">]</span> <span class="p">[</span><span class="k">if</span><span class="p">]</span> <span class="n">infra</span> <span class="n">first</span> <span class="n">choice</span> <span class="n">i</span>
</pre></div>
</div>
<p>Has the effect of grabbing a copy of the stack on which to run the
if-part using infra.</p>
</dd></dl>
<dl class="function">
<dt id="joy.library.infra">
<code class="descclassname">joy.library.</code><code class="descname">infra</code><span class="sig-paren">(</span><em>stack</em>, <em>expression</em>, <em>dictionary</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/library.html#infra"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.library.infra" title="Permalink to this definition"></a></dt>

View File

@ -366,10 +366,9 @@ numbers sixty-six times and then four more.</p>
</div>
<div class="section" id="project-euler-problem-two">
<h2>Project Euler Problem Two<a class="headerlink" href="#project-euler-problem-two" title="Permalink to this headline"></a></h2>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">By</span> <span class="n">considering</span> <span class="n">the</span> <span class="n">terms</span> <span class="ow">in</span> <span class="n">the</span> <span class="n">Fibonacci</span> <span class="n">sequence</span> <span class="n">whose</span> <span class="n">values</span> <span class="n">do</span> <span class="ow">not</span> <span class="n">exceed</span> <span class="n">four</span> <span class="n">million</span><span class="p">,</span>
<span class="n">find</span> <span class="n">the</span> <span class="nb">sum</span> <span class="n">of</span> <span class="n">the</span> <span class="n">even</span><span class="o">-</span><span class="n">valued</span> <span class="n">terms</span><span class="o">.</span>
</pre></div>
</div>
<blockquote>
<div>By considering the terms in the Fibonacci sequence whose values do
not exceed four million, find the sum of the even-valued terms.</div></blockquote>
<p>Now that we have a generator for the Fibonacci sequence, we need a
function that adds a term in the sequence to a sum if it is even, and
<code class="docutils literal notranslate"><span class="pre">pop</span></code>s it otherwise.</p>

View File

@ -17,7 +17,7 @@
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="Treating Trees II: treestep" href="Treestep.html" />
<link rel="prev" title="Recursive Combinators" href="Recursion_Combinators.html" />
<link rel="prev" title="Recursion Combinators" href="Recursion_Combinators.html" />
<link rel="stylesheet" href="../_static/custom.css" type="text/css" />
@ -1373,7 +1373,7 @@ Tree-delete == [pop not] [pop] [_Tree_delete_R0] [_Tree_delete_R1] genrec
<ul>
<li><a href="../index.html">Documentation overview</a><ul>
<li><a href="index.html">Essays about Programming in Joy</a><ul>
<li>Previous: <a href="Recursion_Combinators.html" title="previous chapter">Recursive Combinators</a></li>
<li>Previous: <a href="Recursion_Combinators.html" title="previous chapter">Recursion Combinators</a></li>
<li>Next: <a href="Treestep.html" title="next chapter">Treating Trees II: <code class="docutils literal notranslate"><span class="pre">treestep</span></code></a></li>
</ul></li>
</ul></li>

View File

@ -6,7 +6,7 @@
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Recursive Combinators &#8212; Thun 0.2.0 documentation</title>
<title>Recursion Combinators &#8212; Thun 0.2.0 documentation</title>
<link rel="stylesheet" href="../_static/alabaster.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script type="text/javascript" src="../_static/documentation_options.js"></script>
@ -35,8 +35,8 @@
<div class="code ipython2 highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">notebook_preamble</span> <span class="k">import</span> <span class="n">D</span><span class="p">,</span> <span class="n">DefinitionWrapper</span><span class="p">,</span> <span class="n">J</span><span class="p">,</span> <span class="n">V</span><span class="p">,</span> <span class="n">define</span>
</pre></div>
</div>
<div class="section" id="recursive-combinators">
<h1>Recursive Combinators<a class="headerlink" href="#recursive-combinators" title="Permalink to this headline"></a></h1>
<div class="section" id="recursion-combinators">
<h1>Recursion Combinators<a class="headerlink" href="#recursion-combinators" title="Permalink to this headline"></a></h1>
<p>This article describes the <code class="docutils literal notranslate"><span class="pre">genrec</span></code> combinator, how to use it, and
several generic specializations.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="p">[</span><span class="k">if</span><span class="p">]</span> <span class="p">[</span><span class="n">then</span><span class="p">]</span> <span class="p">[</span><span class="n">rec1</span><span class="p">]</span> <span class="p">[</span><span class="n">rec2</span><span class="p">]</span> <span class="n">genrec</span>
@ -598,7 +598,7 @@ Wire”</a></p>
<div class="sphinxsidebarwrapper">
<h3><a href="../index.html">Table Of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Recursive Combinators</a><ul>
<li><a class="reference internal" href="#">Recursion Combinators</a><ul>
<li><a class="reference internal" href="#designing-recursive-functions">Designing Recursive Functions</a></li>
<li><a class="reference internal" href="#primitive-recursive-functions">Primitive Recursive Functions</a></li>
<li><a class="reference internal" href="#hylomorphism">Hylomorphism</a></li>

View File

@ -16,7 +16,7 @@
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="Recursive Combinators" href="Recursion_Combinators.html" />
<link rel="next" title="Recursion Combinators" href="Recursion_Combinators.html" />
<link rel="prev" title="Quadratic formula" href="Quadratic.html" />
<link rel="stylesheet" href="../_static/custom.css" type="text/css" />
@ -185,7 +185,7 @@ and re-evaluate the expression.</p>
<li><a href="../index.html">Documentation overview</a><ul>
<li><a href="index.html">Essays about Programming in Joy</a><ul>
<li>Previous: <a href="Quadratic.html" title="previous chapter">Quadratic formula</a></li>
<li>Next: <a href="Recursion_Combinators.html" title="next chapter">Recursive Combinators</a></li>
<li>Next: <a href="Recursion_Combinators.html" title="next chapter">Recursion Combinators</a></li>
</ul></li>
</ul></li>
</ul>

View File

@ -55,7 +55,7 @@
<li class="toctree-l2"><a class="reference internal" href="Replacing.html#a-shorter-trace">A shorter trace</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Recursion_Combinators.html">Recursive Combinators</a><ul>
<li class="toctree-l1"><a class="reference internal" href="Recursion_Combinators.html">Recursion Combinators</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#designing-recursive-functions">Designing Recursive Functions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#primitive-recursive-functions">Primitive Recursive Functions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Recursion_Combinators.html#hylomorphism">Hylomorphism</a></li>

File diff suppressed because one or more lines are too long

View File

@ -277,17 +277,6 @@ is used to generate one.</p>
we can capture more information about the type signatures of some functions,
and we can introduce a kind of Kleene Star or sequence type that can stand for
an unbounded sequence of other types.</p>
<dl class="class">
<dt id="joy.utils.polytypes.AnyStarJoyType">
<em class="property">class </em><code class="descclassname">joy.utils.polytypes.</code><code class="descname">AnyStarJoyType</code><span class="sig-paren">(</span><em>number</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/utils/polytypes.html#AnyStarJoyType"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.utils.polytypes.AnyStarJoyType" title="Permalink to this definition"></a></dt>
<dd><dl class="attribute">
<dt id="joy.utils.polytypes.AnyStarJoyType.kind">
<code class="descname">kind</code><a class="headerlink" href="#joy.utils.polytypes.AnyStarJoyType.kind" title="Permalink to this definition"></a></dt>
<dd><p>alias of <a class="reference internal" href="#joy.utils.types.AnyJoyType" title="joy.utils.types.AnyJoyType"><code class="xref py py-class docutils literal notranslate"><span class="pre">joy.utils.types.AnyJoyType</span></code></a></p>
</dd></dl>
</dd></dl>
<dl class="class">
<dt id="joy.utils.polytypes.CombinatorJoyType">
<em class="property">class </em><code class="descclassname">joy.utils.polytypes.</code><code class="descname">CombinatorJoyType</code><span class="sig-paren">(</span><em>name</em>, <em>sec</em>, <em>number</em>, <em>expect=None</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/utils/polytypes.html#CombinatorJoyType"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.utils.polytypes.CombinatorJoyType" title="Permalink to this definition"></a></dt>
@ -324,8 +313,8 @@ guard against being used on invalid types.</p>
<div>A*</div></blockquote>
<p>The <cite>A*</cite> works by splitting the universe into two alternate histories:</p>
<blockquote>
<div><p>A* -&gt; 0</p>
<p>A* -&gt; A A*</p>
<div><p>A* → ∅</p>
<p>A* A A*</p>
</div></blockquote>
<p>The Kleene star variable disappears in one universe, and in the other
it turns into an <cite>AnyJoyType</cite> variable followed by itself again.</p>
@ -339,28 +328,6 @@ dicts, the “unifiers”) that dont lead to type conflicts.</p>
</dd></dl>
<dl class="class">
<dt id="joy.utils.polytypes.NumberStarJoyType">
<em class="property">class </em><code class="descclassname">joy.utils.polytypes.</code><code class="descname">NumberStarJoyType</code><span class="sig-paren">(</span><em>number</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/utils/polytypes.html#NumberStarJoyType"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.utils.polytypes.NumberStarJoyType" title="Permalink to this definition"></a></dt>
<dd><dl class="attribute">
<dt id="joy.utils.polytypes.NumberStarJoyType.kind">
<code class="descname">kind</code><a class="headerlink" href="#joy.utils.polytypes.NumberStarJoyType.kind" title="Permalink to this definition"></a></dt>
<dd><p>alias of <a class="reference internal" href="#joy.utils.types.NumberJoyType" title="joy.utils.types.NumberJoyType"><code class="xref py py-class docutils literal notranslate"><span class="pre">joy.utils.types.NumberJoyType</span></code></a></p>
</dd></dl>
</dd></dl>
<dl class="class">
<dt id="joy.utils.polytypes.StackStarJoyType">
<em class="property">class </em><code class="descclassname">joy.utils.polytypes.</code><code class="descname">StackStarJoyType</code><span class="sig-paren">(</span><em>number</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/utils/polytypes.html#StackStarJoyType"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.utils.polytypes.StackStarJoyType" title="Permalink to this definition"></a></dt>
<dd><dl class="attribute">
<dt id="joy.utils.polytypes.StackStarJoyType.kind">
<code class="descname">kind</code><a class="headerlink" href="#joy.utils.polytypes.StackStarJoyType.kind" title="Permalink to this definition"></a></dt>
<dd><p>alias of <a class="reference internal" href="#joy.utils.types.StackJoyType" title="joy.utils.types.StackJoyType"><code class="xref py py-class docutils literal notranslate"><span class="pre">joy.utils.types.StackJoyType</span></code></a></p>
</dd></dl>
</dd></dl>
<dl class="class">
<dt id="joy.utils.polytypes.SymbolJoyType">
<em class="property">class </em><code class="descclassname">joy.utils.polytypes.</code><code class="descname">SymbolJoyType</code><span class="sig-paren">(</span><em>name</em>, <em>sec</em>, <em>number</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/joy/utils/polytypes.html#SymbolJoyType"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#joy.utils.polytypes.SymbolJoyType" title="Permalink to this definition"></a></dt>

View File

@ -0,0 +1,949 @@
∂RE
===
Brzozowski's Derivatives of Regular Expressions
-----------------------------------------------
Legend:
::
∧ intersection
union
∘ concatenation (see below)
¬ complement
ϕ empty set (aka ∅)
λ singleton set containing just the empty string
I set of all letters in alphabet
Derivative of a set ``R`` of strings and a string ``a``:
::
∂a(R)
∂a(a) → λ
∂a(λ) → ϕ
∂a(ϕ) → ϕ
∂a(¬a) → ϕ
∂a(R*) → ∂a(R)∘R*
∂a(¬R) → ¬∂a(R)
∂a(R∘S) → ∂a(R)∘S δ(R)∘∂a(S)
∂a(R ∧ S) → ∂a(R) ∧ ∂a(S)
∂a(R S) → ∂a(R) ∂a(S)
∂ab(R) = ∂b(∂a(R))
Auxiliary predicate function ``δ`` (I call it ``nully``) returns either
``λ`` if ``λ ⊆ R`` or ``ϕ`` otherwise:
::
δ(a) → ϕ
δ(λ) → λ
δ(ϕ) → ϕ
δ(R*) → λ
δ(¬R) δ(R)≟ϕ → λ
δ(¬R) δ(R)≟λ → ϕ
δ(R∘S) → δ(R) ∧ δ(S)
δ(R ∧ S) → δ(R) ∧ δ(S)
δ(R S) → δ(R) δ(S)
Some rules we will use later for "compaction":
::
R ∧ ϕ = ϕ ∧ R = ϕ
R ∧ I = I ∧ R = R
R ϕ = ϕ R = R
R I = I R = I
R∘ϕ = ϕ∘R = ϕ
R∘λ = λ∘R = R
Concatination of sets: for two sets A and B the set A∘B is defined as:
{a∘b for a in A for b in B}
E.g.:
{'a', 'b'}∘{'c', 'd'} → {'ac', 'ad', 'bc', 'bd'}
Implementation
--------------
.. code:: ipython2
from functools import partial as curry
from itertools import product
``ϕ`` and ``λ``
~~~~~~~~~~~~~~~
The empty set and the set of just the empty string.
.. code:: ipython2
phi = frozenset() # ϕ
y = frozenset({''}) # λ
Two-letter Alphabet
~~~~~~~~~~~~~~~~~~~
I'm only going to use two symbols (at first) becaase this is enough to
illustrate the algorithm and because you can represent any other
alphabet with two symbols (if you had to.)
I chose the names ``O`` and ``l`` (uppercase "o" and lowercase "L") to
look like ``0`` and ``1`` (zero and one) respectively.
.. code:: ipython2
syms = O, l = frozenset({'0'}), frozenset({'1'})
Representing Regular Expressions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To represent REs in Python I'm going to use tagged tuples. A *regular
expression* is one of:
::
O
l
(KSTAR, R)
(NOT, R)
(AND, R, S)
(CONS, R, S)
(OR, R, S)
Where ``R`` and ``S`` stand for *regular expressions*.
.. code:: ipython2
AND, CONS, KSTAR, NOT, OR = 'and cons * not or'.split() # Tags are just strings.
Because they are formed of ``frozenset``, ``tuple`` and ``str`` objects
only, these datastructures are immutable.
String Representation of RE Datastructures
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: ipython2
def stringy(re):
'''
Return a nice string repr for a regular expression datastructure.
'''
if re == I: return '.'
if re in syms: return next(iter(re))
if re == y: return '^'
if re == phi: return 'X'
assert isinstance(re, tuple), repr(re)
tag = re[0]
if tag == KSTAR:
body = stringy(re[1])
if not body: return body
if len(body) > 1: return '(' + body + ")*"
return body + '*'
if tag == NOT:
body = stringy(re[1])
if not body: return body
if len(body) > 1: return '(' + body + ")'"
return body + "'"
r, s = stringy(re[1]), stringy(re[2])
if tag == CONS: return r + s
if tag == OR: return '%s | %s' % (r, s)
if tag == AND: return '(%s) & (%s)' % (r, s)
raise ValueError
``I``
~~~~~
Match anything. Often spelled "."
::
I = (0|1)*
.. code:: ipython2
I = (KSTAR, (OR, O, l))
.. code:: ipython2
print stringy(I)
.. parsed-literal::
.
``(.111.) & (.01 + 11*)'``
~~~~~~~~~~~~~~~~~~~~~~~~~~
The example expression from Brzozowski:
::
(.111.) & (.01 + 11*)'
a & (b + c)'
Note that it contains one of everything.
.. code:: ipython2
a = (CONS, I, (CONS, l, (CONS, l, (CONS, l, I))))
b = (CONS, I, (CONS, O, l))
c = (CONS, l, (KSTAR, l))
it = (AND, a, (NOT, (OR, b, c)))
.. code:: ipython2
print stringy(it)
.. parsed-literal::
(.111.) & ((.01 | 11*)')
``nully()``
~~~~~~~~~~~
Let's get that auxiliary predicate function ``δ`` out of the way.
.. code:: ipython2
def nully(R):
'''
δ - Return λ if λ ⊆ R otherwise ϕ.
'''
# δ(a) → ϕ
# δ(ϕ) → ϕ
if R in syms or R == phi:
return phi
# δ(λ) → λ
if R == y:
return y
tag = R[0]
# δ(R*) → λ
if tag == KSTAR:
return y
# δ(¬R) δ(R)≟ϕ → λ
# δ(¬R) δ(R)≟λ → ϕ
if tag == NOT:
return phi if nully(R[1]) else y
# δ(R∘S) → δ(R) ∧ δ(S)
# δ(R ∧ S) → δ(R) ∧ δ(S)
# δ(R S) → δ(R) δ(S)
r, s = nully(R[1]), nully(R[2])
return r & s if tag in {AND, CONS} else r | s
No "Compaction"
~~~~~~~~~~~~~~~
This is the straightforward version with no "compaction". It works fine,
but does waaaay too much work because the expressions grow each
derivation.
.. code:: ipython2
# This is the straightforward version with no "compaction".
# It works fine, but does waaaay too much work because the
# expressions grow each derivation.
def D(symbol):
def derv(R):
# ∂a(a) → λ
if R == {symbol}:
return y
# ∂a(λ) → ϕ
# ∂a(ϕ) → ϕ
# ∂a(¬a) → ϕ
if R == y or R == phi or R in syms:
return phi
tag = R[0]
# ∂a(R*) → ∂a(R)∘R*
if tag == KSTAR:
return (CONS, derv(R[1]), R)
# ∂a(¬R) → ¬∂a(R)
if tag == NOT:
return (NOT, derv(R[1]))
r, s = R[1:]
# ∂a(R∘S) → ∂a(R)∘S δ(R)∘∂a(S)
if tag == CONS:
A = (CONS, derv(r), s) # A = ∂a(R)∘S
# A δ(R) ∘ ∂a(S)
# A λ ∘ ∂a(S) → A ∂a(S)
# A ϕ ∘ ∂a(S) → A ϕ → A
return (OR, A, derv(s)) if nully(r) else A
# ∂a(R ∧ S) → ∂a(R) ∧ ∂a(S)
# ∂a(R S) → ∂a(R) ∂a(S)
return (tag, derv(r), derv(s))
return derv
Compaction Rules
~~~~~~~~~~~~~~~~
.. code:: ipython2
def _compaction_rule(relation, one, zero, a, b):
return (
b if a == one else # R*1 = 1*R = R
a if b == one else
zero if a == zero or b == zero else # R*0 = 0*R = 0
(relation, a, b)
)
An elegant symmetry.
.. code:: ipython2
# R ∧ I = I ∧ R = R
# R ∧ ϕ = ϕ ∧ R = ϕ
_and = curry(_compaction_rule, AND, I, phi)
# R ϕ = ϕ R = R
# R I = I R = I
_or = curry(_compaction_rule, OR, phi, I)
# R∘λ = λ∘R = R
# R∘ϕ = ϕ∘R = ϕ
_cons = curry(_compaction_rule, CONS, y, phi)
Memoizing
~~~~~~~~~
We can save re-processing by remembering results we have already
computed. RE datastructures are immutable and the ``derv()`` functions
are *pure* so this is fine.
.. code:: ipython2
class Memo(object):
def __init__(self, f):
self.f = f
self.calls = self.hits = 0
self.mem = {}
def __call__(self, key):
self.calls += 1
try:
result = self.mem[key]
self.hits += 1
except KeyError:
result = self.mem[key] = self.f(key)
return result
With "Compaction"
~~~~~~~~~~~~~~~~~
This version uses the rules above to perform compaction. It keeps the
expressions from growing too large.
.. code:: ipython2
def D_compaction(symbol):
@Memo
def derv(R):
# ∂a(a) → λ
if R == {symbol}:
return y
# ∂a(λ) → ϕ
# ∂a(ϕ) → ϕ
# ∂a(¬a) → ϕ
if R == y or R == phi or R in syms:
return phi
tag = R[0]
# ∂a(R*) → ∂a(R)∘R*
if tag == KSTAR:
return _cons(derv(R[1]), R)
# ∂a(¬R) → ¬∂a(R)
if tag == NOT:
return (NOT, derv(R[1]))
r, s = R[1:]
# ∂a(R∘S) → ∂a(R)∘S δ(R)∘∂a(S)
if tag == CONS:
A = _cons(derv(r), s) # A = ∂a(r)∘s
# A δ(R) ∘ ∂a(S)
# A λ ∘ ∂a(S) → A ∂a(S)
# A ϕ ∘ ∂a(S) → A ϕ → A
return _or(A, derv(s)) if nully(r) else A
# ∂a(R ∧ S) → ∂a(R) ∧ ∂a(S)
# ∂a(R S) → ∂a(R) ∂a(S)
dr, ds = derv(r), derv(s)
return _and(dr, ds) if tag == AND else _or(dr, ds)
return derv
Let's try it out...
-------------------
(FIXME: redo.)
.. code:: ipython2
o, z = D_compaction('0'), D_compaction('1')
REs = set()
N = 5
names = list(product(*(N * [(0, 1)])))
dervs = list(product(*(N * [(o, z)])))
for name, ds in zip(names, dervs):
R = it
ds = list(ds)
while ds:
R = ds.pop()(R)
if R == phi or R == I:
break
REs.add(R)
print stringy(it) ; print
print o.hits, '/', o.calls
print z.hits, '/', z.calls
print
for s in sorted(map(stringy, REs), key=lambda n: (len(n), n)):
print s
.. parsed-literal::
(.111.) & ((.01 | 11*)')
92 / 122
92 / 122
(.01)'
(.01 | 1)'
(.01 | ^)'
(.01 | 1*)'
(.111.) & ((.01 | 1)')
(.111. | 11.) & ((.01 | ^)')
(.111. | 11. | 1.) & ((.01)')
(.111. | 11.) & ((.01 | 1*)')
(.111. | 11. | 1.) & ((.01 | 1*)')
Should match:
::
(.111.) & ((.01 | 11*)')
92 / 122
92 / 122
(.01 )'
(.01 | 1 )'
(.01 | ^ )'
(.01 | 1*)'
(.111.) & ((.01 | 1 )')
(.111. | 11.) & ((.01 | ^ )')
(.111. | 11.) & ((.01 | 1*)')
(.111. | 11. | 1.) & ((.01 )')
(.111. | 11. | 1.) & ((.01 | 1*)')
Larger Alphabets
----------------
We could parse larger alphabets by defining patterns for e.g. each byte
of the ASCII code. Or we can generalize this code. If you study the code
above you'll see that we never use the "set-ness" of the symbols ``O``
and ``l``. The only time Python set operators (``&`` and ``|``) appear
is in the ``nully()`` function, and there they operate on (recursively
computed) outputs of that function, never ``O`` and ``l``.
What if we try:
::
(OR, O, l)
∂1((OR, O, l))
∂a(R S) → ∂a(R) ∂a(S)
∂1(O) ∂1(l)
∂a(¬a) → ϕ
ϕ ∂1(l)
∂a(a) → λ
ϕ λ
ϕ R = R
λ
And compare it to:
::
{'0', '1')
∂1({'0', '1'))
∂a(R S) → ∂a(R) ∂a(S)
∂1({'0')) ∂1({'1'))
∂a(¬a) → ϕ
ϕ ∂1({'1'))
∂a(a) → λ
ϕ λ
ϕ R = R
λ
This suggests that we should be able to alter the functions above to
detect sets and deal with them appropriately. Exercise for the Reader
for now.
State Machine
-------------
We can drive the regular expressions to flesh out the underlying state
machine transition table.
::
.111. & (.01 + 11*)'
Says, "Three or more 1's and not ending in 01 nor composed of all 1's."
.. figure:: omg.svg
:alt: omg.svg
omg.svg
Start at ``a`` and follow the transition arrows according to their
labels. Accepting states have a double outline. (Graphic generated with
`Dot from Graphviz <http://www.graphviz.org/>`__.) You'll see that only
paths that lead to one of the accepting states will match the regular
expression. All other paths will terminate at one of the non-accepting
states.
There's a happy path to ``g`` along 111:
::
a→c→e→g
After you reach ``g`` you're stuck there eating 1's until you see a 0,
which takes you to the ``i→j→i|i→j→h→i`` "trap". You can't reach any
other states from those two loops.
If you see a 0 before you see 111 you will reach ``b``, which forms
another "trap" with ``d`` and ``f``. The only way out is another happy
path along 111 to ``h``:
::
b→d→f→h
Once you have reached ``h`` you can see as many 1's or as many 0' in a
row and still be either still at ``h`` (for 1's) or move to ``i`` (for
0's). If you find yourself at ``i`` you can see as many 0's, or
repetitions of 10, as there are, but if you see just a 1 you move to
``j``.
RE to FSM
~~~~~~~~~
So how do we get the state machine from the regular expression?
It turns out that each RE is effectively a state, and each arrow points
to the derivative RE in respect to the arrow's symbol.
If we label the initial RE ``a``, we can say:
::
a --0--> ∂0(a)
a --1--> ∂1(a)
And so on, each new unique RE is a new state in the FSM table.
Here are the derived REs at each state:
::
a = (.111.) & ((.01 | 11*)')
b = (.111.) & ((.01 | 1)')
c = (.111. | 11.) & ((.01 | 1*)')
d = (.111. | 11.) & ((.01 | ^)')
e = (.111. | 11. | 1.) & ((.01 | 1*)')
f = (.111. | 11. | 1.) & ((.01)')
g = (.01 | 1*)'
h = (.01)'
i = (.01 | 1)'
j = (.01 | ^)'
You can see the one-way nature of the ``g`` state and the ``hij`` "trap"
in the way that the ``.111.`` on the left-hand side of the ``&``
disappears once it has been matched.
.. code:: ipython2
from collections import defaultdict
from pprint import pprint
from string import ascii_lowercase
.. code:: ipython2
d0, d1 = D_compaction('0'), D_compaction('1')
``explore()``
~~~~~~~~~~~~~
.. code:: ipython2
def explore(re):
# Don't have more than 26 states...
names = defaultdict(iter(ascii_lowercase).next)
table, accepting = dict(), set()
to_check = {re}
while to_check:
re = to_check.pop()
state_name = names[re]
if (state_name, 0) in table:
continue
if nully(re):
accepting.add(state_name)
o, i = d0(re), d1(re)
table[state_name, 0] = names[o] ; to_check.add(o)
table[state_name, 1] = names[i] ; to_check.add(i)
return table, accepting
.. code:: ipython2
table, accepting = explore(it)
table
.. parsed-literal::
{('a', 0): 'b',
('a', 1): 'c',
('b', 0): 'b',
('b', 1): 'd',
('c', 0): 'b',
('c', 1): 'e',
('d', 0): 'b',
('d', 1): 'f',
('e', 0): 'b',
('e', 1): 'g',
('f', 0): 'b',
('f', 1): 'h',
('g', 0): 'i',
('g', 1): 'g',
('h', 0): 'i',
('h', 1): 'h',
('i', 0): 'i',
('i', 1): 'j',
('j', 0): 'i',
('j', 1): 'h'}
.. code:: ipython2
accepting
.. parsed-literal::
{'h', 'i'}
Generate Diagram
~~~~~~~~~~~~~~~~
Once we have the FSM table and the set of accepting states we can
generate the diagram above.
.. code:: ipython2
_template = '''\
digraph finite_state_machine {
rankdir=LR;
size="8,5"
node [shape = doublecircle]; %s;
node [shape = circle];
%s
}
'''
def link(fr, nm, label):
return ' %s -> %s [ label = "%s" ];' % (fr, nm, label)
def make_graph(table, accepting):
return _template % (
' '.join(accepting),
'\n'.join(
link(from_, to, char)
for (from_, char), (to) in sorted(table.iteritems())
)
)
.. code:: ipython2
print make_graph(table, accepting)
.. parsed-literal::
digraph finite_state_machine {
rankdir=LR;
size="8,5"
node [shape = doublecircle]; i h;
node [shape = circle];
a -> b [ label = "0" ];
a -> c [ label = "1" ];
b -> b [ label = "0" ];
b -> d [ label = "1" ];
c -> b [ label = "0" ];
c -> e [ label = "1" ];
d -> b [ label = "0" ];
d -> f [ label = "1" ];
e -> b [ label = "0" ];
e -> g [ label = "1" ];
f -> b [ label = "0" ];
f -> h [ label = "1" ];
g -> i [ label = "0" ];
g -> g [ label = "1" ];
h -> i [ label = "0" ];
h -> h [ label = "1" ];
i -> i [ label = "0" ];
i -> j [ label = "1" ];
j -> i [ label = "0" ];
j -> h [ label = "1" ];
}
Drive a FSM
~~~~~~~~~~~
There are *lots* of FSM libraries already. Once you have the state
transition table they should all be straightforward to use. State
Machine code is very simple. Just for fun, here is an implementation in
Python that imitates what "compiled" FSM code might look like in an
"unrolled" form. Most FSM code uses a little driver loop and a table
datastructure, the code below instead acts like JMP instructions
("jump", or GOTO in higher-level-but-still-low-level languages) to
hard-code the information in the table into a little patch of branches.
Trampoline Function
^^^^^^^^^^^^^^^^^^^
Python has no GOTO statement but we can fake it with a "trampoline"
function.
.. code:: ipython2
def trampoline(input_, jump_from, accepting):
I = iter(input_)
while True:
try:
bounce_to = jump_from(I)
except StopIteration:
return jump_from in accepting
jump_from = bounce_to
Stream Functions
^^^^^^^^^^^^^^^^
Little helpers to process the iterator of our data (a "stream" of "1"
and "0" characters, not bits.)
.. code:: ipython2
getch = lambda I: int(next(I))
def _1(I):
'''Loop on ones.'''
while getch(I): pass
def _0(I):
'''Loop on zeros.'''
while not getch(I): pass
A Finite State Machine
^^^^^^^^^^^^^^^^^^^^^^
With those preliminaries out of the way, from the state table of
``.111. & (.01 + 11*)'`` we can immediately write down state machine
code. (You have to imagine that these are GOTO statements in C or
branches in assembly and that the state names are branch destination
labels.)
.. code:: ipython2
a = lambda I: c if getch(I) else b
b = lambda I: _0(I) or d
c = lambda I: e if getch(I) else b
d = lambda I: f if getch(I) else b
e = lambda I: g if getch(I) else b
f = lambda I: h if getch(I) else b
g = lambda I: _1(I) or i
h = lambda I: _1(I) or i
i = lambda I: _0(I) or j
j = lambda I: h if getch(I) else i
Note that the implementations of ``h`` and ``g`` are identical ergo
``h = g`` and we could eliminate one in the code but ``h`` is an
accepting state and ``g`` isn't.
.. code:: ipython2
def acceptable(input_):
return trampoline(input_, a, {h, i})
.. code:: ipython2
for n in range(2**5):
s = bin(n)[2:]
print '%05s' % s, acceptable(s)
.. parsed-literal::
0 False
1 False
10 False
11 False
100 False
101 False
110 False
111 False
1000 False
1001 False
1010 False
1011 False
1100 False
1101 False
1110 True
1111 False
10000 False
10001 False
10010 False
10011 False
10100 False
10101 False
10110 False
10111 True
11000 False
11001 False
11010 False
11011 False
11100 True
11101 False
11110 True
11111 False
Reversing the Derivatives to Generate Matching Strings
------------------------------------------------------
(UNFINISHED) Brzozowski also shewed how to go from the state machine to
strings and expressions...
Each of these states is just a name for a Brzozowskian RE, and so, other
than the initial state ``a``, they can can be described in terms of the
derivative-with-respect-to-N of some other state/RE:
::
c = d1(a)
b = d0(a)
b = d0(c)
...
i = d0(j)
j = d1(i)
Consider:
::
c = d1(a)
b = d0(c)
Substituting:
::
b = d0(d1(a))
Unwrapping:
::
b = d10(a)
'''
::
j = d1(d0(j))
Unwrapping:
::
j = d1(d0(j)) = d01(j)
We have a loop or "fixed point".
::
j = d01(j) = d0101(j) = d010101(j) = ...
hmm...
::
j = (01)*

View File

@ -468,10 +468,8 @@ Putting it all together:
Project Euler Problem Two
-------------------------
::
By considering the terms in the Fibonacci sequence whose values do not exceed four million,
find the sum of the even-valued terms.
By considering the terms in the Fibonacci sequence whose values do
not exceed four million, find the sum of the even-valued terms.
Now that we have a generator for the Fibonacci sequence, we need a
function that adds a term in the sequence to a sum if it is even, and

View File

@ -3,7 +3,7 @@
from notebook_preamble import D, DefinitionWrapper, J, V, define
Recursive Combinators
Recursion Combinators
=====================
This article describes the ``genrec`` combinator, how to use it, and

View File

@ -0,0 +1,337 @@
The Four Fundamental Operations of Definite Action
==================================================
All definite actions (computer program) can be defined by four
fundamental patterns of combination:
1. Sequence
2. Branch
3. Loop
4. Parallel
Sequence
--------
Do one thing after another. In joy this is represented by putting two
symbols together, juxtaposition:
::
foo bar
Operations have inputs and outputs. The outputs of ``foo`` must be
compatible in "arity", type, and shape with the inputs of ``bar``.
Branch
------
Do one thing or another.
::
boolean [F] [T] branch
t [F] [T] branch
----------------------
T
f [F] [T] branch
----------------------
F
branch == unit cons swap pick i
boolean [F] [T] branch
boolean [F] [T] unit cons swap pick i
boolean [F] [[T]] cons swap pick i
boolean [[F] [T]] swap pick i
[[F] [T]] boolean pick i
[F-or-T] i
Given some branch function ``G``:
::
G == [F] [T] branch
Used in a sequence like so:
::
foo G bar
The inputs and outputs of ``F`` and ``T`` must be compatible with the
outputs for ``foo`` and the inputs of ``bar``, respectively.
::
foo F bar
foo T bar
``ifte``
~~~~~~~~
Often it will be easier on the programmer to write branching code with
the predicate specified in a quote. The ``ifte`` combinator provides
this (``T`` for "then" and ``E`` for "else"):
::
[P] [T] [E] ifte
Defined in terms of ``branch``:
::
ifte == [nullary not] dip branch
In this case, ``P`` must be compatible with the stack and return a
Boolean value, and ``T`` and ``E`` both must be compatible with the
preceeding and following functions, as described above for ``F`` and
``T``. (Note that in the current implementation we are depending on
Python for the underlying semantics, so the Boolean value doesn't *have*
to be Boolean because Python's rules for "truthiness" will be used to
evaluate it. I reflect this in the structure of the stack effect comment
of ``branch``, it will only accept Boolean values, and in the definition
of ``ifte`` above by including ``not`` in the quote, which also has the
effect that the subject quotes are in the proper order for ``branch``.)
Loop
----
Do one thing zero or more times.
::
boolean [Q] loop
t [Q] loop
----------------
Q [Q] loop
... f [Q] loop
--------------------
...
The ``loop`` combinator generates a copy of itself in the true branch.
This is the hallmark of recursive defintions. In Thun there is no
equivalent to conventional loops. (There is, however, the ``x``
combinator, defined as ``x == dup i``, which permits recursive
constructs that do not need to be directly self-referential, unlike
``loop`` and ``genrec``.)
::
loop == [] swap [dup dip loop] cons branch
boolean [Q] loop
boolean [Q] [] swap [dup dip loop] cons branch
boolean [] [Q] [dup dip loop] cons branch
boolean [] [[Q] dup dip loop] branch
In action the false branch does nothing while the true branch does:
::
t [] [[Q] dup dip loop] branch
[Q] dup dip loop
[Q] [Q] dip loop
Q [Q] loop
Because ``loop`` expects and consumes a Boolean value, the ``Q``
function must be compatible with the previous stack *and itself* with a
boolean flag for the next iteration:
::
Q == G b
Q [Q] loop
G b [Q] loop
G Q [Q] loop
G G b [Q] loop
G G Q [Q] loop
G G G b [Q] loop
G G G
``while``
~~~~~~~~~
Keep doing ``B`` *while* some predicate ``P`` is true. This is
convenient as the predicate function is made nullary automatically and
the body function can be designed without regard to leaving a Boolean
flag for the next iteration:
::
[P] [B] while
--------------------------------------
[P] nullary [B [P] nullary] loop
while == swap [nullary] cons dup dipd concat loop
[P] [B] while
[P] [B] swap [nullary] cons dup dipd concat loop
[B] [P] [nullary] cons dup dipd concat loop
[B] [[P] nullary] dup dipd concat loop
[B] [[P] nullary] [[P] nullary] dipd concat loop
[P] nullary [B] [[P] nullary] concat loop
[P] nullary [B [P] nullary] loop
Parallel
--------
The *parallel* operation indicates that two (or more) functions *do not
interfere* with each other and so can run in parallel. The main
difficulty in this sort of thing is orchestrating the recombining
("join" or "wait") of the results of the functions after they finish.
The current implementaions and the following definitions *are not
actually parallel* (yet), but there is no reason they couldn't be
reimplemented in terms of e.g. Python threads. I am not concerned with
performance of the system just yet, only the elegance of the code it
allows us to write.
``cleave``
~~~~~~~~~~
Joy has a few parallel combinators, the main one being ``cleave``:
::
... x [A] [B] cleave
---------------------------------------------------------
... [x ...] [A] infra first [x ...] [B] infra first
---------------------------------------------------------
... a b
The ``cleave`` combinator expects a value and two quotes and it executes
each quote in "separate universes" such that neither can affect the
other, then it takes the first item from the stack in each universe and
replaces the value and quotes with their respective results.
(I think this corresponds to the "fork" operator, the little
upward-pointed triangle, that takes two functions ``A :: x -> a`` and
``B :: x -> b`` and returns a function ``F :: x -> (a, b)``, in Conal
Elliott's "Compiling to Categories" paper, et. al.)
Just a thought, if you ``cleave`` two jobs and one requires more time to
finish than the other you'd like to be able to assign resources
accordingly so that they both finish at the same time.
"Apply" Functions
~~~~~~~~~~~~~~~~~
There are also ``app2`` and ``app3`` which run a single quote on more
than one value:
::
... y x [Q] app2
---------------------------------------------------------
... [y ...] [Q] infra first [x ...] [Q] infra first
... z y x [Q] app3
---------------------------------
... [z ...] [Q] infra first
[y ...] [Q] infra first
[x ...] [Q] infra first
Because the quoted program can be ``i`` we can define ``cleave`` in
terms of ``app2``:
::
cleave == [i] app2 [popd] dip
(I'm not sure why ``cleave`` was specified to take that value, I may
make a combinator that does the same thing but without expecting a
value.)
::
clv == [i] app2
[A] [B] clv
------------------
a b
``map``
~~~~~~~
The common ``map`` function in Joy should also be though of as a
*parallel* operator:
::
[a b c ...] [Q] map
There is no reason why the implementation of ``map`` couldn't distribute
the ``Q`` function over e.g. a pool of worker CPUs.
``pam``
~~~~~~~
One of my favorite combinators, the ``pam`` combinator is just:
::
pam == [i] map
This can be used to run any number of programs separately on the current
stack and combine their (first) outputs in a result list.
::
[[A] [B] [C] ...] [i] map
-------------------------------
[ a b c ...]
Handling Other Kinds of Join
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``cleave`` operators and others all have pretty brutal join
semantics: everything works and we always wait for every
sub-computation. We can imagine a few different potentially useful
patterns of "joining" results from parallel combinators.
first-to-finish
^^^^^^^^^^^^^^^
Thinking about variations of ``pam`` there could be one that only
returns the first result of the first-to-finish sub-program, or the
stack could be replaced by its output stack.
The other sub-programs would be cancelled.
"Fulminators"
^^^^^^^^^^^^^
Also known as "Futures" or "Promises" (by *everybody* else. "Fulinators"
is what I was going to call them when I was thinking about implementing
them in Thun.)
The runtime could be amended to permit "thunks" representing the results
of in-progress computations to be left on the stack and picked up by
subsequent functions. These would themselves be able to leave behind
more "thunks", the values of which depend on the eventual resolution of
the values of the previous thunks.
In this way you can create "chains" (and more complex shapes) out of
normal-looking code that consist of a kind of call-graph interspersed
with "asyncronous" ... events?
In any case, until I can find a rigorous theory that shows that this
sort of thing works perfectly in Joy code I'm not going to worry about
it. (And I think the Categories can deal with it anyhow? Incremental
evaluation, yeah?)

View File

@ -0,0 +1,172 @@
Type Checking
=============
.. code:: ipython2
import logging, sys
logging.basicConfig(
format='%(message)s',
stream=sys.stdout,
level=logging.INFO,
)
.. code:: ipython2
from joy.utils.polytypes import (
doc_from_stack_effect,
infer,
reify,
unify,
FUNCTIONS,
JoyTypeError,
)
.. code:: ipython2
D = FUNCTIONS.copy()
del D['product']
globals().update(D)
An Example
----------
.. code:: ipython2
fi, fo = infer(pop, swap, rolldown, rrest, ccons)[0]
.. parsed-literal::
25 (--) ∘ pop swap rolldown rrest ccons
28 (a1 --) ∘ swap rolldown rrest ccons
31 (a3 a2 a1 -- a2 a3) ∘ rolldown rrest ccons
34 (a4 a3 a2 a1 -- a2 a3 a4) ∘ rrest ccons
37 ([a4 a5 ...1] a3 a2 a1 -- a2 a3 [...1]) ∘ ccons
40 ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) ∘
.. code:: ipython2
print doc_from_stack_effect(fi, fo)
.. parsed-literal::
([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1])
.. code:: ipython2
from joy.parser import text_to_expression
from joy.utils.stack import stack_to_string
.. code:: ipython2
e = text_to_expression('0 1 2 [3 4]') # reverse order
print stack_to_string(e)
.. parsed-literal::
[3 4] 2 1 0
.. code:: ipython2
u = unify(e, fi)[0]
u
.. parsed-literal::
{a1: 0, a2: 1, a3: 2, a4: 3, a5: 4, s2: (), s1: ()}
.. code:: ipython2
g = reify(u, (fi, fo))
print doc_from_stack_effect(*g)
.. parsed-literal::
(... [3 4 ] 2 1 0 -- ... [1 2 ])
Unification Works "in Reverse"
------------------------------
.. code:: ipython2
e = text_to_expression('[2 3]')
.. code:: ipython2
u = unify(e, fo)[0] # output side, not input side
u
.. parsed-literal::
{a2: 2, a3: 3, s2: (), s1: ()}
.. code:: ipython2
g = reify(u, (fi, fo))
print doc_from_stack_effect(*g)
.. parsed-literal::
(... [a4 a5 ] 3 2 a1 -- ... [2 3 ])
Failing a Check
---------------
.. code:: ipython2
fi, fo = infer(dup, mul)[0]
.. parsed-literal::
25 (--) ∘ dup mul
28 (a1 -- a1 a1) ∘ mul
31 (f1 -- f2) ∘
31 (i1 -- i2) ∘
.. code:: ipython2
e = text_to_expression('"two"')
print stack_to_string(e)
.. parsed-literal::
'two'
.. code:: ipython2
try:
unify(e, fi)
except JoyTypeError, err:
print err
.. parsed-literal::
Cannot unify 'two' and f1.

View File

@ -0,0 +1,185 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: finite_state_machine Pages: 1 -->
<svg width="534pt" height="270pt"
viewBox="0.00 0.00 534.00 270.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 266)">
<title>finite_state_machine</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-266 530,-266 530,4 -4,4"/>
<!-- i -->
<g id="node1" class="node"><title>i</title>
<ellipse fill="none" stroke="black" cx="338" cy="-146" rx="18" ry="18"/>
<ellipse fill="none" stroke="black" cx="338" cy="-146" rx="22" ry="22"/>
<text text-anchor="middle" x="338" y="-142.3" font-family="Times,serif" font-size="14.00">i</text>
</g>
<!-- i&#45;&gt;i -->
<g id="edge17" class="edge"><title>i&#45;&gt;i</title>
<path fill="none" stroke="black" d="M330.317,-166.991C329.369,-177.087 331.93,-186 338,-186 341.889,-186 344.337,-182.342 345.346,-177.059"/>
<polygon fill="black" stroke="black" points="348.846,-177.102 345.683,-166.991 341.85,-176.868 348.846,-177.102"/>
<text text-anchor="middle" x="338" y="-189.8" font-family="Times,serif" font-size="14.00">0</text>
</g>
<!-- j -->
<g id="node10" class="node"><title>j</title>
<ellipse fill="none" stroke="black" cx="421" cy="-136" rx="18" ry="18"/>
<text text-anchor="middle" x="421" y="-132.3" font-family="Times,serif" font-size="14.00">j</text>
</g>
<!-- i&#45;&gt;j -->
<g id="edge18" class="edge"><title>i&#45;&gt;j</title>
<path fill="none" stroke="black" d="M357.466,-135.495C363.775,-132.451 371.008,-129.536 378,-128 383.213,-126.855 388.811,-126.984 394.167,-127.763"/>
<polygon fill="black" stroke="black" points="393.487,-131.197 404.002,-129.894 394.97,-124.355 393.487,-131.197"/>
<text text-anchor="middle" x="381.5" y="-131.8" font-family="Times,serif" font-size="14.00">1</text>
</g>
<!-- h -->
<g id="node2" class="node"><title>h</title>
<ellipse fill="none" stroke="black" cx="504" cy="-85" rx="18" ry="18"/>
<ellipse fill="none" stroke="black" cx="504" cy="-85" rx="22" ry="22"/>
<text text-anchor="middle" x="504" y="-81.3" font-family="Times,serif" font-size="14.00">h</text>
</g>
<!-- h&#45;&gt;i -->
<g id="edge15" class="edge"><title>h&#45;&gt;i</title>
<path fill="none" stroke="black" d="M481.868,-83.4025C461.033,-82.62 428.676,-83.5645 403,-94 387.267,-100.394 372.373,-112.028 360.918,-122.673"/>
<polygon fill="black" stroke="black" points="358.306,-120.33 353.569,-129.807 363.182,-125.353 358.306,-120.33"/>
<text text-anchor="middle" x="421" y="-97.8" font-family="Times,serif" font-size="14.00">0</text>
</g>
<!-- h&#45;&gt;h -->
<g id="edge16" class="edge"><title>h&#45;&gt;h</title>
<path fill="none" stroke="black" d="M496.317,-105.991C495.369,-116.087 497.93,-125 504,-125 507.889,-125 510.337,-121.342 511.346,-116.059"/>
<polygon fill="black" stroke="black" points="514.846,-116.102 511.683,-105.991 507.85,-115.868 514.846,-116.102"/>
<text text-anchor="middle" x="504" y="-128.8" font-family="Times,serif" font-size="14.00">1</text>
</g>
<!-- a -->
<g id="node3" class="node"><title>a</title>
<ellipse fill="none" stroke="black" cx="18" cy="-128" rx="18" ry="18"/>
<text text-anchor="middle" x="18" y="-124.3" font-family="Times,serif" font-size="14.00">a</text>
</g>
<!-- b -->
<g id="node4" class="node"><title>b</title>
<ellipse fill="none" stroke="black" cx="255" cy="-113" rx="18" ry="18"/>
<text text-anchor="middle" x="255" y="-109.3" font-family="Times,serif" font-size="14.00">b</text>
</g>
<!-- a&#45;&gt;b -->
<g id="edge1" class="edge"><title>a&#45;&gt;b</title>
<path fill="none" stroke="black" d="M36.2801,-126.897C76.7816,-124.312 178.091,-117.845 226.89,-114.73"/>
<polygon fill="black" stroke="black" points="227.255,-118.214 237.011,-114.084 226.809,-111.229 227.255,-118.214"/>
<text text-anchor="middle" x="136.5" y="-123.8" font-family="Times,serif" font-size="14.00">0</text>
</g>
<!-- c -->
<g id="node5" class="node"><title>c</title>
<ellipse fill="none" stroke="black" cx="97" cy="-155" rx="18" ry="18"/>
<text text-anchor="middle" x="97" y="-151.3" font-family="Times,serif" font-size="14.00">c</text>
</g>
<!-- a&#45;&gt;c -->
<g id="edge2" class="edge"><title>a&#45;&gt;c</title>
<path fill="none" stroke="black" d="M35.3297,-133.726C45.4364,-137.27 58.635,-141.898 70.1398,-145.932"/>
<polygon fill="black" stroke="black" points="69.099,-149.276 79.6938,-149.282 71.4153,-142.67 69.099,-149.276"/>
<text text-anchor="middle" x="57.5" y="-145.8" font-family="Times,serif" font-size="14.00">1</text>
</g>
<!-- b&#45;&gt;b -->
<g id="edge3" class="edge"><title>b&#45;&gt;b</title>
<path fill="none" stroke="black" d="M248.266,-130.037C246.892,-139.858 249.137,-149 255,-149 258.665,-149 260.916,-145.429 261.753,-140.353"/>
<polygon fill="black" stroke="black" points="265.252,-140.031 261.734,-130.037 258.252,-140.044 265.252,-140.031"/>
<text text-anchor="middle" x="255" y="-152.8" font-family="Times,serif" font-size="14.00">0</text>
</g>
<!-- d -->
<g id="node6" class="node"><title>d</title>
<ellipse fill="none" stroke="black" cx="338" cy="-79" rx="18" ry="18"/>
<text text-anchor="middle" x="338" y="-75.3" font-family="Times,serif" font-size="14.00">d</text>
</g>
<!-- b&#45;&gt;d -->
<g id="edge4" class="edge"><title>b&#45;&gt;d</title>
<path fill="none" stroke="black" d="M272.003,-106.283C283.319,-101.533 298.722,-95.0674 311.693,-89.6227"/>
<polygon fill="black" stroke="black" points="313.164,-92.801 321.03,-85.7034 310.455,-86.3466 313.164,-92.801"/>
<text text-anchor="middle" x="294.5" y="-101.8" font-family="Times,serif" font-size="14.00">1</text>
</g>
<!-- c&#45;&gt;b -->
<g id="edge5" class="edge"><title>c&#45;&gt;b</title>
<path fill="none" stroke="black" d="M114.862,-150.653C138.269,-144.593 181.917,-133.2 219,-123 221.799,-122.23 224.721,-121.414 227.631,-120.594"/>
<polygon fill="black" stroke="black" points="228.623,-123.951 237.284,-117.849 226.708,-117.218 228.623,-123.951"/>
<text text-anchor="middle" x="176" y="-142.8" font-family="Times,serif" font-size="14.00">0</text>
</g>
<!-- e -->
<g id="node7" class="node"><title>e</title>
<ellipse fill="none" stroke="black" cx="176" cy="-206" rx="18" ry="18"/>
<text text-anchor="middle" x="176" y="-202.3" font-family="Times,serif" font-size="14.00">e</text>
</g>
<!-- c&#45;&gt;e -->
<g id="edge6" class="edge"><title>c&#45;&gt;e</title>
<path fill="none" stroke="black" d="M112.483,-164.593C123.668,-172.001 139.356,-182.392 152.219,-190.911"/>
<polygon fill="black" stroke="black" points="150.312,-193.846 160.582,-196.45 154.177,-188.01 150.312,-193.846"/>
<text text-anchor="middle" x="136.5" y="-185.8" font-family="Times,serif" font-size="14.00">1</text>
</g>
<!-- d&#45;&gt;b -->
<g id="edge7" class="edge"><title>d&#45;&gt;b</title>
<path fill="none" stroke="black" d="M320.205,-74.8763C311.208,-73.4911 300.131,-73.1424 291,-77 284.094,-79.9175 277.879,-84.9376 272.669,-90.3183"/>
<polygon fill="black" stroke="black" points="269.694,-88.4067 265.791,-98.2568 274.985,-92.9902 269.694,-88.4067"/>
<text text-anchor="middle" x="294.5" y="-80.8" font-family="Times,serif" font-size="14.00">0</text>
</g>
<!-- f -->
<g id="node8" class="node"><title>f</title>
<ellipse fill="none" stroke="black" cx="176" cy="-46" rx="18" ry="18"/>
<text text-anchor="middle" x="176" y="-42.3" font-family="Times,serif" font-size="14.00">f</text>
</g>
<!-- d&#45;&gt;f -->
<g id="edge8" class="edge"><title>d&#45;&gt;f</title>
<path fill="none" stroke="black" d="M319.923,-75.478C292.098,-69.7389 236.768,-58.3271 203.708,-51.5086"/>
<polygon fill="black" stroke="black" points="204.321,-48.0614 193.82,-49.4692 202.907,-54.9171 204.321,-48.0614"/>
<text text-anchor="middle" x="255" y="-69.8" font-family="Times,serif" font-size="14.00">1</text>
</g>
<!-- e&#45;&gt;b -->
<g id="edge9" class="edge"><title>e&#45;&gt;b</title>
<path fill="none" stroke="black" d="M190.241,-194.796C198.908,-187.136 210.212,-176.503 219,-166 226.507,-157.028 233.803,-146.389 239.774,-137.007"/>
<polygon fill="black" stroke="black" points="242.759,-138.834 245.056,-128.491 236.81,-135.144 242.759,-138.834"/>
<text text-anchor="middle" x="215.5" y="-176.8" font-family="Times,serif" font-size="14.00">0</text>
</g>
<!-- g -->
<g id="node9" class="node"><title>g</title>
<ellipse fill="none" stroke="black" cx="255" cy="-211" rx="18" ry="18"/>
<text text-anchor="middle" x="255" y="-207.3" font-family="Times,serif" font-size="14.00">g</text>
</g>
<!-- e&#45;&gt;g -->
<g id="edge10" class="edge"><title>e&#45;&gt;g</title>
<path fill="none" stroke="black" d="M194.089,-207.11C203.659,-207.731 215.817,-208.521 226.677,-209.226"/>
<polygon fill="black" stroke="black" points="226.753,-212.738 236.959,-209.893 227.207,-205.753 226.753,-212.738"/>
<text text-anchor="middle" x="215.5" y="-211.8" font-family="Times,serif" font-size="14.00">1</text>
</g>
<!-- f&#45;&gt;h -->
<g id="edge12" class="edge"><title>f&#45;&gt;h</title>
<path fill="none" stroke="black" d="M189.02,-33.1864C203.151,-19.5754 227.995,-0 254,-0 254,-0 254,-0 422,-0 453.632,-0 476.677,-31.2311 489.924,-55.8314"/>
<polygon fill="black" stroke="black" points="486.862,-57.5325 494.518,-64.8562 493.1,-54.3566 486.862,-57.5325"/>
<text text-anchor="middle" x="338" y="-3.8" font-family="Times,serif" font-size="14.00">1</text>
</g>
<!-- f&#45;&gt;b -->
<g id="edge11" class="edge"><title>f&#45;&gt;b</title>
<path fill="none" stroke="black" d="M190.834,-56.7689C199.13,-63.3319 209.817,-71.9742 219,-80 224.034,-84.4001 229.343,-89.2757 234.262,-93.899"/>
<polygon fill="black" stroke="black" points="231.917,-96.4985 241.576,-100.852 236.74,-91.4252 231.917,-96.4985"/>
<text text-anchor="middle" x="215.5" y="-83.8" font-family="Times,serif" font-size="14.00">0</text>
</g>
<!-- g&#45;&gt;i -->
<g id="edge13" class="edge"><title>g&#45;&gt;i</title>
<path fill="none" stroke="black" d="M269.741,-199.974C281.437,-190.587 298.524,-176.876 312.548,-165.622"/>
<polygon fill="black" stroke="black" points="314.778,-168.32 320.387,-159.331 310.397,-162.86 314.778,-168.32"/>
<text text-anchor="middle" x="294.5" y="-185.8" font-family="Times,serif" font-size="14.00">0</text>
</g>
<!-- g&#45;&gt;g -->
<g id="edge14" class="edge"><title>g&#45;&gt;g</title>
<path fill="none" stroke="black" d="M248.266,-228.037C246.892,-237.858 249.137,-247 255,-247 258.665,-247 260.916,-243.429 261.753,-238.353"/>
<polygon fill="black" stroke="black" points="265.252,-238.031 261.734,-228.037 258.252,-238.044 265.252,-238.031"/>
<text text-anchor="middle" x="255" y="-250.8" font-family="Times,serif" font-size="14.00">1</text>
</g>
<!-- j&#45;&gt;i -->
<g id="edge19" class="edge"><title>j&#45;&gt;i</title>
<path fill="none" stroke="black" d="M403.34,-139.8C397.561,-140.993 391.021,-142.205 385,-143 380.321,-143.618 375.357,-144.11 370.488,-144.502"/>
<polygon fill="black" stroke="black" points="369.864,-141.036 360.126,-145.209 370.341,-148.02 369.864,-141.036"/>
<text text-anchor="middle" x="381.5" y="-146.8" font-family="Times,serif" font-size="14.00">0</text>
</g>
<!-- j&#45;&gt;h -->
<g id="edge20" class="edge"><title>j&#45;&gt;h</title>
<path fill="none" stroke="black" d="M436.857,-126.646C447.841,-119.73 463.1,-110.122 476.194,-101.878"/>
<polygon fill="black" stroke="black" points="478.237,-104.727 484.835,-96.4375 474.507,-98.8038 478.237,-104.727"/>
<text text-anchor="middle" x="460.5" y="-116.8" font-family="Times,serif" font-size="14.00">1</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB