-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add basic DAG construction * DAG improvements, but gets confused with :block * Working DAGs! * Rename LabelledTree -> LabelledDigraph * Refactor into separate files * Export at-dag_cse * Add test for at-dag_cse * Reduce examples to single notebook * Add CommonSubexpressions to REQUIRE * Add source files
- Loading branch information
Showing
8 changed files
with
675 additions
and
348 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ julia 0.5 | |
LightGraphs 0.7 | ||
TikzGraphs 0.3 | ||
MacroTools 0.3 | ||
CommonSubexpressions |
649 changes: 397 additions & 252 deletions
649
examples/TreeView.ipynb → examples/TreeView usage.ipynb
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.