| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 | package toposortimport (	"bytes"	"fmt"	"sort"	"strings")// Reworked from https://github.com/philopon/go-toposort// Graph represents a directed acyclic graph.type Graph struct {	// Outgoing connections for every node.	outputs map[string]map[string]int	// How many parents each node has.	inputs map[string]int}// NewGraph initializes a new Graph.func NewGraph() *Graph {	return &Graph{		inputs:  map[string]int{},		outputs: map[string]map[string]int{},	}}// Copy clones the graph and returns the independent copy.func (g *Graph) Copy() *Graph {	clone := NewGraph()	for k, v := range g.inputs {		clone.inputs[k] = v	}	for k1, v1 := range g.outputs {		m := map[string]int{}		clone.outputs[k1] = m		for k2, v2 := range v1 {			m[k2] = v2		}	}	return clone}// AddNode inserts a new node into the graph.func (g *Graph) AddNode(name string) bool {	if _, exists := g.outputs[name]; exists {		return false	}	g.outputs[name] = make(map[string]int)	g.inputs[name] = 0	return true}// AddNodes inserts multiple nodes into the graph at once.func (g *Graph) AddNodes(names ...string) bool {	for _, name := range names {		if ok := g.AddNode(name); !ok {			return false		}	}	return true}// AddEdge inserts the link from "from" node to "to" node.func (g *Graph) AddEdge(from, to string) int {	m, ok := g.outputs[from]	if !ok {		return 0	}	m[to] = len(m) + 1	ni := g.inputs[to] + 1	g.inputs[to] = ni	return ni}// ReindexNode updates the internal representation of the node after edge removals.func (g *Graph) ReindexNode(node string) {	children, ok := g.outputs[node]	if !ok {		return	}	keys := []string{}	for key := range children {		keys = append(keys, key)	}	sort.Strings(keys)	for i, key := range keys {		children[key] = i + 1	}}func (g *Graph) unsafeRemoveEdge(from, to string) {	delete(g.outputs[from], to)	g.inputs[to]--}// RemoveEdge deletes the link from "from" node to "to" node.// Call ReindexNode(from) after you finish modifying the edges.func (g *Graph) RemoveEdge(from, to string) bool {	if _, ok := g.outputs[from]; !ok {		return false	}	g.unsafeRemoveEdge(from, to)	return true}// Toposort sorts the nodes in the graph in topological order.func (g *Graph) Toposort() ([]string, bool) {	L := make([]string, 0, len(g.outputs))	S := make([]string, 0, len(g.outputs))	for n := range g.outputs {		if g.inputs[n] == 0 {			S = append(S, n)		}	}	sort.Strings(S)	for len(S) > 0 {		var n string		n, S = S[0], S[1:]		L = append(L, n)		ms := make([]string, len(g.outputs[n]))		for m, i := range g.outputs[n] {			ms[i-1] = m		}		for _, m := range ms {			g.unsafeRemoveEdge(n, m)			if g.inputs[m] == 0 {				S = append(S, m)			}		}	}	N := 0	for _, v := range g.inputs {		N += v	}	if N > 0 {		return L, false	}	return L, true}// BreadthSort sorts the nodes in the graph in BFS order.func (g *Graph) BreadthSort() []string {	L := make([]string, 0, len(g.outputs))	S := make([]string, 0, len(g.outputs))	for n := range g.outputs {		if g.inputs[n] == 0 {			S = append(S, n)		}	}	visited := map[string]bool{}	for len(S) > 0 {		node := S[0]		S = S[1:]		if _, exists := visited[node]; !exists {			L = append(L, node)			visited[node] = true			for child := range g.outputs[node] {				S = append(S, child)			}		}	}	return L}// FindCycle returns the cycle in the graph which contains "seed" node.func (g *Graph) FindCycle(seed string) []string {	type edge struct {		node   string		parent string	}	S := make([]edge, 0, len(g.outputs))	S = append(S, edge{seed, ""})	visited := map[string]string{}	for len(S) > 0 {		e := S[0]		S = S[1:]		if parent, exists := visited[e.node]; !exists || parent == "" {			visited[e.node] = e.parent			for child := range g.outputs[e.node] {				S = append(S, edge{child, e.node})			}		}		if e.node == seed && e.parent != "" {			result := []string{}			node := e.parent			for node != seed {				result = append(result, node)				node = visited[node]			}			result = append(result, seed)			// reverse			for left, right := 0, len(result)-1; left < right; left, right = left+1, right-1 {				result[left], result[right] = result[right], result[left]			}			return result		}	}	return []string{}}// FindParents returns the other ends of incoming edges.func (g *Graph) FindParents(to string) []string {	result := []string{}	for node, children := range g.outputs {		if _, exists := children[to]; exists {			result = append(result, node)		}	}	return result}// FindChildren returns the other ends of outgoing edges.func (g *Graph) FindChildren(from string) []string {	result := []string{}	for child := range g.outputs[from] {		result = append(result, child)	}	sort.Strings(result)	return result}// Serialize outputs the graph in Graphviz format.func (g *Graph) Serialize(sorted []string) string {	node2index := map[string]int{}	for index, node := range sorted {		node2index[node] = index	}	var buffer bytes.Buffer	buffer.WriteString("digraph Hercules {\n")	nodesFrom := []string{}	for nodeFrom := range g.outputs {		nodesFrom = append(nodesFrom, nodeFrom)	}	sort.Strings(nodesFrom)	for _, nodeFrom := range nodesFrom {		links := []string{}		for nodeTo := range g.outputs[nodeFrom] {			links = append(links, nodeTo)		}		sort.Strings(links)		for _, nodeTo := range links {			buffer.WriteString(fmt.Sprintf("  \"%d %s\" -> \"%d %s\"\n",				node2index[nodeFrom], nodeFrom, node2index[nodeTo], nodeTo))		}	}	buffer.WriteString("}")	return buffer.String()}// DebugDump converts the graph to a string. As the name suggests, useful for debugging.func (g *Graph) DebugDump() string {	S := make([]string, 0, len(g.outputs))	for n := range g.outputs {		if g.inputs[n] == 0 {			S = append(S, n)		}	}	sort.Strings(S)	var buffer bytes.Buffer	buffer.WriteString(strings.Join(S, " ") + "\n")	keys := []string{}	vals := map[string][]string{}	for key, val1 := range g.outputs {		val2 := make([]string, len(val1))		for name, idx := range val1 {			val2[idx-1] = name		}		keys = append(keys, key)		vals[key] = val2	}	sort.Strings(keys)	for _, key := range keys {		buffer.WriteString(fmt.Sprintf("%s %d = ", key, g.inputs[key]))		outs := vals[key]		buffer.WriteString(strings.Join(outs, " ") + "\n")	}	return buffer.String()}
 |