Beispiel #1
0
        /// <summary>
        /// Converts this given edge to a purely informative edge.
        /// </summary>
        /// <returns></returns>
        public CHEdgeData ConvertToInformative()
        {
            CHEdgeData informativeData = new CHEdgeData();

            informativeData.Direction          = this.Direction;
            informativeData.ContractedVertexId = this.ContractedVertexId;
            informativeData.Tags   = this.Tags;
            informativeData.Weight = this.Weight;

            // convert the direction.
            if (informativeData.Direction <= 3)
            {
                informativeData.Direction = (byte)(informativeData.Direction + 12);
            }
            else if (informativeData.Direction <= 7)
            {
                informativeData.Direction = (byte)(informativeData.Direction + 8);
            }
            else if (informativeData.Direction <= 11)
            {
                informativeData.Direction = (byte)(informativeData.Direction + 4);
            }
            else
            { // edge was already informative.
                throw new InvalidCastException("Edge was already informative!");
            }

            return(informativeData);
        }
Beispiel #2
0
        /// <summary>
        /// Creates the exact reverse of this edge.
        /// </summary>
        /// <returns></returns>
        public IDynamicGraphEdgeData Reverse()
        {
            // to higher vertex: ( 0=bidirectional,  1=forward,  2=backward,  3=not forward and not backward).
            // to lower  vertex: ( 4=bidirectional,  5=forward,  6=backward,  7=not forward and not backward).
            // no low/high info: ( 8=bidirectional,  9=forward, 10=backward, 11=not forward and not backward).
            var data = new CHEdgeData();

            data.Tags = this.Tags;
            data.ContractedVertexId = this.ContractedVertexId;
            data.Weight             = this.Weight;
            data.Direction          = this.Direction;
            switch (this.Direction)
            {
            case 0:                 // to higher bidirectional.
                data.Direction = 4; // to lower bidirectional.
                break;

            case 1:                 // to higher forward.
                data.Direction = 6; // to lower backward.
                break;

            case 2:                 // to higher backward.
                data.Direction = 5; // to lower forward.
                break;

            case 3:                 // to higher no directional info.
                data.Direction = 7; // to lower no directional info.
                break;

            case 4:                 // to lower bidirectional.
                data.Direction = 0; // to higher bidirectional.
                break;

            case 5:                 // to lower forward.
                data.Direction = 2; // to higher backward.
                break;

            case 6:                 // to lower backward.
                data.Direction = 1; // to higher forward.
                break;

            case 7:                 // to lower no directional info.
                data.Direction = 3; // to higher no directional info.
                break;

            case 9:                  // no low/high forward.
                data.Direction = 10; // no low/high backward.
                break;

            case 10:                // no low/high backward.
                data.Direction = 9; // no low/high forward.
                break;
            }
            return(data);
        }
        public void TestCHEdgeDataSetDirection()
        {
            CHEdgeData edge = new CHEdgeData();
            this.DoTestSetDirection(edge, false, false, false);
            this.DoTestSetDirection(edge, true, false, false);
            this.DoTestSetDirection(edge, false, true, false);
            this.DoTestSetDirection(edge, false, false, true);
            this.DoTestSetDirection(edge, true, true, false);
            this.DoTestSetDirection(edge, true, false, true);
            this.DoTestSetDirection(edge, false, true, true);
            this.DoTestSetDirection(edge, true, true, true);

            this.DoTestSetDirection(edge, false, false);
            this.DoTestSetDirection(edge, true, false);
            this.DoTestSetDirection(edge, false, true);
            this.DoTestSetDirection(edge, true, true);
        }
Beispiel #4
0
        /// <summary>
        /// Adds all downward edges.
        /// </summary>
        /// <param name="graph"></param>
        public static void AddDownwardEdges(this IDynamicGraph <CHEdgeData> graph)
        { // add the reverse edges to get a easy depth-first search.
            for (uint vertexId = 1; vertexId < graph.VertexCount; vertexId++)
            {
                List <KeyValuePair <uint, CHEdgeData> > arcs =
                    new List <KeyValuePair <uint, CHEdgeData> >(graph.GetArcs(vertexId));
                foreach (KeyValuePair <uint, CHEdgeData> arc in arcs)
                {
                    if (arc.Value.ToHigher)
                    {
                        // create severse edge.
                        CHEdgeData reverseEdge = new CHEdgeData();
                        reverseEdge.SetDirection(arc.Value.Backward, arc.Value.Forward, false);
                        reverseEdge.Weight = arc.Value.Weight;

                        graph.AddArc(arc.Key, vertexId, reverseEdge, null);
                    }
                }
            }
        }
Beispiel #5
0
        /// <summary>
        /// Returns the exact inverse of this edge.
        /// </summary>
        /// <returns></returns>
        public IGraphEdgeData Reverse()
        {
            var reverse = new CHEdgeData();

            // forward/backward specific info.
            reverse.BackwardWeight = this.ForwardWeight;
            reverse.BackwardContractedId = this.ForwardContractedId;
            reverse.ForwardContractedId = this.BackwardContractedId;
            reverse.ForwardWeight = this.BackwardWeight;

            // tags.
            reverse.Tags = this.Tags;
            reverse.TagsForward = !this.TagsForward;

            // contracted direction info.
            reverse._contractedDirection = this._contractedDirection;
            switch(_contractedDirection)
            {
                case 1:
                    reverse._contractedDirection = 2;
                    break;
                case 2:
                    reverse._contractedDirection = 1;
                    break;
            }
            return reverse;
        }
