< Summary

Information
Class: MoreStructures.Graphs.ShortestDistanceTree.BellmanFordShortestDistanceTreeFinder
Assembly: MoreStructures
File(s): /home/runner/work/MoreStructures/MoreStructures/MoreStructures/Graphs/ShortestDistanceTree/BellmanFordShortestDistanceTreeFinder.cs
Line coverage
100%
Covered lines: 40
Uncovered lines: 0
Coverable lines: 40
Total lines: 120
Line coverage: 100%
Branch coverage
100%
Covered branches: 18
Total branches: 18
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
get_VisitStrategyBuilder()100%1100%
.ctor(...)100%1100%
FindTree(...)100%2100%
RelaxEdges(...)100%12100%
SetToMinusInfinity(...)100%4100%

File(s)

/home/runner/work/MoreStructures/MoreStructures/MoreStructures/Graphs/ShortestDistanceTree/BellmanFordShortestDistanceTreeFinder.cs

#LineLine coverage
 1using MoreStructures.Graphs.ShortestDistance;
 2using MoreStructures.Graphs.Visitor;
 3
 4namespace MoreStructures.Graphs.ShortestDistanceTree;
 5
 6/// <summary>
 7/// A <see cref="IShortestDistanceFinder"/> implementation based on the Bellman-Ford algorithm.
 8/// </summary>
 9/// <remarks>
 10///     <para id="requirements">
 11///     REQUIREMENTS
 12///     <br/>
 13///     - Same as <see cref="BellmanFordShortestDistanceFinder"/>.
 14///     </para>
 15///     <para id="algorithm">
 16///     ALGORITHM
 17///     <br/>
 18///     - The algorithm closely resembles the one used in <see cref="BellmanFordShortestDistanceFinder"/>, with the
 19///       only main difference that paths from the start vertex are reconstructed, since that would need to be done
 20///       for each of the vertices of the graph, resulting in a worst case O(v^2) Space Complexity.
 21///       <br/>
 22///     - Unlike <see cref="DijkstraShortestDistanceTreeFinder"/>, which can improve w.r.t.
 23///       <see cref="DijkstraShortestDistanceFinder"/> on the average runtime, while the worst case is still bound to
 24///       the total number of vertices in the graph, <see cref="BellmanFordShortestDistanceTreeFinder"/> cannot provide
 25///       the same average running time improvement over <see cref="BellmanFordShortestDistanceFinder"/>, since the
 26///       Bellman-Ford algorithm still requires v - 1 iterations to find optimal distances from the start vertex, and
 27///       one iteration more, to be able to identify negative cycles and set shortest distance to minus infinity, for
 28///       all vertices reachable from a negative cycle.
 29///     </para>
 30///     <para id="complexity">
 31///     COMPLEXITY
 32///     <br/>
 33///     - Same analysis as in <see cref="BellmanFordShortestDistanceFinder"/>.
 34///       <br/>
 35///     - The fact that the algorithm doesn't reconstruct shortest paths doesn't reduce the overall complexity, which
 36///       is bound to the v iterations of the main loop of the algorithm, each one relaxing at most e edges.
 37///       <br/>
 38///     - Therefore, as in single path Bellman-Ford's algorithm variant, Time Complexity is O(v * (v * Tn + e)) and
 39///       Space Complexity is O(v + Sn), where Tn and Sn are the time and space to retrieve the neighborhood of a
 40///       single vertex.
 41///     </para>
 42/// </remarks>
 43public class BellmanFordShortestDistanceTreeFinder : IShortestDistanceTreeFinder
 44{
 45    /// <summary>
 46    /// A building function able to instantiate the <see cref="IVisitStrategy"/> to be used to find all reachable
 47    /// vertices of vertices relaxed in the last iteration of the main loop of the Bellman-Ford algorithm, by running
 48    /// a Depth First Searches from the start vertex via
 49    /// <see cref="IVisitStrategy.DepthFirstSearchFromVertex(IGraph, int)"/>.
 50    /// </summary>
 37951    public Func<IVisitStrategy> VisitStrategyBuilder { get; }
 52
 53    /// <summary>
 54    ///     <inheritdoc cref="BellmanFordShortestDistanceTreeFinder"/>
 55    /// </summary>
 56    /// <param name="visitStrategyBuilder">
 57    ///     <inheritdoc cref="VisitStrategyBuilder" path="/summary"/>
 58    /// </param>
 59    /// <remarks>
 60    ///     <inheritdoc cref="BellmanFordShortestDistanceFinder"/>
 61    /// </remarks>
 37962    public BellmanFordShortestDistanceTreeFinder(Func<IVisitStrategy> visitStrategyBuilder)
 37963    {
 37964        VisitStrategyBuilder = visitStrategyBuilder;
 37965    }
 66
 67    /// <inheritdoc path="//*[not(self::remarks)]"/>
 68    /// <remarks>
 69    ///     <inheritdoc cref="BellmanFordShortestDistanceFinder"/>
 70    /// </remarks>
 71    public BestPreviouses FindTree(IGraph graph, IGraphDistances distances, int start)
 37972    {
 37973        ShortestDistanceFinderHelper.ValidateParameters(graph, start, null);
 74
 37975        var numberOfVertices = graph.GetNumberOfVertices();
 37976        var bestPreviouses = new BestPreviouses(new() { [start] = new(0, -1) });
 77
 37978        var verticesRelaxedInLastIteration = new HashSet<int>();
 747879        for (var iteration = 1; iteration <= numberOfVertices; iteration++)
 336080            RelaxEdges(graph, distances, numberOfVertices, bestPreviouses, iteration, verticesRelaxedInLastIteration);
 81
 37982        SetToMinusInfinity(graph, bestPreviouses, verticesRelaxedInLastIteration, VisitStrategyBuilder);
 37983        return bestPreviouses;
 37984    }
 85
 86    private static void RelaxEdges(
 87        IGraph graph, IGraphDistances distances, int numberOfVertices,
 88        BestPreviouses bestPreviouses, int iteration, HashSet<int> verticesRelaxedInLastIteration)
 336089    {
 7371290        for (var source = 0; source < numberOfVertices; source++)
 3349691        {
 18634892            foreach (var (target, edgeStart, edgeEnd) in graph.GetAdjacentVerticesAndEdges(source, true))
 4293093            {
 4293094                if (!bestPreviouses.Values.TryGetValue(source, out var sourceBest))
 2678195                    continue;
 96
 1614997                var newTargetDistance = sourceBest.DistanceFromStart + distances[(edgeStart, edgeEnd)];
 1614998                if (!bestPreviouses.Values.TryGetValue(target, out var targetBest) ||
 1614999                    targetBest.DistanceFromStart > newTargetDistance)
 2149100                {
 2149101                    if (iteration == numberOfVertices)
 33102                        verticesRelaxedInLastIteration.Add(target);
 103                    else
 2116104                        bestPreviouses.Values[target] = new(newTargetDistance, source);
 2149105                }
 16149106            }
 33496107        }
 3360108    }
 109
 110    private static void SetToMinusInfinity(IGraph graph, BestPreviouses bestPreviouses,
 111        HashSet<int> verticesRelaxedInLastIteration, Func<IVisitStrategy> visitStrategyBuilder)
 379112    {
 379113        if (verticesRelaxedInLastIteration.Count == 0)
 346114            return;
 115
 33116        var visitor = visitStrategyBuilder();
 287117        foreach (var reachableVertex in visitor.BreadthFirstSearchFromVertices(graph, verticesRelaxedInLastIteration))
 94118            bestPreviouses.Values[reachableVertex] = new(int.MinValue, -1);
 379119    }
 120}