diff --git a/.gitignore b/.gitignore index c2658d7..bf76261 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules/ +.* +lib/test.lam diff --git a/__pycache__/nodes.cpython-36.pyc b/__pycache__/nodes.cpython-36.pyc new file mode 100644 index 0000000..1fa8599 Binary files /dev/null and b/__pycache__/nodes.cpython-36.pyc differ diff --git a/debug.txt b/debug.txt new file mode 100644 index 0000000..4c76ee0 --- /dev/null +++ b/debug.txt @@ -0,0 +1,657 @@ + +4 +50 4 +0 4 2 1 4 +1 0 40 12 4 +2 26 13 21 4 +3 6 9 22 4 +4 13 18 17 0 +5 42 10 14 4 +6 28 41 8 4 +7 24 64 36 4 +8 50 37 45 4 +9 30 33 46 4 +10 5 25 20 8 +11 66 34 38 4 +12 52 65 32 4 +13 48 88 60 4 +14 74 61 69 4 +15 54 57 70 4 +16 29 49 44 16 +17 90 58 62 4 +18 76 89 56 4 +19 72 112 84 4 +20 98 85 93 4 +21 78 81 94 4 +22 53 73 68 24 +23 114 82 86 4 +24 100 113 80 4 +25 96 136 108 4 +26 122 109 117 4 +27 102 105 118 4 +28 77 97 92 32 +29 138 106 110 4 +30 124 137 104 4 +31 120 160 132 4 +32 146 133 141 4 +33 126 129 142 4 +34 101 121 116 40 +35 162 130 134 4 +36 148 161 128 4 +37 144 184 156 4 +38 170 157 165 4 +39 150 153 166 4 +40 125 145 140 48 +41 186 154 158 4 +42 172 185 152 4 +43 168 208 180 4 +44 194 181 189 4 +45 174 177 190 4 +46 149 169 164 56 +47 210 178 182 4 +48 196 209 176 4 +49 192 212 204 4 +50 197 202 201 0 +51 198 213 214 4 +52 173 193 188 64 +53 197 205 206 4 + +40 + + +25 + + +28 + + +64 +6 7 +10 5 64 20 11 +16 41 49 44 16 +2 36 13 21 4 +9 8 33 46 4 + +49 + + +52 + + +88 +12 13 +16 41 88 44 16 +22 65 73 68 24 +8 60 37 45 4 +15 32 57 70 4 + +73 + + +76 + + +112 +18 19 +22 65 112 68 24 +28 89 97 92 32 +14 84 61 69 4 +21 56 81 94 4 + +97 + + +100 + + +136 +24 25 +28 89 136 92 32 +34 113 121 116 40 +20 108 85 93 4 +27 80 105 118 4 + +121 + + +124 + + +160 +30 31 +34 113 160 116 40 +40 137 145 140 48 +26 132 109 117 4 +33 104 129 142 4 + +145 + + +148 + + +184 +36 37 +40 137 184 140 48 +46 161 169 164 56 +32 156 133 141 4 +39 128 153 166 4 + +169 + + +172 + + +208 +42 43 +46 161 208 164 56 +52 185 193 188 64 +38 180 157 165 4 +45 152 177 190 4 + +193 + + +196 + + +212 +48 49 +52 185 212 188 64 +53 209 205 206 4 +44 204 181 189 4 +51 176 213 214 4 + +205 + + +176 + + +181 +51 44 +53 209 181 189 4 +45 152 213 190 4 +47 210 214 182 4 + +152 + + +157 +45 38 +53 209 157 189 4 +39 128 213 166 4 +47 210 214 165 4 +41 186 190 158 4 + +128 + + +133 +39 32 +53 209 133 189 4 +33 104 213 142 4 +41 186 190 141 4 +35 162 166 134 4 + +104 + + +109 +33 26 +53 209 109 189 4 +27 80 213 118 4 +35 162 166 117 4 +29 138 142 110 4 + +80 + + +85 +27 20 +53 209 85 189 4 +21 56 213 94 4 +29 138 142 93 4 +23 114 118 86 4 + +56 + + +61 +21 14 +53 209 61 189 4 +15 32 213 70 4 +23 114 118 69 4 +17 90 94 62 4 + +32 + + +37 +15 8 +53 209 37 189 4 +9 8 213 46 4 +17 90 94 45 4 +11 66 70 38 4 + +8 + + +13 +9 2 +53 209 13 189 4 +3 6 213 22 4 +11 66 70 21 4 +5 42 46 14 4 + +6 + + +0 + + +210 + + +185 + + +161 + + +137 + + +113 + + +89 + + +65 + + +41 + + +5 + + +0 + + +214 + + +209 + + +185 + + +161 + + +137 + + +113 + + +89 + + +65 + + +41 + + +5 + + +0 + + +186 + + +161 + + +137 + + +113 + + +89 + + +65 + + +41 + + +5 + + +0 + + +190 + + +210 + + +185 + + +161 + + +137 + + +113 + + +89 + + +65 + + +41 + + +5 + + +0 + + +162 + + +137 + + +113 + + +89 + + +65 + + +41 + + +5 + + +0 + + +166 + + +186 + + +161 + + +137 + + +113 + + +89 + + +65 + + +41 + + +5 + + +0 + + +138 + + +113 + + +89 + + +65 + + +41 + + +5 + + +0 + + +142 + + +162 + + +137 + + +113 + + +89 + + +65 + + +41 + + +5 + + +0 + + +114 + + +89 + + +65 + + +41 + + +5 + + +0 + + +118 + + +138 + + +113 + + +89 + + +65 + + +41 + + +5 + + +0 + + +90 + + +65 + + +41 + + +5 + + +0 + + +94 + + +114 + + +89 + + +65 + + +41 + + +5 + + +0 + + +66 + + +41 + + +5 + + +0 + + +70 + + +90 + + +65 + + +41 + + +5 + + +0 + + +42 + + +5 + + +0 + + +46 + + +66 + + +41 + + +5 + + +0 + + +6 + + +0 + + +213 + + +209 + + +185 + + +161 + + +137 + + +113 + + +89 + + +65 + + +41 + + +5 + + +0 + + +42 + + +5 + + +0 + diff --git a/nodes.py b/nodes.py new file mode 100644 index 0000000..2278f31 --- /dev/null +++ b/nodes.py @@ -0,0 +1,58 @@ +class Nodes: + + def __init__(self): + self.nodes = [] + self.steps = [] + self.read('debug.txt') + self.cur_index = 0 + self.cur_nodes = {i: self.nodes[i] for i in self.steps[0]['mnodes'] if not i in self.steps[0]['rnodes']} + + def __len__(self): + return len(self.steps) + + def __getitem__(self, index): + if index > self.cur_index: + add, mnodes, rnodes = 1, 'mnodes', 'rnodes' + else: + add, mnodes, rnodes = -1, 'rnodes', 'mnodes' + + while self.cur_index != index: + if add == 1: self.cur_index += 1 + for i in self.steps[self.cur_index][mnodes]: + self.cur_nodes[i] = self.nodes[i] + for i in self.steps[self.cur_index][rnodes]: + del self.cur_nodes[i] + if add == -1: self.cur_index -= 1 + return (self.steps[self.cur_index]['gonext'], self.cur_nodes) + + + def read(self, fileName): + maxid = -1 + ndids = [] + with open(fileName, 'r') as file: + lines = iter(file.readlines()) + lines.__next__() + while True: + try: + gonext = int(lines.__next__()) + except StopIteration: + break + remove = [int(i) for i in lines.__next__().split()] + self.steps.append({'gonext': gonext, 'mnodes': [], 'rnodes': []}) + for line in lines: + if line == '\n': break + line = [int(i) for i in line.split()] + maxid += 1 + self.nodes.append(line) + self.steps[-1]['mnodes'].append(maxid) + if len(ndids) > line[0]: + if ndids[line[0]] != -1: + self.steps[-1]['rnodes'].append(ndids[line[0]]) + ndids[line[0]] = -1 + ndids[line[0]] = maxid + else: + ndids.append(maxid) + for indx in remove: + if ndids[indx] != -1: + self.steps[-1]['rnodes'].append(ndids[indx]) + ndids[indx] = -1 \ No newline at end of file diff --git a/package.json b/package.json index 980d579..2b8c397 100644 --- a/package.json +++ b/package.json @@ -25,5 +25,7 @@ "url": "https://github.com/maiavictor/abstract-algorithm/issues" }, "homepage": "https://github.com/maiavictor/abstract-algorithm#readme", - "dependencies": {} + "dependencies": { + "numjs": "^0.16.0" + } } diff --git a/src/abstract-combinators.js b/src/abstract-combinators.js index 3875bea..c495a4f 100644 --- a/src/abstract-combinators.js +++ b/src/abstract-combinators.js @@ -3,27 +3,30 @@ function port(node, slot) { } function node(port) { - return port >>> 2; + return port >> 2; } function slot(port) { return port & 3; } -function newNet(nodes) { +function newNet() { return { - nodes: nodes || [], + debug: null, + gonxt: 0, + nodes: [], reuse: [], stats: {loops:0, rules:0, betas:0, dupls:0, annis:0} }; } function newNode(net, kind) { - var node = net.reuse.pop() || (net.nodes.length / 4); + var node = net.reuse.pop() || (net.nodes.length / 4); net.nodes[node * 4 + 0] = node * 4 + 0; net.nodes[node * 4 + 1] = node * 4 + 1; net.nodes[node * 4 + 2] = node * 4 + 2; net.nodes[node * 4 + 3] = kind << 2; + if(net.debug) { net.debug.nodes.add(node); net.debug.rmove.delete(node) } return node; } @@ -32,59 +35,67 @@ function enterPort(net, w) { } function kind(net, node) { - return net.nodes[node * 4 + 3] >>> 2; + return net.nodes[node * 4 + 3] >>> 2; } function exit(net, node) { - return (net.nodes[node * 4 + 3] >>> 0) & 3; + return (net.nodes[node * 4 + 3] >>> 0) & 3; } function setExit(net, node, exit) { - return net.nodes[node * 4 + 3] = net.nodes[node * 4 + 3] & 0xFFFFFFFC | exit; + return net.nodes[node * 4 + 3] = net.nodes[node * 4 + 3] & 0xFFFFFFFC | exit; } function link(net, a, b) { - net.nodes[a] = b; - net.nodes[b] = a; + net.nodes[a] = b; if (net.debug) net.debug.nodes.add(node(a)) + net.nodes[b] = a; if (net.debug) net.debug.nodes.add(node(b)) +} + +function reuse(net, node) { + net.reuse.push(node); if (net.debug) net.debug.rmove.add(node) } function reduce(net) { var prev, back; var warp = []; - var next = net.nodes[0]; - while (next || warp.length) { - next = next || enterPort(net, port(warp.pop(), 2)); - prev = enterPort(net, next); - next = enterPort(net, prev); - if (slot(next) === 0 && slot(prev) === 0 && node(prev)) { + net.gonxt = net.nodes[0]; + if (net.debug) net.debug.flush(); + while (net.gonxt || warp.length) { + // console.log(JSON.stringify(net.nodes, space=0)); console.log(JSON.stringify(net.reuse, space=0)); + net.gonxt = net.gonxt || enterPort(net, port(warp.pop(), 2)); + prev = enterPort(net, net.gonxt); + net.gonxt = enterPort(net, prev); + if (slot(net.gonxt) === 0 && slot(prev) === 0 && node(prev)) { back = enterPort(net, port(node(prev), exit(net, node(prev)))); - rewrite(net, node(prev), node(next), net.stats); - next = enterPort(net, back); - } else if (slot(next) === 0) { - warp.push(node(next)); - next = enterPort(net, port(node(next), 1)); - setExit(net, node(next), 3); + rewrite(net, node(prev), node(net.gonxt)); + net.gonxt = enterPort(net, back); + } else if (slot(net.gonxt) === 0) { + warp.push(node(net.gonxt)); + net.gonxt = enterPort(net, port(node(net.gonxt), 1)); + setExit(net, node(net.gonxt), 3); } else { - setExit(net, node(next), slot(next)); - next = enterPort(net, port(node(next), 0)); + setExit(net, node(net.gonxt), slot(net.gonxt)); + net.gonxt = enterPort(net, port(node(net.gonxt), 0)); } ++net.stats.loops; + if(net.debug) net.debug.flush() } return net; } function rewrite(net, A, B) { - if (kind(net,A) === kind(net,B)) { + if (kind(net, A) === kind(net, B)) { // 1 2 1 2 // \ / \ / // A == B --> X // / \ / \ // 2 1 2 1 - link(net, enterPort(net, port(A, 1)), enterPort(net, port(B, 1))); - link(net, enterPort(net, port(A, 2)), enterPort(net, port(B, 2))); + link(net, enterPort(net, port(A, 1)), enterPort(net, port(B, 1))); + link(net, enterPort(net, port(A, 2)), enterPort(net, port(B, 2))); net.stats.betas += kind(net, A) === 1 ? 1 : 0; net.stats.annis += 1; - net.reuse.push(A, B); + reuse(net, A); + reuse(net, B) } else { // 1 2 1 = B --- A = 2 // \ / \ / @@ -108,6 +119,12 @@ function rewrite(net, A, B) { net.stats.rules += 1; } +function toJson(net, index) { + var node = { + + } +} + module.exports = { port, node, @@ -119,6 +136,7 @@ module.exports = { exit, setExit, link, + reuse, reduce, rewrite, }; diff --git a/src/lambda-calculus.js b/src/lambda-calculus.js index b421534..336018a 100644 --- a/src/lambda-calculus.js +++ b/src/lambda-calculus.js @@ -77,9 +77,9 @@ const toString = (term, bruijn) => { return go(term, 0); }; -const toNet = term => { +const toNet = (net, term) => { var kind = 1; - var net = I.newNet([0, 2, 1, 4]); + I.newNode(net, kind); I.link(net, 1, 2); var ptr = (function encode(term, scope){ switch (term.tag){ // Arg @@ -114,7 +114,7 @@ const toNet = term => { var [lam,kin] = scope[term.idx]; var arg = I.enterPort(net, I.port(lam,1)); if (I.kind(net, I.node(arg)) === 0) { - net.reuse.push(I.node(arg)); + I.reuse(net, I.node(arg)); return I.port(lam, 1); } else { var dup = I.newNode(net, kin); diff --git a/src/main.js b/src/main.js index fed184d..b66728e 100755 --- a/src/main.js +++ b/src/main.js @@ -3,13 +3,14 @@ var fs = require("fs"); var path = require("path"); var L = require("./lambda-calculus.js"); +var A = require("./abstract-combinators.js"); try { var args = [].slice.call(process.argv, 2); var stats = args.indexOf("-s") !== -1 || args.indexOf("--stats") !== -1; var bruijn = args.indexOf("-b") !== -1 || args.indexOf("--bruijn") !== -1; var nobase = args.indexOf("-n") !== -1 || args.indexOf("--nobase") !== -1; - var dump = args.indexOf("-d") !== -1 || args.indexOf("--dump") !== -1; + var debug = args.indexOf("-d") !== -1 || args.indexOf("--debug") !== -1; var file = args[args.length - 1]; var base = fs.readFileSync(path.join(__dirname, "..", "lib", "base.lam"), "utf8"); var code = fs.readFileSync("./" + (file.indexOf(".") === -1 ? file + ".lam" : file), "utf8"); @@ -34,24 +35,29 @@ try { process.exit(); } -function print(net) { - for (var i=0; i < net.nodes.length; i+=4) { - if (net.reuse.some(x => x === i >> 2)) { - console.log(i>>2); - continue; +var net = A.newNet(); +if (debug) { + fs.writeFileSync('debug.txt', ''); + var file = fs.createWriteStream('debug.txt', {'flags':'a'}); + net.debug = { + rmove: new Set([]), + nodes: new Set([]), + flush: () => { + file.write(`\n${net.gonxt}\n`); + net.debug.rmove.forEach( i => file.write(`${i} `)); file.write('\n'); + net.debug.nodes.forEach( i => file.write(`${i} ${net.nodes[i*4+0]} ${net.nodes[i*4+1]} ${net.nodes[i*4+2]} ${net.nodes[i*4+3]}\n`)); + net.debug.nodes.clear() + net.debug.rmove.clear(); } - [a,b,c,d] = net.nodes.slice(i, i+4); - console.log(i>>2, `${a>>2}:${a&3} ${b>>2}:${b&3} ${c>>2}:${c&3} ${d>>2}:${d&3}`); } } var start = Date.now(); -var net = L.toNet(L.fromString(nobase ? code : base + " " + code)); -if (dump) { print(net); } +var net = L.toNet(net, L.fromString(nobase ? code : base + " " + code)); var net = L.net.reduce(net); -if (dump) { print(net); } -var result = {term: L.toString(L.fromNet(net), bruijn), stats: net.stats}; -var time = Date.now() - start; +var result = { term: L.toString(L.fromNet(net), bruijn), stats: net.stats }; + +if (debug) file.end('') console.log(result.term); if (stats) { diff --git a/visualization.ipynb b/visualization.ipynb new file mode 100644 index 0000000..d2c205e --- /dev/null +++ b/visualization.ipynb @@ -0,0 +1,241 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import networkx as nx\n", + "import matplotlib.pyplot as plt\n", + "from matplotlib.widgets import Slider\n", + "from networkx.drawing.nx_agraph import graphviz_layout\n", + "import ipywidgets as widgets" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "from nodes import Nodes" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "nodess = Nodes()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "86b44f9caf9f412ab359ac4229b11489", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(IntSlider(value=89, description='iteration', max=179), Output()), _dom_classes=('widget-…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "_, nodes = nodess[0]\n", + "\n", + "ports = [(node[0], t >> 2) for node in nodes.values() for t in node[1:4]]\n", + "\n", + "G = nx.DiGraph()\n", + "G.add_edges_from(ports)\n", + "pos = graphviz_layout(G)\n", + "\n", + "@widgets.interact(iteration=(0, len(nodess)-1,1))\n", + "def draw(iteration):\n", + " gonxt, nodes = nodess[iteration]\n", + "\n", + " ports = [(node[0], t >> 2) for node in nodes.values() for t in node[1:4]]\n", + " types = [ node[4] >> 2 for node in nodes.values() ]\n", + "\n", + " plt.figure(figsize=(10,10))\n", + " \n", + " G = nx.DiGraph()\n", + " G.add_edges_from(ports)\n", + "# pos = graphviz_layout(G) #comment this line if you don't want to create new layout each iteration\n", + " \n", + " nx.draw_networkx_nodes(G, pos, cmap=plt.get_cmap('jet'), alpha=0.0, node_size = 500)\n", + " nx.draw_networkx_nodes(G, pos, nodelist=[gonxt >> 2], alpha=1, node_size = 500)\n", + " nx.draw_networkx_labels(G, pos)\n", + " nx.draw_networkx_edges(G, pos, edgelist=ports[0:-1:3], alpha=.5, edge_color='red', width=4)\n", + " nx.draw_networkx_edges(G, pos, edgelist=ports[1:-1:3], alpha=.5, edge_color='blue', width=4)\n", + " nx.draw_networkx_edges(G, pos, edgelist=ports[2:-1:3], alpha=.5, edge_color='grey', width=3)\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on function graphviz_layout in module networkx.drawing.nx_agraph:\n", + "\n", + "graphviz_layout(G, prog='neato', root=None, args='')\n", + " Create node positions for G using Graphviz.\n", + " \n", + " Parameters\n", + " ----------\n", + " G : NetworkX graph\n", + " A graph created with NetworkX\n", + " prog : string\n", + " Name of Graphviz layout program\n", + " root : string, optional\n", + " Root node for twopi layout\n", + " args : string, optional\n", + " Extra arguments to Graphviz layout program\n", + " \n", + " Returns : dictionary\n", + " Dictionary of x, y, positions keyed by node.\n", + " \n", + " Examples\n", + " --------\n", + " >>> G = nx.petersen_graph()\n", + " >>> pos = nx.nx_agraph.graphviz_layout(G)\n", + " >>> pos = nx.nx_agraph.graphviz_layout(G, prog='dot')\n", + " \n", + " Notes\n", + " -----\n", + " This is a wrapper for pygraphviz_layout.\n", + "\n" + ] + } + ], + "source": [ + "help(graphviz_layout)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "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.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}