/// <summary> /// Adds or updates the weight for the given edge. /// </summary> public void AddOrUpdate(OriginalEdge edge, Shortcut <T> shortcut, WeightHandler <T> weightHandler) { Shortcut <T> existing; if (!_data.TryGetValue(edge, out existing)) { _data[edge] = shortcut; return; } // update existing. var existingForward = weightHandler.GetMetric(existing.Forward); var newForward = weightHandler.GetMetric(shortcut.Forward); if (existingForward == 0 || existingForward > newForward) { existing.Forward = shortcut.Forward; } var existingBackward = weightHandler.GetMetric(existing.Backward); var newBackward = weightHandler.GetMetric(shortcut.Backward); if (existingBackward == 0 || existingBackward > newBackward) { existing.Backward = shortcut.Backward; } _data[edge] = existing; }
/// <summary> /// Initializes and resets. /// </summary> public void Initialize() { // algorithm always succeeds, it may be dealing with an empty network and there are no targets. this.HasSucceeded = true; // intialize dykstra data structures. _visits = new Dictionary <uint, EdgePath <T> >(); _heap = new BinaryHeap <EdgePath <T> >(1000); // queue all sources. foreach (var source in _sources) { if (_getRestriction != null) { var restriction = _getRestriction(source.Vertex); if (restriction != Constants.NO_VERTEX) { continue; } } _heap.Push(source, _weightHandler.GetMetric(source.Weight)); } // gets the edge enumerator. _edgeEnumerator = _graph.GetEdgeEnumerator(); }
/// <summary> /// Contracts the given vertex. /// </summary> private void Contract() { var vertex = _vertexInfo.Vertex; var enumerator = _graph.GetEdgeEnumerator(); // remove 'downward' edge to vertex. var i = 0; while (i < _vertexInfo.Count) { var edge = _vertexInfo[i]; _graph.RemoveEdge(edge.Neighbour, vertex); i++; } // add shortcuts. foreach (var s in _vertexInfo.Shortcuts) { var shortcut = s.Value; var edge = s.Key; var forwardMetric = _weightHandler.GetMetric(shortcut.Forward); var backwardMetric = _weightHandler.GetMetric(shortcut.Backward); if (forwardMetric > 0 && forwardMetric < float.MaxValue && backwardMetric > 0 && backwardMetric < float.MaxValue && System.Math.Abs(backwardMetric - forwardMetric) < HierarchyBuilder <float> .E) { // forward and backward and identical weights. _weightHandler.AddOrUpdateEdge(_graph, edge.Vertex1, edge.Vertex2, vertex, null, shortcut.Forward); _weightHandler.AddOrUpdateEdge(_graph, edge.Vertex2, edge.Vertex1, vertex, null, shortcut.Backward); } else { if (forwardMetric > 0 && forwardMetric < float.MaxValue) { _weightHandler.AddOrUpdateEdge(_graph, edge.Vertex1, edge.Vertex2, vertex, true, shortcut.Forward); _weightHandler.AddOrUpdateEdge(_graph, edge.Vertex2, edge.Vertex1, vertex, false, shortcut.Forward); } if (backwardMetric > 0 && backwardMetric < float.MaxValue) { _weightHandler.AddOrUpdateEdge(_graph, edge.Vertex1, edge.Vertex2, vertex, false, shortcut.Backward); _weightHandler.AddOrUpdateEdge(_graph, edge.Vertex2, edge.Vertex1, vertex, true, shortcut.Backward); } } } _contractedFlags[vertex] = true; this.NotifyContracted(vertex); }
/// <summary> /// Initializes and resets. /// </summary> public void Initialize() { // algorithm always succeeds, it may be dealing with an empty network and there are no targets. this.HasSucceeded = true; // intialize dykstra data structures. _visits = new Dictionary <uint, LinkedEdgePath <T> >(); _heap = new BinaryHeap <EdgePath <T> >(); // queue all sources. foreach (var source in _sources) { _heap.Push(source, _weightHandler.GetMetric(source.Weight)); } // gets the edge enumerator. _edgeEnumerator = _graph.GetEdgeEnumerator(); }
/// <summary> /// Executes one step in the search. /// </summary> public bool Step() { if (_pointerHeap.Count == 0) { return(false); } var cPointer = _pointerHeap.Pop(); uint cVertex, cPrevious; T cWeight; _weightHandler.GetPathTree(_pathTree, cPointer, out cVertex, out cWeight, out cPrevious); if (_visited.Contains(cVertex)) { return(true); } _visited.Add(cVertex); if (this.WasFound != null) { if (this.WasFound(cPointer, cVertex, cWeight)) { // when true is returned, the listener signals it knows what it wants to know. return(false); } } _edgeEnumerator.MoveTo(cVertex); while (_edgeEnumerator.MoveNext()) { var nWeight = _weightHandler.GetEdgeWeight(_edgeEnumerator); if ((!_backward && nWeight.Direction.F) || (_backward && nWeight.Direction.B)) { // the edge is forward, and is to higher or was not contracted at all. var nVertex = _edgeEnumerator.Neighbour; var totalWeight = _weightHandler.Add(nWeight.Weight, cWeight); if (!_weightHandler.IsSmallerThan(totalWeight, _max)) { continue; } var nPointer = _weightHandler.AddPathTree(_pathTree, nVertex, totalWeight, cPointer); _pointerHeap.Push(nPointer, _weightHandler.GetMetric(totalWeight)); } } return(true); }
/// <summary> /// Calculates all routes between all sources and all targets. /// </summary> /// <returns></returns> public sealed override Result <T[][]> TryCalculateWeight <T>(IProfileInstance profileInstance, WeightHandler <T> weightHandler, RouterPoint[] sources, RouterPoint[] targets, ISet <int> invalidSources, ISet <int> invalidTargets, RoutingSettings <T> settings) { try { if (!_db.Supports(profileInstance.Profile)) { return(new Result <T[][]>("Routing profile is not supported.", (message) => { return new Exception(message); })); } var maxSearch = weightHandler.Infinite; if (settings != null) { if (!settings.TryGetMaxSearch(profileInstance.Profile.FullName, out maxSearch)) { maxSearch = weightHandler.Infinite; } } ContractedDb contracted; T[][] weights = null; bool useContracted = false; if (_db.TryGetContracted(profileInstance.Profile, out contracted)) { // contracted calculation. useContracted = true; if (_db.HasComplexRestrictions(profileInstance.Profile) && !contracted.HasEdgeBasedGraph) { // there is no edge-based graph for this profile but the db has complex restrictions, don't use the contracted graph. Logging.Logger.Log("Router", Logging.TraceEventType.Warning, "There is a vertex-based contracted graph but also complex restrictions. Not using the contracted graph, add an edge-based contracted graph."); useContracted = false; } if (!weightHandler.CanUse(contracted)) { // there is a contracted graph but it is not equipped to handle this weight-type. Logging.Logger.Log("Router", Logging.TraceEventType.Warning, "There is a contracted graph but it's not built for the given weight calculations, using the default but slow implementation."); useContracted = false; } } if (useContracted) { if (!contracted.HasEdgeBasedGraph) { // use node-based routing. var algorithm = new Itinero.Algorithms.Contracted.ManyToManyWeightsBidirectionalDykstra <T>(_db, profileInstance.Profile, weightHandler, sources, targets, maxSearch); algorithm.Run(); if (!algorithm.HasSucceeded) { return(new Result <T[][]>(algorithm.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } weights = algorithm.Weights; } else { // use edge-based routing. var algorithm = new Itinero.Algorithms.Contracted.EdgeBased.ManyToManyWeightsBidirectionalDykstra <T>(_db, profileInstance.Profile, weightHandler, sources, targets, maxSearch); algorithm.Run(); if (!algorithm.HasSucceeded) { return(new Result <T[][]>(algorithm.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } weights = algorithm.Weights; } } else { // use regular graph. if (_db.HasComplexRestrictions(profileInstance.Profile)) { var algorithm = new Itinero.Algorithms.Default.EdgeBased.ManyToMany <T>(this, weightHandler, _db.GetGetRestrictions(profileInstance.Profile, true), sources, targets, maxSearch); algorithm.Run(); if (!algorithm.HasSucceeded) { return(new Result <T[][]>(algorithm.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } weights = algorithm.Weights; } else { var algorithm = new Itinero.Algorithms.Default.ManyToMany <T>(_db, weightHandler, sources, targets, maxSearch); algorithm.Run(); if (!algorithm.HasSucceeded) { return(new Result <T[][]>(algorithm.ErrorMessage, (message) => { return new RouteNotFoundException(message); })); } weights = algorithm.Weights; } } // check for invalids. var invalidTargetCounts = new int[targets.Length]; for (var s = 0; s < weights.Length; s++) { var invalids = 0; for (var t = 0; t < weights[s].Length; t++) { if (t != s) { if (weightHandler.GetMetric(weights[s][t]) == float.MaxValue) { invalids++; invalidTargetCounts[t]++; if (invalidTargetCounts[t] > (sources.Length - 1) / 2) { invalidTargets.Add(t); } } } } if (invalids > (targets.Length - 1) / 2) { invalidSources.Add(s); } } return(new Result <T[][]>(weights)); } catch (Exception ex) { return(new Result <T[][]>(ex.Message, (m) => ex)); } }
public static bool RemoveShortcuts <T>(this VertexInfo <T> vertexInfo, DirectedGraph witnessGraph, WeightHandler <T> weightHandler) where T : struct { var witnessGraphEnumerator = witnessGraph.GetEdgeEnumerator(); List <Tuple <OriginalEdge, Shortcut <T> > > toUpdate = null; foreach (var pair in vertexInfo.Shortcuts) { var edge = pair.Key; if (edge.Vertex1 >= witnessGraph.VertexCount || edge.Vertex2 >= witnessGraph.VertexCount) { continue; } var shortcut = pair.Value; var shortcutForward = weightHandler.GetMetric(shortcut.Forward); var shortcutBackward = weightHandler.GetMetric(shortcut.Backward); var witnessedForward = float.MaxValue; var witnessedBackward = float.MaxValue; if (edge.Vertex1 < edge.Vertex2) { witnessGraphEnumerator.MoveTo(edge.Vertex1); while (witnessGraphEnumerator.MoveNext()) { if (witnessGraphEnumerator.Neighbour == edge.Vertex2) { witnessedForward = DirectedGraphExtensions.FromData(witnessGraphEnumerator.Data0); witnessedBackward = DirectedGraphExtensions.FromData(witnessGraphEnumerator.Data1); break; } } } else { witnessGraphEnumerator.MoveTo(edge.Vertex2); while (witnessGraphEnumerator.MoveNext()) { if (witnessGraphEnumerator.Neighbour == edge.Vertex1) { witnessedBackward = DirectedGraphExtensions.FromData(witnessGraphEnumerator.Data0); witnessedForward = DirectedGraphExtensions.FromData(witnessGraphEnumerator.Data1); break; } } } // check forward. var hasUpdates = false; if (shortcutForward > 0 && shortcutForward < float.MaxValue && shortcutForward - FastHierarchyBuilder <float> .E > witnessedForward) { shortcut.Forward = weightHandler.Infinite; hasUpdates = true; } if (shortcutBackward > 0 && shortcutBackward < float.MaxValue && shortcutBackward - FastHierarchyBuilder <float> .E > witnessedBackward) { shortcut.Backward = weightHandler.Infinite; hasUpdates = true; } if (hasUpdates) { if (toUpdate == null) { toUpdate = new List <Tuple <OriginalEdge, Shortcut <T> > >(); } toUpdate.Add(new Tuple <OriginalEdge, Shortcut <T> >(edge, shortcut)); } } if (toUpdate != null) { foreach (var update in toUpdate) { vertexInfo.Shortcuts[update.Item1] = update.Item2; } return(true); } return(false); }
/// <summary> /// Calculates the priority of this vertex. /// </summary> public static float Priority <T>(this VertexInfo <T> vertexInfo, DirectedMetaGraph graph, WeightHandler <T> weightHandler, float differenceFactor, float contractedFactor, float depthFactor, float weightDiffFactor = 1) where T : struct { var vertex = vertexInfo.Vertex; var removed = vertexInfo.Count; var added = 0; //var removedWeight = 0f; //var addedWeight = 0f; foreach (var shortcut in vertexInfo.Shortcuts) { var shortcutForward = weightHandler.GetMetric(shortcut.Value.Forward); var shortcutBackward = weightHandler.GetMetric(shortcut.Value.Backward); int localAdded, localRemoved; if (shortcutForward > 0 && shortcutForward < float.MaxValue && shortcutBackward > 0 && shortcutBackward < float.MaxValue && System.Math.Abs(shortcutForward - shortcutBackward) < HierarchyBuilder.E) { // add two bidirectional edges. graph.TryAddOrUpdateEdge(shortcut.Key.Vertex1, shortcut.Key.Vertex2, shortcutForward, null, vertex, out localAdded, out localRemoved); added += localAdded; removed += localRemoved; graph.TryAddOrUpdateEdge(shortcut.Key.Vertex2, shortcut.Key.Vertex1, shortcutForward, null, vertex, out localAdded, out localRemoved); added += localAdded; removed += localRemoved; //added += 2; //addedWeight += shortcutForward; //addedWeight += shortcutBackward; } else { if (shortcutForward > 0 && shortcutForward < float.MaxValue) { graph.TryAddOrUpdateEdge(shortcut.Key.Vertex1, shortcut.Key.Vertex2, shortcutForward, true, vertex, out localAdded, out localRemoved); added += localAdded; removed += localRemoved; graph.TryAddOrUpdateEdge(shortcut.Key.Vertex2, shortcut.Key.Vertex1, shortcutForward, false, vertex, out localAdded, out localRemoved); added += localAdded; removed += localRemoved; //added += 2; //addedWeight += shortcutForward; //addedWeight += shortcutForward; } if (shortcutBackward > 0 && shortcutBackward < float.MaxValue) { graph.TryAddOrUpdateEdge(shortcut.Key.Vertex1, shortcut.Key.Vertex2, shortcutBackward, false, vertex, out localAdded, out localRemoved); added += localAdded; removed += localRemoved; graph.TryAddOrUpdateEdge(shortcut.Key.Vertex2, shortcut.Key.Vertex1, shortcutBackward, true, vertex, out localAdded, out localRemoved); added += localAdded; removed += localRemoved; //added += 2; //addedWeight += shortcutBackward; //addedWeight += shortcutBackward; } } } //for (var e = 0; e < vertexInfo.Count; e++) //{ // var w = weightHandler.GetEdgeWeight(vertexInfo[e]); // var wMetric = weightHandler.GetMetric(w.Weight); // if (w.Direction.F) // { // removedWeight += wMetric; // } // if (w.Direction.B) // { // removedWeight += wMetric; // } //} var weigthDiff = 1f; //if (removedWeight != 0) //{ // weigthDiff = removedWeight; //} return((differenceFactor * (added - removed) + (depthFactor * vertexInfo.Depth) + (contractedFactor * vertexInfo.ContractedNeighbours)) * (weigthDiff * weightDiffFactor)); }
/// <summary> /// Contracts the given vertex. /// </summary> protected virtual void Contract() { var vertex = _vertexInfo.Vertex; // remove 'downward' edge to vertex. var i = 0; while (i < _vertexInfo.Count) { var edge = _vertexInfo[i]; _graph.RemoveEdge(edge.Neighbour, vertex); i++; // TOOD: what to do when stuff is only removed, is nothing ok? //_witnessQueue.Add(edge.Neighbour); } // add shortcuts. foreach (var s in _vertexInfo.Shortcuts) { var shortcut = s.Value; var edge = s.Key; if (edge.Vertex1 == edge.Vertex2) { // TODO: figure out how this is possible, it shouldn't! continue; } var forwardMetric = _weightHandler.GetMetric(shortcut.Forward); var backwardMetric = _weightHandler.GetMetric(shortcut.Backward); if (forwardMetric > 0 && forwardMetric < float.MaxValue && backwardMetric > 0 && backwardMetric < float.MaxValue && System.Math.Abs(backwardMetric - forwardMetric) < FastHierarchyBuilder <float> .E) { // forward and backward and identical weights. _weightHandler.AddOrUpdateEdge(_graph, edge.Vertex1, edge.Vertex2, vertex, null, shortcut.Forward); _weightHandler.AddOrUpdateEdge(_graph, edge.Vertex2, edge.Vertex1, vertex, null, shortcut.Backward); _witnessQueue.Add(edge.Vertex1); _witnessQueue.Add(edge.Vertex2); } else { if (forwardMetric > 0 && forwardMetric < float.MaxValue) { _weightHandler.AddOrUpdateEdge(_graph, edge.Vertex1, edge.Vertex2, vertex, true, shortcut.Forward); _weightHandler.AddOrUpdateEdge(_graph, edge.Vertex2, edge.Vertex1, vertex, false, shortcut.Forward); _witnessQueue.Add(edge.Vertex1); _witnessQueue.Add(edge.Vertex2); } if (backwardMetric > 0 && backwardMetric < float.MaxValue) { _weightHandler.AddOrUpdateEdge(_graph, edge.Vertex1, edge.Vertex2, vertex, false, shortcut.Backward); _weightHandler.AddOrUpdateEdge(_graph, edge.Vertex2, edge.Vertex1, vertex, true, shortcut.Backward); _witnessQueue.Add(edge.Vertex1); _witnessQueue.Add(edge.Vertex2); } } } _contractedFlags[vertex] = true; this.NotifyContracted(vertex); }
/// <summary> /// Contracts the given vertex. /// </summary> private void Contract(uint vertex) { // get and keep edges. var enumerator = _graph.GetEdgeEnumerator(vertex); var edges = new List <DynamicEdge>(enumerator); // check if this vertex has a potential restrictions. var hasRestrictions = _restrictionFlags[vertex]; // loop over all edge-pairs once. for (var j = 1; j < edges.Count; j++) { var edge1 = edges[j]; bool?edge1Direction; var edge1Weight = _weightHandler.GetEdgeWeight(edge1, out edge1Direction); var edge1CanMoveForward = edge1Direction == null || edge1Direction.Value; var edge1CanMoveBackward = edge1Direction == null || !edge1Direction.Value; // figure out what witness paths to calculate. var forwardWitnesses = new EdgePath <T> [j]; var backwardWitnesses = new EdgePath <T> [j]; var targets = new List <uint>(j); var targetWeights = new List <T>(j); for (var k = 0; k < j; k++) { var edge2 = edges[k]; bool?edge2Direction; var edge2Weight = _weightHandler.GetEdgeWeight(edge2, out edge2Direction); var edge2CanMoveForward = edge2Direction == null || edge2Direction.Value; var edge2CanMoveBackward = edge2Direction == null || !edge2Direction.Value; // use witness flags to represent impossible routes. if (!(edge1CanMoveBackward && edge2CanMoveForward)) { forwardWitnesses[k] = new EdgePath <T>(); } if (!(edge1CanMoveForward && edge2CanMoveBackward)) { backwardWitnesses[k] = new EdgePath <T>(); } targets.Add(edge2.Neighbour); if (hasRestrictions) { targetWeights.Add(_weightHandler.Infinite); } else { targetWeights.Add(_weightHandler.Add(edge1Weight, edge2Weight)); } } // calculate all witness paths. _witnessCalculator.Calculate(_graph, _getRestrictions, edge1.Neighbour, targets, targetWeights, ref forwardWitnesses, ref backwardWitnesses, Constants.NO_VERTEX); // get all sequences where needed. var s1forward = new uint[forwardWitnesses.Length][]; var s2forward = new uint[forwardWitnesses.Length][]; var s1backward = new uint[backwardWitnesses.Length][]; var s2backward = new uint[backwardWitnesses.Length][]; for (var k = 0; k < j; k++) { if (forwardWitnesses[k].HasVertex(vertex)) { // get forward sequences. s1forward[k] = forwardWitnesses[k].GetSequence1(enumerator, 1); s2forward[k] = forwardWitnesses[k].GetSequence2(enumerator, 1); } if (backwardWitnesses[k].HasVertex(vertex)) { // get backward sequences. s1backward[k] = backwardWitnesses[k].GetSequence1(enumerator, 1); s2backward[k] = backwardWitnesses[k].GetSequence2(enumerator, 1); } } // add contracted edges if needed. for (var k = 0; k < j; k++) { var edge2 = edges[k]; if (edge1.Neighbour == edge2.Neighbour) { // do not try to add a shortcut between identical vertices. continue; } if (s1forward[k] != null && s1backward[k] != null && System.Math.Abs(_weightHandler.GetMetric(forwardWitnesses[k].Weight) - _weightHandler.GetMetric(backwardWitnesses[k].Weight)) < E) { // paths in both direction are possible and with the same weight, add just one edge in each direction. s1backward[k].Reverse(); s2backward[k].Reverse(); _weightHandler.AddOrUpdateEdge(_graph, edge1.Neighbour, edge2.Neighbour, vertex, null, forwardWitnesses[k].Weight, s1forward[k], s2forward[k]); //_graph.AddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, // forwardWitnesses[k].Weight, null, vertex, s1forward[k], s2forward[k]); _weightHandler.AddOrUpdateEdge(_graph, edge2.Neighbour, edge1.Neighbour, vertex, null, backwardWitnesses[k].Weight, s2backward[k], s1backward[k]); //_graph.AddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, // backwardWitnesses[k].Weight, null, vertex, s2backward[k], s1backward[k]); } else { // add two edge per direction. if (s1forward[k] != null) { // add forward edge. _weightHandler.AddOrUpdateEdge(_graph, edge1.Neighbour, edge2.Neighbour, vertex, true, forwardWitnesses[k].Weight, s1forward[k], s2forward[k]); //_graph.AddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, // forwardWitnesses[k].Weight, true, vertex, s1forward[k], s2forward[k]); s1forward[k].Reverse(); s2forward[k].Reverse(); _weightHandler.AddOrUpdateEdge(_graph, edge2.Neighbour, edge1.Neighbour, vertex, false, forwardWitnesses[k].Weight, s2forward[k], s1forward[k]); //_graph.AddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, // forwardWitnesses[k].Weight, false, vertex, s2forward[k], s1forward[k]); } if (s1backward[k] != null) { // add forward edge. _weightHandler.AddOrUpdateEdge(_graph, edge1.Neighbour, edge2.Neighbour, vertex, false, backwardWitnesses[k].Weight, s2backward[k], s1backward[k]); //_graph.AddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, // backwardWitnesses[k].Weight, false, vertex, s2backward[k], s1backward[k]); s1backward[k].Reverse(); s2backward[k].Reverse(); _weightHandler.AddOrUpdateEdge(_graph, edge2.Neighbour, edge1.Neighbour, vertex, true, backwardWitnesses[k].Weight, s1backward[k], s2backward[k]); //_graph.AddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, // backwardWitnesses[k].Weight, true, vertex, s1backward[k], s2backward[k]); } } } } // remove 'downward' edge to vertex. var i = 0; while (i < edges.Count) { _graph.RemoveEdge(edges[i].Neighbour, vertex); if (_contractedFlags[edges[i].Neighbour]) { // neighbour was already contracted, remove 'downward' edge and exclude it. _graph.RemoveEdge(vertex, edges[i].Neighbour); edges.RemoveAt(i); } else { // move to next edge. i++; } } _contractedFlags[vertex] = true; _priorityCalculator.NotifyContracted(vertex); }
/// <summary> /// Executes the actual run. /// </summary> protected override void DoRun() { // keep settled vertices. _forwardVisits = new Dictionary <uint, EdgePath <T> >(); _backwardVisits = new Dictionary <uint, EdgePath <T> >(); // initialize the queues. var forwardQueue = new BinaryHeap <EdgePath <T> >(); var 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 <uint, T>(Constants.NO_VERTEX, _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.Item2) < queueForwardWeight && _weightHandler.GetMetric(_best.Item2) < queueBackwardWeight) { // stop the search: it now became impossible to find a shorter 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 && _forwardVisits.ContainsKey(current.Vertex)) { // keep trying. current = forwardQueue.Pop(); } if (current != null) { EdgePath <T> toBest; if (_backwardVisits.TryGetValue(current.Vertex, out toBest)) { // check for a new best. var total = _weightHandler.Add(current.Weight, toBest.Weight); if (_weightHandler.IsSmallerThan(total, _best.Item2)) { // a better path was found. _best = new Tuple <uint, T>(current.Vertex, total); this.HasSucceeded = true; } } this.SearchForward(forwardQueue, current); } } // 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 && _backwardVisits.ContainsKey(current.Vertex)) { // keep trying. current = backwardQueue.Pop(); } if (current != null) { EdgePath <T> toBest; if (_forwardVisits.TryGetValue(current.Vertex, out toBest)) { // check for a new best. var total = _weightHandler.Add(current.Weight, toBest.Weight); if (_weightHandler.IsSmallerThan(total, _best.Item2)) { // a better path was found. _best = new Tuple <uint, T>(current.Vertex, total); this.HasSucceeded = true; } } this.SearchBackward(backwardQueue, current); } } // calculate stopping conditions. if (forwardQueue.Count > 0) { queueForwardWeight = forwardQueue.PeekWeight(); } if (backwardQueue.Count > 0) { queueBackwardWeight = backwardQueue.PeekWeight(); } } }
/// <summary> /// Executes the actual run. /// </summary> protected override void DoRun(CancellationToken cancellationToken) { // keep settled vertices. _pathTree = new PathTree(); // initialize the queues. var forwardQueue = new BinaryHeap <uint>(); var backwardQueue = new BinaryHeap <uint>(); // queue sources. if (_source.Vertex1 != Constants.NO_VERTEX) { forwardQueue.Push(_weightHandler.AddPathTree(_pathTree, _source.Vertex1, _source.Weight1, uint.MaxValue), 0); } if (_source.Vertex2 != Constants.NO_VERTEX) { forwardQueue.Push(_weightHandler.AddPathTree(_pathTree, _source.Vertex2, _source.Weight2, uint.MaxValue), 0); } // queue targets. if (_target.Vertex1 != Constants.NO_VERTEX) { backwardQueue.Push(_weightHandler.AddPathTree(_pathTree, _target.Vertex1, _target.Weight1, uint.MaxValue), 0); } if (_target.Vertex2 != Constants.NO_VERTEX) { backwardQueue.Push(_weightHandler.AddPathTree(_pathTree, _target.Vertex2, _target.Weight2, uint.MaxValue), 0); } // update best with current visits. _best = new Tuple <uint, uint, T>(uint.MaxValue, uint.MaxValue, _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; } var bestItem2 = _weightHandler.GetMetric(_best.Item3); if (bestItem2 < queueForwardWeight && bestItem2 < queueBackwardWeight) { // stop the search: it now became impossible to find a shorter 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 cPointer = forwardQueue.Pop(); uint cVertex, cPreviousPointer; T cWeight; _weightHandler.GetPathTree(_pathTree, cPointer, out cVertex, out cWeight, out cPreviousPointer); while (_forwardVisits.ContainsKey(cVertex)) { // keep trying. if (forwardQueue.Count == 0) { cPointer = uint.MaxValue; } else { cPointer = forwardQueue.Pop(); _weightHandler.GetPathTree(_pathTree, cPointer, out cVertex, out cWeight, out cPreviousPointer); } } if (cPointer != uint.MaxValue) { uint bPointer; if (_backwardVisits.TryGetValue(cVertex, out bPointer)) { // check for a new best. uint bVertex, bPreviousPointer; T bWeight; _weightHandler.GetPathTree(_pathTree, bPointer, out bVertex, out bWeight, out bPreviousPointer); var total = _weightHandler.Add(cWeight, bWeight); if (_weightHandler.IsSmallerThan(total, _best.Item2)) { // a better path was found. _best = new Tuple <uint, uint, T>(cPointer, bPointer, total); this.HasSucceeded = true; } } this.SearchForward(forwardQueue, cPointer, cVertex, cWeight); } } // do a backward search. if (backwardQueue.Count > 0) {// first check for better path. // get the current queued with the smallest weight that hasn't been visited yet. var cPointer = backwardQueue.Pop(); uint cVertex, cPreviousPointer; T cWeight; _weightHandler.GetPathTree(_pathTree, cPointer, out cVertex, out cWeight, out cPreviousPointer); while (_backwardVisits.ContainsKey(cVertex)) { // keep trying. if (backwardQueue.Count == 0) { cPointer = uint.MaxValue; } else { cPointer = backwardQueue.Pop(); _weightHandler.GetPathTree(_pathTree, cPointer, out cVertex, out cWeight, out cPreviousPointer); } } if (cPointer != uint.MaxValue) { uint bPointer; // best pointer. if (_forwardVisits.TryGetValue(cVertex, out bPointer)) { // check for a new best. uint bVertex, bPreviousPointer; T bWeight; _weightHandler.GetPathTree(_pathTree, bPointer, out bVertex, out bWeight, out bPreviousPointer); var total = _weightHandler.Add(cWeight, bWeight); if (_weightHandler.IsSmallerThan(total, _best.Item2)) { // a better path was found. _best = new Tuple <uint, uint, T>(bPointer, cPointer, total); this.HasSucceeded = true; } } this.SearchBackward(backwardQueue, cPointer, cVertex, cWeight); } } // calculate stopping conditions. if (forwardQueue.Count > 0) { queueForwardWeight = forwardQueue.PeekWeight(); } if (backwardQueue.Count > 0) { queueBackwardWeight = backwardQueue.PeekWeight(); } } }
/// <summary> /// Calculates witness paths. /// </summary> public virtual void Calculate(DirectedGraph graph, WeightHandler <T> weightHandler, uint vertex, uint source, Dictionary <uint, Shortcut <T> > targets, int maxSettles, int hopLimit) { pathTree.Clear(); pointerHeap.Clear(); var forwardSettled = new HashSet <uint>(); var backwardSettled = new HashSet <uint>(); var forwardTargets = new HashSet <uint>(); var backwardTargets = new HashSet <uint>(); var maxWeight = 0f; foreach (var targetPair in targets) { var target = targetPair.Key; var shortcut = targetPair.Value; var e = new OriginalEdge(source, target); var shortcutForward = weightHandler.GetMetric(shortcut.Forward); if (shortcutForward > 0 && shortcutForward < float.MaxValue) { forwardTargets.Add(e.Vertex2); if (shortcutForward > maxWeight) { maxWeight = shortcutForward; } } var shortcutBackward = weightHandler.GetMetric(shortcut.Backward); if (shortcutBackward > 0 && shortcutBackward < float.MaxValue) { backwardTargets.Add(e.Vertex2); if (shortcutBackward > maxWeight) { maxWeight = shortcutBackward; } } } // queue the source. pathTree.Clear(); pointerHeap.Clear(); var p = pathTree.AddSettledVertex(source, new WeightAndDir <float>() { Direction = new Dir(true, true), Weight = 0 }, 0); pointerHeap.Push(p, 0); // dequeue vertices until stopping conditions are reached. var cVertex = Constants.NO_VERTEX; WeightAndDir <float> cWeight; var cHops = uint.MaxValue; var enumerator = graph.GetEdgeEnumerator(); while (pointerHeap.Count > 0) { var cPointer = pointerHeap.Pop(); pathTree.GetSettledVertex(cPointer, out cVertex, out cWeight, out cHops); if (cVertex == vertex) { continue; } if (cWeight.Weight >= maxWeight) { break; } if (forwardSettled.Contains(cVertex) || forwardTargets.Count == 0 || forwardSettled.Count > maxSettles) { cWeight.Direction = new Dir(false, cWeight.Direction.B); } if (backwardSettled.Contains(cVertex) || backwardTargets.Count == 0 || backwardSettled.Count > maxSettles) { cWeight.Direction = new Dir(cWeight.Direction.F, false); } if (cWeight.Direction.F) { forwardSettled.Add(cVertex); if (forwardTargets.Contains(cVertex)) { // target reached, evaluate it as a shortcut. Shortcut <T> shortcut; if (targets.TryGetValue(cVertex, out shortcut)) { var shortcutForward = weightHandler.GetMetric(shortcut.Forward); if (shortcutForward > cWeight.Weight) { // a witness path was found, don't add a shortcut. shortcut.Forward = weightHandler.Zero; targets[cVertex] = shortcut; } } forwardTargets.Remove(cVertex); if (forwardTargets.Count == 0) { if (backwardTargets.Count == 0) { break; } cWeight.Direction = new Dir(false, cWeight.Direction.B); if (!cWeight.Direction.F && !cWeight.Direction.B) { continue; } } } } if (cWeight.Direction.B) { backwardSettled.Add(cVertex); if (backwardTargets.Contains(cVertex)) { // target reached, evaluate it as a shortcut. Shortcut <T> shortcut; if (targets.TryGetValue(cVertex, out shortcut)) { var shortcutBackward = weightHandler.GetMetric(shortcut.Backward); if (shortcutBackward > cWeight.Weight) { // a witness path was found, don't add a shortcut. shortcut.Backward = weightHandler.Zero; targets[cVertex] = shortcut; } } backwardTargets.Remove(cVertex); if (backwardTargets.Count == 0) { if (forwardTargets.Count == 0) { break; } cWeight.Direction = new Dir(cWeight.Direction.F, false); if (!cWeight.Direction.F && !cWeight.Direction.B) { continue; } } } } if (cHops + 1 >= hopLimit) { continue; } if (forwardSettled.Count > maxSettles && backwardSettled.Count > maxSettles) { continue; } enumerator.MoveTo(cVertex); while (enumerator.MoveNext()) { var nVertex = enumerator.Neighbour; var nWeight = ContractedEdgeDataSerializer.Deserialize(enumerator.Data0); nWeight = new WeightAndDir <float>() { Direction = Dir.Combine(cWeight.Direction, nWeight.Direction), Weight = cWeight.Weight + nWeight.Weight }; if (nWeight.Direction.F && forwardSettled.Contains(nVertex)) { nWeight.Direction = new Dir(false, nWeight.Direction.B); } if (nWeight.Direction.B && backwardSettled.Contains(nVertex)) { nWeight.Direction = new Dir(nWeight.Direction.F, false); } if (!nWeight.Direction.F && !nWeight.Direction.B) { continue; } var nPoiner = pathTree.AddSettledVertex(nVertex, nWeight, cHops + 1); pointerHeap.Push(nPoiner, nWeight.Weight); } } }
/// <summary> /// Remove all witnessed edges. /// </summary> private void RemoveWitnessedEdges() { _logger.Log(TraceEventType.Information, "Removing witnessed edges..."); var edges = new List <MetaEdge>(); var weights = new List <T>(); var metrics = new List <float>(); var targets = new List <uint>(); for (uint vertex = 0; vertex < _graph.VertexCount; vertex++) { edges.Clear(); weights.Clear(); metrics.Clear(); targets.Clear(); edges.AddRange(_graph.GetEdgeEnumerator(vertex)); var forwardWitnesses = new bool[edges.Count]; var backwardWitnesses = new bool[edges.Count]; for (var i = 0; i < edges.Count; i++) { var edge = edges[i]; bool?edgeDirection; var edgeWeight = _weightHandler.GetEdgeWeight(edge, out edgeDirection); var edgeCanMoveForward = edgeDirection == null || edgeDirection.Value; var edgeCanMoveBackward = edgeDirection == null || !edgeDirection.Value; forwardWitnesses[i] = !edgeCanMoveForward; backwardWitnesses[i] = !edgeCanMoveBackward; weights.Add(edgeWeight); metrics.Add(_weightHandler.GetMetric(edgeWeight)); targets.Add(edge.Neighbour); } // calculate all witness paths. _witnessCalculator.Calculate(_graph.Graph, vertex, targets, metrics, ref forwardWitnesses, ref backwardWitnesses, uint.MaxValue); // check witness paths. for (var i = 0; i < edges.Count; i++) { if (forwardWitnesses[i] && backwardWitnesses[i]) { // in both directions the edge does not represent the shortest path. _graph.RemoveEdge(vertex, targets[i]); } else if (forwardWitnesses[i]) { // only in forward direction is this edge useless. _graph.RemoveEdge(vertex, targets[i]); _weightHandler.AddEdge(_graph, vertex, targets[i], Constants.NO_VERTEX, false, weights[i]); //_graph.AddEdge(vertex, targets[i], weights[i], false, Constants.NO_VERTEX); } else if (backwardWitnesses[i]) { // only in backward direction is this edge useless. _graph.RemoveEdge(vertex, targets[i]); _weightHandler.AddEdge(_graph, vertex, targets[i], Constants.NO_VERTEX, true, weights[i]); } } } }
/// <summary> /// Calculates the priority of the given vertex. /// </summary> public float Calculate(BitArray32 contractedFlags, Func <uint, IEnumerable <uint[]> > getRestrictions, uint vertex) { var removed = 0; var added = 0; // get and keep edges. var edges = new List <DynamicEdge>(_graph.GetEdgeEnumerator(vertex)); // check if this vertex has a potential restrictions. var restrictions = getRestrictions(vertex); var hasRestrictions = restrictions != null && restrictions.Any(); // remove 'downward' edge to vertex. var i = 0; while (i < edges.Count) { var edgeEnumerator = _graph.GetEdgeEnumerator(edges[i].Neighbour); edgeEnumerator.Reset(); while (edgeEnumerator.MoveNext()) { if (edgeEnumerator.Neighbour == vertex) { removed++; } } if (contractedFlags[edges[i].Neighbour]) { // neighbour was already contracted, remove 'downward' edge and exclude it. edgeEnumerator.MoveTo(vertex); edgeEnumerator.Reset(); while (edgeEnumerator.MoveNext()) { if (edgeEnumerator.Neighbour == edges[i].Neighbour) { removed++; } } edges.RemoveAt(i); } else { // move to next edge. i++; } } // loop over all edge-pairs once. for (var j = 1; j < edges.Count; j++) { var edge1 = edges[j]; bool?edge1Direction; var edge1Weight = _weightHandler.GetEdgeWeight(edge1, out edge1Direction); var edge1CanMoveForward = edge1Direction == null || edge1Direction.Value; var edge1CanMoveBackward = edge1Direction == null || !edge1Direction.Value; // figure out what witness paths to calculate. var forwardWitnesses = new EdgePath <T> [j]; var backwardWitnesses = new EdgePath <T> [j]; var targets = new List <uint>(j); var targetWeights = new List <T>(j); for (var k = 0; k < j; k++) { var edge2 = edges[k]; bool?edge2Direction; var edge2Weight = _weightHandler.GetEdgeWeight(edge2, out edge2Direction); var edge2CanMoveForward = edge2Direction == null || edge2Direction.Value; var edge2CanMoveBackward = edge2Direction == null || !edge2Direction.Value; if (!(edge1CanMoveBackward && edge2CanMoveForward)) { forwardWitnesses[k] = new EdgePath <T>(); } if (!(edge1CanMoveForward && edge2CanMoveBackward)) { backwardWitnesses[k] = new EdgePath <T>(); } targets.Add(edge2.Neighbour); if (hasRestrictions) { // weight can potentially be bigger. targetWeights.Add(_weightHandler.Infinite); } else { // weight can max be the sum of the two edges. targetWeights.Add(_weightHandler.Add(edge1Weight, edge2Weight)); } } // calculate all witness paths. _witnessCalculator.Calculate(_graph, getRestrictions, edge1.Neighbour, targets, targetWeights, ref forwardWitnesses, ref backwardWitnesses, Constants.NO_VERTEX); // add contracted edges if needed. for (var k = 0; k < j; k++) { var edge2 = edges[k]; var removedLocal = 0; var addedLocal = 0; if (forwardWitnesses[k].HasVertex(vertex) && backwardWitnesses[k].HasVertex(vertex)) { // add bidirectional edge. _graph.TryAddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, _weightHandler.GetMetric(targetWeights[k]), null, vertex, out addedLocal, out removedLocal); added += addedLocal; removed += removedLocal; _graph.TryAddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, _weightHandler.GetMetric(targetWeights[k]), null, vertex, out addedLocal, out removedLocal); added += addedLocal; removed += removedLocal; } else if (forwardWitnesses[k].HasVertex(vertex)) { // add forward edge. _graph.TryAddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, _weightHandler.GetMetric(targetWeights[k]), true, vertex, out addedLocal, out removedLocal); added += addedLocal; removed += removedLocal; _graph.TryAddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, _weightHandler.GetMetric(targetWeights[k]), false, vertex, out addedLocal, out removedLocal); added += addedLocal; removed += removedLocal; } else if (backwardWitnesses[k].HasVertex(vertex)) { // add forward edge. _graph.TryAddOrUpdateEdge(edge1.Neighbour, edge2.Neighbour, _weightHandler.GetMetric(targetWeights[k]), false, vertex, out addedLocal, out removedLocal); added += addedLocal; removed += removedLocal; _graph.TryAddOrUpdateEdge(edge2.Neighbour, edge1.Neighbour, _weightHandler.GetMetric(targetWeights[k]), true, vertex, out addedLocal, out removedLocal); added += addedLocal; removed += removedLocal; } } } var contracted = 0; _contractionCount.TryGetValue(vertex, out contracted); var depth = 0; _depth.TryGetValue(vertex, out depth); return(this.DifferenceFactor * (added - removed) + (this.DepthFactor * depth) + (this.ContractedFactor * contracted)); }
/// <summary> /// Executes the algorithm. /// </summary> protected sealed override void DoRun() { // run mass resolver if needed. if (!_massResolver.HasRun) { _massResolver.Run(); } // create error and resolved point management data structures. _correctedResolvedPoints = _massResolver.RouterPoints; _errors = new Dictionary <int, RouterPointError>(_correctedResolvedPoints.Count); _correctedIndices = new List <int>(_correctedResolvedPoints.Count); // convert sources into directed paths. _sourcePaths = new EdgePath <T> [_correctedResolvedPoints.Count * 2]; for (var i = 0; i < _correctedResolvedPoints.Count; i++) { _correctedIndices.Add(i); var paths = _correctedResolvedPoints[i].ToEdgePathsDirected(_router.Db, _weightHandler, true); if (paths.Length == 0) { this.ErrorMessage = string.Format("Source at {0} could not be resolved properly.", i); return; } _sourcePaths[i * 2 + 0] = paths[0]; if (paths.Length == 2) { _sourcePaths[i * 2 + 1] = paths[1]; } } // convert targets into directed paths. _targetPaths = new EdgePath <T> [_correctedResolvedPoints.Count * 2]; for (var i = 0; i < _correctedResolvedPoints.Count; i++) { var paths = _correctedResolvedPoints[i].ToEdgePathsDirected(_router.Db, _weightHandler, false); if (paths.Length == 0) { this.ErrorMessage = string.Format("Target at {0} could not be resolved properly.", i); return; } // make sure paths are the opposive of the sources. if (paths[0].Edge == _sourcePaths[i * 2 + 0].Edge) { // switchs. _targetPaths[i * 2 + 1] = paths[0]; if (paths.Length == 2) { _targetPaths[i * 2 + 0] = paths[1]; } } else { // keep. _targetPaths[i * 2 + 0] = paths[0]; if (paths.Length == 2) { _targetPaths[i * 2 + 1] = paths[1]; } } } // put in default weights and weights for one-edge-paths. _weights = new T[_sourcePaths.Length][]; for (var i = 0; i < _sourcePaths.Length; i++) { var source = _sourcePaths[i]; _weights[i] = new T[_targetPaths.Length]; for (var j = 0; j < _targetPaths.Length; j++) { var target = _targetPaths[j]; _weights[i][j] = _weightHandler.Infinite; if (source == null || target == null) { continue; } if (target.Edge == -source.Edge) { var s = i / 2; var t = j / 2; var sourcePoint = _correctedResolvedPoints[s]; var targetPoint = _correctedResolvedPoints[t]; EdgePath <T> newPath = null; if (source.Edge > 0 && sourcePoint.Offset <= targetPoint.Offset) { newPath = sourcePoint.EdgePathTo(_router.Db, _weightHandler, targetPoint); } else if (source.Edge < 0 && sourcePoint.Offset >= targetPoint.Offset) { newPath = sourcePoint.EdgePathTo(_router.Db, _weightHandler, targetPoint); } if (newPath != null) { if (_weightHandler.IsLargerThan(_weights[i][j], newPath.Weight)) { _weights[i][j] = newPath.Weight; } } } } } // do forward searches into buckets. for (var i = 0; i < _sourcePaths.Length; i++) { var path = _sourcePaths[i]; if (path != null) { var forward = new Itinero.Algorithms.Contracted.EdgeBased.Dykstra <T>(_graph, _weightHandler, new EdgePath <T>[] { path }, (v) => null, false, _max); forward.WasFound += (foundPath) => { LinkedEdgePath <T> visits; forward.TryGetVisits(foundPath.Vertex, out visits); return(this.ForwardVertexFound(i, foundPath.Vertex, visits)); }; forward.Run(); } } // do backward searches into buckets. for (var i = 0; i < _targetPaths.Length; i++) { var path = _targetPaths[i]; if (path != null) { var backward = new Itinero.Algorithms.Contracted.EdgeBased.Dykstra <T>(_graph, _weightHandler, new EdgePath <T>[] { path }, (v) => null, true, _max); backward.WasFound += (foundPath) => { LinkedEdgePath <T> visits; backward.TryGetVisits(foundPath.Vertex, out visits); return(this.BackwardVertexFound(i, foundPath.Vertex, visits)); }; backward.Run(); } } // check for invalids. var originalInvalids = new HashSet <int>(); var invalidTargetCounts = new int[_weights.Length / 2]; for (var s = 0; s < _weights.Length / 2; s++) { var invalids = 0; for (var t = 0; t < _weights[s * 2].Length / 2; t++) { if (t != s) { if (_weightHandler.GetMetric(_weights[s * 2 + 0][t * 2 + 0]) == float.MaxValue && _weightHandler.GetMetric(_weights[s * 2 + 0][t * 2 + 1]) == float.MaxValue && _weightHandler.GetMetric(_weights[s * 2 + 1][t * 2 + 0]) == float.MaxValue && _weightHandler.GetMetric(_weights[s * 2 + 1][t * 2 + 1]) == float.MaxValue) { invalids++; invalidTargetCounts[t]++; if (invalidTargetCounts[t] > ((_weights.Length / 2) - 1) / 2) { originalInvalids.Add(t); } } } } if (invalids > ((_weights.Length / 2) - 1) / 2) { originalInvalids.Add(s); } } // take into account the non-null invalids now. if (originalInvalids.Count > 0) { // shrink lists and add errors. _correctedResolvedPoints = _correctedResolvedPoints.ShrinkAndCopyList(originalInvalids); _correctedIndices = _correctedIndices.ShrinkAndCopyList(originalInvalids); // convert back to the path indexes. var nonNullInvalids = new HashSet <int>(); foreach (var invalid in originalInvalids) { nonNullInvalids.Add(invalid * 2); nonNullInvalids.Add(invalid * 2 + 1); _errors[invalid] = new RouterPointError() { Code = RouterPointErrorCode.NotRoutable, Message = "Location could not routed to or from." }; } _weights = _weights.SchrinkAndCopyMatrix(nonNullInvalids); _sourcePaths = _sourcePaths.ShrinkAndCopyArray(nonNullInvalids); _targetPaths = _targetPaths.ShrinkAndCopyArray(nonNullInvalids); } this.HasSucceeded = true; }
/// <summary> /// Remove all witnessed edges. /// </summary> private void RemoveWitnessedEdges() { _logger.Log(TraceEventType.Information, "Removing witnessed edges..."); var witnessEdgeEnumerator = _witnessGraph.GetEdgeEnumerator(); var edgeEnumerator = _graph.GetEdgeEnumerator(); var edges = new List <MetaEdge>(); for (uint vertex = 0; vertex < _graph.VertexCount; vertex++) { // collect all relevant edges. edges.Clear(); if (witnessEdgeEnumerator.MoveTo(vertex) && edgeEnumerator.MoveTo(vertex)) { while (edgeEnumerator.MoveNext()) { if (vertex < edgeEnumerator.Neighbour) { // only check in on directions, all edges are added twice initially. edges.Add(edgeEnumerator.Current); } } } // check witness paths. for (var i = 0; i < edges.Count; i++) { var edge = edges[0]; while (witnessEdgeEnumerator.MoveNext()) { if (witnessEdgeEnumerator.Neighbour == edge.Neighbour) { // this edge is witnessed, figure out how. var forwardWitnessWeight = DirectedGraphExtensions.FromData(witnessEdgeEnumerator.Data0); var backwardWitnessWeight = DirectedGraphExtensions.FromData(witnessEdgeEnumerator.Data1); var weightAndDir = _weightHandler.GetEdgeWeight(edge); var weight = _weightHandler.GetMetric(weightAndDir.Weight); var witnessed = false; if (weightAndDir.Direction.F && weight > forwardWitnessWeight) { // witnessed in forward direction. weightAndDir.Direction = new Dir(false, weightAndDir.Direction.B); witnessed = true; } if (weightAndDir.Direction.B && weight > backwardWitnessWeight) { // witnessed in backward direction. weightAndDir.Direction = new Dir(weightAndDir.Direction.F, false); witnessed = true; } if (witnessed) { // edge was witnessed, do something. // remove the edge (in both directions) _graph.RemoveEdge(vertex, edge.Neighbour); _graph.RemoveEdge(edge.Neighbour, vertex); if (weightAndDir.Direction.B || weightAndDir.Direction.F) { // add it again if there is something relevant still left. _weightHandler.AddEdge(_graph, vertex, edge.Neighbour, Constants.NO_VERTEX, weightAndDir.Direction.AsNullableBool(), weightAndDir.Weight); weightAndDir.Direction.Reverse(); _weightHandler.AddEdge(_graph, edge.Neighbour, vertex, Constants.NO_VERTEX, weightAndDir.Direction.AsNullableBool(), weightAndDir.Weight); } } } } } } }
/// <summary> /// Executes one step in the search. /// </summary> public bool Step() { // while the visit list is not empty. var cPointer = uint.MaxValue; while (cPointer == uint.MaxValue) { // choose the next edge. if (_pointerHeap.Count == 0) { return(false); } cPointer = _pointerHeap.Pop(); } // get details. uint cEdge, cPreviousPointer; T cWeight; _weightHandler.GetPathTree(_pathTree, cPointer, out cEdge, out cWeight, out cPreviousPointer); if (_visits.Contains(cEdge)) { return(true); } _visits.Add(cEdge); var cDirectedEdge = new DirectedEdgeId() { Raw = cEdge }; // signal was found. if (this.WasFound != null) { this.WasFound(cPointer, cDirectedEdge, cWeight); } // move to the current edge's target vertex. _edgeEnumerator.MoveToEdge(cDirectedEdge.EdgeId); var cOriginalEdge = new OriginalEdge(_edgeEnumerator.From, _edgeEnumerator.To); if (!cDirectedEdge.Forward) { cOriginalEdge = cOriginalEdge.Reverse(); } var cEdgeWeightAndDirection = _weightHandler.GetEdgeWeight(_edgeEnumerator); // calculate total weight. var totalWeight = _weightHandler.Add(cEdgeWeightAndDirection.Weight, cWeight); if (!_weightHandler.IsSmallerThan(totalWeight, _sourceMax)) { // weight is too big. this.MaxReached = true; return(true); } // loop over all neighbours. _edgeEnumerator.MoveTo(cOriginalEdge.Vertex2); var turn = new Turn(cOriginalEdge, Constants.NO_VERTEX); _restrictions.Update(turn.Vertex2); while (_edgeEnumerator.MoveNext()) { turn.Vertex3 = _edgeEnumerator.To; if (turn.IsUTurn || turn.IsRestrictedBy(_restrictions)) { // turn is restricted. continue; } var nDirectedEdgeId = _edgeEnumerator.DirectedEdgeId(); if (_visits.Contains(nDirectedEdgeId.Raw)) { // has already been choosen. continue; } // get the speed from cache or calculate. var nWeightAndDirection = _weightHandler.GetEdgeWeight(_edgeEnumerator); var nWeightMetric = _weightHandler.GetMetric(nWeightAndDirection.Weight); if (nWeightMetric <= 0) { // edge is not valid for profile. continue; } if (!_backward && !nWeightAndDirection.Direction.F) { // cannot do forward search on edge. continue; } if (_backward && !nWeightAndDirection.Direction.B) { // cannot do backward on edge. continue; } // update the visit list. _pointerHeap.Push(_weightHandler.AddPathTree(_pathTree, nDirectedEdgeId.Raw, totalWeight, cPointer), _weightHandler.GetMetric(totalWeight)); } return(true); }
/// <summary> /// Executes the algorithm. /// </summary> protected sealed override void DoRun(CancellationToken cancellationToken) { // run mass resolver if needed. if (!_massResolver.HasRun) { _massResolver.Run(cancellationToken); } // create error and resolved point management data structures. _correctedResolvedPoints = _massResolver.RouterPoints; _errors = new Dictionary <int, RouterPointError>(_correctedResolvedPoints.Count); _correctedIndices = new List <int>(_correctedResolvedPoints.Count); // convert sources into directed paths. _sourcePaths = new EdgePath <T> [_correctedResolvedPoints.Count * 2]; for (var i = 0; i < _correctedResolvedPoints.Count; i++) { _correctedIndices.Add(i); var paths = _correctedResolvedPoints[i].ToEdgePathsDirectedFixed(_router.Db, _weightHandler, true); if (paths.Length == 0) { this.ErrorMessage = string.Format("Source at {0} could not be resolved properly.", i); return; } _sourcePaths[i * 2 + 0] = paths[0]; _sourcePaths[i * 2 + 1] = paths[1]; } // convert targets into directed paths. _targetPaths = new EdgePath <T> [_correctedResolvedPoints.Count * 2]; for (var i = 0; i < _correctedResolvedPoints.Count; i++) { var paths = _correctedResolvedPoints[i].ToEdgePathsDirectedFixed(_router.Db, _weightHandler, false); if (paths.Length == 0) { this.ErrorMessage = string.Format("Target at {0} could not be resolved properly.", i); return; } _targetPaths[i * 2 + 0] = paths[1]; _targetPaths[i * 2 + 1] = paths[0]; } // put in default weights and weights for one-edge-paths. _weights = new T[_sourcePaths.Length][]; for (var i = 0; i < _sourcePaths.Length; i++) { var source = _sourcePaths[i]; _weights[i] = new T[_targetPaths.Length]; for (var j = 0; j < _targetPaths.Length; j++) { var target = _targetPaths[j]; _weights[i][j] = _weightHandler.Infinite; if (source == null || target == null) { continue; } if (target.Edge == -source.Edge) { var s = i / 2; var t = j / 2; var sourcePoint = _correctedResolvedPoints[s]; var targetPoint = _correctedResolvedPoints[t]; EdgePath <T> newPath = null; if (source.Edge > 0 && sourcePoint.Offset <= targetPoint.Offset) { newPath = sourcePoint.EdgePathTo(_router.Db, _weightHandler, targetPoint); } else if (source.Edge < 0 && sourcePoint.Offset >= targetPoint.Offset) { newPath = sourcePoint.EdgePathTo(_router.Db, _weightHandler, targetPoint); } if (newPath != null) { if (_weightHandler.IsLargerThan(_weights[i][j], newPath.Weight)) { _weights[i][j] = newPath.Weight; } } } } } // run the actual calculations. if (_graph != null) { this.DoEdgeBased(cancellationToken); } else { this.DoDualBased(cancellationToken); } // check for invalids. var originalInvalids = new HashSet <int>(); var invalidTargetCounts = new int[_weights.Length / 2]; for (var s = 0; s < _weights.Length / 2; s++) { var invalids = 0; for (var t = 0; t < _weights[s * 2].Length / 2; t++) { if (t != s) { if (_weightHandler.GetMetric(_weights[s * 2 + 0][t * 2 + 0]) == float.MaxValue && _weightHandler.GetMetric(_weights[s * 2 + 0][t * 2 + 1]) == float.MaxValue && _weightHandler.GetMetric(_weights[s * 2 + 1][t * 2 + 0]) == float.MaxValue && _weightHandler.GetMetric(_weights[s * 2 + 1][t * 2 + 1]) == float.MaxValue) { invalids++; invalidTargetCounts[t]++; if (invalidTargetCounts[t] > ((_weights.Length / 2) - 1) / 2) { originalInvalids.Add(t); } } } } if (invalids > ((_weights.Length / 2) - 1) / 2) { originalInvalids.Add(s); } } // take into account the non-null invalids now. if (originalInvalids.Count > 0) { // shrink lists and add errors. _correctedResolvedPoints = _correctedResolvedPoints.ShrinkAndCopyList(originalInvalids); _correctedIndices = _correctedIndices.ShrinkAndCopyList(originalInvalids); // convert back to the path indexes. var nonNullInvalids = new HashSet <int>(); foreach (var invalid in originalInvalids) { nonNullInvalids.Add(invalid * 2); nonNullInvalids.Add(invalid * 2 + 1); _errors[invalid] = new RouterPointError() { Code = RouterPointErrorCode.NotRoutable, Message = "Location could not routed to or from." }; } _weights = _weights.SchrinkAndCopyMatrix(nonNullInvalids); _sourcePaths = _sourcePaths.ShrinkAndCopyArray(nonNullInvalids); _targetPaths = _targetPaths.ShrinkAndCopyArray(nonNullInvalids); } this.HasSucceeded = true; }