/// <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); }
/// <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); }
/// <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)); }
/// <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); }
/// <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); }
/// <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; }
/// <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)); } } } } }