notes for gim on graph drawing algo, and some TODOs
This commit is contained in:
parent
1dc53518af
commit
c16fc00bf7
16
gg/gg.go
16
gg/gg.go
@ -8,6 +8,22 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO it's a bit unfortunate that it's possible to create disjointed graphs
|
||||||
|
// within the same graph instance. That's not really something that would be
|
||||||
|
// possible with any other type of datastructure. I think all that would be
|
||||||
|
// needed to get rid of this is to remove the Null instance and instead do a
|
||||||
|
// New(value) function. This would allow a graph to be just a single value with
|
||||||
|
// no edges, but I _think_ that's fine?
|
||||||
|
//
|
||||||
|
// Actually, that's kinda bogus, it really messes with how I conceptualized
|
||||||
|
// ginger being used. Which is maybe fine. I should do some research on the
|
||||||
|
// typical way that graphs and other structures are defined.
|
||||||
|
//
|
||||||
|
// It seems that disjoint unions, as they're called, are an accepted thing... if
|
||||||
|
// I need it for gim a Disjoin method might be the best bet, which would walk
|
||||||
|
// through the Graph and compute each disjointed Graph and return them
|
||||||
|
// individually.
|
||||||
|
|
||||||
// Value wraps a go value in a way such that it will be uniquely identified
|
// Value wraps a go value in a way such that it will be uniquely identified
|
||||||
// within any Graph and between Graphs. Use NewValue to create a Value instance.
|
// within any Graph and between Graphs. Use NewValue to create a Value instance.
|
||||||
// You can create an instance manually as long as ID is globally unique.
|
// You can create an instance manually as long as ID is globally unique.
|
||||||
|
71
gim/NOTES
Normal file
71
gim/NOTES
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
Notes from reading https://www.graphviz.org/Documentation/TSE93.pdf, which
|
||||||
|
describes an algorithm for drawing an acyclic graph in basically the way which I
|
||||||
|
want.
|
||||||
|
|
||||||
|
This document assumes the primary flow of drawing is downward, and secondary is
|
||||||
|
right.
|
||||||
|
|
||||||
|
For all of this it might be easier to not even consider edge values yet, as
|
||||||
|
those could be done by converting them into vertices themselves after the
|
||||||
|
cyclic-edge-reversal and then converting them back later.
|
||||||
|
|
||||||
|
Drawing the graph is a four step process:
|
||||||
|
|
||||||
|
1) Rank nodes in the Y axis
|
||||||
|
- Graph must be acyclic.
|
||||||
|
- This can be accomplished by strategically reversing edges which cause
|
||||||
|
a cycle, and then reversing them back as a post-processing step.
|
||||||
|
- Edges can be found by:
|
||||||
|
- walking out from a particular node depth-first from some arbitrary
|
||||||
|
node.
|
||||||
|
- As you do so you assign a rank based on depth to each node you
|
||||||
|
encounter.
|
||||||
|
- If any edge is destined for a node which has already been seen you
|
||||||
|
look at the ranks of the source and destination, and if the source
|
||||||
|
is _greater_ than the destination you reverse the edge's
|
||||||
|
direction.
|
||||||
|
- I think that algorithm only works if there's a source/sink? might have
|
||||||
|
to be modified, or the walk must traverse both to & from.
|
||||||
|
- Assign all edges a weight, default 1, but possibly externally assigned to
|
||||||
|
be greater.
|
||||||
|
- Take a "feasible" minimum spanning tree (MST) of the graph
|
||||||
|
- Feasibility is defined as each edge being "tight", meaning, once you
|
||||||
|
rank each node by their distance from the root and define the length
|
||||||
|
of an edge as the difference of rank of its head and tail, that each
|
||||||
|
tree edge will have a length of 1.
|
||||||
|
- Perform the following on the MST:
|
||||||
|
- For each edge of the graph assign the cut value
|
||||||
|
- If you were to remove any edge of an MST it would create two
|
||||||
|
separate MSTs. The side the edge was pointing from is the tail,
|
||||||
|
the side it was pointing to is the head.
|
||||||
|
- Looking at edges _in the original graph_, sum the weights of all
|
||||||
|
edges directed from the tail to the head (including the one
|
||||||
|
removed) and subtract from that the sum of the weights of the
|
||||||
|
edges directed from the head to the tail. This is the cut value.
|
||||||
|
- "...note that the cut values can be computed using information
|
||||||
|
local to an edge if the search is ordered from the leaves of the
|
||||||
|
feasible tree inward. It is trivial to compute the cut value of a
|
||||||
|
tree edge with one of its endpoints a leaf in the tree, since
|
||||||
|
either the head or the tail component consists of a single node.
|
||||||
|
Now, assuming the cut values are known for all the edges incident
|
||||||
|
on a given node except one, the cut value of the remaining edge is
|
||||||
|
the sum of the known cut values plus a term dependent only on the
|
||||||
|
edges incident to the given node."
|
||||||
|
- Take an edge with a negative cut value and remove it. Find the graph
|
||||||
|
edge between the remaining head and tail MSTs with the smallest
|
||||||
|
"slack" (distance in rank between its ends) and add that edge to the
|
||||||
|
MST to make it connected again.
|
||||||
|
- Repeat until there are no negative cut values.
|
||||||
|
- Apparently searching "cyclically" through the negative edges, rather
|
||||||
|
than iterating from the start each time, is worthwhile.
|
||||||
|
- Normalize the MST by assigning the root node the rank of 0 (and so on), if
|
||||||
|
it changed.
|
||||||
|
- All edges in the MST are of length 1, and the rest can be inferred from
|
||||||
|
that.
|
||||||
|
- To reduce crowding, nodes with equal in/out edge weights and which could
|
||||||
|
be placed on multiple rankings are moved to the ranking with the fewest
|
||||||
|
nodes.
|
||||||
|
|
||||||
|
2) Order nodes in the X axis to reduce edge crossings
|
||||||
|
3) Compute node coordinates
|
||||||
|
4) Determine edge splines
|
@ -16,10 +16,8 @@ import (
|
|||||||
// - Changing the "flow" direction
|
// - Changing the "flow" direction
|
||||||
// - Absolute positioning of some/all vertices
|
// - Absolute positioning of some/all vertices
|
||||||
|
|
||||||
// TODO
|
// TODO be able to draw circular graphs
|
||||||
// - edge values
|
// TODO audit all steps, make sure everything is deterministic
|
||||||
// - be able to draw circular graphs
|
|
||||||
// - audit all steps, make sure everything is deterministic
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
framerate = 10
|
framerate = 10
|
||||||
|
Loading…
Reference in New Issue
Block a user