{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Chapter 4: Syntactic Sugar and Computing Every Function\n",
"\n",
"Code related to [Chapter 4: Syntactic Sugar and Computing Every Function](https://introtcs.org/public/lec_03a_computing_every_function.html) in __Introduction to Theoretical Computer Science__ by Boaz Barak. [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/boazbk/tcscode/blob/master/Chap_04_Syntactic_Sugar.ipynb)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!wget https://raw.githubusercontent.com/boazbk/tcscode/master/Utilities.ipynb"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!pip install schemdraw"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# utility code \n",
"%run \"Utilities.ipynb\"\n",
"from IPython.display import clear_output\n",
"clear_output()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## \"Desugar\" \n",
"\n",
"Function that convert a program using syntactic sugar to a program that does not use it"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import re\n",
"def desugar(code, func_name, func_args,func_body):\n",
" \"\"\"\n",
" Replaces all occurences of \n",
" foo = func_name(func_args) \n",
" with\n",
" func_body[x->a,y->b]\n",
" foo = [result returned in func_body] \n",
" \"\"\"\n",
" # Use `search and replace' to replace calls to a function with its code.\n",
" # Uses Python regular expressions to simplify the search and replace,\n",
" # see https://docs.python.org/3/library/re.html\n",
" \n",
" # regular expression for capturing a list of variable names separated by commas\n",
" arglist = \",\".join([r\"([a-zA-Z0-9\\_\\[\\]]+)\" for i in range(len(func_args))])\n",
" # regular expression for capturing a statement of the form\n",
" # \"variable = func_name(arguments)\"\n",
" regexp = fr'([a-zA-Z0-9\\_\\[\\]]+)\\s*=\\s*{func_name}\\({arglist}\\)\\s*$'\n",
" \n",
" while True:\n",
" m = re.search(regexp, code, re.MULTILINE)\n",
" if not m: break\n",
"\n",
" newcode = func_body \n",
"\n",
" # replace function arguments by the variables from the function invocation\n",
" for i in range(len(func_args)): \n",
" newcode = newcode.replace(func_args[i], m.group(i+2))\n",
" \n",
" # Splice the new code inside\n",
" newcode = newcode.replace('return', m.group(1) + \" = \")\n",
" code = code[:m.start()] + newcode + code[m.end()+1:]\n",
"\n",
" return code"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"temp = NAND(x,y)\n",
"z = NAND(y,c)\n",
"temp = NAND(z,x)\n",
"w = NAND(x,c)\n",
"\n"
]
}
],
"source": [
"blah = r'''temp = NAND(a,b)\n",
"return NAND(b,c)\n",
"'''\n",
"\n",
"code = r'''\n",
"z = blah(x,y)\n",
"w = blah(z,x)\n",
"'''\n",
"\n",
"print(desugar(code,\"blah\",['a','b'],blah))"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"def parse_func(code):\n",
" \"\"\"Parse a function definition into name, arguments and body\"\"\"\n",
" lines = [l.strip() for l in code.split('\\n')]\n",
" regexp = r'def\\s+([a-zA-Z\\_0-9]+)\\(([\\sa-zA-Z0-9\\_,]+)\\)\\s*:\\s*'\n",
" m = re.match(regexp,lines[0])\n",
" return m.group(1), m.group(2).split(','), '\\n'.join(lines[1:])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Some examples"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"notfunc = parse_func('''def NOT(a): \n",
" return NAND(a,a)\n",
"''')\n",
"\n",
"andfunc = parse_func('''def AND(a,b):\n",
" temp = NAND(a,b) \n",
" return NOT(temp)\n",
"''')\n",
"\n",
"orfunc = parse_func('''def OR(a,b):\n",
" temp1 = NOT(a)\n",
" temp2 = NOT(b) \n",
" return NAND(temp1,temp2)\n",
"''')\n",
"\n",
"\n",
"majcode= '''and1 = AND(X[0],X[1])\n",
"and2 = AND(X[0],X[2])\n",
"and3 = AND(X[1],X[2])\n",
"or1 = OR(and1,and2)\n",
"Y[0] = OR(or1,and3)\n",
"'''"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"and1 = AND(X[0],X[1])\n",
"and2 = AND(X[0],X[2])\n",
"and3 = AND(X[1],X[2])\n",
"temp1 = NOT(and1)\n",
"temp2 = NOT(and2)\n",
"or1 = NAND(temp1,temp2)\n",
"temp1 = NOT(or1)\n",
"temp2 = NOT(and3)\n",
"Y[0] = NAND(temp1,temp2)\n",
"\n"
]
}
],
"source": [
"tmp = desugar(majcode,*orfunc)\n",
"print(tmp)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"temp = NAND(X[0],X[1])\n",
"and1 = NOT(temp)\n",
"temp = NAND(X[0],X[2])\n",
"and2 = NOT(temp)\n",
"temp = NAND(X[1],X[2])\n",
"and3 = NOT(temp)\n",
"temp1 = NOT(and1)\n",
"temp2 = NOT(and2)\n",
"or1 = NAND(temp1,temp2)\n",
"temp1 = NOT(or1)\n",
"temp2 = NOT(and3)\n",
"Y[0] = NAND(temp1,temp2)\n",
"\n"
]
}
],
"source": [
"tmp = desugar(tmp,*andfunc)\n",
"print(tmp)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"temp = NAND(X[0],X[1])\n",
"and1 = NAND(temp,temp)\n",
"temp = NAND(X[0],X[2])\n",
"and2 = NAND(temp,temp)\n",
"temp = NAND(X[1],X[2])\n",
"and3 = NAND(temp,temp)\n",
"temp1 = NAND(and1,and1)\n",
"temp2 = NAND(and2,and2)\n",
"or1 = NAND(temp1,temp2)\n",
"temp1 = NAND(or1,or1)\n",
"temp2 = NAND(and3,and3)\n",
"Y[0] = NAND(temp1,temp2)\n",
"\n"
]
}
],
"source": [
"tmp = desugar(tmp,*notfunc)\n",
"print(tmp)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\r\n",
"\r\n",
"\r\n",
"\r\n"
],
"text/plain": [
"