-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Floyd-Warshall #70
base: gr/acset2sym
Are you sure you want to change the base?
Floyd-Warshall #70
Conversation
Added `apex` and `@relation`, `to_graphviz` from Catlab Co-authored-by: James <[email protected]>
Converts ACSet to a series of Symbolic terms that can be rewritten with a provided rewriter
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## gr/acset2sym #70 +/- ##
================================================
- Coverage 84.37% 82.49% -1.89%
================================================
Files 15 15
Lines 960 1011 +51
================================================
+ Hits 810 834 +24
- Misses 150 177 +27 ☔ View full report in Codecov by Sentry. |
Commit d46cf86 added both docstrings and introduced a multiple dispatch scheme by subtyping |
It would be a fun project to investigate whether and how this can be framed in terms of an “Algebraic Path Problem”.[1,2] [1] https://drops.dagstuhl.de/storage/00lipics/lipics-vol211-calco2021/LIPIcs.CALCO.2021.20/LIPIcs.CALCO.2021.20.pdf |
src/graph_traversal.jl
Outdated
function topological_sort_verts(d::SummationDecapode) | ||
m = floyd_warshall(d) | ||
map(parts(d,:Var)) do v | ||
minimum(filter(!isinf, m[v,infer_terminals(d)])) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't do Floyd-Warshall just to do a topological sort. F-W is a more complicated algorithm, has a much higher time complexity, and I'm not entirely convinced that this gets us what we want. Leave the previous implementation of topological sort, since that has been well vetted, and if you want, use the topological sorting to run a shortest paths algorithm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return a list of TraversalNode for :Var
for the output.
test/graph_traversal.jl
Outdated
# XXX Do cycle-detection with FW by using ∞ on the diagonal. | ||
#= | ||
cyclic = @decapode begin | ||
B == g(A) | ||
A == f(B) | ||
end | ||
@test_throws AssertionError topological_sort_edges(cyclic) | ||
=# |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this test removed? I don't think we do cycle detection anywhere else in the parsing pipeline so this should be checked here.
test/graph_traversal.jl
Outdated
|
||
sum_with_single_dependency = @decapode begin | ||
F == A + f(A) + h(g(A)) | ||
end | ||
result = topological_sort_edges(sum_with_single_dependency) | ||
@test is_correct_length(sum_with_single_dependency, result) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add tests for the F-W algorithm.
src/graph_traversal.jl
Outdated
dom::AbstractVector | ||
cod::Int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call these src/tgt since we're talking about hypergraphs.
src/graph_traversal.jl
Outdated
TraversalNode(i, d::SummationDecapode, ::Val{:Op1}) = | ||
TraversalNode{Symbol}(i, d[i,:op1], [d[i,:src]], d[i,:tgt]) | ||
|
||
# TODO: Collect these visited arrays into one structure indexed by :Op1, :Op2, and :Σ | ||
visited_1 = falses(nparts(d, :Op1)) | ||
visited_2 = falses(nparts(d, :Op2)) | ||
visited_Σ = falses(nparts(d, :Σ)) | ||
TraversalNode(i, d::SummationDecapode, ::Val{:Op2}) = | ||
TraversalNode{Symbol}(i, d[i,:op2], [d[i,:proj1],d[i,:proj2]], d[i,:res]) | ||
|
||
# FIXME: this is a quadratic implementation of topological_sort inlined in here. | ||
op_order = TraversalNode{Symbol}[] | ||
TraversalNode(i, d::SummationDecapode, ::Val{:Σ}) = | ||
TraversalNode{Symbol}(i, :+, d[incident(d,i,:summation),:summand], d[i,:sum]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of the dispatching being a seperate argument, maybe we can bake that dispatching into the struct type, so we have TraversalNode{Op1}
instead of TraversalNode{Symbol}
with a name
field that is :Op1.
src/graph_traversal.jl
Outdated
function hyper_edge_list(d::SummationDecapode) | ||
[map(e -> TraversalNode(e, d, Val(:Op1)), parts(d, :Op1))..., | ||
map(e -> TraversalNode(e, d, Val(:Op2)), parts(d, :Op2))..., | ||
map(e -> TraversalNode(e, d, Val(:Σ )), parts(d, :Σ ))...] | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have a function that returns all of the "edge" symbols, so in this case Op1, Op2, Σ
and just iterate over those with the interior functionality. Can also do this with all the "vertex" symbols.
@GeorgeR227 The overarching purpose of this PR to demonstrate how to transform Decapode into a well-known data structure, i.e. a graph, at which point we can use generic traversal algorithms. Not bespoke or manually-inlined traversal algorithms over the bespoke SummationDecapode data structure. To wit, compare the Floyd-Warshall algorithm as implemented here with the pseudocode given for it on Wikipedia. The choice of Floyd-Warshall vs. multi-start Dijkstra's vs. Kuhn's and so on is somewhat beside the point, but of course time and space complexity, weighed against the average size of our datastructures (< 1000 vertices), are to be weighed against maintainability before such a PR is merged. Treat it as a proof of concept for the time being. |
I get your idea about make our hypergraph algorithms more generic. I think many people have wanted that and I do want to keep those parts of this PR. What I don't get is the decision to base everything on Floyd-Warshall. If F-W can be made into a generic hypergraph algorithm, then why can't topological sort? The implementation was almost there, it just needed the concept of the generic edge (which you implemented here) plus a bit of other functionality probably. My main idea here is that the decision to use F-W makes this code less scalable/performant, less readable (since this is no longer the standard topological sort algorithm most people are familiar with) and less maintainable (because now we have graph algorithms which depend on other graph algorithms when there's no reason they have to). I like the push towards going generic (even though that wasn't the explicit push of the branch this is based off) and I don't even mind the inclusion of F-W but it should not be used in the topological sort. |
We're on the same page |
This struct organizes the data into a more generic hypergraph that can then be routed through generic graph algorithms, like topo sort or F-W, without relying on the underlying ACSet structure.
@GeorgeR227 The most recent commit needs to use |
Yeah I can do that. Any thoughts on the generic |
We should probably just switch to using an incidence matrix. Also accommodates arguments of arbitrary arity. In Decapodes then just "dispatch"/ switch/ pattern-match on arity and name of symbol. Restricting operations to unary ops, binary ops, and sums is no longer is a necessary design constraint. |
Or just use this schema, migration or otherwise. Nodes are rows in the Var table. Edges are cached calls to (dom = d[incident(d,i,:arg_op),:arg_var], cod = d[i,:res], op = function[i]) @schema SchVariadicDecapode begin # SchHyperGraph
Var::Ob
(Type, VarName, Operator)::AttrType(Symbol)
type::Attr(Var, Type)
name::Attr(Var, Name)
(Op, Argument)::Ob
(Function)::AttrType(Symbol)
function::Attr(Op, Function)
arg_var::Hom(Argument, Var)
arg_op::Hom(Argument, Op)
res::Hom(Op, Var)
end |
2a6269c
to
9d8dfca
Compare
378d6a1
to
e0ff9a8
Compare
The Floyd-Warshall algorithm can be defined on the variables of a Decapode. This entails a topological ordering of those variables. A topological ordering of operations is given in turn.