github.com/paultyng/terraform@v0.6.11-0.20180227224804-66ff8f8bed40/dag/dag.go (about)

     1  package dag
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strings"
     7  
     8  	"github.com/hashicorp/go-multierror"
     9  )
    10  
    11  // AcyclicGraph is a specialization of Graph that cannot have cycles. With
    12  // this property, we get the property of sane graph traversal.
    13  type AcyclicGraph struct {
    14  	Graph
    15  }
    16  
    17  // WalkFunc is the callback used for walking the graph.
    18  type WalkFunc func(Vertex) error
    19  
    20  // DepthWalkFunc is a walk function that also receives the current depth of the
    21  // walk as an argument
    22  type DepthWalkFunc func(Vertex, int) error
    23  
    24  func (g *AcyclicGraph) DirectedGraph() Grapher {
    25  	return g
    26  }
    27  
    28  // Returns a Set that includes every Vertex yielded by walking down from the
    29  // provided starting Vertex v.
    30  func (g *AcyclicGraph) Ancestors(v Vertex) (*Set, error) {
    31  	s := new(Set)
    32  	start := AsVertexList(g.DownEdges(v))
    33  	memoFunc := func(v Vertex, d int) error {
    34  		s.Add(v)
    35  		return nil
    36  	}
    37  
    38  	if err := g.DepthFirstWalk(start, memoFunc); err != nil {
    39  		return nil, err
    40  	}
    41  
    42  	return s, nil
    43  }
    44  
    45  // Returns a Set that includes every Vertex yielded by walking up from the
    46  // provided starting Vertex v.
    47  func (g *AcyclicGraph) Descendents(v Vertex) (*Set, error) {
    48  	s := new(Set)
    49  	start := AsVertexList(g.UpEdges(v))
    50  	memoFunc := func(v Vertex, d int) error {
    51  		s.Add(v)
    52  		return nil
    53  	}
    54  
    55  	if err := g.ReverseDepthFirstWalk(start, memoFunc); err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	return s, nil
    60  }
    61  
    62  // Root returns the root of the DAG, or an error.
    63  //
    64  // Complexity: O(V)
    65  func (g *AcyclicGraph) Root() (Vertex, error) {
    66  	roots := make([]Vertex, 0, 1)
    67  	for _, v := range g.Vertices() {
    68  		if g.UpEdges(v).Len() == 0 {
    69  			roots = append(roots, v)
    70  		}
    71  	}
    72  
    73  	if len(roots) > 1 {
    74  		// TODO(mitchellh): make this error message a lot better
    75  		return nil, fmt.Errorf("multiple roots: %#v", roots)
    76  	}
    77  
    78  	if len(roots) == 0 {
    79  		return nil, fmt.Errorf("no roots found")
    80  	}
    81  
    82  	return roots[0], nil
    83  }
    84  
    85  // TransitiveReduction performs the transitive reduction of graph g in place.
    86  // The transitive reduction of a graph is a graph with as few edges as
    87  // possible with the same reachability as the original graph. This means
    88  // that if there are three nodes A => B => C, and A connects to both
    89  // B and C, and B connects to C, then the transitive reduction is the
    90  // same graph with only a single edge between A and B, and a single edge
    91  // between B and C.
    92  //
    93  // The graph must be valid for this operation to behave properly. If
    94  // Validate() returns an error, the behavior is undefined and the results
    95  // will likely be unexpected.
    96  //
    97  // Complexity: O(V(V+E)), or asymptotically O(VE)
    98  func (g *AcyclicGraph) TransitiveReduction() {
    99  	// For each vertex u in graph g, do a DFS starting from each vertex
   100  	// v such that the edge (u,v) exists (v is a direct descendant of u).
   101  	//
   102  	// For each v-prime reachable from v, remove the edge (u, v-prime).
   103  	defer g.debug.BeginOperation("TransitiveReduction", "").End("")
   104  
   105  	for _, u := range g.Vertices() {
   106  		uTargets := g.DownEdges(u)
   107  		vs := AsVertexList(g.DownEdges(u))
   108  
   109  		g.depthFirstWalk(vs, false, func(v Vertex, d int) error {
   110  			shared := uTargets.Intersection(g.DownEdges(v))
   111  			for _, vPrime := range AsVertexList(shared) {
   112  				g.RemoveEdge(BasicEdge(u, vPrime))
   113  			}
   114  
   115  			return nil
   116  		})
   117  	}
   118  }
   119  
   120  // Validate validates the DAG. A DAG is valid if it has a single root
   121  // with no cycles.
   122  func (g *AcyclicGraph) Validate() error {
   123  	if _, err := g.Root(); err != nil {
   124  		return err
   125  	}
   126  
   127  	// Look for cycles of more than 1 component
   128  	var err error
   129  	cycles := g.Cycles()
   130  	if len(cycles) > 0 {
   131  		for _, cycle := range cycles {
   132  			cycleStr := make([]string, len(cycle))
   133  			for j, vertex := range cycle {
   134  				cycleStr[j] = VertexName(vertex)
   135  			}
   136  
   137  			err = multierror.Append(err, fmt.Errorf(
   138  				"Cycle: %s", strings.Join(cycleStr, ", ")))
   139  		}
   140  	}
   141  
   142  	// Look for cycles to self
   143  	for _, e := range g.Edges() {
   144  		if e.Source() == e.Target() {
   145  			err = multierror.Append(err, fmt.Errorf(
   146  				"Self reference: %s", VertexName(e.Source())))
   147  		}
   148  	}
   149  
   150  	return err
   151  }
   152  
   153  func (g *AcyclicGraph) Cycles() [][]Vertex {
   154  	var cycles [][]Vertex
   155  	for _, cycle := range StronglyConnected(&g.Graph) {
   156  		if len(cycle) > 1 {
   157  			cycles = append(cycles, cycle)
   158  		}
   159  	}
   160  	return cycles
   161  }
   162  
   163  // Walk walks the graph, calling your callback as each node is visited.
   164  // This will walk nodes in parallel if it can. Because the walk is done
   165  // in parallel, the error returned will be a multierror.
   166  func (g *AcyclicGraph) Walk(cb WalkFunc) error {
   167  	defer g.debug.BeginOperation(typeWalk, "").End("")
   168  
   169  	w := &Walker{Callback: cb, Reverse: true}
   170  	w.Update(g)
   171  	return w.Wait()
   172  }
   173  
   174  // simple convenience helper for converting a dag.Set to a []Vertex
   175  func AsVertexList(s *Set) []Vertex {
   176  	rawList := s.List()
   177  	vertexList := make([]Vertex, len(rawList))
   178  	for i, raw := range rawList {
   179  		vertexList[i] = raw.(Vertex)
   180  	}
   181  	return vertexList
   182  }
   183  
   184  type vertexAtDepth struct {
   185  	Vertex Vertex
   186  	Depth  int
   187  }
   188  
   189  // depthFirstWalk does a depth-first walk of the graph starting from
   190  // the vertices in start.
   191  func (g *AcyclicGraph) DepthFirstWalk(start []Vertex, f DepthWalkFunc) error {
   192  	return g.depthFirstWalk(start, true, f)
   193  }
   194  
   195  // This internal method provides the option of not sorting the vertices during
   196  // the walk, which we use for the Transitive reduction.
   197  // Some configurations can lead to fully-connected subgraphs, which makes our
   198  // transitive reduction algorithm O(n^3). This is still passable for the size
   199  // of our graphs, but the additional n^2 sort operations would make this
   200  // uncomputable in a reasonable amount of time.
   201  func (g *AcyclicGraph) depthFirstWalk(start []Vertex, sorted bool, f DepthWalkFunc) error {
   202  	defer g.debug.BeginOperation(typeDepthFirstWalk, "").End("")
   203  
   204  	seen := make(map[Vertex]struct{})
   205  	frontier := make([]*vertexAtDepth, len(start))
   206  	for i, v := range start {
   207  		frontier[i] = &vertexAtDepth{
   208  			Vertex: v,
   209  			Depth:  0,
   210  		}
   211  	}
   212  	for len(frontier) > 0 {
   213  		// Pop the current vertex
   214  		n := len(frontier)
   215  		current := frontier[n-1]
   216  		frontier = frontier[:n-1]
   217  
   218  		// Check if we've seen this already and return...
   219  		if _, ok := seen[current.Vertex]; ok {
   220  			continue
   221  		}
   222  		seen[current.Vertex] = struct{}{}
   223  
   224  		// Visit the current node
   225  		if err := f(current.Vertex, current.Depth); err != nil {
   226  			return err
   227  		}
   228  
   229  		// Visit targets of this in a consistent order.
   230  		targets := AsVertexList(g.DownEdges(current.Vertex))
   231  
   232  		if sorted {
   233  			sort.Sort(byVertexName(targets))
   234  		}
   235  
   236  		for _, t := range targets {
   237  			frontier = append(frontier, &vertexAtDepth{
   238  				Vertex: t,
   239  				Depth:  current.Depth + 1,
   240  			})
   241  		}
   242  	}
   243  
   244  	return nil
   245  }
   246  
   247  // reverseDepthFirstWalk does a depth-first walk _up_ the graph starting from
   248  // the vertices in start.
   249  func (g *AcyclicGraph) ReverseDepthFirstWalk(start []Vertex, f DepthWalkFunc) error {
   250  	defer g.debug.BeginOperation(typeReverseDepthFirstWalk, "").End("")
   251  
   252  	seen := make(map[Vertex]struct{})
   253  	frontier := make([]*vertexAtDepth, len(start))
   254  	for i, v := range start {
   255  		frontier[i] = &vertexAtDepth{
   256  			Vertex: v,
   257  			Depth:  0,
   258  		}
   259  	}
   260  	for len(frontier) > 0 {
   261  		// Pop the current vertex
   262  		n := len(frontier)
   263  		current := frontier[n-1]
   264  		frontier = frontier[:n-1]
   265  
   266  		// Check if we've seen this already and return...
   267  		if _, ok := seen[current.Vertex]; ok {
   268  			continue
   269  		}
   270  		seen[current.Vertex] = struct{}{}
   271  
   272  		// Add next set of targets in a consistent order.
   273  		targets := AsVertexList(g.UpEdges(current.Vertex))
   274  		sort.Sort(byVertexName(targets))
   275  		for _, t := range targets {
   276  			frontier = append(frontier, &vertexAtDepth{
   277  				Vertex: t,
   278  				Depth:  current.Depth + 1,
   279  			})
   280  		}
   281  
   282  		// Visit the current node
   283  		if err := f(current.Vertex, current.Depth); err != nil {
   284  			return err
   285  		}
   286  	}
   287  
   288  	return nil
   289  }
   290  
   291  // byVertexName implements sort.Interface so a list of Vertices can be sorted
   292  // consistently by their VertexName
   293  type byVertexName []Vertex
   294  
   295  func (b byVertexName) Len() int      { return len(b) }
   296  func (b byVertexName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
   297  func (b byVertexName) Less(i, j int) bool {
   298  	return VertexName(b[i]) < VertexName(b[j])
   299  }