forked from fieldryand/goflow
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdag.go
125 lines (97 loc) · 2.14 KB
/
dag.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package goflow
import (
"github.com/ef-ds/deque"
)
// Credit: The DAG implementation here is roughly a port of the
// one from this Python project: https://github.com/thieman/dagobah
// A DAG is a directed acyclic graph represented by a simple map
// where a key is a node in the graph, and a value is a slice of
// immediately downstream dependent nodes.
type dag map[string][]string
// A node has a name and 0 or more dependent nodes
func (d dag) addNode(name string) {
deps := make([]string, 0)
d[name] = deps
}
// Create an edge between an independent and dependent node
func (d dag) setDownstream(ind, dep string) {
d[ind] = append(d[ind], dep)
}
// Returns true if a node is a downstream node, false if it
// is independent.
func (d dag) isDownstream(nodeName string) bool {
ind := d.independentNodes()
for _, name := range ind {
if nodeName == name {
return false
}
}
return true
}
// Ensure the DAG is acyclic
func (d dag) validate() bool {
degree := make(map[string]int)
for node := range d {
degree[node] = 0
}
for _, ds := range d {
for _, i := range ds {
degree[i]++
}
}
var deq deque.Deque
for node, val := range degree {
if val == 0 {
deq.PushFront(node)
}
}
l := make([]string, 0)
for {
popped, ok := deq.PopBack()
if !ok {
break
} else {
node := popped.(string)
l = append(l, node)
for ds := range d {
degree[ds]--
if degree[ds] == 0 {
deq.PushFront(ds)
}
}
}
}
return len(l) == len(d)
}
// Return the immediately upstream nodes for a given node
func (d dag) dependencies(node string) []string {
dependencies := make([]string, 0)
for dep, ds := range d {
for _, i := range ds {
if node == i {
dependencies = append(dependencies, dep)
}
}
}
return dependencies
}
// Return all the independent nodes in the graph
func (d dag) independentNodes() []string {
downstream := make([]string, 0)
for _, ds := range d {
downstream = append(downstream, ds...)
}
ind := make([]string, 0)
for node := range d {
ctr := 0
for _, i := range downstream {
if node == i {
ctr++
}
}
if ctr == 0 {
ind = append(ind, node)
}
}
return ind
}