From 42310d9ab1b87a77704e7a2984287e2f98bc0a64 Mon Sep 17 00:00:00 2001 From: David Sanders Date: Mon, 30 Jan 2017 07:22:07 -0500 Subject: [PATCH 01/10] Add basic DAG construction --- src/TreeView.jl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/TreeView.jl b/src/TreeView.jl index 6b7c1e9..26bf477 100644 --- a/src/TreeView.jl +++ b/src/TreeView.jl @@ -6,6 +6,10 @@ using MacroTools export LabelledTree, walk_tree, walk_tree!, draw, @tree, @tree_with_call, tikz_representation +include("dag.jl") +export make_dag + + immutable LabelledTree g::Graph labels::Vector{String} @@ -42,20 +46,20 @@ function walk_tree!(g, labels, ex, show_call=true) top_vertex = add_numbered_vertex!(g) - start_argument = 1 # which argument to start with + where_start = 1 # which argument to start with if !(show_call) && ex.head == :call f = ex.args[1] # the function name push!(labels, label(f)) - start_argument = 2 # drop "call" from tree + where_start = 2 # drop "call" from tree else push!(labels, label(ex.head)) end - for i in start_argument:length(ex.args) + for i in where_start:length(ex.args) if isa(ex.args[i], Expr) From 8b6c4d9bce256a2e729d4ca29f795f2780ddba18 Mon Sep 17 00:00:00 2001 From: David Sanders Date: Mon, 30 Jan 2017 08:28:13 -0500 Subject: [PATCH 02/10] DAG improvements, but gets confused with :block --- src/TreeView.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TreeView.jl b/src/TreeView.jl index 26bf477..c6a5c82 100644 --- a/src/TreeView.jl +++ b/src/TreeView.jl @@ -11,7 +11,7 @@ export make_dag immutable LabelledTree - g::Graph + g::DiGraph labels::Vector{String} end @@ -80,7 +80,7 @@ function walk_tree!(g, labels, ex, show_call=true) end function walk_tree(ex::Expr, show_call=false) - g = Graph() + g = DiGraph() labels = String[] walk_tree!(g, labels, ex, show_call) From af011c8a9785f0d762d0954844767a19e038e37a Mon Sep 17 00:00:00 2001 From: David Sanders Date: Mon, 30 Jan 2017 08:59:17 -0500 Subject: [PATCH 03/10] Working DAGs! --- examples/DAG.ipynb | 431 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 431 insertions(+) create mode 100644 examples/DAG.ipynb diff --git a/examples/DAG.ipynb b/examples/DAG.ipynb new file mode 100644 index 0000000..0b99d85 --- /dev/null +++ b/examples/DAG.ipynb @@ -0,0 +1,431 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "using TreeView" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"\\\\texttt{+}\\\" [],\\n2/\\\"\\\\texttt{x}\\\" [],\\n3/\\\"\\\\texttt{*}\\\" [],\\n4/\\\"\\\\texttt{2}\\\" [],\\n;\\n1 -> [,] 2;\\n1 -> [,] 3;\\n3 -> [,] 2;\\n3 -> [,] 4;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dag = make_dag(:(x + 2x))\n", + "draw(dag)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"\\\\texttt{x}\\\" [],\\n2/\\\"\\\\texttt{+}\\\" [],\\n3/\\\"\\\\texttt{*}\\\" [],\\n4/\\\"\\\\texttt{2}\\\" [],\\n;\\n2 -> [,] 1;\\n2 -> [,] 3;\\n3 -> [,] 1;\\n3 -> [,] 4;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dag = make_dag(\n", + "quote \n", + " a = x\n", + " a + 2a\n", + "end\n", + ")\n", + "\n", + "draw(dag)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + "\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" + ], + "text/plain": [ + "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"\\\\texttt{+}\\\" [],\\n2/\\\"\\\\textasciicircum\\\" [],\\n3/\\\"\\\\texttt{+}\\\" [],\\n4/\\\"\\\\texttt{x}\\\" [],\\n5/\\\"\\\\texttt{y}\\\" [],\\n6/\\\"\\\\texttt{2}\\\" [],\\n7/\\\"\\\\texttt{+}\\\" [],\\n;\\n1 -> [,] 2;\\n1 -> [,] 7;\\n2 -> [,] 3;\\n2 -> [,] 6;\\n3 -> [,] 4;\\n3 -> [,] 5;\\n7 -> [,] 4;\\n7 -> [,] 5;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dag = make_dag(:((x+y)^2 + (x+y)))\n", + "\n", + "draw(dag)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "using CommonSubexpressions" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "quote \n", + " ##+xy#270 = x + y\n", + " ##^##+xy#2702#271 = ##+xy#270 ^ 2\n", + " ##+##^##+xy#2702#271##+xy#270#272 = ##^##+xy#2702#271 + ##+xy#270\n", + " ##+##^##+xy#2702#271##+xy#270#272\n", + "end" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ex = macroexpand(:(@cse (x+y)^2 + (x+y)))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "TreeView.DirectedAcyclicGraph({6, 6} directed graph,Any[:+,:x,:y,:^,2,:+],Dict(:y=>3,Symbol(\"##^##+xy#2702#271\")=>4,:x=>2,Symbol(\"##+xy#270\")=>1,Symbol(\"##+##^##+xy#2702#271##+xy#270#272\")=>6))" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dag2 = make_dag(ex)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"\\\\texttt{+}\\\" [],\\n2/\\\"\\\\texttt{x}\\\" [],\\n3/\\\"\\\\texttt{y}\\\" [],\\n4/\\\"\\\\textasciicircum\\\" [],\\n5/\\\"\\\\texttt{2}\\\" [],\\n6/\\\"\\\\texttt{+}\\\" [],\\n;\\n1 -> [,] 2;\\n1 -> [,] 3;\\n4 -> [,] 1;\\n4 -> [,] 5;\\n6 -> [,] 1;\\n6 -> [,] 4;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "draw(dag2)" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Julia 0.5.0", + "language": "julia", + "name": "julia-0.5" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "0.5.0" + }, + "toc": { + "nav_menu": { + "height": "12px", + "width": "252px" + }, + "navigate_menu": true, + "number_sections": true, + "sideBar": true, + "threshold": "2", + "toc_cell": false, + "toc_section_display": "block", + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 37614651cacde24e9b548cafd474382452abeff8 Mon Sep 17 00:00:00 2001 From: David Sanders Date: Mon, 30 Jan 2017 14:46:38 -0500 Subject: [PATCH 04/10] Rename LabelledTree -> LabelledDigraph --- src/TreeView.jl | 20 ++++++++++---------- test/runtests.jl | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/TreeView.jl b/src/TreeView.jl index c6a5c82..13d6155 100644 --- a/src/TreeView.jl +++ b/src/TreeView.jl @@ -3,16 +3,16 @@ module TreeView using LightGraphs, TikzGraphs using MacroTools -export LabelledTree, walk_tree, walk_tree!, draw, @tree, @tree_with_call, +export LabelledDigraph, walk_tree, walk_tree!, draw, @tree, @tree_with_call, tikz_representation include("dag.jl") export make_dag -immutable LabelledTree +immutable LabelledDigraph g::DiGraph - labels::Vector{String} + labels::Vector{Any} end add_numbered_vertex!(g) = (add_vertex!(g); top = nv(g)) # returns the number of the new vertex @@ -55,7 +55,7 @@ function walk_tree!(g, labels, ex, show_call=true) where_start = 2 # drop "call" from tree else - push!(labels, label(ex.head)) + push!(labels, ex.head) end @@ -70,7 +70,7 @@ function walk_tree!(g, labels, ex, show_call=true) n = add_numbered_vertex!(g) add_edge!(g, top_vertex, n) - push!(labels, label(ex.args[i])) + push!(labels, ex.args[i]) end end @@ -81,26 +81,26 @@ end function walk_tree(ex::Expr, show_call=false) g = DiGraph() - labels = String[] + labels = Any[] walk_tree!(g, labels, ex, show_call) - return LabelledTree(g, labels) + return LabelledDigraph(g, labels) end tikz_representation(tree) = TikzGraphs.plot(tree.g, tree.labels) import Base.show -function show(io::IO, mime::MIME"image/svg+xml", tree::LabelledTree) +function show(io::IO, mime::MIME"image/svg+xml", tree::LabelledDigraph) p = tikz_representation(tree) # TikzPicture object show(io, mime, p) end -function draw(tree::LabelledTree) - TikzGraphs.plot(tree.g, tree.labels) +function draw(tree::LabelledDigraph) + TikzGraphs.plot(tree.g, map(label, tree.labels)) end diff --git a/test/runtests.jl b/test/runtests.jl index 335d7c3..66c4ebd 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,12 +6,12 @@ using Base.Test t = @tree 1x - @test typeof(t) == TreeView.LabelledTree - @test typeof(t.g) == LightGraphs.Graph - @test typeof(t.labels) == Vector{String} + @test typeof(t) == TreeView.LabelledDigraph + @test typeof(t.g) == LightGraphs.DiGraph + @test typeof(t.labels) == Vector{Any} @test t.g.vertices == 1:3 - @test t.labels == String["\\texttt{*}","\\texttt{1}","\\texttt{x}"] + @test t.labels == Any["\\texttt{*}",1,:x] t = @tree x^2 + y^2 @@ -22,5 +22,5 @@ end # Test for issues with the characters present in julia's generated symbols expr = Expr(Symbol("##271")) t = walk_tree(expr) - @test t.labels[1] == "\\texttt{\\#\\#271}" + @test t.labels[1] == Symbol("##271") end From 6f216acafa387f655c8712c958a08003c32a24fa Mon Sep 17 00:00:00 2001 From: David Sanders Date: Mon, 30 Jan 2017 17:17:46 -0500 Subject: [PATCH 05/10] Refactor into separate files --- examples/DAG.ipynb | 119 +++--- examples/TreeView.ipynb | 853 +++++++++++++++++++++++++++++++--------- src/TreeView.jl | 103 +---- test/runtests.jl | 9 +- 4 files changed, 737 insertions(+), 347 deletions(-) diff --git a/examples/DAG.ipynb b/examples/DAG.ipynb index 0b99d85..8c369a6 100644 --- a/examples/DAG.ipynb +++ b/examples/DAG.ipynb @@ -13,11 +13,18 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "labels = String[\"\\\\texttt{+}\",\"\\\\texttt{x}\",\"\\\\texttt{*}\",\"\\\\texttt{2}\"]\n" + ] + }, { "data": { "image/svg+xml": [ @@ -68,26 +75,32 @@ "\n" ], "text/plain": [ - "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"\\\\texttt{+}\\\" [],\\n2/\\\"\\\\texttt{x}\\\" [],\\n3/\\\"\\\\texttt{*}\\\" [],\\n4/\\\"\\\\texttt{2}\\\" [],\\n;\\n1 -> [,] 2;\\n1 -> [,] 3;\\n3 -> [,] 2;\\n3 -> [,] 4;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + "TreeView.DirectedAcyclicGraph({4, 4} directed graph,Any[:+,:x,:*,2],Dict(:x=>2))" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "dag = make_dag(:(x + 2x))\n", - "draw(dag)" + "dag = make_dag(:(x + 2x))" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "labels = String[\"\\\\texttt{x}\",\"\\\\texttt{+}\",\"\\\\texttt{*}\",\"\\\\texttt{2}\"]\n" + ] + }, { "data": { "image/svg+xml": [ @@ -138,33 +151,35 @@ "\n" ], "text/plain": [ - "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"\\\\texttt{x}\\\" [],\\n2/\\\"\\\\texttt{+}\\\" [],\\n3/\\\"\\\\texttt{*}\\\" [],\\n4/\\\"\\\\texttt{2}\\\" [],\\n;\\n2 -> [,] 1;\\n2 -> [,] 3;\\n3 -> [,] 1;\\n3 -> [,] 4;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + "TreeView.DirectedAcyclicGraph({4, 4} directed graph,Any[:x,:+,:*,2],Dict(:x=>1,:a=>1))" ] }, - "execution_count": 3, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "dag = make_dag(\n", - "quote \n", + "dag = @dag begin\n", " a = x\n", " a + 2a\n", - "end\n", - ")\n", - "\n", - "draw(dag)\n", - "\n" + "end" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "labels = String[\"\\\\texttt{+}\",\"\\\\textasciicircum\",\"\\\\texttt{+}\",\"\\\\texttt{x}\",\"\\\\texttt{y}\",\"\\\\texttt{2}\",\"\\\\texttt{+}\"]\n" + ] + }, { "data": { "image/svg+xml": [ @@ -238,24 +253,21 @@ "\n" ], "text/plain": [ - "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"\\\\texttt{+}\\\" [],\\n2/\\\"\\\\textasciicircum\\\" [],\\n3/\\\"\\\\texttt{+}\\\" [],\\n4/\\\"\\\\texttt{x}\\\" [],\\n5/\\\"\\\\texttt{y}\\\" [],\\n6/\\\"\\\\texttt{2}\\\" [],\\n7/\\\"\\\\texttt{+}\\\" [],\\n;\\n1 -> [,] 2;\\n1 -> [,] 7;\\n2 -> [,] 3;\\n2 -> [,] 6;\\n3 -> [,] 4;\\n3 -> [,] 5;\\n7 -> [,] 4;\\n7 -> [,] 5;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + "TreeView.DirectedAcyclicGraph({7, 8} directed graph,Any[:+,:^,:+,:x,:y,2,:+],Dict(:y=>5,:x=>4))" ] }, - "execution_count": 4, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "dag = make_dag(:((x+y)^2 + (x+y)))\n", - "\n", - "draw(dag)\n", - "\n" + "dag = @dag ((x+y)^2 + (x+y))\n" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "metadata": { "collapsed": true }, @@ -264,55 +276,6 @@ "using CommonSubexpressions" ] }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "quote \n", - " ##+xy#270 = x + y\n", - " ##^##+xy#2702#271 = ##+xy#270 ^ 2\n", - " ##+##^##+xy#2702#271##+xy#270#272 = ##^##+xy#2702#271 + ##+xy#270\n", - " ##+##^##+xy#2702#271##+xy#270#272\n", - "end" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ex = macroexpand(:(@cse (x+y)^2 + (x+y)))" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "TreeView.DirectedAcyclicGraph({6, 6} directed graph,Any[:+,:x,:y,:^,2,:+],Dict(:y=>3,Symbol(\"##^##+xy#2702#271\")=>4,:x=>2,Symbol(\"##+xy#270\")=>1,Symbol(\"##+##^##+xy#2702#271##+xy#270#272\")=>6))" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dag2 = make_dag(ex)" - ] - }, { "cell_type": "code", "execution_count": 9, @@ -320,6 +283,13 @@ "collapsed": false }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "labels = String[\"\\\\texttt{+}\",\"\\\\texttt{x}\",\"\\\\texttt{y}\",\"\\\\textasciicircum\",\"\\\\texttt{2}\",\"\\\\texttt{+}\"]\n" + ] + }, { "data": { "image/svg+xml": [ @@ -386,7 +356,7 @@ "\n" ], "text/plain": [ - "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"\\\\texttt{+}\\\" [],\\n2/\\\"\\\\texttt{x}\\\" [],\\n3/\\\"\\\\texttt{y}\\\" [],\\n4/\\\"\\\\textasciicircum\\\" [],\\n5/\\\"\\\\texttt{2}\\\" [],\\n6/\\\"\\\\texttt{+}\\\" [],\\n;\\n1 -> [,] 2;\\n1 -> [,] 3;\\n4 -> [,] 1;\\n4 -> [,] 5;\\n6 -> [,] 1;\\n6 -> [,] 4;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + "TreeView.DirectedAcyclicGraph({6, 6} directed graph,Any[:+,:x,:y,:^,2,:+],Dict(Symbol(\"##+#275\")=>6,Symbol(\"##+#273\")=>1,:y=>3,Symbol(\"##^#274\")=>4,:x=>2))" ] }, "execution_count": 9, @@ -395,7 +365,8 @@ } ], "source": [ - "draw(dag2)" + "ex = cse(:((x+y)^2 + (x+y)))\n", + "dag2 = make_dag(ex)" ] } ], diff --git a/examples/TreeView.ipynb b/examples/TreeView.ipynb index 6b309bc..66eb0dd 100644 --- a/examples/TreeView.ipynb +++ b/examples/TreeView.ipynb @@ -2,18 +2,18 @@ "cells": [ { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [], "source": [ - "using TreeView" + "using TreeView, CommonSubexpressions" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": { "collapsed": false }, @@ -32,65 +32,62 @@ "\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", "\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" ], "text/plain": [ - "TreeView.LabelledTree({7, 6} undirected graph,String[\"\\\\texttt{+}\",\"\\\\textasciicircum\",\"\\\\texttt{x}\",\"\\\\texttt{2}\",\"\\\\textasciicircum\",\"\\\\texttt{y}\",\"\\\\texttt{2}\"])" + "TreeView.LabelledDigraph({7, 6} directed graph,Any[\"\\\\texttt{+}\",\"\\\\textasciicircum\",:x,2,\"\\\\textasciicircum\",:y,2])" ] }, - "execution_count": 3, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -101,7 +98,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, "metadata": { "collapsed": false }, @@ -113,72 +110,69 @@ "\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", - "\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", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", "\n", "\n" ], "text/plain": [ - "TreeView.LabelledTree({7, 6} undirected graph,String[\"\\\\texttt{+}\",\"\\\\textasciicircum\",\"\\\\texttt{x}\",\"\\\\texttt{2}\",\"\\\\textasciicircum\",\"\\\\texttt{y}\",\"\\\\texttt{2}\"])" + "TreeView.LabelledDigraph({7, 6} directed graph,Any[\"\\\\texttt{+}\",\"\\\\textasciicircum\",:x,2,\"\\\\textasciicircum\",:y,2])" ] }, - "execution_count": 5, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -189,7 +183,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "metadata": { "collapsed": false }, @@ -201,34 +195,34 @@ "\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", - "\n", + "\n", "\n", "\n", "\n", @@ -253,53 +247,53 @@ "\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", - " \n", - " \n", - " \n", - " \n", + " \n", + " \n", + " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", "\n", "\n" ], "text/plain": [ - "TreeView.LabelledTree({10, 9} undirected graph,String[\"\\\\texttt{call}\",\"\\\\texttt{+}\",\"\\\\texttt{call}\",\"\\\\textasciicircum\",\"\\\\texttt{x}\",\"\\\\texttt{2}\",\"\\\\texttt{call}\",\"\\\\textasciicircum\",\"\\\\texttt{y}\",\"\\\\texttt{2}\"])" + "TreeView.LabelledDigraph({10, 9} directed graph,Any[:call,:+,:call,:^,:x,2,:call,:^,:y,2])" ] }, - "execution_count": 5, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -310,7 +304,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "collapsed": false }, @@ -322,19 +316,19 @@ "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", "\n", @@ -347,26 +341,26 @@ "\n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", "\n", "\n" ], "text/plain": [ - "TreeView.LabelledTree({4, 3} undirected graph,String[\"\\\\texttt{f}\",\"\\\\texttt{g}\",\"\\\\texttt{x}\",\"\\\\texttt{y}\"])" + "TreeView.LabelledDigraph({4, 3} directed graph,Any[\"\\\\texttt{f}\",\"\\\\texttt{g}\",:x,:y])" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -377,7 +371,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 9, "metadata": { "collapsed": false }, @@ -389,71 +383,68 @@ "\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", - "\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", "\n", "\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", @@ -484,100 +475,100 @@ "\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", + " \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", - " \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", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", "\n", "\n" ], "text/plain": [ - "TreeView.LabelledTree({19, 18} undirected graph,String[\"\\\\texttt{block}\",\"\\\\texttt{line}\",\"\\\\texttt{2}\",\"\\\\texttt{In[6]}\",\"\\\\texttt{=}\",\"\\\\texttt{a}\",\"\\\\texttt{+}\",\"\\\\texttt{b}\",\"\\\\texttt{c}\",\"\\\\texttt{line}\",\"\\\\texttt{3}\",\"\\\\texttt{In[6]}\",\"\\\\texttt{=}\",\"\\\\texttt{d}\",\"\\\\textasciicircum\",\"\\\\texttt{-}\",\"\\\\texttt{a}\",\"\\\\texttt{2}\",\"\\\\texttt{2}\"])" + "TreeView.LabelledDigraph({19, 18} directed graph,Any[:block,:line,2,Symbol(\"In[9]\"),:(=),:a,\"\\\\texttt{+}\",:b,:c,:line,3,Symbol(\"In[9]\"),:(=),:d,\"\\\\textasciicircum\",\"\\\\texttt{-}\",:a,2,2])" ] }, - "execution_count": 6, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -588,6 +579,514 @@ " d = (a - 2)^2\n", "end" ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "TreeView.DirectedAcyclicGraph({4, 4} directed graph,Any[:+,:x,:*,2],Dict(:x=>2))" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@dag x + 2x" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + ":(x + 2x)" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ex = :(x + 2x)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "TreeView.DirectedAcyclicGraph({4, 4} directed graph,Any[:*,2,:x,:+],Dict(Symbol(\"##+#275\")=>4,:x=>3,Symbol(\"##*#274\")=>1))" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "make_dag(cse(ex))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "quote \n", + " ##*#276 = 2x\n", + " ##+#277 = x + ##*#276\n", + " ##+#277\n", + "end" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cse(ex)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "labels = String[\"\\\\texttt{*}\",\"\\\\texttt{2}\",\"\\\\texttt{x}\",\"\\\\texttt{+}\"]\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "\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", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "TreeView.DirectedAcyclicGraph({4, 4} directed graph,Any[:*,2,:x,:+],Dict(:x=>3,:a=>1,:b=>4))" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dag = make_dag(quote\n", + " a = 2x\n", + " b = x + a\n", + " end\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "@edit TikzGraphs.plot(dag.g, String[TreeView.label(x) for x in dag.labels])" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"1\\\" [],\\n2/\\\"2\\\" [],\\n3/\\\"3\\\" [],\\n4/\\\"4\\\" [],\\n;\\n1 -> [,] 2;\\n1 -> [,] 3;\\n4 -> [,] 1;\\n4 -> [,] 3;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "TikzGraphs.plot(dag.g)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\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", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"\\\\texttt{*}\\\" [],\\n2/\\\"\\\\texttt{2}\\\" [],\\n3/\\\"\\\\texttt{x}\\\" [],\\n4/\\\"\\\\texttt{+}\\\" [],\\n;\\n1 -> [,] 2;\\n1 -> [,] 3;\\n4 -> [,] 1;\\n4 -> [,] 3;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "TikzGraphs.plot(dag.g, String[TreeView.label(x) for x in dag.labels])" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4-element Array{String,1}:\n", + " \"\\\\texttt{*}\"\n", + " \"\\\\texttt{2}\"\n", + " \"\\\\texttt{x}\"\n", + " \"\\\\texttt{+}\"" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "String[TreeView.label(x) for x in dag.labels]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4-element Array{String,1}:\n", + " \"\\\\texttt{*}\"\n", + " \"\\\\texttt{2}\"\n", + " \"\\\\texttt{x}\"\n", + " \"\\\\texttt{+}\"" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + " String[TreeView.label(x) for x in dag.labels]" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "using TikzPictures" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "LoadError", + "evalue": "MethodError: no method matching TikzPictures.TikzPicture(::String, ::String, ::String, ::Bool, ::Bool)\u001b[0m\nClosest candidates are:\n TikzPictures.TikzPicture(::AbstractString; usePDF2SVG, enableWrite18, options, preamble) at /Users/dpsanders/.julia/v0.5/TikzPictures/src/TikzPictures.jl:56\n TikzPictures.TikzPicture{T}(::Any) at sysimg.jl:53\u001b[0m", + "output_type": "error", + "traceback": [ + "MethodError: no method matching TikzPictures.TikzPicture(::String, ::String, ::String, ::Bool, ::Bool)\u001b[0m\nClosest candidates are:\n TikzPictures.TikzPicture(::AbstractString; usePDF2SVG, enableWrite18, options, preamble) at /Users/dpsanders/.julia/v0.5/TikzPictures/src/TikzPictures.jl:56\n TikzPictures.TikzPicture{T}(::Any) at sysimg.jl:53\u001b[0m", + "" + ] + } + ], + "source": [ + "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"\\\\texttt{+}\\\" [],\\n2/\\\"\\\\texttt{x}\\\" [],\\n3/\\\"\\\\texttt{*}\\\" [],\\n4/\\\"\\\\texttt{2}\\\" [],\\n;\\n1 -> [,] 2;\\n1 -> [,] 3;\\n3 -> [,] 2;\\n3 -> [,] 4;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/src/TreeView.jl b/src/TreeView.jl index 13d6155..85f20bf 100644 --- a/src/TreeView.jl +++ b/src/TreeView.jl @@ -2,115 +2,30 @@ module TreeView using LightGraphs, TikzGraphs using MacroTools +using CommonSubexpressions -export LabelledDigraph, walk_tree, walk_tree!, draw, @tree, @tree_with_call, +export LabelledTree, walk_tree, walk_tree!, draw, @tree, @tree_with_call, tikz_representation -include("dag.jl") -export make_dag +export make_dag, @dag + +abstract LabelledDiGraph -immutable LabelledDigraph +immutable LabelledTree <: LabelledDiGraph g::DiGraph labels::Vector{Any} end add_numbered_vertex!(g) = (add_vertex!(g); top = nv(g)) # returns the number of the new vertex -# latex treats # as a special character, so we have to escape it. See: -# https://github.com/sisl/TikzGraphs.jl/issues/12 -latex_escape(s::String) = replace(s, "#", "\\#") - -"Convert the current node into a label" -function label(sym) - sym == :(^) && return "\\textasciicircum" # TikzGraphs chokes on ^ - - return latex_escape(string("\\texttt{", sym, "}")) -end - - -""" - walk_tree!(g, labels, ex, show_call=true) - -Walk the abstract syntax tree (AST) of the given expression `ex`. -Builds up the graph `g` and the set of `labels` -for each node, both modified in place - -`show_call` specifies whether to include `call` nodes in the graph. -Including them represents the Julia AST more precisely, but adds visual noise. - -Returns the number of the top vertex. -""" - -function walk_tree!(g, labels, ex, show_call=true) - - top_vertex = add_numbered_vertex!(g) - - where_start = 1 # which argument to start with - - if !(show_call) && ex.head == :call - f = ex.args[1] # the function name - push!(labels, label(f)) - - where_start = 2 # drop "call" from tree - - else - push!(labels, ex.head) - end - - - for i in where_start:length(ex.args) - - if isa(ex.args[i], Expr) - - child = walk_tree!(g, labels, ex.args[i], show_call) - add_edge!(g, top_vertex, child) - else - n = add_numbered_vertex!(g) - add_edge!(g, top_vertex, n) - push!(labels, ex.args[i]) - - end - end - - return top_vertex - -end - -function walk_tree(ex::Expr, show_call=false) - g = DiGraph() - labels = Any[] - - walk_tree!(g, labels, ex, show_call) - - return LabelledDigraph(g, labels) - -end - -tikz_representation(tree) = TikzGraphs.plot(tree.g, tree.labels) - -import Base.show -function show(io::IO, mime::MIME"image/svg+xml", tree::LabelledDigraph) - p = tikz_representation(tree) # TikzPicture object - show(io, mime, p) -end - - - -function draw(tree::LabelledDigraph) - TikzGraphs.plot(tree.g, map(label, tree.labels)) -end +include("tree.jl") +include("dag.jl") +include("display.jl") -macro tree(ex::Expr) - walk_tree(ex) -end - -macro tree_with_call(ex::Expr) - walk_tree(ex, true) -end end # module diff --git a/test/runtests.jl b/test/runtests.jl index 66c4ebd..9dfa63c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,12 +6,12 @@ using Base.Test t = @tree 1x - @test typeof(t) == TreeView.LabelledDigraph + @test typeof(t) == TreeView.LabelledTree @test typeof(t.g) == LightGraphs.DiGraph @test typeof(t.labels) == Vector{Any} @test t.g.vertices == 1:3 - @test t.labels == Any["\\texttt{*}",1,:x] + @test t.labels == Any[:*,1,:x] t = @tree x^2 + y^2 @@ -24,3 +24,8 @@ end t = walk_tree(expr) @test t.labels[1] == Symbol("##271") end + +@testset "DAG" begin + dag = @dag x + 2x + @test length(dag.labels) == 4 +end From 44d4b1d4697e68d2c948af5d965662f482cb5be5 Mon Sep 17 00:00:00 2001 From: David Sanders Date: Mon, 30 Jan 2017 17:25:04 -0500 Subject: [PATCH 06/10] Export at-dag_cse --- src/TreeView.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TreeView.jl b/src/TreeView.jl index 85f20bf..7c994b9 100644 --- a/src/TreeView.jl +++ b/src/TreeView.jl @@ -7,7 +7,7 @@ using CommonSubexpressions export LabelledTree, walk_tree, walk_tree!, draw, @tree, @tree_with_call, tikz_representation -export make_dag, @dag +export make_dag, @dag, @dag_cse abstract LabelledDiGraph From a4a2967f0b64f515e7c5f4ac0d6eecfd1663ac80 Mon Sep 17 00:00:00 2001 From: David Sanders Date: Mon, 30 Jan 2017 17:26:38 -0500 Subject: [PATCH 07/10] Add test for at-dag_cse --- examples/DAG.ipynb | 137 +++++++++++++++++++++++++-------------------- test/runtests.jl | 6 ++ 2 files changed, 82 insertions(+), 61 deletions(-) diff --git a/examples/DAG.ipynb b/examples/DAG.ipynb index 8c369a6..282581e 100644 --- a/examples/DAG.ipynb +++ b/examples/DAG.ipynb @@ -13,18 +13,11 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "labels = String[\"\\\\texttt{+}\",\"\\\\texttt{x}\",\"\\\\texttt{*}\",\"\\\\texttt{2}\"]\n" - ] - }, { "data": { "image/svg+xml": [ @@ -78,29 +71,22 @@ "TreeView.DirectedAcyclicGraph({4, 4} directed graph,Any[:+,:x,:*,2],Dict(:x=>2))" ] }, - "execution_count": 3, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "dag = make_dag(:(x + 2x))" + "dag = @dag x + 2x" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "labels = String[\"\\\\texttt{x}\",\"\\\\texttt{+}\",\"\\\\texttt{*}\",\"\\\\texttt{2}\"]\n" - ] - }, { "data": { "image/svg+xml": [ @@ -154,7 +140,7 @@ "TreeView.DirectedAcyclicGraph({4, 4} directed graph,Any[:x,:+,:*,2],Dict(:x=>1,:a=>1))" ] }, - "execution_count": 5, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -168,18 +154,11 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "labels = String[\"\\\\texttt{+}\",\"\\\\textasciicircum\",\"\\\\texttt{+}\",\"\\\\texttt{x}\",\"\\\\texttt{y}\",\"\\\\texttt{2}\",\"\\\\texttt{+}\"]\n" - ] - }, { "data": { "image/svg+xml": [ @@ -256,7 +235,7 @@ "TreeView.DirectedAcyclicGraph({7, 8} directed graph,Any[:+,:^,:+,:x,:y,2,:+],Dict(:y=>5,:x=>4))" ] }, - "execution_count": 6, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -267,7 +246,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 5, "metadata": { "collapsed": true }, @@ -278,7 +257,28 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "LoadError", + "evalue": "UndefVarError: @dag_cse not defined", + "output_type": "error", + "traceback": [ + "UndefVarError: @dag_cse not defined", + "" + ] + } + ], + "source": [ + "@dag_cse ((x+y)^2 + (x+y))" + ] + }, + { + "cell_type": "code", + "execution_count": 10, "metadata": { "collapsed": false }, @@ -287,87 +287,102 @@ "name": "stdout", "output_type": "stream", "text": [ - "labels = String[\"\\\\texttt{+}\",\"\\\\texttt{x}\",\"\\\\texttt{y}\",\"\\\\textasciicircum\",\"\\\\texttt{2}\",\"\\\\texttt{+}\"]\n" + "labels = String[\"\\\\texttt{+}\",\"\\\\textasciicircum\",\"\\\\texttt{+}\",\"\\\\texttt{x}\",\"\\\\texttt{y}\",\"\\\\texttt{2}\",\"\\\\texttt{+}\"]\n" ] }, { "data": { "image/svg+xml": [ "\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", - "\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", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", "\n", "\n" ], "text/plain": [ - "TreeView.DirectedAcyclicGraph({6, 6} directed graph,Any[:+,:x,:y,:^,2,:+],Dict(Symbol(\"##+#275\")=>6,Symbol(\"##+#273\")=>1,:y=>3,Symbol(\"##^#274\")=>4,:x=>2))" + "TreeView.DirectedAcyclicGraph({7, 8} directed graph,Any[:+,:^,:+,:x,:y,2,:+],Dict(:y=>5,:x=>4))" ] }, - "execution_count": 9, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "ex = cse(:((x+y)^2 + (x+y)))\n", - "dag2 = make_dag(ex)" + "@dag((x+y)^2 + (x+y))" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/test/runtests.jl b/test/runtests.jl index 9dfa63c..0dad375 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -28,4 +28,10 @@ end @testset "DAG" begin dag = @dag x + 2x @test length(dag.labels) == 4 + + dag = @dag((x+y)^2 + (x+y)) + @test length(dag.labels) == 7 + + dag2 = @dag_cse((x+y)^2 + (x+y)) + @test length(dag2.labels) == 6 end From 65f8fa472c37735a45ef057a7d6f8fbabafb54be Mon Sep 17 00:00:00 2001 From: David Sanders Date: Mon, 30 Jan 2017 17:34:10 -0500 Subject: [PATCH 08/10] Reduce examples to single notebook --- README.md | 2 +- examples/DAG.ipynb | 417 -------- .../{TreeView.ipynb => TreeView usage.ipynb} | 962 ++++++------------ 3 files changed, 305 insertions(+), 1076 deletions(-) delete mode 100644 examples/DAG.ipynb rename examples/{TreeView.ipynb => TreeView usage.ipynb} (58%) diff --git a/README.md b/README.md index 4091032..477a502 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ which gives the following output: ![example_tree](example_tree.png) -See [this notebook](examples/TreeView.ipynb) for usage examples. +See [this notebook](examples/TreeView usage.ipynb) for usage examples. ## Installation prerequisites diff --git a/examples/DAG.ipynb b/examples/DAG.ipynb deleted file mode 100644 index 282581e..0000000 --- a/examples/DAG.ipynb +++ /dev/null @@ -1,417 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "using TreeView" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\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", - "\n", - " \n", - "\n", - "\n", - "\n", - "\n" - ], - "text/plain": [ - "TreeView.DirectedAcyclicGraph({4, 4} directed graph,Any[:+,:x,:*,2],Dict(:x=>2))" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dag = @dag x + 2x" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\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", - "\n", - " \n", - "\n", - "\n", - "\n", - "\n" - ], - "text/plain": [ - "TreeView.DirectedAcyclicGraph({4, 4} directed graph,Any[:x,:+,:*,2],Dict(:x=>1,:a=>1))" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dag = @dag begin\n", - " a = x\n", - " a + 2a\n", - "end" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\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", - "\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" - ], - "text/plain": [ - "TreeView.DirectedAcyclicGraph({7, 8} directed graph,Any[:+,:^,:+,:x,:y,2,:+],Dict(:y=>5,:x=>4))" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dag = @dag ((x+y)^2 + (x+y))\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "using CommonSubexpressions" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "ename": "LoadError", - "evalue": "UndefVarError: @dag_cse not defined", - "output_type": "error", - "traceback": [ - "UndefVarError: @dag_cse not defined", - "" - ] - } - ], - "source": [ - "@dag_cse ((x+y)^2 + (x+y))" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "labels = String[\"\\\\texttt{+}\",\"\\\\textasciicircum\",\"\\\\texttt{+}\",\"\\\\texttt{x}\",\"\\\\texttt{y}\",\"\\\\texttt{2}\",\"\\\\texttt{+}\"]\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\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", - "\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" - ], - "text/plain": [ - "TreeView.DirectedAcyclicGraph({7, 8} directed graph,Any[:+,:^,:+,:x,:y,2,:+],Dict(:y=>5,:x=>4))" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "@dag((x+y)^2 + (x+y))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Julia 0.5.0", - "language": "julia", - "name": "julia-0.5" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "0.5.0" - }, - "toc": { - "nav_menu": { - "height": "12px", - "width": "252px" - }, - "navigate_menu": true, - "number_sections": true, - "sideBar": true, - "threshold": "2", - "toc_cell": false, - "toc_section_display": "block", - "toc_window_display": false - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/TreeView.ipynb b/examples/TreeView usage.ipynb similarity index 58% rename from examples/TreeView.ipynb rename to examples/TreeView usage.ipynb index 66eb0dd..e02a401 100644 --- a/examples/TreeView.ipynb +++ b/examples/TreeView usage.ipynb @@ -1,189 +1,33 @@ { "cells": [ { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [], + "cell_type": "markdown", + "metadata": {}, "source": [ - "using TreeView, CommonSubexpressions" + "# Usage of the TreeView package" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 6, "metadata": { - "collapsed": false + "collapsed": true }, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\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", - "\n", - "\n", - " \n", - "\n", - "\n", - " \n", - "\n", - "\n", - " \n", - "\n", - "\n", - " \n", - "\n", - "\n", - " \n", - "\n", - "\n", - " \n", - "\n", - "\n", - "\n", - "\n" - ], - "text/plain": [ - "TreeView.LabelledDigraph({7, 6} directed graph,Any[\"\\\\texttt{+}\",\"\\\\textasciicircum\",:x,2,\"\\\\textasciicircum\",:y,2])" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "tree = walk_tree(:(x^2 + y^2))" + "using TreeView" ] }, { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\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", - "\n", - "\n", - " \n", - "\n", - "\n", - " \n", - "\n", - "\n", - " \n", - "\n", - "\n", - " \n", - "\n", - "\n", - " \n", - "\n", - "\n", - " \n", - "\n", - "\n", - "\n", - "\n" - ], - "text/plain": [ - "TreeView.LabelledDigraph({7, 6} directed graph,Any[\"\\\\texttt{+}\",\"\\\\textasciicircum\",:x,2,\"\\\\textasciicircum\",:y,2])" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "cell_type": "markdown", + "metadata": {}, "source": [ - "@tree x^2 + y^2" + "The `@tree` macro displays a given expression as a directed graph:" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 2, "metadata": { "collapsed": false }, @@ -192,119 +36,86 @@ "data": { "image/svg+xml": [ "\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", + "\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", + "\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", "\n", - " \n", + " \n", "\n", "\n", "\n", "\n" ], "text/plain": [ - "TreeView.LabelledDigraph({10, 9} directed graph,Any[:call,:+,:call,:^,:x,2,:call,:^,:y,2])" + "TreeView.LabelledTree({7, 6} directed graph,Any[:+,:^,:x,2,:^,:y,2])" ] }, - "execution_count": 8, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "@tree_with_call x^2 + y^2" + "@tree x^2 + y^2" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": { "collapsed": false }, @@ -316,19 +127,19 @@ "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", - "\n", + "\n", "\n", "\n", "\n", @@ -341,26 +152,26 @@ "\n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", "\n", "\n" ], "text/plain": [ - "TreeView.LabelledDigraph({4, 3} directed graph,Any[\"\\\\texttt{f}\",\"\\\\texttt{g}\",:x,:y])" + "TreeView.LabelledTree({4, 3} directed graph,Any[:f,:g,:x,:y])" ] }, - "execution_count": 5, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -371,7 +182,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 7, "metadata": { "collapsed": false }, @@ -383,69 +194,72 @@ "\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", - "\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", "\n", "\n", - "\n", - "\n", - "\n", - "\n", + "\n", "\n", "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", "\n", "\n", "\n", @@ -475,100 +289,100 @@ "\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", + " \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", - " \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", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", "\n", "\n" ], "text/plain": [ - "TreeView.LabelledDigraph({19, 18} directed graph,Any[:block,:line,2,Symbol(\"In[9]\"),:(=),:a,\"\\\\texttt{+}\",:b,:c,:line,3,Symbol(\"In[9]\"),:(=),:d,\"\\\\textasciicircum\",\"\\\\texttt{-}\",:a,2,2])" + "TreeView.LabelledTree({19, 18} directed graph,Any[:block,:line,2,Symbol(\"In[7]\"),:(=),:a,:+,:b,:c,:line,3,Symbol(\"In[7]\"),:(=),:d,:^,:-,:a,2,2])" ] }, - "execution_count": 9, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -580,9 +394,16 @@ "end" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Internally, function calls in `Expr`essions are represented using nodes with `call`, which can also be visualized:" + ] + }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": { "collapsed": false }, @@ -591,275 +412,140 @@ "data": { "image/svg+xml": [ "\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", + "\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", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", + " \n", + " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", + "\n", + " \n", "\n", - "\n", - "\n" - ], - "text/plain": [ - "TreeView.DirectedAcyclicGraph({4, 4} directed graph,Any[:+,:x,:*,2],Dict(:x=>2))" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "@dag x + 2x" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - ":(x + 2x)" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ex = :(x + 2x)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\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", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", - " \n", + " \n", "\n", "\n", "\n", "\n" ], "text/plain": [ - "TreeView.DirectedAcyclicGraph({4, 4} directed graph,Any[:*,2,:x,:+],Dict(Symbol(\"##+#275\")=>4,:x=>3,Symbol(\"##*#274\")=>1))" + "TreeView.LabelledTree({10, 9} directed graph,Any[:call,:+,:call,:^,:x,2,:call,:^,:y,2])" ] }, - "execution_count": 10, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "make_dag(cse(ex))" + "@tree_with_call x^2 + y^2" ] }, { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "quote \n", - " ##*#276 = 2x\n", - " ##+#277 = x + ##*#276\n", - " ##+#277\n", - "end" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "cell_type": "markdown", + "metadata": {}, "source": [ - "cse(ex)" + "## Directed Acyclic Graphs (DAGs)" ] }, { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "labels = String[\"\\\\texttt{*}\",\"\\\\texttt{2}\",\"\\\\texttt{x}\",\"\\\\texttt{+}\"]\n" - ] - }, - { - "data": { - "image/svg+xml": [ - "\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", - "\n", - " \n", - "\n", - "\n", - "\n", - "\n" - ], - "text/plain": [ - "TreeView.DirectedAcyclicGraph({4, 4} directed graph,Any[:*,2,:x,:+],Dict(:x=>3,:a=>1,:b=>4))" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "cell_type": "markdown", + "metadata": {}, "source": [ - "dag = make_dag(quote\n", - " a = 2x\n", - " b = x + a\n", - " end\n", - " )" + "Directed Acyclic Graphs (DAGs) give a higher-level view of the graph, with less Julia-specific detail." ] }, { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, - "outputs": [], + "cell_type": "markdown", + "metadata": {}, "source": [ - "@edit TikzGraphs.plot(dag.g, String[TreeView.label(x) for x in dag.labels])" + "In the following, the expression `x+y` is repeated twice:" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 9, "metadata": { "collapsed": false }, @@ -868,67 +554,97 @@ "data": { "image/svg+xml": [ "\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", - "\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", + " \n", "\n", "\n", - " \n", + " \n", + "\n", + "\n", + " \n", "\n", "\n", "\n", "\n" ], "text/plain": [ - "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"1\\\" [],\\n2/\\\"2\\\" [],\\n3/\\\"3\\\" [],\\n4/\\\"4\\\" [],\\n;\\n1 -> [,] 2;\\n1 -> [,] 3;\\n4 -> [,] 1;\\n4 -> [,] 3;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + "TreeView.DirectedAcyclicGraph({7, 8} directed graph,Any[:+,:^,:+,:x,:y,2,:+],Dict(:y=>5,:x=>4))" ] }, - "execution_count": 12, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "TikzGraphs.plot(dag.g)" + "@dag (x + y)^2 + (x + y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can apply **Common Subexpression Elimination** (CSE) from the [`CommonSubexpressions.jl` package](https://github.com/rdeits/CommonSubexpressions.jl/):" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "metadata": { "collapsed": false }, @@ -937,156 +653,86 @@ "data": { "image/svg+xml": [ "\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", - "\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" ], "text/plain": [ - "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"\\\\texttt{*}\\\" [],\\n2/\\\"\\\\texttt{2}\\\" [],\\n3/\\\"\\\\texttt{x}\\\" [],\\n4/\\\"\\\\texttt{+}\\\" [],\\n;\\n1 -> [,] 2;\\n1 -> [,] 3;\\n4 -> [,] 1;\\n4 -> [,] 3;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + "TreeView.DirectedAcyclicGraph({6, 6} directed graph,Any[:+,:x,:y,:^,2,:+],Dict(Symbol(\"##^#271\")=>4,Symbol(\"##+#272\")=>6,:y=>3,:x=>2,Symbol(\"##+#270\")=>1))" ] }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "TikzGraphs.plot(dag.g, String[TreeView.label(x) for x in dag.labels])" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "4-element Array{String,1}:\n", - " \"\\\\texttt{*}\"\n", - " \"\\\\texttt{2}\"\n", - " \"\\\\texttt{x}\"\n", - " \"\\\\texttt{+}\"" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "String[TreeView.label(x) for x in dag.labels]" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "4-element Array{String,1}:\n", - " \"\\\\texttt{*}\"\n", - " \"\\\\texttt{2}\"\n", - " \"\\\\texttt{x}\"\n", - " \"\\\\texttt{+}\"" - ] - }, - "execution_count": 8, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ - " String[TreeView.label(x) for x in dag.labels]" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "using TikzPictures" + "@dag_cse (x + y)^2 + (x + y)" ] }, { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "ename": "LoadError", - "evalue": "MethodError: no method matching TikzPictures.TikzPicture(::String, ::String, ::String, ::Bool, ::Bool)\u001b[0m\nClosest candidates are:\n TikzPictures.TikzPicture(::AbstractString; usePDF2SVG, enableWrite18, options, preamble) at /Users/dpsanders/.julia/v0.5/TikzPictures/src/TikzPictures.jl:56\n TikzPictures.TikzPicture{T}(::Any) at sysimg.jl:53\u001b[0m", - "output_type": "error", - "traceback": [ - "MethodError: no method matching TikzPictures.TikzPicture(::String, ::String, ::String, ::Bool, ::Bool)\u001b[0m\nClosest candidates are:\n TikzPictures.TikzPicture(::AbstractString; usePDF2SVG, enableWrite18, options, preamble) at /Users/dpsanders/.julia/v0.5/TikzPictures/src/TikzPictures.jl:56\n TikzPictures.TikzPicture{T}(::Any) at sysimg.jl:53\u001b[0m", - "" - ] - } - ], + "cell_type": "markdown", + "metadata": {}, "source": [ - "TikzPictures.TikzPicture(\"\\\\graph [layered layout, ] {\\n1/\\\"\\\\texttt{+}\\\" [],\\n2/\\\"\\\\texttt{x}\\\" [],\\n3/\\\"\\\\texttt{*}\\\" [],\\n4/\\\"\\\\texttt{2}\\\" [],\\n;\\n1 -> [,] 2;\\n1 -> [,] 3;\\n3 -> [,] 2;\\n3 -> [,] 4;\\n};\\n\",\"\",\"\\\\usepackage{fontspec}\\n\\\\setmainfont{Latin Modern Math}\\n\\\\usetikzlibrary{graphs}\\n\\\\usetikzlibrary{graphdrawing}\\n\\n\\\\usegdlibrary{layered}\",true,true)" + "We see that the common subexpression `x+y` now appears only once." ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] } ], "metadata": { From 128d63174ed1ee3b4a5d9699188345441e41d6bc Mon Sep 17 00:00:00 2001 From: David Sanders Date: Tue, 31 Jan 2017 14:44:03 -0500 Subject: [PATCH 09/10] Add CommonSubexpressions to REQUIRE --- REQUIRE | 1 + 1 file changed, 1 insertion(+) diff --git a/REQUIRE b/REQUIRE index 46ad0dd..bc26d86 100644 --- a/REQUIRE +++ b/REQUIRE @@ -2,3 +2,4 @@ julia 0.5 LightGraphs 0.7 TikzGraphs 0.3 MacroTools 0.3 +CommonSubexpressions From 2cb0e47049739601749158f0c16afa0b2347423d Mon Sep 17 00:00:00 2001 From: David Sanders Date: Tue, 31 Jan 2017 14:46:39 -0500 Subject: [PATCH 10/10] Add source files --- src/dag.jl | 146 +++++++++++++++++++++++++++++++++++++++++++++++++ src/display.jl | 30 ++++++++++ src/tree.jl | 75 +++++++++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 src/dag.jl create mode 100644 src/display.jl create mode 100644 src/tree.jl diff --git a/src/dag.jl b/src/dag.jl new file mode 100644 index 0000000..fa7aee5 --- /dev/null +++ b/src/dag.jl @@ -0,0 +1,146 @@ +# Make a DAG (Directed Acyclic Graph) by storing references to each symbol + +""" +Structure representing a DAG. +Maintains a `symbol_map` giving the currently-known symbols and the corresponding +vertex number in the graph. +""" +immutable DirectedAcyclicGraph <: LabelledDiGraph + g::DiGraph + labels::Vector{Any} + symbol_map::Dict{Symbol, Int} +end + +DirectedAcyclicGraph() = DirectedAcyclicGraph(DiGraph(), Symbol[], Dict()) + +""" +Adds a symbol to the DAG if it doesn't already exist. +Returns the vertex number +""" + +# Make numbers unique: +function add_symbol!(dag::DirectedAcyclicGraph, s) # number + vertex = add_numbered_vertex!(dag.g) + push!(dag.labels, s) + return vertex +end + +function lookup!(dag::DirectedAcyclicGraph, s) + add_symbol!(dag, s) +end + +""" +Look up a symbol to see if it has already been seen. +""" +function lookup!(dag::DirectedAcyclicGraph, s::Symbol) + if haskey(dag.symbol_map, s) + return dag.symbol_map[s] + + else # make new one: + vertex = add_numbered_vertex!(dag.g) + push!(dag.labels, s) + dag.symbol_map[s] = vertex + return vertex + end +end + + +make_dag!(dag::DirectedAcyclicGraph, s) = lookup!(dag, s) + +""" +Update a Directed Acyclic Graph with the result of traversing the given `Expr`ession. +""" +function make_dag!(dag::DirectedAcyclicGraph, ex::Expr) + + local top + + if ex.head == :block + for arg in ex.args + make_dag!(dag, arg) + end + return -1 + + elseif ex.head == :(=) # treat assignment as just giving pointers to the tree + local_var = ex.args[1] + + top = make_dag!(dag, ex.args[2]) + + dag.symbol_map[local_var] = top # add an alias to the corresponding tree node + + return top + + end + + + where_start = 1 # which argument to start with + + if ex.head == :call + f = ex.args[1] # the function name + top = add_symbol!(dag, f) + + where_start = 2 # drop "call" from tree + + + else + @show ex.head + top = add_symbol!(dag, ex.head) + end + + # @show top + + for arg in ex.args[where_start:end] + + # @show arg, typeof(arg) + + if isa(arg, Expr) + + child = make_dag!(dag, arg) + # @show "Expr", top, child + add_edge!(dag.g, top, child) + + else + child = lookup!(dag, arg) + # @show top, child + add_edge!(dag.g, top, child) + + end + end + + return top + +end + +""" +Make a Directed Acyclic Graph (DAG) from a Julia expression. +""" +function make_dag(ex::Expr) + + dag = DirectedAcyclicGraph() + + make_dag!(dag, MacroTools.striplines(ex)) + + return dag + +end + +""" +Make a Directed Acyclic Graph (DAG) from a Julia expression. +""" +macro dag(ex::Expr) + make_dag(ex) +end + +""" +Perform common subexpression elimination on a Julia `Expr`ession, +and make a Directed Acyclic Graph (DAG) of the result. +""" +macro dag_cse(ex::Expr) + make_dag(cse(ex)) # common subexpression elimination +end + + +import Base.show +function show(io::IO, mime::MIME"image/svg+xml", dag::DirectedAcyclicGraph) + p = tikz_representation(dag) # TikzPicture object + show(io, mime, p) +end diff --git a/src/display.jl b/src/display.jl new file mode 100644 index 0000000..fb5cc63 --- /dev/null +++ b/src/display.jl @@ -0,0 +1,30 @@ + +# latex treats # as a special character, so we have to escape it. See: +# https://github.com/sisl/TikzGraphs.jl/issues/12 + +latex_escape(s::String) = replace(s, "#", "\\#") + +"Convert a symbol or into a LaTeX label" +function latex_label(sym) + sym == :(^) && return "\\textasciicircum" # TikzGraphs chokes on ^ + + return latex_escape(string("\\texttt{", sym, "}")) +end + + +""" +Return a Tikz representation of a tree object. +The tree object must have fields `g` (the graph) and `labels`. +""" +function tikz_representation(tree::LabelledDiGraph) + labels = String[latex_label(x) for x in tree.labels] + return TikzGraphs.plot(tree.g, labels) +end + + +function Base.show(io::IO, mime::MIME"image/svg+xml", tree::LabelledTree) + + p = tikz_representation(tree) # TikzPicture object + show(io, mime, p) + +end diff --git a/src/tree.jl b/src/tree.jl new file mode 100644 index 0000000..2d5eb80 --- /dev/null +++ b/src/tree.jl @@ -0,0 +1,75 @@ +""" + walk_tree!(g, labels, ex, show_call=true) + +Walk the abstract syntax tree (AST) of the given expression `ex`. +Builds up the graph `g` and the set of `labels` +for each node, both modified in place + +`show_call` specifies whether to include `call` nodes in the graph. +Including them represents the Julia AST more precisely, but adds visual noise. + +Returns the number of the top vertex. +""" + +function walk_tree!(g, labels, ex, show_call=true) + + top_vertex = add_numbered_vertex!(g) + + where_start = 1 # which argument to start with + + if !(show_call) && ex.head == :call + f = ex.args[1] # the function name + push!(labels, f) + + where_start = 2 # drop "call" from tree + + else + push!(labels, ex.head) + end + + + for i in where_start:length(ex.args) + + if isa(ex.args[i], Expr) + + child = walk_tree!(g, labels, ex.args[i], show_call) + add_edge!(g, top_vertex, child) + + else + n = add_numbered_vertex!(g) + add_edge!(g, top_vertex, n) + + push!(labels, ex.args[i]) + + end + end + + return top_vertex + +end + +function walk_tree(ex::Expr, show_call=false) + g = DiGraph() + labels = Any[] + + walk_tree!(g, labels, ex, show_call) + + return LabelledTree(g, labels) + +end + +""" +Make a tree from a Julia `Expr`ession. +Omits `call`. +""" +macro tree(ex::Expr) + walk_tree(ex) +end + +""" +Make a tree from a Julia `Expr`ession. +Includes `call`. +""" +macro tree_with_call(ex::Expr) + walk_tree(ex, true) +end