예제 #1
0
        private HeapNode GetHeapNode(T oddDegreeNode, IEnumerable <T> oddDegreeNodes, Graph <T> graph)
        {
            var adsp = new AllDestinationShortestPaths <T>(oddDegreeNode, oddDegreeNodes, graph, (_, x) => x.Distance);

            adsp.RunWithNumTargets(_comparisonSetSize);
            var costDict = adsp.LowestCost;

            if (costDict.ContainsKey(oddDegreeNode))
            {
                costDict.Remove(oddDegreeNode);
            }

            var costs = costDict.Values.ToList();

            costs.Sort();
            var firstChoiceSavings = costs.Count > 1 ? costs[0] - costs.Skip(1).Average() : 0;
            var firstChoice        = costDict.First(kvp => Math.Abs(kvp.Value - costs.First()) < 1e-12).Key;
            var path     = adsp.GetPath(oddDegreeNode, firstChoice);
            var heapNode = new LazyGraphAugmenter <T> .HeapNode
            {
                Cost  = firstChoiceSavings,
                End   = firstChoice,
                Path  = path,
                Start = oddDegreeNode
            };

            return(heapNode);
        }
        public List <T> GetRoutes(T startingPlace, double maxDistance)
        {
            var potentialRoutes = new List <WeightedAdjacencyNode <T>[]>();

            // step 1: get all destinations shortest path
            // get distance-based shortest paths
            // limit to 0.4 to 0.6 of total distance
            // get weight-based shortest paths to those nodes
            Func <T, WeightedAdjacencyNode <T>, double> basicWeightCostFunction = (_, x) => x.Weight;
            var adspDistance = new AllDestinationShortestPaths <T>(startingPlace, _graph.Neighbors.Keys, _graph, (_, x) => x.Distance);

            adspDistance.RunWithDistanceCap(maxDistance * MaxDistanceOutbound);
            var targets    = adspDistance.LowestCost.Where(kvp => kvp.Value > maxDistance * MinDistanceOutbound).Select(k => k.Key);
            var adspWeight = new AllDestinationShortestPaths <T>(startingPlace, targets, _graph, basicWeightCostFunction);

            adspWeight.Run();

            // step 2: for each destination, try to find a return trip. double weight any segment that was previously used.
            var      currentMinDistance = double.MaxValue;
            List <T> fullPath           = new List <T>();

            foreach (var potentialDestinationKvp in adspWeight.LowestCost)
            {
                // early stop: return trip will always be more expensive, so quit if over half of total best cost.
                if (currentMinDistance * .5 < potentialDestinationKvp.Value)
                {
                    break;
                }

                // double the weights
                var endPosition  = potentialDestinationKvp.Key;
                var reversePaths = ReverseWeights(endPosition, adspWeight.TraversalPath);
                // get weight-based shortest path back
                var adspReversed = new AllDestinationShortestPaths <T>(endPosition, new[] { startingPlace }, _graph, GetCostFunction(basicWeightCostFunction, reversePaths));
                adspReversed.Run();
                var reversePathsReturnTrip = ReverseWeights(startingPlace, adspReversed.TraversalPath);

                var totalCost = potentialDestinationKvp.Value + adspReversed.LowestCost.Values.First();
                if (currentMinDistance > totalCost)
                {
                    currentMinDistance = totalCost;
                    fullPath           = adspWeight.GetPath(startingPlace, endPosition);
                    fullPath.Reverse();
                    var t = adspReversed.GetPath(endPosition, startingPlace);
                    t.Reverse();
                    fullPath.AddRange(t);
                }
            }

            Console.WriteLine(currentMinDistance);


            return(fullPath);
        }
예제 #3
0
        public Graph <T> AugmentGraph(Graph <T> graph)
        {
            var extraWeight = 0.0;

            while (true)
            {
                if (!graph.OddDegreeNodes().Any())
                {
                    break;
                }
                var oddDegreeNodes = graph.OddDegreeNodes();
                var startingNode   = oddDegreeNodes.First();
                var adsp           = new AllDestinationShortestPaths <T>(startingNode, graph.OddDegreeNodes().Intersect(graph.MustHitVertices), graph, (_, x) => x.Distance);
                adsp.Run();
                var paths     = adsp.TraversalPath;
                var nodeOrder = adsp.LowestCost.OrderByDescending(kvp => kvp.Value).Select(kvp => kvp.Key);

                // find pairs of nodes on the shortest path tree
                var oddNodeLookup = new HashSet <T>(graph.OddDegreeNodes());
                var usedNodes     = new HashSet <T>();
                foreach (var node in nodeOrder)
                {
                    if (node.Equals(startingNode) || usedNodes.Contains(node))
                    {
                        continue;
                    }
                    var endNode = paths[node];
                    var path    = new List <T>(new[] { node, endNode });
                    while (!oddNodeLookup.Contains(endNode) && paths.ContainsKey(endNode))
                    {
                        endNode = paths[endNode];
                        path.Add(endNode);
                    }

                    if (!usedNodes.Contains(node) && !usedNodes.Contains(endNode))
                    {
                        // at this stage, node and endNode are a short path between odd nodes.
                        usedNodes.Add(endNode);
                        usedNodes.Add(node);
                        extraWeight += graph.AddEdgeCardinality(path);
                    }
                }
            }

            Console.WriteLine($"GreedyGraphAugmenter added {extraWeight}");
            return(graph);
        }
예제 #4
0
        /// <summary>
        /// Construct a set of vertices that are on the shortest path between any two nodes in the required node set.
        /// These may include non-required nodes.
        /// </summary>
        /// <param name="g"></param>
        /// <returns></returns>
        private HashSet <Node> GetPathsBetweenRequiredNodes(Graph <Node> g)
        {
            var fullVertexSet = new HashSet <Node>(g.MustHitVertices);

            foreach (var node in g.MustHitVertices)
            {
                var adsp = new AllDestinationShortestPaths <Node>(node, g.MustHitVertices, g, (_, x) => x.Distance);
                adsp.Run();
                var traversalPaths = adsp.TraversalPath;
                foreach (var endNode in g.MustHitVertices)
                {
                    var localNode = endNode;
                    while (traversalPaths.ContainsKey(localNode) && localNode != node)
                    {
                        fullVertexSet.Add(localNode);
                        localNode = traversalPaths[localNode];
                    }
                }
            }

            return(fullVertexSet);
        }