Beispiel #6
0
        /// <summary>
        /// Contracts the given vertex.
        /// </summary>
        /// <param name="vertex"></param>
        public void Contract(uint vertex)
        {
            if (_contracted.Length > vertex && _contracted[vertex])
            {
                throw new Exception("Is already contracted!");
            }

            // keep the neighbours.
            HashSet<KeyValuePair<uint, CHEdgeData>> neighbours =
                new HashSet<KeyValuePair<uint, CHEdgeData>>();

            // get all information from the source.
            KeyValuePair<uint, CHEdgeData>[] edges = _target.GetArcs(vertex);

            // remove all informative edges.
            edges = edges.RemoveInformativeEdges();

            // report the before contraction event.
            this.OnBeforeContraction(vertex, edges);

            // remove the edges from the neighbours to the target.
            foreach (KeyValuePair<uint, CHEdgeData> edge in edges)
            { // remove the edge.
                _target.DeleteArc(edge.Key, vertex);

                // keep the neighbour.
                if (_keepDirectNeighbours && !edge.Value.HasContractedVertex)
                { // edge does represent a neighbour relation.
                    neighbours.Add(
                        new KeyValuePair<uint, CHEdgeData>(edge.Key, edge.Value.ConvertToInformative()));
                }
            }

            // loop over each combination of edges just once.
            for (int x = 1; x < edges.Length; x++)
            { // loop over all elements first.
                KeyValuePair<uint, CHEdgeData> xEdge = edges[x];
                if (xEdge.Value.IsInformative) { continue; }

                for (int y = 0; y < x; y++)
                { // loop over all elements.
                    KeyValuePair<uint, CHEdgeData> yEdge = edges[y];
                    if (yEdge.Value.IsInformative) { continue; }

                    // calculate the total weight.
                    float weight = xEdge.Value.Weight + yEdge.Value.Weight;

                    // add the combinations of these edges.
                    if (((xEdge.Value.Backward && yEdge.Value.Forward) ||
                        (yEdge.Value.Backward && xEdge.Value.Forward)) &&
                        (xEdge.Key != yEdge.Key))
                    { // there is a connection from x to y and there is no witness path.
                        bool witnessXToY = _witnessCalculator.Exists(_target, xEdge.Key,
                            yEdge.Key, vertex, weight, 100);
                        bool witnessYToX = _witnessCalculator.Exists(_target, yEdge.Key,
                            xEdge.Key, vertex, weight, 100);

                        // create x-to-y data and edge.
                        CHEdgeData dataXToY = new CHEdgeData();
                        bool forward = (xEdge.Value.Backward && yEdge.Value.Forward) &&
                            !witnessXToY;
                        bool backward = (yEdge.Value.Backward && xEdge.Value.Forward) &&
                            !witnessYToX;
                        dataXToY.SetDirection(forward, backward, true);
                        dataXToY.Weight = weight;
                        dataXToY.ContractedVertexId = vertex;
                        if ((dataXToY.Forward || dataXToY.Backward) ||
                            !_target.HasArc(xEdge.Key, yEdge.Key))
                        { // add the edge if there is usefull info or if there needs to be a neighbour relationship.
                            _target.AddArc(xEdge.Key, yEdge.Key, dataXToY, _comparer);
                        }

                        // create y-to-x data and edge.
                        CHEdgeData dataYToX = new CHEdgeData();
                        forward = (yEdge.Value.Backward && xEdge.Value.Forward) &&
                            !witnessYToX;
                        backward = (xEdge.Value.Backward && yEdge.Value.Forward) &&
                            !witnessXToY;
                        dataYToX.SetDirection(forward, backward, true);
                        dataYToX.Weight = weight;
                        dataYToX.ContractedVertexId = vertex;
                        if ((dataYToX.Forward || dataYToX.Backward) ||
                            !_target.HasArc(yEdge.Key, xEdge.Key))
                        { // add the edge if there is usefull info or if there needs to be a neighbour relationship.
                            _target.AddArc(yEdge.Key, xEdge.Key, dataYToX, _comparer);
                        }
                    }
                }
            }

            // mark the vertex as contracted.
            this.MarkContracted(vertex);

            // notify a contracted neighbour.
            _calculator.NotifyContracted(vertex);

            // add contracted neighbour edges again.
            if (_keepDirectNeighbours)
            {
                foreach (KeyValuePair<uint, CHEdgeData> neighbour in neighbours)
                {
                    _target.AddArc(neighbour.Key, vertex, neighbour.Value, null);
                }
            }

            // report the after contraction event.
            this.OnAfterContraction(vertex, edges);
        }
