/// <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); }
void IMutableGraph <TVertex, TEdge> .Clear() { IMutableGraph <TVertex, TEdge> ithis = this; }