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 }
// 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 }
// 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 } }
// 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, graph.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 graph.WeightFunc if g, ok := g.(graph.Weighter); ok { weight = g.Weight } else { weight = graph.UniformCost } 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()] joint := path.dist[j] + weight(g.Edge(u, v)) 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()] if path.dist[j]+weight(g.Edge(u, v)) < path.dist[k] { return path, false } } } return path, true }
// 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 }
// 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 graph.WeightFunc if g, ok := g.(graph.Weighter); ok { weight = g.Weight } else { weight = graph.UniformCost } 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 := weight(g.Edge(mid.node, v)) 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) } } } } }
// 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 }
// 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 }
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 }
// 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 }