Beispiel #7
0
        /// <summary>
        /// Contracts the given vertex.
        /// </summary>
        /// <param name="vertex"></param>
        public void Contract(uint vertex)
        {
            if (this.IsContracted(vertex))
            {
                throw new Exception("Is already contracted!");
            }

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

            // report the before contraction event.
            this.OnBeforeContraction(vertex, edges);

            // build the list of edges to replace.
            var allNeigbours = 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.
                allNeigbours.Add(edge);
                tos.Add(edge.Neighbour);
                tosSet.Add(edge.Neighbour);

                // remove the edge in downwards direction and on the edge with the same data.
                _target.RemoveEdge(edge.Neighbour, vertex);
            }

            //// build the list of pairs and make sure duplicates don't count.
            //var allNeighbourPairs = new Dictionary<Tuple<uint, uint>, Tuple<float, float>>();
            //for(int x = 1; x < allNeigbours.Count; x++)
            //{
            //    var xEdge = allNeigbours[x];
            //    var xEdgeForwardWeight = xEdge.EdgeData.CanMoveBackward ? xEdge.EdgeData.Weight : float.MaxValue;
            //    var xEdgeBackwardWeight = xEdge.EdgeData.CanMoveForward ? xEdge.EdgeData.Weight : float.MaxValue;
            //    for(int y = 0; y < x; y++)
            //    {
            //        var yEdge = allNeigbours[x];
            //        //var yEdgeForwardWeight = yEdge.EdgeData.CanMoveBackward ? yEdge.EdgeData.Weight : float.MaxValue;
            //        //var yEdgeBackwardWeight = yEdge.EdgeData.CanMoveForward ? yEdge.EdgeData.Weight : float.MaxValue;
            //        float forwardWeight = float.MaxValue;
            //        float backwardWeight = float.MaxValue;
            //        if(xEdge.Neighbour < yEdge.Neighbour)
            //        {
            //            if (xEdge.EdgeData.CanMoveBackward && yEdge.EdgeData.CanMoveForward)
            //            {
            //                forwardWeight = xEdgeBackwardWeight + yEdge.EdgeData.Weight;
            //            }
            //            if (xEdge.EdgeData.CanMoveForward && yEdge.EdgeData.CanMoveBackward)
            //            {
            //                backwardWeight = xEdgeForwardWeight + yEdge.EdgeData.Weight;
            //            }
            //        }
            //        else if(xEdge.Neighbour > yEdge.Neighbour)
            //        {
            //            if (xEdge.EdgeData.CanMoveBackward && yEdge.EdgeData.CanMoveForward)
            //            {
            //                backwardWeight = xEdgeBackwardWeight + yEdge.EdgeData.Weight;
            //            }
            //            if (xEdge.EdgeData.CanMoveForward && yEdge.EdgeData.CanMoveBackward)
            //            {
            //                forwardWeight = xEdgeForwardWeight + yEdge.EdgeData.Weight;
            //            }
            //        }

            //        Tuple<float, float> existingWeights;
            //        Tuple<uint, uint> neighbourPair = new Tuple<uint,uint>(xEdge.Neighbour, yEdge.Neighbour);
            //        if(!allNeighbourPairs.TryGetValue(neighbourPair, out existingWeights))
            //        {
            //            if (existingWeights.Item1 < forwardWeight)
            //            {
            //                forwardWeight = existingWeights.Item1;
            //            }
            //            if (existingWeights.Item2 < backwardWeight)
            //            {
            //                backwardWeight = existingWeights.Item2;
            //            }
            //        }
            //        allNeighbourPairs[neighbourPair] = new Tuple<float, float>(forwardWeight, backwardWeight);
            //    }
            //}

            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[allNeigbours.Count];
            var backwardWitnesses = new bool[allNeigbours.Count];
            var weights = new List<float>(allNeigbours.Count);
            var edgesToY = new Dictionary<uint, Tuple<CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>>(allNeigbours.Count);
            for (int x = 1; x < allNeigbours.Count; x++)
            { // loop over all elements first.
                var xEdge = allNeigbours[x];

                // get edges.
                edgesToY.Clear();
                var rawEdgesToY = _target.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 = allNeigbours[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 (forwardUnknown || backwardUnknown)
                {
                    _contractionWitnessCalculator.Exists(_target, xEdge.Neighbour, tos, weights, int.MaxValue,
                        ref forwardWitnesses, ref backwardWitnesses);
                }

                for (int y = 0; y < x; y++)
                { // loop over all elements.
                    var yEdge = allNeigbours[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.
                            // 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 existingForwardWeight = float.MaxValue;
                            var existingBackwardWeight = float.MaxValue;
                            uint existingForwardContracted = 0;
                            uint existingBackwardContracted = 0;
                            var existingCanMoveForward = false;
                            var existingCanMoveBackward = false;
                            var existingEdges = _target.GetEdges(xEdge.Neighbour, yEdge.Neighbour);
                            existingEdgesToRemove.Clear();
                            while(existingEdges.MoveNext())
                            {
                                var existingEdgeData = existingEdges.EdgeData;
                                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.
                                        _target.RemoveEdge(xEdge.Neighbour, yEdge.Neighbour, existingEdgeToRemove);
                                    }
                                    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.
                                        _target.RemoveEdge(yEdge.Neighbour, xEdge.Neighbour, existingEdgeToRemoveBackward);
                                    }
                                }

                                // add remaining edges.
                                if (forwardEdges[0].HasValue) { _target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, forwardEdges[0].Value); }
                                if (forwardEdges[1].HasValue) { _target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, forwardEdges[1].Value); }
                                if (backwardEdges[0].HasValue) { _target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, backwardEdges[0].Value); }
                                if (backwardEdges[1].HasValue) { _target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, backwardEdges[1].Value); }

                                toRequeue.Add(xEdge.Neighbour);
                                toRequeue.Add(yEdge.Neighbour);
                            }
                            else
                            { // there is no edge, just add the data.
                                // add contracted edges like normal.
                                _target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(vertex, canMoveForward, canMoveBackward, weight));
                                _target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(vertex, canMoveBackward, canMoveForward, weight));

                                toRequeue.Add(xEdge.Neighbour);
                                toRequeue.Add(yEdge.Neighbour);
                            }
                        }
                    }
                }
            }

            // mark the vertex as contracted.
            this.MarkContracted(vertex);

            // notify a contracted neighbour.
            _calculator.NotifyContracted(vertex);

            // report the after contraction event.
            this.OnAfterContraction(vertex, allNeigbours);

            //// update priority of direct neighbours.
            //foreach (var neighbour in toRequeue)
            //{
            //    this.ReQueue(neighbour);
            //}
        }
