topo.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. // Copyright ©2014 The Gonum Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package topo
  5. import (
  6. "gonum.org/v1/gonum/graph"
  7. "gonum.org/v1/gonum/graph/traverse"
  8. )
  9. // IsPathIn returns whether path is a path in g.
  10. //
  11. // As special cases, IsPathIn returns true for a zero length path or for
  12. // a path of length 1 when the node in path exists in the graph.
  13. func IsPathIn(g graph.Graph, path []graph.Node) bool {
  14. switch len(path) {
  15. case 0:
  16. return true
  17. case 1:
  18. return g.Node(path[0].ID()) != nil
  19. default:
  20. var canReach func(uid, vid int64) bool
  21. switch g := g.(type) {
  22. case graph.Directed:
  23. canReach = g.HasEdgeFromTo
  24. default:
  25. canReach = g.HasEdgeBetween
  26. }
  27. for i, u := range path[:len(path)-1] {
  28. if !canReach(u.ID(), path[i+1].ID()) {
  29. return false
  30. }
  31. }
  32. return true
  33. }
  34. }
  35. // PathExistsIn returns whether there is a path in g starting at from extending
  36. // to to.
  37. //
  38. // PathExistsIn exists as a helper function. If many tests for path existence
  39. // are being performed, other approaches will be more efficient.
  40. func PathExistsIn(g graph.Graph, from, to graph.Node) bool {
  41. var t traverse.BreadthFirst
  42. return t.Walk(g, from, func(n graph.Node, _ int) bool { return n.ID() == to.ID() }) != nil
  43. }
  44. // ConnectedComponents returns the connected components of the undirected graph g.
  45. func ConnectedComponents(g graph.Undirected) [][]graph.Node {
  46. var (
  47. w traverse.DepthFirst
  48. c []graph.Node
  49. cc [][]graph.Node
  50. )
  51. during := func(n graph.Node) {
  52. c = append(c, n)
  53. }
  54. after := func() {
  55. cc = append(cc, []graph.Node(nil))
  56. cc[len(cc)-1] = append(cc[len(cc)-1], c...)
  57. c = c[:0]
  58. }
  59. w.WalkAll(g, nil, after, during)
  60. return cc
  61. }