Beispiel #1
0
        private void TestShortestPathsAlgorithm(IWeightedGraph <int, double> graph,
                                                IVertex <int> source,
                                                IVertex <int> target,
                                                double pathCosts,
                                                ShortestPathAlgorithm algorithm,
                                                double precision = 0.1)
        {
            IWeightedGraph <int, double> shortestPath = null;

            switch (algorithm)
            {
            case ShortestPathAlgorithm.Dijkstra:
                shortestPath = Dijkstra.FindShortestPath(graph, source, target, 0.0, double.MaxValue, (x, y) => x + y);
                break;

            case ShortestPathAlgorithm.BellmanFordMoore:
                shortestPath = BellmanFordMoore.FindShortestPath(graph, source, target, 0.0, double.MaxValue, (x, y) => x + y);
                break;

            default:
                throw new NotSupportedException($"Testing shortest path for the {algorithm} algorithm is currently not supported.");
            }
            AssertDoublesNearlyEqual(pathCosts, shortestPath.GetAllEdges().Sum(e => e.Weight), precision);
        }
Beispiel #2
0
        public static IWeightedGraph <TV, TW> FindCostMinimalFlow <TV, TW>(IWeightedGraph <TV, TW> graph,
                                                                           TV superSourceValue,
                                                                           TV superTargetValue,
                                                                           Func <TW, TW, TW> combineValues,
                                                                           Func <TW, TW, TW> substractValues,
                                                                           Func <TW, TW> negateValue,
                                                                           TW zeroValue,
                                                                           TW maxValue)
            where TV : IEquatable <TV> where TW : IComparable
        {
            // Build graph with super nodes
            IWeightedGraph <TV, TW> graphWithSuperNodes = BuildGraphWithSuperNodes(graph, superSourceValue, superTargetValue, negateValue);

            // Get max flow in graph with super nodes
            IWeightedGraph <TV, TW> maxFlow = EdmondsKarp.FindMaxFlow(graphWithSuperNodes,
                                                                      graphWithSuperNodes.GetFirstMatchingVertex(v => v.Value.Equals(superSourceValue)),
                                                                      graphWithSuperNodes.GetFirstMatchingVertex(v => v.Value.Equals(superTargetValue)),
                                                                      combineValues,
                                                                      substractValues,
                                                                      zeroValue);
            TW maxFlowValue = FlowValue(maxFlow, superSourceValue, combineValues, zeroValue);

            // Check for existance of a b-flow
            IEnumerable <IVertex <TV> > sources = graph.GetAllMatchingVerteces(v => v.GetAttribute <double>(Constants.BALANCE) > 0);
            IEnumerable <IVertex <TV> > targets = graph.GetAllMatchingVerteces(v => v.GetAttribute <double>(Constants.BALANCE) < 0);
            TW sourcesBalance = zeroValue;
            TW targetsBalance = zeroValue;

            foreach (IVertex <TV> source in sources)
            {
                sourcesBalance = combineValues(sourcesBalance, source.GetAttribute <TW>(Constants.BALANCE));
            }
            foreach (IVertex <TV> target in targets)
            {
                targetsBalance = combineValues(targetsBalance, target.GetAttribute <TW>(Constants.BALANCE));
            }
            if (maxFlowValue.Equals(sourcesBalance) &&
                maxFlowValue.Equals(negateValue(targetsBalance)))
            {
                // Copy flow values from graph with super nodes to original graph
                foreach (IWeightedEdge <TV, TW> edge in graphWithSuperNodes.GetAllEdges())
                {
                    if (edge is IWeightedDirectedEdge <TV, TW> directedEdge)
                    {
                        if (!directedEdge.OriginVertex.Value.Equals(superSourceValue) &&
                            !directedEdge.TargetVertex.Value.Equals(superTargetValue))
                        {
                            graph.GetEdgeBetweenVerteces(directedEdge.OriginVertex.Value, directedEdge.TargetVertex.Value)
                            .SetAttribute(Constants.FLOW, edge.GetAttribute <TW>(Constants.FLOW));
                        }
                    }
                    else
                    {
                        throw new GraphNotDirectedException();
                    }
                }

                bool modifyingCycleLeft;
                do
                {
                    // Build residual graph
                    IWeightedGraph <TV, TW> residualGraph = BuildResidualGraph(graph, substractValues, negateValue, zeroValue);

                    // Prepare graph for BellmanFordMoore
                    IWeightedGraph <TV, TW> bfmGraph = BuildGraphForBellmanFordMoore(residualGraph, superSourceValue, zeroValue);

                    // Attempt to find modifying cycle
                    IVertex <TV> bfmSuperSource = bfmGraph.GetFirstMatchingVertex(v => v.Value.Equals(superSourceValue));
                    if (modifyingCycleLeft = BellmanFordMoore.TryFindNegativeCycle(bfmGraph,
                                                                                   bfmSuperSource,
                                                                                   zeroValue,
                                                                                   maxValue,
                                                                                   combineValues,
                                                                                   out IEnumerable <IWeightedDirectedEdge <TV, TW> > cycle))
                    {
                        // Get minimum capacity of the cycle in the residual graph
                        List <IWeightedDirectedEdge <TV, TW> > rgCycle = new List <IWeightedDirectedEdge <TV, TW> >();
                        foreach (IWeightedDirectedEdge <TV, TW> edge in cycle)
                        {
                            rgCycle.Add((IWeightedDirectedEdge <TV, TW>)residualGraph.GetEdgeBetweenVerteces(edge.OriginVertex.Value, edge.TargetVertex.Value));
                        }
                        TW minCycleCapacity = rgCycle.Min(e => e.Weight);

                        // Modify b-flow along cycle
                        foreach (IWeightedDirectedEdge <TV, TW> edge in rgCycle)
                        {
                            if (edge.GetAttribute <EdgeDirection>(Constants.DIRECTION) == EdgeDirection.Forward)
                            {
                                IWeightedDirectedEdge <TV, TW> graphEdge = (IWeightedDirectedEdge <TV, TW>)graph.GetEdgeBetweenVerteces(edge.OriginVertex.Value, edge.TargetVertex.Value);
                                graphEdge.SetAttribute(Constants.FLOW, combineValues(graphEdge.GetAttribute <TW>(Constants.FLOW), minCycleCapacity));
                            }
                            else
                            {
                                IWeightedDirectedEdge <TV, TW> graphEdge = (IWeightedDirectedEdge <TV, TW>)graph.GetEdgeBetweenVerteces(edge.TargetVertex.Value, edge.OriginVertex.Value);
                                graphEdge.SetAttribute(Constants.FLOW, substractValues(graphEdge.GetAttribute <TW>(Constants.FLOW), minCycleCapacity));
                            }
                        }
                    }
                }while (modifyingCycleLeft);

                // Return same graph
                return(graph);
            }
            else
            {
                throw new NoBFlowException();
            }
        }