Beispiel #8
0
        /// <summary>
        /// Contracts the given vertex.
        /// </summary>
        /// <param name="vertex"></param>
        public void Contract(uint vertex)
        {
            if (_contracted.Length > vertex && _contracted[vertex])
            {
                throw new Exception("Is already contracted!");
            }

            // keep the neighbours.
            HashSet <KeyValuePair <uint, CHEdgeData> > neighbours =
                new HashSet <KeyValuePair <uint, CHEdgeData> >();

            // get all information from the source.
            KeyValuePair <uint, CHEdgeData>[] edges = _target.GetArcs(vertex);

            // remove all informative edges.
            edges = edges.RemoveInformativeEdges();

            // report the before contraction event.
            this.OnBeforeContraction(vertex, edges);

            // remove the edges from the neighbours to the target.
            foreach (KeyValuePair <uint, CHEdgeData> edge in edges)
            { // remove the edge.
                _target.DeleteArc(edge.Key, vertex);

                // keep the neighbour.
                if (_keepDirectNeighbours && !edge.Value.HasContractedVertex)
                { // edge does represent a neighbour relation.
                    neighbours.Add(
                        new KeyValuePair <uint, CHEdgeData>(edge.Key, edge.Value.ConvertToInformative()));
                }
            }

            // loop over each combination of edges just once.
            for (int x = 1; x < edges.Length; x++)
            { // loop over all elements first.
                KeyValuePair <uint, CHEdgeData> xEdge = edges[x];
                if (xEdge.Value.IsInformative)
                {
                    continue;
                }

                for (int y = 0; y < x; y++)
                { // loop over all elements.
                    KeyValuePair <uint, CHEdgeData> yEdge = edges[y];
                    if (yEdge.Value.IsInformative)
                    {
                        continue;
                    }

                    // calculate the total weight.
                    float weight = xEdge.Value.Weight + yEdge.Value.Weight;

                    // add the combinations of these edges.
                    if (((xEdge.Value.Backward && yEdge.Value.Forward) ||
                         (yEdge.Value.Backward && xEdge.Value.Forward)) &&
                        (xEdge.Key != yEdge.Key))
                    { // there is a connection from x to y and there is no witness path.
                        bool witnessXToY = _witnessCalculator.Exists(_target, xEdge.Key,
                                                                     yEdge.Key, vertex, weight, 100);
                        bool witnessYToX = _witnessCalculator.Exists(_target, yEdge.Key,
                                                                     xEdge.Key, vertex, weight, 100);

                        // create x-to-y data and edge.
                        CHEdgeData dataXToY = new CHEdgeData();
                        bool       forward  = (xEdge.Value.Backward && yEdge.Value.Forward) &&
                                              !witnessXToY;
                        bool backward = (yEdge.Value.Backward && xEdge.Value.Forward) &&
                                        !witnessYToX;
                        dataXToY.SetDirection(forward, backward, true);
                        dataXToY.Weight             = weight;
                        dataXToY.ContractedVertexId = vertex;
                        if ((dataXToY.Forward || dataXToY.Backward) ||
                            !_target.HasArc(xEdge.Key, yEdge.Key))
                        { // add the edge if there is usefull info or if there needs to be a neighbour relationship.
                            _target.AddArc(xEdge.Key, yEdge.Key, dataXToY, _comparer);
                        }

                        // create y-to-x data and edge.
                        CHEdgeData dataYToX = new CHEdgeData();
                        forward = (yEdge.Value.Backward && xEdge.Value.Forward) &&
                                  !witnessYToX;
                        backward = (xEdge.Value.Backward && yEdge.Value.Forward) &&
                                   !witnessXToY;
                        dataYToX.SetDirection(forward, backward, true);
                        dataYToX.Weight             = weight;
                        dataYToX.ContractedVertexId = vertex;
                        if ((dataYToX.Forward || dataYToX.Backward) ||
                            !_target.HasArc(yEdge.Key, xEdge.Key))
                        { // add the edge if there is usefull info or if there needs to be a neighbour relationship.
                            _target.AddArc(yEdge.Key, xEdge.Key, dataYToX, _comparer);
                        }
                    }
                }
            }

            // mark the vertex as contracted.
            this.MarkContracted(vertex);

            // notify a contracted neighbour.
            _calculator.NotifyContracted(vertex);

            // add contracted neighbour edges again.
            if (_keepDirectNeighbours)
            {
                foreach (KeyValuePair <uint, CHEdgeData> neighbour in neighbours)
                {
                    _target.AddArc(neighbour.Key, vertex, neighbour.Value, null);
                }
            }

            // report the after contraction event.
            this.OnAfterContraction(vertex, edges);
        }
