/// <summary>
            /// If possible, relax the given edge using the supplied base cost and edge-weight function.
            /// </summary>
            /// <param name="edge">The edge to relax.</param>
            /// <param name="cost">The base cost to reach the edge destination vertex.</param>
            /// <param name="ew">The edge weigher.</param>
            /// <param name="forbidNegatives">If true, negative values will forbid the link.</param>
            /// <returns>True if the edge was relaxed, otherwise false.</returns>
            public bool RelaxEdge(E edge, IWeight cost, IEdgeWeigher <V, E> ew, bool forbidNegatives = true)
            {
                V       v       = edge.Dst;
                IWeight hopCost = ew.GetWeight(edge);

                if ((!hopCost.IsViable) || (hopCost.IsNegative && forbidNegatives))
                {
                    return(false);
                }

                IWeight newCost = cost.Merge(hopCost);

                int compareResult = -1;

                if (HasCost(v))
                {
                    IWeight oldCost = GetCost(v);
                    compareResult = newCost.CompareTo(oldCost);
                }

                if (compareResult <= 0)
                {
                    UpdateVertex(v, edge, newCost, compareResult < 0);
                }

                return(compareResult < 0);
            }
Beispiel #2
0
        /// <inheritdoc/>
        protected override IResult <V, E> InternalSearch(IGraph <V, E> graph, V src, V dst, IEdgeWeigher <V, E> weigher, int maxPaths = -1)
        {
            if (maxPaths == AllPaths)
            {
                maxPaths = popSize;
            }
            if (useSuurballe)
            {
                return(new SuurballeGraphSearch <V, E>().Search(graph, src, dst, weigher, AllPaths));
            }
            orig         = graph;
            this.src     = src;
            this.dst     = dst;
            this.weigher = weigher;
            IList <Subset> best = new GaPopulation <Subset>().RunGa(iterations, popSize, maxPaths, new Subset(this, new bool[numGroups]));
            var            dpps = new HashSet <DisjointPathPair <V, E> >();

            foreach (Subset s in best)
            {
                dpps.UnionWith(s.BuildPaths());
            }
            IResult <V, E> firstDijkstra = new DijkstraGraphSearch <V, E>().Search(orig, src, dst, weigher, 1);
            var            result        = new InternalResult(this, firstDijkstra, dpps);

            return(result);
        }
 public ShortestPathEnumerator(IGraph <V, E> graph, V src, V dst, IEdgeWeigher <V, E> weigher)
 {
     this.graph = CheckNotNull(graph);
     CheckNotNull(src);
     this.dst       = CheckNotNull(dst);
     this.weigher   = CheckNotNull(weigher);
     maskingWeigher = new InnerEdgeWeigher(weigher);
     next           = () => search.Search(graph, src, dst, weigher, 1).Paths.FirstOrDefault();
 }
            /// <summary>
            /// Sums the given edges using the given weigher.
            /// </summary>
            /// <param name="weigher">The weigher to use.</param>
            /// <param name="edges">The edges to sum.</param>
            /// <returns>The sum of path cost between the given edges.</returns>
            private IWeight CalculatePathCost(IEdgeWeigher <V, E> weigher, IEnumerable <E> edges)
            {
                IWeight totalCost = weigher.InitialWeight;

                foreach (E edge in edges)
                {
                    totalCost = totalCost.Merge(weigher.GetWeight(edge));
                }
                return(totalCost);
            }