Beispiel #3
0
        public static IWeightedGraph <TV, TW> FindCostMinimalFlow <TV, TW>(IWeightedGraph <TV, TW> graph,
                                                                           TV superSourceValue,
                                                                           TV superTargetValue,
                                                                           Func <TW, TW, TW> combineValues,
                                                                           Func <TW, TW, TW> substractValues,
                                                                           Func <TW, TW> negateValue,
                                                                           TW zeroValue,
                                                                           TW maxValue)
            where TV : IEquatable <TV> where TW : IComparable
        {
            // Add initial flow values to all graph edges: 0 or maximum edge capacity for edges with negative costs
            foreach (IWeightedEdge <TV, TW> edge in graph.GetAllEdges())
            {
                if (edge.GetAttribute <TW>(Constants.COSTS).CompareTo(zeroValue) < 0)
                {
                    edge.SetAttribute(Constants.FLOW, edge.Weight);
                }
                else
                {
                    edge.SetAttribute(Constants.FLOW, zeroValue);
                }
            }

            // Set pseudo-balances and track pseudo-nodes
            List <IVertex <TV> > pseudoSources = new List <IVertex <TV> >();
            List <IVertex <TV> > pseudoTargets = new List <IVertex <TV> >();

            foreach (IVertex <TV> vertex in graph.GetAllVerteces())
            {
                // Compute pseudo balances
                UpdatePseudoBalance(graph, vertex, combineValues, substractValues, zeroValue);

                // Track pseudo-sources and pseudo-targets
                if (vertex.GetAttribute <TW>(Constants.BALANCE).CompareTo(vertex.GetAttribute <TW>(Constants.PSEUDO_BALANCE)) > 0)
                {
                    pseudoSources.Add(vertex);
                }
                else if (vertex.GetAttribute <TW>(Constants.BALANCE).CompareTo(vertex.GetAttribute <TW>(Constants.PSEUDO_BALANCE)) < 0)
                {
                    pseudoTargets.Add(vertex);
                }
            }

            while (pseudoSources.Any() && pseudoTargets.Any())
            {
                // Build residual graph
                IWeightedGraph <TV, TW> residualGraph = CycleCanceling.BuildResidualGraph(graph, substractValues, negateValue, zeroValue);

                // Select pseudo-source
                IVertex <TV> pseudoSource = pseudoSources.First();

                // Attempt to find a pseudo-target reachable from the pseudo-source in the residual graph
                IVertex <TV>            pseudoTarget = null;
                IWeightedGraph <TV, TW> pathToTarget = null;
                foreach (IVertex <TV> currentPseudoTarget in pseudoTargets)
                {
                    try
                    {
                        IWeightedGraph <TV, TW> bfmGraph            = BuildGraphForBellmanFordMoore(residualGraph);
                        IVertex <TV>            bfmSource           = bfmGraph.GetFirstMatchingVertex(v => v.Value.Equals(pseudoSource.Value));
                        IVertex <TV>            bfmTarget           = bfmGraph.GetFirstMatchingVertex(v => v.Value.Equals(currentPseudoTarget.Value));
                        IWeightedGraph <TV, TW> pathToCurrentTarget = BellmanFordMoore.FindShortestPath(bfmGraph, bfmSource, bfmTarget, zeroValue, maxValue, combineValues);
                        if (pathToCurrentTarget != null)
                        {
                            pseudoTarget = currentPseudoTarget;
                            pathToTarget = pathToCurrentTarget;
                            break;
                        }
                    }
                    catch (Exception) { /* silent */ }
                }

                // Abort if no pair of reachable pseudo-nodes was found
                if (pseudoTarget == null)
                {
                    break;
                }

                // Determine max possible augmenting flow value
                TW minPathCapacity = maxValue;
                foreach (IWeightedEdge <TV, TW> edge in pathToTarget.GetAllEdges())
                {
                    if (edge is IWeightedDirectedEdge <TV, TW> directedEdge)
                    {
                        IWeightedEdge <TV, TW> residualEdge = residualGraph.GetEdgeBetweenVerteces(directedEdge.OriginVertex.Value, directedEdge.TargetVertex.Value);
                        minPathCapacity = MinValue(new TW[] { minPathCapacity, residualEdge.Weight });
                    }
                    else
                    {
                        throw new GraphNotDirectedException();
                    }
                }
                TW sourceRestBalance = substractValues(pseudoSource.GetAttribute <TW>(Constants.BALANCE), pseudoSource.GetAttribute <TW>(Constants.PSEUDO_BALANCE));
                TW targetRestBalance = substractValues(pseudoTarget.GetAttribute <TW>(Constants.PSEUDO_BALANCE), pseudoTarget.GetAttribute <TW>(Constants.BALANCE));
                TW augmentingFlow    = MinValue(new TW[] { minPathCapacity, sourceRestBalance, targetRestBalance });

                // Update b-flow in original graph
                foreach (IWeightedEdge <TV, TW> edge in pathToTarget.GetAllEdges())
                {
                    if (edge is IWeightedDirectedEdge <TV, TW> directedEdge)
                    {
                        IWeightedEdge <TV, TW> residualEdge = residualGraph.GetEdgeBetweenVerteces(directedEdge.OriginVertex.Value, directedEdge.TargetVertex.Value);
                        if (residualEdge.GetAttribute <EdgeDirection>(Constants.DIRECTION) == EdgeDirection.Forward)
                        {
                            IWeightedEdge <TV, TW> graphEdge = graph.GetEdgeBetweenVerteces(directedEdge.OriginVertex.Value, directedEdge.TargetVertex.Value);
                            graphEdge.SetAttribute(Constants.FLOW, combineValues(graphEdge.GetAttribute <TW>(Constants.FLOW), augmentingFlow));
                        }
                        else
                        {
                            IWeightedEdge <TV, TW> graphEdge = graph.GetEdgeBetweenVerteces(directedEdge.TargetVertex.Value, directedEdge.OriginVertex.Value);
                            graphEdge.SetAttribute(Constants.FLOW, substractValues(graphEdge.GetAttribute <TW>(Constants.FLOW), augmentingFlow));
                        }
                    }
                    else
                    {
                        throw new GraphNotDirectedException();
                    }
                }

                // Remove pseudo-nodes (from tracking) if they will have their balance satisfied
                if (augmentingFlow.Equals(sourceRestBalance))
                {
                    pseudoSources.Remove(pseudoSource);
                }
                if (augmentingFlow.Equals(targetRestBalance))
                {
                    pseudoTargets.Remove(pseudoTarget);
                }

                // Update pseudo-balances of used pseudo-source and pseudo-target
                UpdatePseudoBalance(graph, pseudoSource, combineValues, substractValues, zeroValue);
                UpdatePseudoBalance(graph, pseudoTarget, combineValues, substractValues, zeroValue);
            }

            // Check balances
            if (!graph.GetAllVerteces().All(v => v.GetAttribute <TW>(Constants.BALANCE).Equals(v.GetAttribute <TW>(Constants.PSEUDO_BALANCE))))
            {
                throw new NoBFlowException();
            }

            // If we reach this, a valid b-flow was found!
            return(graph);
        }