Beispiel #9
0
        /// <summary>
        /// Contracts the given vertex.
        /// </summary>
        /// <param name="vertex"></param>
        public void Contract(uint vertex)
        {
            if (this.IsContracted(vertex))
            {
                throw new Exception("Is already contracted!");
            }

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

            // report the before contraction event.
            this.OnBeforeContraction(vertex, edges);

            // replace the adjacent edges with edges that are point up.
            var edgesForContractions = new List<Edge<CHEdgeData>>(edges.Count);
            var tos = new List<uint>(edges.Count);
            foreach (var edge in edges)
            {
                if (!edge.EdgeData.ToLower)
                { // the edge is not to lower or higher.
                    // use this edge for contraction.
                    edgesForContractions.Add(edge);
                    tos.Add(edge.Neighbour);

                    // overwrite the old edge making it point 'to higher' only.
                    var toHigherData = edge.EdgeData;
                    toHigherData.SetContractedDirection(true, false);
                    ICoordinateCollection shape = null;
                    if (!_target.GetEdgeShape(vertex, edge.Neighbour, out shape))
                    {
                        shape = null;
                    }
                    _target.AddEdge(vertex, edge.Neighbour, toHigherData, shape);
                }
            }

            // loop over each combination of edges just once.
            int newEdge = 0;
            var witnesses = new bool[edgesForContractions.Count];
            var tosWeights = new List<float>(edgesForContractions.Count);
            var toRequeue = new HashSet<uint>();
            for (int x = 0; x < edgesForContractions.Count; x++)
            { // loop over all elements first.
                var xEdge = edgesForContractions[x];
                if (!xEdge.EdgeData.Backward) { continue; }

                // calculate max weight.
                tosWeights.Clear();
                for (int idx = 0; idx < edgesForContractions.Count; idx++)
                {
                    // update maxWeight.
                    var yEdge = edgesForContractions[idx];
                    if (xEdge.Neighbour != yEdge.Neighbour &&
                        yEdge.EdgeData.Forward)
                    {
                        // reset witnesses.
                        float weight = (float)xEdge.EdgeData.BackwardWeight + (float)yEdge.EdgeData.ForwardWeight;
                        witnesses[idx] = false;
                        tosWeights.Add(weight);
                    }
                    else
                    { // already set this to true, not use calculating it's witness.
                        witnesses[idx] = true;
                        tosWeights.Add(0);
                    }
                }

                _contractionWitnessCalculator.Exists(_target, xEdge.Neighbour, tos, tosWeights, int.MaxValue, ref witnesses);

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

                    // add the combinations of these edges.
                    if (yEdge.EdgeData.Forward &&
                        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 forward = (xEdge.EdgeData.Backward && yEdge.EdgeData.Forward) && !witnesses[y];

                        if (forward)
                        { // add the edge if there is usefull info or if there needs to be a neighbour relationship.
                            // calculate the total weight.
                            var forwardWeight = xEdge.EdgeData.BackwardWeight + yEdge.EdgeData.ForwardWeight;

                            CHEdgeData data;
                            if (_target.GetEdge(xEdge.Neighbour, yEdge.Neighbour, out data))
                            { // there already is an edge; evaluate for each direction.
                                if (forward && data.ForwardWeight > forwardWeight)
                                { // replace forward edge.
                                    ICoordinateCollection shape;
                                    if (data.RepresentsNeighbourRelations &&
                                        _target.GetEdgeShape(xEdge.Neighbour, yEdge.Neighbour, out shape) &&
                                        shape != null && shape.Count > 0)
                                    { // an edge that represents a relation between two neighbours and has shapes should never be replaced.
                                        // TODO: keep existing edge by inserting a dummy vertex for one of the shapes.
                                        // TODO: check if this is still needed because these case are supposed to be remove in osm->graph conversions.
                                        // WARNING: The assumption here is that the weight is in direct relation with the distance.
                                        var shapeCoordinates = new List<GeoCoordinateSimple>(shape.ToSimpleArray());
                                        float latitude, longitude;
                                        _target.GetVertex(xEdge.Neighbour, out latitude, out longitude);
                                        var previousCoordinate = new GeoCoordinate(shapeCoordinates[0]);
                                        var distanceFirst = (new GeoCoordinate(latitude, longitude)).DistanceEstimate(previousCoordinate).Value;
                                        var totalDistance = distanceFirst;
                                        for(int idx = 1; idx < shapeCoordinates.Count; idx++)
                                        {
                                            var currentCoordinate = new GeoCoordinate(shapeCoordinates[idx]);
                                            totalDistance = totalDistance + currentCoordinate.DistanceEstimate(previousCoordinate).Value;

                                            previousCoordinate = currentCoordinate;
                                        }
                                        _target.GetVertex(yEdge.Neighbour, out latitude, out longitude);
                                        totalDistance = totalDistance + previousCoordinate.DistanceEstimate(new GeoCoordinate(latitude, longitude)).Value;

                                        // calculate the new edge data's.
                                        float firstPartRatio = (float)(distanceFirst / totalDistance);
                                        float secondPartRatio = 1 - firstPartRatio;
                                        // REMARK: the edge being split can never have contracted id's because it would not have a shape.
                                        var firstPartEdgeData = new CHEdgeData()
                                        {
                                            BackwardContractedId = data.BackwardContractedId,
                                            BackwardWeight = data.BackwardWeight,
                                            ForwardContractedId = data.ForwardContractedId,
                                            ForwardWeight = data.ForwardWeight,
                                            Tags = data.Tags,
                                            TagsForward = data.TagsForward
                                        };
                                        var secondPartEdgeData = new CHEdgeData()
                                        {
                                            BackwardContractedId = data.BackwardContractedId,
                                            BackwardWeight = data.BackwardWeight,
                                            ForwardContractedId = data.ForwardContractedId,
                                            ForwardWeight = data.ForwardWeight,
                                            Tags = data.Tags,
                                            TagsForward = data.TagsForward
                                        };
                                        // calculate firstpart weights.
                                        if(data.Backward)
                                        {
                                            firstPartEdgeData.BackwardWeight = firstPartEdgeData.BackwardWeight * firstPartRatio;
                                            secondPartEdgeData.BackwardWeight = secondPartEdgeData.BackwardWeight * secondPartRatio;
                                        }
                                        if (data.Forward)
                                        {
                                            firstPartEdgeData.ForwardWeight = firstPartEdgeData.ForwardWeight * firstPartRatio;
                                            secondPartEdgeData.ForwardWeight = secondPartEdgeData.ForwardWeight * secondPartRatio;
                                        }

                                        // add intermediate vertex.
                                        var newVertex = _target.AddVertex(shapeCoordinates[0].Latitude, shapeCoordinates[0].Longitude);
                                        toRequeue.Add(newVertex); // immidiately queue for contraction.

                                        // add edge before.
                                        _target.AddEdge(xEdge.Neighbour, newVertex, firstPartEdgeData, null);

                                        // add edge after.
                                        var secondPartShape = shapeCoordinates.GetRange(1, shapeCoordinates.Count - 1);
                                        _target.AddEdge(newVertex, yEdge.Neighbour, secondPartEdgeData, new CoordinateArrayCollection<GeoCoordinateSimple>(secondPartShape.ToArray()));

                                        // remove original edge.
                                        _target.RemoveEdge(xEdge.Neighbour, yEdge.Neighbour);
                                    }

                                    toRequeue.Add(xEdge.Neighbour);
                                    newEdge++;
                                    data.ForwardWeight = forwardWeight;
                                    data.ForwardContractedId = vertex;
                                    _target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, data, null, _comparer);
                                }
                            }
                            else
                            { // there is no edge, just add the data.
                                var dataXToY = new CHEdgeData();
                                dataXToY.BackwardWeight = float.MaxValue;

                                dataXToY.SetContractedDirection(false, false);

                                toRequeue.Add(xEdge.Neighbour);
                                newEdge++;
                                dataXToY.ForwardWeight = forwardWeight;
                                dataXToY.ForwardContractedId = vertex;
                                _target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, dataXToY, null, _comparer);
                            }
                        }
                    }
                }
            }

            // update priority of direct neighbours.
            foreach (var neighbour in toRequeue)
            {
                this.ReQueue(neighbour);
            }

            // mark the vertex as contracted.
            this.MarkContracted(vertex);

            // notify a contracted neighbour.
            _calculator.NotifyContracted(vertex);

            // report the after contraction event.
            this.OnAfterContraction(vertex, edges);
        }
 /// <summary>
 /// Tests if the two given edges are compared correctly by the CHEdgeDataComparer.
 /// </summary>
 /// <param name="overapping"></param>
 /// <param name="overlappee"></param>
 private void DoTestCompare(CHEdgeData overapping, CHEdgeData overlappee, bool result)
 {
     CHEdgeDataComparer comparer = new CHEdgeDataComparer();
     if (result)
     {
         Assert.IsTrue(comparer.Overlaps(overapping, overlappee));
     }
     else
     {
         Assert.IsFalse(comparer.Overlaps(overapping, overlappee));
     }
 }
        /// <summary>
        /// Tests the set direction functionality for the given parameters.
        /// </summary>
        /// <param name="edge"></param>
        /// <param name="forward"></param>
        /// <param name="backward"></param>
        /// <param name="toHigher"></param>
        private void DoTestSetDirection(CHEdgeData edge, bool forward, bool backward, bool toHigher)
        {
            edge.SetDirection(forward, backward, toHigher);

            if (forward) { Assert.IsTrue(edge.Forward); }
            else { Assert.IsFalse(edge.Forward); }
            if (backward) { Assert.IsTrue(edge.Backward); }
            else { Assert.IsFalse(edge.Backward); }
            if (toHigher) { Assert.IsTrue(edge.ToHigher); }
            else { Assert.IsFalse(edge.ToHigher); }
        }
