示例#1
0
        public static IWeightedGraph <TV, TW> FindTour <TV, TW>(IWeightedGraph <TV, TW> graph, IVertex <TV> source) where TV : IEquatable <TV>
        {
            GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>();

            // Starting point
            IVertex <TV> currentVertex = source;

            builder.AddVertex(source.Value);

            // Track which verteces have already been added to the tour, and how many edges have already been used
            HashSet <TV> visitedVerteces = new HashSet <TV>()
            {
                source.Value
            };
            int edgesUsed = 0;

            // Find and use minimum non-used edge leading from each vertex
            while (edgesUsed < graph.VertexCount)
            {
                // Last edge, select edge back to start
                if (edgesUsed == graph.VertexCount - 1)
                {
                    try
                    {
                        IWeightedEdge <TV, TW> closingEdge = graph.GetEdgeBetweenVerteces(currentVertex, source);
                        builder.AddEdge(currentVertex.Value, source.Value, closingEdge.Weight);
                    }
                    catch (VertecesNotConnectedException <TV> exception)
                    {
                        throw new GraphNotCompleteException("The NearestNeighbor algorithm expects the input graph to be complete!", exception);
                    }
                }
                else
                {
                    IWeightedEdge <TV, TW> minEdge = graph.GetEdgesOfVertex(currentVertex)
                                                     .Where(e => !visitedVerteces.Contains(e.ConnectedVertex(currentVertex).Value))
                                                     .OrderBy(e => e.Weight)
                                                     .FirstOrDefault();
                    if (minEdge == null)
                    {
                        throw new GraphNotCompleteException("The NearestNeighbor algorithm expects the input graph to be complete!");
                    }

                    // Get target vertex and update current vertex
                    IVertex <TV> target = minEdge.ConnectedVertex(currentVertex);
                    currentVertex = target;

                    // Update tracking
                    visitedVerteces.Add(target.Value);

                    // Update result graph
                    builder.AddVertex(target.Value);
                    builder.AddEdge(source.Value, target.Value, minEdge.Weight);
                }
                edgesUsed++;
            }

            // Done: used n-1 edges for n verteces
            return(builder.Build());
        }
示例#2
0
 private static void RelaxEdge <TV, TW>(Dictionary <IVertex <TV>, TW> distanceMap,
                                        Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> > predecessor,
                                        IVertex <TV> sourceVertex,
                                        IVertex <TV> targetVertex,
                                        TW weight,
                                        IWeightedEdge <TV, TW> edge,
                                        Func <TW, TW, TW> combineCosts)
     where TV : IEquatable <TV> where TW : IComparable
 {
     if (combineCosts(distanceMap[sourceVertex], weight).CompareTo(distanceMap[targetVertex]) < 0)
     {
         distanceMap[targetVertex] = combineCosts(distanceMap[sourceVertex], weight);
         predecessor[targetVertex] = edge;
     }
 }
示例#3
0
        public static IWeightedGraph <TV, TW> FindTour <TV, TW>(IWeightedGraph <TV, TW> graph) where TV : IEquatable <TV>
        {
            GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>();

            builder.AddVerteces(graph.GetAllVerteces().Select(v => v.Value));

            // Find minimum spanning tree
            IWeightedGraph <TV, TW> msp = Kruskal.FindMinimumSpanningTree(graph);

            // Connect verteces in the order of the MSP
            IVertex <TV> lastVertex = null;

            DepthFirstSearch.Traverse(msp, currentVertex =>
            {
                if (lastVertex != null)
                {
                    try
                    {
                        builder.AddEdge(lastVertex.Value, currentVertex.Value, graph.GetEdgeBetweenVerteces(lastVertex.Value, currentVertex.Value).Weight);
                    }
                    catch (VertecesNotConnectedException <TV> exception)
                    {
                        throw new GraphNotCompleteException("The graph is not complete.", exception);
                    }
                }
                lastVertex = currentVertex;
            });

            // Add closing edge
            IVertex <TV>           firstVertex = msp.GetFirstVertex();
            IWeightedEdge <TV, TW> closingEdge = graph.GetEdgeBetweenVerteces(lastVertex.Value, firstVertex.Value);

            builder.AddEdge(lastVertex.Value, firstVertex.Value, closingEdge.Weight);

            // Done!
            return(builder.Build());
        }
