/// <summary>
        /// Trace back path from destination to source using parent map.
        /// </summary>
        private ShortestPathResult <T, W> tracePath(IDiGraph <T> graph,
                                                    Dictionary <T, T> parentMap, T source, T destination)
        {
            //trace the path
            var pathStack = new Stack <T>();

            pathStack.Push(destination);

            var currentV = destination;

            while (!Equals(currentV, default(T)) && !Equals(parentMap[currentV], default(T)))
            {
                pathStack.Push(parentMap[currentV]);
                currentV = parentMap[currentV];
            }

            //return result
            var resultPath   = new List <T>();
            var resultLength = @operator.DefaultValue;

            while (pathStack.Count > 0)
            {
                resultPath.Add(pathStack.Pop());
            }

            for (var i = 0; i < resultPath.Count - 1; i++)
            {
                resultLength = @operator.Sum(resultLength,
                                             graph.GetVertex(resultPath[i]).GetOutEdge(graph.GetVertex(resultPath[i + 1])).Weight <W>());
            }

            return(new ShortestPathResult <T, W>(resultPath, resultLength));
        }
        /// <summary>
        /// Returns the vertices in Topologically Sorted Order.
        /// </summary>
        public List <T> GetTopSort(IDiGraph <T> graph)
        {
            var inEdgeMap = new Dictionary <T, int>();

            var kahnQueue = new Queue <T>();

            foreach (var vertex in graph.VerticesAsEnumberable)
            {
                inEdgeMap.Add(vertex.Key, vertex.InEdgeCount);

                //init queue with vertices having not in edges
                if (vertex.InEdgeCount == 0)
                {
                    kahnQueue.Enqueue(vertex.Key);
                }
            }

            //no vertices with zero number of in edges
            if (kahnQueue.Count == 0)
            {
                throw new Exception("Graph has a cycle.");
            }

            var result = new List <T>();

            int visitCount = 0;

            //until queue is empty
            while (kahnQueue.Count > 0)
            {
                //cannot exceed vertex number of iterations
                if (visitCount > graph.VerticesCount)
                {
                    throw new Exception("Graph has a cycle.");
                }

                //pick a neighbour
                var nextPick = graph.GetVertex(kahnQueue.Dequeue());

                //if in edge count is 0 then ready for result
                if (inEdgeMap[nextPick.Key] == 0)
                {
                    result.Add(nextPick.Key);
                }

                //decrement in edge count for neighbours
                foreach (var edge in nextPick.OutEdges)
                {
                    inEdgeMap[edge.TargetVertexKey]--;
                    kahnQueue.Enqueue(edge.TargetVertexKey);
                }

                visitCount++;
            }

            return(result);
        }
Beispiel #3
0
        public List <MinCutEdge <T> > ComputeMinCut(IDiGraph <T> graph,
                                                    T source, T sink)
        {
            if (this.@operator == null)
            {
                throw new ArgumentException("Provide an operator implementation for generic type W during initialization.");
            }

            if (!graph.IsWeightedGraph)
            {
                if ([email protected]() != typeof(int))
                {
                    throw new ArgumentException("Edges of unweighted graphs are assigned an imaginary weight of one (1)." +
                                                "Provide an appropriate IFlowOperators<int> operator implementation during initialization.");
                }
            }

            var edmondsKarpMaxFlow = new EdmondKarpMaxFlow <T, W>(@operator);

            var maxFlowResidualGraph = edmondsKarpMaxFlow
                                       .computeMaxFlowAndReturnResidualGraph(graph, source, sink);

            //according to Min Max theory
            //the Min Cut can be obtained by Finding edges
            //from Reachable Vertices from Source
            //to unreachable vertices in residual graph
            var reachableVertices = getReachable(maxFlowResidualGraph, source);

            var result = new List <MinCutEdge <T> >();

            foreach (var vertex in reachableVertices)
            {
                foreach (var edge in graph.GetVertex(vertex).OutEdges)
                {
                    //if unreachable
                    if (!reachableVertices.Contains(edge.TargetVertexKey))
                    {
                        result.Add(new MinCutEdge <T>(vertex, edge.TargetVertexKey));
                    }
                }
            }

            return(result);
        }
        /// <summary>
        /// Find shortest distance to target.
        /// </summary>
        public ShortestPathResult <T, W> FindShortestPath(IDiGraph <T> graph,
                                                          T source, T destination)
        {
            //regular argument checks
            if (graph == null || graph.GetVertex(source) == null ||
                graph.GetVertex(destination) == null)
            {
                throw new ArgumentException("Empty Graph or invalid source/destination.");
            }

            if (this.@operator == null)
            {
                throw new ArgumentException("Provide an operator implementation for generic type W during initialization.");
            }

            if (!graph.IsWeightedGraph)
            {
                if ([email protected]() != typeof(int))
                {
                    throw new ArgumentException("Edges of unweighted graphs are assigned an imaginary weight of one (1)." +
                                                "Provide an appropriate IShortestPathOperators<int> operator implementation during initialization.");
                }
            }

            var progress  = new Dictionary <T, W>();
            var parentMap = new Dictionary <T, T>();

            foreach (var vertex in graph.VerticesAsEnumberable)
            {
                parentMap.Add(vertex.Key, default(T));
                progress.Add(vertex.Key, @operator.MaxValue);
            }

            progress[source] = @operator.DefaultValue;

            var iterations = graph.VerticesCount - 1;
            var updated    = true;

            while (iterations > 0 && updated)
            {
                updated = false;

                foreach (var vertex in graph.VerticesAsEnumberable)
                {
                    //skip not discovered nodes
                    if (progress[vertex.Key].Equals(@operator.MaxValue))
                    {
                        continue;
                    }

                    foreach (var edge in vertex.OutEdges)
                    {
                        var currentDistance = progress[edge.TargetVertexKey];
                        var newDistance     = @operator.Sum(progress[vertex.Key],
                                                            vertex.GetOutEdge(edge.TargetVertex).Weight <W>());

                        if (newDistance.CompareTo(currentDistance) < 0)
                        {
                            updated = true;
                            progress[edge.TargetVertexKey]  = newDistance;
                            parentMap[edge.TargetVertexKey] = vertex.Key;
                        }
                    }
                }

                iterations--;

                if (iterations < 0)
                {
                    throw new Exception("Negative cycle exists in this graph.");
                }
            }

            return(tracePath(graph, parentMap, source, destination));
        }