github.com/iaas-resource-provision/iaas-rpc@v1.0.7-0.20211021023331-ed21f798c408/internal/dag/dag.go (about)

     1  package dag
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strings"
     7  
     8  	"github.com/iaas-resource-provision/iaas-rpc/internal/tfdiags"
     9  
    10  	"github.com/hashicorp/go-multierror"
    11  )
    12  
    13  // AcyclicGraph is a specialization of Graph that cannot have cycles.
    14  type AcyclicGraph struct {
    15  	Graph
    16  }
    17  
    18  // WalkFunc is the callback used for walking the graph.
    19  type WalkFunc func(Vertex) tfdiags.Diagnostics
    20  
    21  // DepthWalkFunc is a walk function that also receives the current depth of the
    22  // walk as an argument
    23  type DepthWalkFunc func(Vertex, int) error
    24  
    25  func (g *AcyclicGraph) DirectedGraph() Grapher {
    26  	return g
    27  }
    28  
    29  // Returns a Set that includes every Vertex yielded by walking down from the
    30  // provided starting Vertex v.
    31  func (g *AcyclicGraph) Ancestors(v Vertex) (Set, error) {
    32  	s := make(Set)
    33  	memoFunc := func(v Vertex, d int) error {
    34  		s.Add(v)
    35  		return nil
    36  	}
    37  
    38  	if err := g.DepthFirstWalk(g.downEdgesNoCopy(v), 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 := make(Set)
    49  	memoFunc := func(v Vertex, d int) error {
    50  		s.Add(v)
    51  		return nil
    52  	}
    53  
    54  	if err := g.ReverseDepthFirstWalk(g.upEdgesNoCopy(v), memoFunc); err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	return s, nil
    59  }
    60  
    61  // Root returns the root of the DAG, or an error.
    62  //
    63  // Complexity: O(V)
    64  func (g *AcyclicGraph) Root() (Vertex, error) {
    65  	roots := make([]Vertex, 0, 1)
    66  	for _, v := range g.Vertices() {
    67  		if g.upEdgesNoCopy(v).Len() == 0 {
    68  			roots = append(roots, v)
    69  		}
    70  	}
    71  
    72  	if len(roots) > 1 {
    73  		// TODO(mitchellh): make this error message a lot better
    74  		return nil, fmt.Errorf("multiple roots: %#v", roots)
    75  	}
    76  
    77  	if len(roots) == 0 {
    78  		return nil, fmt.Errorf("no roots found")
    79  	}
    80  
    81  	return roots[0], nil
    82  }
    83  
    84  // TransitiveReduction performs the transitive reduction of graph g in place.
    85  // The transitive reduction of a graph is a graph with as few edges as
    86  // possible with the same reachability as the original graph. This means
    87  // that if there are three nodes A => B => C, and A connects to both
    88  // B and C, and B connects to C, then the transitive reduction is the
    89  // same graph with only a single edge between A and B, and a single edge
    90  // between B and C.
    91  //
    92  // The graph must be valid for this operation to behave properly. If
    93  // Validate() returns an error, the behavior is undefined and the results
    94  // will likely be unexpected.
    95  //
    96  // Complexity: O(V(V+E)), or asymptotically O(VE)
    97  func (g *AcyclicGraph) TransitiveReduction() {
    98  	// For each vertex u in graph g, do a DFS starting from each vertex
    99  	// v such that the edge (u,v) exists (v is a direct descendant of u).
   100  	//
   101  	// For each v-prime reachable from v, remove the edge (u, v-prime).
   102  	for _, u := range g.Vertices() {
   103  		uTargets := g.downEdgesNoCopy(u)
   104  
   105  		g.DepthFirstWalk(g.downEdgesNoCopy(u), func(v Vertex, d int) error {
   106  			shared := uTargets.Intersection(g.downEdgesNoCopy(v))
   107  			for _, vPrime := range shared {
   108  				g.RemoveEdge(BasicEdge(u, vPrime))
   109  			}
   110  
   111  			return nil
   112  		})
   113  	}
   114  }
   115  
   116  // Validate validates the DAG. A DAG is valid if it has a single root
   117  // with no cycles.
   118  func (g *AcyclicGraph) Validate() error {
   119  	if _, err := g.Root(); err != nil {
   120  		return err
   121  	}
   122  
   123  	// Look for cycles of more than 1 component
   124  	var err error
   125  	cycles := g.Cycles()
   126  	if len(cycles) > 0 {
   127  		for _, cycle := range cycles {
   128  			cycleStr := make([]string, len(cycle))
   129  			for j, vertex := range cycle {
   130  				cycleStr[j] = VertexName(vertex)
   131  			}
   132  
   133  			err = multierror.Append(err, fmt.Errorf(
   134  				"Cycle: %s", strings.Join(cycleStr, ", ")))
   135  		}
   136  	}
   137  
   138  	// Look for cycles to self
   139  	for _, e := range g.Edges() {
   140  		if e.Source() == e.Target() {
   141  			err = multierror.Append(err, fmt.Errorf(
   142  				"Self reference: %s", VertexName(e.Source())))
   143  		}
   144  	}
   145  
   146  	return err
   147  }
   148  
   149  func (g *AcyclicGraph) Cycles() [][]Vertex {
   150  	var cycles [][]Vertex
   151  	for _, cycle := range StronglyConnected(&g.Graph) {
   152  		if len(cycle) > 1 {
   153  			cycles = append(cycles, cycle)
   154  		}
   155  	}
   156  	return cycles
   157  }
   158  
   159  // Walk walks the graph, calling your callback as each node is visited.
   160  // This will walk nodes in parallel if it can. The resulting diagnostics
   161  // contains problems from all graphs visited, in no particular order.
   162  func (g *AcyclicGraph) Walk(cb WalkFunc) tfdiags.Diagnostics {
   163  	w := &Walker{Callback: cb, Reverse: true}
   164  	w.Update(g)
   165  	return w.Wait()
   166  }
   167  
   168  // simple convenience helper for converting a dag.Set to a []Vertex
   169  func AsVertexList(s Set) []Vertex {
   170  	vertexList := make([]Vertex, 0, len(s))
   171  	for _, raw := range s {
   172  		vertexList = append(vertexList, raw.(Vertex))
   173  	}
   174  	return vertexList
   175  }
   176  
   177  type vertexAtDepth struct {
   178  	Vertex Vertex
   179  	Depth  int
   180  }
   181  
   182  // DepthFirstWalk does a depth-first walk of the graph starting from
   183  // the vertices in start.
   184  func (g *AcyclicGraph) DepthFirstWalk(start Set, f DepthWalkFunc) error {
   185  	seen := make(map[Vertex]struct{})
   186  	frontier := make([]*vertexAtDepth, 0, len(start))
   187  	for _, v := range start {
   188  		frontier = append(frontier, &vertexAtDepth{
   189  			Vertex: v,
   190  			Depth:  0,
   191  		})
   192  	}
   193  	for len(frontier) > 0 {
   194  		// Pop the current vertex
   195  		n := len(frontier)
   196  		current := frontier[n-1]
   197  		frontier = frontier[:n-1]
   198  
   199  		// Check if we've seen this already and return...
   200  		if _, ok := seen[current.Vertex]; ok {
   201  			continue
   202  		}
   203  		seen[current.Vertex] = struct{}{}
   204  
   205  		// Visit the current node
   206  		if err := f(current.Vertex, current.Depth); err != nil {
   207  			return err
   208  		}
   209  
   210  		for _, v := range g.downEdgesNoCopy(current.Vertex) {
   211  			frontier = append(frontier, &vertexAtDepth{
   212  				Vertex: v,
   213  				Depth:  current.Depth + 1,
   214  			})
   215  		}
   216  	}
   217  
   218  	return nil
   219  }
   220  
   221  // SortedDepthFirstWalk does a depth-first walk of the graph starting from
   222  // the vertices in start, always iterating the nodes in a consistent order.
   223  func (g *AcyclicGraph) SortedDepthFirstWalk(start []Vertex, f DepthWalkFunc) error {
   224  	seen := make(map[Vertex]struct{})
   225  	frontier := make([]*vertexAtDepth, len(start))
   226  	for i, v := range start {
   227  		frontier[i] = &vertexAtDepth{
   228  			Vertex: v,
   229  			Depth:  0,
   230  		}
   231  	}
   232  	for len(frontier) > 0 {
   233  		// Pop the current vertex
   234  		n := len(frontier)
   235  		current := frontier[n-1]
   236  		frontier = frontier[:n-1]
   237  
   238  		// Check if we've seen this already and return...
   239  		if _, ok := seen[current.Vertex]; ok {
   240  			continue
   241  		}
   242  		seen[current.Vertex] = struct{}{}
   243  
   244  		// Visit the current node
   245  		if err := f(current.Vertex, current.Depth); err != nil {
   246  			return err
   247  		}
   248  
   249  		// Visit targets of this in a consistent order.
   250  		targets := AsVertexList(g.downEdgesNoCopy(current.Vertex))
   251  		sort.Sort(byVertexName(targets))
   252  
   253  		for _, t := range targets {
   254  			frontier = append(frontier, &vertexAtDepth{
   255  				Vertex: t,
   256  				Depth:  current.Depth + 1,
   257  			})
   258  		}
   259  	}
   260  
   261  	return nil
   262  }
   263  
   264  // ReverseDepthFirstWalk does a depth-first walk _up_ the graph starting from
   265  // the vertices in start.
   266  func (g *AcyclicGraph) ReverseDepthFirstWalk(start Set, f DepthWalkFunc) error {
   267  	seen := make(map[Vertex]struct{})
   268  	frontier := make([]*vertexAtDepth, 0, len(start))
   269  	for _, v := range start {
   270  		frontier = append(frontier, &vertexAtDepth{
   271  			Vertex: v,
   272  			Depth:  0,
   273  		})
   274  	}
   275  	for len(frontier) > 0 {
   276  		// Pop the current vertex
   277  		n := len(frontier)
   278  		current := frontier[n-1]
   279  		frontier = frontier[:n-1]
   280  
   281  		// Check if we've seen this already and return...
   282  		if _, ok := seen[current.Vertex]; ok {
   283  			continue
   284  		}
   285  		seen[current.Vertex] = struct{}{}
   286  
   287  		for _, t := range g.upEdgesNoCopy(current.Vertex) {
   288  			frontier = append(frontier, &vertexAtDepth{
   289  				Vertex: t,
   290  				Depth:  current.Depth + 1,
   291  			})
   292  		}
   293  
   294  		// Visit the current node
   295  		if err := f(current.Vertex, current.Depth); err != nil {
   296  			return err
   297  		}
   298  	}
   299  
   300  	return nil
   301  }
   302  
   303  // SortedReverseDepthFirstWalk does a depth-first walk _up_ the graph starting from
   304  // the vertices in start, always iterating the nodes in a consistent order.
   305  func (g *AcyclicGraph) SortedReverseDepthFirstWalk(start []Vertex, f DepthWalkFunc) error {
   306  	seen := make(map[Vertex]struct{})
   307  	frontier := make([]*vertexAtDepth, len(start))
   308  	for i, v := range start {
   309  		frontier[i] = &vertexAtDepth{
   310  			Vertex: v,
   311  			Depth:  0,
   312  		}
   313  	}
   314  	for len(frontier) > 0 {
   315  		// Pop the current vertex
   316  		n := len(frontier)
   317  		current := frontier[n-1]
   318  		frontier = frontier[:n-1]
   319  
   320  		// Check if we've seen this already and return...
   321  		if _, ok := seen[current.Vertex]; ok {
   322  			continue
   323  		}
   324  		seen[current.Vertex] = struct{}{}
   325  
   326  		// Add next set of targets in a consistent order.
   327  		targets := AsVertexList(g.upEdgesNoCopy(current.Vertex))
   328  		sort.Sort(byVertexName(targets))
   329  		for _, t := range targets {
   330  			frontier = append(frontier, &vertexAtDepth{
   331  				Vertex: t,
   332  				Depth:  current.Depth + 1,
   333  			})
   334  		}
   335  
   336  		// Visit the current node
   337  		if err := f(current.Vertex, current.Depth); err != nil {
   338  			return err
   339  		}
   340  	}
   341  
   342  	return nil
   343  }
   344  
   345  // byVertexName implements sort.Interface so a list of Vertices can be sorted
   346  // consistently by their VertexName
   347  type byVertexName []Vertex
   348  
   349  func (b byVertexName) Len() int      { return len(b) }
   350  func (b byVertexName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
   351  func (b byVertexName) Less(i, j int) bool {
   352  	return VertexName(b[i]) < VertexName(b[j])
   353  }