示例#4
0
        public static IWeightedGraph <TV, TW> FindShortestPath <TV, TW>(IWeightedGraph <TV, TW> graph,
                                                                        IVertex <TV> source,
                                                                        IVertex <TV> target,
                                                                        TW zeroValue,
                                                                        TW maxValue,
                                                                        Func <TW, TW, TW> combineCosts) where TV : IEquatable <TV> where TW : IComparable
        {
            HashSet <IVertex <TV> >           visitedVerteces = new HashSet <IVertex <TV> >();
            IPriorityQueue <IVertex <TV>, TW> vertecesToVisit = new NaivePriorityQueue <IVertex <TV>, TW>();
            Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> > predecessor = new Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> >();

            // Initialize queue and predecessor map
            foreach (IVertex <TV> vertex in graph.GetAllVerteces())
            {
                vertecesToVisit.Enqueue(vertex, maxValue);
                predecessor.Add(vertex, null);
            }
            vertecesToVisit.UpdatePriority(source, zeroValue);

            // Continue as long as there are verteces to visit
            IVertex <TV> currentVertex = null;
            TW           currentCosts  = zeroValue;

            while (!vertecesToVisit.Empty)
            {
                // Get the closest next vertex
                (currentVertex, currentCosts) = vertecesToVisit.Dequeue();

                // Check whether we reached our target
                if (currentVertex == target)
                {
                    break;
                }
                visitedVerteces.Add(currentVertex);

                // If not, discover the next verteces that can be visited
                foreach (IWeightedEdge <TV, TW> edge in graph.GetEdgesOfVertex(currentVertex))
                {
                    if (edge.Weight.CompareTo(zeroValue) < 0)
                    {
                        throw new NegativeEdgeWeightException();
                    }
                    IVertex <TV> connectedVertex = edge.ConnectedVertex(currentVertex);
                    if (!visitedVerteces.Contains(connectedVertex))
                    {
                        TW newCosts = combineCosts(currentCosts, edge.Weight);
                        if (newCosts.CompareTo(vertecesToVisit.GetPriorityOf(connectedVertex)) < 0)
                        {
                            vertecesToVisit.UpdatePriority(connectedVertex, newCosts);
                            predecessor[connectedVertex] = edge;
                        }
                    }
                }
            }

            // If we reached the target vertex, build result graph
            if (currentVertex == target)
            {
                GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>(true).AddVertex(target.Value);
                while (currentVertex != source)
                {
                    IWeightedEdge <TV, TW> pathEdge       = predecessor[currentVertex];
                    IVertex <TV>           previousVertex = pathEdge.ConnectedVertex(currentVertex);
                    builder
                    .AddVertex(previousVertex.Value)
                    .AddEdge(previousVertex.Value, currentVertex.Value, pathEdge.Weight);
                    currentVertex = previousVertex;
                }
                return(builder.Build());
            }
            else
            {
                throw new VertexNotReachableException <TV>(target);
            }
        }