Beispiel #12
0
        /// <summary>
        /// Contracts the given vertex.
        /// </summary>
        /// <param name="vertex"></param>
        public void Contract(uint vertex)
        {
            if (_contracted.Length > vertex && _contracted[vertex])
            {
                throw new Exception("Is already contracted!");
            }

            // keep the neighbours.
            var neighbours = new HashSet <KeyValuePair <uint, CHEdgeData> >();

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

            // report the before contraction event.
            this.OnBeforeContraction(vertex, edges);

            // replace the adjacent edges with edges that are point up.
            var edgesForContractions = new List <KeyValuePair <uint, CHEdgeData> >(edges.Length);

            foreach (var edge in edges)
            {
                if (!edge.Value.ToLower && !edge.Value.ToHigher)
                { // the edge is not to lower or higher.
                    // use this edge for contraction.
                    edgesForContractions.Add(edge);

                    // overwrite the old edge making it point 'to higher' only.
                    _target.AddEdge(vertex, edge.Key,
                                    new CHEdgeData(edge.Value.Weight, edge.Value.Forward, edge.Value.Backward, true, edge.Value.ContractedVertexId, edge.Value.Tags), null);
                }
            }

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

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

                    // calculate the total weight.
                    var weight = xEdge.Value.Weight + yEdge.Value.Weight;

                    // add the combinations of these edges.
                    if (((xEdge.Value.Backward && yEdge.Value.Forward) ||
                         (yEdge.Value.Backward && xEdge.Value.Forward)) &&
                        (xEdge.Key != yEdge.Key))
                    { // there is a connection from x to y and there is no witness path.
                        var witnessXToY = _contractionWitnessCalculator.Exists(_target, xEdge.Key,
                                                                               yEdge.Key, vertex, weight, int.MaxValue);
                        var witnessYToX = _contractionWitnessCalculator.Exists(_target, yEdge.Key,
                                                                               xEdge.Key, vertex, weight, int.MaxValue);

                        // create x-to-y data and edge.
                        var dataXToY = new CHEdgeData();
                        var forward  = (xEdge.Value.Backward && yEdge.Value.Forward) &&
                                       !witnessXToY;
                        var backward = (yEdge.Value.Backward && xEdge.Value.Forward) &&
                                       !witnessYToX;
                        if ((forward || backward) ||
                            !_target.ContainsEdge(xEdge.Key, yEdge.Key))
                        { // add the edge if there is usefull info or if there needs to be a neighbour relationship.
                            dataXToY.SetDirection(forward, backward);
                            dataXToY.Weight             = weight;
                            dataXToY.ContractedVertexId = vertex;

                            _target.AddEdge(xEdge.Key, yEdge.Key, dataXToY, null, _comparer);
                        }
                    }
                }
            }

            // mark the vertex as contracted.
            this.MarkContracted(vertex);

            // notify a contracted neighbour.
            _calculator.NotifyContracted(vertex);

            // report the after contraction event.
            this.OnAfterContraction(vertex, edges);
        }
