예제 #1
0
        /// <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])));
        }
예제 #2
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);
            }
        }
예제 #3
0
        /// <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);
            }
        }