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;
            }
        }
Example #2
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);
                }
            }
        }