示例#5
0
        public static IWeightedGraph <TV, TW> FindShortestPath <TV, TW>(IWeightedGraph <TV, TW> graph,
                                                                        IVertex <TV> source,
                                                                        IVertex <TV> target,
                                                                        TW zeroValue,
                                                                        TW maxValue,
                                                                        Func <TW, TW, TW> combineCosts) where TV : IEquatable <TV> where TW : IComparable
        {
            Dictionary <IVertex <TV>, TW> distance = new Dictionary <IVertex <TV>, TW>();
            Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> > predecessor = new Dictionary <IVertex <TV>, IWeightedEdge <TV, TW> >();

            // Initialize distance and predecessor maps
            foreach (IVertex <TV> vertex in graph.GetAllVerteces())
            {
                distance.Add(vertex, maxValue);
                predecessor.Add(vertex, null);
            }
            distance[source] = zeroValue;

            // Relax edges repeatedly
            IEnumerable <IWeightedEdge <TV, TW> > edges = graph.GetAllEdges();

            for (int i = 0; i < graph.VertexCount - 1; i++)
            {
                foreach (IWeightedEdge <TV, TW> edge in edges)
                {
                    if (graph.IsDirected)
                    {
                        try
                        {
                            IWeightedDirectedEdge <TV, TW> directedEdge = (IWeightedDirectedEdge <TV, TW>)edge;
                            RelaxEdge(distance, predecessor, directedEdge.OriginVertex, directedEdge.TargetVertex, directedEdge.Weight, directedEdge, combineCosts);
                        }
                        catch
                        {
                            throw new Exception("Failed casting edge to directed edge for directed graph.");
                        }
                    }
                    else
                    {
                        IVertex <TV> sourceVertex = edge.Verteces.First();
                        IVertex <TV> targetVertex = edge.ConnectedVertex(sourceVertex);
                        RelaxEdge(distance, predecessor, sourceVertex, targetVertex, edge.Weight, edge, combineCosts);
                        RelaxEdge(distance, predecessor, targetVertex, sourceVertex, edge.Weight, edge, combineCosts);
                    }
                }
            }

            // Check for negative - weight cycles
            foreach (IWeightedEdge <TV, TW> edge in graph.GetAllEdges())
            {
                if (graph.IsDirected)
                {
                    IWeightedDirectedEdge <TV, TW> directedEdge = (IWeightedDirectedEdge <TV, TW>)edge;
                    CheckForNegativeCycles(distance, directedEdge.OriginVertex, directedEdge.TargetVertex, directedEdge.Weight, combineCosts);
                }
                else
                {
                    IVertex <TV> sourceVertex = edge.Verteces.First();
                    IVertex <TV> targetVertex = edge.ConnectedVertex(sourceVertex);
                    CheckForNegativeCycles(distance, sourceVertex, targetVertex, edge.Weight, combineCosts);
                    CheckForNegativeCycles(distance, targetVertex, sourceVertex, edge.Weight, combineCosts);
                }
            }

            // Build and output path
            IVertex <TV>          currentVertex = target;
            GraphBuilder <TV, TW> builder       = new GraphBuilder <TV, TW>(true).AddVertex(target.Value);

            while (currentVertex != source)
            {
                IWeightedEdge <TV, TW> pathEdge       = predecessor[currentVertex];
                IVertex <TV>           previousVertex = pathEdge.ConnectedVertex(currentVertex);
                builder
                .AddVertex(previousVertex.Value)
                .AddEdge(previousVertex.Value, currentVertex.Value, pathEdge.Weight);
                currentVertex = previousVertex;
            }
            return(builder.Build());
        }
示例#6
0
        /// <summary>
        /// Builds the minimum spanning tree of a given graph.
        /// </summary>
        /// <typeparam name="TV">Type of the graph vertex values.</typeparam>
        /// <typeparam name="TW">Type of the graph edge weights.</typeparam>
        /// <param name="graph">The graph got which to build the minimum spanning tree.</param>
        /// <returns>Returns the minimum spanning tree of the given graph.</returns>
        public static IWeightedGraph <TV, TW> FindMinimumSpanningTree <TV, TW>(IWeightedGraph <TV, TW> graph, TW min, TW max)
            where TV : IEquatable <TV>
            where TW : IComparable
        {
            // Builder used to incrementally build the target minimum spanning tree
            GraphBuilder <TV, TW> builder = new GraphBuilder <TV, TW>();

            // Get all verteces and edges of graph
            IEnumerable <IVertex <TV> >           verteces = graph.GetAllVerteces();
            IEnumerable <IWeightedEdge <TV, TW> > edges    = graph.GetAllEdges();

            // TODO: replace with more performant priority queue implementation
            // Track minimum known cost to connect to target vertex
            IPriorityQueue <TV, TW> vertexCosts = new NaivePriorityQueue <TV, TW>();

            // Track target vertex and edge connecting to target vertex with minimum known cost
            Dictionary <TV, IVertex <TV> >           vertexValue = new Dictionary <TV, IVertex <TV> >();
            Dictionary <TV, IWeightedEdge <TV, TW> > vertexEdges = new Dictionary <TV, IWeightedEdge <TV, TW> >();

            // Initialize vertex costs with all costs set to max
            foreach (IVertex <TV> vertex in verteces)
            {
                vertexCosts.Enqueue(vertex.Value, max);
                vertexValue.Add(vertex.Value, vertex);
                vertexEdges.Add(vertex.Value, null);
            }

            // Set starting vertex
            vertexCosts.UpdatePriority(verteces.First().Value, min);

            // While there are verteces left to add, select vertex with smallest cost
            while (!vertexCosts.Empty)
            {
                // Get and remove vertex with smallest cost
                TV minCost = vertexCosts.Dequeue().Item1;

                // For easier handling, get vertex and edge
                IVertex <TV>           vertex = vertexValue[minCost];
                IWeightedEdge <TV, TW> edge   = vertexEdges[minCost];

                // Add vertex and edge to target MST
                builder.AddVertex(vertex.Value);
                if (edge != null)
                {
                    builder.AddEdge(vertex.Value, edge.ConnectedVertex(vertex.Value).Value, edge.Weight);
                }

                // Update vertex cost for adjacent verteces and store edges
                foreach (IWeightedEdge <TV, TW> connectedEdge in graph.GetEdgesOfVertex(vertex))
                {
                    // Ignore edges leading to verteces already added to the MST
                    IVertex <TV> targetVertex = connectedEdge.ConnectedVertex(vertex);
                    if (vertexCosts.Contains(targetVertex.Value) &&
                        connectedEdge.Weight.CompareTo(vertexCosts.GetPriorityOf(targetVertex.Value)) < 0)
                    {
                        vertexCosts.UpdatePriority(targetVertex.Value, connectedEdge.Weight);
                        vertexEdges[targetVertex.Value] = connectedEdge;
                    }
                }
            }

            // All verteces added to MST - done!
            return(builder.Build());
        }
