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