예제 #1
0
        /// <summary>
        /// Called when a backward vertex was found.
        /// </summary>
        /// <returns></returns>
        protected virtual bool BackwardVertexFound(int i, uint vertex, LinkedEdgePath <T> backwardVisit)
        {
            Dictionary <int, LinkedEdgePath <T> > bucket;

            if (_buckets.TryGetValue(vertex, out bucket))
            {
                var edgeEnumerator = _graph.GetEdgeEnumerator();

                var originalBackwardVisit = backwardVisit;
                foreach (var pair in bucket)
                {
                    var best = _weights[pair.Key][i];

                    var forwardVisit = pair.Value;
                    while (forwardVisit != null)
                    {
                        var forwardCurrent = forwardVisit.Path;
                        if (_weightHandler.IsLargerThan(forwardCurrent.Weight, best))
                        {
                            forwardVisit = forwardVisit.Next;
                            continue;
                        }
                        backwardVisit = originalBackwardVisit;
                        while (backwardVisit != null)
                        {
                            var backwardCurrent    = backwardVisit.Path;
                            var totalCurrentWeight = _weightHandler.Add(forwardCurrent.Weight, backwardCurrent.Weight);
                            if (_weightHandler.IsSmallerThan(totalCurrentWeight, best))
                            { // potentially a weight improvement.
                                var allowed = true;

                                // check u-turn.
                                var sequence2Forward = backwardCurrent.GetSequence2(edgeEnumerator);
                                var sequence2Current = forwardCurrent.GetSequence2(edgeEnumerator);
                                if (sequence2Current != null && sequence2Current.Length > 0 &&
                                    sequence2Forward != null && sequence2Forward.Length > 0)
                                {
                                    if (sequence2Current[sequence2Current.Length - 1] ==
                                        sequence2Forward[sequence2Forward.Length - 1])
                                    {
                                        allowed = false;
                                    }
                                }

                                if (allowed)
                                {
                                    best = totalCurrentWeight;
                                }
                            }
                            backwardVisit = backwardVisit.Next;
                        }
                        forwardVisit = forwardVisit.Next;
                    }

                    _weights[pair.Key][i] = best;
                }
            }
            return(false);
        }
예제 #2
0
        /// <summary>
        /// Called when a forward vertex was found.
        /// </summary>
        /// <returns></returns>
        protected bool ForwardVertexFound(int i, uint vertex, LinkedEdgePath <T> visit)
        {
            Dictionary <int, LinkedEdgePath <T> > bucket;

            if (!_buckets.TryGetValue(vertex, out bucket))
            {
                bucket = new Dictionary <int, LinkedEdgePath <T> >();
                _buckets.Add(vertex, bucket);
            }
            bucket[i] = visit;
            return(false);
        }
예제 #3
0
 /// <summary>
 /// Returns true if the given vertex was visited and sets the visits output parameter with the actual visits data.
 /// </summary>
 /// <returns></returns>
 public bool TryGetVisits(uint vertex, out LinkedEdgePath <T> visits)
 {
     return(_visits.TryGetValue(vertex, out visits));
 }
