/// <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); }
/// <summary> /// Finds the shortest path in the graph given a subset of edge types to use. /// </summary> /// <param name="subset"></param> /// <returns></returns> private IResult <V, E> FindShortestPathFromSubset(bool[] subset) { IGraph <V, E> graph = orig; IEdgeWeigher <V, E> modified = new InternalWeigher(weigher, riskGrouping, subset); IResult <V, E> res = new DijkstraGraphSearch <V, E>().Search(graph, src, dst, modified, 1); return(res); }
/// <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); }
/// <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); }