replace parser with actions/workflow-parser
This commit is contained in:
498
vendor/github.com/soniakeys/graph/fromlist.go
generated
vendored
Normal file
498
vendor/github.com/soniakeys/graph/fromlist.go
generated
vendored
Normal file
@@ -0,0 +1,498 @@
|
||||
// Copyright 2014 Sonia Keys
|
||||
// License MIT: http://opensource.org/licenses/MIT
|
||||
|
||||
package graph
|
||||
|
||||
import "github.com/soniakeys/bits"
|
||||
|
||||
// FromList represents a rooted tree (or forest) where each node is associated
|
||||
// with a half arc identifying an arc "from" another node.
|
||||
//
|
||||
// Other terms for this data structure include "parent list",
|
||||
// "predecessor list", "in-tree", "inverse arborescence", and
|
||||
// "spaghetti stack."
|
||||
//
|
||||
// The Paths member represents the tree structure. Leaves and MaxLen are
|
||||
// not always needed. Where Leaves is used it serves as a bitmap where
|
||||
// Leaves.Bit(n) == 1 for each leaf n of the tree. Where MaxLen is used it is
|
||||
// provided primarily as a convenience for functions that might want to
|
||||
// anticipate the maximum path length that would be encountered traversing
|
||||
// the tree.
|
||||
//
|
||||
// Various graph search methods use a FromList to returns search results.
|
||||
// For a start node of a search, From will be -1 and Len will be 1. For other
|
||||
// nodes reached by the search, From represents a half arc in a path back to
|
||||
// start and Len represents the number of nodes in the path. For nodes not
|
||||
// reached by the search, From will be -1 and Len will be 0.
|
||||
//
|
||||
// A single FromList can also represent a forest. In this case paths from
|
||||
// all leaves do not return to a single root node, but multiple root nodes.
|
||||
//
|
||||
// While a FromList generally encodes a tree or forest, it is technically
|
||||
// possible to encode a cyclic graph. A number of FromList methods require
|
||||
// the receiver to be acyclic. Graph methods documented to return a tree or
|
||||
// forest will never return a cyclic FromList. In other cases however,
|
||||
// where a FromList is not known to by cyclic, the Cyclic method can be
|
||||
// useful to validate the acyclic property.
|
||||
type FromList struct {
|
||||
Paths []PathEnd // tree representation
|
||||
Leaves bits.Bits // leaves of tree
|
||||
MaxLen int // length of longest path, max of all PathEnd.Len values
|
||||
}
|
||||
|
||||
// PathEnd associates a half arc and a path length.
|
||||
//
|
||||
// A PathEnd list is an element type of FromList.
|
||||
type PathEnd struct {
|
||||
From NI // a "from" half arc, the node the arc comes from
|
||||
Len int // number of nodes in path from start
|
||||
}
|
||||
|
||||
/* NewFromList could be confusing now with bits also needing allocation.
|
||||
maybe best to not have this function. Maybe a more useful new would be
|
||||
one that took a PathEnd slice and intitialized everything including roots
|
||||
and max len. Maybe its time for a separate []PathEnd type when that's
|
||||
all that's needed. (and reconsider the name PathEnd)
|
||||
*/
|
||||
|
||||
// NewFromList creates a FromList object of given order.
|
||||
//
|
||||
// The Paths member is allocated to the specified order n but other members
|
||||
// are left as zero values.
|
||||
func NewFromList(n int) FromList {
|
||||
return FromList{Paths: make([]PathEnd, n)}
|
||||
}
|
||||
|
||||
// BoundsOk validates the "from" values in the list.
|
||||
//
|
||||
// Negative values are allowed as they indicate root nodes.
|
||||
//
|
||||
// BoundsOk returns true when all from values are less than len(t).
|
||||
// Otherwise it returns false and a node with a from value >= len(t).
|
||||
func (f FromList) BoundsOk() (ok bool, n NI) {
|
||||
for n, e := range f.Paths {
|
||||
if int(e.From) >= len(f.Paths) {
|
||||
return false, NI(n)
|
||||
}
|
||||
}
|
||||
return true, -1
|
||||
}
|
||||
|
||||
// CommonStart returns the common start node of minimal paths to a and b.
|
||||
//
|
||||
// It returns -1 if a and b cannot be traced back to a common node.
|
||||
//
|
||||
// The method relies on populated PathEnd.Len members. Use RecalcLen if
|
||||
// the Len members are not known to be present and correct.
|
||||
func (f FromList) CommonStart(a, b NI) NI {
|
||||
p := f.Paths
|
||||
if p[a].Len < p[b].Len {
|
||||
a, b = b, a
|
||||
}
|
||||
for bl := p[b].Len; p[a].Len > bl; {
|
||||
a = p[a].From
|
||||
if a < 0 {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
for a != b {
|
||||
a = p[a].From
|
||||
if a < 0 {
|
||||
return -1
|
||||
}
|
||||
b = p[b].From
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// Cyclic determines if f contains a cycle, a non-empty path from a node
|
||||
// back to itself.
|
||||
//
|
||||
// Cyclic returns true if g contains at least one cycle. It also returns
|
||||
// an example of a node involved in a cycle.
|
||||
//
|
||||
// Cyclic returns (false, -1) in the normal case where f is acyclic.
|
||||
// Note that the bool is not an "ok" return. A cyclic FromList is usually
|
||||
// not okay.
|
||||
func (f FromList) Cyclic() (cyclic bool, n NI) {
|
||||
p := f.Paths
|
||||
vis := bits.New(len(p))
|
||||
for i := range p {
|
||||
path := bits.New(len(p))
|
||||
for n := i; vis.Bit(n) == 0; {
|
||||
vis.SetBit(n, 1)
|
||||
path.SetBit(n, 1)
|
||||
if n = int(p[n].From); n < 0 {
|
||||
break
|
||||
}
|
||||
if path.Bit(n) == 1 {
|
||||
return true, NI(n)
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, -1
|
||||
}
|
||||
|
||||
// IsolatedNodeBits returns a bitmap of isolated nodes in receiver graph f.
|
||||
//
|
||||
// An isolated node is one with no arcs going to or from it.
|
||||
func (f FromList) IsolatedNodes() (iso bits.Bits) {
|
||||
p := f.Paths
|
||||
iso = bits.New(len(p))
|
||||
iso.SetAll()
|
||||
for n, e := range p {
|
||||
if e.From >= 0 {
|
||||
iso.SetBit(n, 0)
|
||||
iso.SetBit(int(e.From), 0)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PathTo decodes a FromList, recovering a single path.
|
||||
//
|
||||
// The path is returned as a list of nodes where the first element will be
|
||||
// a root node and the last element will be the specified end node.
|
||||
//
|
||||
// Only the Paths member of the receiver is used. Other members of the
|
||||
// FromList do not need to be valid, however the MaxLen member can be useful
|
||||
// for allocating argument p.
|
||||
//
|
||||
// Argument p can provide the result slice. If p has capacity for the result
|
||||
// it will be used, otherwise a new slice is created for the result.
|
||||
//
|
||||
// See also function PathTo.
|
||||
func (f FromList) PathTo(end NI, p []NI) []NI {
|
||||
return PathTo(f.Paths, end, p)
|
||||
}
|
||||
|
||||
// PathTo decodes a single path from a PathEnd list.
|
||||
//
|
||||
// A PathEnd list is the main data representation in a FromList. See FromList.
|
||||
//
|
||||
// PathTo returns a list of nodes where the first element will be
|
||||
// a root node and the last element will be the specified end node.
|
||||
//
|
||||
// Argument p can provide the result slice. If p has capacity for the result
|
||||
// it will be used, otherwise a new slice is created for the result.
|
||||
//
|
||||
// See also method FromList.PathTo.
|
||||
func PathTo(paths []PathEnd, end NI, p []NI) []NI {
|
||||
n := paths[end].Len
|
||||
if n == 0 {
|
||||
return p[:0]
|
||||
}
|
||||
if cap(p) >= n {
|
||||
p = p[:n]
|
||||
} else {
|
||||
p = make([]NI, n)
|
||||
}
|
||||
for {
|
||||
n--
|
||||
p[n] = end
|
||||
if n == 0 {
|
||||
return p
|
||||
}
|
||||
end = paths[end].From
|
||||
}
|
||||
}
|
||||
|
||||
// PathToLabeled decodes a FromList, recovering a single path.
|
||||
//
|
||||
// The start of the returned path will be a root node of the FromList.
|
||||
//
|
||||
// Only the Paths member of the receiver is used. Other members of the
|
||||
// FromList do not need to be valid, however the MaxLen member can be useful
|
||||
// for allocating argument p.
|
||||
//
|
||||
// Argument p can provide the result slice. If p has capacity for the result
|
||||
// it will be used, otherwise a new slice is created for the result.
|
||||
//
|
||||
// See also function PathTo.
|
||||
func (f FromList) PathToLabeled(end NI, labels []LI, p []Half) LabeledPath {
|
||||
n := f.Paths[end].Len - 1
|
||||
if n <= 0 {
|
||||
return LabeledPath{end, p[:0]}
|
||||
}
|
||||
if cap(p) >= n {
|
||||
p = p[:n]
|
||||
} else {
|
||||
p = make([]Half, n)
|
||||
}
|
||||
for {
|
||||
n--
|
||||
p[n] = Half{To: end, Label: labels[end]}
|
||||
end = f.Paths[end].From
|
||||
if n == 0 {
|
||||
return LabeledPath{end, p}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Preorder traverses a FromList in preorder.
|
||||
//
|
||||
// Nodes are visited in order such that for any node n with from node fr,
|
||||
// fr is visited before n. Where f represents a tree, the visit ordering
|
||||
// corresponds to a preordering, or depth first traversal of the tree.
|
||||
// Where f represents a forest, the preorderings of the trees can be
|
||||
// intermingled.
|
||||
//
|
||||
// Leaves must be set correctly first. Use RecalcLeaves if leaves are not
|
||||
// known to be set correctly. FromList f cannot be cyclic.
|
||||
//
|
||||
// Traversal continues while visitor function v returns true. It terminates
|
||||
// if v returns false. Preorder returns true if it completes without v
|
||||
// returning false. Preorder returns false if traversal is terminated by v
|
||||
// returning false.
|
||||
func (f FromList) Preorder(v func(NI) bool) bool {
|
||||
p := f.Paths
|
||||
done := bits.New(len(p))
|
||||
var df func(NI) bool
|
||||
df = func(n NI) bool {
|
||||
done.SetBit(int(n), 1)
|
||||
if fr := p[n].From; fr >= 0 && done.Bit(int(fr)) == 0 {
|
||||
df(fr)
|
||||
}
|
||||
return v(n)
|
||||
}
|
||||
for n := range f.Paths {
|
||||
p[n].Len = 0
|
||||
}
|
||||
return f.Leaves.IterateOnes(func(n int) bool {
|
||||
return df(NI(n))
|
||||
})
|
||||
}
|
||||
|
||||
// RecalcLeaves recomputes the Leaves member of f.
|
||||
func (f *FromList) RecalcLeaves() {
|
||||
p := f.Paths
|
||||
lv := &f.Leaves
|
||||
if lv.Num != len(p) {
|
||||
*lv = bits.New(len(p))
|
||||
}
|
||||
lv.SetAll()
|
||||
for n := range f.Paths {
|
||||
if fr := p[n].From; fr >= 0 {
|
||||
lv.SetBit(int(fr), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RecalcLen recomputes Len for each path end, and recomputes MaxLen.
|
||||
//
|
||||
// RecalcLen relies on the Leaves member being valid. If it is not known
|
||||
// to be valid, call RecalcLeaves before calling RecalcLen.
|
||||
//
|
||||
// RecalcLen will panic if the FromList is cyclic. Use the Cyclic method
|
||||
// if needed to verify that the FromList is acyclic.
|
||||
func (f *FromList) RecalcLen() {
|
||||
p := f.Paths
|
||||
var setLen func(NI) int
|
||||
setLen = func(n NI) int {
|
||||
switch {
|
||||
case p[n].Len > 0:
|
||||
return p[n].Len
|
||||
case p[n].From < 0:
|
||||
p[n].Len = 1
|
||||
return 1
|
||||
}
|
||||
l := 1 + setLen(p[n].From)
|
||||
p[n].Len = l
|
||||
return l
|
||||
}
|
||||
for n := range f.Paths {
|
||||
p[n].Len = 0
|
||||
}
|
||||
f.MaxLen = 0
|
||||
f.Leaves.IterateOnes(func(n int) bool {
|
||||
if l := setLen(NI(n)); l > f.MaxLen {
|
||||
f.MaxLen = l
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// ReRoot reorients the tree containing n to make n the root node.
|
||||
//
|
||||
// It keeps the tree connected by "reversing" the path from n to the old root.
|
||||
//
|
||||
// After ReRoot, the Leaves and Len members are invalid.
|
||||
// Call RecalcLeaves or RecalcLen as needed.
|
||||
func (f *FromList) ReRoot(n NI) {
|
||||
p := f.Paths
|
||||
fr := p[n].From
|
||||
if fr < 0 {
|
||||
return
|
||||
}
|
||||
p[n].From = -1
|
||||
for {
|
||||
ff := p[fr].From
|
||||
p[fr].From = n
|
||||
if ff < 0 {
|
||||
return
|
||||
}
|
||||
n = fr
|
||||
fr = ff
|
||||
}
|
||||
}
|
||||
|
||||
// Root finds the root of a node in a FromList.
|
||||
func (f FromList) Root(n NI) NI {
|
||||
for p := f.Paths; ; {
|
||||
fr := p[n].From
|
||||
if fr < 0 {
|
||||
return n
|
||||
}
|
||||
n = fr
|
||||
}
|
||||
}
|
||||
|
||||
// Transpose constructs the directed graph corresponding to FromList f
|
||||
// but with arcs in the opposite direction. That is, from roots toward leaves.
|
||||
//
|
||||
// If non-nil argrument roots is passed, Transpose populates it as roots of
|
||||
// the resulting forest and returns nRoots as a count of the roots.
|
||||
//
|
||||
// The method relies only on the From member of f.Paths. Other members of
|
||||
// the FromList are not used.
|
||||
func (f FromList) Transpose(roots *bits.Bits) (forest Directed, nRoots int) {
|
||||
p := f.Paths
|
||||
g := make(AdjacencyList, len(p))
|
||||
if roots != nil {
|
||||
nRoots = len(p)
|
||||
if roots.Num != nRoots {
|
||||
*roots = bits.New(nRoots)
|
||||
}
|
||||
roots.SetAll()
|
||||
}
|
||||
for i, e := range p {
|
||||
if e.From == -1 {
|
||||
continue
|
||||
}
|
||||
g[e.From] = append(g[e.From], NI(i))
|
||||
if roots != nil && roots.Bit(i) == 1 {
|
||||
roots.SetBit(i, 0)
|
||||
nRoots--
|
||||
}
|
||||
}
|
||||
return Directed{g}, nRoots
|
||||
}
|
||||
|
||||
// TransposeLabeled constructs the labeled directed graph corresponding
|
||||
// to FromList f but with arcs in the opposite direction. That is, from
|
||||
// roots toward leaves.
|
||||
//
|
||||
// The argument labels can be nil. In this case labels are generated matching
|
||||
// the path indexes. This corresponds to the "to", or child node.
|
||||
//
|
||||
// If labels is non-nil, it must be the same length as t.Paths and is used
|
||||
// to look up label numbers by the path index.
|
||||
//
|
||||
// If non-nil argrument roots is passed, Transpose populates it as roots of
|
||||
// the resulting forest and returns nRoots as a count of the roots.
|
||||
//
|
||||
// The method relies only on the From member of f.Paths. Other members of
|
||||
// the FromList are not used.
|
||||
func (f FromList) TransposeLabeled(labels []LI, roots *bits.Bits) (forest LabeledDirected, nRoots int) {
|
||||
p := f.Paths
|
||||
g := make(LabeledAdjacencyList, len(p))
|
||||
if roots != nil {
|
||||
nRoots = len(p)
|
||||
if roots.Num != nRoots {
|
||||
*roots = bits.New(nRoots)
|
||||
}
|
||||
roots.SetAll()
|
||||
}
|
||||
for i, p := range f.Paths {
|
||||
if p.From == -1 {
|
||||
continue
|
||||
}
|
||||
l := LI(i)
|
||||
if labels != nil {
|
||||
l = labels[i]
|
||||
}
|
||||
g[p.From] = append(g[p.From], Half{NI(i), l})
|
||||
if roots != nil && roots.Bit(i) == 1 {
|
||||
roots.SetBit(i, 0)
|
||||
nRoots--
|
||||
}
|
||||
}
|
||||
return LabeledDirected{g}, nRoots
|
||||
}
|
||||
|
||||
// Undirected constructs the undirected graph corresponding to FromList f.
|
||||
//
|
||||
// The resulting graph will be a tree or forest.
|
||||
//
|
||||
// If non-nil argrument roots is passed, Transpose populates it as roots of
|
||||
// the resulting forest and returns nRoots as a count of the roots.
|
||||
//
|
||||
// The method relies only on the From member of f.Paths. Other members of
|
||||
// the FromList are not used.
|
||||
func (f FromList) Undirected(roots *bits.Bits) (forest Undirected, nRoots int) {
|
||||
p := f.Paths
|
||||
g := make(AdjacencyList, len(p))
|
||||
if roots != nil {
|
||||
nRoots = len(p)
|
||||
if roots.Num != nRoots {
|
||||
*roots = bits.New(nRoots)
|
||||
}
|
||||
roots.SetAll()
|
||||
}
|
||||
for i, e := range p {
|
||||
if e.From == -1 {
|
||||
continue
|
||||
}
|
||||
g[i] = append(g[i], e.From)
|
||||
g[e.From] = append(g[e.From], NI(i))
|
||||
if roots != nil && roots.Bit(i) == 1 {
|
||||
roots.SetBit(i, 0)
|
||||
nRoots--
|
||||
}
|
||||
}
|
||||
return Undirected{g}, nRoots
|
||||
}
|
||||
|
||||
// LabeledUndirected constructs the labeled undirected graph corresponding
|
||||
// to FromList f.
|
||||
//
|
||||
// The resulting graph will be a tree or forest.
|
||||
//
|
||||
// The argument labels can be nil. In this case labels are generated matching
|
||||
// the path indexes. This corresponds to the "to", or child node.
|
||||
//
|
||||
// If labels is non-nil, it must be the same length as t.Paths and is used
|
||||
// to look up label numbers by the path index.
|
||||
//
|
||||
// If non-nil argrument roots is passed, LabeledUndirected populates it as
|
||||
// roots of the resulting forest and returns nRoots as a count of the roots.
|
||||
//
|
||||
// The method relies only on the From member of f.Paths. Other members of
|
||||
// the FromList are not used.
|
||||
func (f FromList) LabeledUndirected(labels []LI, roots *bits.Bits) (forest LabeledUndirected, nRoots int) {
|
||||
p := f.Paths
|
||||
g := make(LabeledAdjacencyList, len(p))
|
||||
if roots != nil {
|
||||
nRoots = len(p)
|
||||
if roots.Num != nRoots {
|
||||
*roots = bits.New(nRoots)
|
||||
}
|
||||
roots.SetAll()
|
||||
}
|
||||
for i, p := range f.Paths {
|
||||
if p.From == -1 {
|
||||
continue
|
||||
}
|
||||
l := LI(i)
|
||||
if labels != nil {
|
||||
l = labels[i]
|
||||
}
|
||||
g[i] = append(g[i], Half{p.From, l})
|
||||
g[p.From] = append(g[p.From], Half{NI(i), l})
|
||||
if roots != nil && roots.Bit(i) == 1 {
|
||||
roots.SetBit(i, 0)
|
||||
nRoots--
|
||||
}
|
||||
}
|
||||
return LabeledUndirected{g}, nRoots
|
||||
}
|
||||
Reference in New Issue
Block a user