/// <summary> /// Adds a new settled vertex. /// </summary> public static uint AddSettledVertex(this PathTree tree, uint vertex, WeightAndDir <float> weightAndDir, uint hops, uint pPointer) { var hopsAndDirection = hops * 4 + weightAndDir.Direction._val; return(tree.Add(vertex, (uint)(weightAndDir.Weight * WeightFactor), hopsAndDirection, pPointer)); }
/// <summary> /// Gets a settled vertex. /// </summary> public static void GetSettledVertex(this PathTree tree, uint pointer, out uint vertex, out WeightAndDir <float> weightAndDir, out uint hops) { uint data0, data1, data2; tree.Get(pointer, out data0, out data1, out data2); vertex = data0; weightAndDir = new WeightAndDir <float>() { Weight = data1 / WeightFactor, Direction = new Dir() { _val = (byte)(data2 & 3) } }; hops = data2 / 4; }
/// <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); } } }