コード例 #1
0
ファイル: chaindescriber.go プロジェクト: RomainVabre/origin
func (d *DepthFirst) visit(g graph.Graph, t graph.Node, until func(graph.Node) bool) graph.Node {
	if until != nil && until(t) {
		return t
	}
	d.stack.Push(t)
	children := osgraph.ByID(g.From(t))
	sort.Sort(children)
	for _, n := range children {
		if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(t, n)) {
			continue
		}
		if d.visited(n.ID()) {
			continue
		}
		if d.Visit != nil {
			d.Visit(t, n)
		}
		result := d.visit(g, n, until)
		if result != nil {
			return result
		}
	}
	d.stack.Pop()
	return nil
}
コード例 #2
0
ファイル: traverse.go プロジェクト: sbinet/gonum-graph
// Walk performs a depth-first traversal of the graph g starting from the given node,
// depending on the the EdgeFilter field and the until parameter if they are non-nil. The
// traversal follows edges for which EdgeFilter(edge) is true and returns the first node
// for which until(node) is true. During the traversal, if the Visit field is non-nil, it
// is called with the nodes joined by each followed edge.
func (d *DepthFirst) Walk(g graph.Graph, from graph.Node, until func(graph.Node) bool) graph.Node {
	if d.visited == nil {
		d.visited = &intsets.Sparse{}
	}
	d.stack.Push(from)
	d.visited.Insert(from.ID())

	for d.stack.Len() > 0 {
		t := d.stack.Pop()
		if until != nil && until(t) {
			return t
		}
		for _, n := range g.From(t) {
			if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(t, n)) {
				continue
			}
			if d.visited.Has(n.ID()) {
				continue
			}
			if d.Visit != nil {
				d.Visit(t, n)
			}
			d.visited.Insert(n.ID())
			d.stack.Push(n)
		}
	}

	return nil
}
コード例 #3
0
ファイル: bfs_tree.go プロジェクト: Grissess/sdnd16
// Builds a BFS tree (as a directed graph) from the given graph and start node.
func BFSTree(g graph.Graph, start graph.Node) *simple.DirectedGraph {
	if !g.Has(start) {
		panic(fmt.Sprintf("BFSTree: Start node %r not in graph %r", start, g))
	}

	ret := simple.NewDirectedGraph(0.0, math.Inf(1))
	seen := make(map[int]bool)
	q := queue.New()
	q.Add(start)
	ret.AddNode(simple.Node(start.ID()))

	for q.Length() > 0 {
		node := q.Peek().(graph.Node)
		q.Remove()
		for _, neighbor := range g.From(node) {
			if !seen[neighbor.ID()] {
				seen[neighbor.ID()] = true
				ret.AddNode(simple.Node(neighbor.ID()))
				ret.SetEdge(simple.Edge{F: simple.Node(node.ID()), T: simple.Node(neighbor.ID()), W: g.Edge(node, neighbor).Weight()})
				q.Add(neighbor)
			}
		}
	}

	return ret
}
コード例 #4
0
ファイル: dot.go プロジェクト: sbinet/gonum-graph
func graphID(g graph.Graph, n graph.Node) string {
	switch g := g.(type) {
	case Node:
		return g.DOTID()
	default:
		return nodeID(n)
	}
}
コード例 #5
0
ファイル: control_flow.go プロジェクト: sbinet/gonum-graph
// PostDominatores returns all dominators for all nodes in g. It does not
// prune for strict post-dominators, immediate dominators etc.
//
// A dominates B if and only if the only path through B travels through A.
func Dominators(start graph.Node, g graph.Graph) map[int]set.Nodes {
	allNodes := make(set.Nodes)
	nlist := g.Nodes()
	dominators := make(map[int]set.Nodes, len(nlist))
	for _, node := range nlist {
		allNodes.Add(node)
	}

	var to func(graph.Node) []graph.Node
	switch g := g.(type) {
	case graph.Directed:
		to = g.To
	default:
		to = g.From
	}

	for _, node := range nlist {
		dominators[node.ID()] = make(set.Nodes)
		if node.ID() == start.ID() {
			dominators[node.ID()].Add(start)
		} else {
			dominators[node.ID()].Copy(allNodes)
		}
	}

	for somethingChanged := true; somethingChanged; {
		somethingChanged = false
		for _, node := range nlist {
			if node.ID() == start.ID() {
				continue
			}
			preds := to(node)
			if len(preds) == 0 {
				continue
			}
			tmp := make(set.Nodes).Copy(dominators[preds[0].ID()])
			for _, pred := range preds[1:] {
				tmp.Intersect(tmp, dominators[pred.ID()])
			}

			dom := make(set.Nodes)
			dom.Add(node)

			dom.Union(dom, tmp)
			if !set.Equal(dom, dominators[node.ID()]) {
				dominators[node.ID()] = dom
				somethingChanged = true
			}
		}
	}

	return dominators
}
コード例 #6
0
ファイル: weight.go プロジェクト: sbinet/gonum-graph
// UniformCost returns a Weighting that returns an edge cost of 1 for existing
// edges, zero for node identity and Inf for otherwise absent edges.
func UniformCost(g graph.Graph) Weighting {
	return func(x, y graph.Node) (w float64, ok bool) {
		xid := x.ID()
		yid := y.ID()
		if xid == yid {
			return 0, true
		}
		if e := g.Edge(x, y); e != nil {
			return 1, true
		}
		return math.Inf(1), false
	}
}
コード例 #7
0
ファイル: betweenness.go プロジェクト: jacobxk/graph
// brandes is the common code for Betweenness and EdgeBetweenness. It corresponds
// to algorithm 1 in http://algo.uni-konstanz.de/publications/b-vspbc-08.pdf with
// the accumulation loop provided by the accumulate closure.
func brandes(g graph.Graph, accumulate func(s graph.Node, stack internal.NodeStack, p map[int][]graph.Node, delta, sigma map[int]float64)) {
	var (
		nodes = g.Nodes()
		stack internal.NodeStack
		p     = make(map[int][]graph.Node, len(nodes))
		sigma = make(map[int]float64, len(nodes))
		d     = make(map[int]int, len(nodes))
		delta = make(map[int]float64, len(nodes))
		queue internal.NodeQueue
	)
	for _, s := range nodes {
		stack = stack[:0]

		for _, w := range nodes {
			p[w.ID()] = p[w.ID()][:0]
		}

		for _, t := range nodes {
			sigma[t.ID()] = 0
			d[t.ID()] = -1
		}
		sigma[s.ID()] = 1
		d[s.ID()] = 0

		queue.Enqueue(s)
		for queue.Len() != 0 {
			v := queue.Dequeue()
			stack.Push(v)
			for _, w := range g.From(v) {
				// w found for the first time?
				if d[w.ID()] < 0 {
					queue.Enqueue(w)
					d[w.ID()] = d[v.ID()] + 1
				}
				// shortest path to w via v?
				if d[w.ID()] == d[v.ID()]+1 {
					sigma[w.ID()] += sigma[v.ID()]
					p[w.ID()] = append(p[w.ID()], v)
				}
			}
		}

		for _, v := range nodes {
			delta[v.ID()] = 0
		}

		// S returns vertices in order of non-increasing distance from s
		accumulate(s, stack, p, delta, sigma)
	}
}
コード例 #8
0
ファイル: floydwarshall.go プロジェクト: sbinet/gonum-graph
// FloydWarshall returns a shortest-path tree for the graph g or false indicating
// that a negative cycle exists in the graph. If the graph does not implement
// graph.Weighter, UniformCost is used.
//
// The time complexity of FloydWarshall is O(|V|^3).
func FloydWarshall(g graph.Graph) (paths AllShortest, ok bool) {
	var weight Weighting
	if wg, ok := g.(graph.Weighter); ok {
		weight = wg.Weight
	} else {
		weight = UniformCost(g)
	}

	nodes := g.Nodes()
	paths = newAllShortest(nodes, true)
	for i, u := range nodes {
		paths.dist.Set(i, i, 0)
		for _, v := range g.From(u) {
			j := paths.indexOf[v.ID()]
			w, ok := weight(u, v)
			if !ok {
				panic("floyd-warshall: unexpected invalid weight")
			}
			paths.set(i, j, w, j)
		}
	}

	for k := range nodes {
		for i := range nodes {
			for j := range nodes {
				ij := paths.dist.At(i, j)
				joint := paths.dist.At(i, k) + paths.dist.At(k, j)
				if ij > joint {
					paths.set(i, j, joint, paths.at(i, k)...)
				} else if ij-joint == 0 {
					paths.add(i, j, paths.at(i, k)...)
				}
			}
		}
	}

	ok = true
	for i := range nodes {
		if paths.dist.At(i, i) < 0 {
			ok = false
			break
		}
	}

	return paths, ok
}
コード例 #9
0
ファイル: dijkstra.go プロジェクト: sbinet/gonum-graph
// dijkstraAllPaths is the all-paths implementation of Dijkstra. It is shared
// between DijkstraAllPaths and JohnsonAllPaths to avoid repeated allocation
// of the nodes slice and the indexOf map. It returns nothing, but stores the
// result of the work in the paths parameter which is a reference type.
func dijkstraAllPaths(g graph.Graph, paths AllShortest) {
	var weight Weighting
	if wg, ok := g.(graph.Weighter); ok {
		weight = wg.Weight
	} else {
		weight = UniformCost(g)
	}

	var Q priorityQueue
	for i, u := range paths.nodes {
		// Dijkstra's algorithm here is implemented essentially as
		// described in Function B.2 in figure 6 of UTCS Technical
		// Report TR-07-54 with the addition of handling multiple
		// co-equal paths.
		//
		// http://www.cs.utexas.edu/ftp/techreports/tr07-54.pdf

		// Q must be empty at this point.
		heap.Push(&Q, distanceNode{node: u, dist: 0})
		for Q.Len() != 0 {
			mid := heap.Pop(&Q).(distanceNode)
			k := paths.indexOf[mid.node.ID()]
			if mid.dist < paths.dist.At(i, k) {
				paths.dist.Set(i, k, mid.dist)
			}
			for _, v := range g.From(mid.node) {
				j := paths.indexOf[v.ID()]
				w, ok := weight(mid.node, v)
				if !ok {
					panic("dijkstra: unexpected invalid weight")
				}
				if w < 0 {
					panic("dijkstra: negative edge weight")
				}
				joint := paths.dist.At(i, k) + w
				if joint < paths.dist.At(i, j) {
					heap.Push(&Q, distanceNode{node: v, dist: joint})
					paths.set(i, j, joint, k)
				} else if joint == paths.dist.At(i, j) {
					paths.add(i, j, k)
				}
			}
		}
	}
}
コード例 #10
0
ファイル: control_flow.go プロジェクト: sbinet/gonum-graph
// PostDominatores returns all post-dominators for all nodes in g. It does not
// prune for strict post-dominators, immediate post-dominators etc.
//
// A post-dominates B if and only if all paths from B travel through A.
func PostDominators(end graph.Node, g graph.Graph) map[int]set.Nodes {
	allNodes := make(set.Nodes)
	nlist := g.Nodes()
	dominators := make(map[int]set.Nodes, len(nlist))
	for _, node := range nlist {
		allNodes.Add(node)
	}

	for _, node := range nlist {
		dominators[node.ID()] = make(set.Nodes)
		if node.ID() == end.ID() {
			dominators[node.ID()].Add(end)
		} else {
			dominators[node.ID()].Copy(allNodes)
		}
	}

	for somethingChanged := true; somethingChanged; {
		somethingChanged = false
		for _, node := range nlist {
			if node.ID() == end.ID() {
				continue
			}
			succs := g.From(node)
			if len(succs) == 0 {
				continue
			}
			tmp := make(set.Nodes).Copy(dominators[succs[0].ID()])
			for _, succ := range succs[1:] {
				tmp.Intersect(tmp, dominators[succ.ID()])
			}

			dom := make(set.Nodes)
			dom.Add(node)

			dom.Union(dom, tmp)
			if !set.Equal(dom, dominators[node.ID()]) {
				dominators[node.ID()] = dom
				somethingChanged = true
			}
		}
	}

	return dominators
}
コード例 #11
0
ファイル: distance.go プロジェクト: RomainVabre/origin
// Farness returns the farness for nodes in the graph g used to construct
// the given shortest paths.
//
//  F(v) = \sum_u d(u,v)
//
// For directed graphs the incoming paths are used. Infinite distances are
// not considered.
func Farness(g graph.Graph, p path.AllShortest) map[int]float64 {
	nodes := g.Nodes()
	f := make(map[int]float64, len(nodes))
	for _, u := range nodes {
		var sum float64
		for _, v := range nodes {
			// The ordering here is not relevant for
			// undirected graphs, but we make sure we
			// are counting incoming paths.
			d := p.Weight(v, u)
			if math.IsInf(d, 0) {
				continue
			}
			sum += d
		}
		f[u.ID()] = sum
	}
	return f
}
コード例 #12
0
ファイル: distance.go プロジェクト: RomainVabre/origin
// Harmonic returns the harmonic centrality for nodes in the graph g used to
// construct the given shortest paths.
//
//  H(v)= \sum_{u ≠ v} 1 / d(u,v)
//
// For directed graphs the incoming paths are used. Infinite distances are
// not considered.
func Harmonic(g graph.Graph, p path.AllShortest) map[int]float64 {
	nodes := g.Nodes()
	h := make(map[int]float64, len(nodes))
	for i, u := range nodes {
		var sum float64
		for j, v := range nodes {
			// The ordering here is not relevant for
			// undirected graphs, but we make sure we
			// are counting incoming paths.
			d := p.Weight(v, u)
			if math.IsInf(d, 0) {
				continue
			}
			if i != j {
				sum += 1 / d
			}
		}
		h[u.ID()] = sum
	}
	return h
}
コード例 #13
0
ファイル: traverse.go プロジェクト: sbinet/gonum-graph
// Walk performs a breadth-first traversal of the graph g starting from the given node,
// depending on the the EdgeFilter field and the until parameter if they are non-nil. The
// traversal follows edges for which EdgeFilter(edge) is true and returns the first node
// for which until(node, depth) is true. During the traversal, if the Visit field is
// non-nil, it is called with the nodes joined by each followed edge.
func (b *BreadthFirst) Walk(g graph.Graph, from graph.Node, until func(n graph.Node, d int) bool) graph.Node {
	if b.visited == nil {
		b.visited = &intsets.Sparse{}
	}
	b.queue.Enqueue(from)
	b.visited.Insert(from.ID())

	var (
		depth     int
		children  int
		untilNext = 1
	)
	for b.queue.Len() > 0 {
		t := b.queue.Dequeue()
		if until != nil && until(t, depth) {
			return t
		}
		for _, n := range g.From(t) {
			if b.EdgeFilter != nil && !b.EdgeFilter(g.Edge(t, n)) {
				continue
			}
			if b.visited.Has(n.ID()) {
				continue
			}
			if b.Visit != nil {
				b.Visit(t, n)
			}
			b.visited.Insert(n.ID())
			children++
			b.queue.Enqueue(n)
		}
		if untilNext--; untilNext == 0 {
			depth++
			untilNext = children
			children = 0
		}
	}

	return nil
}
コード例 #14
0
ファイル: topo.go プロジェクト: sbinet/gonum-graph
// IsPathIn returns whether path is a path in g.
//
// As special cases, IsPathIn returns true for a zero length path or for
// a path of length 1 when the node in path exists in the graph.
func IsPathIn(g graph.Graph, path []graph.Node) bool {
	switch len(path) {
	case 0:
		return true
	case 1:
		return g.Has(path[0])
	default:
		var canReach func(u, v graph.Node) bool
		switch g := g.(type) {
		case graph.Directed:
			canReach = g.HasEdgeFromTo
		default:
			canReach = g.HasEdgeBetween
		}

		for i, u := range path[:len(path)-1] {
			if !canReach(u, path[i+1]) {
				return false
			}
		}
		return true
	}
}
コード例 #15
0
ファイル: dijkstra.go プロジェクト: RomainVabre/origin
// DijkstraFrom returns a shortest-path tree for a shortest path from u to all nodes in
// the graph g. If the graph does not implement graph.Weighter, graph.UniformCost is used.
// DijkstraFrom will panic if g has a u-reachable negative edge weight.
//
// The time complexity of DijkstrFrom is O(|E|+|V|.log|V|).
func DijkstraFrom(u graph.Node, g graph.Graph) Shortest {
	if !g.Has(u) {
		return Shortest{from: u}
	}
	var weight graph.WeightFunc
	if g, ok := g.(graph.Weighter); ok {
		weight = g.Weight
	} else {
		weight = graph.UniformCost
	}

	nodes := g.Nodes()
	path := newShortestFrom(u, nodes)

	// Dijkstra's algorithm here is implemented essentially as
	// described in Function B.2 in figure 6 of UTCS Technical
	// Report TR-07-54.
	//
	// http://www.cs.utexas.edu/ftp/techreports/tr07-54.pdf
	Q := priorityQueue{{node: u, dist: 0}}
	for Q.Len() != 0 {
		mid := heap.Pop(&Q).(distanceNode)
		k := path.indexOf[mid.node.ID()]
		if mid.dist < path.dist[k] {
			path.dist[k] = mid.dist
		}
		for _, v := range g.From(mid.node) {
			j := path.indexOf[v.ID()]
			w := weight(g.Edge(mid.node, v))
			if w < 0 {
				panic("dijkstra: negative edge weight")
			}
			joint := path.dist[k] + w
			if joint < path.dist[j] {
				heap.Push(&Q, distanceNode{node: v, dist: joint})
				path.set(j, joint, k)
			}
		}
	}

	return path
}
コード例 #16
0
ファイル: floydwarshall.go プロジェクト: RomainVabre/origin
// FloydWarshall returns a shortest-path tree for the graph g or false indicating
// that a negative cycle exists in the graph. If the graph does not implement
// graph.Weighter, graph.UniformCost is used.
//
// The time complexity of FloydWarshall is O(|V|^3).
func FloydWarshall(g graph.Graph) (paths AllShortest, ok bool) {
	var weight graph.WeightFunc
	if g, ok := g.(graph.Weighter); ok {
		weight = g.Weight
	} else {
		weight = graph.UniformCost
	}

	nodes := g.Nodes()
	paths = newAllShortest(nodes, true)
	for i, u := range nodes {
		paths.dist.Set(i, i, 0)
		for _, v := range g.From(u) {
			j := paths.indexOf[v.ID()]
			paths.set(i, j, weight(g.Edge(u, v)), j)
		}
	}

	for k := range nodes {
		for i := range nodes {
			for j := range nodes {
				ij := paths.dist.At(i, j)
				joint := paths.dist.At(i, k) + paths.dist.At(k, j)
				if ij > joint {
					paths.set(i, j, joint, paths.at(i, k)...)
				} else if ij-joint == 0 {
					paths.add(i, j, paths.at(i, k)...)
				}
			}
		}
	}

	ok = true
	for i := range nodes {
		if paths.dist.At(i, i) < 0 {
			ok = false
			break
		}
	}

	return paths, ok
}
コード例 #17
0
ファイル: betweenness.go プロジェクト: RomainVabre/origin
// Betweenness returns the non-zero betweenness centrality for nodes in the unweighted graph g.
//
//  C_B(v) = \sum_{s ≠ v ≠ t ∈ V} (\sigma_{st}(v) / \sigma_{st})
//
// where \sigma_{st} and \sigma_{st}(v) are the number of shortest paths from s to t,
// and the subset of those paths containing v respectively.
func Betweenness(g graph.Graph) map[int]float64 {
	// Brandes' algorithm for finding betweenness centrality for nodes in
	// and unweighted graph:
	//
	// http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf

	// TODO(kortschak): Consider using the parallel algorithm when
	// GOMAXPROCS != 1.
	//
	// http://htor.inf.ethz.ch/publications/img/edmonds-hoefler-lumsdaine-bc.pdf

	// Also note special case for sparse networks:
	// http://wwwold.iit.cnr.it/staff/marco.pellegrini/papiri/asonam-final.pdf

	var (
		cb = make(map[int]float64)

		nodes = g.Nodes()
		stack internal.NodeStack
		p     = make(map[int][]graph.Node, len(nodes))
		sigma = make(map[int]float64, len(nodes))
		d     = make(map[int]int, len(nodes))
		delta = make(map[int]float64, len(nodes))
		queue internal.NodeQueue
	)
	for _, s := range nodes {
		stack = stack[:0]

		for _, w := range nodes {
			p[w.ID()] = p[w.ID()][:0]
		}

		for _, t := range nodes {
			sigma[t.ID()] = 0
			d[t.ID()] = -1
		}
		sigma[s.ID()] = 1
		d[s.ID()] = 0

		queue.Enqueue(s)
		for queue.Len() != 0 {
			v := queue.Dequeue()
			stack.Push(v)
			for _, w := range g.From(v) {
				// w found for the first time?
				if d[w.ID()] < 0 {
					queue.Enqueue(w)
					d[w.ID()] = d[v.ID()] + 1
				}
				// shortest path to w via v?
				if d[w.ID()] == d[v.ID()]+1 {
					sigma[w.ID()] += sigma[v.ID()]
					p[w.ID()] = append(p[w.ID()], v)
				}
			}
		}

		for _, v := range nodes {
			delta[v.ID()] = 0
		}
		// S returns vertices in order of non-increasing distance from s
		for stack.Len() != 0 {
			w := stack.Pop()
			for _, v := range p[w.ID()] {
				delta[v.ID()] += sigma[v.ID()] / sigma[w.ID()] * (1 + delta[w.ID()])
			}
			if w.ID() != s.ID() {
				if d := delta[w.ID()]; d != 0 {
					cb[w.ID()] += d
				}
			}
		}
	}

	return cb
}
コード例 #18
0
ファイル: dijkstra.go プロジェクト: sbinet/gonum-graph
// DijkstraAllPaths returns a shortest-path tree for shortest paths in the graph g.
// If the graph does not implement graph.Weighter, UniformCost is used.
// DijkstraAllPaths will panic if g has a negative edge weight.
//
// The time complexity of DijkstrAllPaths is O(|V|.|E|+|V|^2.log|V|).
func DijkstraAllPaths(g graph.Graph) (paths AllShortest) {
	paths = newAllShortest(g.Nodes(), false)
	dijkstraAllPaths(g, paths)
	return paths
}
コード例 #19
0
ファイル: dstarlite.go プロジェクト: jmptrader/graph
// NewDStarLite returns a new DStarLite planner for the path from s to t in g using the
// heuristic h. The world model, m, is used to store shortest path information during path
// planning. The world model must be an empty graph when NewDStarLite is called.
//
// If h is nil, the DStarLite will use the g.HeuristicCost method if g implements
// path.HeuristicCoster, falling back to path.NullHeuristic otherwise. If the graph does not
// implement graph.Weighter, path.UniformCost is used. NewDStarLite will panic if g has
// a negative edge weight.
func NewDStarLite(s, t graph.Node, g graph.Graph, h path.Heuristic, m WorldModel) *DStarLite {
	/*
	   procedure Initialize()
	   {02”} U = ∅;
	   {03”} k_m = 0;
	   {04”} for all s ∈ S rhs(s) = g(s) = ∞;
	   {05”} rhs(s_goal) = 0;
	   {06”} U.Insert(s_goal, [h(s_start, s_goal); 0]);
	*/

	d := &DStarLite{
		s: newDStarLiteNode(s),
		t: newDStarLiteNode(t), // badKey is overwritten below.

		model: m,

		heuristic: h,
	}
	d.t.rhs = 0

	/*
		procedure Main()
		{29”} s_last = s_start;
		{30”} Initialize();
	*/
	d.last = d.s

	if wg, ok := g.(graph.Weighter); ok {
		d.weight = wg.Weight
	} else {
		d.weight = path.UniformCost(g)
	}
	if d.heuristic == nil {
		if g, ok := g.(path.HeuristicCoster); ok {
			d.heuristic = g.HeuristicCost
		} else {
			d.heuristic = path.NullHeuristic
		}
	}

	d.queue.insert(d.t, key{d.heuristic(s, t), 0})

	for _, n := range g.Nodes() {
		switch n.ID() {
		case d.s.ID():
			d.model.AddNode(d.s)
		case d.t.ID():
			d.model.AddNode(d.t)
		default:
			d.model.AddNode(newDStarLiteNode(n))
		}
	}
	for _, u := range d.model.Nodes() {
		for _, v := range g.From(u) {
			w := edgeWeight(d.weight, u, v)
			if w < 0 {
				panic("D* Lite: negative edge weight")
			}
			d.model.SetEdge(concrete.Edge{F: u, T: d.model.Node(v.ID()), W: w})
		}
	}

	/*
		procedure Main()
		{31”} ComputeShortestPath();
	*/
	d.findShortestPath()

	return d
}
コード例 #20
0
ファイル: dot.go プロジェクト: sbinet/gonum-graph
func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool) error {
	nodes := g.Nodes()
	sort.Sort(ordered.ByID(nodes))

	p.buf.WriteString(p.prefix)
	if needsIndent {
		for i := 0; i < p.depth; i++ {
			p.buf.WriteString(p.indent)
		}
	}
	_, isDirected := g.(graph.Directed)
	if isSubgraph {
		p.buf.WriteString("sub")
	} else if isDirected {
		p.buf.WriteString("di")
	}
	p.buf.WriteString("graph")

	if name == "" {
		if g, ok := g.(Graph); ok {
			name = g.DOTID()
		}
	}
	if name != "" {
		p.buf.WriteByte(' ')
		p.buf.WriteString(name)
	}

	p.openBlock(" {")
	if a, ok := g.(Attributers); ok {
		p.writeAttributeComplex(a)
	}
	if s, ok := g.(Structurer); ok {
		for _, g := range s.Structure() {
			_, subIsDirected := g.(graph.Directed)
			if subIsDirected != isDirected {
				return errors.New("dot: mismatched graph type")
			}
			p.buf.WriteByte('\n')
			p.print(g, g.DOTID(), true, true)
		}
	}

	havePrintedNodeHeader := false
	for _, n := range nodes {
		if s, ok := n.(Subgrapher); ok {
			// If the node is not linked to any other node
			// the graph needs to be written now.
			if len(g.From(n)) == 0 {
				g := s.Subgraph()
				_, subIsDirected := g.(graph.Directed)
				if subIsDirected != isDirected {
					return errors.New("dot: mismatched graph type")
				}
				if !havePrintedNodeHeader {
					p.newline()
					p.buf.WriteString("// Node definitions.")
					havePrintedNodeHeader = true
				}
				p.newline()
				p.print(g, graphID(g, n), false, true)
			}
			continue
		}
		if !havePrintedNodeHeader {
			p.newline()
			p.buf.WriteString("// Node definitions.")
			havePrintedNodeHeader = true
		}
		p.newline()
		p.writeNode(n)
		if a, ok := n.(Attributer); ok {
			p.writeAttributeList(a)
		}
		p.buf.WriteByte(';')
	}

	havePrintedEdgeHeader := false
	for _, n := range nodes {
		to := g.From(n)
		sort.Sort(ordered.ByID(to))
		for _, t := range to {
			if isDirected {
				if p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] {
					continue
				}
				p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true
			} else {
				if p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] {
					continue
				}
				p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true
				p.visited[edge{inGraph: name, from: t.ID(), to: n.ID()}] = true
			}

			if !havePrintedEdgeHeader {
				p.buf.WriteByte('\n')
				p.buf.WriteString(strings.TrimRight(p.prefix, " \t\xa0")) // Trim whitespace suffix.
				p.newline()
				p.buf.WriteString("// Edge definitions.")
				havePrintedEdgeHeader = true
			}
			p.newline()

			if s, ok := n.(Subgrapher); ok {
				g := s.Subgraph()
				_, subIsDirected := g.(graph.Directed)
				if subIsDirected != isDirected {
					return errors.New("dot: mismatched graph type")
				}
				p.print(g, graphID(g, n), false, true)
			} else {
				p.writeNode(n)
			}
			e, edgeIsPorter := g.Edge(n, t).(Porter)
			if edgeIsPorter {
				p.writePorts(e.FromPort())
			}

			if isDirected {
				p.buf.WriteString(" -> ")
			} else {
				p.buf.WriteString(" -- ")
			}

			if s, ok := t.(Subgrapher); ok {
				g := s.Subgraph()
				_, subIsDirected := g.(graph.Directed)
				if subIsDirected != isDirected {
					return errors.New("dot: mismatched graph type")
				}
				p.print(g, graphID(g, t), false, true)
			} else {
				p.writeNode(t)
			}
			if edgeIsPorter {
				p.writePorts(e.ToPort())
			}

			if a, ok := g.Edge(n, t).(Attributer); ok {
				p.writeAttributeList(a)
			}

			p.buf.WriteByte(';')
		}
	}
	p.closeBlock("}")

	return nil
}
コード例 #21
0
ファイル: internals.go プロジェクト: cjnygard/origin
func genIsNeighbor(g graph.Graph) func(graph.Node, graph.Node) bool {
	return func(node, succ graph.Node) bool {
		return g.EdgeBetween(succ, node) != nil
	}
}
コード例 #22
-1
// BellmanFordFrom returns a shortest-path tree for a shortest path from u to all nodes in
// the graph g, or false indicating that a negative cycle exists in the graph. If the graph
// does not implement graph.Weighter, UniformCost is used.
//
// The time complexity of BellmanFordFrom is O(|V|.|E|).
func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
	if !g.Has(u) {
		return Shortest{from: u}, true
	}
	var weight Weighting
	if wg, ok := g.(graph.Weighter); ok {
		weight = wg.Weight
	} else {
		weight = UniformCost(g)
	}

	nodes := g.Nodes()

	path = newShortestFrom(u, nodes)
	path.dist[path.indexOf[u.ID()]] = 0

	// TODO(kortschak): Consider adding further optimisations
	// from http://arxiv.org/abs/1111.5414.
	for i := 1; i < len(nodes); i++ {
		changed := false
		for j, u := range nodes {
			for _, v := range g.From(u) {
				k := path.indexOf[v.ID()]
				w, ok := weight(u, v)
				if !ok {
					panic("bellman-ford: unexpected invalid weight")
				}
				joint := path.dist[j] + w
				if joint < path.dist[k] {
					path.set(k, joint, j)
					changed = true
				}
			}
		}
		if !changed {
			break
		}
	}

	for j, u := range nodes {
		for _, v := range g.From(u) {
			k := path.indexOf[v.ID()]
			w, ok := weight(u, v)
			if !ok {
				panic("bellman-ford: unexpected invalid weight")
			}
			if path.dist[j]+w < path.dist[k] {
				return path, false
			}
		}
	}

	return path, true
}