예제 #4
0
        /// <summary>
        /// Executes one step in the search.
        /// </summary>
        public bool Step()
        {
            if (_heap.Count == 0)
            {
                return(false);
            }
            _current = _heap.Pop();
            while (_current != null)
            { // keep trying.
                LinkedEdgePath <T> edgePath = null;
                if (!_visits.TryGetValue(_current.Vertex, out edgePath))
                { // this vertex has not been visited before.
                    _visits.Add(_current.Vertex, new LinkedEdgePath <T>()
                    {
                        Path = _current
                    });
                    break;
                }
                else
                {     // vertex has been visited before, check if edge has.
                    if (!edgePath.HasPath(_current))
                    { // current edge has not been used to get to this vertex.
                        _visits[_current.Vertex] = new LinkedEdgePath <T>()
                        {
                            Path = _current,
                            Next = edgePath
                        };
                        break;
                    }
                }
                _current = _heap.Pop();
            }

            if (_current == null)
            {
                return(false);
            }

            if (this.WasFound != null)
            {
                this.WasFound(_current.Vertex, _current.Weight);
            }

            // get relevant restrictions.
            var restrictions = _getRestrictions(_current.Vertex);

            // get the edge enumerator.
            var currentSequence = _current.GetSequence2(_edgeEnumerator);

            currentSequence = currentSequence.Append(_current.Vertex);

            // get neighbours.
            _edgeEnumerator.MoveTo(_current.Vertex);

            // add the neighbours to the queue.
            while (_edgeEnumerator.MoveNext())
            {
                bool?neighbourDirection;
                var  neighbourWeight = _weightHandler.GetEdgeWeight(_edgeEnumerator.Current, out neighbourDirection);

                if (neighbourDirection == null || (neighbourDirection.Value != _backward))
                { // the edge is forward, and is to higher or was not contracted at all.
                    var neighbourNeighbour = _edgeEnumerator.Neighbour;
                    var neighbourSequence  = Constants.EMPTY_SEQUENCE;
                    if (_edgeEnumerator.IsOriginal())
                    {     // original edge.
                        if (currentSequence.Length > 1 && currentSequence[currentSequence.Length - 2] == neighbourNeighbour)
                        { // this is a u-turn.
                            continue;
                        }
                        if (restrictions != null)
                        {
                            neighbourSequence = currentSequence.Append(neighbourNeighbour);
                        }
                    }
                    else
                    { // not an original edge, use the sequence.
                        neighbourSequence = _edgeEnumerator.GetSequence1();
                        if (currentSequence.Length > 1 && currentSequence[currentSequence.Length - 2] == neighbourSequence[0])
                        { // this is a u-turn.
                            continue;
                        }
                        if (restrictions != null)
                        {
                            neighbourSequence = currentSequence.Append(neighbourSequence);
                        }
                    }

                    if (restrictions != null)
                    { // check restrictions.
                        if (!restrictions.IsSequenceAllowed(neighbourSequence))
                        {
                            continue;
                        }
                    }

                    // build route to neighbour and check if it has been visited already.
                    var routeToNeighbour = new EdgePath <T>(
                        neighbourNeighbour, _weightHandler.Add(_current.Weight, neighbourWeight), _edgeEnumerator.IdDirected(), _current);
                    LinkedEdgePath <T> edgePath = null;
                    if (!_visits.TryGetValue(_current.Vertex, out edgePath) ||
                        !edgePath.HasPath(routeToNeighbour))
                    { // this vertex has not been visited in this way before.
                        _heap.Push(routeToNeighbour, _weightHandler.GetMetric(routeToNeighbour.Weight));
                    }
                }
            }

            return(true);
        }
예제 #5
0
        /// <summary>
        /// Called when a backward vertex was found.
        /// </summary>
        /// <returns></returns>
        protected override bool BackwardVertexFound(int i, uint vertex, LinkedEdgePath <Weight> backwardVisit)
        {
            Dictionary <int, LinkedEdgePath <Weight> > bucket;

            if (_buckets.TryGetValue(vertex, out bucket))
            {
                var edgeEnumerator = _graph.GetEdgeEnumerator();

                var originalBackwardVisit = backwardVisit;
                foreach (var pair in bucket)
                {
                    var best = _weights[pair.Key][i];

                    var forwardVisit = pair.Value;
                    while (forwardVisit != null)
                    {
                        var forwardCurrent = forwardVisit.Path;
                        if (forwardCurrent.Weight.Value > best.Value)
                        {
                            forwardVisit = forwardVisit.Next;
                            continue;
                        }
                        backwardVisit = originalBackwardVisit;
                        while (backwardVisit != null)
                        {
                            var backwardCurrent    = backwardVisit.Path;
                            var totalCurrentWeight = new Weight()
                            {
                                Distance = forwardCurrent.Weight.Distance + backwardCurrent.Weight.Distance,
                                Time     = forwardCurrent.Weight.Time + backwardCurrent.Weight.Time,
                                Value    = forwardCurrent.Weight.Value + backwardCurrent.Weight.Value
                            };
                            if (totalCurrentWeight.Value < best.Value)
                            { // potentially a weight improvement.
                                var allowed = true;

                                // check u-turn.
                                var sequence2Forward = backwardCurrent.GetSequence2(edgeEnumerator);
                                var sequence2Current = forwardCurrent.GetSequence2(edgeEnumerator);
                                if (sequence2Current != null && sequence2Current.Length > 0 &&
                                    sequence2Forward != null && sequence2Forward.Length > 0)
                                {
                                    if (sequence2Current[sequence2Current.Length - 1] ==
                                        sequence2Forward[sequence2Forward.Length - 1])
                                    {
                                        allowed = false;
                                    }
                                }

                                if (allowed)
                                {
                                    best = totalCurrentWeight;
                                }
                            }
                            backwardVisit = backwardVisit.Next;
                        }
                        forwardVisit = forwardVisit.Next;
                    }

                    _weights[pair.Key][i] = best;
                }
            }
            return(false);
        }
