{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"[google collab version](https://colab.research.google.com/github/boazbk/nandnotebooks/blob/master/Lecture03_Defining_Computation.ipynb) (might have to click to allow \"scripts from insecure source\")"
]
},
{
"cell_type": "code",
"execution_count": 115,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%%html\n",
""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"%%capture\n",
"%run \"NAND programming language.ipynb\"\n",
"# from IPython.display import clear_output\n",
"# clear_output()"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"![alt](ahlfors.png \"\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Lecture 3: Defining Computation"
]
},
{
"cell_type": "code",
"execution_count": 113,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/html": [
"Laptops etc last 5 rows
"
],
"text/plain": [
""
]
},
"execution_count": 113,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from IPython.core.display import HTML\n",
"HTML('Laptops etc last 5 rows
')\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
" ## On collaboration\n",
" \n",
" Solving _80% of questions on your own_ is better for your understanding __and grade__ than solving _100% with others_.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Computation\n",
"\n",
"Like a recipe - follow _sequence of basic steps_ to achieve desired result"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Important to distinguish **what** and **how**"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"**what**/**specification**: The function $F:\\{0,1\\}^n \\rightarrow \\{0,1\\}^m$ we want to compute"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"**how**/**implementation**: The _algorithm_ or _program_ specifying instructions how to compute it."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"There are many programs to compute the same function!"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Is the following a function?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"def f(n):\n",
" return n*2"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"a. Yes\n",
"\n",
"b. No\n",
"\n",
"[pollev.com/cs121](http://pollev.com/cs121)"
]
},
{
"cell_type": "code",
"execution_count": 117,
"metadata": {
"scrolled": true,
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%%html\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## NO"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"def f(n):\n",
" return n*2\n",
"\n",
"def g(n):\n",
" L = []\n",
" for i in range(n): L = L + [2]\n",
" return sum(L)\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 121,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"60000"
]
},
"execution_count": 121,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f(30000)"
]
},
{
"cell_type": "code",
"execution_count": 122,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"60000"
]
},
"execution_count": 122,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"g(30000)"
]
},
{
"cell_type": "code",
"execution_count": 120,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"[True, True, True, True, True, True, True, True, True, True]"
]
},
"execution_count": 120,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[f(n)==g(n) for n in range(10)]"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"`f` and `g` _compute_ the same function but they are _not_ identical objects. "
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Computing using NAND"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"![alt](transistor-NAND-Gate.png \"\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"![alt](moorelaw.jpeg \"\")"
]
},
{
"cell_type": "code",
"execution_count": 123,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"image/svg+xml": [
"\r\n",
"\r\n",
"\r\n",
"\r\n",
"\r\n"
],
"text/plain": [
""
]
},
"execution_count": 123,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def mystery1(x): return NAND(NAND(x,x),NAND(x,x))\n",
"\n",
"nandcircuit(mystery1)"
]
},
{
"cell_type": "code",
"execution_count": 124,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Temp[0] = NAND(X[0],X[0])\n",
"Temp[1] = NAND(X[0],X[0])\n",
"Y[0] = NAND(Temp[0],Temp[1])\n"
]
}
],
"source": [
"print(nandcode(mystery1))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"What function does `mystery1` compute?"
]
},
{
"cell_type": "code",
"execution_count": 125,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%%html\n",
""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"def mystery2(a,b): return AND(a,NOT(b))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Which function does mystery2 compute?"
]
},
{
"cell_type": "code",
"execution_count": 129,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Temp[0] = NAND(X[1],X[1])\n",
"Temp[1] = NAND(X[0],Temp[0])\n",
"Y[0] = NAND(Temp[1],Temp[1])\n"
]
}
],
"source": [
"print(nandcode(mystery2))"
]
},
{
"cell_type": "code",
"execution_count": 127,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%%html\n",
""
]
},
{
"cell_type": "code",
"execution_count": 130,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 0 | 0\n",
"0 1 | 0\n",
"1 0 | 1\n",
"1 1 | 0\n"
]
}
],
"source": [
"for a in [0,1]: \n",
" for b in [0,1]:\n",
" print(f\"{a} {b} | {mystery2(a,b)}\") "
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"__Exercise:__ Draw NAND circuit for function $BIG_2:\\{0,1\\}^4 \\rightarrow \\{0,1\\}$ such that $BIGGER(a,b,c,d)=1$ iff $a+2*b > c +2*d$"
]
},
{
"cell_type": "code",
"execution_count": 131,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%%html\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"__Exercise:__ Draw NAND circuit for function $BIG_2:\\{0,1\\}^4 \\rightarrow \\{0,1\\}$ such that $BIGGER(a,b,c,d)=1$ iff $a+2*b > c +2*d$"
]
},
{
"cell_type": "code",
"execution_count": 132,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"def NOT(a): return NAND(a,a)\n",
"def OR(a,b): return NAND(NOT(a),NOT(b))\n",
"def AND(a,b): return NOT(NAND(a,b))\n",
"# b>d OR [ NOT(d>b) AND ( a>c ) ]\n",
"def BIG2(a,b,c,d): return OR(mystery2(b,d),AND(NOT(mystery2(d,b)),mystery2(a,c)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"import itertools"
]
},
{
"cell_type": "code",
"execution_count": 133,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 0 0 0 | 0 0 | 0\n",
"0 0 0 1 | 0 2 | 0\n",
"0 0 1 0 | 0 1 | 0\n",
"0 0 1 1 | 0 3 | 0\n",
"0 1 0 0 | 2 0 | 1\n",
"0 1 0 1 | 2 2 | 0\n",
"0 1 1 0 | 2 1 | 1\n",
"0 1 1 1 | 2 3 | 0\n",
"1 0 0 0 | 1 0 | 1\n",
"1 0 0 1 | 1 2 | 0\n",
"1 0 1 0 | 1 1 | 0\n",
"1 0 1 1 | 1 3 | 0\n",
"1 1 0 0 | 3 0 | 1\n",
"1 1 0 1 | 3 2 | 1\n",
"1 1 1 0 | 3 1 | 1\n",
"1 1 1 1 | 3 3 | 0\n"
]
}
],
"source": [
"for (a,b,c,d) in itertools.product([0,1],[0,1],[0,1],[0,1]): # ∀(a,b,c,d)∈{0,1}×{0,1}×{0,1}×{0,1}\n",
" print(f\"{a} {b} {c} {d} | {a+2*b} {c+2*d} | {BIG2(a,b,c,d)}\")"
]
},
{
"cell_type": "code",
"execution_count": 134,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"image/svg+xml": [
"\r\n",
"\r\n",
"\r\n",
"\r\n",
"\r\n"
],
"text/plain": [
""
]
},
"execution_count": 134,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"nandcircuit(BIG2)"
]
},
{
"cell_type": "code",
"execution_count": 135,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"image/svg+xml": [
"\r\n",
"\r\n",
"\r\n",
"\r\n",
"\r\n"
],
"text/plain": [
""
]
},
"execution_count": 135,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"nandcircuit(BIG2,pruneit=True)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Getting the code and syntactic sugar"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"def NOT(a): return NAND(a,a)\n",
"def OR(a,b): return NAND(NOT(a),NOT(b))\n",
"def AND(a,b): return NOT(NAND(a,b))\n",
"\n",
"def BIG2(a,b,c,d): return OR(mystery2(b,d),AND(NOT(mystery2(d,b)),mystery2(a,c)))"
]
},
{
"cell_type": "code",
"execution_count": 136,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"ctr = 0\n",
"def NAND(a,b): \n",
" global ctr\n",
" temp = \"Temp[\"+str(ctr)+\"]\"\n",
" ctr = ctr + 1\n",
" print( temp + \"= NAND(\"+a+\",\"+b+\")\" )\n",
" return temp"
]
},
{
"cell_type": "code",
"execution_count": 137,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Temp[0]= NAND(X[3],X[3])\n",
"Temp[1]= NAND(X[1],Temp[0])\n",
"Temp[2]= NAND(Temp[1],Temp[1])\n",
"Temp[3]= NAND(X[1],X[1])\n",
"Temp[4]= NAND(X[3],Temp[3])\n",
"Temp[5]= NAND(Temp[4],Temp[4])\n",
"Temp[6]= NAND(Temp[5],Temp[5])\n",
"Temp[7]= NAND(X[2],X[2])\n",
"Temp[8]= NAND(X[0],Temp[7])\n",
"Temp[9]= NAND(Temp[8],Temp[8])\n",
"Temp[10]= NAND(Temp[6],Temp[9])\n",
"Temp[11]= NAND(Temp[10],Temp[10])\n",
"Temp[12]= NAND(Temp[2],Temp[2])\n",
"Temp[13]= NAND(Temp[11],Temp[11])\n",
"Temp[14]= NAND(Temp[12],Temp[13])\n"
]
},
{
"data": {
"text/plain": [
"'Temp[14]'"
]
},
"execution_count": 137,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"BIG2(\"X[0]\",\"X[1]\",\"X[2]\",\"X[3]\")"
]
},
{
"cell_type": "code",
"execution_count": 138,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"def NAND(a,b): return 1-a*b"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"print(nandcode(BIG2))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"print(nandcode(BIG2,pruneit=True))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"## IF function (skip)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"def IF(cond,a,b):\n",
" notcond = NAND(cond,cond)\n",
" temp = NAND(b,notcond)\n",
" temp1 = NAND(a,cond)\n",
" return NAND(temp,temp1)\n",
"\n",
"nandcircuit(IF)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"print(nandcode(IF))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"# IF(\"X[0]\",\"X[1]\",\"X[2]\");"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"ctr = 0\n",
"#BIG2(\"X[0]\",\"X[1]\",\"X[2]\",\"X[3]\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Nothing special about NAND"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"__Theorem:__ Let $TOF:\\{0,1\\}^3 \\rightarrow \\{0,1\\}$ defined as \n",
"\n",
"$$TOF(a,b,c) = \\begin{cases} NOT(c) & a=b=1 \\\\ c & \\text{otherwise} \\end{cases} $$\n",
"\n",
" and let $one:\\{0,1\\} \\rightarrow \\{0,1\\}$ be defined as $one(a)=1$.\n",
" \n",
" Then we every NAND program can be transformed to a $(TOF,one)$ program.\n",
" \n",
" __Exercise!__"
]
},
{
"cell_type": "code",
"execution_count": 139,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%%html\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"__Theorem:__ Let $TOF:\\{0,1\\}^3 \\rightarrow \\{0,1\\}$ defined as $TOF(a,b,c) = \\begin{cases} NOT(c) & a=b=1 \\\\ c & \\text{otherwise} \\end{cases}$ and let $ONE:\\{0,1\\} \\rightarrow \\{0,1\\}$ be defined as $ONE(a)=1$. Then we can compute NAND using $(TOF,ONE)$"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"__Proof:__ $NAND(a,b) = TOF(a,b,1)$"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"__Corollary:__ For every NAND program $P$, there is a $(TOF,ONE)$ program $Q$ that computes the same function as P"
]
},
{
"cell_type": "code",
"execution_count": 140,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Temp[0] = TOF(X[3],X[3],ONE(X[0])\n",
"Temp[1] = TOF(X[1],Temp[0],ONE(X[0])\n",
"Temp[2] = TOF(Temp[1],Temp[1],ONE(X[0])\n",
"Temp[3] = TOF(X[1],X[1],ONE(X[0])\n",
"Temp[4] = TOF(X[3],Temp[3],ONE(X[0])\n",
"Temp[5] = TOF(Temp[4],Temp[4],ONE(X[0])\n",
"Temp[6] = TOF(Temp[5],Temp[5],ONE(X[0])\n",
"Temp[7] = TOF(X[2],X[2],ONE(X[0])\n",
"Temp[8] = TOF(X[0],Temp[7],ONE(X[0])\n",
"Temp[9] = TOF(Temp[8],Temp[8],ONE(X[0])\n",
"Temp[10] = TOF(Temp[6],Temp[9],ONE(X[0])\n",
"Temp[11] = TOF(Temp[10],Temp[10],ONE(X[0])\n",
"Temp[12] = TOF(Temp[2],Temp[2],ONE(X[0])\n",
"Temp[13] = TOF(Temp[11],Temp[11],ONE(X[0])\n",
"Y[0] = TOF(Temp[12],Temp[13],ONE(X[0])\n"
]
}
],
"source": [
"# \"Proof by Python\"\n",
"def TOFONE(P):\n",
" Q = P.replace(\"NAND(\",\"TOF(\").replace(\")\",\",ONE(X[0])\")\n",
" return Q\n",
"\n",
"print( TOFONE(nandcode(BIG2)))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Composition\n",
"\n",
"If we have NAND program $P$ to compute $F:\\{0,1\\}^2 \\rightarrow \\{0,1\\}$ then there is NAND program $Q$ to compute $G:\\{0,1\\}^4 \\rightarrow \\{0,1\\}$\n",
"where $G(a,b,c,d) = F(F(a,b),F(c,d))$\n",
"\n",
"Number of lines in $Q$ = $3 \\times$ number of lines in $P$\n",
"\n",
"__Exercise:__ Give 12 line NAND program for $XOR_4:\\{0,1\\}^4 \\rightarrow \\{0,1\\}$."
]
},
{
"cell_type": "code",
"execution_count": 141,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%%html\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Composition\n",
"\n",
"If we have NAND program $P$ to compute $F:\\{0,1\\}^2 \\rightarrow \\{0,1\\}$ then there is NAND program $Q$ to compute $G:\\{0,1\\}^4 \\rightarrow \\{0,1\\}$\n",
"where $G(a,b,c,d) = F(F(a,b),F(c,d))$\n",
"\n",
"Number of lines in $Q$ = $3 \\times$ number of lines in $P$\n",
"\n",
"__Exercise:__ Give 12 line NAND program for $XOR_4:\\{0,1\\}^4 \\rightarrow \\{0,1\\}$."
]
},
{
"cell_type": "code",
"execution_count": 144,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"image/svg+xml": [
"\r\n",
"\r\n",
"\r\n",
"\r\n",
"\r\n"
],
"text/plain": [
""
]
},
"execution_count": 144,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def XOR2(a,b):\n",
" t1 = NAND(a,b)\n",
" t2 = NAND(a,t1)\n",
" t3 = NAND(b,t1)\n",
" return NAND(t2,t3)\n",
"\n",
"def XOR4(a,b,c,d): return XOR2(XOR2(a,b),XOR2(c,d))\n",
"\n",
"nandcircuit(XOR4)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Addition\n",
"\n",
"__Theorem:__ For every $n$, there is a NAND program of at most $100n$ lines that computes $ADD_n:\\{0,1\\}^{2n} \\rightarrow \\{0,1\\}^{n+1}$, which adds two numbers in the binary basis."
]
},
{
"cell_type": "code",
"execution_count": 146,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"[1, 1, 1, 1, 0, 0]"
]
},
"execution_count": 146,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def MAJ(a,b,c): return OR(OR(AND(a,b),AND(b,c)),AND(a,c))\n",
"def ADDONE(a,b,c): return XOR(XOR(a,b),c), MAJ(a,b,c)\n",
"\n",
"def ADD(n,A,B):\n",
" Y = [0]*(n+1)\n",
" carry = zero(A[0])\n",
" for i in range(n):\n",
" Y[i],carry = ADDONE(A[i],B[i],carry)\n",
" Y[n] = carry\n",
" return Y\n",
"\n",
"ADD(5,[0,1,1,0,0],[1,0,0,1,0]) "
]
},
{
"cell_type": "code",
"execution_count": 147,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"image/svg+xml": [
"\r\n",
"\r\n",
"\r\n",
"\r\n",
"\r\n"
],
"text/plain": [
""
]
},
"execution_count": 147,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def add3(a0,a1,a2,b0,b1,b2):\n",
" return ADD(3,[a0,a1,a2],[b0,b1,b2])\n",
"\n",
"nandcircuit(add3,pruneit=True)"
]
},
{
"cell_type": "code",
"execution_count": 149,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"image/svg+xml": [
"\r\n",
"\r\n",
"\r\n",
"\r\n",
"\r\n"
],
"text/plain": [
""
]
},
"execution_count": 149,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def add5(a0,a1,a2,a3,a4,b0,b1,b2,b3,b4):\n",
" return ADD(5,[a0,a1,a2,a3,a4],[b0,b1,b2,b3,b4])\n",
"\n",
"nandcircuit(add5,pruneit=True)"
]
},
{
"cell_type": "code",
"execution_count": 150,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"104"
]
},
"execution_count": 150,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"len(nandcode(add5).split('\\n'))"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Bottom line\n",
"\n",
"1. Can _mathematically define_ the notion of \"Program $P$ computes function $F$\", at least for _finite_ $F$.\n",
"\n",
"2. Can describe finite programs as either _circuits_ or _code_.\n",
"\n",
"3. Even this ultra simple programming language is strong enough to capture interesting algorithms. We can use the ideas of _abstraction_ and _composition_ to build complex programs from simple ones."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Next up\n",
"\n",
"__First Major Theorem:__ For every $F:\\{0,1\\}^n \\rightarrow \\{0,1\\}^m$, there exists a NAND program $P$ that computes $F$."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"__We show:__ There is a program $P$ using $O(\\frac{m\\cdot 2^n}{n})$ operations."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"__Next next lecture:__ There exists _some_ $F:\\{0,1\\}^n \\rightarrow \\{0,1\\}^m$, such that the shortest program $P$ to compute $F$ requires $\\Omega(\\frac{m \\cdot 2^n}{n})$ operations"
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.5"
}
},
"nbformat": 4,
"nbformat_minor": 2
}