/// <summary> /// Turns a DAG which is already a tree into a <see cref="Tree{T}"/>. If the DAG is weakly or strongly cyclic, or disconnected, <see cref="Maybe.Nothing{T}"/> is returned. /// </summary> /// <typeparam name="TVertex">The type of the vertices.</typeparam> /// <param name="g">The graph.</param> public static Maybe <Tree <TVertex> > DagToTree <TVertex>(this DirectedGraph <TVertex, DirectedEdge <TVertex> > g) where TVertex : IEquatable <TVertex> { var visitedVertices = new HashSet <TVertex>(); var roots = g.Vertices.Where(v => g.GetEdgesToEndVertex(v).Where(e => e.EndVertex.Equals(v)).Empty()).ToList(); var sorter = new CycleDetectingSorter <TVertex, DirectedEdge <TVertex> >(g, true); //Definition of a tree: |E| = |V|-1 && the graph is connected. if (roots.Count != 1 || g.EdgeCount != (g.VertexCount - 1) || !g.IsConnected()) { return(Maybe.Nothing <Tree <TVertex> >()); } Tree <TVertex> go(TVertex cur) { visitedVertices.Add(cur); var children = g.GetEdgesFromStartVertex(cur); if (children.Count == 0) { return(Tree.MakeLeaf(cur)); } else { return(Tree.MakeInner(cur, children.Where(c => !visitedVertices.Contains(c.EndVertex)).Select(c => go(c.EndVertex)))); } }; return(Maybe.Just(go(roots[0]))); }
/// <summary> /// Returns true iff the graph has cycles. The dependency from <see cref="IWindsorContainer"/> to <see cref="IWindsorContainer"/> will be excluded, as that is the one permissible cycle according to Castle Windsor. /// </summary> /// <param name="cycles">The vertices which form part of cycles, with their outgoing edges. The outgoing edges indicates dependencies of the vertex. If there are no cycles, <c>default</c> will be returned.</param> public bool HasCycles(out IDictionary <Type, ISet <Type> > cycles) { var g = CreateGraph(false); var sorter = new CycleDetectingSorter <Type, DirectedEdge <Type> >(g, true); cycles = default; var result = sorter.SortWithCycleDetection(out var _); if (result.HasValue) { cycles = new Dictionary <Type, ISet <Type> >(); foreach (var cycle in result.Value()) { cycles[cycle.Item1] = cycle.Item2.Select(c => c.EndVertex).ToHashSet(); } //Special case: we exclude the cycle {IWindsorContainer -> IWindsorContainer} if (HasOnlyWindsorCycle(cycles)) { cycles = default; return(false); } return(true); } else { return(false); } }
/// <summary> /// Returns true iff the graph has cycles. /// </summary> /// <param name="g">The graph.</param> /// <param name="cycles">The vertices which form part of cycles, with their outgoing edges. If there are no cycles, <c>default</c> will be returned.</param> public static bool HasCycles <TVertex, TEdge>(this DirectedGraph <TVertex, TEdge> g, out IDictionary <TVertex, ISet <TVertex> > cycles) where TEdge : DirectedEdge <TVertex> { var sorter = new CycleDetectingSorter <TVertex, TEdge>(g, true); cycles = default; var result = sorter.SortWithCycleDetection(out var _); if (result.HasValue) { cycles = new Dictionary <TVertex, ISet <TVertex> >(); foreach (var cycle in result.Value()) { cycles[cycle.Item1] = cycle.Item2.Select(c => c.EndVertex).ToHashSet(); } return(true); } else { return(false); } }