예제 #6
0
        /// <summary>
        /// Executes the actual run.
        /// </summary>
        protected override void DoRun()
        {
            var edgeEnumerator = _graph.GetEdgeEnumerator();

            // keep settled vertices.
            _forwardVisits  = new Dictionary <uint, LinkedEdgePath>();
            _backwardVisits = new Dictionary <uint, LinkedEdgePath>();

            // initialize the queues.
            _forwardQueue  = new BinaryHeap <EdgePath <T> >();
            _backwardQueue = new BinaryHeap <EdgePath <T> >();

            // queue sources.
            foreach (var source in _sources)
            {
                _forwardQueue.Push(source, _weightHandler.GetMetric(source.Weight));
            }

            // queue targets.
            foreach (var target in _targets)
            {
                _backwardQueue.Push(target, _weightHandler.GetMetric(target.Weight));
            }

            // update best with current visits.
            _best = new Tuple <EdgePath <T>, EdgePath <T>, T>(new EdgePath <T>(), new EdgePath <T>(), _weightHandler.Infinite);

            // calculate stopping conditions.
            var queueBackwardWeight = _backwardQueue.PeekWeight();
            var queueForwardWeight  = _forwardQueue.PeekWeight();

            while (true)
            {     // keep looping until stopping conditions.
                if (_backwardQueue.Count == 0 && _forwardQueue.Count == 0)
                { // stop the search; both queues are empty.
                    break;
                }
                if (_weightHandler.GetMetric(_best.Item3) < queueForwardWeight &&
                    _weightHandler.GetMetric(_best.Item3) < queueBackwardWeight)
                { // stop the search: it now became impossible to find a better route by further searching.
                    break;
                }

                // do a forward search.
                if (_forwardQueue.Count > 0)
                { // first check for better path.
                    // get the current queued with the smallest weight that hasn't been visited yet.
                    var current = _forwardQueue.Pop();
                    while (current != null)
                    { // keep trying.
                        LinkedEdgePath edgePath = null;
                        if (!_forwardVisits.TryGetValue(current.Vertex, out edgePath))
                        { // this vertex has not been visited before.
                            _forwardVisits.Add(current.Vertex, new LinkedEdgePath()
                            {
                                Path = current
                            });
                            break;
                        }
                        else
                        {     // vertex has been visited before, check if edge has.
                            if (!edgePath.HasPath(current))
                            { // current edge has not been used to get to this vertex.
                                _forwardVisits[current.Vertex] = new LinkedEdgePath()
                                {
                                    Path = current,
                                    Next = edgePath
                                };
                                break;
                            }
                        }
                        current = _forwardQueue.Pop();
                    }

                    if (current != null)
                    {
                        // get relevant restrictions.
                        var restrictions = _getRestrictions(current.Vertex);

                        // check if there is a backward path that matches this vertex.
                        LinkedEdgePath backwardPath = null;
                        if (_backwardVisits.TryGetValue(current.Vertex, out backwardPath))
                        { // check for a new best.
                            while (backwardPath != null)
                            {
                                var totalCurrentWeight = _weightHandler.Add(current.Weight, backwardPath.Path.Weight);
                                if (_weightHandler.IsSmallerThan(totalCurrentWeight, _best.Item3))
                                { // potentially a weight improvement.
                                    var allowed = true;
                                    if (restrictions != null)
                                    {
                                        allowed = false;
                                        var sequence = new List <uint>(
                                            current.GetSequence2(edgeEnumerator));
                                        sequence.Reverse();
                                        sequence.Add(current.Vertex);
                                        var s1 = backwardPath.Path.GetSequence2(edgeEnumerator);
                                        sequence.AddRange(s1);

                                        allowed = restrictions.IsSequenceAllowed(sequence);
                                    }

                                    if (allowed)
                                    {
                                        _best = new Tuple <EdgePath <T>, EdgePath <T>, T>(current, backwardPath.Path,
                                                                                          _weightHandler.Add(current.Weight, backwardPath.Path.Weight));
                                        this.HasSucceeded = true;
                                    }
                                }
                                backwardPath = backwardPath.Next;
                            }
                        }

                        // continue the search.
                        this.SearchForward(edgeEnumerator, current, restrictions);
                    }
                }

                // do a backward search.
                if (_backwardQueue.Count > 0)
                {// first check for better path.
                    // get the current vertex with the smallest weight.
                    var current = _backwardQueue.Pop();
                    while (current != null)
                    { // keep trying.
                        LinkedEdgePath edgePath = null;
                        if (!_backwardVisits.TryGetValue(current.Vertex, out edgePath))
                        { // this vertex has not been visited before.
                            _backwardVisits.Add(current.Vertex, new LinkedEdgePath()
                            {
                                Path = current
                            });
                            break;
                        }
                        else
                        {     // vertex has been visited before, check if edge has.
                            if (!edgePath.HasPath(current))
                            { // current edge has not been used to get to this vertex.
                                _backwardVisits[current.Vertex] = new LinkedEdgePath()
                                {
                                    Path = current,
                                    Next = edgePath
                                };
                                break;
                            }
                        }
                        current = _backwardQueue.Pop();
                    }

                    if (current != null)
                    {
                        // get relevant restrictions.
                        var restrictions = _getRestrictions(current.Vertex);

                        // check if there is a backward path that matches this vertex.
                        LinkedEdgePath forwardPath = null;
                        if (_forwardVisits.TryGetValue(current.Vertex, out forwardPath))
                        { // check for a new best.
                            while (forwardPath != null)
                            {
                                var total = _weightHandler.Add(current.Weight, forwardPath.Path.Weight);
                                if (_weightHandler.IsSmallerThan(total, _best.Item3))
                                { // potentially a weight improvement.
                                    var allowed = true;
                                    if (restrictions != null)
                                    {
                                        allowed = false;
                                        var sequence = new List <uint>(
                                            forwardPath.Path.GetSequence2(edgeEnumerator));
                                        sequence.Add(current.Vertex);
                                        var s1 = current.GetSequence2(edgeEnumerator);
                                        s1.Reverse();
                                        sequence.AddRange(s1);

                                        allowed = restrictions.IsSequenceAllowed(sequence);
                                    }

                                    if (allowed)
                                    {
                                        _best = new Tuple <EdgePath <T>, EdgePath <T>, T>(forwardPath.Path, current,
                                                                                          _weightHandler.Add(current.Weight, forwardPath.Path.Weight));
                                        this.HasSucceeded = true;
                                    }
                                }
                                forwardPath = forwardPath.Next;
                            }
                        }

                        // continue the search.
                        this.SearchBackward(edgeEnumerator, current, restrictions);
                    }
                }

                // calculate stopping conditions.
                if (_forwardQueue.Count > 0)
                {
                    queueForwardWeight = _forwardQueue.PeekWeight();
                }
                if (_backwardQueue.Count > 0)
                {
                    queueBackwardWeight = _backwardQueue.PeekWeight();
                }
            }

            _forwardQueue  = null;
            _backwardQueue = null;
        }
