Editing Trees; implemented BTree-Delete.

This commit is contained in:
Simon Forman
2018-05-08 08:34:20 -07:00
parent c3a3f5a527
commit aafecdc035
11 changed files with 771 additions and 294 deletions
+552 -37
View File
@@ -133,11 +133,11 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"from notebook_preamble import J, V, define"
"from notebook_preamble import D, J, V, define, DefinitionWrapper"
]
},
{
@@ -906,7 +906,7 @@
},
{
"cell_type": "code",
"execution_count": 30,
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
@@ -917,6 +917,22 @@
"\n",
"@FunctionWrapper\n",
"def cmp_(stack, expression, dictionary):\n",
" '''\n",
" cmp takes two values and three quoted programs on the stack and runs\n",
" one of the three depending on the results of comparing the two values:\n",
"\n",
" a b [G] [E] [L] cmp\n",
" ------------------------- a > b\n",
" G\n",
"\n",
" a b [G] [E] [L] cmp\n",
" ------------------------- a = b\n",
" E\n",
"\n",
" a b [G] [E] [L] cmp\n",
" ------------------------- a < b\n",
" L\n",
" '''\n",
" L, (E, (G, (b, (a, stack)))) = stack\n",
" expression = pushback(G if a > b else L if a < b else E, expression)\n",
" return stack, expression, dictionary\n",
@@ -925,6 +941,55 @@
"D['cmp'] = cmp_"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"from joy.library import FunctionWrapper, S_ifte\n",
"\n",
"\n",
"@FunctionWrapper\n",
"def cond(stack, expression, dictionary):\n",
" '''\n",
" like a case statement; works by rewriting into a chain of ifte.\n",
"\n",
" [..[[Bi] Ti]..[D]] -> ...\n",
"\n",
"\n",
" [[[B0] T0] [[B1] T1] [D]] cond\n",
" -----------------------------------------\n",
" [B0] [T0] [[B1] [T1] [D] ifte] ifte\n",
"\n",
" '''\n",
" conditions, stack = stack\n",
" if conditions:\n",
" expression = _cond(conditions, expression)\n",
" try:\n",
" # Attempt to preload the args to first ifte.\n",
" (P, (T, (E, expression))) = expression\n",
" except ValueError:\n",
" # If, for any reason, the argument to cond should happen to contain\n",
" # only the default clause then this optimization will fail.\n",
" pass\n",
" else:\n",
" stack = (E, (T, (P, stack)))\n",
" return stack, expression, dictionary\n",
"\n",
"\n",
"def _cond(conditions, expression):\n",
" (clause, rest) = conditions\n",
" if not rest: # clause is [D]\n",
" return clause\n",
" P, T = clause\n",
" return (P, (T, (_cond(rest, ()), (S_ifte, expression))))\n",
"\n",
"\n",
"\n",
"D['cond'] = cond"
]
},
{
"cell_type": "code",
"execution_count": 31,
@@ -1415,17 +1480,16 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# TODO: BTree-delete\n",
"# BTree-delete\n",
"\n",
"Then, once we have add, get, and delete we can see about abstracting them.\n",
"\n",
" tree key [E] BTree-delete\n",
" ---------------------------- key in tree\n",
" tree key [Er] BTree-delete\n",
" -------------------------------- key in tree\n",
" tree\n",
"\n",
" tree key [E] BTree-delete\n",
" ---------------------------- key not in tree\n",
" tree key E"
" tree key [Er] BTree-delete\n",
" ---------------------- ------ key not in tree\n",
" tree key Er"
]
},
{
@@ -1434,26 +1498,16 @@
"source": [
"So:\n",
"\n",
" BTree-delete == [pop not] [] [R0] [R1] genrec\n",
"\n",
"And:\n",
"\n",
" [n_key n_value left right] key R0 [BTree-get] R1\n",
" [n_key n_value left right] key [dup first] dip [BTree-get] R1\n",
" [n_key n_value left right] n_key key [BTree-get] R1\n",
" [n_key n_value left right] n_key key [BTree-get] roll> [T>] [E] [T<] cmp\n",
" [n_key n_value left right] [BTree-get] n_key key [T>] [E] [T<] cmp\n",
"\n",
" BTree-delete == [pop not] swap [[dup first] dip] [roll> [T>] [E] [T<] cmp] genrec"
" BTree-Delete == [pop not] swap [R0] [R1] genrec\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" [n_key n_value left right] [BTree-get] T>\n",
" [n_key n_value left right] [BTree-get] E\n",
" [n_key n_value left right] [BTree-get] T<"
" [Er] BTree-delete\n",
" -------------------------------------\n",
" [pop not] [Er] [R0] [R1] genrec"
]
},
{
@@ -1466,32 +1520,493 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": []
"source": [
"Now we get to figure out the recursive case:\n",
"\n",
" w/ D == [pop not] [Er] [R0] [R1] genrec\n",
"\n",
" [node_key node_value left right] key R0 [D] R1\n",
" [node_key node_value left right] key over first swap dup [D] R1\n",
" [node_key node_value left right] node_key key key [D] R1\n",
"\n",
"And then:\n",
"\n",
" [node_key node_value left right] node_key key key [D] R1\n",
" [node_key node_value left right] node_key key key [D] cons roll> [T>] [E] [T<] cmp\n",
" [node_key node_value left right] node_key key [key D] roll> [T>] [E] [T<] cmp\n",
" [node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now this:;\n",
"\n",
" [node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp\n",
"\n",
"Becomes one of these three:;\n",
"\n",
" [node_key node_value left right] [key D] T>\n",
" [node_key node_value left right] [key D] E\n",
" [node_key node_value left right] [key D] T<"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Greater than case and less than case\n",
"\n",
" [node_key node_value left right] [key D] T>\n",
" -------------------------------------------------\n",
" [node_key node_value left key D right]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First:\n",
"\n",
" right left node_value node_key [key D] dipd\n",
" right left key D node_value node_key\n",
" right left' node_value node_key"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ergo:\n",
"\n",
" [node_key node_value left right] [key D] [dipd] cons infra"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So:\n",
"\n",
" T> == [dipd] cons infra\n",
" T< == [dipdd] cons infra"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The else case\n",
"\n",
" [node_key node_value left right] [key D] E\n",
"\n",
"We have to handle three cases, so let's use `cond`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The first two cases are symmetrical, if we only have one non-empty child node return it.\n",
"\n",
" E == [\n",
" [[pop third not] pop fourth]\n",
" [[pop fourth not] pop third]\n",
" [default]\n",
" ] cond"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"(If both child nodes are empty return an empty node.)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The initial structure of the default function:\n",
"\n",
" default == [E'] cons infra\n",
"\n",
" [node_key node_value left right] [key D] default\n",
" [node_key node_value left right] [key D] [E'] cons infra\n",
" [node_key node_value left right] [[key D] E'] infra\n",
"\n",
" right left node_value node_key [key D] E'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If both child nodes are non-empty, we find the highest node in our lower sub-tree, take its key and value to replace (delete) our own, then get rid of it by recursively calling delete() on our lower sub-node with our new key.\n",
"\n",
"(We could also find the lowest node in our higher sub-tree and take its key and value and delete it. I only implemented one of these two symmetrical options. Over a lot of deletions this might make the tree more unbalanced. Oh well.)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First things first, we no longer need this node's key and value:\n",
"\n",
" right left node_value node_key [key D] roll> popop E''\n",
" right left [key D] node_value node_key popop E''\n",
" right left [key D] E''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then we have to we find the highest (right-most) node in our lower (left) sub-tree:\n",
"\n",
" right left [key D] E''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ditch the key:\n",
"\n",
" right left [key D] rest E'''\n",
" right left [D] E'''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Find the right-most node:\n",
"\n",
" right left [D] [dup W] dip E''''\n",
" right left dup W [D] E''''\n",
" right left left W [D] E''''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Consider:\n",
"\n",
" left W"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We know left is not empty:\n",
"\n",
" [L_key L_value L_left L_right] W"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We want to keep extracting the right node as long as it is not empty:\n",
"\n",
" left [P] [B] while W'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The predicate:\n",
"\n",
" [L_key L_value L_left L_right] P\n",
" [L_key L_value L_left L_right] fourth\n",
" L_right\n",
" \n",
"(This has a bug, can run on `[]` so must be guarded:\n",
"\n",
" if_not_empty == [] swap [] ifte\n",
" ?fourth == [fourth] if_not_empty\n",
" W.rightmost == [?fourth] [fourth] while"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The body is also `fourth`:\n",
"\n",
" left [fourth] [fourth] while W'\n",
" rightest W'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We know rightest is not empty:\n",
"\n",
" [R_key R_value R_left R_right] W'\n",
" [R_key R_value R_left R_right] uncons uncons pop\n",
" R_key [R_value R_left R_right] uncons pop\n",
" R_key R_value [R_left R_right] pop\n",
" R_key R_value"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So:\n",
"\n",
" W == [fourth] [fourth] while uncons uncons pop"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And:\n",
"\n",
" right left left W [D] E''''\n",
" right left R_key R_value [D] E''''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Final stretch. We want to end up with something like:\n",
"\n",
" right left [R_key D] i R_value R_key\n",
" right left R_key D R_value R_key\n",
" right left' R_value R_key"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we adjust our definition of `W` to include `over` at the end:\n",
"\n",
" W == [fourth] [fourth] while uncons uncons pop over"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"That will give us:\n",
"\n",
" right left R_key R_value R_key [D] E''''\n",
"\n",
" right left R_key R_value R_key [D] cons dipdd E'''''\n",
" right left R_key R_value [R_key D] dipdd E'''''\n",
" right left R_key D R_key R_value E'''''\n",
" right left' R_key R_value E'''''\n",
" right left' R_key R_value swap\n",
" right left' R_value R_key"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So:\n",
"\n",
" E' == roll> popop E''\n",
"\n",
" E'' == rest E'''\n",
"\n",
" E''' == [dup W] dip E''''\n",
"\n",
" E'''' == cons dipdd swap"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Substituting:\n",
"\n",
" W == [fourth] [fourth] while uncons uncons pop over\n",
" E' == roll> popop rest [dup W] dip cons dipdd swap\n",
" E == [\n",
" [[pop third not] pop fourth]\n",
" [[pop fourth not] pop third]\n",
" [[E'] cons infra]\n",
" ] cond"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Minor rearrangement:\n",
"\n",
" W == dup [fourth] [fourth] while uncons uncons pop over\n",
" E' == roll> popop rest [W] dip cons dipdd swap\n",
" E == [\n",
" [[pop third not] pop fourth]\n",
" [[pop fourth not] pop third]\n",
" [[E'] cons infra]\n",
" ] cond"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Refactoring\n",
"\n",
" W.rightmost == [fourth] [fourth] while\n",
" W.unpack == uncons uncons pop\n",
" E.clear_stuff == roll> popop rest\n",
" E.delete == cons dipdd\n",
" W == dup W.rightmost W.unpack over\n",
" E.0 == E.clear_stuff [W] dip E.delete swap\n",
" E == [\n",
" [[pop third not] pop fourth]\n",
" [[pop fourth not] pop third]\n",
" [[E.0] cons infra]\n",
" ] cond\n",
" T> == [dipd] cons infra\n",
" T< == [dipdd] cons infra\n",
" R0 == over first swap dup\n",
" R1 == cons roll> [T>] [E] [T<] cmp\n",
" BTree-Delete == [pop not] swap [R0] [R1] genrec\n",
"\n",
"By the standards of the code I've written so far, this is a *huge* Joy program."
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": []
"source": [
"DefinitionWrapper.add_definitions('''\n",
"first_two == uncons uncons pop\n",
"fourth == rest rest rest first\n",
"?fourth == [] [fourth] [] ifte\n",
"W.rightmost == [?fourth] [fourth] while\n",
"E.clear_stuff == roll> popop rest\n",
"E.delete == cons dipdd\n",
"W == dup W.rightmost first_two over\n",
"E.0 == E.clear_stuff [W] dip E.delete swap\n",
"E == [[[pop third not] pop fourth] [[pop fourth not] pop third] [[E.0] cons infra]] cond\n",
"T> == [dipd] cons infra\n",
"T< == [dipdd] cons infra\n",
"R0 == over first swap dup\n",
"R1 == cons roll> [T>] [E] [T<] cmp\n",
"BTree-Delete == [pop not] swap [R0] [R1] genrec''', D)"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": []
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['a' 23 [] ['b' 88 [] []]]\n"
]
}
],
"source": [
"J(\"['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' ['Er'] BTree-Delete \")"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": []
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['a' 23 [] ['c' 44 [] []]]\n"
]
}
],
"source": [
"J(\"['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' ['Er'] BTree-Delete \")"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['b' 88 [] ['c' 44 [] []]]\n"
]
}
],
"source": [
"J(\"['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' ['Er'] BTree-Delete \")"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['a' 23 [] ['b' 88 [] ['c' 44 [] 'Er' 'der' []]]]\n"
]
}
],
"source": [
"J(\"['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' ['Er'] BTree-Delete \")"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['a' 23 [] ['b' 88 [] ['c' 44 [] []]]]\n"
]
}
],
"source": [
"J(\"['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' [pop] BTree-Delete \")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"One bug, I forgot to put `not` in the first two clauses of the `cond`.\n",
"\n",
"The behavior of the `[Er]` function should maybe be different: either just silently fail, or maybe implement some sort of function that can grab the pending expression up to a sentinel value or something, allowing for a kind of \"except\"-ish control-flow?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then, once we have add, get, and delete we can see about abstracting them.\n"
]
},
{
"cell_type": "markdown",
@@ -2161,7 +2676,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.13"
"version": "2.7.12"
}
},
"nbformat": 4,