Beispiel #13
0
        /// <summary>
        /// Contracts the given vertex.
        /// </summary>
        /// <param name="vertex"></param>
        public void Contract(uint vertex)
        {
            if (this.IsContracted(vertex))
            {
                throw new Exception("Is already contracted!");
            }

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

            // report the before contraction event.
            this.OnBeforeContraction(vertex, edges);

            // build the list of edges to replace.
            var allNeigbours = 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.
                allNeigbours.Add(edge);
                tos.Add(edge.Neighbour);
                tosSet.Add(edge.Neighbour);

                // remove the edge in downwards direction and on the edge with the same data.
                _target.RemoveEdge(edge.Neighbour, vertex);
            }

            //// build the list of pairs and make sure duplicates don't count.
            //var allNeighbourPairs = new Dictionary<Tuple<uint, uint>, Tuple<float, float>>();
            //for(int x = 1; x < allNeigbours.Count; x++)
            //{
            //    var xEdge = allNeigbours[x];
            //    var xEdgeForwardWeight = xEdge.EdgeData.CanMoveBackward ? xEdge.EdgeData.Weight : float.MaxValue;
            //    var xEdgeBackwardWeight = xEdge.EdgeData.CanMoveForward ? xEdge.EdgeData.Weight : float.MaxValue;
            //    for(int y = 0; y < x; y++)
            //    {
            //        var yEdge = allNeigbours[x];
            //        //var yEdgeForwardWeight = yEdge.EdgeData.CanMoveBackward ? yEdge.EdgeData.Weight : float.MaxValue;
            //        //var yEdgeBackwardWeight = yEdge.EdgeData.CanMoveForward ? yEdge.EdgeData.Weight : float.MaxValue;
            //        float forwardWeight = float.MaxValue;
            //        float backwardWeight = float.MaxValue;
            //        if(xEdge.Neighbour < yEdge.Neighbour)
            //        {
            //            if (xEdge.EdgeData.CanMoveBackward && yEdge.EdgeData.CanMoveForward)
            //            {
            //                forwardWeight = xEdgeBackwardWeight + yEdge.EdgeData.Weight;
            //            }
            //            if (xEdge.EdgeData.CanMoveForward && yEdge.EdgeData.CanMoveBackward)
            //            {
            //                backwardWeight = xEdgeForwardWeight + yEdge.EdgeData.Weight;
            //            }
            //        }
            //        else if(xEdge.Neighbour > yEdge.Neighbour)
            //        {
            //            if (xEdge.EdgeData.CanMoveBackward && yEdge.EdgeData.CanMoveForward)
            //            {
            //                backwardWeight = xEdgeBackwardWeight + yEdge.EdgeData.Weight;
            //            }
            //            if (xEdge.EdgeData.CanMoveForward && yEdge.EdgeData.CanMoveBackward)
            //            {
            //                forwardWeight = xEdgeForwardWeight + yEdge.EdgeData.Weight;
            //            }
            //        }

            //        Tuple<float, float> existingWeights;
            //        Tuple<uint, uint> neighbourPair = new Tuple<uint,uint>(xEdge.Neighbour, yEdge.Neighbour);
            //        if(!allNeighbourPairs.TryGetValue(neighbourPair, out existingWeights))
            //        {
            //            if (existingWeights.Item1 < forwardWeight)
            //            {
            //                forwardWeight = existingWeights.Item1;
            //            }
            //            if (existingWeights.Item2 < backwardWeight)
            //            {
            //                backwardWeight = existingWeights.Item2;
            //            }
            //        }
            //        allNeighbourPairs[neighbourPair] = new Tuple<float, float>(forwardWeight, backwardWeight);
            //    }
            //}

            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[allNeigbours.Count];
            var backwardWitnesses = new bool[allNeigbours.Count];
            var weights           = new List <float>(allNeigbours.Count);
            var edgesToY          = new Dictionary <uint, Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> >(allNeigbours.Count);

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

                // get edges.
                edgesToY.Clear();
                var rawEdgesToY = _target.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 = allNeigbours[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 (forwardUnknown || backwardUnknown)
                {
                    _contractionWitnessCalculator.Exists(_target, xEdge.Neighbour, tos, weights, int.MaxValue,
                                                         ref forwardWitnesses, ref backwardWitnesses);
                }

                for (int y = 0; y < x; y++)
                { // loop over all elements.
                    var yEdge = allNeigbours[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.
                            // 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  existingForwardWeight      = float.MaxValue;
                            var  existingBackwardWeight     = float.MaxValue;
                            uint existingForwardContracted  = 0;
                            uint existingBackwardContracted = 0;
                            var  existingCanMoveForward     = false;
                            var  existingCanMoveBackward    = false;
                            var  existingEdges = _target.GetEdges(xEdge.Neighbour, yEdge.Neighbour);
                            existingEdgesToRemove.Clear();
                            while (existingEdges.MoveNext())
                            {
                                var existingEdgeData = existingEdges.EdgeData;
                                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.
                                        _target.RemoveEdge(xEdge.Neighbour, yEdge.Neighbour, existingEdgeToRemove);
                                    }
                                    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.
                                        _target.RemoveEdge(yEdge.Neighbour, xEdge.Neighbour, existingEdgeToRemoveBackward);
                                    }
                                }

                                // add remaining edges.
                                if (forwardEdges[0].HasValue)
                                {
                                    _target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, forwardEdges[0].Value);
                                }
                                if (forwardEdges[1].HasValue)
                                {
                                    _target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, forwardEdges[1].Value);
                                }
                                if (backwardEdges[0].HasValue)
                                {
                                    _target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, backwardEdges[0].Value);
                                }
                                if (backwardEdges[1].HasValue)
                                {
                                    _target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, backwardEdges[1].Value);
                                }

                                toRequeue.Add(xEdge.Neighbour);
                                toRequeue.Add(yEdge.Neighbour);
                            }
                            else
                            { // there is no edge, just add the data.
                                // add contracted edges like normal.
                                _target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(vertex, canMoveForward, canMoveBackward, weight));
                                _target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(vertex, canMoveBackward, canMoveForward, weight));

                                toRequeue.Add(xEdge.Neighbour);
                                toRequeue.Add(yEdge.Neighbour);
                            }
                        }
                    }
                }
            }

            // mark the vertex as contracted.
            this.MarkContracted(vertex);

            // notify a contracted neighbour.
            _calculator.NotifyContracted(vertex);

            // report the after contraction event.
            this.OnAfterContraction(vertex, allNeigbours);

            //// update priority of direct neighbours.
            //foreach (var neighbour in toRequeue)
            //{
            //    this.ReQueue(neighbour);
            //}
        }