示例#7
0
        private static void RecursivelyTryAllTours <TV, TW>(IWeightedGraph <TV, TW> graph,
                                                            IVertex <TV> currentVertex,
                                                            IVertex <TV> startingVertex,
                                                            TW currentCosts,
                                                            HashSet <IVertex <TV> > visitedVerteces,
                                                            HashSet <IWeightedEdge <TV, TW> > usedEdges,
                                                            ref HashSet <IWeightedEdge <TV, TW> > minTour,
                                                            ref TW minCosts,
                                                            Func <TW, TW, TW> combineCosts) where TV : IEquatable <TV> where TW : IComparable
        {
            // Check whether we can complete a tour
            if (usedEdges.Count == graph.VertexCount - 1)
            {
                try
                {
                    // Add closing edge to complete tour
                    IWeightedEdge <TV, TW> closingEdge = graph.GetEdgeBetweenVerteces(currentVertex, startingVertex);
                    usedEdges.Add(closingEdge);

                    // Check tour costs and compare to current min tour/costs
                    TW tourCosts = combineCosts(currentCosts, closingEdge.Weight);
                    if (tourCosts.CompareTo(minCosts) < 0)
                    {
                        minTour  = new HashSet <IWeightedEdge <TV, TW> >(usedEdges);
                        minCosts = tourCosts;
                    }

                    // Pop closing edge
                    usedEdges.Remove(closingEdge);
                }
                catch (VertecesNotConnectedException <TV> exception)
                {
                    throw new GraphNotCompleteException("The graph is not complete!", exception);
                }
            }
            // Continue building tours using connected verteces
            else
            {
                visitedVerteces.Add(currentVertex);

                // Check all connected verteces
                foreach (IWeightedEdge <TV, TW> edge in graph.GetEdgesOfVertex(currentVertex))
                {
                    IVertex <TV> targetVertex = edge.ConnectedVertex(currentVertex);
                    if (!visitedVerteces.Contains(targetVertex))
                    {
                        usedEdges.Add(edge);

                        // Comput new tour costs and branch and bound
                        TW newCosts = combineCosts(currentCosts, edge.Weight);
                        if (newCosts.CompareTo(minCosts) < 0)
                        {
                            RecursivelyTryAllTours(graph, targetVertex, startingVertex, newCosts, visitedVerteces, usedEdges, ref minTour, ref minCosts, combineCosts);
                        }

                        // Pop last edge on the way up
                        usedEdges.Remove(edge);
                    }
                }

                // Pop last vertex on the way up
                visitedVerteces.Remove(currentVertex);
            }
        }
示例#8
0
 /// <summary> Сравниваем </summary>
 public bool Equals(IWeightedEdge other)
 {
     return(Equals((IEdge)other));
 }
示例#9
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);
        }