/// <summary>
        /// Tries to compute the shortest paths in a weighted graph with the Bellman-Ford's algorithm. Returns true if successful; otherwise false.
        /// </summary>
        /// <typeparam name="TVertex">The data type of the vertices. TVertex implements <see cref="IComparable{T}"/>.</typeparam>
        /// <typeparam name="TWeight">The data type of weight of the edges. TWeight implements <see cref="IComparable{T}"/>.</typeparam>
        /// <param name="graph">The graph structure that implements <see cref="IWeightedGraph{TVertex, TWeight}"/>.</param>
        /// <param name="source">The source vertex for which the shortest paths are computed.</param>
        /// <param name="shortestPaths">The <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> object that contains the shortest paths of the graph if the algorithm was successful; otherwise null.</param>
        /// <param name="weightAdder">The method corresponding to the <see cref="AddWeights{TWeight}"/> delegate used for calculating the sum of two edge weights.</param>
        /// <returns>Returns true if the shortest paths were successfully computed; otherwise false. Also returns false if the given source vertex does not belong to the graph.</returns>
        public static bool TryGetBellmanFordShortestPaths <TVertex, TWeight>(this IWeightedGraph <TVertex, TWeight> graph, TVertex source, out WeightedGraphShortestPaths <TVertex, TWeight> shortestPaths, AddWeights <TWeight> weightAdder)
            where TVertex : IComparable <TVertex>
            where TWeight : IComparable <TWeight>
        {
            shortestPaths = null;

            if (!graph.ContainsVertex(source))
            {
                return(false);
            }

            // A dictionary holding a vertex as key and as value a key-value pair of its previous vertex in the path(being the key) and the weight of the edge connecting them(being the value).
            var previousVertices = new Dictionary <TVertex, KeyValuePair <TVertex, TWeight> >();
            // The dictionary holding a vertex as key and as value a key-value pair holding the weight of the path from the source vertex(being the key) and the distance from the source vertex(being the value).
            var weightAndDistance = new Dictionary <TVertex, KeyValuePair <TWeight, int> >();

            // Add source vertex to computed weights and distances
            weightAndDistance.Add(source, new KeyValuePair <TWeight, int>(default(TWeight), 0));

            // Get all edges and sort them by their source and then by their destination vertex to create a consistent shortest paths output.
            var allEdges = graph.Edges.ToList();

            if (allEdges.Count > 0)
            {
                allEdges.QuickSort((x, y) =>
                {
                    int cmp = x.Source.CompareTo(y.Source);
                    if (cmp == 0)
                    {
                        cmp = x.Destination.CompareTo(y.Destination);
                    }
                    return(cmp);
                });
            }

            // We relax all edges n - 1 times and if at the n-th step a relaxation is needed we have a negative cycle
            int lastStep = graph.VerticesCount - 1;

            for (int i = 0; i < graph.VerticesCount; i++)
            {
                foreach (var edge in allEdges)
                {
                    var edgeSource      = edge.Source;
                    var edgeDestination = edge.Destination;
                    var edgeWeight      = edge.Weight;

                    // If we have computed the path to the the source vertex of the edge
                    if (weightAndDistance.ContainsKey(edgeSource))
                    {
                        var     wd          = weightAndDistance[edgeSource];
                        TWeight curWeight   = wd.Key;
                        int     curDistance = wd.Value;

                        // If the edge destination is the source we continue with the next edge
                        if (object.Equals(source, edgeDestination))
                        {
                            continue;
                        }

                        // Compute path weight
                        TWeight pathWeight;
                        if (curWeight == null)
                        {
                            pathWeight = edgeWeight;
                        }
                        else
                        {
                            pathWeight = weightAdder(curWeight, edgeWeight);
                        }

                        // If this path is longer than an already computed path we continue with the next edge
                        if (weightAndDistance.ContainsKey(edgeDestination))
                        {
                            int cmp = pathWeight.CompareTo(weightAndDistance[edgeDestination].Key);
                            if (cmp > 0)
                            {
                                continue;
                            }
                            else if (cmp == 0)// if path is equal to an already computed path
                            {
                                // we continue with the next edge only if the distance is bigger or equal
                                if (curDistance + 1 >= weightAndDistance[edgeDestination].Value)
                                {
                                    continue;
                                }
                                // if the distance is smaller we update the path with this one
                            }
                        }

                        if (i == lastStep)// if we need to relax on the last iteration we have a negative cycle
                        {
                            return(false);
                        }

                        // Else we save the path
                        previousVertices[edgeDestination]  = new KeyValuePair <TVertex, TWeight>(edgeSource, edgeWeight);
                        weightAndDistance[edgeDestination] = new KeyValuePair <TWeight, int>(pathWeight, curDistance + 1);
                    }
                }
            }

            // Remove source vertex from weight and distance dictionary
            weightAndDistance.Remove(source);

            shortestPaths = new WeightedGraphShortestPaths <TVertex, TWeight>(source, previousVertices, weightAndDistance);
            return(true);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Uses Dijkstra's algorithm to compute the shortest paths in a weighted graph. Returns a <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> object containing the shortest paths.
        /// </summary>
        /// <typeparam name="TVertex">The data type of the vertices. TVertex implements <see cref="IComparable{T}"/>.</typeparam>
        /// <typeparam name="TWeight">The data type of weight of the edges. TWeight implements <see cref="IComparable{T}"/>.</typeparam>
        /// <param name="graph">The graph structure that implements <see cref="IWeightedGraph{TVertex, TWeight}"/>.</param>
        /// <param name="source">The source vertex for which the shortest paths are computed.</param>
        /// <param name="weightAdder">The method corresponding to the <see cref="AddWeights{TWeight}"/> delegate used for calculating the sum of two edge weights.</param>
        /// <returns>Returns a <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> containing the shortest paths for the given source vertex.</returns>
        public static WeightedGraphShortestPaths <TVertex, TWeight> DijkstraShortestPaths <TVertex, TWeight>(this IWeightedGraph <TVertex, TWeight> graph, TVertex source, AddWeights <TWeight> weightAdder)
            where TVertex : IComparable <TVertex>
            where TWeight : IComparable <TWeight>
        {
            if (!graph.ContainsVertex(source))
            {
                throw new ArgumentException("Vertex does not belong to the graph!");
            }

            // A dictionary holding a vertex as key and as value a key-value pair of its previous vertex in the path(being the key) and the weight of the edge connecting them(being the value).
            var previousVertices = new Dictionary <TVertex, KeyValuePair <TVertex, TWeight> >();
            // The dictionary holding a vertex as key and as value a key-value pair holding the weight of the path from the source vertex(being the key) and the distance from the source vertex(being the value).
            var weightAndDistance = new Dictionary <TVertex, KeyValuePair <TWeight, int> >();
            // Comparer for the key-value pair in the sorted set
            var kvpComparer = Comparer <KeyValuePair <TWeight, KeyValuePair <TVertex, int> > > .Create((x, y) =>
            {
                int cmp = 0;
                // null checking because TWeight can be null
                if (x.Key == null)
                {
                    if (y.Key == null)
                    {
                        cmp = -1;                // change cmp to skip next comparisons
                    }
                    else
                    {
                        return(int.MinValue);
                    }
                }

                if (cmp == 0)// if x.Key and y.Key are not null
                {
                    if (y.Key == null)
                    {
                        return(int.MaxValue);
                    }
                    // normal check if both weights are not null
                    cmp = x.Key.CompareTo(y.Key);
                }
                else
                {
                    cmp = 0; // if x.Key and y.Key were both null, compare the kvp value
                }
                if (cmp == 0)
                {
                    cmp = x.Value.Key.CompareTo(y.Value.Key);
                }
                if (cmp == 0)
                {
                    cmp = x.Value.Value.CompareTo(y.Value.Value);
                }
                return(cmp);
            });

            // Sorted set containing the vertices for computing. Having a kvp with the path weight as key and as value another kvp with the vertex as key and the distance from the source as value.
            var priorityQueue = new MinPriorityQueue <TWeight, KeyValuePair <TVertex, int> >(kvpComparer);

            // Add the source vertex
            priorityQueue.Enqueue(default(TWeight), new KeyValuePair <TVertex, int>(source, 0));

            while (priorityQueue.Count > 0)
            {
                var     curKVP      = priorityQueue.Dequeue();
                TWeight curWeight   = curKVP.Key;
                TVertex curVertex   = curKVP.Value.Key;
                int     curDistance = curKVP.Value.Value;

                foreach (var edge in graph.OutgoingEdgesSorted(curVertex))
                {
                    var edgeDestination = edge.Destination;
                    var edgeWeight      = edge.Weight;

                    // If the edge destination is the source we continue with the next edge
                    if (object.Equals(source, edgeDestination))
                    {
                        continue;
                    }

                    // Compute path weight
                    TWeight pathWeight;
                    if (curWeight == null)
                    {
                        pathWeight = edgeWeight;
                    }
                    else
                    {
                        pathWeight = weightAdder(curWeight, edgeWeight);
                    }

                    // If this path is longer than an already computed path we continue with the next edge
                    if (weightAndDistance.ContainsKey(edgeDestination))
                    {
                        int cmp = pathWeight.CompareTo(weightAndDistance[edgeDestination].Key);
                        if (cmp > 0)
                        {
                            continue;
                        }
                        else if (cmp == 0)// if path is equal to an already computed path
                        {
                            // we continue with the next edge only if the distance is bigger or equal
                            if (curDistance + 1 >= weightAndDistance[edgeDestination].Value)
                            {
                                continue;
                            }
                            // if the distance is smaller we update the path with this one
                        }
                    }

                    // Else we save the path
                    previousVertices[edgeDestination]  = new KeyValuePair <TVertex, TWeight>(curVertex, edgeWeight);
                    weightAndDistance[edgeDestination] = new KeyValuePair <TWeight, int>(pathWeight, curDistance + 1);

                    // Add the destination vertex for computing
                    priorityQueue.Enqueue(pathWeight, new KeyValuePair <TVertex, int>(edgeDestination, curDistance + 1));
                }
            }

            var shortestPaths = new WeightedGraphShortestPaths <TVertex, TWeight>(source, previousVertices, weightAndDistance);

            return(shortestPaths);
        }
        /// <summary>
        /// Uses Bellman-Ford's algorithm to compute the shortest paths in a weighted graph. Returns a <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> object containing the shortest paths.
        /// </summary>
        /// <typeparam name="TVertex">The data type of the vertices. TVertex implements <see cref="IComparable{T}"/>.</typeparam>
        /// <typeparam name="TWeight">The data type of weight of the edges. TWeight implements <see cref="IComparable{T}"/>.</typeparam>
        /// <param name="graph">The graph structure that implements <see cref="IWeightedGraph{TVertex, TWeight}"/>.</param>
        /// <param name="source">The source vertex for which the shortest paths are computed.</param>
        /// <param name="weightAdder">The method corresponding to the <see cref="AddWeights{TWeight}"/> delegate used for calculating the sum of two edge weights.</param>
        /// <returns>Returns a <see cref="WeightedGraphShortestPaths{TVertex, TWeight}"/> containing the shortest paths for the given source vertex.</returns>
        public static WeightedGraphShortestPaths <TVertex, TWeight> BellmanFordShortestPaths <TVertex, TWeight>(this IWeightedGraph <TVertex, TWeight> graph, TVertex source, AddWeights <TWeight> weightAdder)
            where TVertex : IComparable <TVertex>
            where TWeight : IComparable <TWeight>
        {
            if (!graph.ContainsVertex(source))
            {
                throw new ArgumentException("Vertex does not belong to the graph!");
            }

            WeightedGraphShortestPaths <TVertex, TWeight> shortestPaths;

            if (TryGetBellmanFordShortestPaths(graph, source, out shortestPaths, weightAdder))
            {
                return(shortestPaths);
            }
            else
            {
                throw new InvalidOperationException("Negative weight cycle found!");
            }
        }
Exemplo n.º 4
0
        public static int Test2()
        {
            AddWeights <int> f = (num, num1) => num * num1;

            return(f(10, 10));
        }