예제 #1
0
        /// <summary>
        /// Calculates a path.
        /// </summary>
        /// <returns>The path.</returns>
        public Path Run(RouterDb routerDb, SnapPoint source, SnapPoint target,
                        Func <RouterDbEdgeEnumerator, uint> getWeight, Func <VertexId, bool> settled = null, Func <VertexId, bool> queued = null)
        {
            var enumerator = routerDb.GetEdgeEnumerator();

            _tree.Clear();
            _visits.Clear();
            _heap.Clear();

            // add sources.
            // add forward.
            if (!enumerator.MoveToEdge(source.EdgeId, true))
            {
                throw new Exception($"Edge in source {source} not found!");
            }
            var sourceCostForward = getWeight(enumerator);

            if (sourceCostForward > 0)
            {
                // can traverse edge in the forward direction.
                var sourceOffsetCostForward = sourceCostForward * (1 - source.OffsetFactor());
                var p = _tree.AddVisit(enumerator.To, source.EdgeId, uint.MaxValue);
                _heap.Push(p, sourceOffsetCostForward);
            }

            // add backward.
            if (!enumerator.MoveToEdge(source.EdgeId, false))
            {
                throw new Exception($"Edge in source {source} not found!");
            }
            var sourceCostBackward = getWeight(enumerator);

            if (sourceCostBackward > 0)
            {
                // can traverse edge in the backward direction.
                var sourceOffsetCostBackward = sourceCostBackward * source.OffsetFactor();
                var p = _tree.AddVisit(enumerator.To, source.EdgeId, uint.MaxValue);
                _heap.Push(p, sourceOffsetCostBackward);
            }

            // add targets.
            (uint pointer, float cost, bool forward, SnapPoint target)bestTarget = (uint.MaxValue, float.MaxValue,
                                                                                    false,
예제 #2
0
        public void Run(DirectedGraph graph, DirectedGraph witnessGraph, uint vertex, HashSet <uint> dirty)
        {
            try
            {
                forwardSettled.Clear();
                backwardSettled.Clear();
                pathTree.Clear();
                pointerHeap.Clear();
                witnesses.Clear();

                var p = pathTree.AddSettledVertex(vertex, new WeightAndDir <float>()
                {
                    Direction = new Dir(true, true),
                    Weight    = 0
                }, 0, Constants.NO_VERTEX);
                pointerHeap.Push(p, 0);

                // dequeue vertices until stopping conditions are reached.
                var enumerator = graph.GetEdgeEnumerator();

                // calculate max forward/backward weight.
                var forwardMax  = 0f;
                var backwardMax = 0f;
                enumerator.MoveTo(vertex);
                var nextEnumerator = graph.GetEdgeEnumerator();
                while (enumerator.MoveNext())
                {
                    var nVertex1 = enumerator.Neighbour;

                    if (dirty != null &&
                        !dirty.Contains(nVertex1))
                    { // this is not a hop-2 to consider.
                        continue;
                    }

                    ContractedEdgeDataSerializer.Deserialize(enumerator.Data0,
                                                             out Dir dir1, out float weight1);
                    var p1 = pathTree.AddSettledVertex(nVertex1, weight1, dir1, 1, vertex);
                    pointerHeap.Push(p1, weight1);

                    nextEnumerator.MoveTo(enumerator.Neighbour);
                    while (nextEnumerator.MoveNext())
                    {
                        var nVertex2 = nextEnumerator.Neighbour;
                        if (nVertex2 == vertex)
                        { // no u-turns.
                            continue;
                        }

                        ContractedEdgeDataSerializer.Deserialize(nextEnumerator.Data0,
                                                                 out Dir dir2, out float weight2);

                        dir2._val = (byte)(dir1._val & dir2._val);
                        if (dir2._val == 0)
                        {
                            continue;
                        }

                        var weight2Hops = weight1 + weight2;
                        var p2          = pathTree.AddSettledVertex(nVertex2, weight2Hops, dir2, 2, nVertex1);
                        pointerHeap.Push(p2, weight2Hops);

                        if (dir2.F && weight2Hops > forwardMax)
                        {
                            forwardMax = weight2Hops;
                        }
                        if (dir2.B && weight2Hops > backwardMax)
                        {
                            backwardMax = weight2Hops;
                        }
                    }
                }

                if (forwardMax == 0 &&
                    backwardMax == 0)
                {
                    return;
                }

                while (pointerHeap.Count > 0)
                {
                    var cPointer = pointerHeap.Pop();
                    pathTree.GetSettledVertex(cPointer, out uint cVertex, out WeightAndDir <float> cWeight,
                                              out uint cHops, out uint pVertex);

                    if (cHops == 2)
                    { // check if the search can stop or not.
                        var witness = new Shortcut <float>();
                        witness.Forward  = float.MaxValue;
                        witness.Backward = float.MaxValue;
                        if (cWeight.Direction.F &&
                            forwardSettled.TryGetValue(cVertex, out float best) &&
                            best < cWeight.Weight)
                        { // this is a 2-hop and vertex was settled before, we have a witness!
                            witness.Forward = best;
                        }
                        if (cWeight.Direction.B &&
                            backwardSettled.TryGetValue(cVertex, out best) &&
                            best < cWeight.Weight)
                        { // this is a 2-hop and vertex was settled before, we have a witness!
                            witness.Backward = best;
                        }
                        if (witness.Backward != float.MaxValue ||
                            witness.Forward != float.MaxValue)
                        {     // report witness here.
                            if (vertex != cVertex)
                            { // TODO: check this, how can they ever be the same?
                                witnesses.Add(new Witness()
                                {
                                    Vertex1  = vertex,
                                    Vertex2  = cVertex,
                                    Forward  = witness.Forward,
                                    Backward = witness.Backward
                                });
                            }
                        }
                    }

                    if (forwardSettled.Count > _maxSettles ||
                        backwardSettled.Count > _maxSettles)
                    { // over settled count.
                        break;
                    }

                    if (cWeight.Weight > backwardMax &&
                        cWeight.Weight > forwardMax)
                    { // over max weights.
                        break;
                    }

                    if (forwardSettled.ContainsKey(cVertex) ||
                        cWeight.Weight > forwardMax)
                    {
                        cWeight.Direction = new Dir(false, cWeight.Direction.B);
                    }
                    if (backwardSettled.ContainsKey(cVertex) ||
                        cWeight.Weight > backwardMax)
                    {
                        cWeight.Direction = new Dir(cWeight.Direction.F, false);
                    }

                    var isRelevant = false;
                    if (cWeight.Direction.F)
                    {
                        forwardSettled.Add(cVertex, cWeight.Weight);
                        isRelevant = true;
                    }
                    if (cWeight.Direction.B)
                    {
                        backwardSettled.Add(cVertex, cWeight.Weight);
                        isRelevant = true;
                    }

                    if (!isRelevant)
                    { // not forward, not backwards.
                        continue;
                    }

                    cHops++;
                    if (cHops >= _hopLimit)
                    { // over hop limit, don't queue.
                        continue;
                    }

                    if (cHops == 1)
                    {
                        if (dirty == null)
                        { // all hops 1 are already queued.
                            continue;
                        }
                    }
                    else if (cHops == 2)
                    {
                        if (dirty == null ||
                            dirty.Contains(cVertex))
                        { // all these hops 2 are already queue.
                            continue;
                        }
                    }

                    enumerator.MoveTo(cVertex);
                    while (enumerator.MoveNext())
                    {
                        var nVertex = enumerator.Neighbour;

                        if (nVertex == pVertex)
                        { // no going back.
                            continue;
                        }

                        if (cHops == 1)
                        {     // check if the neighbour is dirty.
                            if (dirty.Contains(nVertex))
                            { // skip dirty vertices, they are already in the queue.
                                continue;
                            }
                        }

                        Dir   nDir;
                        float nWeight;
                        ContractedEdgeDataSerializer.Deserialize(enumerator.Data0,
                                                                 out nDir, out nWeight);

                        nDir._val = (byte)(cWeight.Direction._val & nDir._val);
                        if (nDir._val == 0)
                        {
                            continue;
                        }

                        nWeight = nWeight + cWeight.Weight;

                        if (nDir.F && nWeight > forwardMax)
                        {
                            nDir = new Dir(false, nDir.B);
                            if (nDir._val == 0)
                            {
                                continue;
                            }
                        }
                        if (nDir.B && nWeight > backwardMax)
                        {
                            nDir = new Dir(nDir.F, false);
                            if (nDir._val == 0)
                            {
                                continue;
                            }
                        }

                        var nPoiner = pathTree.AddSettledVertex(nVertex, nWeight, nDir, cHops, cVertex);
                        pointerHeap.Push(nPoiner, nWeight);
                    }
                }

                if (witnesses.Count > 0)
                {
                    lock (witnessGraph)
                    {
                        foreach (var witness in witnesses)
                        {
                            //witnessGraph.AddOrUpdateEdge(witness.Item1, witness.Item2, witness.Item3.Forward,
                            //        witness.Item3.Backward);
                            witnessGraph.AddOrUpdateEdge(witness.Vertex1, witness.Vertex2,
                                                         witness.Forward, witness.Backward);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
예제 #3
0
        /// <summary>
        /// Calculates witness paths.
        /// </summary>
        public virtual void Calculate(DirectedGraph graph, WeightHandler <T> weightHandler, uint vertex,
                                      uint source, Dictionary <uint, Shortcut <T> > targets, int maxSettles, int hopLimit)
        {
            pathTree.Clear();
            pointerHeap.Clear();

            var forwardSettled  = new HashSet <uint>();
            var backwardSettled = new HashSet <uint>();

            var forwardTargets  = new HashSet <uint>();
            var backwardTargets = new HashSet <uint>();

            var maxWeight = 0f;

            foreach (var targetPair in targets)
            {
                var target   = targetPair.Key;
                var shortcut = targetPair.Value;
                var e        = new OriginalEdge(source, target);

                var shortcutForward = weightHandler.GetMetric(shortcut.Forward);
                if (shortcutForward > 0 && shortcutForward < float.MaxValue)
                {
                    forwardTargets.Add(e.Vertex2);
                    if (shortcutForward > maxWeight)
                    {
                        maxWeight = shortcutForward;
                    }
                }
                var shortcutBackward = weightHandler.GetMetric(shortcut.Backward);
                if (shortcutBackward > 0 && shortcutBackward < float.MaxValue)
                {
                    backwardTargets.Add(e.Vertex2);
                    if (shortcutBackward > maxWeight)
                    {
                        maxWeight = shortcutBackward;
                    }
                }
            }

            // queue the source.
            pathTree.Clear();
            pointerHeap.Clear();
            var p = pathTree.AddSettledVertex(source, new WeightAndDir <float>()
            {
                Direction = new Dir(true, true),
                Weight    = 0
            }, 0);

            pointerHeap.Push(p, 0);

            // dequeue vertices until stopping conditions are reached.
            var cVertex = Constants.NO_VERTEX;
            WeightAndDir <float> cWeight;
            var cHops      = uint.MaxValue;
            var enumerator = graph.GetEdgeEnumerator();

            while (pointerHeap.Count > 0)
            {
                var cPointer = pointerHeap.Pop();
                pathTree.GetSettledVertex(cPointer, out cVertex, out cWeight, out cHops);

                if (cVertex == vertex)
                {
                    continue;
                }

                if (cWeight.Weight >= maxWeight)
                {
                    break;
                }

                if (forwardSettled.Contains(cVertex) ||
                    forwardTargets.Count == 0 ||
                    forwardSettled.Count > maxSettles)
                {
                    cWeight.Direction = new Dir(false, cWeight.Direction.B);
                }
                if (backwardSettled.Contains(cVertex) ||
                    backwardTargets.Count == 0 ||
                    backwardSettled.Count > maxSettles)
                {
                    cWeight.Direction = new Dir(cWeight.Direction.F, false);
                }

                if (cWeight.Direction.F)
                {
                    forwardSettled.Add(cVertex);
                    if (forwardTargets.Contains(cVertex))
                    { // target reached, evaluate it as a shortcut.
                        Shortcut <T> shortcut;
                        if (targets.TryGetValue(cVertex, out shortcut))
                        {
                            var shortcutForward = weightHandler.GetMetric(shortcut.Forward);
                            if (shortcutForward > cWeight.Weight)
                            { // a witness path was found, don't add a shortcut.
                                shortcut.Forward = weightHandler.Zero;
                                targets[cVertex] = shortcut;
                            }
                        }
                        forwardTargets.Remove(cVertex);
                        if (forwardTargets.Count == 0)
                        {
                            if (backwardTargets.Count == 0)
                            {
                                break;
                            }
                            cWeight.Direction = new Dir(false, cWeight.Direction.B);
                            if (!cWeight.Direction.F && !cWeight.Direction.B)
                            {
                                continue;
                            }
                        }
                    }
                }
                if (cWeight.Direction.B)
                {
                    backwardSettled.Add(cVertex);
                    if (backwardTargets.Contains(cVertex))
                    { // target reached, evaluate it as a shortcut.
                        Shortcut <T> shortcut;
                        if (targets.TryGetValue(cVertex, out shortcut))
                        {
                            var shortcutBackward = weightHandler.GetMetric(shortcut.Backward);
                            if (shortcutBackward > cWeight.Weight)
                            { // a witness path was found, don't add a shortcut.
                                shortcut.Backward = weightHandler.Zero;
                                targets[cVertex]  = shortcut;
                            }
                        }
                        backwardTargets.Remove(cVertex);
                        if (backwardTargets.Count == 0)
                        {
                            if (forwardTargets.Count == 0)
                            {
                                break;
                            }
                            cWeight.Direction = new Dir(cWeight.Direction.F, false);
                            if (!cWeight.Direction.F && !cWeight.Direction.B)
                            {
                                continue;
                            }
                        }
                    }
                }

                if (cHops + 1 >= hopLimit)
                {
                    continue;
                }

                if (forwardSettled.Count > maxSettles &&
                    backwardSettled.Count > maxSettles)
                {
                    continue;
                }

                enumerator.MoveTo(cVertex);
                while (enumerator.MoveNext())
                {
                    var nVertex = enumerator.Neighbour;
                    var nWeight = ContractedEdgeDataSerializer.Deserialize(enumerator.Data0);

                    nWeight = new WeightAndDir <float>()
                    {
                        Direction = Dir.Combine(cWeight.Direction, nWeight.Direction),
                        Weight    = cWeight.Weight + nWeight.Weight
                    };

                    if (nWeight.Direction.F &&
                        forwardSettled.Contains(nVertex))
                    {
                        nWeight.Direction = new Dir(false, nWeight.Direction.B);
                    }
                    if (nWeight.Direction.B &&
                        backwardSettled.Contains(nVertex))
                    {
                        nWeight.Direction = new Dir(nWeight.Direction.F, false);
                    }
                    if (!nWeight.Direction.F && !nWeight.Direction.B)
                    {
                        continue;
                    }

                    var nPoiner = pathTree.AddSettledVertex(nVertex, nWeight, cHops + 1);
                    pointerHeap.Push(nPoiner, nWeight.Weight);
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Finds loops and merges them together.
        /// </summary>
        /// <param name="maxSettles">The maximum labels to settle.</param>
        /// <param name="updateLabel">A callback to update label.</param>
        internal void FindLoops(uint maxSettles, IslandLabels islandLabels, Action <uint, uint> updateLabel)
        {
            // TODO: it's probably better to call reduce here when too much has changed.

            var  pathTree   = new PathTree();
            var  enumerator = _graph.GetEdgeEnumerator();
            var  settled    = new HashSet <uint>();
            var  queue      = new Queue <uint>();
            var  loop       = new HashSet <uint>(); // keeps all with a path back to label, initially only label.
            uint label      = 0;

            while (label < _graph.VertexCount)
            {
                if (!enumerator.MoveTo(label))
                {
                    label++;
                    continue;
                }

                if (islandLabels[label] != label)
                {
                    label++;
                    continue;
                }

                queue.Clear();
                pathTree.Clear();
                settled.Clear();

                loop.Add(label);
                queue.Enqueue(pathTree.Add(label, uint.MaxValue));

                while (queue.Count > 0 &&
                       settled.Count < maxSettles)
                {
                    var pointer = queue.Dequeue();
                    pathTree.Get(pointer, out var current, out var previous);

                    if (settled.Contains(current))
                    {
                        continue;
                    }

                    settled.Add(current);

                    if (!enumerator.MoveTo(current))
                    {
                        continue;
                    }

                    while (enumerator.MoveNext())
                    {
                        var n = enumerator.Neighbour;

                        n = islandLabels[n];

                        if (loop.Contains(n))
                        {
                            // yay, a loop!
                            loop.Add(current);
                            while (previous != uint.MaxValue)
                            {
                                pathTree.Get(previous, out current, out previous);
                                loop.Add(current);
                            }
                        }
                        if (settled.Contains(n))
                        {
                            continue;
                        }

                        queue.Enqueue(pathTree.Add(n, pointer));
                    }
                }

                if (loop.Count > 0)
                {
                    this.Merge(loop, updateLabel);
                }
                loop.Clear();

                // move to the next label.
                label++;
            }
        }