Cleaning up docs.

This commit is contained in:
Simon Forman
2018-06-07 12:37:32 -07:00
parent 956d849c8a
commit 507d045a3d
19 changed files with 921 additions and 658 deletions
+198 -126
View File
@@ -4,7 +4,10 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# [Newton's method](https://en.wikipedia.org/wiki/Newton%27s_method)"
"# [Newton's method](https://en.wikipedia.org/wiki/Newton%27s_method)\n",
"Let's use the Newton-Raphson method for finding the root of an equation to write a function that can compute the square root of a number.\n",
"\n",
"Cf. [\"Why Functional Programming Matters\" by John Hughes](https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf)"
]
},
{
@@ -20,13 +23,23 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Cf. [\"Why Functional Programming Matters\" by John Hughes](https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf)"
"## A Generator for Approximations\n",
"\n",
"To make a generator that generates successive approximations lets start by assuming an initial approximation and then derive the function that computes the next approximation:\n",
"\n",
" a F\n",
" ---------\n",
" a'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### A Function to Compute the Next Approximation\n",
"\n",
"This is the equation for computing the next approximate value of the square root:\n",
"\n",
"$a_{i+1} = \\frac{(a_i+\\frac{n}{a_i})}{2}$"
]
},
@@ -34,21 +47,41 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's define a function that computes the above equation:\n",
"\n",
" n a Q\n",
" ---------------\n",
" (a+n/a)/2\n",
"\n",
" n a tuck / + 2 /\n",
" a n over / + 2 /\n",
" a n a / + 2 /\n",
" a n/a + 2 /\n",
" a+n/a 2 /\n",
" (a+n/a)/2\n",
"\n",
"We want it to leave n but replace a, so we execute it with `unary`:\n",
"The function we want has the argument `n` in it:\n",
"\n",
" Q == [tuck / + 2 /] unary"
" F == n over / + 2 /"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Make it into a Generator\n",
"\n",
"Our generator would be created by:\n",
"\n",
" a [dup F] make_generator\n",
"\n",
"With n as part of the function F, but n is the input to the sqrt function were writing. If we let 1 be the initial approximation:\n",
"\n",
" 1 n 1 / + 2 /\n",
" 1 n/1 + 2 /\n",
" 1 n + 2 /\n",
" n+1 2 /\n",
" (n+1)/2\n",
"\n",
"The generator can be written as:\n",
"\n",
" 23 1 swap [over / + 2 /] cons [dup] swoncat make_generator\n",
" 1 23 [over / + 2 /] cons [dup] swoncat make_generator\n",
" 1 [23 over / + 2 /] [dup] swoncat make_generator\n",
" 1 [dup 23 over / + 2 /] make_generator"
]
},
{
@@ -57,125 +90,122 @@
"metadata": {},
"outputs": [],
"source": [
"define('Q == [tuck / + 2 /] unary')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And a function to compute the error:\n",
"\n",
" n a sqr - abs\n",
" |n-a**2|\n",
"\n",
"This should be `nullary` so as to leave both n and a on the stack below the error.\n",
"\n",
" err == [sqr - abs] nullary"
"define('codireco == cons dip rest cons')\n",
"define('make_generator == [codireco] ccons')\n",
"define('ccons == cons cons')"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"define('err == [sqr - abs] nullary')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can define a recursive program that expects a number `n`, an initial estimate `a`, and an epsilon value `ε`, and that leaves on the stack the square root of `n` to within the precision of the epsilon value. (Later on we'll refine it to generate the initial estimate and hard-code an epsilon value.)\n",
"\n",
" n a ε square-root\n",
" -----------------\n",
" √n\n",
"\n",
"\n",
"If we apply the two functions `Q` and `err` defined above we get the next approximation and the error on the stack below the epsilon.\n",
"\n",
" n a ε [Q err] dip\n",
" n a Q err ε \n",
" n a' err ε \n",
" n a' e ε\n",
"\n",
"Let's define the recursive function from here. Start with `ifte`; the predicate and the base case behavior are obvious:\n",
"\n",
" n a' e ε [<] [popop popd] [J] ifte\n",
"\n",
"Base-case\n",
"\n",
" n a' e ε popop popd\n",
" n a' popd\n",
" a'\n",
"\n",
"The recursive branch is pretty easy. Discard the error and recur.\n",
"\n",
" w/ K == [<] [popop popd] [J] ifte\n",
"\n",
" n a' e ε J\n",
" n a' e ε popd [Q err] dip [K] i\n",
" n a' ε [Q err] dip [K] i\n",
" n a' Q err ε [K] i\n",
" n a'' e ε K\n",
"\n",
"This fragment alone is pretty useful."
"define('gsra == 1 swap [over / + 2 /] cons [dup] swoncat make_generator')"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"define('K == [<] [popop popd] [popd [Q err] dip] primrec')"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5.000000232305737\n"
"[1 [dup 23 over / + 2 /] codireco]\n"
]
}
],
"source": [
"J('25 10 0.001 dup K')"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5.000000000000005\n"
]
}
],
"source": [
"J('25 10 0.000001 dup K')"
"J('23 gsra')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So now all we need is a way to generate an initial approximation and an epsilon value:\n",
"Let's drive the generator a few time (with the `x` combinator) and square the approximation to see how well it works..."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"23.0000000001585\n"
]
}
],
"source": [
"J('23 gsra 6 [x popd] times first sqr')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Finding Consecutive Approximations within a Tolerance\n",
"\n",
" square-root == dup 3 / 0.000001 dup K"
"\n",
"> The remainder of a square root finder is a function _within_, which takes a tolerance and a list of approximations and looks down the list for two successive approximations that differ by no more than the given tolerance.\n",
"\n",
"From [\"Why Functional Programming Matters\" by John Hughes](https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf)\n",
"\n",
"(And note that by “list” he means a lazily-evaluated list.)\n",
"\n",
"Using the _output_ `[a G]` of the above generator for square root approximations, and further assuming that the first term a has been generated already and epsilon ε is handy on the stack...\n",
"\n",
" a [b G] ε within\n",
" ---------------------- a b - abs ε <=\n",
" b\n",
"\n",
"\n",
" a [b G] ε within\n",
" ---------------------- a b - abs ε >\n",
" b [c G] ε within\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Predicate\n",
"\n",
" a [b G] ε [first - abs] dip <=\n",
" a [b G] first - abs ε <=\n",
" a b - abs ε <=\n",
" a-b abs ε <=\n",
" abs(a-b) ε <=\n",
" (abs(a-b)<=ε)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"define('_within_P == [first - abs] dip <=')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Base-Case\n",
"\n",
" a [b G] ε roll< popop first\n",
" [b G] ε a popop first\n",
" [b G] first\n",
" b"
]
},
{
@@ -184,61 +214,103 @@
"metadata": {},
"outputs": [],
"source": [
"define('square-root == dup 3 / 0.000001 dup K')"
"define('_within_B == roll< popop first')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Recur\n",
"\n",
" a [b G] ε R0 [within] R1\n",
"\n",
"1. Discard a.\n",
"2. Use x combinator to generate next term from G.\n",
"3. Run within with `i` (it is a `primrec` function.)\n",
"\n",
"Pretty straightforward:\n",
"\n",
" a [b G] ε R0 [within] R1\n",
" a [b G] ε [popd x] dip [within] i\n",
" a [b G] popd x ε [within] i\n",
" [b G] x ε [within] i\n",
" b [c G] ε [within] i\n",
" b [c G] ε within\n",
"\n",
" b [c G] ε within"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"6.000000000000007\n"
]
}
],
"outputs": [],
"source": [
"J('36 square-root')"
"define('_within_R == [popd x] dip')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Setting up\n",
"\n",
"The recursive function we have defined so far needs a slight preamble: `x` to prime the generator and the epsilon value to use:\n",
"\n",
" [a G] x ε ...\n",
" a [b G] ε ..."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2212475.6192184356\n"
]
}
],
"outputs": [],
"source": [
"J('4895048365636 square-root')"
"define('within == x 0.000000001 [_within_P] [_within_B] [_within_R] primrec')\n",
"define('sqrt == gsra within')"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"4.795831523312719\n"
]
}
],
"source": [
"J('23 sqrt')"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"4895048365636.0"
"22.999999999999996"
]
},
"execution_count": 10,
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"2212475.6192184356 * 2212475.6192184356"
"4.795831523312719**2"
]
}
],