{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# ~~Cerrect~~\n", "\n", "# ~~Corroct~~\n", "\n", "# Correct Programming\n", "\n", "Symbolic Logic in the Laws of Form ○ Python Expressions to Represent Forms ○ Reify Forms in an Environment ○ Building Circuits ○ Simplifying Expressions ○ SAT Solver ○ A Model of Computation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction\n", "\n", "In 1969 George Spencer-Brown (GSB) published [\"Laws of Form\"](https://en.wikipedia.org/wiki/Laws_of_Form) which presented a logical system based on a single action, a distinction, that is both an operation and a value. This notebook describes a Python implementation that mimics the Laws of Form notation and uses it to develop a model of computer circuits." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Laws of Form\n", "\n", "See [The Markable Mark](http://www.markability.net/).\n", "\n", "#### Arithmetic\n", "\n", " (()) =\n", " ()() = ()\n", " \n", "#### Calculus\n", "\n", " A((B)) = AB\n", " A() = ()\n", " A(AB) = A(B)\n", " \n", "I call these three laws the __Bricken Basis__ after [William Bricken](http://wbricken.com/) who figured out that the third law is complete with the other two. GSB had the first two laws and \"Each Way\" as the basis. (TODO: Find and include the references for all this.)\n", "\n", "(If anything here is unclear read [The Markable Mark](http://www.markability.net/). George Burnett-Stuart has done a fantastic job there explaining the _Laws of Form_.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Python Sets and Strings as Laws of Form Calculus Expressions\n", "\n", "We can use data structures made solely out of Python `frozenset` and string objects to represent the forms of the Laws of Form notation. I'm going to use the terms \"expression\" and \"form\" interchangably in this document." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "class Form(frozenset):\n", "\n", " def __str__(self):\n", " # Because frozenset is immutable, and the contents are all string or frozenset,\n", " # we can cache the string repr of a form.\n", " try:\n", " return self._str\n", " except AttributeError:\n", " self._str = '(%s)' % ' '.join(sorted(map(str, self)))\n", " return self._str\n", "\n", " __repr__ = __str__\n", " \n", "\n", "def F(*terms):\n", " '''Create a Form from terms.'''\n", " return Form([\n", " term if isinstance(term, (basestring, Form)) else F(*term)\n", " for term in terms\n", " ])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define a few variable names." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "a, b, c = 'abc'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some examples of forms." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(a b c)" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = F(a, b, c)\n", "A" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(((c) b) a)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B = F(a, (b, (c,)))\n", "B" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Forms like `a b c` must be enclosed in a pair of nested containers like so `(( a b c ))`, this lets us treat them as a single (Python) object without inverting the logical value of the form." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((a b c))" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C = F((a, b, c))\n", "C" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Duplicate terms in a form are automatically removed by `frozenset`." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((b) a)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "F(a, (b,), a, (b,))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Order is irrelevant, again due to `frozenset`." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "F(b, a, c) == F(a, b, c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It's prefectly okay to create forms out of other forms (not just strings.)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(((((a b c))) (((c) b) a)) (a b c) a)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "F(A, (B, (C,)), a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Mark and Void." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "()" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Mark = F()\n", "Mark" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is no way to represent Void directly in a programming language so we have to use the simplest Void-valued form instead." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(())" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Void = F(Mark)\n", "Void" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Environments\n", "We can use a Python `dict` as a context or environment that supplies values (Mark or Void) for the names in a form." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "env = dict(a=Mark, b=Mark, c=Mark)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The `reify(form, environment)` Function\n", "Given forms with string variable names in them we want to be able to substitute values from an environment. If these values are Mark or Void the result will be a pure arithmentic form." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "def reify(form, environment):\n", " if isinstance(form, basestring):\n", " return environment.get(form, form)\n", " return Form(reify(inner, environment) for inner in form)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(a b c) ⟶ (())\n", "(((c) b) a) ⟶ (((()) ()) ())\n", "((a b c)) ⟶ ((()))\n" ] } ], "source": [ "for form in (A, B, C):\n", " print form, u'⟶', reify(form, env)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The `void(form)` Function\n", "Once the forms have been rendered to pure arithmetic we can use the `void()` function to find the value of each expression." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "def void(form):\n", " return any(not void(i) for i in form)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `void()` function returns a Boolean value (Python `True` or `False`), for convenience let's write a function that returns the Mark or Void value of a form." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "def value_of(form, m=Mark, v=Void):\n", " return (m, v)[void(form)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can use the `void()` function (by way of `value_of()`) to calculate the base value of each expression structure." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(a b c) ⟶ (()) ⟶ (())\n", "(((c) b) a) ⟶ (((()) ()) ()) ⟶ (())\n", "((a b c)) ⟶ ((())) ⟶ ()\n" ] } ], "source": [ "for form in (A, B, C):\n", " arith = reify(form, env)\n", " print form, u'⟶', arith, u'⟶', value_of(arith)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## All Possible Environments\n", "For $n$ variables there are $2^n$ possible assignments of the two values of Mark and Void. If we generate environments that each contain one of the possible assignments of names to the base value we can evaluate an expression containing those names and compute its value." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[{'a': (()), 'b': (()), 'c': (())},\n", " {'a': (()), 'b': (()), 'c': ()},\n", " {'a': (()), 'b': (), 'c': (())},\n", " {'a': (()), 'b': (), 'c': ()},\n", " {'a': (), 'b': (()), 'c': (())},\n", " {'a': (), 'b': (()), 'c': ()},\n", " {'a': (), 'b': (), 'c': (())},\n", " {'a': (), 'b': (), 'c': ()}]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from itertools import product, izip\n", "\n", "\n", "BASE = Void, Mark\n", "\n", "\n", "def environments_of_variables(*variables):\n", " universe = [BASE] * len(variables)\n", " for values in product(*universe):\n", " yield dict(izip(variables, values))\n", "\n", "\n", "envs = list(environments_of_variables(*'abc'))\n", "\n", "\n", "envs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is a bit hard to read, so let's define a helper function to convert an environment to a string format." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "def format_env(env, m='()', v=' '):\n", " return ' '.join((v, m)[not env[k]] for k in sorted(env))\n", "\n", "# Note that Mark is an empty frozenset so in a Boolean context in Python it is False,\n", "# likewise Void is a set with one member, so Python considers it True in a Boolean context.\n", "# The `not` in the expression is just to force such a Boolean context, and we compensate\n", "# by putting `v` in the zero-is-False position in the indexed tuple." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can print out the environments in a table. Notice that it looks just like a list of the eight three-bit binary numbers." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "i a b c i in Binary\n", "0 -- -- -- 0\n", "1 -- -- () 1\n", "2 -- () -- 10\n", "3 -- () () 11\n", "4 () -- -- 100\n", "5 () -- () 101\n", "6 () () -- 110\n", "7 () () () 111\n" ] } ], "source": [ "print 'i a b c i in Binary'\n", "for i, env in enumerate(envs):\n", " print i, format_env(env, v='--'), '%3s' % (bin(i)[2:],)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Reify the Forms with Each Meaning\n", "Let's pick one of the expressions and iterate through the environments showing the result of reifying that expression in that environment." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(((c) b) a)\n", "-----------\n", "0 -- -- -- ⟶ ((((())) (())) (())) ⟶ ()\n", "1 -- -- () ⟶ (((())) (())) ⟶ \n", "2 -- () -- ⟶ ((((())) ()) (())) ⟶ ()\n", "3 -- () () ⟶ (((()) ()) (())) ⟶ ()\n", "4 () -- -- ⟶ ((((())) (())) ()) ⟶ \n", "5 () -- () ⟶ (((())) ()) ⟶ \n", "6 () () -- ⟶ ((((())) ()) ()) ⟶ \n", "7 () () () ⟶ (((()) ()) ()) ⟶ \n" ] } ], "source": [ "print B\n", "print '-----------'\n", "for i, env in enumerate(envs):\n", " e = reify(B, env)\n", " print i, format_env(env, v='--'), u'⟶', e, u'⟶', value_of(e, m='()', v='')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Truth Table\n", "\n", "Let's render the above as a [Truth Table](https://en.wikipedia.org/wiki/Truth_table)." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "def truth_table_3(expression):\n", " print expression\n", " print ' a b c | Value'\n", " print '---------+------'\n", " for E in envs:\n", " e = reify(expression, E)\n", " print format_env(E), '|', value_of(e, m='()', v='')" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(((c) b) a)\n", " a b c | Value\n", "---------+------\n", " | ()\n", " () | \n", " () | ()\n", " () () | ()\n", "() | \n", "() () | \n", "() () | \n", "() () () | \n" ] } ], "source": [ "truth_table_3(B)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This makes it clear that *each expression in Laws of Form calculus is describing a digital Boolean circuit*. The names are its inputs and its Void/Mark value is its output. Each boundary is a [multi-input **NOR** gate](https://en.wikipedia.org/wiki/Logical_NOR), known as the Peirce arrow or Quine dagger (See [Sheffer stroke](https://en.wikipedia.org/wiki/Sheffer_stroke) and [NOR gate](https://en.wikipedia.org/wiki/NOR_gate).) Instead of two Boolean values there is only one value and non-existance." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Let's build Circuits\n", "In order to work with expressions as digital circuits, let's define some helper functions that will create logic circuits out of simpler forms. The names of the functions below reflect the choice of Mark as Boolean `True` but this is [just a convention](#Appendix:-Duals)." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "nor = lambda *bits: F(*bits)\n", "or_ = lambda *bits: F(bits)\n", "and_ = lambda *bits: Form(F(bit) for bit in bits)\n", "nand = lambda *bits: nor(and_(*bits))\n", "nxor = eqiv = lambda a, b: F((a, (b,)), ((a,), b))\n", "xor = lambda a, b: F(nxor(a, b))\n", "\n", "# To build logical expressions with Void as Boolean True use these functions.\n", "anti_nor = nand\n", "anti_or = and_\n", "anti_and = or_\n", "anti_nand = nor\n", "anti_eqiv = xor\n", "anti_xor = eqiv" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some examples:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(a b c)\n", "((a b c))\n", "((a) (b) (c))\n", "(((a) (b) (c)))\n", "((((a) b) ((b) a)))\n", "(((a) b) ((b) a))\n", "((((((((b) c) ((c) b)))) a) (((((b) c) ((c) b))) (a))))\n" ] } ], "source": [ "a, b, c = 'abc'\n", "\n", "\n", "some_expressions = (\n", " nor(a, b, c),\n", " or_(a, b, c),\n", " and_(a, b, c),\n", " nand(a, b, c),\n", " xor(a, b),\n", " eqiv(a, b),\n", " xor(a, xor(b, c)),\n", ")\n", "\n", "\n", "for expression in some_expressions:\n", " print expression" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And let's rewrite the `truth_table_3()` function to make it work for any number of variables." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "def yield_variables_of(expression):\n", " '''Yield all string members of an expression.'''\n", " if isinstance(expression, basestring):\n", " yield expression\n", " else:\n", " for inner in expression:\n", " for leaf in yield_variables_of(inner):\n", " yield leaf\n", "\n", "\n", "def collect_names(expression):\n", " '''Return a set of the variables mentioned in an expression.'''\n", " return set(yield_variables_of(expression))\n", "\n", "\n", "def truth_table(expression):\n", " '''Print a truth table for an expression.'''\n", " names = sorted(collect_names(expression))\n", " header = ' ' + ' '.join(names)\n", " n = 1 + len(header)\n", " header += ' | Value'\n", " print expression\n", " print header\n", " print '-' * n + '+------'\n", " for env in environments_of_variables(*names):\n", " e = reify(expression, env)\n", " print format_env(env), '|', ['()', ''][void(e)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use this `truth_table()` function to examine the expressions we created above." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(a b c)\n", " a b c | Value\n", "---------+------\n", " | ()\n", " () | \n", " () | \n", " () () | \n", "() | \n", "() () | \n", "() () | \n", "() () () | \n" ] } ], "source": [ "truth_table(nor(a, b, c))" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "((a b c))\n", " a b c | Value\n", "---------+------\n", " | \n", " () | ()\n", " () | ()\n", " () () | ()\n", "() | ()\n", "() () | ()\n", "() () | ()\n", "() () () | ()\n" ] } ], "source": [ "truth_table(or_(a, b, c))" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "((a) (b) (c))\n", " a b c | Value\n", "---------+------\n", " | \n", " () | \n", " () | \n", " () () | \n", "() | \n", "() () | \n", "() () | \n", "() () () | ()\n" ] } ], "source": [ "truth_table(and_(a, b, c))" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "((((a) b) ((b) a)))\n", " a b | Value\n", "------+------\n", " | \n", " () | ()\n", "() | ()\n", "() () | \n" ] } ], "source": [ "truth_table(xor(a, b))" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(((a) b) ((b) a))\n", " a b | Value\n", "------+------\n", " | ()\n", " () | \n", "() | \n", "() () | ()\n" ] } ], "source": [ "truth_table(eqiv(a, b))" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "((((((((b) c) ((c) b)))) a) (((((b) c) ((c) b))) (a))))\n", " a b c | Value\n", "---------+------\n", " | \n", " () | ()\n", " () | ()\n", " () () | \n", "() | ()\n", "() () | \n", "() () | \n", "() () () | ()\n" ] } ], "source": [ "truth_table(xor(a, xor(b, c)))" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "((((((a) (b)) ((a) (c)) ((b) (c))))) ((((a) (b) (c)))))\n", " a b c | Value\n", "---------+------\n", " | \n", " () | \n", " () | \n", " () () | ()\n", "() | \n", "() () | ()\n", "() () | ()\n", "() () () | \n" ] } ], "source": [ "E1 = and_(\n", " or_(and_(a, b), and_(b, c), and_(c, a)), # Any two variables...\n", " nand(a, b, c) # ...but not all three.\n", ")\n", "truth_table(E1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is a [brute-force](https://en.wikipedia.org/wiki/Brute-force_search) [SAT](https://en.wikipedia.org/wiki/Boolean_satisfiability_problem) [solver](https://en.wikipedia.org/wiki/Boolean_satisfiability_problem#Algorithms_for_solving_SAT) that doesn't even bother to stop once it's found a solution." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Expressions from Truth Tables\n", "\n", "Sometimes we will have a function for which we know the behavior (truth table) but not an expression and we want the expression. For example, imagine that we didn't just create the expression for this table:\n", "\n", " a b c | Value\n", " ---------+------\n", " | \n", " () | \n", " () | \n", " () () | ()\n", " () | \n", " () () | ()\n", " () () | ()\n", " () () () | \n", " \n", "### Each Row can be Represented as an Expression\n", "To write an expression for this table, first we should understand that each row can be represented as an expression.\n", "\n", " ⟶ ( a b c )\n", " () ⟶ ( a b (c))\n", " () ⟶ ( a (b) c )\n", " () () ⟶ ( a (b) (c))\n", " () ⟶ ((a) b c )\n", " () () ⟶ ((a) b (c))\n", " () () ⟶ ((a) (b) c )\n", " () () () ⟶ ((a) (b) (c))\n", "\n", "Each of the above expressions will be true (Mark-valued) for only one possible combination of the three input variables. For example, let's look at the sixth expression above:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "((a) (c) b)\n", " a b c | Value\n", "---------+------\n", " | \n", " () | \n", " () | \n", " () () | \n", "() | \n", "() () | ()\n", "() () | \n", "() () () | \n" ] } ], "source": [ "e6 = F((a,), b, (c,))\n", "truth_table(e6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To make an expression that is Mark-valued for just certain rows of the table, pick those rows' expressions,\n", "\n", " () () | ( a (b) (c))\n", " () () | ((a) b (c))\n", " () () | ((a) (b) c )\n", " \n", "And write them down as terms in an **OR** expression:\n", "\n", " E = (a(b)(c)) ((a)b(c)) ((a)(b)c)\n", " \n", "In conventional notation this is called [Disjunctive normal form](https://en.wikipedia.org/wiki/Disjunctive_normal_form):\n", "\n", " E = (¬a ∧ b ∧ c) ∨ (a ∧ ¬b ∧ c) ∨ (a ∧ b ∧ ¬c)\n", "\n", "Here it is in action:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "((((a) (b) c) ((a) (c) b) ((b) (c) a)))\n", " a b c | Value\n", "---------+------\n", " | \n", " () | \n", " () | \n", " () () | ()\n", "() | \n", "() () | ()\n", "() () | ()\n", "() () () | \n" ] } ], "source": [ "e4 = ( a, (b,), (c,))\n", "e6 = ((a,), b, (c,))\n", "e7 = ((a,), (b,), c )\n", "\n", "E2 = or_(e4, e6, e7)\n", "\n", "truth_table(E2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Equivalence\n", "Note that the expression E2 above is equivalent to the ealier expression E1 that has the same truth table, in other words:\n", "\n", " ((((((a) (b)) ((b) (c)) ((c) (a))))) ((((a) (b) (c)))))\n", " \n", "equals\n", "\n", " (((a (b) (c)) ((a) b (c)) ((a) (b) c)))\n", " \n", "We can demonstrate this equivalence by evaluating the expression formed by `eqiv()` from these two.\n", "\n", "For every environment (from the set of possible values for the variables) if both expressions have the same value when evaluated then the `eqiv()` of those expressions will be Mark-valued (true in our chosen context.)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(((((((((a) (b)) ((a) (c)) ((b) (c))))) ((((a) (b) (c)))))) ((((a) (b) c) ((a) (c) b) ((b) (c) a)))) (((((((a) (b)) ((a) (c)) ((b) (c))))) ((((a) (b) (c))))) (((((a) (b) c) ((a) (c) b) ((b) (c) a))))))\n", " a b c | Value\n", "---------+------\n", " | ()\n", " () | ()\n", " () | ()\n", " () () | ()\n", "() | ()\n", "() () | ()\n", "() () | ()\n", "() () () | ()\n" ] } ], "source": [ "truth_table(eqiv(E1, E2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The truth table above shows that the equivalence expression is true (Mark-valued by our current convention) for all possible assignments of Mark/Void to the three variables `a`, `b`, and `c`. This indicates that the expression is a **tautology**." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [Half-Bit Adder](https://en.wikipedia.org/wiki/Adder_%28electronics%29#Half_adder)\n", "\n", "If you have two binary digits (\"bits\") and you are interested in the (binary) sum of these digits you will need two circuits, one for the \"ones place\" and one for the \"twos place\" or \"carry bit\".\n", "\n", "Consider:\n", "\n", " a b | c s\n", " ----+----\n", " 0 0 | 0 0\n", " 0 1 | 0 1\n", " 1 0 | 0 1\n", " 1 1 | 1 0\n", " \n", "Treating each output column ('c' for carry, 's' for sum) as a single expression, it's easy to see that the carry bit is just **AND** and the sum bit is just **XOR** of the two input bits." ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Carry\n", "((a) (b))\n", " a b | Value\n", "------+------\n", " | \n", " () | \n", "() | \n", "() () | ()\n", "\n", "Sum\n", "((((a) b) ((b) a)))\n", " a b | Value\n", "------+------\n", " | \n", " () | ()\n", "() | ()\n", "() () | \n", "\n" ] } ], "source": [ "a, b = 'ab'\n", "\n", "\n", "half_bit_adder = {\n", " 'Sum': xor(a, b),\n", " 'Carry': and_(a, b),\n", "}\n", "\n", "\n", "for name, expr in half_bit_adder.items():\n", " print name\n", " truth_table(expr)\n", " print" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [Full-bit Adder](https://en.wikipedia.org/wiki/Adder_%28electronics%29#Full_adder)\n", "In order to add two multi-bit binary numbers we need adder circuits that are designed to work with _three_ input bits: the two bits to add together and a carry bit from the previous addition:\n", "\n", " a b Cin Sum Cout\n", " 0 0 0 | 0 0\n", " 0 0 1 | 1 0\n", " 0 1 0 | 1 0\n", " 0 1 1 | 0 1\n", " 1 0 0 | 1 0\n", " 1 0 1 | 0 1\n", " 1 1 0 | 0 1\n", " 1 1 1 | 1 1\n", "\n", "Looking back at our table of three-variable expressions:\n", "\n", " ⟶ ( a b c )\n", " () ⟶ ( a b (c))\n", " () ⟶ ( a (b) c )\n", " () () ⟶ ( a (b) (c))\n", " () ⟶ ((a) b c )\n", " () () ⟶ ((a) b (c))\n", " () () ⟶ ((a) (b) c )\n", " () () () ⟶ ((a) (b) (c))\n", " \n", "We can easily determine expressions for sum and carry:\n", "\n", " Sum = (a b (c)) (a (b) c) ((a) b c) ((a) (b) (c))\n", "\n", " Cout = (a (b) (c)) ((a) b (c)) ((a) (b) c) ((a) (b) (c))\n" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "Sum = F(( (a, b, (c,)), (a, (b,), c), ((a,), b, c), ((a,), (b,), (c,)) ),)\n", "Carry = F(( (a, (b,), (c,)), ((a,), b, (c,)), ((a,), (b,), c), ((a,), (b,), (c,)) ),)" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Sum\n", "((((a) (b) (c)) ((a) b c) ((b) a c) ((c) a b)))\n", " a b c | Value\n", "---------+------\n", " | \n", " () | ()\n", " () | ()\n", " () () | \n", "() | ()\n", "() () | \n", "() () | \n", "() () () | ()\n", "\n", "Carry\n", "((((a) (b) (c)) ((a) (b) c) ((a) (c) b) ((b) (c) a)))\n", " a b c | Value\n", "---------+------\n", " | \n", " () | \n", " () | \n", " () () | ()\n", "() | \n", "() () | ()\n", "() () | ()\n", "() () () | ()\n" ] } ], "source": [ "print 'Sum'\n", "truth_table(Sum)\n", "print\n", "print 'Carry'\n", "truth_table(Carry)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's make a `full_bit_adder()` function that can define new expressions in terms of variables (or expressions) passed into it." ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [], "source": [ "def full_bit_adder(a, b, c):\n", " return (\n", " F(( (a, b, (c,)), (a, (b,), c), ((a,), b, c), ((a,), (b,), (c,)) ),),\n", " F(( (a, (b,), (c,)), ((a,), b, (c,)), ((a,), (b,), c), ((a,), (b,), (c,)) ),),\n", " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can chain it to make a set of circuits that define together an eight-bit adder circuit with carry." ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [], "source": [ "sum0, cout = full_bit_adder('a0', 'b0', 'Cin')\n", "sum1, cout = full_bit_adder('a1', 'b1', cout)\n", "sum2, cout = full_bit_adder('a2', 'b2', cout)\n", "sum3, cout = full_bit_adder('a3', 'b3', cout)\n", "sum4, cout = full_bit_adder('a4', 'b4', cout)\n", "sum5, cout = full_bit_adder('a5', 'b5', cout)\n", "sum6, cout = full_bit_adder('a6', 'b6', cout)\n", "sum7, cout = full_bit_adder('a7', 'b7', cout)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Unfortunately, the sizes of the resulting expression explode:" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[63, 327, 1383, 5607, 22503, 90087, 360423, 1441767, 1441773]" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "map(len, map(str, (sum0, sum1, sum2, sum3, sum4, sum5, sum6, sum7, cout)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using the definitions for Sum and Carry\n", "We could also use the definitions from the [Wikipedia article](https://en.wikipedia.org/wiki/Adder_%28electronics%29#Full_adder):\n", "\n", " S = A ⊕ B ⊕ C\n", " Cout = (A ⋅ B) + (Cin ⋅ (A ⊕ B))" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [], "source": [ "def full_bit_adder(a, b, c):\n", " return (\n", " xor(xor(a, b), c),\n", " or_(and_(a, b), and_(c, xor(a, b))),\n", " )" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "sum0, cout = full_bit_adder('a0', 'b0', 'Cin')" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Sum\n", "((((((((a0) b0) ((b0) a0)))) Cin) (((((a0) b0) ((b0) a0))) (Cin))))\n", " Cin a0 b0 | Value\n", "-------------+------\n", " | \n", " () | ()\n", " () | ()\n", " () () | \n", "() | ()\n", "() () | \n", "() () | \n", "() () () | ()\n", "\n", "Carry\n", "((((((((a0) b0) ((b0) a0)))) (Cin)) ((a0) (b0))))\n", " Cin a0 b0 | Value\n", "-------------+------\n", " | \n", " () | \n", " () | \n", " () () | ()\n", "() | \n", "() () | ()\n", "() () | ()\n", "() () () | ()\n" ] } ], "source": [ "print 'Sum'\n", "truth_table(sum0)\n", "print\n", "print 'Carry'\n", "truth_table(cout) " ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "sum1, cout = full_bit_adder('a1', 'b1', cout)\n", "sum2, cout = full_bit_adder('a2', 'b2', cout)\n", "sum3, cout = full_bit_adder('a3', 'b3', cout)\n", "sum4, cout = full_bit_adder('a4', 'b4', cout)\n", "sum5, cout = full_bit_adder('a5', 'b5', cout)\n", "sum6, cout = full_bit_adder('a6', 'b6', cout)\n", "sum7, cout = full_bit_adder('a7', 'b7', cout)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The sizes of these expression are much more tractable:" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[67, 159, 251, 343, 435, 527, 619, 711, 371]" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "map(len, map(str, (sum0, sum1, sum2, sum3, sum4, sum5, sum6, sum7, cout)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Simplifying Expressions\n", "\n", "The `Form` Python datastructure is based on `frozenset` so duplicate terms are automatically removed and order of terms is irrelevant just as we would prefer. But we want to be able to automatically simplify forms beyond just that. Ideally, we would like a function that applies the rules of the calculus automatically:\n", "\n", " A((B)) = AB\n", " A() = ()\n", " A(AB) = A(B)\n", "\n", "I'm going to specify the behaviour of the desired function in a unittest." ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [], "source": [ "import unittest" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Three Easy Cases\n", "Let's deal with three easy cases first: string, the Mark, and the Void. The `simplify()` function should just return them unchanged." ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "...\n", "----------------------------------------------------------------------\n", "Ran 3 tests in 0.004s\n", "\n", "OK\n" ] } ], "source": [ "class UnwrapTest0(unittest.TestCase):\n", "\n", " def testMark(self):\n", " self.assertEqual(Mark, simplify(Mark))\n", " \n", " def testVoid(self):\n", " self.assertEqual(Void, simplify(Void))\n", "\n", " def testLeaf(self):\n", " self.assertEqual('a', simplify('a'))\n", "\n", "\n", "def simplify(form):\n", " # Three easy cases, for strings, Mark, or Void, just return it.\n", " if isinstance(form, basestring) or form in BASE:\n", " return form\n", "\n", "\n", "if __name__ == '__main__':\n", " unittest.main(argv=['ignored', 'UnwrapTest0'], exit=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `(a)`\n", "A single string in a form `(a)` should also be returned unchanged:" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ ".\n", "----------------------------------------------------------------------\n", "Ran 1 test in 0.001s\n", "\n", "OK\n" ] } ], "source": [ "class UnwrapTest1(unittest.TestCase):\n", "\n", " def testNegatedLeaf(self):\n", " a = nor('a')\n", " self.assertEqual(a, simplify(a))\n", "\n", "\n", "def simplify(form):\n", "\n", " # Three easy cases, for strings, Mark, or Void, just return it.\n", " if isinstance(form, basestring) or form in BASE:\n", " return form\n", " \n", " # We know it's a Form and it's not empty (else it would be the Mark and\n", " # returned above.)\n", " \n", " # Let's just recurse.\n", " return Form(simplify(inner) for inner in form)\n", "\n", "\n", "if __name__ == '__main__':\n", " unittest.main(argv=['ignored', 'UnwrapTest1'], exit=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Doubly-Wrapped Forms\n", "So far, so good. But what about `((a))`? This should be returned as just `a`. And `((a b))` should remain `((a b))` because we can't represent just `a b` as a single Python object, so we have to retain the outer pair of containers to hold them without inverting the Mark/Void value (if we just used one container.)" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "..\n", "----------------------------------------------------------------------\n", "Ran 2 tests in 0.002s\n", "\n", "OK\n" ] } ], "source": [ "class UnwrapTest2(unittest.TestCase):\n", "\n", " def testUnwrapLeaf(self):\n", " '''((a)) = a'''\n", " a = or_('a')\n", " self.assertEqual('a', simplify(a))\n", "\n", " def testDoNotUnwrapTwoLeaves(self):\n", " '''((a b)) = ((a b))'''\n", " a = or_('a', 'b')\n", " self.assertEqual(a, simplify(a))\n", "\n", "\n", "def simplify(form):\n", "\n", " # Three easy cases, for strings, Mark, or Void, just return it.\n", " if isinstance(form, basestring) or form in BASE:\n", " return form\n", " \n", " # We know it's a Form and it's not empty (else it would be the Mark and\n", " # returned above.)\n", " \n", " # Let's just recurse.\n", " result = Form(simplify(inner) for inner in form)\n", " \n", " # Check for ((a)) and return just a.\n", " # If there is more than one item in the inner container ((a b..))\n", " # then we must keep the outer containers.\n", " if len(result) == 1:\n", " inner, = result # inner = (a)\n", " if isinstance(inner, Form) and len(inner) == 1:\n", " a, = inner\n", " return a\n", "\n", " return result\n", "\n", "\n", "if __name__ == '__main__':\n", " unittest.main(argv=['ignored', 'UnwrapTest2'], exit=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Does it work for `(((a))) = (a)` and `((((a)))) = a` and so on?" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "..\n", "----------------------------------------------------------------------\n", "Ran 2 tests in 0.003s\n", "\n", "OK\n" ] } ], "source": [ "class UnwrapTest3(unittest.TestCase):\n", "\n", " def testMultiUnwrapLeaf(self):\n", " A = 'a'\n", " B = nor(A)\n", " a = nor(B)\n", " self.assertEqual(A, simplify(a))\n", " a = nor(a)\n", " self.assertEqual(B, simplify(a))\n", " a = nor(a)\n", " self.assertEqual(A, simplify(a))\n", " a = nor(a)\n", " self.assertEqual(B, simplify(a))\n", " a = nor(a)\n", " self.assertEqual(A, simplify(a))\n", " a = nor(a)\n", " self.assertEqual(B, simplify(a))\n", "\n", " def testMultiDoNotUnwrapTwoLeaves(self):\n", " e = F('a', 'b')\n", " f = a = nor(e)\n", " self.assertEqual(f, simplify(a))\n", " a = nor(a)\n", " self.assertEqual(e, simplify(a))\n", " a = nor(a)\n", " self.assertEqual(f, simplify(a))\n", " a = nor(a)\n", " self.assertEqual(e, simplify(a))\n", " a = nor(a)\n", " self.assertEqual(f, simplify(a))\n", " a = nor(a)\n", " self.assertEqual(e, simplify(a))\n", "\n", "# Technically, several of the tests above are redundant,\n", "# I'm not willing to figure out the right point ot stop\n", "# right now, so I just do extra tests.\n", "\n", "if __name__ == '__main__':\n", " unittest.main(argv=['ignored', 'UnwrapTest3'], exit=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Unwrapping Inner Forms\n", "But now let's trick our function, it can't handle `(a ((b c))) = (a b c)` yet. This is going to require an auxiliary helper function that is similar to `simplify()` but that yields terms into an outer context." ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "...\n", "----------------------------------------------------------------------\n", "Ran 3 tests in 0.005s\n", "\n", "OK\n" ] } ], "source": [ "class UnwrapTest4(unittest.TestCase):\n", "\n", " def testMultiUnwrapLeaf(self):\n", " a, b, c = 'abc'\n", " f = F(a,((b, c),))\n", " e = F(a, b, c)\n", " self.assertEqual(e, simplify(f))\n", "\n", " def testMulti_blah_Leaf(self):\n", " a, b, c = 'abc'\n", " f = F(a,(((b, c),),),)\n", " e = F(a, (b, c))\n", " self.assertEqual(e, simplify(f))\n", "\n", " def testMulti_blah_blah_Leaf(self):\n", " a, b, c, d = 'abcd'\n", " f = F(a,((((b, c),), d),))\n", " e = F(a, b, c, d)\n", " self.assertEqual(e, simplify(f))\n", "\n", "\n", "def simplify(form):\n", "\n", " # Three easy cases, for strings, Mark, or Void, just return it.\n", " if isinstance(form, basestring) or form in BASE:\n", " return form\n", "\n", " # We know it's a Form and it's not empty (else it would be the Mark and\n", " # returned above.)\n", " \n", " result = []\n", " for inner in simplify_gen(form): # Use the generator instead of recursing into simplify().\n", " result.append(inner)\n", " result = Form(result)\n", " \n", " # Check for ((a)) and return just a.\n", " # If there is more than one item in the inner container ((a b..))\n", " # then we must keep the outer containers.\n", " if len(result) == 1:\n", " inner, = result # inner = (a)\n", " if isinstance(inner, Form):\n", " if len(inner) == 1:\n", " a, = inner\n", " return a\n", " else:\n", " # len(inner) cannot be 0, because that means form is Void\n", " # and would already have been returned.\n", " assert len(inner) > 1, repr(inner)\n", " \n", " # What to do here?\n", " # We cannot yield the items in inner into the containing context\n", " # because we don't have it (or even know if it exists.)\n", " # Therefore we need a different simplify() generator function that yields\n", " # the simplified contents of a form, and we have to call that instead\n", " # of recurring on simplify() above.\n", " pass\n", " \n", "\n", " return result\n", "\n", "\n", "def simplify_gen(form):\n", " \n", " for inner in form:\n", " \n", " inner = simplify(inner)\n", " # Now inner is simplified, except for ((a b...)) which simplify() can't handle.\n", "\n", " # Three easy cases, strings, Mark, or Void.\n", " if isinstance(inner, basestring):\n", " yield inner\n", " continue\n", "\n", " if inner == Mark:\n", " yield inner\n", " assert False # The simplify() function will not keep iterating after this.\n", " return # Partial implementation of ()A = ().\n", " \n", " if inner == Void:\n", " continue # Omit Void. Implementation of (()) = .\n", " \n", " # We know it's a Form and it's not empty (else it would be the Mark and\n", " # yielded above.)\n", " \n", " # Check for ((...)) and return just ... .\n", " if len(inner) > 1: # (foo bar)\n", " yield inner\n", " continue\n", "\n", " assert len(inner) == 1, repr(inner) # Just in case...\n", "\n", " inner_inner, = inner\n", " if isinstance(inner_inner, Form): # inner_inner = (...)\n", " for inner_inner_inner in inner_inner:\n", " yield inner_inner_inner\n", " continue\n", "\n", " #else: # inner_inner = foo ; inner = (foo)\n", " \n", " yield inner\n", "\n", " \n", "if __name__ == '__main__':\n", " unittest.main(argv=['ignored', 'UnwrapTest4'], exit=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Marks\n", "If the Mark occurs in a sub-form it should _Occlude_ all sibling sub-forms, rendering its container form Void." ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "...\n", "----------------------------------------------------------------------\n", "Ran 3 tests in 0.004s\n", "\n", "OK\n" ] } ], "source": [ "class MarkTest0(unittest.TestCase):\n", "\n", " def testMarkOccludes0(self):\n", " a, b, c = 'abc'\n", " f = F(a, (), b, c)\n", " self.assertEqual(Void, simplify(f))\n", "\n", " def testMarkOccludes1(self):\n", " a, b, c = 'abc'\n", " f = F(a, (b, c, ()))\n", " e = F(a)\n", " self.assertEqual(e, simplify(f))\n", "\n", " def testMarkOccludes2(self):\n", " a, b, c = 'abc'\n", " f = F(a, (b, ((), c)))\n", " e = F(a, (b,))\n", " self.assertEqual(e, simplify(f))\n", "\n", "\n", "def simplify(form):\n", "\n", " # Three easy cases, for strings, Mark, or Void, just return it.\n", " if isinstance(form, basestring) or form in BASE:\n", " return form\n", "\n", " # We know it's a Form and it's not empty (else it would be the Mark and\n", " # returned above.)\n", "\n", " result = []\n", " for inner in simplify_gen(form):\n", " if inner == Mark:\n", " return Void # Discard any other inner forms, form is Void.\n", " result.append(inner)\n", " result = Form(result)\n", "\n", " # Check for ((a)) and return just a.\n", " # If there is more than one item in the inner container ((a b..))\n", " # then we must keep the outer containers.\n", " if len(result) == 1:\n", " inner, = result # inner = (a)\n", " if isinstance(inner, Form):\n", " if len(inner) == 1:\n", " a, = inner\n", " return a \n", "\n", " return result\n", "\n", "\n", "if __name__ == '__main__':\n", " unittest.main(argv=['ignored', 'MarkTest0'], exit=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Pervade\n", "So we have `(()) = --` and `()A = ()` what about `A(AB) = A(B)`?" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "...\n", "----------------------------------------------------------------------\n", "Ran 3 tests in 0.004s\n", "\n", "OK\n" ] } ], "source": [ "class PervadeTest0(unittest.TestCase):\n", "\n", " def testPervade0(self):\n", " a = 'a'\n", " f = F(a, (a,))\n", " self.assertEqual(Void, simplify(f))\n", "\n", " def testPervade1(self):\n", " a = 'a'\n", " f = F(((a,),), (a,))\n", " self.assertEqual(Void, simplify(f))\n", " \n", " def testPervade2(self):\n", " a = 'a'\n", " b = 'b'\n", " f = F(a, (b, (a,)))\n", " e = F(a)\n", " self.assertEqual(e, simplify(f))\n", "\n", "\n", "def simplify(form, exclude=None):\n", "\n", " # Three easy cases, for strings, Mark, or Void, just return it.\n", " if isinstance(form, basestring) or form in BASE:\n", " return form\n", "\n", " # We know it's a Form and it's not empty (else it would be the Mark and\n", " # returned above.)\n", "\n", " if exclude is None:\n", " exclude = set()\n", "\n", " new_stuff = form - exclude \n", " exclude = exclude | new_stuff\n", "\n", " result = []\n", " for inner in simplify_gen(new_stuff, exclude):\n", " if inner == Mark:\n", " return Void # Discard any other inner forms, form is Void.\n", " result.append(inner)\n", " result = Form(result)\n", "\n", " # Check for ((a)) and return just a.\n", " # If there is more than one item in the inner container ((a b..))\n", " # then we must keep the outer containers.\n", " if len(result) == 1:\n", " inner, = result # inner = (a)\n", " if isinstance(inner, Form):\n", " if len(inner) == 1:\n", " a, = inner\n", " return a \n", "\n", " return result\n", "\n", "\n", "def simplify_gen(form, exclude):\n", " \n", " for inner in form:\n", " \n", " inner = simplify(inner, exclude)\n", " # Now inner is simplified, except for ((a b...)) which simplify() can't handle.\n", "\n", " # Three easy cases, strings, Mark, or Void.\n", " if isinstance(inner, basestring):\n", " yield inner\n", " continue\n", "\n", " if inner == Mark:\n", " yield inner\n", " assert False # The simplify() function will not keep iterating after this.\n", " return # Partial implementation of ()A = ().\n", " \n", " if inner == Void:\n", " continue # Omit Void. Implementation of (()) = .\n", " \n", " # We know it's a Form and it's not empty (else it would be the Mark and\n", " # yielded above.)\n", " \n", " # Check for ((...)) and return just ... .\n", " if len(inner) > 1: # (foo bar)\n", " yield inner\n", " continue\n", "\n", " assert len(inner) == 1, repr(inner) # Just in case...\n", "\n", " inner_inner, = inner\n", " if isinstance(inner_inner, Form): # inner_inner = (...)\n", " for inner_inner_inner in inner_inner:\n", " yield inner_inner_inner\n", " continue\n", "\n", " #else: # inner_inner = foo ; inner = (foo)\n", " \n", " yield inner\n", "\n", "\n", "if __name__ == '__main__':\n", " unittest.main(argv=['ignored', 'PervadeTest0'], exit=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "TODO set up [Hypothesis](http://hypothesis.works/) to generate test cases..." ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ ".................\n", "----------------------------------------------------------------------\n", "Ran 17 tests in 0.022s\n", "\n", "OK\n" ] } ], "source": [ "# Run ALL the tests!\n", "\n", "if __name__ == '__main__':\n", " unittest.main(argv=['ignored'], exit=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [Using \"Each-Way\" to Simplify Forms](http://www.markability.net/case_analysis.htm)\n", "\n", "GSB called this \"Each-Way\":\n", "\n", " a = ((a b) (a (b)))" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(((b) a) (a b))\n", " a b | Value\n", "------+------\n", " | \n", " () | \n", "() | ()\n", "() () | ()\n" ] } ], "source": [ "truth_table(F((a, b), (a, (b,))))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The form says, \"if b then a else a\". I'll come back to the interpretation of \"Each-Way\" as an `if-then-else` statement later.\n", "\n", "The thing to note here is that the value for `a` can be a whole expression which appears twice in the new form: once next to `b` and once next to `(b)`.\n", "\n", "In the first case we can remove any occurances of `b` from the `a` next to it\n", "\n", " b (...(b c (d ...)))\n", " b (...( c (d ...)))\n", "\n", "and in the second case we can change any occurances of `b` to the Mark.\n", "\n", " (b)(...(b c (d ...)))\n", " (b)((b)(b c (d ...)))\n", " (b)(...(b (b) c (d ...)))\n", " (b)(...(b ( ) c (d ...)))\n", " (b)(...( ( ) ))\n", " (b)(... )\n", "\n", "We can send `(b)` into the form until it reaches and `b`, at which point `b(b)` becomes `()` and sweeps out any siblings rendering its containing form Void.\n", "\n", "For the first case we can use `simplify()` and pass in `b` as a member of the `exclude` set." ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(((c) b) a)" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = F(a, (b, (c,)))\n", "A" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(a c)" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simplify(A, {b})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `with_mark`\n", "In the second case `(b)...b... = (b)...()...` we can modify the `simplify()` function to accept a name that it should treat as Mark-valued." ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ ".\n", "----------------------------------------------------------------------\n", "Ran 1 test in 0.001s\n", "\n", "OK\n" ] } ], "source": [ "class MarkitTest0(unittest.TestCase):\n", "\n", " def testMarkit0(self):\n", " a, b, c = 'abc'\n", " f = F(a, (b, (c,)))\n", " e = F(a)\n", " self.assertEqual(e, simplify(f, with_mark=b))\n", "\n", "\n", "def simplify(form, exclude=None, with_mark=None):\n", "\n", " # Three easy cases, for strings, Mark, or Void, just return it.\n", " if isinstance(form, basestring) or form in BASE:\n", " return form\n", "\n", " # We know it's a Form and it's not empty (else it would be the Mark and\n", " # returned above.)\n", "\n", " if exclude is None:\n", " exclude = set()\n", "\n", " new_stuff = form - exclude \n", " exclude = exclude | new_stuff\n", "\n", " result = []\n", " for inner in simplify_gen(new_stuff, exclude, with_mark):\n", " if inner == Mark or inner == with_mark:\n", " return Void # Discard any other inner forms, form is Void.\n", " result.append(inner)\n", " result = Form(result)\n", "\n", " # Check for ((a)) and return just a.\n", " # If there is more than one item in the inner container ((a b..))\n", " # then we must keep the outer containers.\n", " if len(result) == 1:\n", " inner, = result # inner = (a)\n", " if isinstance(inner, Form):\n", " if len(inner) == 1:\n", " a, = inner\n", " return a \n", "\n", " return result\n", "\n", "\n", "def simplify_gen(form, exclude, with_mark):\n", " \n", " for inner in form:\n", " \n", " inner = simplify(inner, exclude, with_mark)\n", " # Now inner is simplified, except for ((a b...)) which simplify() can't handle.\n", "\n", " # Three easy cases, strings, Mark, or Void.\n", " if isinstance(inner, basestring):\n", " yield inner\n", " continue\n", "\n", " if inner == Mark or inner == with_mark:\n", " yield Mark\n", " assert False # The simplify() function will not keep iterating after this.\n", " return # Partial implementation of ()A = ().\n", " \n", " if inner == Void:\n", " continue # Omit Void. Implementation of (()) = .\n", " \n", " # We know it's a Form and it's not empty (else it would be the Mark and\n", " # yielded above.)\n", " \n", " # Check for ((...)) and return just ... .\n", " if len(inner) > 1: # (foo bar)\n", " yield inner\n", " continue\n", "\n", " assert len(inner) == 1, repr(inner) # Just in case...\n", "\n", " inner_inner, = inner\n", " if isinstance(inner_inner, Form): # inner_inner = (...)\n", " for inner_inner_inner in inner_inner:\n", " if inner_inner_inner == with_mark:\n", " yield Mark\n", " assert False # The simplify() function will not keep iterating after this.\n", " return # Never reached, could delete this line.\n", " yield inner_inner_inner\n", " continue\n", "\n", " #else: # inner_inner = foo ; inner = (foo)\n", " \n", " yield inner\n", "\n", "\n", "if __name__ == '__main__':\n", " unittest.main(argv=['ignored', 'MarkitTest0'], exit=False)" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(a)" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simplify(A, with_mark=b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can create a new form that is equivalent to `A`." ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(((c) b) a) = (((a c) b) ((a) (b)))\n" ] } ], "source": [ "def each_way(form, name):\n", " return simplify(F(\n", " ( name , form),\n", " ((name,), simplify(form, with_mark=name)),\n", " ))\n", "\n", "Ab = each_way(A, b)\n", "\n", "print A, '=', Ab" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this particular case the original form `A` was so simple that the new version `Ab` is actually a bit larger. With a large expression to start with the form after simplification would (usually) be smaller." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Simplifying the Full-Bit Adder\n", "Recall our original expressions for the sum and carry bits of a full-bit adder circuit, derived from the truth tables:" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [], "source": [ "Sum = F(( (a, b, (c,)), (a, (b,), c), ((a,), b, c), ((a,), (b,), (c,)) ),)\n", "Carry = F(( (a, (b,), (c,)), ((a,), b, (c,)), ((a,), (b,), c), ((a,), (b,), (c,)) ),)" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((((a) (b) (c)) ((a) b c) ((b) a c) ((c) a b)))" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Sum" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((((a) (b) (c)) ((a) (b) c) ((a) (c) b) ((b) (c) a)))" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Carry" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And the expressions derived from the definitions on Wikipedia:" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [], "source": [ "Sum, Carry = full_bit_adder(a, b, c)" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((((((((a) b) ((b) a)))) c) (((((a) b) ((b) a))) (c))))" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Sum" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((((((((a) b) ((b) a)))) (c)) ((a) (b))))" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Carry" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use the `each_way()` function to look for simpler equivalent forms by, for example, iterating though the names and trying it with each. Try the following cells with both versions of the `Sum` and `Carry` above." ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "((((((((a) b) ((b) a)))) c) (((((a) b) ((b) a))) (c))))\n", "((((b) (c)) (a) (b c)) (((b) c) ((c) b) a))\n", "(((((a) (c)) (a c)) b) ((((a) c) ((c) a)) (b)))\n", "(((((a) (b)) (a b)) c) ((((a) b) ((b) a)) (c)))\n", "(((((b) (c)) (b c)) a) ((((b) c) ((c) b)) (a)))\n", "(((((a) (c)) (a c)) b) ((((a) c) ((c) a)) (b)))\n", "(((((a) (b)) (a b)) c) ((((a) b) ((b) a)) (c)))\n" ] } ], "source": [ "print Sum\n", "for name in (a, b, c, a, b, c):\n", " Sum = each_way(Sum, name)\n", " print Sum" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "((((((((a) b) ((b) a)))) (c)) ((a) (b))))\n", "((((b) (c)) a) ((a) b c))\n", "(((((a) c) (a)) b) ((b) a c))\n", "(((((b) a) (b)) c) ((c) a b))\n", "(((((c) b) (c)) a) ((a) b c))\n", "(((((a) c) (a)) b) ((b) a c))\n", "(((((b) a) (b)) c) ((c) a b))\n" ] } ], "source": [ "print Carry\n", "for name in (a, b, c, a, b, c):\n", " Carry = each_way(Carry, name)\n", " print Carry" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's redefine the `full_bit_adder()` function with the smallest version of each above." ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [], "source": [ "def full_bit_adder(a, b, c):\n", " '''From the truth table.'''\n", " return (\n", " F(( (a, b, (c,)), (a, (b,), c), ((a,), b, c), ((a,), (b,), (c,)) ),),\n", " F(( (a, (b,), (c,)), ((a,), b, (c,)), ((a,), (b,), c), ((a,), (b,), (c,)) ),),\n", " )\n", "# Sizes: [63, 327, 1383, 5607, 22503, 90087, 360423, 1441767, 1441773]" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [], "source": [ "def full_bit_adder(a, b, c):\n", " '''Simplest forms from above.'''\n", " return (\n", " F( (((b,), (c,)), (a,), (b, c)), (((b,), c), ((c,), b), a) ),\n", " F( (((a,), (c,)), b), ((b,), a, c) ),\n", " )\n", "# Sizes: [57, 177, 417, 897, 1857, 3777, 7617, 15297, 7653]" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [], "source": [ "def full_bit_adder(a, b, c):\n", " '''Based on the definitions from Wikipedia.'''\n", " return (\n", " xor(xor(a, b), c), # ((((((((a) b) ((b) a)))) c) (((((a) b) ((b) a))) (c))))\n", " or_(and_(a, b), and_(c, xor(a, b))), # ((((((((a) b) ((b) a)))) (c)) ((a) (b))))\n", " )\n", "# Sizes: [67, 159, 251, 343, 435, 527, 619, 711, 371]" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [], "source": [ "def full_bit_adder(a, b, c):\n", " '''Based on the definitions from Wikipedia.'''\n", " return (\n", " simplify(xor(xor(a, b), c)),\n", " simplify(or_(and_(a, b), and_(c, xor(a, b)))),\n", " )\n", "# Sizes: [59, 135, 211, 287, 363, 439, 515, 591, 311]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this case, the version from the definitions does much better than the other two." ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "((((((a) b) ((b) a)) c) (((a) b) ((b) a) (c))))\n", " a b c | Value\n", "---------+------\n", " | \n", " () | ()\n", " () | ()\n", " () () | \n", "() | ()\n", "() () | \n", "() () | \n", "() () () | ()\n", "\n", "((((((a) b) ((b) a)) (c)) ((a) (b))))\n", " a b c | Value\n", "---------+------\n", " | \n", " () | \n", " () | \n", " () () | ()\n", "() | \n", "() () | ()\n", "() () | ()\n", "() () () | ()\n", "\n", "[59, 135, 211, 287, 363, 439, 515, 591, 311]\n" ] } ], "source": [ "Sum, Carry = full_bit_adder(a, b, c)\n", "\n", "truth_table(Sum)\n", "print\n", "truth_table(Carry)\n", "print\n", "\n", "sum0, cout = full_bit_adder('a0', 'b0', 'Cin')\n", "sum1, cout = full_bit_adder('a1', 'b1', cout)\n", "sum2, cout = full_bit_adder('a2', 'b2', cout)\n", "sum3, cout = full_bit_adder('a3', 'b3', cout)\n", "sum4, cout = full_bit_adder('a4', 'b4', cout)\n", "sum5, cout = full_bit_adder('a5', 'b5', cout)\n", "sum6, cout = full_bit_adder('a6', 'b6', cout)\n", "sum7, cout = full_bit_adder('a7', 'b7', cout)\n", "\n", "print map(len, map(str, (sum0, sum1, sum2, sum3, sum4, sum5, sum6, sum7, cout)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# [Davis–Putnam–Logemann–Loveland (DPLL) algorithm](https://en.wikipedia.org/wiki/Davis%E2%80%93Putnam%E2%80%93Logemann%E2%80%93Loveland_algorithm) SAT Solver\n", "\n", "This is something of an Interlude, we aren't going to use it below, but it's too cool to omit mention.\n", "\n", "We can use the `simplify()` function to create a more efficient SAT solver along the lines of the DPLL algorithm.\n", "\n", "It works by selecting a name from the form, and simplifying the form with that name first as `Void` then as `Mark`, then recursing with the new form and the next name. If the resulting simplified form becomes the `Mark` then our choices (of assigning `Void` or `Mark` to the names selected so far) constitute a \"solution\" to the original form. That is, if we `reify()` the form with the *environment* returned by the `dpll()` function the result will be Mark-valued." ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [], "source": [ "def dpll(E, partial=None, unit=True):\n", " if partial is None:\n", " partial = {}\n", " else:\n", " partial = partial.copy() # so we can backtrack later..\n", "\n", " if isinstance(E, basestring):\n", " partial[E] = Mark\n", " return partial\n", "\n", " if unit:\n", " E = assign_unit_clauses(E, partial)\n", "\n", " if not E:\n", " return partial\n", "\n", " if Mark in E:\n", " return\n", "\n", " v = next_symbol_of(E)\n", "\n", " partial[v] = Void\n", "\n", " res = dpll(simplify(E, {v}), partial, unit)\n", " if res is not None: \n", " return res\n", "\n", " partial[v] = Mark\n", "\n", " return dpll(simplify(E, with_mark=v), partial, unit)\n", "\n", "\n", "def assign_unit_clauses(E, partial):\n", " '''\n", " Find and assign values to an \"unit clauses\" in the form, simplifying as you go.\n", " A unit clause is a bare name or a negated name: a or (a), for these clauses we\n", " can set them to Void or Mark, respectively, to contibute to making their containing\n", " Form the Mark.\n", " '''\n", " on, off, E = find_units(E)\n", " while on or off:\n", " while on:\n", " if on & off: return Void\n", " term = first_of(on)\n", " partial[term] = Mark\n", " ON, OFF, E = find_units(simplify(E, with_mark=term))\n", " on |= ON\n", " on.remove(term)\n", " off |= OFF\n", " while off:\n", " if on & off: return Void\n", " term = first_of(off)\n", " partial[term] = Void\n", " ON, OFF, E = find_units(simplify(E, {term}))\n", " off |= OFF\n", " off.remove(term)\n", " on |= ON\n", " return E\n", "\n", "\n", "def next_symbol_of(E):\n", " if isinstance(E, basestring):\n", " return E\n", " for it in E:\n", " return next_symbol_of(it)\n", " raise Exception(\"no more symbols\")\n", "\n", "\n", "def find_units(E):\n", " '''\n", " Return two sets and a possibly-reduced E. The literals in the first\n", " set must be Void and those in the second must be set Mark to have the\n", " entire expression become Void.\n", " '''\n", " on, off, poly = set(), set(), set()\n", " for clause in E:\n", " if isinstance(clause, basestring):\n", " off.add(clause)\n", " continue\n", " if len(clause) != 1:\n", " poly.add(clause)\n", " continue\n", " (n,) = clause # Unwrap one layer of containment.\n", " if isinstance(n, basestring):\n", " on.add(n)\n", " else:\n", " poly.add(clause)\n", " return on, off, Form(poly)\n", "\n", "\n", "# Return any item from a form.\n", "first_of = lambda form: next(iter(form))" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(((c) b) a)\n", " a b c | Value\n", "---------+------\n", " | ()\n", " () | \n", " () | ()\n", " () () | ()\n", "() | \n", "() () | \n", "() () | \n", "() () () | \n", "\n", "A solution: {'a': (()), 'c': (()), 'b': (())}\n", "\n", "Reifies to ((((())) (())) (())) ⟶ ()\n" ] } ], "source": [ "A = F(a, (b, (c,)))\n", "truth_table(A)\n", "solution = dpll(A)\n", "arith = reify(A, solution)\n", "print\n", "print 'A solution:', solution\n", "print\n", "print 'Reifies to', arith, u'⟶', value_of(arith)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `dpll_iter()`\n", "We can write a generator version of the function that keeps looking for solutions after the first." ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [], "source": [ "def dpll_iter(E, partial=None, unit=True):\n", " if partial is None:\n", " partial = {}\n", " else:\n", " partial = partial.copy() # so we can backtrack later..\n", "\n", " if isinstance(E, basestring):\n", " partial[E] = Mark\n", " yield partial\n", " return\n", "\n", " if unit:\n", " E = assign_unit_clauses(E, partial)\n", "\n", " if not E:\n", " yield partial\n", " return\n", "\n", " if Mark in E:\n", " return\n", "\n", " v = next_symbol_of(E)\n", "\n", " partial[v] = Void\n", "\n", " for res in dpll_iter(simplify(E, {v}), partial, unit):\n", " yield res\n", "\n", " partial[v] = Mark\n", "\n", " for res in dpll_iter(simplify(E, with_mark=v), partial, unit):\n", " yield res" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'a': (()), 'c': (()), 'b': (())}\n", "{'a': (()), 'b': ()}\n" ] } ], "source": [ "for solution in dpll_iter(A):\n", " print (solution)" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [], "source": [ "Sum, Carry = full_bit_adder(a, b, c)" ] }, { "cell_type": "code", "execution_count": 80, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'a': (()), 'c': (), 'b': (())} (((((((())) (()))) ()) ((((())) (())) (())))) = ()\n", "{'a': (()), 'c': (()), 'b': ()} (((((((())) ()) ((()))) (())) ((((())) ()) ((()))))) = ()\n", "{'a': (), 'c': (()), 'b': (())} (((((((())) ()) ((()))) (())) ((((())) ()) ((()))))) = ()\n", "{'a': (), 'c': (), 'b': ()} ((((((()) ())) ()) (((()) ()) (())))) = ()\n" ] } ], "source": [ "for solution in dpll_iter(Sum, unit=False):\n", " r = reify(Sum, solution)\n", " print (solution), r, '=', simplify(r)" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'a': (()), 'c': (), 'b': ()} (((((((())) ()) ((()))) (())) (((())) (())))) = ()\n", "{'a': (), 'c': (), 'b': (())} (((((((())) ()) ((()))) (())) (((())) (())))) = ()\n", "{'a': (), 'b': ()} ((((((()) ())) (c)) ((())))) = ()\n" ] } ], "source": [ "for solution in dpll_iter(Carry, unit=False):\n", " r = reify(Carry, solution)\n", " print (solution), r, '=', simplify(r)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Notice that the reified form still has `c` in it but that doesn't prevent the `simplify()` function from reducing the form to the Mark. This should be the case for all solutions generated by the `dpll_iter()` function." ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "() () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () (((a5) a5)) (((a5) a5)) () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () (((a5) a5)) (((a5) a5)) () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () (((a5) a5)) (((a5) a5)) () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () () (((a5) a5)) (((a5) a5)) () ()\n" ] } ], "source": [ "for solution in dpll_iter(cout):\n", " print simplify(reify(cout, solution))," ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Interesting! Some solutions do not `simplify()` completely in one go. The form `(((a5) a5))` is Mark-valued:\n", "\n", " (((a5) a5))\n", " ((( ) a5))\n", " ((( ) ))\n", " ( )\n", " ()\n" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(((a) a))\n", "()\n" ] } ], "source": [ "E = F(((a,), a))\n", "print E\n", "print simplify(E)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Something to keep in mind." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Now back to Circuits\n", "\n", "## Using the Adder Circuits to Add\n", "\n", "In order to keep things tractable I'm going to use just four bits rather than eight." ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [], "source": [ "sum0, cout = full_bit_adder('a0', 'b0', 'Cin')\n", "sum1, cout = full_bit_adder('a1', 'b1', cout)\n", "sum2, cout = full_bit_adder('a2', 'b2', cout)\n", "sum3, cout = full_bit_adder('a3', 'b3', cout)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Put the circuit expressions into a handy dictionary, and we are ready to add some numbers." ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [], "source": [ "CIRCUITS = {\n", " 'sum0': sum0,\n", " 'sum1': sum1,\n", " 'sum2': sum2,\n", " 'sum3': sum3,\n", " 'cout': cout,\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A bunch of crufty junk to print out a nice truth table with the columns arranged to make it (relatively) easy to see the addition." ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Ci|a3 a2 a1 a0|b3 b2 b1 b0 | Co s3 s2 s1 s0\n", "-- -- -- -- -- -- -- -- -- | -- -- -- -- --\n", "-- -- -- -- -- -- -- -- () | -- -- -- -- ()\n", "-- -- -- -- -- -- -- () -- | -- -- -- () --\n", "-- -- -- -- -- -- -- () () | -- -- -- () ()\n", "-- -- -- -- -- -- () -- -- | -- -- () -- --\n", "-- -- -- -- -- -- () -- () | -- -- () -- ()\n", "-- -- -- -- -- -- () () -- | -- -- () () --\n", "-- -- -- -- -- -- () () () | -- -- () () ()\n", "-- -- -- -- -- () -- -- -- | -- () -- -- --\n", "-- -- -- -- -- () -- -- () | -- () -- -- ()\n", "-- -- -- -- -- () -- () -- | -- () -- () --\n", "-- -- -- -- -- () -- () () | -- () -- () ()\n", "-- -- -- -- -- () () -- -- | -- () () -- --\n", "-- -- -- -- -- () () -- () | -- () () -- ()\n", "-- -- -- -- -- () () () -- | -- () () () --\n", "-- -- -- -- -- () () () () | -- () () () ()\n", "-- -- -- -- () -- -- -- -- | -- -- -- -- ()\n", "-- -- -- -- () -- -- -- () | -- -- -- () --\n", "-- -- -- -- () -- -- () -- | -- -- -- () ()\n", "-- -- -- -- () -- -- () () | -- -- () -- --\n", "-- -- -- -- () -- () -- -- | -- -- () -- ()\n", "-- -- -- -- () -- () -- () | -- -- () () --\n", "-- -- -- -- () -- () () -- | -- -- () () ()\n", "-- -- -- -- () -- () () () | -- () -- -- --\n", "-- -- -- -- () () -- -- -- | -- () -- -- ()\n", "-- -- -- -- () () -- -- () | -- () -- () --\n", "-- -- -- -- () () -- () -- | -- () -- () ()\n", "-- -- -- -- () () -- () () | -- () () -- --\n", "-- -- -- -- () () () -- -- | -- () () -- ()\n", "-- -- -- -- () () () -- () | -- () () () --\n", "-- -- -- -- () () () () -- | -- () () () ()\n", "-- -- -- -- () () () () () | () -- -- -- --\n", "-- -- -- () -- -- -- -- -- | -- -- -- () --\n", "-- -- -- () -- -- -- -- () | -- -- -- () ()\n", "-- -- -- () -- -- -- () -- | -- -- () -- --\n", "-- -- -- () -- -- -- () () | -- -- () -- ()\n", "-- -- -- () -- -- () -- -- | -- -- () () --\n", "-- -- -- () -- -- () -- () | -- -- () () ()\n", "-- -- -- () -- -- () () -- | -- () -- -- --\n", "-- -- -- () -- -- () () () | -- () -- -- ()\n", "-- -- -- () -- () -- -- -- | -- () -- () --\n", "-- -- -- () -- () -- -- () | -- () -- () ()\n", "-- -- -- () -- () -- () -- | -- () () -- --\n", "-- -- -- () -- () -- () () | -- () () -- ()\n", "-- -- -- () -- () () -- -- | -- () () () --\n", "-- -- -- () -- () () -- () | -- () () () ()\n", "-- -- -- () -- () () () -- | () -- -- -- --\n", "-- -- -- () -- () () () () | () -- -- -- ()\n", "-- -- -- () () -- -- -- -- | -- -- -- () ()\n", "-- -- -- () () -- -- -- () | -- -- () -- --\n", "-- -- -- () () -- -- () -- | -- -- () -- ()\n", "-- -- -- () () -- -- () () | -- -- () () --\n", "-- -- -- () () -- () -- -- | -- -- () () ()\n", "-- -- -- () () -- () -- () | -- () -- -- --\n", "-- -- -- () () -- () () -- | -- () -- -- ()\n", "-- -- -- () () -- () () () | -- () -- () --\n", "-- -- -- () () () -- -- -- | -- () -- () ()\n", "-- -- -- () () () -- -- () | -- () () -- --\n", "-- -- -- () () () -- () -- | -- () () -- ()\n", "-- -- -- () () () -- () () | -- () () () --\n", "-- -- -- () () () () -- -- | -- () () () ()\n", "-- -- -- () () () () -- () | () -- -- -- --\n", "-- -- -- () () () () () -- | () -- -- -- ()\n", "-- -- -- () () () () () () | () -- -- () --\n", "-- -- () -- -- -- -- -- -- | -- -- () -- --\n", "-- -- () -- -- -- -- -- () | -- -- () -- ()\n", "-- -- () -- -- -- -- () -- | -- -- () () --\n", "-- -- () -- -- -- -- () () | -- -- () () ()\n", "-- -- () -- -- -- () -- -- | -- () -- -- --\n", "-- -- () -- -- -- () -- () | -- () -- -- ()\n", "-- -- () -- -- -- () () -- | -- () -- () --\n", "-- -- () -- -- -- () () () | -- () -- () ()\n", "-- -- () -- -- () -- -- -- | -- () () -- --\n", "-- -- () -- -- () -- -- () | -- () () -- ()\n", "-- -- () -- -- () -- () -- | -- () () () --\n", "-- -- () -- -- () -- () () | -- () () () ()\n", "-- -- () -- -- () () -- -- | () -- -- -- --\n", "-- -- () -- -- () () -- () | () -- -- -- ()\n", "-- -- () -- -- () () () -- | () -- -- () --\n", "-- -- () -- -- () () () () | () -- -- () ()\n", "-- -- () -- () -- -- -- -- | -- -- () -- ()\n", "-- -- () -- () -- -- -- () | -- -- () () --\n", "-- -- () -- () -- -- () -- | -- -- () () ()\n", "-- -- () -- () -- -- () () | -- () -- -- --\n", "-- -- () -- () -- () -- -- | -- () -- -- ()\n", "-- -- () -- () -- () -- () | -- () -- () --\n", "-- -- () -- () -- () () -- | -- () -- () ()\n", "-- -- () -- () -- () () () | -- () () -- --\n", "-- -- () -- () () -- -- -- | -- () () -- ()\n", "-- -- () -- () () -- -- () | -- () () () --\n", "-- -- () -- () () -- () -- | -- () () () ()\n", "-- -- () -- () () -- () () | () -- -- -- --\n", "-- -- () -- () () () -- -- | () -- -- -- ()\n", "-- -- () -- () () () -- () | () -- -- () --\n", "-- -- () -- () () () () -- | () -- -- () ()\n", "-- -- () -- () () () () () | () -- () -- --\n", "-- -- () () -- -- -- -- -- | -- -- () () --\n", "-- -- () () -- -- -- -- () | -- -- () () ()\n", "-- -- () () -- -- -- () -- | -- () -- -- --\n", "-- -- () () -- -- -- () () | -- () -- -- ()\n", "-- -- () () -- -- () -- -- | -- () -- () --\n", "-- -- () () -- -- () -- () | -- () -- () ()\n", "-- -- () () -- -- () () -- | -- () () -- --\n", "-- -- () () -- -- () () () | -- () () -- ()\n", "-- -- () () -- () -- -- -- | -- () () () --\n", "-- -- () () -- () -- -- () | -- () () () ()\n", "-- -- () () -- () -- () -- | () -- -- -- --\n", "-- -- () () -- () -- () () | () -- -- -- ()\n", "-- -- () () -- () () -- -- | () -- -- () --\n", "-- -- () () -- () () -- () | () -- -- () ()\n", "-- -- () () -- () () () -- | () -- () -- --\n", "-- -- () () -- () () () () | () -- () -- ()\n", "-- -- () () () -- -- -- -- | -- -- () () ()\n", "-- -- () () () -- -- -- () | -- () -- -- --\n", "-- -- () () () -- -- () -- | -- () -- -- ()\n", "-- -- () () () -- -- () () | -- () -- () --\n", "-- -- () () () -- () -- -- | -- () -- () ()\n", "-- -- () () () -- () -- () | -- () () -- --\n", "-- -- () () () -- () () -- | -- () () -- ()\n", "-- -- () () () -- () () () | -- () () () --\n", "-- -- () () () () -- -- -- | -- () () () ()\n", "-- -- () () () () -- -- () | () -- -- -- --\n", "-- -- () () () () -- () -- | () -- -- -- ()\n", "-- -- () () () () -- () () | () -- -- () --\n", "-- -- () () () () () -- -- | () -- -- () ()\n", "-- -- () () () () () -- () | () -- () -- --\n", "-- -- () () () () () () -- | () -- () -- ()\n", "-- -- () () () () () () () | () -- () () --\n", "-- () -- -- -- -- -- -- -- | -- () -- -- --\n", "-- () -- -- -- -- -- -- () | -- () -- -- ()\n", "-- () -- -- -- -- -- () -- | -- () -- () --\n", "-- () -- -- -- -- -- () () | -- () -- () ()\n", "-- () -- -- -- -- () -- -- | -- () () -- --\n", "-- () -- -- -- -- () -- () | -- () () -- ()\n", "-- () -- -- -- -- () () -- | -- () () () --\n", "-- () -- -- -- -- () () () | -- () () () ()\n", "-- () -- -- -- () -- -- -- | () -- -- -- --\n", "-- () -- -- -- () -- -- () | () -- -- -- ()\n", "-- () -- -- -- () -- () -- | () -- -- () --\n", "-- () -- -- -- () -- () () | () -- -- () ()\n", "-- () -- -- -- () () -- -- | () -- () -- --\n", "-- () -- -- -- () () -- () | () -- () -- ()\n", "-- () -- -- -- () () () -- | () -- () () --\n", "-- () -- -- -- () () () () | () -- () () ()\n", "-- () -- -- () -- -- -- -- | -- () -- -- ()\n", "-- () -- -- () -- -- -- () | -- () -- () --\n", "-- () -- -- () -- -- () -- | -- () -- () ()\n", "-- () -- -- () -- -- () () | -- () () -- --\n", "-- () -- -- () -- () -- -- | -- () () -- ()\n", "-- () -- -- () -- () -- () | -- () () () --\n", "-- () -- -- () -- () () -- | -- () () () ()\n", "-- () -- -- () -- () () () | () -- -- -- --\n", "-- () -- -- () () -- -- -- | () -- -- -- ()\n", "-- () -- -- () () -- -- () | () -- -- () --\n", "-- () -- -- () () -- () -- | () -- -- () ()\n", "-- () -- -- () () -- () () | () -- () -- --\n", "-- () -- -- () () () -- -- | () -- () -- ()\n", "-- () -- -- () () () -- () | () -- () () --\n", "-- () -- -- () () () () -- | () -- () () ()\n", "-- () -- -- () () () () () | () () -- -- --\n", "-- () -- () -- -- -- -- -- | -- () -- () --\n", "-- () -- () -- -- -- -- () | -- () -- () ()\n", "-- () -- () -- -- -- () -- | -- () () -- --\n", "-- () -- () -- -- -- () () | -- () () -- ()\n", "-- () -- () -- -- () -- -- | -- () () () --\n", "-- () -- () -- -- () -- () | -- () () () ()\n", "-- () -- () -- -- () () -- | () -- -- -- --\n", "-- () -- () -- -- () () () | () -- -- -- ()\n", "-- () -- () -- () -- -- -- | () -- -- () --\n", "-- () -- () -- () -- -- () | () -- -- () ()\n", "-- () -- () -- () -- () -- | () -- () -- --\n", "-- () -- () -- () -- () () | () -- () -- ()\n", "-- () -- () -- () () -- -- | () -- () () --\n", "-- () -- () -- () () -- () | () -- () () ()\n", "-- () -- () -- () () () -- | () () -- -- --\n", "-- () -- () -- () () () () | () () -- -- ()\n", "-- () -- () () -- -- -- -- | -- () -- () ()\n", "-- () -- () () -- -- -- () | -- () () -- --\n", "-- () -- () () -- -- () -- | -- () () -- ()\n", "-- () -- () () -- -- () () | -- () () () --\n", "-- () -- () () -- () -- -- | -- () () () ()\n", "-- () -- () () -- () -- () | () -- -- -- --\n", "-- () -- () () -- () () -- | () -- -- -- ()\n", "-- () -- () () -- () () () | () -- -- () --\n", "-- () -- () () () -- -- -- | () -- -- () ()\n", "-- () -- () () () -- -- () | () -- () -- --\n", "-- () -- () () () -- () -- | () -- () -- ()\n", "-- () -- () () () -- () () | () -- () () --\n", "-- () -- () () () () -- -- | () -- () () ()\n", "-- () -- () () () () -- () | () () -- -- --\n", "-- () -- () () () () () -- | () () -- -- ()\n", "-- () -- () () () () () () | () () -- () --\n", "-- () () -- -- -- -- -- -- | -- () () -- --\n", "-- () () -- -- -- -- -- () | -- () () -- ()\n", "-- () () -- -- -- -- () -- | -- () () () --\n", "-- () () -- -- -- -- () () | -- () () () ()\n", "-- () () -- -- -- () -- -- | () -- -- -- --\n", "-- () () -- -- -- () -- () | () -- -- -- ()\n", "-- () () -- -- -- () () -- | () -- -- () --\n", "-- () () -- -- -- () () () | () -- -- () ()\n", "-- () () -- -- () -- -- -- | () -- () -- --\n", "-- () () -- -- () -- -- () | () -- () -- ()\n", "-- () () -- -- () -- () -- | () -- () () --\n", "-- () () -- -- () -- () () | () -- () () ()\n", "-- () () -- -- () () -- -- | () () -- -- --\n", "-- () () -- -- () () -- () | () () -- -- ()\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "-- () () -- -- () () () -- | () () -- () --\n", "-- () () -- -- () () () () | () () -- () ()\n", "-- () () -- () -- -- -- -- | -- () () -- ()\n", "-- () () -- () -- -- -- () | -- () () () --\n", "-- () () -- () -- -- () -- | -- () () () ()\n", "-- () () -- () -- -- () () | () -- -- -- --\n", "-- () () -- () -- () -- -- | () -- -- -- ()\n", "-- () () -- () -- () -- () | () -- -- () --\n", "-- () () -- () -- () () -- | () -- -- () ()\n", "-- () () -- () -- () () () | () -- () -- --\n", "-- () () -- () () -- -- -- | () -- () -- ()\n", "-- () () -- () () -- -- () | () -- () () --\n", "-- () () -- () () -- () -- | () -- () () ()\n", "-- () () -- () () -- () () | () () -- -- --\n", "-- () () -- () () () -- -- | () () -- -- ()\n", "-- () () -- () () () -- () | () () -- () --\n", "-- () () -- () () () () -- | () () -- () ()\n", "-- () () -- () () () () () | () () () -- --\n", "-- () () () -- -- -- -- -- | -- () () () --\n", "-- () () () -- -- -- -- () | -- () () () ()\n", "-- () () () -- -- -- () -- | () -- -- -- --\n", "-- () () () -- -- -- () () | () -- -- -- ()\n", "-- () () () -- -- () -- -- | () -- -- () --\n", "-- () () () -- -- () -- () | () -- -- () ()\n", "-- () () () -- -- () () -- | () -- () -- --\n", "-- () () () -- -- () () () | () -- () -- ()\n", "-- () () () -- () -- -- -- | () -- () () --\n", "-- () () () -- () -- -- () | () -- () () ()\n", "-- () () () -- () -- () -- | () () -- -- --\n", "-- () () () -- () -- () () | () () -- -- ()\n", "-- () () () -- () () -- -- | () () -- () --\n", "-- () () () -- () () -- () | () () -- () ()\n", "-- () () () -- () () () -- | () () () -- --\n", "-- () () () -- () () () () | () () () -- ()\n", "-- () () () () -- -- -- -- | -- () () () ()\n", "-- () () () () -- -- -- () | () -- -- -- --\n", "-- () () () () -- -- () -- | () -- -- -- ()\n", "-- () () () () -- -- () () | () -- -- () --\n", "-- () () () () -- () -- -- | () -- -- () ()\n", "-- () () () () -- () -- () | () -- () -- --\n", "-- () () () () -- () () -- | () -- () -- ()\n", "-- () () () () -- () () () | () -- () () --\n", "-- () () () () () -- -- -- | () -- () () ()\n", "-- () () () () () -- -- () | () () -- -- --\n", "-- () () () () () -- () -- | () () -- -- ()\n", "-- () () () () () -- () () | () () -- () --\n", "-- () () () () () () -- -- | () () -- () ()\n", "-- () () () () () () -- () | () () () -- --\n", "-- () () () () () () () -- | () () () -- ()\n", "-- () () () () () () () () | () () () () --\n", "() -- -- -- -- -- -- -- -- | -- -- -- -- ()\n", "() -- -- -- -- -- -- -- () | -- -- -- () --\n", "() -- -- -- -- -- -- () -- | -- -- -- () ()\n", "() -- -- -- -- -- -- () () | -- -- () -- --\n", "() -- -- -- -- -- () -- -- | -- -- () -- ()\n", "() -- -- -- -- -- () -- () | -- -- () () --\n", "() -- -- -- -- -- () () -- | -- -- () () ()\n", "() -- -- -- -- -- () () () | -- () -- -- --\n", "() -- -- -- -- () -- -- -- | -- () -- -- ()\n", "() -- -- -- -- () -- -- () | -- () -- () --\n", "() -- -- -- -- () -- () -- | -- () -- () ()\n", "() -- -- -- -- () -- () () | -- () () -- --\n", "() -- -- -- -- () () -- -- | -- () () -- ()\n", "() -- -- -- -- () () -- () | -- () () () --\n", "() -- -- -- -- () () () -- | -- () () () ()\n", "() -- -- -- -- () () () () | () -- -- -- --\n", "() -- -- -- () -- -- -- -- | -- -- -- () --\n", "() -- -- -- () -- -- -- () | -- -- -- () ()\n", "() -- -- -- () -- -- () -- | -- -- () -- --\n", "() -- -- -- () -- -- () () | -- -- () -- ()\n", "() -- -- -- () -- () -- -- | -- -- () () --\n", "() -- -- -- () -- () -- () | -- -- () () ()\n", "() -- -- -- () -- () () -- | -- () -- -- --\n", "() -- -- -- () -- () () () | -- () -- -- ()\n", "() -- -- -- () () -- -- -- | -- () -- () --\n", "() -- -- -- () () -- -- () | -- () -- () ()\n", "() -- -- -- () () -- () -- | -- () () -- --\n", "() -- -- -- () () -- () () | -- () () -- ()\n", "() -- -- -- () () () -- -- | -- () () () --\n", "() -- -- -- () () () -- () | -- () () () ()\n", "() -- -- -- () () () () -- | () -- -- -- --\n", "() -- -- -- () () () () () | () -- -- -- ()\n", "() -- -- () -- -- -- -- -- | -- -- -- () ()\n", "() -- -- () -- -- -- -- () | -- -- () -- --\n", "() -- -- () -- -- -- () -- | -- -- () -- ()\n", "() -- -- () -- -- -- () () | -- -- () () --\n", "() -- -- () -- -- () -- -- | -- -- () () ()\n", "() -- -- () -- -- () -- () | -- () -- -- --\n", "() -- -- () -- -- () () -- | -- () -- -- ()\n", "() -- -- () -- -- () () () | -- () -- () --\n", "() -- -- () -- () -- -- -- | -- () -- () ()\n", "() -- -- () -- () -- -- () | -- () () -- --\n", "() -- -- () -- () -- () -- | -- () () -- ()\n", "() -- -- () -- () -- () () | -- () () () --\n", "() -- -- () -- () () -- -- | -- () () () ()\n", "() -- -- () -- () () -- () | () -- -- -- --\n", "() -- -- () -- () () () -- | () -- -- -- ()\n", "() -- -- () -- () () () () | () -- -- () --\n", "() -- -- () () -- -- -- -- | -- -- () -- --\n", "() -- -- () () -- -- -- () | -- -- () -- ()\n", "() -- -- () () -- -- () -- | -- -- () () --\n", "() -- -- () () -- -- () () | -- -- () () ()\n", "() -- -- () () -- () -- -- | -- () -- -- --\n", "() -- -- () () -- () -- () | -- () -- -- ()\n", "() -- -- () () -- () () -- | -- () -- () --\n", "() -- -- () () -- () () () | -- () -- () ()\n", "() -- -- () () () -- -- -- | -- () () -- --\n", "() -- -- () () () -- -- () | -- () () -- ()\n", "() -- -- () () () -- () -- | -- () () () --\n", "() -- -- () () () -- () () | -- () () () ()\n", "() -- -- () () () () -- -- | () -- -- -- --\n", "() -- -- () () () () -- () | () -- -- -- ()\n", "() -- -- () () () () () -- | () -- -- () --\n", "() -- -- () () () () () () | () -- -- () ()\n", "() -- () -- -- -- -- -- -- | -- -- () -- ()\n", "() -- () -- -- -- -- -- () | -- -- () () --\n", "() -- () -- -- -- -- () -- | -- -- () () ()\n", "() -- () -- -- -- -- () () | -- () -- -- --\n", "() -- () -- -- -- () -- -- | -- () -- -- ()\n", "() -- () -- -- -- () -- () | -- () -- () --\n", "() -- () -- -- -- () () -- | -- () -- () ()\n", "() -- () -- -- -- () () () | -- () () -- --\n", "() -- () -- -- () -- -- -- | -- () () -- ()\n", "() -- () -- -- () -- -- () | -- () () () --\n", "() -- () -- -- () -- () -- | -- () () () ()\n", "() -- () -- -- () -- () () | () -- -- -- --\n", "() -- () -- -- () () -- -- | () -- -- -- ()\n", "() -- () -- -- () () -- () | () -- -- () --\n", "() -- () -- -- () () () -- | () -- -- () ()\n", "() -- () -- -- () () () () | () -- () -- --\n", "() -- () -- () -- -- -- -- | -- -- () () --\n", "() -- () -- () -- -- -- () | -- -- () () ()\n", "() -- () -- () -- -- () -- | -- () -- -- --\n", "() -- () -- () -- -- () () | -- () -- -- ()\n", "() -- () -- () -- () -- -- | -- () -- () --\n", "() -- () -- () -- () -- () | -- () -- () ()\n", "() -- () -- () -- () () -- | -- () () -- --\n", "() -- () -- () -- () () () | -- () () -- ()\n", "() -- () -- () () -- -- -- | -- () () () --\n", "() -- () -- () () -- -- () | -- () () () ()\n", "() -- () -- () () -- () -- | () -- -- -- --\n", "() -- () -- () () -- () () | () -- -- -- ()\n", "() -- () -- () () () -- -- | () -- -- () --\n", "() -- () -- () () () -- () | () -- -- () ()\n", "() -- () -- () () () () -- | () -- () -- --\n", "() -- () -- () () () () () | () -- () -- ()\n", "() -- () () -- -- -- -- -- | -- -- () () ()\n", "() -- () () -- -- -- -- () | -- () -- -- --\n", "() -- () () -- -- -- () -- | -- () -- -- ()\n", "() -- () () -- -- -- () () | -- () -- () --\n", "() -- () () -- -- () -- -- | -- () -- () ()\n", "() -- () () -- -- () -- () | -- () () -- --\n", "() -- () () -- -- () () -- | -- () () -- ()\n", "() -- () () -- -- () () () | -- () () () --\n", "() -- () () -- () -- -- -- | -- () () () ()\n", "() -- () () -- () -- -- () | () -- -- -- --\n", "() -- () () -- () -- () -- | () -- -- -- ()\n", "() -- () () -- () -- () () | () -- -- () --\n", "() -- () () -- () () -- -- | () -- -- () ()\n", "() -- () () -- () () -- () | () -- () -- --\n", "() -- () () -- () () () -- | () -- () -- ()\n", "() -- () () -- () () () () | () -- () () --\n", "() -- () () () -- -- -- -- | -- () -- -- --\n", "() -- () () () -- -- -- () | -- () -- -- ()\n", "() -- () () () -- -- () -- | -- () -- () --\n", "() -- () () () -- -- () () | -- () -- () ()\n", "() -- () () () -- () -- -- | -- () () -- --\n", "() -- () () () -- () -- () | -- () () -- ()\n", "() -- () () () -- () () -- | -- () () () --\n", "() -- () () () -- () () () | -- () () () ()\n", "() -- () () () () -- -- -- | () -- -- -- --\n", "() -- () () () () -- -- () | () -- -- -- ()\n", "() -- () () () () -- () -- | () -- -- () --\n", "() -- () () () () -- () () | () -- -- () ()\n", "() -- () () () () () -- -- | () -- () -- --\n", "() -- () () () () () -- () | () -- () -- ()\n", "() -- () () () () () () -- | () -- () () --\n", "() -- () () () () () () () | () -- () () ()\n", "() () -- -- -- -- -- -- -- | -- () -- -- ()\n", "() () -- -- -- -- -- -- () | -- () -- () --\n", "() () -- -- -- -- -- () -- | -- () -- () ()\n", "() () -- -- -- -- -- () () | -- () () -- --\n", "() () -- -- -- -- () -- -- | -- () () -- ()\n", "() () -- -- -- -- () -- () | -- () () () --\n", "() () -- -- -- -- () () -- | -- () () () ()\n", "() () -- -- -- -- () () () | () -- -- -- --\n", "() () -- -- -- () -- -- -- | () -- -- -- ()\n", "() () -- -- -- () -- -- () | () -- -- () --\n", "() () -- -- -- () -- () -- | () -- -- () ()\n", "() () -- -- -- () -- () () | () -- () -- --\n", "() () -- -- -- () () -- -- | () -- () -- ()\n", "() () -- -- -- () () -- () | () -- () () --\n", "() () -- -- -- () () () -- | () -- () () ()\n", "() () -- -- -- () () () () | () () -- -- --\n", "() () -- -- () -- -- -- -- | -- () -- () --\n", "() () -- -- () -- -- -- () | -- () -- () ()\n", "() () -- -- () -- -- () -- | -- () () -- --\n", "() () -- -- () -- -- () () | -- () () -- ()\n", "() () -- -- () -- () -- -- | -- () () () --\n", "() () -- -- () -- () -- () | -- () () () ()\n", "() () -- -- () -- () () -- | () -- -- -- --\n", "() () -- -- () -- () () () | () -- -- -- ()\n", "() () -- -- () () -- -- -- | () -- -- () --\n", "() () -- -- () () -- -- () | () -- -- () ()\n", "() () -- -- () () -- () -- | () -- () -- --\n", "() () -- -- () () -- () () | () -- () -- ()\n", "() () -- -- () () () -- -- | () -- () () --\n", "() () -- -- () () () -- () | () -- () () ()\n", "() () -- -- () () () () -- | () () -- -- --\n", "() () -- -- () () () () () | () () -- -- ()\n", "() () -- () -- -- -- -- -- | -- () -- () ()\n", "() () -- () -- -- -- -- () | -- () () -- --\n", "() () -- () -- -- -- () -- | -- () () -- ()\n", "() () -- () -- -- -- () () | -- () () () --\n", "() () -- () -- -- () -- -- | -- () () () ()\n", "() () -- () -- -- () -- () | () -- -- -- --\n", "() () -- () -- -- () () -- | () -- -- -- ()\n", "() () -- () -- -- () () () | () -- -- () --\n", "() () -- () -- () -- -- -- | () -- -- () ()\n", "() () -- () -- () -- -- () | () -- () -- --\n", "() () -- () -- () -- () -- | () -- () -- ()\n", "() () -- () -- () -- () () | () -- () () --\n", "() () -- () -- () () -- -- | () -- () () ()\n", "() () -- () -- () () -- () | () () -- -- --\n", "() () -- () -- () () () -- | () () -- -- ()\n", "() () -- () -- () () () () | () () -- () --\n", "() () -- () () -- -- -- -- | -- () () -- --\n", "() () -- () () -- -- -- () | -- () () -- ()\n", "() () -- () () -- -- () -- | -- () () () --\n", "() () -- () () -- -- () () | -- () () () ()\n", "() () -- () () -- () -- -- | () -- -- -- --\n", "() () -- () () -- () -- () | () -- -- -- ()\n", "() () -- () () -- () () -- | () -- -- () --\n", "() () -- () () -- () () () | () -- -- () ()\n", "() () -- () () () -- -- -- | () -- () -- --\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "() () -- () () () -- -- () | () -- () -- ()\n", "() () -- () () () -- () -- | () -- () () --\n", "() () -- () () () -- () () | () -- () () ()\n", "() () -- () () () () -- -- | () () -- -- --\n", "() () -- () () () () -- () | () () -- -- ()\n", "() () -- () () () () () -- | () () -- () --\n", "() () -- () () () () () () | () () -- () ()\n", "() () () -- -- -- -- -- -- | -- () () -- ()\n", "() () () -- -- -- -- -- () | -- () () () --\n", "() () () -- -- -- -- () -- | -- () () () ()\n", "() () () -- -- -- -- () () | () -- -- -- --\n", "() () () -- -- -- () -- -- | () -- -- -- ()\n", "() () () -- -- -- () -- () | () -- -- () --\n", "() () () -- -- -- () () -- | () -- -- () ()\n", "() () () -- -- -- () () () | () -- () -- --\n", "() () () -- -- () -- -- -- | () -- () -- ()\n", "() () () -- -- () -- -- () | () -- () () --\n", "() () () -- -- () -- () -- | () -- () () ()\n", "() () () -- -- () -- () () | () () -- -- --\n", "() () () -- -- () () -- -- | () () -- -- ()\n", "() () () -- -- () () -- () | () () -- () --\n", "() () () -- -- () () () -- | () () -- () ()\n", "() () () -- -- () () () () | () () () -- --\n", "() () () -- () -- -- -- -- | -- () () () --\n", "() () () -- () -- -- -- () | -- () () () ()\n", "() () () -- () -- -- () -- | () -- -- -- --\n", "() () () -- () -- -- () () | () -- -- -- ()\n", "() () () -- () -- () -- -- | () -- -- () --\n", "() () () -- () -- () -- () | () -- -- () ()\n", "() () () -- () -- () () -- | () -- () -- --\n", "() () () -- () -- () () () | () -- () -- ()\n", "() () () -- () () -- -- -- | () -- () () --\n", "() () () -- () () -- -- () | () -- () () ()\n", "() () () -- () () -- () -- | () () -- -- --\n", "() () () -- () () -- () () | () () -- -- ()\n", "() () () -- () () () -- -- | () () -- () --\n", "() () () -- () () () -- () | () () -- () ()\n", "() () () -- () () () () -- | () () () -- --\n", "() () () -- () () () () () | () () () -- ()\n", "() () () () -- -- -- -- -- | -- () () () ()\n", "() () () () -- -- -- -- () | () -- -- -- --\n", "() () () () -- -- -- () -- | () -- -- -- ()\n", "() () () () -- -- -- () () | () -- -- () --\n", "() () () () -- -- () -- -- | () -- -- () ()\n", "() () () () -- -- () -- () | () -- () -- --\n", "() () () () -- -- () () -- | () -- () -- ()\n", "() () () () -- -- () () () | () -- () () --\n", "() () () () -- () -- -- -- | () -- () () ()\n", "() () () () -- () -- -- () | () () -- -- --\n", "() () () () -- () -- () -- | () () -- -- ()\n", "() () () () -- () -- () () | () () -- () --\n", "() () () () -- () () -- -- | () () -- () ()\n", "() () () () -- () () -- () | () () () -- --\n", "() () () () -- () () () -- | () () () -- ()\n", "() () () () -- () () () () | () () () () --\n", "() () () () () -- -- -- -- | () -- -- -- --\n", "() () () () () -- -- -- () | () -- -- -- ()\n", "() () () () () -- -- () -- | () -- -- () --\n", "() () () () () -- -- () () | () -- -- () ()\n", "() () () () () -- () -- -- | () -- () -- --\n", "() () () () () -- () -- () | () -- () -- ()\n", "() () () () () -- () () -- | () -- () () --\n", "() () () () () -- () () () | () -- () () ()\n", "() () () () () () -- -- -- | () () -- -- --\n", "() () () () () () -- -- () | () () -- -- ()\n", "() () () () () () -- () -- | () () -- () --\n", "() () () () () () -- () () | () () -- () ()\n", "() () () () () () () -- -- | () () () -- --\n", "() () () () () () () -- () | () () () -- ()\n", "() () () () () () () () -- | () () () () --\n", "() () () () () () () () () | () () () () ()\n" ] } ], "source": [ "def stringy_env(env):\n", " return {\n", " k: value_of(e, v='--', m='()')\n", " for k, e in env.items()\n", " }\n", "\n", "INPUTs = ('Cin', 'a3', 'a2', 'a1', 'a0', 'b3', 'b2', 'b1', 'b0')\n", "OUTPUTs = ('cout', 'sum3', 'sum2', 'sum1', 'sum0')\n", "\n", "format_string = '%(' + ')s %('.join(INPUTs) + ')s | %(' + ')s %('.join(OUTPUTs) + ')s'\n", "\n", "\n", "print 'Ci|a3 a2 a1 a0|b3 b2 b1 b0 | Co s3 s2 s1 s0'\n", "results = {}\n", "for env in environments_of_variables(*INPUTs):\n", "\n", " for name, expression in CIRCUITS.items():\n", " results[name] = value_of(reify(expression, env))\n", "\n", " env.update(results)\n", " print format_string % stringy_env(env)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# A Model of Computation.\n", "\n", "That was a bit steep, let's formalize it and make it a little easier to work with.\n", "\n", "First let's have a _register_ of named values:" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [], "source": [ "R = {name: Void for name in 'Cin a3 a2 a1 a0 b3 b2 b1 b0 Cout'.split()}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's have a _program_ of named expressions that give new values when evaluated in terms of the current values in **R** (this is just the same `CIRCUITS`, but feeding back the results into the \"b\" bits):" ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [], "source": [ "P = {\n", " 'b0': sum0,\n", " 'b1': sum1,\n", " 'b2': sum2,\n", " 'b3': sum3,\n", " 'Cout': cout,\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One _cycle_ of the machine means to evaluate each named expression in the program with the current values in the register." ] }, { "cell_type": "code", "execution_count": 89, "metadata": {}, "outputs": [], "source": [ "make_reify_reducer = lambda env: lambda form: value_of(reify(form, env))\n", "\n", "\n", "def cycle(program, register):\n", " rr = make_reify_reducer(register)\n", " return {bit: rr(expression) for bit, expression in program.iteritems()}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With all the register values at \"zero\" (Void) nothing happens." ] }, { "cell_type": "code", "execution_count": 90, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'Cin': (()),\n", " 'Cout': (()),\n", " 'a0': (()),\n", " 'a1': (()),\n", " 'a2': (()),\n", " 'a3': (()),\n", " 'b0': (()),\n", " 'b1': (()),\n", " 'b2': (()),\n", " 'b3': (())}" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "R.update(cycle(P, R))\n", "R" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's make a nice display function to inspect our little adder computer." ] }, { "cell_type": "code", "execution_count": 91, "metadata": {}, "outputs": [], "source": [ "def show_as_int(*names):\n", " '''\n", " Return a function that converts a sequence of\n", " named bits (as Void/Mark values) into a integer.\n", " '''\n", " def inner(register):\n", " i, n = 0, 1\n", " for name in names:\n", " if not register[name]:\n", " i += n\n", " n <<= 1\n", " return i\n", " return inner" ] }, { "cell_type": "code", "execution_count": 92, "metadata": {}, "outputs": [], "source": [ "a_register = show_as_int('a0', 'a1', 'a2', 'a3')\n", "b_register = show_as_int('b0', 'b1', 'b2', 'b3')\n", "\n", "\n", "def show_computer_state(R):\n", " print 'a: %-3i b: %-3i Cin: %-3i Cout: %-3i' % (\n", " a_register(R),\n", " b_register(R),\n", " int(not R['Cin']),\n", " int(not R['Cout']),\n", " )" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a: 0 b: 0 Cin: 0 Cout: 0 \n" ] } ], "source": [ "show_computer_state(R)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's set one bit to true (Mark-valued in the chosen convention. We could have Void be true but we would have to form the circuit expressions differently.)" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [], "source": [ "R['a0'] = Mark" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's count to twenty." ] }, { "cell_type": "code", "execution_count": 95, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a: 1 b: 0 Cin: 0 Cout: 0 \n", "a: 1 b: 1 Cin: 0 Cout: 0 \n", "a: 1 b: 2 Cin: 0 Cout: 0 \n", "a: 1 b: 3 Cin: 0 Cout: 0 \n", "a: 1 b: 4 Cin: 0 Cout: 0 \n", "a: 1 b: 5 Cin: 0 Cout: 0 \n", "a: 1 b: 6 Cin: 0 Cout: 0 \n", "a: 1 b: 7 Cin: 0 Cout: 0 \n", "a: 1 b: 8 Cin: 0 Cout: 0 \n", "a: 1 b: 9 Cin: 0 Cout: 0 \n", "a: 1 b: 10 Cin: 0 Cout: 0 \n", "a: 1 b: 11 Cin: 0 Cout: 0 \n", "a: 1 b: 12 Cin: 0 Cout: 0 \n", "a: 1 b: 13 Cin: 0 Cout: 0 \n", "a: 1 b: 14 Cin: 0 Cout: 0 \n", "a: 1 b: 15 Cin: 0 Cout: 0 \n", "a: 1 b: 0 Cin: 0 Cout: 1 \n", "a: 1 b: 1 Cin: 0 Cout: 0 \n", "a: 1 b: 2 Cin: 0 Cout: 0 \n", "a: 1 b: 3 Cin: 0 Cout: 0 \n" ] } ], "source": [ "for _ in range(20):\n", " show_computer_state(R)\n", " R.update(cycle(P, R))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can see that at the sixteenth step the \"Cout\" carry bit is true and the count cycles back to zero." ] }, { "cell_type": "code", "execution_count": 96, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a: 3 b: 0 Cin: 0 Cout: 0 \n", "a: 3 b: 3 Cin: 0 Cout: 0 \n", "a: 3 b: 6 Cin: 0 Cout: 0 \n", "a: 3 b: 9 Cin: 0 Cout: 0 \n", "a: 3 b: 12 Cin: 0 Cout: 0 \n", "a: 3 b: 15 Cin: 0 Cout: 0 \n", "a: 3 b: 2 Cin: 0 Cout: 1 \n", "a: 3 b: 5 Cin: 0 Cout: 0 \n", "a: 3 b: 8 Cin: 0 Cout: 0 \n", "a: 3 b: 11 Cin: 0 Cout: 0 \n", "a: 3 b: 14 Cin: 0 Cout: 0 \n", "a: 3 b: 1 Cin: 0 Cout: 1 \n", "a: 3 b: 4 Cin: 0 Cout: 0 \n", "a: 3 b: 7 Cin: 0 Cout: 0 \n", "a: 3 b: 10 Cin: 0 Cout: 0 \n", "a: 3 b: 13 Cin: 0 Cout: 0 \n", "a: 3 b: 0 Cin: 0 Cout: 1 \n", "a: 3 b: 3 Cin: 0 Cout: 0 \n", "a: 3 b: 6 Cin: 0 Cout: 0 \n", "a: 3 b: 9 Cin: 0 Cout: 0 \n" ] } ], "source": [ "# Reset the register.\n", "R = {name: Void for name in 'Cin a3 a2 a1 a0 b3 b2 b1 b0 Cout'.split()}\n", "\n", "# Count by three.\n", "R['a0'] = R['a1'] = Mark\n", "\n", "# Print out twenty cycles.\n", "for _ in range(20):\n", " show_computer_state(R)\n", " R.update(cycle(P, R))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can see that the \"b\" bits are indeed counting by threes: 0, 3, 6, 9, 12, 15 & carry, 2, 5, 8, 11, 14 & carry, 1, 4, 7, 10, 13 & carry, 0, 3, 6, 9, ...\n", "\n", "This is my basic model for computation: A register, a program, and a cycle function. Note that reducing the form on each cycle isn't necessary, we can run the cycles and just `reify()` without reducing and we get new circuits that define bits in terms of the register values N cycles in the past." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Simple One-Dimensional Cellular Automaton" ] }, { "cell_type": "code", "execution_count": 97, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "...................................................0\n", "..................................................00\n", ".................................................0.0\n", "................................................0000\n", "...............................................0...0\n", "..............................................00..00\n", ".............................................0.0.0.0\n", "............................................00000000\n", "...........................................0.......0\n", "..........................................00......00\n", ".........................................0.0.....0.0\n", "........................................0000....0000\n", ".......................................0...0...0...0\n", "......................................00..00..00..00\n", ".....................................0.0.0.0.0.0.0.0\n", "....................................0000000000000000\n", "...................................0...............0\n", "..................................00..............00\n", ".................................0.0.............0.0\n", "................................0000............0000\n", "...............................0...0...........0...0\n", "..............................00..00..........00..00\n", ".............................0.0.0.0.........0.0.0.0\n", "............................00000000........00000000\n", "...........................0.......0.......0.......0\n", "..........................00......00......00......00\n", ".........................0.0.....0.0.....0.0.....0.0\n", "........................0000....0000....0000....0000\n", ".......................0...0...0...0...0...0...0...0\n", "......................00..00..00..00..00..00..00..00\n", ".....................0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0\n", "....................00000000000000000000000000000000\n", "...................0...............................0\n", "..................00..............................00\n", ".................0.0.............................0.0\n", "................0000............................0000\n", "...............0...0...........................0...0\n", "..............00..00..........................00..00\n", ".............0.0.0.0.........................0.0.0.0\n", "............00000000........................00000000\n", "...........0.......0.......................0.......0\n", "..........00......00......................00......00\n", ".........0.0.....0.0.....................0.0.....0.0\n", "........0000....0000....................0000....0000\n", ".......0...0...0...0...................0...0...0...0\n", "......00..00..00..00..................00..00..00..00\n", ".....0.0.0.0.0.0.0.0.................0.0.0.0.0.0.0.0\n", "....0000000000000000................0000000000000000\n", "...0...............0...............0...............0\n", "..00..............00..............00..............00\n", ".0.0.............0.0.............0.0.............0.0\n", "0000............0000............0000............0000\n", "...0...........0...0...........0...0...........0....\n", "..00..........00..00..........00..00..........00....\n", ".0.0.........0.0.0.0.........0.0.0.0.........0.0....\n", "0000........00000000........00000000........0000....\n", "...0.......0.......0.......0.......0.......0...0...0\n", "..00......00......00......00......00......00..00..00\n", ".0.0.....0.0.....0.0.....0.0.....0.0.....0.0.0.0.0.0\n", "0000....0000....0000....0000....0000....000000000000\n", "...0...0...0...0...0...0...0...0...0...0............\n", "..00..00..00..00..00..00..00..00..00..00............\n", ".0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0............\n", "0000000000000000000000000000000000000000............\n", ".......................................0...........0\n", "......................................00..........00\n", ".....................................0.0.........0.0\n", "....................................0000........0000\n", "...................................0...0.......0...0\n", "..................................00..00......00..00\n", ".................................0.0.0.0.....0.0.0.0\n", "................................00000000....00000000\n", "...............................0.......0...0.......0\n", "..............................00......00..00......00\n", ".............................0.0.....0.0.0.0.....0.0\n", "............................0000....00000000....0000\n", "...........................0...0...0.......0...0...0\n", "..........................00..00..00......00..00..00\n", ".........................0.0.0.0.0.0.....0.0.0.0.0.0\n", "........................000000000000....000000000000\n", ".......................0...........0...0...........0\n", "......................00..........00..00..........00\n", ".....................0.0.........0.0.0.0.........0.0\n", "....................0000........00000000........0000\n", "...................0...0.......0.......0.......0...0\n", "..................00..00......00......00......00..00\n", ".................0.0.0.0.....0.0.....0.0.....0.0.0.0\n", "................00000000....0000....0000....00000000\n", "...............0.......0...0...0...0...0...0.......0\n", "..............00......00..00..00..00..00..00......00\n", ".............0.0.....0.0.0.0.0.0.0.0.0.0.0.0.....0.0\n", "............0000....000000000000000000000000....0000\n", "...........0...0...0.......................0...0...0\n", "..........00..00..00......................00..00..00\n", ".........0.0.0.0.0.0.....................0.0.0.0.0.0\n", "........000000000000....................000000000000\n", ".......0...........0...................0...........0\n", "......00..........00..................00..........00\n", ".....0.0.........0.0.................0.0.........0.0\n", "....0000........0000................0000........0000\n" ] } ], "source": [ "# Universe\n", "U = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'\n", "\n", "\n", "# Register.\n", "R = {name: Void for name in U}\n", "\n", "\n", "# A program to XOR each bit with its neighbor, wrapping at the edge.\n", "P = {\n", " name: xor(name, U[(U.index(name) + 1) % len(U)])\n", " for name in U\n", "}\n", "\n", "\n", "def show(reg):\n", " '''Simple visualization of the register.'''\n", " print ''.join('.0'[not reg[name]] for name in U)\n", "\n", "\n", "# Set one \"bit\" in the register.\n", "R[U[-1]] = Mark\n", "\n", "\n", "# Run through some cycles.\n", "for _ in range(100):\n", " show(R)\n", " R.update(cycle(P, R))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A More Efficient Implementation\n", "\n", "Before building larger \"computers\" I want to switch to a more efficient implementation based on a register as a `set` of names that are currently Mark-valued, and a `set_solve()` function that evaluates a form in terms of such a `set`, and assuming all other names are Void-valued." ] }, { "cell_type": "code", "execution_count": 98, "metadata": {}, "outputs": [], "source": [ "def set_solve(form, marks):\n", " '''\n", " Given a form and a set of names that are Marks assume all other names\n", " in the form are Void and reduce to basic value (Mark or Void.)\n", " '''\n", " return (\n", " (Void, Mark)[form in marks]\n", " if isinstance(form, basestring)\n", " else _set_solve(form, marks)\n", " )\n", "\n", "\n", "def _set_solve(form, marks):\n", " for inner in form:\n", " if isinstance(inner, basestring):\n", " if inner in marks: \n", " return Void\n", " continue\n", " if not _set_solve(inner, marks): # Mark\n", " return Void\n", " return Mark" ] }, { "cell_type": "code", "execution_count": 99, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(((c) b) a)\n", "(())\n", "()\n", "(())\n" ] } ], "source": [ "A = F(a, (b, (c,)))\n", "print A\n", "print set_solve(A, {a})\n", "print set_solve(A, {b})\n", "print set_solve(A, {c})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To calculate the new R first collect all the names in R that are not mentioned in P (and so cannot be\n", "set to Void by it) then add the names evaluated by solving P's expressions with the marks in R." ] }, { "cell_type": "code", "execution_count": 100, "metadata": {}, "outputs": [], "source": [ "def set_cycle(R, P):\n", " return R.difference(P).union(\n", " signal\n", " for signal, expression in P.iteritems()\n", " if not set_solve(expression, R)\n", " )" ] }, { "cell_type": "code", "execution_count": 101, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "...................................................0\n", "..................................................00\n", ".................................................0.0\n", "................................................0000\n", "...............................................0...0\n", "..............................................00..00\n", ".............................................0.0.0.0\n", "............................................00000000\n", "...........................................0.......0\n", "..........................................00......00\n", ".........................................0.0.....0.0\n", "........................................0000....0000\n", ".......................................0...0...0...0\n", "......................................00..00..00..00\n", ".....................................0.0.0.0.0.0.0.0\n", "....................................0000000000000000\n", "...................................0...............0\n", "..................................00..............00\n", ".................................0.0.............0.0\n", "................................0000............0000\n", "...............................0...0...........0...0\n", "..............................00..00..........00..00\n", ".............................0.0.0.0.........0.0.0.0\n", "............................00000000........00000000\n", "...........................0.......0.......0.......0\n", "..........................00......00......00......00\n", ".........................0.0.....0.0.....0.0.....0.0\n", "........................0000....0000....0000....0000\n", ".......................0...0...0...0...0...0...0...0\n", "......................00..00..00..00..00..00..00..00\n", ".....................0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0\n", "....................00000000000000000000000000000000\n", "...................0...............................0\n", "..................00..............................00\n", ".................0.0.............................0.0\n", "................0000............................0000\n", "...............0...0...........................0...0\n", "..............00..00..........................00..00\n", ".............0.0.0.0.........................0.0.0.0\n", "............00000000........................00000000\n", "...........0.......0.......................0.......0\n", "..........00......00......................00......00\n", ".........0.0.....0.0.....................0.0.....0.0\n", "........0000....0000....................0000....0000\n", ".......0...0...0...0...................0...0...0...0\n", "......00..00..00..00..................00..00..00..00\n", ".....0.0.0.0.0.0.0.0.................0.0.0.0.0.0.0.0\n", "....0000000000000000................0000000000000000\n", "...0...............0...............0...............0\n", "..00..............00..............00..............00\n", ".0.0.............0.0.............0.0.............0.0\n", "0000............0000............0000............0000\n", "...0...........0...0...........0...0...........0....\n", "..00..........00..00..........00..00..........00....\n", ".0.0.........0.0.0.0.........0.0.0.0.........0.0....\n", "0000........00000000........00000000........0000....\n", "...0.......0.......0.......0.......0.......0...0...0\n", "..00......00......00......00......00......00..00..00\n", ".0.0.....0.0.....0.0.....0.0.....0.0.....0.0.0.0.0.0\n", "0000....0000....0000....0000....0000....000000000000\n", "...0...0...0...0...0...0...0...0...0...0............\n", "..00..00..00..00..00..00..00..00..00..00............\n", ".0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0............\n", "0000000000000000000000000000000000000000............\n", ".......................................0...........0\n", "......................................00..........00\n", ".....................................0.0.........0.0\n", "....................................0000........0000\n", "...................................0...0.......0...0\n", "..................................00..00......00..00\n", ".................................0.0.0.0.....0.0.0.0\n", "................................00000000....00000000\n", "...............................0.......0...0.......0\n", "..............................00......00..00......00\n", ".............................0.0.....0.0.0.0.....0.0\n", "............................0000....00000000....0000\n", "...........................0...0...0.......0...0...0\n", "..........................00..00..00......00..00..00\n", ".........................0.0.0.0.0.0.....0.0.0.0.0.0\n", "........................000000000000....000000000000\n", ".......................0...........0...0...........0\n", "......................00..........00..00..........00\n", ".....................0.0.........0.0.0.0.........0.0\n", "....................0000........00000000........0000\n", "...................0...0.......0.......0.......0...0\n", "..................00..00......00......00......00..00\n", ".................0.0.0.0.....0.0.....0.0.....0.0.0.0\n", "................00000000....0000....0000....00000000\n", "...............0.......0...0...0...0...0...0.......0\n", "..............00......00..00..00..00..00..00......00\n", ".............0.0.....0.0.0.0.0.0.0.0.0.0.0.0.....0.0\n", "............0000....000000000000000000000000....0000\n", "...........0...0...0.......................0...0...0\n", "..........00..00..00......................00..00..00\n", ".........0.0.0.0.0.0.....................0.0.0.0.0.0\n", "........000000000000....................000000000000\n", ".......0...........0...................0...........0\n", "......00..........00..................00..........00\n", ".....0.0.........0.0.................0.0.........0.0\n", "....0000........0000................0000........0000\n" ] } ], "source": [ "# Universe\n", "U = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'\n", "\n", "\n", "# Register.\n", "R = {U[-1]}\n", "\n", "\n", "# A program to XOR each bit with its neighbor, wrapping at the edge.\n", "P = {\n", " name: xor(name, U[(U.index(name) + 1) % len(U)])\n", " for name in U\n", "}\n", "\n", "\n", "def show(reg):\n", " '''Simple visualization of the register.'''\n", " print ''.join('.0'[name in reg] for name in U)\n", "\n", "\n", "# Run through some cycles.\n", "for _ in range(100):\n", " show(R)\n", " R = set_cycle(R, P)" ] }, { "cell_type": "code", "execution_count": 102, "metadata": {}, "outputs": [], "source": [ "def set_show_as_int(*names):\n", " def inner(register):\n", " i, n = 0, 1\n", " for name in names:\n", " if name in register:\n", " i += n\n", " n <<= 1\n", " return i\n", " return inner" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "### Each-Way as If... Then..." ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(((a) b) (a c))\n", " a b c | Value\n", "---------+------\n", " | \n", " () | ()\n", " () | \n", " () () | ()\n", "() | \n", "() () | \n", "() () | ()\n", "() () () | ()\n" ] } ], "source": [ "def ifte(predicate, true, false):\n", " return F(\n", " ((predicate,), true),\n", " ( predicate , false),\n", " )\n", "\n", "\n", "E = ifte(a, b, c)\n", "\n", "\n", "truth_table(E)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If `a` is Mark-valued the value of the whole form is that of `b`, but if `a` is Void-valued the value of the whole form is that of `c`.\n", "\n", " w/ a = ()\n", "\n", " ((( a) b) ( a c))\n", " (((()) b) (() c))\n", " (( b) (() ))\n", " (( b) )\n", " b\n", "\n", " w/ a =\n", "\n", " (((a) b) (a c))\n", " ((( ) b) ( c))\n", " ((( ) ) ( c))\n", " ( ( c))\n", " c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Flip-Flops for Memory" ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "((q s) r)\n", " q r s | Value\n", "---------+------\n", " | \n", " () | ()\n", " () | \n", " () () | \n", "() | ()\n", "() () | ()\n", "() () | \n", "() () () | \n" ] } ], "source": [ "def flip_flop(q, reset, set_):\n", " return F(reset, (q, set_))\n", "\n", "q, r, s = 'qrs'\n", "E = flip_flop(q, r, s)\n", "truth_table(E)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is a form that can be used in a circuit to \"remember\" a value.\n", "\n", " w/ r = ()\n", "\n", " ((q s) r)\n", " ((q s) ())\n", " ( ())\n", " \n", " w/ s = (), r = ___\n", "\n", " ((q s) r)\n", " ((q ()) )\n", " (( ()) )\n", " ( )\n", "\n", " w/ s = ___, r = ___\n", "\n", " ((q s) r)\n", " ((q ) )\n", " q\n", "\n", "If both are Void then the form is just `q`, if `r` is Mark then the form is Void, otherwise if `s` is Mark the form becomes Mark. This is called a \"flip-flop\" circuit, and it comprises a simple machine to remember one bit.\n", "\n", "Consider a simple computer: " ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [], "source": [ "U = q, r, s = 'qrs'\n", "\n", "P = {\n", " q: flip_flop(q, r, s),\n", " r: Void,\n", " s: Void,\n", "}\n", "\n", "R = set() # Initially all signals are off, Void-valued." ] }, { "cell_type": "code", "execution_count": 106, "metadata": {}, "outputs": [], "source": [ "bools_of = lambda universe: lambda register: (name in register for name in universe)\n", "\n", "\n", "def simple_show(universe):\n", " B = bools_of(universe)\n", " def _shower(register):\n", " print ''.join('.0'[b] for b in B(register))\n", " return _shower" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "...\n" ] } ], "source": [ "show = simple_show(U)\n", "show(R)" ] }, { "cell_type": "code", "execution_count": 108, "metadata": {}, "outputs": [], "source": [ "def SET(R):\n", " R |= {s}\n", " show(R)\n", " return set_cycle(R, P)\n", "\n", "\n", "def RESET(R):\n", " R |= {r}\n", " show(R)\n", " return set_cycle(R, P)" ] }, { "cell_type": "code", "execution_count": 109, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "qrs\n", "...\n", "...\n", "...\n", "..0\n", "0..\n", "0..\n", "0.0\n", "0..\n", "0..\n", "00.\n", "...\n", "...\n", ".0.\n", "...\n", "...\n" ] } ], "source": [ "print U\n", "show(R) ; R = set_cycle(R, P)\n", "show(R) ; R = set_cycle(R, P)\n", "show(R) ; R = set_cycle(R, P)\n", "\n", "R = SET(R)\n", "\n", "show(R) ; R = set_cycle(R, P)\n", "show(R) ; R = set_cycle(R, P)\n", "\n", "R = SET(R)\n", "\n", "show(R) ; R = set_cycle(R, P)\n", "show(R) ; R = set_cycle(R, P)\n", "\n", "R = RESET(R)\n", "\n", "show(R) ; R = set_cycle(R, P)\n", "show(R) ; R = set_cycle(R, P)\n", "\n", "R = RESET(R)\n", "\n", "show(R) ; R = set_cycle(R, P)\n", "show(R) ; R = set_cycle(R, P)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can see that `q` is stable unless `s` or `r` set or reset it." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using Flip-Flops and If...Then...Else... to make RAM\n", "\n", "We can use the system we have developed so far to build addressable RAM.\n" ] }, { "cell_type": "code", "execution_count": 110, "metadata": {}, "outputs": [], "source": [ "# Width in bits of the DATA registers.\n", "WIDTH = 2\n", "\n", "# Width in bits of the ADDR registers.\n", "LENGTH = 3 # Actual length 2**LENGTH" ] }, { "cell_type": "code", "execution_count": 111, "metadata": {}, "outputs": [], "source": [ "P = {}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll assume a single `WRITE` bit that sets a RAM location determined by the `ADDR` sub-register to the contents of the `DATA` sub-register." ] }, { "cell_type": "code", "execution_count": 112, "metadata": {}, "outputs": [], "source": [ "WRITE = 'WRITE'" ] }, { "cell_type": "code", "execution_count": 113, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['addr_0', 'addr_1', 'addr_2']" ] }, "execution_count": 113, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Address register.\n", "ADDR = ['addr_%i' % i for i in range(LENGTH)]\n", "ADDR" ] }, { "cell_type": "code", "execution_count": 114, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['a0', 'a1']" ] }, "execution_count": 114, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Data register.\n", "DATA = ['a%i' % i for i in range(WIDTH)]\n", "DATA" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can recognize which `RAM` location we want to address by using the [expressions for each row from above](#Each-Row-can-be-Represented-as-an-Expression) to create a predicate for each location that depends on the `ADDR` bits." ] }, { "cell_type": "code", "execution_count": 115, "metadata": {}, "outputs": [], "source": [ "def make_ram(program, addrs, data, width, write):\n", " RAM = []\n", " for addr, env in enumerate(environments_of_variables(*addrs)):\n", "\n", " addr_predicate = F((name,) if env[name] else name for name in env)\n", "\n", " predicate = and_(write, addr_predicate)\n", "\n", " for bit in range(width):\n", " ram = 'RAM_%i_%i' % (addr, bit)\n", " RAM.append(ram)\n", " program[ram] = simplify(ifte(predicate, data[bit], ram))\n", "\n", " return RAM" ] }, { "cell_type": "code", "execution_count": 116, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['RAM_0_0',\n", " 'RAM_0_1',\n", " 'RAM_1_0',\n", " 'RAM_1_1',\n", " 'RAM_2_0',\n", " 'RAM_2_1',\n", " 'RAM_3_0',\n", " 'RAM_3_1',\n", " 'RAM_4_0',\n", " 'RAM_4_1',\n", " 'RAM_5_0',\n", " 'RAM_5_1',\n", " 'RAM_6_0',\n", " 'RAM_6_1',\n", " 'RAM_7_0',\n", " 'RAM_7_1']" ] }, "execution_count": 116, "metadata": {}, "output_type": "execute_result" } ], "source": [ "RAM = make_ram(P, ADDR, DATA, WIDTH, WRITE)\n", "RAM" ] }, { "cell_type": "code", "execution_count": 117, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'RAM_0_0': (((((addr_0) (addr_1) (addr_2)) (WRITE)) RAM_0_0) (((addr_0) (addr_1) (addr_2)) (WRITE) a0)),\n", " 'RAM_0_1': (((((addr_0) (addr_1) (addr_2)) (WRITE)) RAM_0_1) (((addr_0) (addr_1) (addr_2)) (WRITE) a1)),\n", " 'RAM_1_0': (((((addr_0) (addr_1) addr_2) (WRITE)) RAM_1_0) (((addr_0) (addr_1) addr_2) (WRITE) a0)),\n", " 'RAM_1_1': (((((addr_0) (addr_1) addr_2) (WRITE)) RAM_1_1) (((addr_0) (addr_1) addr_2) (WRITE) a1)),\n", " 'RAM_2_0': (((((addr_0) (addr_2) addr_1) (WRITE)) RAM_2_0) (((addr_0) (addr_2) addr_1) (WRITE) a0)),\n", " 'RAM_2_1': (((((addr_0) (addr_2) addr_1) (WRITE)) RAM_2_1) (((addr_0) (addr_2) addr_1) (WRITE) a1)),\n", " 'RAM_3_0': (((((addr_0) addr_1 addr_2) (WRITE)) RAM_3_0) (((addr_0) addr_1 addr_2) (WRITE) a0)),\n", " 'RAM_3_1': (((((addr_0) addr_1 addr_2) (WRITE)) RAM_3_1) (((addr_0) addr_1 addr_2) (WRITE) a1)),\n", " 'RAM_4_0': (((((addr_1) (addr_2) addr_0) (WRITE)) RAM_4_0) (((addr_1) (addr_2) addr_0) (WRITE) a0)),\n", " 'RAM_4_1': (((((addr_1) (addr_2) addr_0) (WRITE)) RAM_4_1) (((addr_1) (addr_2) addr_0) (WRITE) a1)),\n", " 'RAM_5_0': (((((addr_1) addr_0 addr_2) (WRITE)) RAM_5_0) (((addr_1) addr_0 addr_2) (WRITE) a0)),\n", " 'RAM_5_1': (((((addr_1) addr_0 addr_2) (WRITE)) RAM_5_1) (((addr_1) addr_0 addr_2) (WRITE) a1)),\n", " 'RAM_6_0': (((((addr_2) addr_0 addr_1) (WRITE)) RAM_6_0) (((addr_2) addr_0 addr_1) (WRITE) a0)),\n", " 'RAM_6_1': (((((addr_2) addr_0 addr_1) (WRITE)) RAM_6_1) (((addr_2) addr_0 addr_1) (WRITE) a1)),\n", " 'RAM_7_0': ((((WRITE) (addr_0 addr_1 addr_2)) RAM_7_0) ((WRITE) (addr_0 addr_1 addr_2) a0)),\n", " 'RAM_7_1': ((((WRITE) (addr_0 addr_1 addr_2)) RAM_7_1) ((WRITE) (addr_0 addr_1 addr_2) a1))}" ] }, "execution_count": 117, "metadata": {}, "output_type": "execute_result" } ], "source": [ "P" ] }, { "cell_type": "code", "execution_count": 118, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(((((addr_0) (addr_1) (addr_2)) (WRITE)) RAM_0_0) (((addr_0) (addr_1) (addr_2)) (WRITE) a0))" ] }, "execution_count": 118, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E = P['RAM_0_0']\n", "E" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that if the `WRITE` bit is unset then each `RAM` bit is just set to itself." ] }, { "cell_type": "code", "execution_count": 119, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'RAM_0_0'" ] }, "execution_count": 119, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simplify(E, exclude={'WRITE'})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But if the `WRITE` bit is set then each `RAM` location still depends on the -per-location-predicate." ] }, { "cell_type": "code", "execution_count": 120, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((((addr_0) (addr_1) (addr_2)) a0) ((addr_0) (addr_1) (addr_2) RAM_0_0))" ] }, "execution_count": 120, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simplify(E, with_mark='WRITE')" ] }, { "cell_type": "code", "execution_count": 121, "metadata": {}, "outputs": [], "source": [ "def make_accumulator(program, addrs, data, width, read, alts):\n", "\n", " addr_predicates = [\n", " F((name,) if env[name] else name for name in env)\n", " for env in environments_of_variables(*addrs)\n", " ]\n", "\n", " for bit in range(width):\n", " a = data[bit]\n", " alt = alts[bit]\n", " foo = Void\n", " for addr, predicate in enumerate(addr_predicates):\n", " ram = 'RAM_%i_%i' % (addr, bit)\n", " foo = (ifte(predicate, ram, foo))\n", " program[a] = ifte(read, foo, alt)" ] }, { "cell_type": "code", "execution_count": 122, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a0': ((((((((((((((((((((((addr_0) (addr_1) (addr_2)))) RAM_0_0) ((((addr_0) (addr_1) (addr_2))) (()))) (((addr_0) (addr_1) addr_2))) (((((addr_0) (addr_1) addr_2))) RAM_1_0)) (((addr_0) (addr_2) addr_1))) (((((addr_0) (addr_2) addr_1))) RAM_2_0)) (((addr_0) addr_1 addr_2))) (((((addr_0) addr_1 addr_2))) RAM_3_0)) (((addr_1) (addr_2) addr_0))) (((((addr_1) (addr_2) addr_0))) RAM_4_0)) (((addr_1) addr_0 addr_2))) (((((addr_1) addr_0 addr_2))) RAM_5_0)) (((addr_2) addr_0 addr_1))) (((((addr_2) addr_0 addr_1))) RAM_6_0)) ((addr_0 addr_1 addr_2))) ((((addr_0 addr_1 addr_2))) RAM_7_0)) (READ)) (READ a0)),\n", " 'a1': ((((((((((((((((((((((addr_0) (addr_1) (addr_2)))) RAM_0_1) ((((addr_0) (addr_1) (addr_2))) (()))) (((addr_0) (addr_1) addr_2))) (((((addr_0) (addr_1) addr_2))) RAM_1_1)) (((addr_0) (addr_2) addr_1))) (((((addr_0) (addr_2) addr_1))) RAM_2_1)) (((addr_0) addr_1 addr_2))) (((((addr_0) addr_1 addr_2))) RAM_3_1)) (((addr_1) (addr_2) addr_0))) (((((addr_1) (addr_2) addr_0))) RAM_4_1)) (((addr_1) addr_0 addr_2))) (((((addr_1) addr_0 addr_2))) RAM_5_1)) (((addr_2) addr_0 addr_1))) (((((addr_2) addr_0 addr_1))) RAM_6_1)) ((addr_0 addr_1 addr_2))) ((((addr_0 addr_1 addr_2))) RAM_7_1)) (READ)) (READ a1))}" ] }, "execution_count": 122, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = {}\n", "make_accumulator(p, ADDR, DATA, WIDTH, 'READ', DATA)\n", "p" ] }, { "cell_type": "code", "execution_count": 123, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((((((((((((((((((((((addr_0) (addr_1) (addr_2)))) RAM_0_0) ((((addr_0) (addr_1) (addr_2))) (()))) (((addr_0) (addr_1) addr_2))) (((((addr_0) (addr_1) addr_2))) RAM_1_0)) (((addr_0) (addr_2) addr_1))) (((((addr_0) (addr_2) addr_1))) RAM_2_0)) (((addr_0) addr_1 addr_2))) (((((addr_0) addr_1 addr_2))) RAM_3_0)) (((addr_1) (addr_2) addr_0))) (((((addr_1) (addr_2) addr_0))) RAM_4_0)) (((addr_1) addr_0 addr_2))) (((((addr_1) addr_0 addr_2))) RAM_5_0)) (((addr_2) addr_0 addr_1))) (((((addr_2) addr_0 addr_1))) RAM_6_0)) ((addr_0 addr_1 addr_2))) ((((addr_0 addr_1 addr_2))) RAM_7_0)) (READ)) (READ a0))" ] }, "execution_count": 123, "metadata": {}, "output_type": "execute_result" } ], "source": [ "E = p[DATA[0]]\n", "E" ] }, { "cell_type": "code", "execution_count": 124, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((((((((((((((((((addr_0) (addr_1) (addr_2)) RAM_0_0) ((addr_0) (addr_1) (addr_2))) (addr_0) (addr_1) addr_2) (((addr_0) (addr_1) addr_2) RAM_1_0)) (addr_0) (addr_2) addr_1) (((addr_0) (addr_2) addr_1) RAM_2_0)) (addr_0) addr_1 addr_2) (((addr_0) addr_1 addr_2) RAM_3_0)) (addr_1) (addr_2) addr_0) (((addr_1) (addr_2) addr_0) RAM_4_0)) (addr_1) addr_0 addr_2) (((addr_1) addr_0 addr_2) RAM_5_0)) (addr_2) addr_0 addr_1) (((addr_2) addr_0 addr_1) RAM_6_0)) addr_0 addr_1 addr_2) ((addr_0 addr_1 addr_2) RAM_7_0))" ] }, "execution_count": 124, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simplify(E, with_mark='READ')" ] }, { "cell_type": "code", "execution_count": 125, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'a0'" ] }, "execution_count": 125, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simplify(E, {'READ'})" ] }, { "cell_type": "code", "execution_count": 126, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((((((((((((((((((((((addr_0) (addr_1) (addr_2)) RAM_0_0) ((addr_0) (addr_1) (addr_2))) (addr_0) (addr_1) addr_2) (((addr_0) (addr_1) addr_2) RAM_1_0)) (addr_0) (addr_2) addr_1) (((addr_0) (addr_2) addr_1) RAM_2_0)) (addr_0) addr_1 addr_2) (((addr_0) addr_1 addr_2) RAM_3_0)) (addr_1) (addr_2) addr_0) (((addr_1) (addr_2) addr_0) RAM_4_0)) (addr_1) addr_0 addr_2) (((addr_1) addr_0 addr_2) RAM_5_0)) (addr_2) addr_0 addr_1) (((addr_2) addr_0 addr_1) RAM_6_0)) addr_0 addr_1 addr_2) ((addr_0 addr_1 addr_2) RAM_7_0)) (READ)) (READ)) a0) ((((addr_0 addr_1 addr_2) RAM_7_0) (RAM_6_0 addr_0 addr_1 addr_2)) (READ) (a0)))" ] }, "execution_count": 126, "metadata": {}, "output_type": "execute_result" } ], "source": [ "each_way(E, 'a0')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 127, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((((((((((((((((((((((addr_0) (addr_1) (addr_2)) RAM_0_0) ((addr_0) (addr_1) (addr_2))) (addr_0) (addr_1) addr_2) (((addr_0) (addr_1) addr_2) RAM_1_0)) (addr_0) (addr_2) addr_1) (((addr_0) (addr_2) addr_1) RAM_2_0)) (addr_0) addr_1 addr_2) (((addr_0) addr_1 addr_2) RAM_3_0)) (addr_1) (addr_2) addr_0) (((addr_1) (addr_2) addr_0) RAM_4_0)) (addr_1) addr_0 addr_2) (((addr_1) addr_0 addr_2) RAM_5_0)) (addr_2) addr_0 addr_1) (((addr_2) addr_0 addr_1) RAM_6_0)) addr_0 addr_1 addr_2) ((addr_0 addr_1 addr_2) RAM_7_0)) (READ)) (READ a0)) WRITE) ((((((addr_0 addr_1 addr_2) RAM_7_0) (RAM_6_0 addr_0 addr_1 addr_2)) (READ)) (READ a0)) (WRITE)))" ] }, "execution_count": 127, "metadata": {}, "output_type": "execute_result" } ], "source": [ "each_way(E, 'WRITE')" ] }, { "cell_type": "code", "execution_count": 128, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((((((((((((((addr_1) (addr_2)) RAM_4_0) ((addr_1) (addr_2) RAM_3_0)) (addr_1) addr_2) (((addr_1) addr_2) RAM_5_0)) (addr_2) addr_1) (((addr_2) addr_1) RAM_6_0)) addr_1 addr_2) ((addr_1 addr_2) RAM_7_0)) (READ)) (READ a0)) addr_0) ((((READ) RAM_7_0) (READ a0)) (addr_0)))" ] }, "execution_count": 128, "metadata": {}, "output_type": "execute_result" } ], "source": [ "each_way(E, 'addr_0')" ] }, { "cell_type": "code", "execution_count": 129, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((((((((((((((((((((((addr_0) (addr_1) (addr_2)) RAM_0_0) ((addr_0) (addr_1) (addr_2))) (addr_0) (addr_1) addr_2) (((addr_0) (addr_1) addr_2) RAM_1_0)) (addr_0) (addr_2) addr_1) (((addr_0) (addr_2) addr_1) RAM_2_0)) (addr_0) addr_1 addr_2) (((addr_0) addr_1 addr_2) RAM_3_0)) (addr_1) (addr_2) addr_0) (((addr_1) (addr_2) addr_0) RAM_4_0)) (addr_1) addr_0 addr_2) (((addr_1) addr_0 addr_2) RAM_5_0)) (addr_2) addr_0 addr_1) (((addr_2) addr_0 addr_1) RAM_6_0)) addr_0 addr_1 addr_2) ((addr_0 addr_1 addr_2) RAM_7_0)) (READ)) (READ)) a0) ((((addr_0 addr_1 addr_2) RAM_7_0) (RAM_6_0 addr_0 addr_1 addr_2)) (READ) (a0)))" ] }, "execution_count": 129, "metadata": {}, "output_type": "execute_result" } ], "source": [ "each_way(E, 'a0')" ] }, { "cell_type": "code", "execution_count": 130, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "(((((addr_0 addr_1 addr_2) RAM_7_0) (RAM_6_0 addr_0 addr_1 addr_2)) (READ)) (READ a0))" ] }, "execution_count": 130, "metadata": {}, "output_type": "execute_result" } ], "source": [ "simplify(each_way(E, 'WRITE'), with_mark='WRITE')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ ", Sorting Networks for routing, more basic functions.\n", "\n", "Eventually: Orchestration with Joy." ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# FIN for now." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Appendix: Demonstration of A(AB) = A(B)\n", "\n", "The rule `A(AB) = A(B)` is the powerhouse of LoF.\n", "\n", "w/ A = ()\n", "\n", " A(AB) = A(B)\n", " ()(()B) = ()(B)\n", " () = ()\n", "\n", "w/ A =\n", "\n", " A(AB) = A(B)\n", " (B) = (B)\n", "\n", "\n", "Be aware of the recursive nature of this rule:\n", "\n", " A(...(...(A B)))\n", " A(.A.(...(A B)))\n", " A(.A.(.A.(A B)))\n", " A(.A.(.A.( B)))\n", " A(.A.(...( B)))\n", " A(...(...( B)))\n", "\n", "There is this too:\n", "\n", " (A)(...(...(... A B)))\n", " (A)((A)(...(... A B)))\n", " (A)((A)((A)(... A B)))\n", " (A)((A)((A)((A) A B)))\n", " (A)((A)((A)(( ) A B)))\n", " (A)((A)(...(( ) )))\n", " (A)(...(... ))\n", "\n", "Summarized:\n", "\n", " (A)(...(...(... A )))\n", " (A)(...(...(... () )))\n", " (A)(...(... ))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Appendix: Reduce String Expressions by Substitution\n", "Given a string form of an arithmetic expression (in other words a string that consists of only balanced pairs of parentheses) we can reduce it to its Mark/Void value by substitution to a [fixed-point](https://en.wikipedia.org/wiki/Fixed_point_%28mathematics%29)." ] }, { "cell_type": "code", "execution_count": 131, "metadata": {}, "outputs": [], "source": [ "# Translate the LoF Arithmetic rules to string substitution rules.\n", "reduce_string = lambda s: (\n", " s\n", " .replace('()()', '()')\n", " .replace('(())', '')\n", ")" ] }, { "cell_type": "code", "execution_count": 132, "metadata": {}, "outputs": [], "source": [ "def to_fixed_point(initial_value, F, limit=10000):\n", " '''Do value = F(value) until value == F(value).'''\n", " \n", " next_value = F(initial_value)\n", " \n", " while next_value != initial_value:\n", " \n", " if not limit: # A safety mechanism. Bail out after N iterations.\n", " raise RuntimeError('Reached limit of allowed iterations without finding fixed point.')\n", " limit -= 1\n", " \n", " initial_value = next_value\n", " next_value = F(initial_value)\n", " \n", " return initial_value" ] }, { "cell_type": "code", "execution_count": 133, "metadata": {}, "outputs": [], "source": [ "from operator import add\n", "\n", "\n", "def dyck_language(left, right=0, t='', A='(', B=')', op=add):\n", " '''Yield balanced pairs of A and B.'''\n", " if not (left or right):\n", " yield t\n", " return\n", "\n", " if left > 0:\n", " for i in dyck_language(left - 1, right + 1, op(t, A), A, B, op):\n", " yield i\n", "\n", " if right > 0:\n", " for i in dyck_language(left, right - 1, op(t, B), A, B, op):\n", " yield i" ] }, { "cell_type": "code", "execution_count": 134, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "((((())))) ⟶ ()\n", "(((()()))) ⟶ \n", "(((())())) ⟶ ()\n", "(((()))()) ⟶ \n", "(((())))() ⟶ ()\n", "((()(()))) ⟶ ()\n", "((()()())) ⟶ ()\n", "((()())()) ⟶ \n", "((()()))() ⟶ ()\n", "((())(())) ⟶ ()\n", "((())()()) ⟶ \n", "((())())() ⟶ ()\n", "((()))(()) ⟶ ()\n", "((()))()() ⟶ ()\n", "(()((()))) ⟶ \n", "(()(()())) ⟶ \n", "(()(())()) ⟶ \n", "(()(()))() ⟶ ()\n", "(()()(())) ⟶ \n", "(()()()()) ⟶ \n", "(()()())() ⟶ ()\n", "(()())(()) ⟶ \n", "(()())()() ⟶ ()\n", "(())((())) ⟶ ()\n", "(())(()()) ⟶ \n", "(())(())() ⟶ ()\n", "(())()(()) ⟶ ()\n", "(())()()() ⟶ ()\n", "()(((()))) ⟶ ()\n", "()((()())) ⟶ ()\n", "()((())()) ⟶ ()\n", "()((()))() ⟶ ()\n", "()(()(())) ⟶ ()\n", "()(()()()) ⟶ ()\n", "()(()())() ⟶ ()\n", "()(())(()) ⟶ ()\n", "()(())()() ⟶ ()\n", "()()((())) ⟶ ()\n", "()()(()()) ⟶ ()\n", "()()(())() ⟶ ()\n", "()()()(()) ⟶ ()\n", "()()()()() ⟶ ()\n" ] } ], "source": [ "for s in dyck_language(5):\n", " print s, u'⟶', to_fixed_point(s, reduce_string)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## Appendix: `void()` and `mark()`\n", "\n", "The `void()` and `mark()` functions can be defined recursively in terms of each other. Note that `void()` uses `any()` while `mark()` uses `all()`. These functions implement a depth-first search. If we used versions of `any()` and `all()` that evaluated their arguments in parallel `void()` could return after the `True` result while `mark()` depends on all terms's results so its runtime will be bound by term with the greatest runtime." ] }, { "cell_type": "code", "execution_count": 135, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(()) is void ? True\n", "(()) is mark ? False\n", "() is void ? False\n", "() is mark ? True\n" ] } ], "source": [ "def void(form):\n", " return any(mark(i) for i in form)\n", "\n", "def mark(form):\n", " return all(void(i) for i in form)\n", "\n", "for form in BASE:\n", " for func in (void, mark):\n", " print form, 'is', func.__name__, '?', func(form)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## Appendix: Duals\n", "\n", "The Void and the Mark are not Boolean true and false. Rather they correspond to non-existance and existance. When translating a traditional logical statement into Laws of Form the first thing we must do is choose which mapping we would like to use: true = Mark or true = Void. The notation works the same way once the translation is made, so the only real criteria for choosing is which gives the smaller form.\n", "\n", "If you examine the truth tables for the basic forms above in light of this, you can see that each defines two logical functions depending on whether you treat Void as true and Mark as false, or Void as false and Mark as true.\n", "\n", "For example, the juxtaposition of two terms next to each other `a b` corresponds to **OR** if Mark is true, and to **AND** if Void is true. Likewise, the form `((a)(b))` is **AND** if Mark is true and **OR** if Void is true.\n", "\n", "Consider:\n", "\n", " (A ∧ ¬B) ∨ (C ∧ D)\n", " \n", "(This reads \"(A and not B) or (C and D)\" in case you have a hard time remembering what the symbols mean like I do.)\n", "\n", "If we choose Mark to be true then the form is:\n", "\n", " ((A) B) ((C)(D))\n", " \n", "If we choose Void to be true then the form is:\n", "\n", " ((A (B)) (C D))\n", "\n", "As I said above, the notation works the same way either way, so once the translation is made you can forget about the Boolean true/false and just work with the Laws of Form rules. Logic is containers.\n", "\n", "### De Morgan Duals\n", "\n", "Consider also the [De Morgan dual](https://en.wikipedia.org/wiki/De_Morgan%27s_laws) of the original statement:\n", "\n", " ¬((¬A ∨ B) ∧ (¬C ∨ ¬D))\n", "\n", "If we choose Mark to be true then the form is:\n", "\n", " (( ((A) B) ((C)(D)) ))\n", "\n", "The outer pair of containers can be deleted leaving the same form as above:\n", "\n", " ((A) B) ((C)(D))\n", "\n", "Likewise, if we choose Void to be true then the form is:\n", "\n", " ((((A)) (B)) (((C)) ((D))))\n", " \n", "Again, A((B)) => AB reduces this form to the same one above:\n", "\n", " ((A (B)) (C D))\n", "\n", "In the Laws of Form there are no De Morgan Dual statements. If you translate a logic statement and its dual into Laws of Form notation they both reduce to the same form.\n", "\n", "To me this is a clear indication that the Laws of Form are superior to the traditional notation involving `¬ ∨ ∧`, etc. LoF replaces all the symbols with just names and boundaries. The Laws of Form are not dualistic, they work directly in terms of existance and non-existance. Duality only comes in when you interpret the forms as Boolean statements and have to pick a mapping." ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# Misc. Junk" ] }, { "cell_type": "code", "execution_count": 136, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Counter({'Cin': 1,\n", " 'a0': 3,\n", " 'a1': 3,\n", " 'a2': 3,\n", " 'a3': 3,\n", " 'b0': 3,\n", " 'b1': 3,\n", " 'b2': 3,\n", " 'b3': 3})" ] }, "execution_count": 136, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from collections import Counter\n", "\n", "histo = Counter(yield_variables_of(cout))\n", "histo" ] }, { "cell_type": "code", "execution_count": 137, "metadata": {}, "outputs": [], "source": [ "#import pprint as pp\n", "\n", "\n", "#E = cout\n", "#for var, count in histo.most_common():\n", "# print 'stan', var, count\n", "# E = to_fixed_point(simplify(standardize(E, var)), simplify)\n", "# print len(str(E))\n", "# pp.pprint(dict(Counter(yield_variables_of(E))))\n", "# print '------'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Rather than manually calling `standard_form()` let's define a function that reduces a form to a (hopefully) smaller equivalent form by going through all the variables in the form and using `standard_form()` with each. Along with clean and unwrap we can drive an expression to a fixed point." ] }, { "cell_type": "code", "execution_count": 138, "metadata": {}, "outputs": [], "source": [ "def STAN(form):\n", " for var, _ in Counter(yield_variables_of(form)).most_common():\n", " form = to_fixed_point(simplify(standardize(form, var)), simplify)\n", " return form" ] }, { "cell_type": "code", "execution_count": 139, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[59, 135, 211, 287, 159]" ] }, "execution_count": 139, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sum0, cout = full_bit_adder('a0', 'b0', 'Cin')\n", "sum1, cout = full_bit_adder('a1', 'b1', cout)\n", "sum2, cout = full_bit_adder('a2', 'b2', cout)\n", "sum3, cout = full_bit_adder('a3', 'b3', cout)\n", "\n", "map(len, map(str, (sum0, sum1, sum2, sum3, cout)))" ] }, { "cell_type": "code", "execution_count": 140, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "global name 'standardize' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0msum0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfull_bit_adder\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'a0'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'b0'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'Cin'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0msum0\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mto_fixed_point\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msum0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mSTAN\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mcout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mto_fixed_point\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcout\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mSTAN\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0msum1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcout\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfull_bit_adder\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'a1'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'b1'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m\u001b[0m in \u001b[0;36mto_fixed_point\u001b[0;34m(initial_value, F, limit)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m'''Do value = F(value) until value == F(value).'''\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mnext_value\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mF\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minitial_value\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32mwhile\u001b[0m \u001b[0mnext_value\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0minitial_value\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m\u001b[0m in \u001b[0;36mSTAN\u001b[0;34m(form)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mSTAN\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mform\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mvar\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0m_\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mCounter\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0myield_variables_of\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mform\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmost_common\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mform\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mto_fixed_point\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msimplify\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstandardize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mform\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvar\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msimplify\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mform\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mNameError\u001b[0m: global name 'standardize' is not defined" ] } ], "source": [ "sum0, cout = full_bit_adder('a0', 'b0', 'Cin')\n", "sum0 = to_fixed_point(sum0, STAN)\n", "cout = to_fixed_point(cout, STAN)\n", "\n", "sum1, cout = full_bit_adder('a1', 'b1', cout)\n", "sum1 = to_fixed_point(sum1, STAN)\n", "cout = to_fixed_point(cout, STAN)\n", "\n", "sum2, cout = full_bit_adder('a2', 'b2', cout)\n", "sum2 = to_fixed_point(sum2, STAN)\n", "cout = to_fixed_point(cout, STAN)\n", "\n", "sum3, cout = full_bit_adder('a3', 'b3', cout)\n", "sum3 = to_fixed_point(sum3, STAN)\n", "cout = to_fixed_point(cout, STAN)\n", "\n", "\n", "map(len, map(str, (sum0, sum1, sum2, sum3, cout)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It would be useful and fun to write a simple search algorithm that tried different ways to reduce a form to see if it could find particulaly compact versions.\n", "\n", "Let's generate the expressions for the next two output bits, and the carry bit." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `sum3` bit expression is pretty big." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sum3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But it's only about 1/9th of size of the previous version (which was 9261.)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "len(str(sum3))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's simplify the first one manually just for fun:\n", "\n", " (((((())) (())) ((()))))\n", " (( ) ) ( )\n", " ( )\n", "\n", "Sure enough, it reduces to Mark after just a few applications of the rule `(()) = __` (the underscores indicates the absence of any value, aka Void.) We could also just delete variables that are Void in the original expression:\n", "\n", " ((((a)b)(c)))\n", " (( ) )( )\n", " ( )" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "C = F((a, b))\n", "for form in (A, B, C):\n", " arth = reify(form, env)\n", " print form, u'⟶', arth, u'⟶', value_of(arth)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print A\n", "Aa = simplify(A, {a})\n", "print a, Aa\n", "Aab = simplify(Aa, {b})\n", "print a, b, Aab\n", "Aabc = simplify(Aab, {c})\n", "print a, b, c, Aabc" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print a, Aa\n", "Aab = simplify(Aa, with_mark=b)\n", "print a, F(b), Aab" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print a, Aa\n", "Aac = simplify(Aa, with_mark=c)\n", "print a, F(c), Aac" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print a, Aa\n", "Aac = simplify(Aa, {c})\n", "print a, c, Aac" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from collections import Counter\n", "\n", "histo = Counter(yield_variables_of(sum7))\n", "histo" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "len(str(sum7))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Immediately we can just call `simplify()` until it stops shinking the expression." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s7 = simplify(sum7)\n", "len(str(s7))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s7 = simplify(s7)\n", "len(str(s7))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once was enough (we should consider adding a call to `simplify()` in the `full_bit_adder()` function.)\n", "\n", "Let's try using `each_way()` with the most common names in the form." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s7 = simplify(each_way(s7, 'a0'))\n", "len(str(s7))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s7 = simplify(s7)\n", "len(str(s7))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Counter(yield_variables_of(s7))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s7 = sum7\n", "\n", "#for name, count in histo.most_common():\n", "# s7 = simplify(each_way(s7, name))\n", "# print len(str(s7))\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def super_simple(form):\n", " return to_fixed_point(form, simplify)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "len(str(sum7))\n", "s7 = super_simple(sum7)\n", "len(str(s7))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s7 = sum7\n", "\n", "#for name, count in histo.most_common():\n", "# s7 = super_simple(each_way(s7, name))\n", "# print len(str(s7))\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print ' '.join(name[:2] for name in sorted(R))\n", "for _ in range(20):\n", " print format_env(R), '=', b_register(R)\n", " R.update(cycle(P, R))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.15" } }, "nbformat": 4, "nbformat_minor": 2 }