Update some of the docs.

This commit is contained in:
Simon Forman
2020-05-20 19:15:47 -07:00
parent 6a6b63bf62
commit ffabda0407
60 changed files with 5182 additions and 5853 deletions
+112 -106
View File
@@ -4,7 +4,7 @@ Advent of Code 2017
December 5th
------------
a list of the offsets for each jump. Jumps are relative: -1 moves to
...a list of the offsets for each jump. Jumps are relative: -1 moves to
the previous instruction, and 2 skips the next one. Start at the first
instruction in the list. The goal is to follow the jumps until one leads
outside the list.
@@ -18,13 +18,13 @@ For example, consider the following list of jump offsets:
::
0
3
0
1
-3
0
3
0
1
-3
Positive jumps (forward) move downward; negative jumps move upward.
Positive jumps ("forward") move downward; negative jumps move upward.
For legibility in this example, these offset values will be written all
on one line, with the current instruction marked in parentheses. The
following steps would be taken before an exit is found:
@@ -35,24 +35,14 @@ following steps would be taken before an exit is found:
-
(1) 3 0 1 -3 - jump with offset 0 (that is, dont jump at all).
(1) 3 0 1 -3 - jump with offset 0 (that is, don't jump at all).
Fortunately, the instruction is then incremented to 1.
- ::
2 (3) 0 1 -3 - step forward because of the instruction we just modified. The first instruction is incremented again, now to 2.
- ::
2 4 0 1 (-3) - jump all the way to the end; leave a 4 behind.
- ::
2 (4) 0 1 -2 - go back to where we just were; increment -3 to -2.
- ::
2 5 0 1 -2 - jump 4 steps forward, escaping the maze.
- 2 (3) 0 1 -3 - step forward because of the instruction we just
modified. The first instruction is incremented again, now to 2.
- 2 4 0 1 (-3) - jump all the way to the end; leave a 4 behind.
- 2 (4) 0 1 -2 - go back to where we just were; increment -3 to -2.
- 2 5 0 1 -2 - jump 4 steps forward, escaping the maze.
In this example, the exit is reached in 5 steps.
@@ -61,7 +51,7 @@ How many steps does it take to reach the exit?
Breakdown
---------
For now, Im going to assume a starting state with the size of the
For now, I'm going to assume a starting state with the size of the
sequence pre-computed. We need it to define the exit condition and it is
a trivial preamble to generate it. We then need and ``index`` and a
``step-count``, which are both initially zero. Then we have the sequence
@@ -69,69 +59,69 @@ itself, and some recursive function ``F`` that does the work.
::
size index step-count [...] F
-----------------------------------
step-count
size index step-count [...] F
-----------------------------------
step-count
F == [P] [T] [R1] [R2] genrec
F == [P] [T] [R1] [R2] genrec
Later on I was thinking about it and the Forth heuristic came to mind,
to wit: four things on the stack are kind of much. Immediately I
realized that the size properly belongs in the predicate of ``F``! Doh!
realized that the size properly belongs in the predicate of ``F``! D'oh!
::
index step-count [...] F
------------------------------
step-count
index step-count [...] F
------------------------------
step-count
So, lets start by nailing down the predicate:
So, let's start by nailing down the predicate:
::
F == [P] [T] [R1] [R2] genrec
== [P] [T] [R1 [F] R2] ifte
F == [P] [T] [R1] [R2] genrec
== [P] [T] [R1 [F] R2] ifte
0 0 [0 3 0 1 -3] popop 5 >=
0 0 [0 3 0 1 -3] popop 5 >=
P == popop 5 >=
P == popop 5 >=
Now we need the else-part:
::
index step-count [0 3 0 1 -3] roll< popop
index step-count [0 3 0 1 -3] roll< popop
E == roll< popop
E == roll< popop
Last but not least, the recursive branch
::
0 0 [0 3 0 1 -3] R1 [F] R2
0 0 [0 3 0 1 -3] R1 [F] R2
The ``R1`` function has a big job:
::
R1 == get the value at index
increment the value at the index
add the value gotten to the index
increment the step count
R1 == get the value at index
increment the value at the index
add the value gotten to the index
increment the step count
The only tricky thing there is incrementing an integer in the sequence.
Joy sequences are not particularly good for random access. We could
encode the list of jump offsets in a big integer and use math to do the
processing for a good speed-up, but it still wouldnt beat the
performance of e.g. a mutable array. This is just one of those places
where plain vanilla Joypy doesnt shine (in default performance. The
processing for a good speed-up, but it still wouldn't beat the
performance of e.g. a mutable array. This is just one of those places
where "plain vanilla" Joypy doesn't shine (in default performance. The
legendary *Sufficiently-Smart Compiler* would of course rewrite this
function to use an array under the hood.)
function to use an array "under the hood".)
In the meantime, Im going to write a primitive function that just does
In the meantime, I'm going to write a primitive function that just does
what we need.
.. code:: ipython2
.. code:: ipython3
from notebook_preamble import D, J, V, define
from joy.library import SimpleFunctionWrapper
@@ -161,7 +151,7 @@ what we need.
D['incr_at'] = incr_at
.. code:: ipython2
.. code:: ipython3
J('3 [0 1 2 3 4 5] incr_at')
@@ -176,74 +166,90 @@ get the value at index
::
3 0 [0 1 2 3 4] [roll< at] nullary
3 0 [0 1 2 n 4] n
3 0 [0 1 2 3 4] [roll< at] nullary
3 0 [0 1 2 n 4] n
increment the value at the index
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
3 0 [0 1 2 n 4] n [Q] dip
3 0 [0 1 2 n 4] Q n
3 0 [0 1 2 n 4] [popd incr_at] unary n
3 0 [0 1 2 n+1 4] n
3 0 [0 1 2 n 4] n [Q] dip
3 0 [0 1 2 n 4] Q n
3 0 [0 1 2 n 4] [popd incr_at] unary n
3 0 [0 1 2 n+1 4] n
add the value gotten to the index
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
3 0 [0 1 2 n+1 4] n [+] cons dipd
3 0 [0 1 2 n+1 4] [n +] dipd
3 n + 0 [0 1 2 n+1 4]
3+n 0 [0 1 2 n+1 4]
3 0 [0 1 2 n+1 4] n [+] cons dipd
3 0 [0 1 2 n+1 4] [n +] dipd
3 n + 0 [0 1 2 n+1 4]
3+n 0 [0 1 2 n+1 4]
increment the step count
~~~~~~~~~~~~~~~~~~~~~~~~
::
3+n 0 [0 1 2 n+1 4] [++] dip
3+n 1 [0 1 2 n+1 4]
3+n 0 [0 1 2 n+1 4] [++] dip
3+n 1 [0 1 2 n+1 4]
All together now
~~~~~~~~~~~~~~~~~
All together now...
~~~~~~~~~~~~~~~~~~~
::
get_value == [roll< at] nullary
incr_value == [[popd incr_at] unary] dip
add_value == [+] cons dipd
incr_step_count == [++] dip
get_value == [roll< at] nullary
incr_value == [[popd incr_at] unary] dip
add_value == [+] cons dipd
incr_step_count == [++] dip
R1 == get_value incr_value add_value incr_step_count
R1 == get_value incr_value add_value incr_step_count
F == [P] [T] [R1] primrec
F == [P] [T] [R1] primrec
F == [popop !size! >=] [roll< pop] [get_value incr_value add_value incr_step_count] primrec
F == [popop !size! >=] [roll< pop] [get_value incr_value add_value incr_step_count] tailrec
.. code:: ipython2
.. code:: ipython3
from joy.library import DefinitionWrapper
DefinitionWrapper.add_definitions('''
get_value == [roll< at] nullary
incr_value == [[popd incr_at] unary] dip
add_value == [+] cons dipd
incr_step_count == [++] dip
get_value [roll< at] nullary
incr_value [[popd incr_at] unary] dip
add_value [+] cons dipd
incr_step_count [++] dip
AoC2017.5.0 == get_value incr_value add_value incr_step_count
AoC2017.5.0 get_value incr_value add_value incr_step_count
''', D)
.. code:: ipython2
.. code:: ipython3
define('F == [popop 5 >=] [roll< popop] [AoC2017.5.0] primrec')
from joy.library import DefinitionWrapper
DefinitionWrapper.add_definitions('''
get_value [roll< at] nullary
incr_value [[popd incr_at] unary] dip
add_value [+] cons dipd
incr_step_count [++] dip
AoC2017.5.0 get_value incr_value add_value incr_step_count
''', D)
.. code:: ipython2
.. code:: ipython3
define('F [popop 5 >=] [roll< popop] [AoC2017.5.0] tailrec')
.. code:: ipython3
J('0 0 [0 3 0 1 -3] F')
@@ -260,9 +266,9 @@ We want to go from this to this:
::
[...] AoC2017.5.preamble
------------------------------
0 0 [...] [popop n >=]
[...] AoC2017.5.preamble
------------------------------
0 0 [...] [popop n >=]
Where ``n`` is the size of the sequence.
@@ -270,38 +276,38 @@ The first part is obviously ``0 0 roll<``, then ``dup size``:
::
[...] 0 0 roll< dup size
0 0 [...] n
[...] 0 0 roll< dup size
0 0 [...] n
Then:
::
0 0 [...] n [>=] cons [popop] swoncat
0 0 [...] n [>=] cons [popop] swoncat
So:
::
init-index-and-step-count == 0 0 roll<
prepare-predicate == dup size [>=] cons [popop] swoncat
init-index-and-step-count == 0 0 roll<
prepare-predicate == dup size [>=] cons [popop] swoncat
AoC2017.5.preamble == init-index-and-step-count prepare-predicate
AoC2017.5.preamble == init-index-and-step-count prepare-predicate
.. code:: ipython2
.. code:: ipython3
DefinitionWrapper.add_definitions('''
init-index-and-step-count == 0 0 roll<
prepare-predicate == dup size [>=] cons [popop] swoncat
init-index-and-step-count 0 0 roll<
prepare-predicate dup size [>=] cons [popop] swoncat
AoC2017.5.preamble == init-index-and-step-count prepare-predicate
AoC2017.5.preamble init-index-and-step-count prepare-predicate
AoC2017.5 == AoC2017.5.preamble [roll< popop] [AoC2017.5.0] primrec
AoC2017.5 AoC2017.5.preamble [roll< popop] [AoC2017.5.0] tailrec
''', D)
.. code:: ipython2
.. code:: ipython3
J('[0 3 0 1 -3] AoC2017.5')
@@ -313,21 +319,21 @@ So:
::
AoC2017.5 == AoC2017.5.preamble [roll< popop] [AoC2017.5.0] primrec
AoC2017.5 == AoC2017.5.preamble [roll< popop] [AoC2017.5.0] primrec
AoC2017.5.0 == get_value incr_value add_value incr_step_count
AoC2017.5.preamble == init-index-and-step-count prepare-predicate
AoC2017.5.0 == get_value incr_value add_value incr_step_count
AoC2017.5.preamble == init-index-and-step-count prepare-predicate
get_value == [roll< at] nullary
incr_value == [[popd incr_at] unary] dip
add_value == [+] cons dipd
incr_step_count == [++] dip
get_value == [roll< at] nullary
incr_value == [[popd incr_at] unary] dip
add_value == [+] cons dipd
incr_step_count == [++] dip
init-index-and-step-count == 0 0 roll<
prepare-predicate == dup size [>=] cons [popop] swoncat
init-index-and-step-count == 0 0 roll<
prepare-predicate == dup size [>=] cons [popop] swoncat
This is by far the largest program I have yet written in Joy. Even with
the ``incr_at`` function it is still a bear. There may be an arrangement
of the parameters that would permit more elegant definitions, but it
still wouldnt be as efficient as something written in assembly, C, or
still wouldn't be as efficient as something written in assembly, C, or
even Python.