/// <summary>Bellman-Ford algorithm.</summary>
        /// <param name="graph">The directed weighted graph.</param>
        /// <param name="source">The source vertex.</param>
        /// <returns>Dictionary of distances for vertices.</returns>
        /// <exception cref="InvalidOperationException">If graph contains a negative cycle.</exception>
        public static Dictionary <Vertex <TVertexId>, double> BellmanFord <TVertexId, TVertexProperty, TEdgeProperty>(
            IDirectedGraph <TVertexId, TVertexProperty, TEdgeProperty> graph, Vertex <TVertexId> source)
            where TEdgeProperty : IWeighted
        {
            var distances = new Dictionary <Vertex <TVertexId>, double>(
                graph.Vertices.Select(v => KeyValuePair.Create(v, IWeighted.Infinity)))
            {
                [source] = 0.0
            };

            for (int i = 0; i < graph.VerticesCount - 1; ++i)
            {
                foreach (Vertex <TVertexId> vertex in graph.Vertices)
                {
                    foreach (Edge <TVertexId> edge in graph.GetAdjacentEdges(vertex))
                    {
                        distances[edge.Destination] = Math.Min(distances[edge.Destination],
                                                               distances[vertex] + graph.Properties[edge].Weight);
                    }
                }
            }

            foreach (Vertex <TVertexId> vertex in graph.Vertices)
            {
                foreach (Edge <TVertexId> edge in graph.GetAdjacentEdges(vertex))
                {
                    if (distances[vertex] < IWeighted.Infinity &&
                        distances[vertex] + graph.Properties[edge].Weight < distances[edge.Destination])
                    {
                        throw new InvalidOperationException("Graph contains a cycle with negative weight");
                    }
                }
            }

            return(distances);
        }