Beispiel #14
0
        /// <summary>
        /// Contracts the given vertex.
        /// </summary>
        /// <param name="vertex"></param>
        public void Contract(uint vertex)
        {
            if (_contracted.Length > vertex && _contracted[vertex])
            {
                throw new Exception("Is already contracted!");
            }

            // keep the neighbours.
            HashSet<uint> neighbours = new HashSet<uint>();

            // get all information from the source.
            KeyValuePair<uint, CHEdgeData>[] edges = _target.GetArcs(vertex);

            // report the before contraction event.
            this.OnBeforeContraction(vertex, edges);

            // remove the edges from the neighbours to the target.
            foreach (KeyValuePair<uint, CHEdgeData> edge in edges)
            { // remove the edge.
                _target.DeleteArc(edge.Key, vertex);

                // keep the neighbour.
                neighbours.Add(edge.Key);
            }

            // loop over each combination of edges just once.
            for (int x = 1; x < edges.Length; x++)
            { // loop over all elements first.
                KeyValuePair<uint, CHEdgeData> x_edge = edges[x];

                //System.Threading.Tasks.Parallel.For(0, x, y =>
                for (int y = 0; y < x; y++)
                { // loop over all elements.
                    KeyValuePair<uint, CHEdgeData> y_edge = edges[y];

                    // calculate the total weight.
                    float weight = x_edge.Value.Weight + y_edge.Value.Weight;

                    // add the combinations of these edges.
                    if ((x_edge.Value.Backward && y_edge.Value.Forward) ||
                        (y_edge.Value.Backward && x_edge.Value.Forward))
                    { // there is a connection from x to y and there is no witness path.

                        bool witness_x_to_y = _witness_calculator.Exists(x_edge.Key, y_edge.Key, vertex, weight, 100);
                        bool witness_y_to_x = _witness_calculator.Exists(y_edge.Key, x_edge.Key, vertex, weight, 100);

                        // create x-to-y data and edge.
                        CHEdgeData data_x_to_y = new CHEdgeData();
                        data_x_to_y.Forward = (x_edge.Value.Backward && y_edge.Value.Forward) &&
                            !witness_x_to_y;
                        data_x_to_y.Backward = (y_edge.Value.Backward && x_edge.Value.Forward) &&
                            !witness_y_to_x;
                        data_x_to_y.Weight = weight;
                        data_x_to_y.ContractedVertexId = vertex;
                        if ((data_x_to_y.Forward || data_x_to_y.Backward) ||
                            !_target.HasNeighbour(x_edge.Key, y_edge.Key))
                        { // add the edge if there is usefull info or if there needs to be a neighbour relationship.
                            _target.AddArc(x_edge.Key, y_edge.Key, data_x_to_y, _comparer);
                        }

                        // create y-to-x data and edge.
                        CHEdgeData data_y_to_x = new CHEdgeData();
                        data_y_to_x.Forward = (y_edge.Value.Backward && x_edge.Value.Forward) &&
                            !witness_y_to_x;
                        data_y_to_x.Backward = (x_edge.Value.Backward && y_edge.Value.Forward) &&
                            !witness_x_to_y;
                        data_y_to_x.Weight = weight;
                        data_y_to_x.ContractedVertexId = vertex;
                        if ((data_y_to_x.Forward || data_y_to_x.Backward) ||
                            !_target.HasNeighbour(y_edge.Key, x_edge.Key))
                        { // add the edge if there is usefull info or if there needs to be a neighbour relationship.
                            _target.AddArc(y_edge.Key, x_edge.Key, data_y_to_x, _comparer);
                        }
                    }
                }
                //});
            }

            //// re-enqueue all the neigbours.
            //foreach (uint neighbour in neighbours)
            //{
            //    if (_queue.Remove(neighbour))
            //    {
            //        this.ReQueue(neighbour);
            //    }
            //    if (_contracted.Length > neighbour && _contracted[neighbour])
            //    { // vertex was neighbour but already contracted (= impossible)
            //        throw new Exception(string.Format("Vertex {0} has contracted neighbour: {1}!",
            //            vertex, neighbour));
            //    }
            //}

            // mark the vertex as contracted.
            this.MarkContracted(vertex);

            // notify a contracted neighbour.
            _calculator.NotifyContracted(vertex);

            // report the after contraction event.
            this.OnAfterContraction(vertex, edges);
        }