예제 #7
0
        /// <summary>
        /// Search backward from one vertex.
        /// </summary>
        /// <returns></returns>
        private void SearchBackward(DirectedDynamicGraph.EdgeEnumerator edgeEnumerator, EdgePath <T> current, IEnumerable <uint[]> restrictions)
        {
            if (current != null)
            { // there is a next vertex found.
                // get the edge enumerator.
                var currentSequence = current.GetSequence2(edgeEnumerator);
                currentSequence = currentSequence.Append(current.Vertex);

                // get neighbours.
                edgeEnumerator.MoveTo(current.Vertex);

                // add the neighbours to the queue.
                while (edgeEnumerator.MoveNext())
                {
                    bool?neighbourDirection;
                    var  neighbourWeight = _weightHandler.GetEdgeWeight(edgeEnumerator.Current, out neighbourDirection);

                    if (neighbourDirection == null || !neighbourDirection.Value)
                    { // the edge is forward, and is to higher or was not contracted at all.
                        var neighbourNeighbour = edgeEnumerator.Neighbour;
                        var neighbourSequence  = Constants.EMPTY_SEQUENCE;
                        if (edgeEnumerator.IsOriginal())
                        {     // original edge.
                            if (currentSequence.Length > 1 && currentSequence[currentSequence.Length - 2] == neighbourNeighbour)
                            { // this is a u-turn.
                                continue;
                            }
                            if (restrictions != null)
                            {
                                neighbourSequence = currentSequence.Append(neighbourNeighbour);
                            }
                        }
                        else
                        { // not an original edge, use the sequence.
                            neighbourSequence = edgeEnumerator.GetSequence1();
                            if (currentSequence.Length > 1 && currentSequence[currentSequence.Length - 2] == neighbourSequence[0])
                            { // this is a u-turn.
                                continue;
                            }
                            if (restrictions != null)
                            {
                                neighbourSequence = currentSequence.Append(neighbourSequence);
                            }
                        }

                        if (restrictions != null)
                        { // check restrictions.
                            neighbourSequence.Reverse();
                            if (!restrictions.IsSequenceAllowed(neighbourSequence))
                            {
                                continue;
                            }
                        }

                        // build route to neighbour and check if it has been visited already.
                        var routeToNeighbour = new EdgePath <T>(
                            neighbourNeighbour, _weightHandler.Add(current.Weight, neighbourWeight), edgeEnumerator.IdDirected(), current);
                        LinkedEdgePath edgePath = null;
                        if (!_backwardVisits.TryGetValue(current.Vertex, out edgePath) ||
                            !edgePath.HasPath(routeToNeighbour))
                        { // this vertex has not been visited in this way before.
                            _backwardQueue.Push(routeToNeighbour, _weightHandler.GetMetric(routeToNeighbour.Weight));
                        }
                    }
                }
            }
        }