4 "cell_type": "markdown",
7 "# [Newton's method](https://en.wikipedia.org/wiki/Newton%27s_method)\n",
8 "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",
10 "Cf. [\"Why Functional Programming Matters\" by John Hughes](https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf)"
14 "cell_type": "markdown",
17 "## A Generator for Approximations\n",
19 "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",
27 "cell_type": "markdown",
30 "### A Function to Compute the Next Approximation\n",
32 "This is the equation for computing the next approximate value of the square root:\n",
34 "$a_{i+1} = \\frac{(a_i+\\frac{n}{a_i})}{2}$"
38 "cell_type": "markdown",
41 "Starting with $\\frac{(a_i+\\frac{n}{a_i})}{2}$ we can derive the Joy expression to compute it using abstract dummy variables to stand in for actual values. First undivide by two:\n",
43 "$(a_i+\\frac{n}{a_i})$ `2 /`"
47 "cell_type": "markdown",
50 "Then unadd terms:\n",
52 "$a_i$ $\\frac{n}{a_i}$ `+ 2 /`"
56 "cell_type": "markdown",
61 "$a_i$ $n$ $a_i$ `/ + 2 /`"
65 "cell_type": "markdown",
68 "Finally deduplicate the $a_i$ term:\n",
70 "$a_i$ $n$ `over / + 2 /`"
74 "cell_type": "markdown",
77 "Let's try out this function `over / + 2 /` on an example:\n",
89 "output_type": "stream",
94 "[F over / + 2 /] inscribe"
98 "cell_type": "markdown",
101 "In order to use this function `F` we have to provide an initial estimate for the value of the square root, and we want to keep the input value `n` handy for iterations (we don't want the user to have to keep reentering it.)"
106 "execution_count": 2,
111 "output_type": "stream",
114 " 5 36 • over / + 2 /\n",
115 "5 36 5 • / + 2 /\n",
132 "cell_type": "markdown",
135 "The initial estimate can be 2, and we can `cons` the input value onto a quote with `F`:"
140 "execution_count": 3,
145 "output_type": "stream",
152 "[F1 2 swap [F] cons] inscribe"
157 "execution_count": 4,
162 "output_type": "stream",
165 " 36 • 2 swap [F] cons\n",
166 " 36 2 • swap [F] cons\n",
167 " 2 36 • [F] cons\n",
183 "execution_count": 5,
188 "output_type": "stream",
192 " 2 36 • over / + 2 /\n",
193 "2 36 2 • / + 2 /\n",
209 "execution_count": 6,
214 "output_type": "stream",
226 "execution_count": 7,
231 "output_type": "stream",
241 "execution_count": 8,
246 "output_type": "stream",
248 "[2 [36 F] codireco]"
253 "36 F1 make_generator"
258 "execution_count": 9,
263 "output_type": "stream",
275 "execution_count": 10,
280 "output_type": "stream",
287 "144 F1 make_generator x x x x first"
292 "execution_count": 11,
297 "output_type": "stream",
311 "execution_count": 12,
318 "output_type": "stream",
325 "[first] [pop sqr] fork - abs 3 <"
330 "execution_count": 13,
335 "output_type": "stream",
347 "execution_count": 14,
354 "output_type": "stream",
361 "[36 F] [first] [pop sqr] fork - abs 3 <"
366 "execution_count": 15,
371 "output_type": "stream",
383 "execution_count": 16,
390 "output_type": "stream",
397 "[36 F] [first] [pop sqr] fork - abs 3 <"
402 "execution_count": null,
409 "execution_count": 17,
414 "output_type": "stream",
428 "execution_count": 18,
433 "output_type": "stream",
440 "[] true [i [36 F] [first] [pop sqr] fork - abs 3 >] loop pop"
445 "execution_count": 19,
450 "output_type": "stream",
459 "7 [] true [i [144 F] [first] [pop sqr] fork - abs 3 >] loop pop"
464 "execution_count": 20,
469 "output_type": "stream",
478 "7 [] true [i [14400 F] [first] [pop sqr] fork - abs 3 >] loop pop"
482 "cell_type": "markdown",
485 "broken due to no float div\n",
489 " 7 [] true [i [1000 F] [first] [pop sqr] fork - abs 10 >] loop pop"
493 "cell_type": "markdown",
496 "### Make it into a Generator\n",
498 "Our generator would be created by:\n",
500 " a [dup F] make_generator\n",
502 "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",
510 "The generator can be written as:\n",
512 " 23 1 swap [over / + 2 /] cons [dup] swoncat make_generator\n",
513 " 1 23 [over / + 2 /] cons [dup] swoncat make_generator\n",
514 " 1 [23 over / + 2 /] [dup] swoncat make_generator\n",
515 " 1 [dup 23 over / + 2 /] make_generator"
520 "execution_count": null,
526 "define('gsra 1 swap [over / + 2 /] cons [dup] swoncat make_generator')"
531 "execution_count": null,
539 "cell_type": "markdown",
542 "Let's drive the generator a few time (with the `x` combinator) and square the approximation to see how well it works..."
547 "execution_count": null,
551 "J('23 gsra 6 [x popd] times first sqr')"
555 "cell_type": "markdown",
558 "## Finding Consecutive Approximations within a Tolerance\n",
560 "From [\"Why Functional Programming Matters\" by John Hughes](https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf):\n",
563 "> 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",
565 "(And note that by “list” he means a lazily-evaluated list.)\n",
567 "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",
569 " a [b G] ε within\n",
570 " ---------------------- a b - abs ε <=\n",
574 " a [b G] ε within\n",
575 " ---------------------- a b - abs ε >\n",
576 " b [c G] ε within\n",
581 "cell_type": "markdown",
586 " a [b G] ε [first - abs] dip <=\n",
587 " a [b G] first - abs ε <=\n",
596 "execution_count": null,
600 "define('_within_P [first - abs] dip <=')"
604 "cell_type": "markdown",
609 " a [b G] ε roll< popop first\n",
610 " [b G] ε a popop first\n",
617 "execution_count": null,
621 "define('_within_B roll< popop first')"
625 "cell_type": "markdown",
630 " a [b G] ε R0 [within] R1\n",
633 "2. Use `x` combinator to generate next term from `G`.\n",
634 "3. Run `within` with `i` (it is a \"tail-recursive\" function.)\n",
636 "Pretty straightforward:\n",
638 " a [b G] ε R0 [within] R1\n",
639 " a [b G] ε [popd x] dip [within] i\n",
640 " a [b G] popd x ε [within] i\n",
641 " [b G] x ε [within] i\n",
642 " b [c G] ε [within] i\n",
643 " b [c G] ε within\n",
650 "execution_count": null,
654 "define('_within_R [popd x] dip')"
658 "cell_type": "markdown",
663 "The recursive function we have defined so far needs a slight preamble: `x` to prime the generator and the epsilon value to use:\n",
671 "execution_count": null,
675 "define('within x 0.000000001 [_within_P] [_within_B] [_within_R] tailrec')\n",
676 "define('sqrt gsra within')"
680 "cell_type": "markdown",
688 "execution_count": null,
699 "execution_count": null,
709 "cell_type": "markdown",
717 "execution_count": null,
723 "4.795831523312719**2"
728 "execution_count": null,
732 "from math import sqrt\n",
740 "display_name": "Joypy",
745 "file_extension": ".joy",
746 "mimetype": "text/plain",