Beispiel #5
0
        /// <summary>
        /// <para>
        /// This implementation produces results augmented with information on SCCs within the graph.
        /// </para>
        /// <para>
        /// To prevent traversal of an edge, the <see cref="IEdgeWeigher{V, E}"/> should
        /// return a negative value as an edge weigher.
        /// </para>
        /// </summary>
        /// <param name="graph">The graph to search.</param>
        /// <param name="weigher">The weigher to use.</param>
        /// <returns>The SCC search result.</returns>
        public IResultBase <V, E> Search(IGraph <V, E> graph, IEdgeWeigher <V, E> weigher)
        {
            SccResult result = new SccResult(graph);

            foreach (V vertex in graph.Vertices)
            {
                VertexData data = result.GetData(vertex);
                if (data is null)
                {
                    Connect(graph, vertex, weigher, result);
                }
            }
            return(result.Build());
        }
        protected void ExecuteSinglePathSearch(IGraphPathSearch <TestVertex, TestEdge> search,
                                               IGraph <TestVertex, TestEdge> graph, TestVertex src, TestVertex dst,
                                               IEdgeWeigher <TestVertex, TestEdge> weigher, int pathCount, IWeight pathCost)
        {
            IResult <TestVertex, TestEdge>       result = search.Search(graph, src, dst, weigher, 1);
            ISet <IPath <TestVertex, TestEdge> > paths  = result.Paths;

            PrintPaths(paths);
            Assert.Equal(Math.Min(pathCount, 1), paths.Count);
            if (pathCount > 0)
            {
                IPath <TestVertex, TestEdge> path = paths.First();
                Assert.Equal(pathCost, path.Cost);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Scans the specified graph, using recursion, and produces SCC results.
        /// </summary>
        /// <param name="graph">The graph to search.</param>
        /// <param name="vertex">The current vertex to scan and connect.</param>
        /// <param name="weigher">The optional weigher to use.</param>
        /// <param name="result">The graph search result.</param>
        /// <returns>Augmentation vertex data for the current vertex.</returns>
        private VertexData Connect(IGraph <V, E> graph, V vertex, IEdgeWeigher <V, E> weigher, SccResult result)
        {
            VertexData data = result.AddData(vertex);

            // Scan through all egress edges of the current vertex.
            foreach (E edge in graph.GetEdgesFrom(vertex))
            {
                V nextVertex = edge.Dst;

                // If edge is not viable, skip it.
                if (weigher != null && !weigher.GetWeight(edge).IsViable)
                {
                    continue;
                }

                // Attempt to get the augmentation vertex data for the next vertex.
                VertexData nextData = result.GetData(nextVertex);
                if (nextData is null)
                {
                    // Next vertex has not been visited yet, so do this now.
                    nextData     = Connect(graph, nextVertex, weigher, result);
                    data.LowLink = Math.Min(data.LowLink, nextData.LowLink);
                }
                else if (result.Visited(nextData))
                {
                    // Next vertex has been visited, which means
                    // it is in the same cluster as the current vertex.
                    data.LowLink = Math.Min(data.LowLink, nextData.Index);
                }
            }

            if (data.LowLink == data.Index)
            {
                result.AddCluster(data);
            }
            return(data);
        }
        /// <summary>
        /// Searches the given graph for paths between the given vertices.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="src"></param>
        /// <param name="dst"></param>
        /// <param name="weigher"></param>
        /// <returns></returns>
        public IEnumerable <IPath <V, E> > LazyPathSearch(IGraph <V, E> graph, V src, V dst, IEdgeWeigher <V, E> weigher)
        {
            var enumerator = new ShortestPathEnumerator(graph, src, dst, weigher);
            var paths      = new SortedSet <IPath <V, E> >(EnumeratePaths(enumerator), new PathComparer());

            foreach (IPath <V, E> path in paths)
            {
                yield return(path);
            }
        }
Beispiel #9
0
        /// <inheritdoc/>
        protected override IResult <V, E> InternalSearch(IGraph <V, E> graph, V src, V dst, IEdgeWeigher <V, E> weigher, int maxPaths = -1)
        {
            // Prepare the graph result.
            var result = new DefaultResult(src, dst, maxPaths);

            // Set up the starting frontier with the source as the sole vertex.
            var frontier = new HashSet <V>();

            result.UpdateVertex(src, default, weigher.InitialWeight, true);
        /// <inheritdoc/>
        protected override IResult <V, E> InternalSearch(IGraph <V, E> graph, V src, V dst, IEdgeWeigher <V, E> weigher, int maxPaths = -1)
        {
            // TODO: This method needs to be refactored as it is difficult to follow and debug.
            // TODO: There is a defect here triggered by 3+ edges between the same vertices which
            // makes an attempt to produce looping paths. Protection against this was added to
            // AbstractGraphPathSearch, but the root issue remains here.
            // TODO: There is a defect here where not all paths are truly disjoint.
            // This class needs to filter its own results to make sure that the paths
            // are indeed disjoint. Temporary fix for this is provided, but the issue still
            // needs to be addressed through refactoring.
            weightF        = weigher;
            firstDijkstraS = (DefaultResult)base.InternalSearch(graph, src, dst, weigher, AllPaths);
            firstDijkstra  = (DefaultResult)base.InternalSearch(graph, src, null, weigher, AllPaths);

            // Choose an arbitrary shortest path to run Suurballe on.
            IPath <V, E> shortPath = null;

            if (firstDijkstraS.Paths.Count == 0)
            {
                return(firstDijkstraS);
            }

            DisjointPathResult result = new DisjointPathResult(firstDijkstra, src, dst, maxPaths);

            foreach (IPath <V, E> p in firstDijkstraS.Paths)
            {
                shortPath = p;
                // Transforms the graph so tree edges have 0 weight.
                var modified = new ModifiedWeigher(this);
                // Create a residual graph g' by removing all source vertices and reversing 0 length path edges.
                IMutableGraph <V, E> gt = MutableCopy(graph);
                foreach (E edge in graph.GetEdgesTo(src))
                {
                    gt.RemoveEdge(edge);
                }
                foreach (E edge in shortPath.Edges)
                {
                    gt.RemoveEdge(edge);
                    E reverse = (E)Activator.CreateInstance(typeof(E), edge.Dst, edge.Src);
                    revToEdge.AddOrSet(reverse, edge);
                    gt.AddEdge(reverse);
                }
                // Rerun dijkstra on the temporary graph to get a second path.
                IResult <V, E> secondDijkstra    = new DijkstraGraphSearch <V, E>().Search(gt, src, dst, modified);
                IPath <V, E>   residualShortPath = null;

                if (secondDijkstra.Paths.Count == 0)
                {
                    result.Dpps.Add(new DisjointPathPair <V, E>(shortPath, null));
                    continue;
                }

                foreach (IPath <V, E> p2 in secondDijkstra.Paths)
                {
                    residualShortPath = p2;
                    IMutableGraph <V, E> roundTrip = MutableCopy(graph);
                    List <E>             tmp       = roundTrip.Edges.ToList();
                    tmp.ForEach(roundTrip.RemoveEdge);
                    foreach (E edge in shortPath.Edges)
                    {
                        roundTrip.AddEdge(edge);
                    }

                    if (residualShortPath != null)
                    {
                        foreach (E edge in residualShortPath.Edges)
                        {
                            if (revToEdge.ContainsKey(edge))
                            {
                                E edgeToRemove = revToEdge[edge];
                                if (roundTrip.Edges.Contains(edgeToRemove))
                                {
                                    roundTrip.RemoveEdge(edgeToRemove);
                                }
                            }
                            else
                            {
                                roundTrip.AddEdge(edge);
                            }
                        }
                    }

                    // Actually build the final result.
                    DefaultResult lastSearch = (DefaultResult)base.InternalSearch(roundTrip, src, dst, weigher, AllPaths);
                    IPath <V, E>  primary    = lastSearch.Paths.First();

                    foreach (E edge in primary.Edges)
                    {
                        roundTrip.RemoveEdge(edge);
                    }

                    ISet <IPath <V, E> > backups = base.InternalSearch(roundTrip, src, dst, weigher, AllPaths).Paths;

                    // Find first backup path that does not share any nodes with the primary.
                    foreach (IPath <V, E> backup in backups)
                    {
                        if (IsDisjoint(primary, backup))
                        {
                            result.Dpps.Add(new DisjointPathPair <V, E>(primary, backup));
                            break;
                        }
                    }
                }
            }

            for (int i = result.Dpps.Count - 1; i > 0; --i)
            {
                if (result.Dpps[i].Size <= 1)
                {
                    result.Dpps.RemoveAt(i);
                }
            }

            result.BuildPaths();
            return(result);
        }
Beispiel #11
0
 public InternalWeigher(IEdgeWeigher <V, E> weigher, IDictionary <E, int> riskGrouping, bool[] subset)
 => (this.weigher, this.riskGrouping, subsetF) = (weigher, riskGrouping, subset);
Beispiel #12
0
        /// <inheritdoc/>
        protected override IResult <V, E> InternalSearch(IGraph <V, E> graph, V src, V dst, IEdgeWeigher <V, E> weigher, int maxPaths = 1)
        {
            CheckNotNull(weigher, "The edge weigher cannot be null.");
            CheckArgument(maxPaths != AllPaths, "KShortestPath cannot search all paths.");
            CheckArgument(maxPaths > 0, "The max number of paths must be greater than 0.");

            IGraph <V, E>        originalGraph   = CheckNotNull(graph, "The graph cannot be null.");
            var                  modifiedWeigher = new InnerEdgeWeigher(weigher);
            var                  result          = new InnerOrderedResult(src, dst, maxPaths);
            var                  resultPaths     = new List <IPath <V, E> >(maxPaths);
            var                  potentialPaths  = new List <IPath <V, E> >();
            var                  dijkstraSearch  = new DijkstraGraphSearch <V, E>();
            ISet <IPath <V, E> > dijkstraResults = dijkstraSearch.Search(originalGraph, src, dst, modifiedWeigher, 1).Paths;

            // Checks if the destination was reachable.
            if (dijkstraResults.Count == 0)
            {
                log.Warn("No path was found.");
                return(result);
            }

            // If it was reachable, add the first shortest path to the set of results.
            resultPaths.Add(dijkstraResults.First());

            for (int k = 1; k < maxPaths; ++k)
            {
                for (int i = 0; i < resultPaths[k - 1].Edges.Count; ++i)
                {
                    V        spurNode         = resultPaths[k - 1].Edges[i].Src;
                    List <E> rootPathEdgeList = resultPaths[k - 1].Edges.Take(i).ToList();

                    foreach (IPath <V, E> path in resultPaths)
                    {
                        if (path.Edges.Count >= i && rootPathEdgeList.SequenceEqual(path.Edges.Take(i)))
                        {
                            modifiedWeigher.RemovedEdges.Add(path.Edges[i]);
                        }
                    }

                    // Effectively remove all nodes from the source path.
                    foreach (E edge in rootPathEdgeList)
                    {
                        foreach (E e in originalGraph.GetEdgesFrom(edge.Src))
                        {
                            modifiedWeigher.RemovedEdges.Add(e);
                        }
                        foreach (E e in originalGraph.GetEdgesTo(edge.Src))
                        {
                            modifiedWeigher.RemovedEdges.Add(e);
                        }
                    }

                    dijkstraResults = dijkstraSearch.Search(originalGraph, spurNode, dst, modifiedWeigher, 1).Paths;

                    if (dijkstraResults.Count > 0)
                    {
                        IPath <V, E> spurPath  = dijkstraResults.First();
                        var          totalPath = new List <E>(rootPathEdgeList);
                        foreach (E edge in spurPath.Edges)
                        {
                            totalPath.Add(edge);
                        }
                        // The following line must use the original weigher, not the modified weigher, because the
                        // modifed weigher will count -1 values used for modifying the graph and return an inaccurate cost.
                        potentialPaths.Add(new DefaultPath <V, E>(totalPath, CalculatePathCost(weigher, totalPath)));
                    }

                    // Restore all removed paths and nodes.
                    modifiedWeigher.RemovedEdges.Clear();
                }

                if (potentialPaths.Count == 0)
                {
                    break;
                }

                potentialPaths.Sort(new InnerPathComparer());
                resultPaths.Add(potentialPaths[0]);
                potentialPaths.RemoveAt(0);
            }

            resultPaths.ForEach(p => result.PathSet.Add(p));

            return(result);
        }
Beispiel #13
0
        /// <inheritdoc/>
        protected override IResult <V, E> InternalSearch(IGraph <V, E> graph, V src, V dst, IEdgeWeigher <V, E> weigher, int maxPaths = -1)
        {
            // Use the default result to remember cumulative costs and
            // parent edges to each respective vertex.
            var result = new DefaultResult(src, dst, maxPaths);

            // Cost to reach the source vertex is 0, of course.
            result.UpdateVertex(src, null, weigher.InitialWeight, false);

            if (graph.Edges.Count is 0)
            {
                result.BuildPaths();
                return(result);
            }

            // Use the min priority queue to progressively find each
            // nearest vertex until we reach the desired destination,
            // if one was given, or until we reach all possible destinations.
            Heap <V> minQueue = new Heap <V>(graph.Vertices, new PathCostComparer(result));

            while (minQueue.Count > 0)
            {
                // Get the nearest vertex.
                V nearest = minQueue.ExtractExtreme();
                if (nearest.Equals(dst))
                {
                    break;
                }

                // Find its cost and use it to determine if the vertex is reachable.
                if (result.HasCost(nearest))
                {
                    IWeight cost = result.GetCost(nearest);

                    // If the vertex is reachable, relax all its egress edges.
                    foreach (E e in graph.GetEdgesFrom(nearest))
                    {
                        result.RelaxEdge(e, cost, weigher, true);
                    }
                }

                // Reprioritize the min queue.
                minQueue.Heapify();
            }

            // Build a set of paths from the results and return it.
            result.BuildPaths();
            return(result);
        }
Beispiel #14
0
 public InnerEdgeWeigher(IEdgeWeigher <V, E> weigher) => innerEdgeWeigher = weigher;
 public InnerEdgeWeigher(IEdgeWeigher <V, E> weigher) => this.weigher = weigher;
 /// <summary>
 /// The abstract implementation of this algorithm's search function.
 /// </summary>
 /// <param name="graph">The graph to search.</param>
 /// <param name="src">The source vertex.</param>
 /// <param name="dst">The destination vertex.</param>
 /// <param name="weigher">The edge weigher.</param>
 /// <param name="maxPaths">The maximum number of paths to find.</param>
 /// <returns>A search result.</returns>
 protected abstract IResult <V, E> InternalSearch(IGraph <V, E> graph, V src, V dst, IEdgeWeigher <V, E> weigher, int maxPaths = AllPaths);
Beispiel #17
0
        /// <inheritdoc/>
        protected override IResult <V, E> InternalSearch(IGraph <V, E> graph, V src, V dst, IEdgeWeigher <V, E> weigher, int maxPaths = -1)
        {
            // Prepare the search result.
            var result = new SpanningTreeResult(src, dst, maxPaths);

            // The source vertex has cost 0, of course.
            result.UpdateVertex(src, default, weigher.InitialWeight, true);
 /// <inheritdoc/>
 public IResult <V, E> Search(IGraph <V, E> graph, V src, V dst, IEdgeWeigher <V, E> weigher, int maxPaths = AllPaths)
 {
     CheckArguments(graph, src, dst);
     return(InternalSearch(graph, src, dst, weigher ?? new DefaultEdgeWeigher <V, E>(), maxPaths));
 }