Skip to content
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

Open
wants to merge 16 commits into
base: gr/acset2sym
Choose a base branch
from
Open

Floyd-Warshall #70

wants to merge 16 commits into from

Conversation

lukem12345
Copy link
Member

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.

Copy link

codecov bot commented Aug 24, 2024

Codecov Report

Attention: Patch coverage is 67.74194% with 30 lines in your changes missing coverage. Please review.

Project coverage is 82.49%. Comparing base (2a6269c) to head (a93295a).

Files with missing lines Patch % Lines
src/graph_interface.jl 64.06% 23 Missing ⚠️
src/acset2symbolic.jl 75.86% 7 Missing ⚠️
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.
📢 Have feedback on the report? Share it here.

@lukem12345
Copy link
Member Author

Commit d46cf86 added both docstrings and introduced a multiple dispatch scheme by subtyping TraversalNode. The MD scheme can be undone depending on design constraints I’m not aware of. This results in cleaner algorithm code

@lukem12345
Copy link
Member Author

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
[2] https://edge.edx.org/asset-v1:BerkeleyX+CS188-SU16+SU16+type@asset+block/kleene_algebras_path_problems.pdf

Comment on lines 87 to 92
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
Copy link
Contributor

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.

Copy link
Contributor

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.

Comment on lines 32 to 39
# 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)
=#
Copy link
Contributor

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.

Comment on lines 67 to 72

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)
Copy link
Contributor

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.

Comment on lines 9 to 10
dom::AbstractVector
cod::Int
Copy link
Contributor

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.

Comment on lines 13 to 20
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])
Copy link
Contributor

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.

Comment on lines 42 to 46
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
Copy link
Contributor

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.

@lukem12345
Copy link
Member Author

@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.

@GeorgeR227
Copy link
Contributor

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.

@lukem12345
Copy link
Member Author

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.
@lukem12345
Copy link
Member Author

@GeorgeR227 The most recent commit needs to use git mv. We shouldn't delete files and place their contents in new files.

@GeorgeR227
Copy link
Contributor

Yeah I can do that. Any thoughts on the generic HyperGraph?

@lukem12345
Copy link
Member Author

lukem12345 commented Aug 29, 2024

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.

@lukem12345
Copy link
Member Author

lukem12345 commented Aug 29, 2024

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

@GeorgeR227 GeorgeR227 force-pushed the gr/acset2sym branch 2 times, most recently from 378d6a1 to e0ff9a8 Compare September 18, 2024 17:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants