Exemplo n.º 1
0
        /*public static IEnumerable<IMutableVertexAndEdgeListGraph<TVertex, TEdge>> StronglyConnectedComponents<TVertex, TEdge>(this IVertexListGraph<TVertex, TEdge> g, Func<IMutableVertexAndEdgeListGraph<TVertex, TEdge>> componentMaker)
         *  where TEdge : QuickGraph.IEdge<TVertex>
         * {
         *  g.StronglyConnectedComponents(out var scc);
         *
         *  return scc.GroupBy(kv => kv.Value).Select(group =>
         *  {
         *      var c = componentMaker();
         *
         *      group.ForEach(kv => c.AddVertex(kv.Key));
         *
         *      foreach (var v1 in c.Vertices)
         *          foreach (var v2 in c.Vertices)
         *          {
         *              if (g.TryGetEdges(v1, v2, out var edges))
         *                  edges.ForEach(e => c.AddEdge(e));
         *          }
         *  });
         * }*/



        /// <summary>
        /// Returns the list of weakly connected components in a graph. A weakly connected component is one in which
        /// <list type="number">
        ///     <item>for every pair of vertices V,W, W is reachable from V, ignoring edge-direction, and </item>
        ///     <item>one cannot add another node U such that the first property still holds.</item>
        /// </list>
        /// </summary>
        /// <typeparam name="TGraph">The type of the produced components.</typeparam>
        /// <typeparam name="TVertex">The type of the vertices.</typeparam>
        /// <typeparam name="TEdge">The type of the edges.</typeparam>
        /// <param name="g">The graph.</param>
        /// <param name="componentMaker">A producer-function for empty empty components.</param>
        public static IList <TGraph> WeaklyConnectedComponents <TGraph, TVertex, TEdge>(this GraphBase <TVertex, TEdge> g, Func <TGraph> componentMaker)
            where TEdge : class, IEdge <TVertex>
            where TGraph : GraphBase <TVertex, TEdge>
        {
            var undirected = new NonDirectedGraph <TVertex, NonDirectedEdge <TVertex> >();

            g.Vertices.ForEach(undirected.Add);
            g.Edges.ForEach(e => undirected.Add(new NonDirectedEdge <TVertex>(e.StartVertex, e.EndVertex)));

            var subgraphs = new List <TGraph>();

            //Find the subgraphs (connected components that are candidates for being turned into trees).
            var dcGraphFinder = new DisconnectedGraphsFinder <TVertex, NonDirectedEdge <TVertex> >(
                () => new SubGraphView <TVertex, NonDirectedEdge <TVertex> >(undirected), undirected);

            dcGraphFinder.FindDisconnectedGraphs();

            foreach (var component in dcGraphFinder.FoundDisconnectedGraphs)
            {
                var subG = componentMaker();
                component.Vertices.ForEach(subG.Add);

                foreach (var v1 in component.Vertices)
                {
                    foreach (var v2 in component.Vertices)
                    {
                        g.GetEdges(v1, v2).ForEach(subG.Add);
                    }
                }

                subgraphs.Add(subG);
            }

            return(subgraphs);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Calculates witnesses from one source to multiple targets at once but using only one hop.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="from"></param>
        /// <param name="tos"></param>
        /// <param name="tosWeights"></param>
        /// <param name="maxSettles"></param>
        /// <param name="forwardExists"></param>
        /// <param name="backwardExists"></param>
        private void ExistsOneHop(GraphBase <CHEdgeData> graph, uint from, List <uint> tos, List <float> tosWeights, int maxSettles,
                                  ref bool[] forwardExists, ref bool[] backwardExists)
        {
            var   toSet     = new HashSet <uint>();
            float maxWeight = 0;

            for (int idx = 0; idx < tosWeights.Count; idx++)
            {
                if (!forwardExists[idx] || !backwardExists[idx])
                {
                    toSet.Add(tos[idx]);
                    if (maxWeight < tosWeights[idx])
                    {
                        maxWeight = tosWeights[idx];
                    }
                }
            }

            if (toSet.Count > 0)
            {
                var neighbours = graph.GetEdges(from);
                while (neighbours.MoveNext())
                {
                    if (toSet.Contains(neighbours.Neighbour))
                    { // ok, this is a to-edge.
                        int index = tos.IndexOf(neighbours.Neighbour);
                        toSet.Remove(neighbours.Neighbour);

                        var edgeData = neighbours.EdgeData;
                        if (edgeData.CanMoveForward &&
                            edgeData.Weight < tosWeights[index])
                        {
                            forwardExists[index] = true;
                        }
                        if (edgeData.CanMoveBackward &&
                            edgeData.Weight < tosWeights[index])
                        {
                            backwardExists[index] = true;
                        }

                        if (toSet.Count == 0)
                        {
                            break;
                        }
                    }
                }
            }
        }
 /// <summary>
 /// Gets an edge from the given graph taking into account 'can have duplicates'.
 /// </summary>
 /// <param name="graph"></param>
 /// <param name="from"></param>
 /// <param name="to"></param>
 /// <param name="existingData"></param>
 /// <param name="shape"></param>
 /// <returns></returns>
 private bool GetEdge(GraphBase <TEdgeData> graph, uint from, uint to, out TEdgeData existingData, out ICoordinateCollection shape)
 {
     if (!graph.CanHaveDuplicates)
     {
         graph.GetEdgeShape(from, to, out shape);
         return(graph.GetEdge(from, to, out existingData));
     }
     else
     {
         var edges = graph.GetEdges(from, to);
         while (edges.MoveNext())
         {
             if (edges.Neighbour == to)
             {
                 existingData = edges.EdgeData;
                 shape        = edges.Intermediates;
                 return(true);
             }
         }
         existingData = default(TEdgeData);
         shape        = null;
         return(false);
     }
 }
Exemplo n.º 4
0
        /// <summary>
        /// Starts pre-processing all nodes
        /// </summary>
        public void Start()
        {
            //_witnessCalculator.HopLimit = 5;

            _missesQueue = new Queue <bool>();
            _misses      = 0;

            // calculate the entire queue.
            this.RecalculateQueue();

            // loop over the priority queue until it's empty.
            uint  total          = _target.VertexCount;
            uint  current        = 1;
            uint? vertex         = this.SelectNext();
            float latestProgress = 0;

            while (vertex != null)
            {
                // contract the nodes.
                this.Contract(vertex.Value);

                // select the next vertex.
                vertex = this.SelectNext();

                // calculate and log progress.
                float progress = (float)(System.Math.Floor(((double)current / (double)total) * 1000) / 10.0);
                if (progress > 99)
                {
                    progress = (float)(System.Math.Floor(((double)current / (double)total) * 10000) / 100.0);
                }
                if (progress != latestProgress)
                {
                    OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information,
                                                    "Pre-processing... {0}% [{1}/{2}]", progress, current, total);
                    latestProgress = progress;
                    if (progress % 1 == 0 || progress > 99)
                    {
                        int totaEdges         = 0;
                        int totalUncontracted = 0;
                        int maxCardinality    = 0;
                        var neighbourCount    = new Dictionary <uint, int>();
                        for (uint v = 0; v < _target.VertexCount; v++)
                        {
                            if (!this.IsContracted(v))
                            {
                                neighbourCount.Clear();
                                var edges = _target.GetEdges(v);
                                if (edges != null)
                                {
                                    int edgesCount = edges.Count;
                                    //int edgesCount = 0;
                                    //foreach (var edge in edges)
                                    //{
                                    //    int nCount;
                                    //    if (!neighbourCount.TryGetValue(edge.Neighbour, out nCount))
                                    //    {
                                    //        neighbourCount.Add(edge.Neighbour, 1);
                                    //    }
                                    //    else
                                    //    {
                                    //        neighbourCount[edge.Neighbour] = nCount++;
                                    //    }
                                    //    if (nCount > 2)
                                    //    {
                                    //        throw new Exception();
                                    //    }
                                    //    edgesCount++;
                                    //}
                                    totaEdges = edgesCount + totaEdges;
                                    if (maxCardinality < edgesCount)
                                    {
                                        maxCardinality = edgesCount;
                                    }
                                }
                                totalUncontracted++;
                            }
                        }

                        var density = (double)totaEdges / (double)totalUncontracted;
                        OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information,
                                                        "Average card uncontracted vertices: {0} with max {1}", density, maxCardinality);

                        //if (density > 20 &&
                        //    _witnessCalculator.HopLimit < 5)
                        //{
                        //    OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information, "Increased hoplimit.");

                        //    _witnessCalculator.HopLimit = 5;
                        //    this.RecalculateQueue();
                        //}
                        //else if (density > 10 &&
                        //    _witnessCalculator.HopLimit < 4)
                        //{
                        //    OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information, "Increased hoplimit.");

                        //    _witnessCalculator.HopLimit = 4;
                        //    this.RecalculateQueue();
                        //}
                        //else if (density > 5 &&
                        //    _witnessCalculator.HopLimit < 3)
                        //{
                        //    OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information, "Increased hoplimit.");

                        //    _witnessCalculator.HopLimit = 3;
                        //    this.RecalculateQueue();
                        //}
                        //else if (density > 3.3 &&
                        //    _witnessCalculator.HopLimit < 2)
                        //{
                        //    OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information, "Increased hoplimit.");

                        //    _witnessCalculator.HopLimit = 2;
                        //    this.RecalculateQueue();
                        //}
                    }
                }
                current++;
            }

            OsmSharp.Logging.Log.TraceEvent("CHPreProcessor", TraceEventType.Information,
                                            "Pre-processing finsihed!");
        }
Exemplo n.º 5
0
        /// <summary>
        /// Calculates witnesses from on source to multiple targets at once.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="from"></param>
        /// <param name="tos"></param>
        /// <param name="tosWeights"></param>
        /// <param name="maxSettles"></param>
        /// <param name="forwardExists"></param>
        /// <param name="backwardExists"></param>
        /// <param name="toSkip"></param>
        public void Exists(GraphBase <CHEdgeData> graph, uint from, List <uint> tos, List <float> tosWeights, int maxSettles,
                           ref bool[] forwardExists, ref bool[] backwardExists, uint toSkip)
        {
            int maxHops = _hopLimit;

            if (maxHops == 1)
            {
                this.ExistsOneHop(graph, from, tos, tosWeights, maxSettles, ref forwardExists, ref backwardExists);
                return;
            }

            // creates the settled list.
            var   backwardSettled = new HashSet <uint>();
            var   forwardSettled = new HashSet <uint>();
            var   backwardToSet = new HashSet <uint>();
            var   forwardToSet = new HashSet <uint>();
            float forwardMaxWeight = 0, backwardMaxWeight = 0;

            for (int idx = 0; idx < tosWeights.Count; idx++)
            {
                if (!forwardExists[idx])
                {
                    forwardToSet.Add(tos[idx]);
                    if (forwardMaxWeight < tosWeights[idx])
                    {
                        forwardMaxWeight = tosWeights[idx];
                    }
                }
                if (!backwardExists[idx])
                {
                    backwardToSet.Add(tos[idx]);
                    if (backwardMaxWeight < tosWeights[idx])
                    {
                        backwardMaxWeight = tosWeights[idx];
                    }
                }
            }
            if (forwardMaxWeight == 0 && backwardMaxWeight == 0)
            { // no need to search!
                return;
            }

            // creates the priorty queue.
            var forwardMinWeight  = new Dictionary <uint, float>();
            var backwardMinWeight = new Dictionary <uint, float>();
            var heap = _reusableHeap;

            heap.Clear();
            heap.Push(new SettledVertex(from, 0, 0, forwardMaxWeight > 0, backwardMaxWeight > 0), 0);

            // keep looping until the queue is empty or the target is found!
            while (heap.Count > 0)
            { // pop the first customer.
                var current = heap.Pop();
                if (current.Hops + 1 < maxHops)
                { // the current vertex has net been settled.
                    if (current.VertexId == toSkip)
                    {
                        continue;
                    }
                    bool forwardWasSettled  = forwardSettled.Contains(current.VertexId);
                    bool backwardWasSettled = backwardSettled.Contains(current.VertexId);
                    if (forwardWasSettled && backwardWasSettled)
                    {
                        continue;
                    }

                    if (current.Forward)
                    { // this is a forward settle.
                        forwardSettled.Add(current.VertexId);
                        forwardMinWeight.Remove(current.VertexId);
                        if (forwardToSet.Contains(current.VertexId))
                        {
                            int index = tos.IndexOf(current.VertexId);
                            forwardExists[index] = current.Weight <= tosWeights[index];
                            //if (forwardExists[index])
                            //{
                            forwardToSet.Remove(current.VertexId);
                            //}
                        }
                    }
                    if (current.Backward)
                    { // this is a backward settle.
                        backwardSettled.Add(current.VertexId);
                        backwardMinWeight.Remove(current.VertexId);
                        if (backwardToSet.Contains(current.VertexId))
                        {
                            int index = tos.IndexOf(current.VertexId);
                            backwardExists[index] = current.Weight <= tosWeights[index];
                            //if (backwardExists[index])
                            //{
                            backwardToSet.Remove(current.VertexId);
                            //}
                        }
                    }

                    if (forwardToSet.Count == 0 &&
                        backwardToSet.Count == 0)
                    { // there is nothing left to check.
                        break;
                    }

                    if (forwardSettled.Count >= maxSettles &&
                        backwardSettled.Count >= maxSettles)
                    { // do not continue searching.
                        break;
                    }

                    bool doForward  = current.Forward && forwardToSet.Count > 0 && !forwardWasSettled;
                    bool doBackward = current.Backward && backwardToSet.Count > 0 && !backwardWasSettled;
                    if (doForward || doBackward)
                    { // get the neighbours.
                        var neighbours = graph.GetEdges(current.VertexId);
                        while (neighbours.MoveNext())
                        { // move next.
                            var edgeData           = neighbours.EdgeData;
                            var neighbourWeight    = current.Weight + edgeData.Weight;
                            var doNeighbourForward = doForward && edgeData.CanMoveForward && neighbourWeight <= forwardMaxWeight &&
                                                     !forwardSettled.Contains(neighbours.Neighbour);
                            var doNeighbourBackward = doBackward && edgeData.CanMoveBackward && neighbourWeight <= backwardMaxWeight &&
                                                      !backwardSettled.Contains(neighbours.Neighbour);
                            if (doNeighbourBackward || doNeighbourForward)
                            {
                                float existingWeight;
                                if (doNeighbourForward)
                                {
                                    if (forwardMinWeight.TryGetValue(neighbours.Neighbour, out existingWeight))
                                    {
                                        if (existingWeight <= neighbourWeight)
                                        {
                                            doNeighbourForward = false;
                                        }
                                        else
                                        {
                                            forwardMinWeight[neighbours.Neighbour] = neighbourWeight;
                                        }
                                    }
                                    else
                                    {
                                        forwardMinWeight[neighbours.Neighbour] = neighbourWeight;
                                    }
                                }
                                if (doNeighbourBackward)
                                {
                                    if (backwardMinWeight.TryGetValue(neighbours.Neighbour, out existingWeight))
                                    {
                                        if (existingWeight <= neighbourWeight)
                                        {
                                            doNeighbourBackward = false;
                                        }
                                        else
                                        {
                                            backwardMinWeight[neighbours.Neighbour] = neighbourWeight;
                                        }
                                    }
                                    else
                                    {
                                        backwardMinWeight[neighbours.Neighbour] = neighbourWeight;
                                    }
                                }

                                if (doNeighbourBackward || doNeighbourForward)
                                {
                                    var neighbour = new SettledVertex(neighbours.Neighbour,
                                                                      neighbourWeight, current.Hops + 1, doNeighbourForward, doNeighbourBackward);
                                    heap.Push(neighbour, neighbour.Weight);
                                }
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// Calculates witnesses from one source to multiple targets at once but using only one hop.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="from"></param>
        /// <param name="tos"></param>
        /// <param name="tosWeights"></param>
        /// <param name="maxSettles"></param>
        /// <param name="forwardExists"></param>
        /// <param name="backwardExists"></param>
        private void ExistsOneHop(GraphBase<CHEdgeData> graph, uint from, List<uint> tos, List<float> tosWeights, int maxSettles,
            ref bool[] forwardExists, ref bool[] backwardExists)
        {
            var toSet = new HashSet<uint>();
            float maxWeight = 0;
            for (int idx = 0; idx < tosWeights.Count; idx++)
            {
                if (!forwardExists[idx] || !backwardExists[idx])
                {
                    toSet.Add(tos[idx]);
                    if (maxWeight < tosWeights[idx])
                    {
                        maxWeight = tosWeights[idx];
                    }
                }
            }

            if (toSet.Count > 0)
            {
                var neighbours = graph.GetEdges(from);
                while (neighbours.MoveNext())
                {
                    if (toSet.Contains(neighbours.Neighbour))
                    { // ok, this is a to-edge.
                        int index = tos.IndexOf(neighbours.Neighbour);
                        toSet.Remove(neighbours.Neighbour);

                        var edgeData = neighbours.EdgeData;
                        if (edgeData.CanMoveForward &&
                            edgeData.Weight < tosWeights[index])
                        {
                            forwardExists[index] = true;
                        }
                        if (edgeData.CanMoveBackward &&
                            edgeData.Weight < tosWeights[index])
                        {
                            backwardExists[index] = true;
                        }

                        if (toSet.Count == 0)
                        {
                            break;
                        }
                    }
                }
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// Calculates witnesses from on source to multiple targets at once.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="from"></param>
        /// <param name="tos"></param>
        /// <param name="tosWeights"></param>
        /// <param name="maxSettles"></param>
        /// <param name="forwardExists"></param>
        /// <param name="backwardExists"></param>
        /// <param name="toSkip"></param>
        public void Exists(GraphBase<CHEdgeData> graph, uint from, List<uint> tos, List<float> tosWeights, int maxSettles,
            ref bool[] forwardExists, ref bool[] backwardExists, uint toSkip)
        {
            int maxHops = _hopLimit;

            if (maxHops == 1)
            {
                this.ExistsOneHop(graph, from, tos, tosWeights, maxSettles, ref forwardExists, ref backwardExists);
                return;
            }

            // creates the settled list.
            var backwardSettled = new HashSet<uint>();
            var forwardSettled = new HashSet<uint>();
            var backwardToSet = new HashSet<uint>();
            var forwardToSet = new HashSet<uint>();
            float forwardMaxWeight = 0, backwardMaxWeight = 0;
            for (int idx = 0; idx < tosWeights.Count; idx++)
            {
                if (!forwardExists[idx])
                {
                    forwardToSet.Add(tos[idx]);
                    if (forwardMaxWeight < tosWeights[idx])
                    {
                        forwardMaxWeight = tosWeights[idx];
                    }
                }
                if (!backwardExists[idx])
                {
                    backwardToSet.Add(tos[idx]);
                    if (backwardMaxWeight < tosWeights[idx])
                    {
                        backwardMaxWeight = tosWeights[idx];
                    }
                }
            }
            if (forwardMaxWeight == 0 && backwardMaxWeight == 0)
            { // no need to search!
                return;
            }

            // creates the priorty queue.
            var forwardMinWeight = new Dictionary<uint, float>();
            var backwardMinWeight = new Dictionary<uint, float>();
            var heap = _reusableHeap;
            heap.Clear();
            heap.Push(new SettledVertex(from, 0, 0, forwardMaxWeight > 0, backwardMaxWeight > 0), 0);

            // keep looping until the queue is empty or the target is found!
            while (heap.Count > 0)
            { // pop the first customer.
                var current = heap.Pop();
                if (current.Hops + 1 < maxHops)
                { // the current vertex has net been settled.
                    if(current.VertexId == toSkip)
                    {
                        continue;
                    }
                    bool forwardWasSettled = forwardSettled.Contains(current.VertexId);
                    bool backwardWasSettled = backwardSettled.Contains(current.VertexId);
                    if (forwardWasSettled && backwardWasSettled)
                    {
                        continue;
                    }

                    if (current.Forward)
                    { // this is a forward settle.
                        forwardSettled.Add(current.VertexId);
                        forwardMinWeight.Remove(current.VertexId);
                        if (forwardToSet.Contains(current.VertexId))
                        {
                            int index = tos.IndexOf(current.VertexId);
                            forwardExists[index] = current.Weight <= tosWeights[index];
                            //if (forwardExists[index])
                            //{
                            forwardToSet.Remove(current.VertexId);
                            //}
                        }
                    }
                    if (current.Backward)
                    { // this is a backward settle.
                        backwardSettled.Add(current.VertexId);
                        backwardMinWeight.Remove(current.VertexId);
                        if (backwardToSet.Contains(current.VertexId))
                        {
                            int index = tos.IndexOf(current.VertexId);
                            backwardExists[index] = current.Weight <= tosWeights[index];
                            //if (backwardExists[index])
                            //{
                            backwardToSet.Remove(current.VertexId);
                            //}
                        }
                    }

                    if (forwardToSet.Count == 0 &&
                        backwardToSet.Count == 0)
                    { // there is nothing left to check.
                        break;
                    }

                    if (forwardSettled.Count >= maxSettles &&
                        backwardSettled.Count >= maxSettles)
                    { // do not continue searching.
                        break;
                    }

                    bool doForward = current.Forward && forwardToSet.Count > 0 && !forwardWasSettled;
                    bool doBackward = current.Backward && backwardToSet.Count > 0 && !backwardWasSettled;
                    if (doForward || doBackward)
                    { // get the neighbours.
                        var neighbours = graph.GetEdges(current.VertexId);
                        while (neighbours.MoveNext())
                        { // move next.
                            var edgeData = neighbours.EdgeData;
                            var neighbourWeight = current.Weight + edgeData.Weight;
                            var doNeighbourForward = doForward && edgeData.CanMoveForward && neighbourWeight <= forwardMaxWeight &&
                                !forwardSettled.Contains(neighbours.Neighbour);
                            var doNeighbourBackward = doBackward && edgeData.CanMoveBackward && neighbourWeight <= backwardMaxWeight &&
                                !backwardSettled.Contains(neighbours.Neighbour);
                            if (doNeighbourBackward || doNeighbourForward)
                            {
                                float existingWeight;
                                if (doNeighbourForward)
                                {
                                    if (forwardMinWeight.TryGetValue(neighbours.Neighbour, out existingWeight))
                                    {
                                        if(existingWeight <= neighbourWeight)
                                        {
                                            doNeighbourForward = false;
                                        }
                                        else
                                        {
                                            forwardMinWeight[neighbours.Neighbour] = neighbourWeight;
                                        }
                                    }
                                    else
                                    {
                                        forwardMinWeight[neighbours.Neighbour] = neighbourWeight;
                                    }
                                }
                                if (doNeighbourBackward)
                                {
                                    if (backwardMinWeight.TryGetValue(neighbours.Neighbour, out existingWeight))
                                    {
                                        if (existingWeight <= neighbourWeight)
                                        {
                                            doNeighbourBackward = false;
                                        }
                                        else
                                        {
                                            backwardMinWeight[neighbours.Neighbour] = neighbourWeight;
                                        }
                                    }
                                    else
                                    {
                                        backwardMinWeight[neighbours.Neighbour] = neighbourWeight;
                                    }
                                }

                                if (doNeighbourBackward || doNeighbourForward)
                                {
                                    var neighbour = new SettledVertex(neighbours.Neighbour,
                                        neighbourWeight, current.Hops + 1, doNeighbourForward, doNeighbourBackward);
                                    heap.Push(neighbour, neighbour.Weight);
                                }
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// Calculates the priority of the given vertex.
        /// </summary>
        /// <param name="vertex">The vertex to calculate the priority for.</param>
        /// <param name="newEdges">The number of new edges that would be added.</param>
        /// <param name="removedEdges">The number of edges that would be removed.</param>
        /// <param name="depth">The depth of the vertex.</param>
        /// <param name="contracted">The number of contracted neighours.</param>
        public float Calculate(uint vertex, out int newEdges, out int removedEdges, out int depth, out int contracted)
        {
            newEdges     = 0;
            removedEdges = 0;
            _contractionCount.TryGetValue(vertex, out contracted);

            // get all information from the source.
            var edges = _data.GetEdges(vertex).ToList();

            // build the list of edges to replace.
            var edgesForContractions = new List <Edge <CHEdgeData> >(edges.Count);
            var tos    = new List <uint>(edges.Count);
            var tosSet = new HashSet <uint>();

            foreach (var edge in edges)
            {
                // use this edge for contraction.
                edgesForContractions.Add(edge);
                tos.Add(edge.Neighbour);
                tosSet.Add(edge.Neighbour);
                removedEdges++;
            }

            var toRequeue = new HashSet <uint>();

            var forwardEdges          = new CHEdgeData?[2];
            var backwardEdges         = new CHEdgeData?[2];
            var existingEdgesToRemove = new HashSet <CHEdgeData>();

            // loop over each combination of edges just once.
            var forwardWitnesses  = new bool[edgesForContractions.Count];
            var backwardWitnesses = new bool[edgesForContractions.Count];
            var weights           = new List <float>(edgesForContractions.Count);
            var edgesToY          = new Dictionary <uint, Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> >(edgesForContractions.Count);

            for (int x = 1; x < edgesForContractions.Count; x++)
            { // loop over all elements first.
                var xEdge = edgesForContractions[x];

                // get edges.
                edgesToY.Clear();
                var rawEdgesToY = _data.GetEdges(xEdge.Neighbour);
                while (rawEdgesToY.MoveNext())
                {
                    var rawEdgeNeighbour = rawEdgesToY.Neighbour;
                    if (tosSet.Contains(rawEdgeNeighbour))
                    {
                        var rawEdgeData           = rawEdgesToY.EdgeData;
                        var rawEdgeForwardWeight  = rawEdgeData.CanMoveForward ? rawEdgeData.Weight : float.MaxValue;
                        var rawEdgeBackwardWeight = rawEdgeData.CanMoveBackward ? rawEdgeData.Weight : float.MaxValue;
                        Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> edgeTuple;
                        if (!edgesToY.TryGetValue(rawEdgeNeighbour, out edgeTuple))
                        {
                            edgeTuple = new Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>(rawEdgeData, null, null,
                                                                                                        rawEdgeForwardWeight, rawEdgeBackwardWeight);
                            edgesToY.Add(rawEdgeNeighbour, edgeTuple);
                        }
                        else if (!edgeTuple.Item2.HasValue)
                        {
                            edgesToY[rawEdgeNeighbour] = new Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>(
                                edgeTuple.Item1, rawEdgeData, null,
                                rawEdgeForwardWeight < edgeTuple.Item4 ? rawEdgeForwardWeight : edgeTuple.Item4,
                                rawEdgeBackwardWeight < edgeTuple.Item5 ? rawEdgeBackwardWeight : edgeTuple.Item5);
                        }
                        else
                        {
                            edgesToY[rawEdgeNeighbour] = new Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>(
                                edgeTuple.Item1, edgeTuple.Item2, rawEdgeData,
                                rawEdgeForwardWeight < edgeTuple.Item4 ? rawEdgeForwardWeight : edgeTuple.Item4,
                                rawEdgeBackwardWeight < edgeTuple.Item5 ? rawEdgeBackwardWeight : edgeTuple.Item5);
                        }
                    }
                }

                // calculate max weight.
                weights.Clear();
                var forwardUnknown  = false;
                var backwardUnknown = false;
                for (int y = 0; y < x; y++)
                {
                    // update maxWeight.
                    var yEdge = edgesForContractions[y];
                    if (xEdge.Neighbour != yEdge.Neighbour)
                    {
                        // reset witnesses.
                        var forwardWeight = (float)xEdge.EdgeData.Weight + (float)yEdge.EdgeData.Weight;
                        forwardWitnesses[y]  = !xEdge.EdgeData.CanMoveBackward || !yEdge.EdgeData.CanMoveForward;
                        backwardWitnesses[y] = !xEdge.EdgeData.CanMoveForward || !yEdge.EdgeData.CanMoveBackward;
                        weights.Add(forwardWeight);

                        Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> edgeTuple;
                        if (edgesToY.TryGetValue(yEdge.Neighbour, out edgeTuple))
                        {
                            if (!forwardWitnesses[y])
                            { // check 1-hop witnesses.
                                if (edgeTuple.Item4 <= forwardWeight)
                                {
                                    forwardWitnesses[y] = true;
                                }
                            }
                            if (!backwardWitnesses[y])
                            { // check 1-hop witnesses.
                                if (edgeTuple.Item5 <= forwardWeight)
                                {
                                    backwardWitnesses[y] = true;
                                }
                            }
                        }
                        forwardUnknown  = !forwardWitnesses[y] || forwardUnknown;
                        backwardUnknown = !backwardWitnesses[y] || backwardUnknown;
                    }
                    else
                    { // already set this to true, not use calculating it's witness.
                        forwardWitnesses[y]  = true;
                        backwardWitnesses[y] = true;
                        weights.Add(0);
                    }
                }

                // calculate witnesses.
                if (_witnessCalculator.HopLimit > 1)
                { // 1-hops already checked.
                    if (forwardUnknown || backwardUnknown)
                    {
                        _witnessCalculator.Exists(_data, xEdge.Neighbour, tos, weights, int.MaxValue,
                                                  ref forwardWitnesses, ref backwardWitnesses, vertex);
                    }
                }

                for (int y = 0; y < x; y++)
                { // loop over all elements.
                    var yEdge = edgesForContractions[y];

                    // add the combinations of these edges.
                    if (xEdge.Neighbour != yEdge.Neighbour)
                    { // there is a connection from x to y and there is no witness path.
                        // create x-to-y data and edge.
                        var canMoveForward  = !forwardWitnesses[y] && (xEdge.EdgeData.CanMoveBackward && yEdge.EdgeData.CanMoveForward);
                        var canMoveBackward = !backwardWitnesses[y] && (xEdge.EdgeData.CanMoveForward && yEdge.EdgeData.CanMoveBackward);

                        if (canMoveForward || canMoveBackward)
                        { // add the edge if there is usefull info or if there needs to be a neighbour relationship.
                            // add contracted edges like normal. // calculate the total weights.
                            var weight = (float)xEdge.EdgeData.Weight + (float)yEdge.EdgeData.Weight;

                            // there are a few options now:
                            //  1) No edges yet between xEdge.Neighbour and yEdge.Neighbour.
                            //  1) There is no other contracted edge: just add as a duplicate.
                            //  2) There is at least on other contracted edge: optimize information because there can only be 4 case between two vertices:
                            //     - One bidirectional edge.
                            //     - Two directed edges with different weights.
                            //     - One forward edge.
                            //     - One backward edge.
                            //    =>  all available information needs to be combined.

                            // check existing data.
                            var  existingCanMoveForward     = false;
                            var  existingCanMoveBackward    = false;
                            var  existingForwardWeight      = float.MaxValue;
                            var  existingBackwardWeight     = float.MaxValue;
                            uint existingForwardContracted  = 0;
                            uint existingBackwardContracted = 0;
                            Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> edgeTuple;
                            if (edgesToY.TryGetValue(yEdge.Neighbour, out edgeTuple))
                            {
                                //var existingEdges = _data.GetEdges(xEdge.Neighbour, yEdge.Neighbour);
                                existingEdgesToRemove.Clear();
                                // remove all existing stuff.
                                var existingEdge = new CHEdgeData();
                                for (int idx = 0; idx < 3; idx++)
                                {
                                    switch (idx)
                                    {
                                    case 0:
                                        existingEdge = edgeTuple.Item1.Value;
                                        break;

                                    case 1:
                                        if (!edgeTuple.Item2.HasValue)
                                        {
                                            idx = 2;
                                            break;
                                        }
                                        existingEdge = edgeTuple.Item2.Value;
                                        break;

                                    case 2:
                                        if (!edgeTuple.Item3.HasValue)
                                        {
                                            idx = 2;
                                            break;
                                        }
                                        existingEdge = edgeTuple.Item3.Value;
                                        break;
                                    }

                                    var existingEdgeData = existingEdge;
                                    if (existingEdgeData.IsContracted)
                                    { // this edge is contracted, collect it's information.
                                        existingEdgesToRemove.Add(existingEdgeData);
                                        if (existingEdgeData.CanMoveForward)
                                        { // can move forward, so at least one edge that can move forward.
                                            existingCanMoveForward = true;
                                            if (existingForwardWeight > existingEdgeData.Weight)
                                            { // update forward weight.
                                                existingForwardWeight     = existingEdgeData.Weight;
                                                existingForwardContracted = existingEdgeData.ContractedId;
                                            }
                                        }
                                        if (existingEdgeData.CanMoveBackward)
                                        { // can move backward, so at least one edge that can move backward.
                                            existingCanMoveBackward = true;
                                            if (existingBackwardWeight > existingEdgeData.Weight)
                                            { // update backward weight.
                                                existingBackwardWeight     = existingEdgeData.Weight;
                                                existingBackwardContracted = existingEdgeData.ContractedId;
                                            }
                                        }
                                    }
                                }
                            }

                            if (existingCanMoveForward || existingCanMoveBackward)
                            { // there is already another contraced edge.
                                uint  forwardContractedId = vertex;
                                float forwardWeight       = weight;
                                // merge with existing data.
                                if (existingCanMoveForward &&
                                    ((weight > existingForwardWeight) || !canMoveForward))
                                { // choose the smallest weight.
                                    canMoveForward      = true;
                                    forwardContractedId = existingForwardContracted;
                                    forwardWeight       = existingForwardWeight;
                                }

                                uint  backwardContractedId = vertex;
                                float backwardWeight       = weight;
                                // merge with existing data.
                                if (existingCanMoveBackward &&
                                    ((weight > existingBackwardWeight) || !canMoveBackward))
                                { // choose the smallest weight.
                                    canMoveBackward      = true;
                                    backwardContractedId = existingBackwardContracted;
                                    backwardWeight       = existingBackwardWeight;
                                }

                                // add one of the 4 above case.
                                forwardEdges[0]  = null;
                                forwardEdges[1]  = null;
                                backwardEdges[0] = null;
                                backwardEdges[1] = null;
                                if (canMoveForward && canMoveBackward && forwardWeight == backwardWeight && forwardContractedId == backwardContractedId)
                                { // just add one edge.
                                    forwardEdges[0] = new CHEdgeData(forwardContractedId, true, true, forwardWeight);
                                    //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(forwardContractedId, true, true, forwardWeight));
                                    backwardEdges[0] = new CHEdgeData(backwardContractedId, true, true, backwardWeight);
                                    //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(backwardContractedId, true, true, backwardWeight));
                                }
                                else if (canMoveBackward && canMoveForward)
                                { // add two different edges.
                                    forwardEdges[0] = new CHEdgeData(forwardContractedId, true, false, forwardWeight);
                                    //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(forwardContractedId, true, false, forwardWeight));
                                    backwardEdges[0] = new CHEdgeData(forwardContractedId, false, true, forwardWeight);
                                    //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(forwardContractedId, false, true, forwardWeight));
                                    forwardEdges[1] = new CHEdgeData(backwardContractedId, false, true, backwardWeight);
                                    //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(backwardContractedId, false, true, backwardWeight));
                                    backwardEdges[1] = new CHEdgeData(backwardContractedId, true, false, backwardWeight);
                                    //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(backwardContractedId, true, false, backwardWeight));
                                }
                                else if (canMoveForward)
                                { // only add one forward edge.
                                    forwardEdges[0] = new CHEdgeData(forwardContractedId, true, false, forwardWeight);
                                    //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(forwardContractedId, true, false, forwardWeight));
                                    backwardEdges[0] = new CHEdgeData(forwardContractedId, false, true, forwardWeight);
                                    //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(forwardContractedId, false, true, forwardWeight));
                                }
                                else if (canMoveBackward)
                                { // only add one backward edge.
                                    forwardEdges[0] = new CHEdgeData(backwardContractedId, false, true, backwardWeight);
                                    //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(backwardContractedId, false, true, backwardWeight));
                                    backwardEdges[0] = new CHEdgeData(backwardContractedId, true, false, backwardWeight);
                                    //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(backwardContractedId, true, false, backwardWeight));
                                }

                                // remove all existing stuff.
                                foreach (var existingEdgeToRemove in existingEdgesToRemove)
                                {
                                    if (forwardEdges[0].Equals(existingEdgeToRemove))
                                    {                           // this forward edge is to be kept.
                                        forwardEdges[0] = null; // it's already there.
                                    }
                                    else if (forwardEdges[1] != null &&
                                             !forwardEdges[1].Equals(existingEdgeToRemove))
                                    {                           // this forward edge is to be kept.
                                        forwardEdges[1] = null; // it's already there.
                                    }
                                    else
                                    { // yup, just remove it now.
                                        removedEdges++;
                                    }
                                    var existingEdgeToRemoveBackward = (CHEdgeData)existingEdgeToRemove.Reverse();
                                    if (backwardEdges[0].Equals(existingEdgeToRemoveBackward))
                                    {                            // this backward edge is to be kept.
                                        backwardEdges[0] = null; // it's already there.
                                    }
                                    else if (backwardEdges[1] != null &&
                                             !backwardEdges[1].Equals(existingEdgeToRemoveBackward))
                                    {                            // this backward edge is to be kept.
                                        backwardEdges[1] = null; // it's already there.
                                    }
                                    else
                                    { // yup, just remove it now.
                                        removedEdges++;
                                    }
                                }

                                // add remaining edges.
                                if (forwardEdges[0].HasValue)
                                {
                                    newEdges++;
                                }
                                if (forwardEdges[1].HasValue)
                                {
                                    newEdges++;
                                }
                                if (backwardEdges[0].HasValue)
                                {
                                    newEdges++;
                                }
                                if (backwardEdges[1].HasValue)
                                {
                                    newEdges++;
                                }
                            }
                            else
                            { // there is no edge, just add the data.
                                newEdges = newEdges + 2;
                            }
                        }
                    }
                }
            }

            // get the depth.
            _depth.TryGetValue(vertex, out depth);
            return(1 * (newEdges - removedEdges) + (2 * depth) + (1 * contracted));
        }
        /// <summary>
        /// Starts pre-processing all nodes.
        /// </summary>
        public void Start()
        {
            // build the empty coordinate list.
            var emptyCoordinateList = new GeoCoordinateSimple[0];
            var verticesList        = new HashSet <uint>();

            // initialize status variables.
            uint nextToProcess = 0;
            uint nextPosition  = 0;

            // search edge until a real node.
            double latestProgress = 0;

            while (nextToProcess < _graph.VertexCount)
            { // keep looping until all vertices have been processed.
                // select a new vertext to select.
                var vertexToProcess = nextToProcess;
                var edges           = _graph.GetEdges(vertexToProcess).ToList();
                if (edges.Count == 2)
                { // find one of the neighbours that is usefull.
                    vertexToProcess = edges[0].Neighbour;
                    edges           = _graph.GetEdges(vertexToProcess).ToList();
                    verticesList.Clear();
                    verticesList.Add(vertexToProcess);
                    while (edges.Count == 2)
                    { // keep looping until there is a vertex that is usefull.
                        vertexToProcess = edges[0].Neighbour;
                        if (verticesList.Contains(vertexToProcess))
                        { // take the other vertex.
                            vertexToProcess = edges[1].Neighbour;
                            if (verticesList.Contains(vertexToProcess))
                            { // an island was detected with only vertices having two neighbours.
                                // TODO: find a way to handle this!
                                edges = new List <Edge <Edge> >(0);
                                break;
                            }
                        }
                        verticesList.Add(vertexToProcess);
                        edges = _graph.GetEdges(vertexToProcess).ToList();
                    }
                }
                if (edges.Count > 0)
                { // ok, the vertex was not already processed.
                    nextPosition++;
                    var oldEdges   = new List <Edge <Edge> >(edges);
                    var ignoreList = new HashSet <uint>();
                    foreach (var oldEdge in oldEdges)
                    {
                        if (ignoreList.Contains(oldEdge.Neighbour))
                        { // ignore this edge: already removed in a previous iteration.
                            break;
                        }

                        // don't re-process edges that already have coordinates.
                        ICoordinateCollection oldEdgeValueCoordinates;
                        _graph.GetEdgeShape(vertexToProcess, oldEdge.Neighbour, out oldEdgeValueCoordinates);
                        if (oldEdgeValueCoordinates != null)
                        { // this edge has already been processed.
                            break;
                        }

                        // STEP1: Build list of vertices that are only for form.

                        // set current/previous.
                        var distance = oldEdge.EdgeData.Distance;
                        var current  = oldEdge.Neighbour;
                        var previous = vertexToProcess;

                        // build list of vertices.
                        var vertices = new List <uint>();
                        vertices.Add(previous);
                        vertices.Add(current);

                        // get next edges list.
                        var nextEdges = _graph.GetEdges(current).ToList();
                        while (nextEdges.Count == 2)
                        { // ok the current vertex can be removed.
                            var nextEdge = nextEdges[0];
                            if (nextEdge.Neighbour == previous)
                            { // it's the other edge!
                                nextEdge = nextEdges[1];
                            }

                            // compare edges.
                            if (nextEdge.EdgeData.Forward != oldEdge.EdgeData.Forward ||
                                nextEdge.EdgeData.Tags != oldEdge.EdgeData.Tags)
                            { // oeps, edges are different!
                                break;
                            }

                            // check for intermediates.
                            ICoordinateCollection nextEdgeValueCoordinates;
                            _graph.GetEdgeShape(current, nextEdge.Neighbour, out nextEdgeValueCoordinates);
                            if (nextEdgeValueCoordinates != null)
                            { // oeps, there are intermediates already, this can occur when two osm-ways are drawn on top of eachother.
                                break;
                            }

                            // add distance.
                            distance = distance + nextEdge.EdgeData.Distance;

                            // set current/previous.
                            previous = current;
                            current  = nextEdge.Neighbour;
                            vertices.Add(current);

                            // get next edges.
                            nextEdges = _graph.GetEdges(current).ToList();
                        }

                        // check if the edge contains intermediate points.
                        if (vertices.Count == 2)
                        { // no intermediate points: add the empty coordinate list.
                            var oldEdgeValue = oldEdge.EdgeData;

                            // keep edges that already have intermediates.
                            ICoordinateCollection edgeToKeepValueCoordinates = null;
                            var edgesToKeep = new List <Tuple <uint, Edge, ICoordinateCollection> >();
                            foreach (var edgeToKeep in _graph.GetEdges(vertexToProcess).ToList())
                            {
                                edgeToKeepValueCoordinates = null;
                                if (edgeToKeep.Neighbour == oldEdge.Neighbour &&
                                    _graph.GetEdgeShape(vertexToProcess, edgeToKeep.Neighbour, out edgeToKeepValueCoordinates))
                                {
                                    edgesToKeep.Add(new Tuple <uint, Edge, ICoordinateCollection>(
                                                        edgeToKeep.Neighbour, edgeToKeep.EdgeData, edgeToKeepValueCoordinates));
                                }
                            }

                            // delete olds arcs.
                            _graph.RemoveEdge(vertexToProcess, oldEdge.Neighbour);

                            // add new arc.
                            if (oldEdgeValue.Forward)
                            {
                                _graph.AddEdge(vertexToProcess, oldEdge.Neighbour, oldEdgeValue, null);
                            }
                            else
                            {
                                _graph.AddEdge(vertexToProcess, oldEdge.Neighbour, (Edge)oldEdgeValue.Reverse(), null);
                            }

                            // add edges to keep.
                            foreach (var edgeToKeep in edgesToKeep)
                            {
                                _graph.AddEdge(vertexToProcess, edgeToKeep.Item1, edgeToKeep.Item2, edgeToKeep.Item3);
                            }
                        }
                        else
                        { // intermediate points: build array.
                            // STEP2: Build array of coordinates.
                            var   coordinates = new GeoCoordinateSimple[vertices.Count - 2];
                            float latitude, longitude;
                            for (int idx = 1; idx < vertices.Count - 1; idx++)
                            {
                                _graph.GetVertex(vertices[idx], out latitude, out longitude);
                                coordinates[idx - 1] = new GeoCoordinateSimple()
                                {
                                    Latitude  = latitude,
                                    Longitude = longitude
                                };
                            }

                            // STEP3: Remove all unneeded edges.
                            _graph.RemoveEdge(vertices[0], vertices[1]); // remove first edge.
                            for (int idx = 1; idx < vertices.Count - 1; idx++)
                            {                                            // delete all intermidiate arcs.
                                _graph.RemoveEdges(vertices[idx]);
                            }
                            _graph.RemoveEdge(vertices[vertices.Count - 1], vertices[vertices.Count - 2]); // remove last edge.
                            if (vertices[0] == vertices[vertices.Count - 1])
                            {                                                                              // also remove outgoing edge.
                                ignoreList.Add(vertices[vertices.Count - 2]);                              // make sure this arc is ignored in next iteration.
                            }

                            // STEP4: Add new edge.
                            if (oldEdge.EdgeData.Forward)
                            {
                                _graph.AddEdge(vertices[0], vertices[vertices.Count - 1], new Edge()
                                {
                                    Forward  = oldEdge.EdgeData.Forward,
                                    Tags     = oldEdge.EdgeData.Tags,
                                    Distance = distance
                                }, new CoordinateArrayCollection <GeoCoordinateSimple>(coordinates));
                            }
                            else
                            {
                                var reverse = new GeoCoordinateSimple[coordinates.Length];
                                coordinates.CopyToReverse(reverse, 0);
                                _graph.AddEdge(vertices[vertices.Count - 1], vertices[0], new Edge()
                                {
                                    Forward  = !oldEdge.EdgeData.Forward,
                                    Tags     = oldEdge.EdgeData.Tags,
                                    Distance = distance
                                }, new CoordinateArrayCollection <GeoCoordinateSimple>(reverse));
                            }
                        }
                    }
                }
                // move to the next position.
                nextToProcess++;

                // report progress.
                float progress = (float)System.Math.Round((((double)nextToProcess / (double)_graph.VertexCount) * 100));
                if (progress != latestProgress)
                {
                    OsmSharp.Logging.Log.TraceEvent("Preprocessor", TraceEventType.Information,
                                                    "Removing edges... {0}%", progress);
                    latestProgress = progress;
                }
            }

            // compress the graph.
            this.CompressGraph();
        }