diff options
| author | Petter Rasmussen | 2016-04-17 13:11:19 +0200 | 
|---|---|---|
| committer | Petter Rasmussen | 2016-04-17 13:11:19 +0200 | 
| commit | 97981f7fd205353907135eacfc0e0ade24b88269 (patch) | |
| tree | 1fdb61a7138642a1612bb201434e8ebda141cc8a /vendor/github.com/soniakeys/graph/dir_RO.go | |
| parent | 8de8e05c483c6b5f23b14742315f1860211dcef7 (diff) | |
| parent | b5eb2866cfceb69b0d4dd4948273d679a884fbb2 (diff) | |
| download | gdrive-97981f7fd205353907135eacfc0e0ade24b88269.tar.bz2 | |
Merge pull request #140 from paulz/godep
add Go dependencies by godep
Diffstat (limited to 'vendor/github.com/soniakeys/graph/dir_RO.go')
| -rw-r--r-- | vendor/github.com/soniakeys/graph/dir_RO.go | 395 | 
1 files changed, 395 insertions, 0 deletions
| diff --git a/vendor/github.com/soniakeys/graph/dir_RO.go b/vendor/github.com/soniakeys/graph/dir_RO.go new file mode 100644 index 0000000..77558a9 --- /dev/null +++ b/vendor/github.com/soniakeys/graph/dir_RO.go @@ -0,0 +1,395 @@ +// Copyright 2014 Sonia Keys +// License MIT: http://opensource.org/licenses/MIT + +package graph + +// dir_RO.go is code generated from dir_cg.go by directives in graph.go. +// Editing dir_cg.go is okay.  It is the code generation source. +// DO NOT EDIT dir_RO.go. +// The RO means read only and it is upper case RO to slow you down a bit +// in case you start to edit the file. + +// Balanced returns true if for every node in g, in-degree equals out-degree. +// +// There are equivalent labeled and unlabeled versions of this method. +func (g Directed) Balanced() bool { +	for n, in := range g.InDegree() { +		if in != len(g.AdjacencyList[n]) { +			return false +		} +	} +	return true +} + +// Copy makes a deep copy of g. +// Copy also computes the arc size ma, the number of arcs. +// +// There are equivalent labeled and unlabeled versions of this method. +func (g Directed) Copy() (c Directed, ma int) { +	l, s := g.AdjacencyList.Copy() +	return Directed{l}, s +} + +// Cyclic determines if g 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 an arc involved in a cycle. +// Cyclic returns false if g is acyclic. +// +// Also see Topological, which detects cycles. +// +// There are equivalent labeled and unlabeled versions of this method. +func (g Directed) Cyclic() (cyclic bool, fr NI, to NI) { +	a := g.AdjacencyList +	fr, to = -1, -1 +	var temp, perm Bits +	var df func(NI) +	df = func(n NI) { +		switch { +		case temp.Bit(n) == 1: +			cyclic = true +			return +		case perm.Bit(n) == 1: +			return +		} +		temp.SetBit(n, 1) +		for _, nb := range a[n] { +			df(nb) +			if cyclic { +				if fr < 0 { +					fr, to = n, nb +				} +				return +			} +		} +		temp.SetBit(n, 0) +		perm.SetBit(n, 1) +	} +	for n := range a { +		if perm.Bit(NI(n)) == 1 { +			continue +		} +		if df(NI(n)); cyclic { // short circuit as soon as a cycle is found +			break +		} +	} +	return +} + +// FromList transposes a labeled graph into a FromList. +// +// Receiver g should be connected as a tree or forest.  Specifically no node +// can have multiple incoming arcs.  If any node n in g has multiple incoming +// arcs, the method returns (nil, n) where n is a node with multiple +// incoming arcs. +// +// Otherwise (normally) the method populates the From members in a +// FromList.Path and returns the FromList and -1. +// +// Other members of the FromList are left as zero values. +// Use FromList.RecalcLen and FromList.RecalcLeaves as needed. +// +// Unusual cases are parallel arcs and loops.  A parallel arc represents +// a case of multiple arcs going to some node and so will lead to a (nil, n) +// return, even though a graph might be considered a multigraph tree. +// A single loop on a node that would otherwise be a root node, though, +// is not a case of multiple incoming arcs and so does not force a (nil, n) +// result. +// +// There are equivalent labeled and unlabeled versions of this method. +func (g Directed) FromList() (*FromList, NI) { +	paths := make([]PathEnd, len(g.AdjacencyList)) +	for i := range paths { +		paths[i].From = -1 +	} +	for fr, to := range g.AdjacencyList { +		for _, to := range to { +			if paths[to].From >= 0 { +				return nil, to +			} +			paths[to].From = NI(fr) +		} +	} +	return &FromList{Paths: paths}, -1 +} + +// InDegree computes the in-degree of each node in g +// +// There are equivalent labeled and unlabeled versions of this method. +func (g Directed) InDegree() []int { +	ind := make([]int, len(g.AdjacencyList)) +	for _, nbs := range g.AdjacencyList { +		for _, nb := range nbs { +			ind[nb]++ +		} +	} +	return ind +} + +// IsTree identifies trees in directed graphs. +// +// Return value isTree is true if the subgraph reachable from root is a tree. +// Further, return value allTree is true if the entire graph g is reachable +// from root. +// +// There are equivalent labeled and unlabeled versions of this method. +func (g Directed) IsTree(root NI) (isTree, allTree bool) { +	a := g.AdjacencyList +	var v Bits +	v.SetAll(len(a)) +	var df func(NI) bool +	df = func(n NI) bool { +		if v.Bit(n) == 0 { +			return false +		} +		v.SetBit(n, 0) +		for _, to := range a[n] { +			if !df(to) { +				return false +			} +		} +		return true +	} +	isTree = df(root) +	return isTree, isTree && v.Zero() +} + +// Tarjan identifies strongly connected components in a directed graph using +// Tarjan's algorithm. +// +// The method calls the emit argument for each component identified.  Each +// component is a list of nodes.  A property of the algorithm is that +// components are emitted in reverse topological order of the condensation. +// (See https://en.wikipedia.org/wiki/Strongly_connected_component#Definitions +// for description of condensation.) +// +// There are equivalent labeled and unlabeled versions of this method. +// +// See also TarjanForward and TarjanCondensation. +func (g Directed) Tarjan(emit func([]NI) bool) { +	// See "Depth-first search and linear graph algorithms", Robert Tarjan, +	// SIAM J. Comput. Vol. 1, No. 2, June 1972. +	// +	// Implementation here from Wikipedia pseudocode, +	// http://en.wikipedia.org/w/index.php?title=Tarjan%27s_strongly_connected_components_algorithm&direction=prev&oldid=647184742 +	var indexed, stacked Bits +	a := g.AdjacencyList +	index := make([]int, len(a)) +	lowlink := make([]int, len(a)) +	x := 0 +	var S []NI +	var sc func(NI) bool +	sc = func(n NI) bool { +		index[n] = x +		indexed.SetBit(n, 1) +		lowlink[n] = x +		x++ +		S = append(S, n) +		stacked.SetBit(n, 1) +		for _, nb := range a[n] { +			if indexed.Bit(nb) == 0 { +				if !sc(nb) { +					return false +				} +				if lowlink[nb] < lowlink[n] { +					lowlink[n] = lowlink[nb] +				} +			} else if stacked.Bit(nb) == 1 { +				if index[nb] < lowlink[n] { +					lowlink[n] = index[nb] +				} +			} +		} +		if lowlink[n] == index[n] { +			var c []NI +			for { +				last := len(S) - 1 +				w := S[last] +				S = S[:last] +				stacked.SetBit(w, 0) +				c = append(c, w) +				if w == n { +					if !emit(c) { +						return false +					} +					break +				} +			} +		} +		return true +	} +	for n := range a { +		if indexed.Bit(NI(n)) == 0 && !sc(NI(n)) { +			return +		} +	} +} + +// TarjanForward returns strongly connected components. +// +// It returns components in the reverse order of Tarjan, for situations +// where a forward topological ordering is easier. +func (g Directed) TarjanForward() [][]NI { +	var r [][]NI +	g.Tarjan(func(c []NI) bool { +		r = append(r, c) +		return true +	}) +	scc := make([][]NI, len(r)) +	last := len(r) - 1 +	for i, ci := range r { +		scc[last-i] = ci +	} +	return scc +} + +// TarjanCondensation returns strongly connected components and their +// condensation graph. +// +// Components are ordered in a forward topological ordering. +func (g Directed) TarjanCondensation() (scc [][]NI, cd AdjacencyList) { +	scc = g.TarjanForward() +	cd = make(AdjacencyList, len(scc))       // return value +	cond := make([]NI, len(g.AdjacencyList)) // mapping from g node to cd node +	for cn := NI(len(scc) - 1); cn >= 0; cn-- { +		c := scc[cn] +		for _, n := range c { +			cond[n] = NI(cn) // map g node to cd node +		} +		var tos []NI // list of 'to' nodes +		var m Bits   // tos map +		m.SetBit(cn, 1) +		for _, n := range c { +			for _, to := range g.AdjacencyList[n] { +				if ct := cond[to]; m.Bit(ct) == 0 { +					m.SetBit(ct, 1) +					tos = append(tos, ct) +				} +			} +		} +		cd[cn] = tos +	} +	return +} + +// Topological computes a topological ordering of a directed acyclic graph. +// +// For an acyclic graph, return value ordering is a permutation of node numbers +// in topologically sorted order and cycle will be nil.  If the graph is found +// to be cyclic, ordering will be nil and cycle will be the path of a found +// cycle. +// +// There are equivalent labeled and unlabeled versions of this method. +func (g Directed) Topological() (ordering, cycle []NI) { +	a := g.AdjacencyList +	ordering = make([]NI, len(a)) +	i := len(ordering) +	var temp, perm Bits +	var cycleFound bool +	var cycleStart NI +	var df func(NI) +	df = func(n NI) { +		switch { +		case temp.Bit(n) == 1: +			cycleFound = true +			cycleStart = n +			return +		case perm.Bit(n) == 1: +			return +		} +		temp.SetBit(n, 1) +		for _, nb := range a[n] { +			df(nb) +			if cycleFound { +				if cycleStart >= 0 { +					// a little hack: orderng won't be needed so repurpose the +					// slice as cycle.  this is read out in reverse order +					// as the recursion unwinds. +					x := len(ordering) - 1 - len(cycle) +					ordering[x] = n +					cycle = ordering[x:] +					if n == cycleStart { +						cycleStart = -1 +					} +				} +				return +			} +		} +		temp.SetBit(n, 0) +		perm.SetBit(n, 1) +		i-- +		ordering[i] = n +	} +	for n := range a { +		if perm.Bit(NI(n)) == 1 { +			continue +		} +		df(NI(n)) +		if cycleFound { +			return nil, cycle +		} +	} +	return ordering, nil +} + +// TopologicalKahn computes a topological ordering of a directed acyclic graph. +// +// For an acyclic graph, return value ordering is a permutation of node numbers +// in topologically sorted order and cycle will be nil.  If the graph is found +// to be cyclic, ordering will be nil and cycle will be the path of a found +// cycle. +// +// This function is based on the algorithm by Arthur Kahn and requires the +// transpose of g be passed as the argument. +// +// There are equivalent labeled and unlabeled versions of this method. +func (g Directed) TopologicalKahn(tr Directed) (ordering, cycle []NI) { +	// code follows Wikipedia pseudocode. +	var L, S []NI +	// rem for "remaining edges," this function makes a local copy of the +	// in-degrees and consumes that instead of consuming an input. +	rem := make([]int, len(g.AdjacencyList)) +	for n, fr := range tr.AdjacencyList { +		if len(fr) == 0 { +			// accumulate "set of all nodes with no incoming edges" +			S = append(S, NI(n)) +		} else { +			// initialize rem from in-degree +			rem[n] = len(fr) +		} +	} +	for len(S) > 0 { +		last := len(S) - 1 // "remove a node n from S" +		n := S[last] +		S = S[:last] +		L = append(L, n) // "add n to tail of L" +		for _, m := range g.AdjacencyList[n] { +			// WP pseudo code reads "for each node m..." but it means for each +			// node m *remaining in the graph.*  We consume rem rather than +			// the graph, so "remaining in the graph" for us means rem[m] > 0. +			if rem[m] > 0 { +				rem[m]--         // "remove edge from the graph" +				if rem[m] == 0 { // if "m has no other incoming edges" +					S = append(S, m) // "insert m into S" +				} +			} +		} +	} +	// "If graph has edges," for us means a value in rem is > 0. +	for c, in := range rem { +		if in > 0 { +			// recover cyclic nodes +			for _, nb := range g.AdjacencyList[c] { +				if rem[nb] > 0 { +					cycle = append(cycle, NI(c)) +					break +				} +			} +		} +	} +	if len(cycle) > 0 { +		return nil, cycle +	} +	return L, nil +} | 
