/3.0/sources/QuickGraph/Algorithms/ShortestPath/BellmanFordShortestPathAlgorithm.cs
C# | 248 lines | 146 code | 25 blank | 77 comment | 16 complexity | 3e1b7239aaba7bbc3e71412ba8cdb688 MD5 | raw file
- using System;
- using System.Collections.Generic;
- using QuickGraph.Algorithms.Services;
-
- namespace QuickGraph.Algorithms.ShortestPath
- {
- /// <summary>
- /// Bellman Ford shortest path algorithm.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The Bellman-Ford algorithm solves the single-source shortest paths
- /// problem for a graph with both positive and negative edge weights.
- /// </para>
- /// <para>
- /// If you only need to solve the shortest paths problem for positive
- /// edge weights, Dijkstra's algorithm provides a more efficient
- /// alternative.
- /// </para>
- /// <para>
- /// If all the edge weights are all equal to one then breadth-first search
- /// provides an even more efficient alternative.
- /// </para>
- /// </remarks>
- /// <reference-ref
- /// idref="shi03datastructures"
- /// />
- public sealed class BellmanFordShortestPathAlgorithm<TVertex, TEdge>
- : ShortestPathAlgorithmBase<TVertex,TEdge
- , IVertexAndEdgeListGraph<TVertex,TEdge>>
- , ITreeBuilderAlgorithm<TVertex, TEdge>
- where TEdge : IEdge<TVertex>
- {
- private readonly Dictionary<TVertex,TVertex> predecessors;
- private bool foundNegativeCycle;
-
- public BellmanFordShortestPathAlgorithm(
- IVertexAndEdgeListGraph<TVertex, TEdge> visitedGraph,
- Func<TEdge, double> weights
- )
- : this(visitedGraph, weights, DistanceRelaxers.ShortestDistance)
- { }
-
- public BellmanFordShortestPathAlgorithm(
- IVertexAndEdgeListGraph<TVertex, TEdge> visitedGraph,
- Func<TEdge, double> weights,
- IDistanceRelaxer distanceRelaxer
- )
- : this(null, visitedGraph, weights, distanceRelaxer)
- { }
-
- public BellmanFordShortestPathAlgorithm(
- IAlgorithmComponent host,
- IVertexAndEdgeListGraph<TVertex,TEdge> visitedGraph,
- Func<TEdge,double> weights,
- IDistanceRelaxer distanceRelaxer
- )
- :base(host, visitedGraph, weights, distanceRelaxer)
- {
- this.predecessors = new Dictionary<TVertex,TVertex>();
- }
-
- public bool FoundNegativeCycle
- {
- get { return this.foundNegativeCycle;}
- }
-
- /// <summary>
- /// Invoked on each vertex in the graph before the start of the
- /// algorithm.
- /// </summary>
- public event VertexAction<TVertex> InitializeVertex;
-
- /// <summary>
- /// Raises the <see cref="InitializeVertex"/> event.
- /// </summary>
- /// <param name="v">vertex that raised the event</param>
- private void OnInitializeVertex(TVertex v)
- {
- var eh = this.InitializeVertex;
- if (eh != null)
- eh(v);
- }
-
- /// <summary>
- /// Invoked on every edge in the graph |V| times.
- /// </summary>
- public event EdgeAction<TVertex,TEdge> ExamineEdge;
-
- /// <summary>
- /// Raises the <see cref="ExamineEdge"/> event.
- /// </summary>
- /// <param name="e">edge that raised the event</param>
- private void OnExamineEdge(TEdge e)
- {
- var eh = this.ExamineEdge;
- if (eh != null)
- eh(e);
- }
-
- /// <summary>
- /// Invoked if the distance label for the target vertex is not
- /// decreased.
- /// </summary>
- public event EdgeAction<TVertex,TEdge> EdgeNotRelaxed;
-
- /// <summary>
- /// Raises the <see cref="EdgeNotRelaxed"/> event.
- /// </summary>
- /// <param name="e">edge that raised the event</param>
- private void OnEdgeNotRelaxed(TEdge e)
- {
- var eh = this.EdgeNotRelaxed;
- if (eh != null)
- eh(e);
- }
-
- /// <summary>
- /// Invoked during the second stage of the algorithm,
- /// during the test of whether each edge was minimized.
- ///
- /// If the edge is minimized then this function is invoked.
- /// </summary>
- public event EdgeAction<TVertex,TEdge> EdgeMinimized;
-
-
- /// <summary>
- /// Raises the <see cref="EdgeMinimized"/> event.
- /// </summary>
- /// <param name="e">edge that raised the event</param>
- private void OnEdgeMinimized(TEdge e)
- {
- var eh = this.EdgeMinimized;
- if (eh != null)
- eh(e);
- }
-
- /// <summary>
- /// Invoked during the second stage of the algorithm,
- /// during the test of whether each edge was minimized.
- ///
- /// If the edge was not minimized, this function is invoked.
- /// This happens when there is a negative cycle in the graph.
- /// </summary>
- public event EdgeAction<TVertex,TEdge> EdgeNotMinimized;
-
-
- /// <summary>
- /// Raises the <see cref="EdgeNotMinimized"/> event.
- /// </summary>
- /// <param name="e">edge that raised the event</param>
- private void OnEdgeNotMinimized(TEdge e)
- {
- var eh = this.EdgeNotMinimized;
- if (eh != null)
- eh(e);
- }
-
- /// <summary>
- /// Constructed predecessor map
- /// </summary>
- public IDictionary<TVertex,TVertex> Predecessors
- {
- get
- {
- return predecessors;
- }
- }
-
- protected override void Initialize()
- {
- base.Initialize();
-
- this.foundNegativeCycle = false;
- // init color, distance
- this.VertexColors.Clear();
- foreach (var u in VisitedGraph.Vertices)
- {
- this.VertexColors[u] = GraphColor.White;
- this.Distances[u] = double.PositiveInfinity;
- this.OnInitializeVertex(u);
- }
-
- TVertex root;
- if (!this.TryGetRootVertex(out root))
- foreach (var v in this.VisitedGraph.Vertices)
- {
- root = v;
- break;
- }
-
- this.Distances[root] = 0;
- }
-
- /// <summary>
- /// Applies the Bellman Ford algorithm
- /// </summary>
- /// <remarks>
- /// Does not initialize the predecessor and distance map.
- /// </remarks>
- /// <returns>true if successful, false if there was a negative cycle.</returns>
- protected override void InternalCompute()
- {
- // getting the number of
- int N = this.VisitedGraph.VertexCount;
- for (int k = 0; k < N; ++k)
- {
- bool atLeastOneTreeEdge = false;
- foreach (var e in this.VisitedGraph.Edges)
- {
- this.OnExamineEdge(e);
-
- if (Relax(e))
- {
- atLeastOneTreeEdge = true;
- OnTreeEdge(e);
- }
- else
- this.OnEdgeNotRelaxed(e);
- }
- if (!atLeastOneTreeEdge)
- break;
- }
-
- var relaxer = this.DistanceRelaxer;
- foreach (var e in this.VisitedGraph.Edges)
- {
- var edgeWeight = Weights(e);
- if (edgeWeight < 0)
- throw new InvalidOperationException("non negative edge weight");
- if (relaxer.Compare(
- relaxer.Combine(
- this.Distances[e.Source], edgeWeight),
- this.Distances[e.Target]
- ) < 0
- )
- {
- this.OnEdgeMinimized(e);
- this.foundNegativeCycle = true;
- return;
- }
- else
- this.OnEdgeNotMinimized(e);
- }
- this.foundNegativeCycle = false;
- }
- }
- }