public void Run(DirectedGraph graph, DirectedGraph witnessGraph, uint vertex, HashSet <uint> dirty) { try { forwardSettled.Clear(); backwardSettled.Clear(); pathTree.Clear(); pointerHeap.Clear(); witnesses.Clear(); var p = pathTree.AddSettledVertex(vertex, new WeightAndDir <float>() { Direction = new Dir(true, true), Weight = 0 }, 0, Constants.NO_VERTEX); pointerHeap.Push(p, 0); // dequeue vertices until stopping conditions are reached. var enumerator = graph.GetEdgeEnumerator(); // calculate max forward/backward weight. var forwardMax = 0f; var backwardMax = 0f; enumerator.MoveTo(vertex); var nextEnumerator = graph.GetEdgeEnumerator(); while (enumerator.MoveNext()) { var nVertex1 = enumerator.Neighbour; if (dirty != null && !dirty.Contains(nVertex1)) { // this is not a hop-2 to consider. continue; } ContractedEdgeDataSerializer.Deserialize(enumerator.Data0, out Dir dir1, out float weight1); var p1 = pathTree.AddSettledVertex(nVertex1, weight1, dir1, 1, vertex); pointerHeap.Push(p1, weight1); nextEnumerator.MoveTo(enumerator.Neighbour); while (nextEnumerator.MoveNext()) { var nVertex2 = nextEnumerator.Neighbour; if (nVertex2 == vertex) { // no u-turns. continue; } ContractedEdgeDataSerializer.Deserialize(nextEnumerator.Data0, out Dir dir2, out float weight2); dir2._val = (byte)(dir1._val & dir2._val); if (dir2._val == 0) { continue; } var weight2Hops = weight1 + weight2; var p2 = pathTree.AddSettledVertex(nVertex2, weight2Hops, dir2, 2, nVertex1); pointerHeap.Push(p2, weight2Hops); if (dir2.F && weight2Hops > forwardMax) { forwardMax = weight2Hops; } if (dir2.B && weight2Hops > backwardMax) { backwardMax = weight2Hops; } } } if (forwardMax == 0 && backwardMax == 0) { return; } while (pointerHeap.Count > 0) { var cPointer = pointerHeap.Pop(); pathTree.GetSettledVertex(cPointer, out uint cVertex, out WeightAndDir <float> cWeight, out uint cHops, out uint pVertex); if (cHops == 2) { // check if the search can stop or not. var witness = new Shortcut <float>(); witness.Forward = float.MaxValue; witness.Backward = float.MaxValue; if (cWeight.Direction.F && forwardSettled.TryGetValue(cVertex, out float best) && best < cWeight.Weight) { // this is a 2-hop and vertex was settled before, we have a witness! witness.Forward = best; } if (cWeight.Direction.B && backwardSettled.TryGetValue(cVertex, out best) && best < cWeight.Weight) { // this is a 2-hop and vertex was settled before, we have a witness! witness.Backward = best; } if (witness.Backward != float.MaxValue || witness.Forward != float.MaxValue) { // report witness here. if (vertex != cVertex) { // TODO: check this, how can they ever be the same? witnesses.Add(new Witness() { Vertex1 = vertex, Vertex2 = cVertex, Forward = witness.Forward, Backward = witness.Backward }); } } } if (forwardSettled.Count > _maxSettles || backwardSettled.Count > _maxSettles) { // over settled count. break; } if (cWeight.Weight > backwardMax && cWeight.Weight > forwardMax) { // over max weights. break; } if (forwardSettled.ContainsKey(cVertex) || cWeight.Weight > forwardMax) { cWeight.Direction = new Dir(false, cWeight.Direction.B); } if (backwardSettled.ContainsKey(cVertex) || cWeight.Weight > backwardMax) { cWeight.Direction = new Dir(cWeight.Direction.F, false); } var isRelevant = false; if (cWeight.Direction.F) { forwardSettled.Add(cVertex, cWeight.Weight); isRelevant = true; } if (cWeight.Direction.B) { backwardSettled.Add(cVertex, cWeight.Weight); isRelevant = true; } if (!isRelevant) { // not forward, not backwards. continue; } cHops++; if (cHops >= _hopLimit) { // over hop limit, don't queue. continue; } if (cHops == 1) { if (dirty == null) { // all hops 1 are already queued. continue; } } else if (cHops == 2) { if (dirty == null || dirty.Contains(cVertex)) { // all these hops 2 are already queue. continue; } } enumerator.MoveTo(cVertex); while (enumerator.MoveNext()) { var nVertex = enumerator.Neighbour; if (nVertex == pVertex) { // no going back. continue; } if (cHops == 1) { // check if the neighbour is dirty. if (dirty.Contains(nVertex)) { // skip dirty vertices, they are already in the queue. continue; } } Dir nDir; float nWeight; ContractedEdgeDataSerializer.Deserialize(enumerator.Data0, out nDir, out nWeight); nDir._val = (byte)(cWeight.Direction._val & nDir._val); if (nDir._val == 0) { continue; } nWeight = nWeight + cWeight.Weight; if (nDir.F && nWeight > forwardMax) { nDir = new Dir(false, nDir.B); if (nDir._val == 0) { continue; } } if (nDir.B && nWeight > backwardMax) { nDir = new Dir(nDir.F, false); if (nDir._val == 0) { continue; } } var nPoiner = pathTree.AddSettledVertex(nVertex, nWeight, nDir, cHops, cVertex); pointerHeap.Push(nPoiner, nWeight); } } if (witnesses.Count > 0) { lock (witnessGraph) { foreach (var witness in witnesses) { //witnessGraph.AddOrUpdateEdge(witness.Item1, witness.Item2, witness.Item3.Forward, // witness.Item3.Backward); witnessGraph.AddOrUpdateEdge(witness.Vertex1, witness.Vertex2, witness.Forward, witness.Backward); } } } } catch (Exception ex) { throw ex; } }
/// <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); } } }