mirror of
https://code.forgejo.org/forgejo/runner.git
synced 2025-08-26 18:20:59 +00:00
replace parser with actions/workflow-parser
This commit is contained in:
parent
f6be37b2a2
commit
d956aff028
41 changed files with 12740 additions and 633 deletions
254
vendor/github.com/soniakeys/graph/mst.go
generated
vendored
Normal file
254
vendor/github.com/soniakeys/graph/mst.go
generated
vendored
Normal file
|
@ -0,0 +1,254 @@
|
|||
// Copyright 2014 Sonia Keys
|
||||
// License MIT: http://opensource.org/licenses/MIT
|
||||
|
||||
package graph
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"sort"
|
||||
|
||||
"github.com/soniakeys/bits"
|
||||
)
|
||||
|
||||
type dsElement struct {
|
||||
from NI
|
||||
rank int
|
||||
}
|
||||
|
||||
type disjointSet struct {
|
||||
set []dsElement
|
||||
}
|
||||
|
||||
func newDisjointSet(n int) disjointSet {
|
||||
set := make([]dsElement, n)
|
||||
for i := range set {
|
||||
set[i].from = -1
|
||||
}
|
||||
return disjointSet{set}
|
||||
}
|
||||
|
||||
// return true if disjoint trees were combined.
|
||||
// false if x and y were already in the same tree.
|
||||
func (ds disjointSet) union(x, y NI) bool {
|
||||
xr := ds.find(x)
|
||||
yr := ds.find(y)
|
||||
if xr == yr {
|
||||
return false
|
||||
}
|
||||
switch xe, ye := &ds.set[xr], &ds.set[yr]; {
|
||||
case xe.rank < ye.rank:
|
||||
xe.from = yr
|
||||
case xe.rank == ye.rank:
|
||||
xe.rank++
|
||||
fallthrough
|
||||
default:
|
||||
ye.from = xr
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (ds disjointSet) find(n NI) NI {
|
||||
// fast paths for n == root or from root.
|
||||
// no updates need in these cases.
|
||||
s := ds.set
|
||||
fr := s[n].from
|
||||
if fr < 0 { // n is root
|
||||
return n
|
||||
}
|
||||
n, fr = fr, s[fr].from
|
||||
if fr < 0 { // n is from root
|
||||
return n
|
||||
}
|
||||
// otherwise updates needed.
|
||||
// two iterative passes (rather than recursion or stack)
|
||||
// pass 1: find root
|
||||
r := fr
|
||||
for {
|
||||
f := s[r].from
|
||||
if f < 0 {
|
||||
break
|
||||
}
|
||||
r = f
|
||||
}
|
||||
// pass 2: update froms
|
||||
for {
|
||||
s[n].from = r
|
||||
if fr == r {
|
||||
return r
|
||||
}
|
||||
n = fr
|
||||
fr = s[n].from
|
||||
}
|
||||
}
|
||||
|
||||
// Kruskal implements Kruskal's algorithm for constructing a minimum spanning
|
||||
// forest on an undirected graph.
|
||||
//
|
||||
// The forest is returned as an undirected graph.
|
||||
//
|
||||
// Also returned is a total distance for the returned forest.
|
||||
//
|
||||
// This method is a convenience wrapper for LabeledEdgeList.Kruskal.
|
||||
// If you have no need for the input graph as a LabeledUndirected, it may be
|
||||
// more efficient to construct a LabeledEdgeList directly.
|
||||
func (g LabeledUndirected) Kruskal(w WeightFunc) (spanningForest LabeledUndirected, dist float64) {
|
||||
return g.WeightedArcsAsEdges(w).Kruskal()
|
||||
}
|
||||
|
||||
// Kruskal implements Kruskal's algorithm for constructing a minimum spanning
|
||||
// forest on an undirected graph.
|
||||
//
|
||||
// The algorithm allows parallel edges, thus it is acceptable to construct
|
||||
// the receiver with LabeledUndirected.WeightedArcsAsEdges. It may be more
|
||||
// efficient though, if you can construct the receiver WeightedEdgeList
|
||||
// directly without parallel edges.
|
||||
//
|
||||
// The forest is returned as an undirected graph.
|
||||
//
|
||||
// Also returned is a total distance for the returned forest.
|
||||
//
|
||||
// The edge list of the receiver is sorted in place as a side effect of this
|
||||
// method. See KruskalSorted for a version that relies on the edge list being
|
||||
// already sorted. This method is a wrapper for KruskalSorted. If you can
|
||||
// generate the input graph sorted as required for KruskalSorted, you can
|
||||
// call that method directly and avoid the overhead of the sort.
|
||||
func (l WeightedEdgeList) Kruskal() (g LabeledUndirected, dist float64) {
|
||||
e := l.Edges
|
||||
w := l.WeightFunc
|
||||
sort.Slice(e, func(i, j int) bool { return w(e[i].LI) < w(e[j].LI) })
|
||||
return l.KruskalSorted()
|
||||
}
|
||||
|
||||
// KruskalSorted implements Kruskal's algorithm for constructing a minimum
|
||||
// spanning tree on an undirected graph.
|
||||
//
|
||||
// When called, the edge list of the receiver must be already sorted by weight.
|
||||
// See the Kruskal method for a version that accepts an unsorted edge list.
|
||||
// As with Kruskal, parallel edges are allowed.
|
||||
//
|
||||
// The forest is returned as an undirected graph.
|
||||
//
|
||||
// Also returned is a total distance for the returned forest.
|
||||
func (l WeightedEdgeList) KruskalSorted() (g LabeledUndirected, dist float64) {
|
||||
ds := newDisjointSet(l.Order)
|
||||
g.LabeledAdjacencyList = make(LabeledAdjacencyList, l.Order)
|
||||
for _, e := range l.Edges {
|
||||
if ds.union(e.N1, e.N2) {
|
||||
g.AddEdge(Edge{e.N1, e.N2}, e.LI)
|
||||
dist += l.WeightFunc(e.LI)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Prim implements the Jarník-Prim-Dijkstra algorithm for constructing
|
||||
// a minimum spanning tree on an undirected graph.
|
||||
//
|
||||
// Prim computes a minimal spanning tree on the connected component containing
|
||||
// the given start node. The tree is returned in FromList f. Argument f
|
||||
// cannot be a nil pointer although it can point to a zero value FromList.
|
||||
//
|
||||
// If the passed FromList.Paths has the len of g though, it will be reused.
|
||||
// In the case of a graph with multiple connected components, this allows a
|
||||
// spanning forest to be accumulated by calling Prim successively on
|
||||
// representative nodes of the components. In this case if leaves for
|
||||
// individual trees are of interest, pass a non-nil zero-value for the argument
|
||||
// componentLeaves and it will be populated with leaves for the single tree
|
||||
// spanned by the call.
|
||||
//
|
||||
// If argument labels is non-nil, it must have the same length as g and will
|
||||
// be populated with labels corresponding to the edges of the tree.
|
||||
//
|
||||
// Returned are the number of nodes spanned for the single tree (which will be
|
||||
// the order of the connected component) and the total spanned distance for the
|
||||
// single tree.
|
||||
func (g LabeledUndirected) Prim(start NI, w WeightFunc, f *FromList, labels []LI, componentLeaves *bits.Bits) (numSpanned int, dist float64) {
|
||||
al := g.LabeledAdjacencyList
|
||||
if len(f.Paths) != len(al) {
|
||||
*f = NewFromList(len(al))
|
||||
}
|
||||
if f.Leaves.Num != len(al) {
|
||||
f.Leaves = bits.New(len(al))
|
||||
}
|
||||
b := make([]prNode, len(al)) // "best"
|
||||
for n := range b {
|
||||
b[n].nx = NI(n)
|
||||
b[n].fx = -1
|
||||
}
|
||||
rp := f.Paths
|
||||
var frontier prHeap
|
||||
rp[start] = PathEnd{From: -1, Len: 1}
|
||||
numSpanned = 1
|
||||
fLeaves := &f.Leaves
|
||||
fLeaves.SetBit(int(start), 1)
|
||||
if componentLeaves != nil {
|
||||
if componentLeaves.Num != len(al) {
|
||||
*componentLeaves = bits.New(len(al))
|
||||
}
|
||||
componentLeaves.SetBit(int(start), 1)
|
||||
}
|
||||
for a := start; ; {
|
||||
for _, nb := range al[a] {
|
||||
if rp[nb.To].Len > 0 {
|
||||
continue // already in MST, no action
|
||||
}
|
||||
switch bp := &b[nb.To]; {
|
||||
case bp.fx == -1: // new node for frontier
|
||||
bp.from = fromHalf{From: a, Label: nb.Label}
|
||||
bp.wt = w(nb.Label)
|
||||
heap.Push(&frontier, bp)
|
||||
case w(nb.Label) < bp.wt: // better arc
|
||||
bp.from = fromHalf{From: a, Label: nb.Label}
|
||||
bp.wt = w(nb.Label)
|
||||
heap.Fix(&frontier, bp.fx)
|
||||
}
|
||||
}
|
||||
if len(frontier) == 0 {
|
||||
break // done
|
||||
}
|
||||
bp := heap.Pop(&frontier).(*prNode)
|
||||
a = bp.nx
|
||||
rp[a].Len = rp[bp.from.From].Len + 1
|
||||
rp[a].From = bp.from.From
|
||||
if len(labels) != 0 {
|
||||
labels[a] = bp.from.Label
|
||||
}
|
||||
dist += bp.wt
|
||||
fLeaves.SetBit(int(bp.from.From), 0)
|
||||
fLeaves.SetBit(int(a), 1)
|
||||
if componentLeaves != nil {
|
||||
componentLeaves.SetBit(int(bp.from.From), 0)
|
||||
componentLeaves.SetBit(int(a), 1)
|
||||
}
|
||||
numSpanned++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type prNode struct {
|
||||
nx NI
|
||||
from fromHalf
|
||||
wt float64 // p.Weight(from.Label)
|
||||
fx int
|
||||
}
|
||||
|
||||
type prHeap []*prNode
|
||||
|
||||
func (h prHeap) Len() int { return len(h) }
|
||||
func (h prHeap) Less(i, j int) bool { return h[i].wt < h[j].wt }
|
||||
func (h prHeap) Swap(i, j int) {
|
||||
h[i], h[j] = h[j], h[i]
|
||||
h[i].fx = i
|
||||
h[j].fx = j
|
||||
}
|
||||
func (p *prHeap) Push(x interface{}) {
|
||||
nd := x.(*prNode)
|
||||
nd.fx = len(*p)
|
||||
*p = append(*p, nd)
|
||||
}
|
||||
func (p *prHeap) Pop() interface{} {
|
||||
r := *p
|
||||
last := len(r) - 1
|
||||
*p = r[:last]
|
||||
return r[last]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue