383 lines
8.6 KiB
Plaintext
383 lines
8.6 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# [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)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from notebook_preamble import J, V, define"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## A Generator for Approximations\n",
|
||
"\n",
|
||
"To make a generator that generates successive approximations let’s 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}$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
" 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",
|
||
"The function we want has the argument `n` in it:\n",
|
||
"\n",
|
||
" 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 we’re 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"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {
|
||
"scrolled": true
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"define('gsra 1 swap [over / + 2 /] cons [dup] swoncat make_generator')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"[1 [dup 23 over / + 2 /] codireco]\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"J('23 gsra')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"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": 4,
|
||
"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",
|
||
"From [\"Why Functional Programming Matters\" by John Hughes](https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf):\n",
|
||
"\n",
|
||
"\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",
|
||
"(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": 5,
|
||
"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"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"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 \"tail-recursive\" 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": 7,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"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": 8,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"define('within x 0.000000001 [_within_P] [_within_B] [_within_R] tailrec')\n",
|
||
"define('sqrt gsra within')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Try it out..."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"metadata": {
|
||
"scrolled": true
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"6.0\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"J('36 sqrt')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"metadata": {
|
||
"scrolled": true
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"4.795831523312719\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"J('23 sqrt')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Check it."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"metadata": {
|
||
"scrolled": true
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"22.999999999999996"
|
||
]
|
||
},
|
||
"execution_count": 11,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"4.795831523312719**2"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 12,
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"4.795831523312719"
|
||
]
|
||
},
|
||
"execution_count": 12,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"from math import sqrt\n",
|
||
"\n",
|
||
"sqrt(23)"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Python 2",
|
||
"language": "python",
|
||
"name": "python2"
|
||
},
|
||
"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.8.3"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 2
|
||
}
|