/// <summary> /// Tests the set direction functionality for the given parameters. /// </summary> /// <param name="edge"></param> /// <param name="forward"></param> /// <param name="backward"></param> /// <param name="toHigher"></param> private void DoTestSetDirection(CHEdgeData edge, bool forward, bool backward, bool toHigher) { edge.SetDirection(forward, backward, toHigher); if (forward) { Assert.IsTrue(edge.Forward); } else { Assert.IsFalse(edge.Forward); } if (backward) { Assert.IsTrue(edge.Backward); } else { Assert.IsFalse(edge.Backward); } if (toHigher) { Assert.IsTrue(edge.ToHigher); } else { Assert.IsFalse(edge.ToHigher); } }
/// <summary> /// Tests if the two given edges are compared correctly by the CHEdgeDataComparer. /// </summary> /// <param name="overapping"></param> /// <param name="overlappee"></param> /// <param name="result"></param> private void DoTestCompare(CHEdgeData overapping, CHEdgeData overlappee, bool result) { CHEdgeDataComparer comparer = new CHEdgeDataComparer(); if (result) { Assert.IsTrue(comparer.Overlaps(overapping, overlappee)); } else { Assert.IsFalse(comparer.Overlaps(overapping, overlappee)); } }
public void TestContracted() { var edge = new CHEdgeData(123, true, true, 123.45f); Assert.AreEqual(11, edge.Meta); Assert.AreEqual(123.45f, edge.Weight); Assert.AreEqual(123, edge.Value); Assert.AreEqual(uint.MaxValue, edge.Tags); Assert.AreEqual(false, edge.Forward); Assert.AreEqual(true, edge.CanMoveBackward); Assert.AreEqual(true, edge.CanMoveForward); Assert.AreEqual(123, edge.ContractedId); Assert.IsTrue(edge.IsContracted); Assert.IsFalse(edge.RepresentsNeighbourRelations); edge = new CHEdgeData(123, false, true, 123.45f); Assert.AreEqual(10, edge.Meta); Assert.AreEqual(123.45f, edge.Weight); Assert.AreEqual(123, edge.Value); Assert.AreEqual(uint.MaxValue, edge.Tags); Assert.AreEqual(false, edge.Forward); Assert.AreEqual(false, edge.CanMoveForward); Assert.AreEqual(true, edge.CanMoveBackward); Assert.AreEqual(123, edge.ContractedId); Assert.IsTrue(edge.IsContracted); Assert.IsFalse(edge.RepresentsNeighbourRelations); edge = new CHEdgeData(123, true, false, 123.45f); Assert.AreEqual(9, edge.Meta); Assert.AreEqual(123.45f, edge.Weight); Assert.AreEqual(123, edge.Value); Assert.AreEqual(uint.MaxValue, edge.Tags); Assert.AreEqual(false, edge.Forward); Assert.AreEqual(true, edge.CanMoveForward); Assert.AreEqual(false, edge.CanMoveBackward); Assert.AreEqual(123, edge.ContractedId); Assert.IsTrue(edge.IsContracted); Assert.IsFalse(edge.RepresentsNeighbourRelations); }
public void TestCHEdgeDataSetDirection() { var edge = new CHEdgeData(); this.DoTestSetDirection(edge, false, false, false); this.DoTestSetDirection(edge, true, false, false); this.DoTestSetDirection(edge, false, true, false); this.DoTestSetDirection(edge, false, false, true); this.DoTestSetDirection(edge, true, true, false); this.DoTestSetDirection(edge, true, false, true); this.DoTestSetDirection(edge, false, true, true); this.DoTestSetDirection(edge, true, true, true); this.DoTestSetDirection(edge, false, false); this.DoTestSetDirection(edge, true, false); this.DoTestSetDirection(edge, false, true); this.DoTestSetDirection(edge, true, true); }
/// <summary> /// Calculates the priority of the given vertex. /// </summary> /// <param name="vertex">The vertex to calculate the priority for.</param> /// <param name="newEdges">The number of new edges that would be added.</param> /// <param name="removedEdges">The number of edges that would be removed.</param> /// <param name="depth">The depth of the vertex.</param> /// <param name="contracted">The number of contracted neighours.</param> public float Calculate(uint vertex, out int newEdges, out int removedEdges, out int depth, out int contracted) { newEdges = 0; removedEdges = 0; _contractionCount.TryGetValue(vertex, out contracted); // get all information from the source. var edges = _data.GetEdges(vertex).ToList(); // build the list of edges to replace. var edgesForContractions = new List<Edge<CHEdgeData>>(edges.Count); var tos = new List<uint>(edges.Count); var tosSet = new HashSet<uint>(); foreach (var edge in edges) { // use this edge for contraction. edgesForContractions.Add(edge); tos.Add(edge.Neighbour); tosSet.Add(edge.Neighbour); removedEdges++; } var toRequeue = new HashSet<uint>(); var forwardEdges = new CHEdgeData?[2]; var backwardEdges = new CHEdgeData?[2]; var existingEdgesToRemove = new HashSet<CHEdgeData>(); // loop over each combination of edges just once. var forwardWitnesses = new bool[edgesForContractions.Count]; var backwardWitnesses = new bool[edgesForContractions.Count]; var weights = new List<float>(edgesForContractions.Count); var edgesToY = new Dictionary<uint, Tuple<CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>>(edgesForContractions.Count); for (int x = 1; x < edgesForContractions.Count; x++) { // loop over all elements first. var xEdge = edgesForContractions[x]; // get edges. edgesToY.Clear(); var rawEdgesToY = _data.GetEdges(xEdge.Neighbour); while (rawEdgesToY.MoveNext()) { var rawEdgeNeighbour = rawEdgesToY.Neighbour; if (tosSet.Contains(rawEdgeNeighbour)) { var rawEdgeData = rawEdgesToY.EdgeData; var rawEdgeForwardWeight = rawEdgeData.CanMoveForward ? rawEdgeData.Weight : float.MaxValue; var rawEdgeBackwardWeight = rawEdgeData.CanMoveBackward ? rawEdgeData.Weight : float.MaxValue; Tuple<CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> edgeTuple; if (!edgesToY.TryGetValue(rawEdgeNeighbour, out edgeTuple)) { edgeTuple = new Tuple<CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>(rawEdgeData, null, null, rawEdgeForwardWeight, rawEdgeBackwardWeight); edgesToY.Add(rawEdgeNeighbour, edgeTuple); } else if (!edgeTuple.Item2.HasValue) { edgesToY[rawEdgeNeighbour] = new Tuple<CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>( edgeTuple.Item1, rawEdgeData, null, rawEdgeForwardWeight < edgeTuple.Item4 ? rawEdgeForwardWeight : edgeTuple.Item4, rawEdgeBackwardWeight < edgeTuple.Item5 ? rawEdgeBackwardWeight : edgeTuple.Item5); } else { edgesToY[rawEdgeNeighbour] = new Tuple<CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>( edgeTuple.Item1, edgeTuple.Item2, rawEdgeData, rawEdgeForwardWeight < edgeTuple.Item4 ? rawEdgeForwardWeight : edgeTuple.Item4, rawEdgeBackwardWeight < edgeTuple.Item5 ? rawEdgeBackwardWeight : edgeTuple.Item5); } } } // calculate max weight. weights.Clear(); var forwardUnknown = false; var backwardUnknown = false; for (int y = 0; y < x; y++) { // update maxWeight. var yEdge = edgesForContractions[y]; if (xEdge.Neighbour != yEdge.Neighbour) { // reset witnesses. var forwardWeight = (float)xEdge.EdgeData.Weight + (float)yEdge.EdgeData.Weight; forwardWitnesses[y] = !xEdge.EdgeData.CanMoveBackward || !yEdge.EdgeData.CanMoveForward; backwardWitnesses[y] = !xEdge.EdgeData.CanMoveForward || !yEdge.EdgeData.CanMoveBackward; weights.Add(forwardWeight); Tuple<CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> edgeTuple; if (edgesToY.TryGetValue(yEdge.Neighbour, out edgeTuple)) { if (!forwardWitnesses[y]) { // check 1-hop witnesses. if (edgeTuple.Item4 <= forwardWeight) { forwardWitnesses[y] = true; } } if (!backwardWitnesses[y]) { // check 1-hop witnesses. if (edgeTuple.Item5 <= forwardWeight) { backwardWitnesses[y] = true; } } } forwardUnknown = !forwardWitnesses[y] || forwardUnknown; backwardUnknown = !backwardWitnesses[y] || backwardUnknown; } else { // already set this to true, not use calculating it's witness. forwardWitnesses[y] = true; backwardWitnesses[y] = true; weights.Add(0); } } // calculate witnesses. if (_witnessCalculator.HopLimit > 1) { // 1-hops already checked. if (forwardUnknown || backwardUnknown) { _witnessCalculator.Exists(_data, xEdge.Neighbour, tos, weights, int.MaxValue, ref forwardWitnesses, ref backwardWitnesses, vertex); } } for (int y = 0; y < x; y++) { // loop over all elements. var yEdge = edgesForContractions[y]; // add the combinations of these edges. if (xEdge.Neighbour != yEdge.Neighbour) { // there is a connection from x to y and there is no witness path. // create x-to-y data and edge. var canMoveForward = !forwardWitnesses[y] && (xEdge.EdgeData.CanMoveBackward && yEdge.EdgeData.CanMoveForward); var canMoveBackward = !backwardWitnesses[y] && (xEdge.EdgeData.CanMoveForward && yEdge.EdgeData.CanMoveBackward); if (canMoveForward || canMoveBackward) { // add the edge if there is usefull info or if there needs to be a neighbour relationship. // add contracted edges like normal. // calculate the total weights. var weight = (float)xEdge.EdgeData.Weight + (float)yEdge.EdgeData.Weight; // there are a few options now: // 1) No edges yet between xEdge.Neighbour and yEdge.Neighbour. // 1) There is no other contracted edge: just add as a duplicate. // 2) There is at least on other contracted edge: optimize information because there can only be 4 case between two vertices: // - One bidirectional edge. // - Two directed edges with different weights. // - One forward edge. // - One backward edge. // => all available information needs to be combined. // check existing data. var existingCanMoveForward = false; var existingCanMoveBackward = false; var existingForwardWeight = float.MaxValue; var existingBackwardWeight = float.MaxValue; uint existingForwardContracted = 0; uint existingBackwardContracted = 0; Tuple<CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> edgeTuple; if (edgesToY.TryGetValue(yEdge.Neighbour, out edgeTuple)) { //var existingEdges = _data.GetEdges(xEdge.Neighbour, yEdge.Neighbour); existingEdgesToRemove.Clear(); // remove all existing stuff. var existingEdge = new CHEdgeData(); for (int idx = 0; idx < 3; idx++) { switch (idx) { case 0: existingEdge = edgeTuple.Item1.Value; break; case 1: if (!edgeTuple.Item2.HasValue) { idx = 2; break; } existingEdge = edgeTuple.Item2.Value; break; case 2: if (!edgeTuple.Item3.HasValue) { idx = 2; break; } existingEdge = edgeTuple.Item3.Value; break; } var existingEdgeData = existingEdge; if (existingEdgeData.IsContracted) { // this edge is contracted, collect it's information. existingEdgesToRemove.Add(existingEdgeData); if (existingEdgeData.CanMoveForward) { // can move forward, so at least one edge that can move forward. existingCanMoveForward = true; if (existingForwardWeight > existingEdgeData.Weight) { // update forward weight. existingForwardWeight = existingEdgeData.Weight; existingForwardContracted = existingEdgeData.ContractedId; } } if (existingEdgeData.CanMoveBackward) { // can move backward, so at least one edge that can move backward. existingCanMoveBackward = true; if (existingBackwardWeight > existingEdgeData.Weight) { // update backward weight. existingBackwardWeight = existingEdgeData.Weight; existingBackwardContracted = existingEdgeData.ContractedId; } } } } } if (existingCanMoveForward || existingCanMoveBackward) { // there is already another contraced edge. uint forwardContractedId = vertex; float forwardWeight = weight; // merge with existing data. if (existingCanMoveForward && ((weight > existingForwardWeight) || !canMoveForward)) { // choose the smallest weight. canMoveForward = true; forwardContractedId = existingForwardContracted; forwardWeight = existingForwardWeight; } uint backwardContractedId = vertex; float backwardWeight = weight; // merge with existing data. if (existingCanMoveBackward && ((weight > existingBackwardWeight) || !canMoveBackward)) { // choose the smallest weight. canMoveBackward = true; backwardContractedId = existingBackwardContracted; backwardWeight = existingBackwardWeight; } // add one of the 4 above case. forwardEdges[0] = null; forwardEdges[1] = null; backwardEdges[0] = null; backwardEdges[1] = null; if (canMoveForward && canMoveBackward && forwardWeight == backwardWeight && forwardContractedId == backwardContractedId) { // just add one edge. forwardEdges[0] = new CHEdgeData(forwardContractedId, true, true, forwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(forwardContractedId, true, true, forwardWeight)); backwardEdges[0] = new CHEdgeData(backwardContractedId, true, true, backwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(backwardContractedId, true, true, backwardWeight)); } else if (canMoveBackward && canMoveForward) { // add two different edges. forwardEdges[0] = new CHEdgeData(forwardContractedId, true, false, forwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(forwardContractedId, true, false, forwardWeight)); backwardEdges[0] = new CHEdgeData(forwardContractedId, false, true, forwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(forwardContractedId, false, true, forwardWeight)); forwardEdges[1] = new CHEdgeData(backwardContractedId, false, true, backwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(backwardContractedId, false, true, backwardWeight)); backwardEdges[1] = new CHEdgeData(backwardContractedId, true, false, backwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(backwardContractedId, true, false, backwardWeight)); } else if (canMoveForward) { // only add one forward edge. forwardEdges[0] = new CHEdgeData(forwardContractedId, true, false, forwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(forwardContractedId, true, false, forwardWeight)); backwardEdges[0] = new CHEdgeData(forwardContractedId, false, true, forwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(forwardContractedId, false, true, forwardWeight)); } else if (canMoveBackward) { // only add one backward edge. forwardEdges[0] = new CHEdgeData(backwardContractedId, false, true, backwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(backwardContractedId, false, true, backwardWeight)); backwardEdges[0] = new CHEdgeData(backwardContractedId, true, false, backwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(backwardContractedId, true, false, backwardWeight)); } // remove all existing stuff. foreach (var existingEdgeToRemove in existingEdgesToRemove) { if (forwardEdges[0].Equals(existingEdgeToRemove)) { // this forward edge is to be kept. forwardEdges[0] = null; // it's already there. } else if (forwardEdges[1] != null && !forwardEdges[1].Equals(existingEdgeToRemove)) { // this forward edge is to be kept. forwardEdges[1] = null; // it's already there. } else { // yup, just remove it now. removedEdges++; } var existingEdgeToRemoveBackward = (CHEdgeData)existingEdgeToRemove.Reverse(); if (backwardEdges[0].Equals(existingEdgeToRemoveBackward)) { // this backward edge is to be kept. backwardEdges[0] = null; // it's already there. } else if (backwardEdges[1] != null && !backwardEdges[1].Equals(existingEdgeToRemoveBackward)) { // this backward edge is to be kept. backwardEdges[1] = null; // it's already there. } else { // yup, just remove it now. removedEdges++; } } // add remaining edges. if (forwardEdges[0].HasValue) { newEdges++; } if (forwardEdges[1].HasValue) { newEdges++; } if (backwardEdges[0].HasValue) { newEdges++; } if (backwardEdges[1].HasValue) { newEdges++; } } else { // there is no edge, just add the data. newEdges = newEdges + 2; } } } } } // get the depth. _depth.TryGetValue(vertex, out depth); return 1 * (newEdges - removedEdges) + (2 * depth) + (1 * contracted); }
/// <summary> /// Calculates the priority of the given vertex. /// </summary> /// <param name="vertex">The vertex to calculate the priority for.</param> /// <param name="newEdges">The number of new edges that would be added.</param> /// <param name="removedEdges">The number of edges that would be removed.</param> /// <param name="depth">The depth of the vertex.</param> /// <param name="contracted">The number of contracted neighours.</param> public float Calculate(uint vertex, out int newEdges, out int removedEdges, out int depth, out int contracted) { newEdges = 0; removedEdges = 0; _contractionCount.TryGetValue(vertex, out contracted); // get all information from the source. var edges = _data.GetEdges(vertex).ToList(); // build the list of edges to replace. var edgesForContractions = new List <Edge <CHEdgeData> >(edges.Count); var tos = new List <uint>(edges.Count); var tosSet = new HashSet <uint>(); foreach (var edge in edges) { // use this edge for contraction. edgesForContractions.Add(edge); tos.Add(edge.Neighbour); tosSet.Add(edge.Neighbour); removedEdges++; } var toRequeue = new HashSet <uint>(); var forwardEdges = new CHEdgeData?[2]; var backwardEdges = new CHEdgeData?[2]; var existingEdgesToRemove = new HashSet <CHEdgeData>(); // loop over each combination of edges just once. var forwardWitnesses = new bool[edgesForContractions.Count]; var backwardWitnesses = new bool[edgesForContractions.Count]; var weights = new List <float>(edgesForContractions.Count); var edgesToY = new Dictionary <uint, Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> >(edgesForContractions.Count); for (int x = 1; x < edgesForContractions.Count; x++) { // loop over all elements first. var xEdge = edgesForContractions[x]; // get edges. edgesToY.Clear(); var rawEdgesToY = _data.GetEdges(xEdge.Neighbour); while (rawEdgesToY.MoveNext()) { var rawEdgeNeighbour = rawEdgesToY.Neighbour; if (tosSet.Contains(rawEdgeNeighbour)) { var rawEdgeData = rawEdgesToY.EdgeData; var rawEdgeForwardWeight = rawEdgeData.CanMoveForward ? rawEdgeData.Weight : float.MaxValue; var rawEdgeBackwardWeight = rawEdgeData.CanMoveBackward ? rawEdgeData.Weight : float.MaxValue; Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> edgeTuple; if (!edgesToY.TryGetValue(rawEdgeNeighbour, out edgeTuple)) { edgeTuple = new Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>(rawEdgeData, null, null, rawEdgeForwardWeight, rawEdgeBackwardWeight); edgesToY.Add(rawEdgeNeighbour, edgeTuple); } else if (!edgeTuple.Item2.HasValue) { edgesToY[rawEdgeNeighbour] = new Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>( edgeTuple.Item1, rawEdgeData, null, rawEdgeForwardWeight < edgeTuple.Item4 ? rawEdgeForwardWeight : edgeTuple.Item4, rawEdgeBackwardWeight < edgeTuple.Item5 ? rawEdgeBackwardWeight : edgeTuple.Item5); } else { edgesToY[rawEdgeNeighbour] = new Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float>( edgeTuple.Item1, edgeTuple.Item2, rawEdgeData, rawEdgeForwardWeight < edgeTuple.Item4 ? rawEdgeForwardWeight : edgeTuple.Item4, rawEdgeBackwardWeight < edgeTuple.Item5 ? rawEdgeBackwardWeight : edgeTuple.Item5); } } } // calculate max weight. weights.Clear(); var forwardUnknown = false; var backwardUnknown = false; for (int y = 0; y < x; y++) { // update maxWeight. var yEdge = edgesForContractions[y]; if (xEdge.Neighbour != yEdge.Neighbour) { // reset witnesses. var forwardWeight = (float)xEdge.EdgeData.Weight + (float)yEdge.EdgeData.Weight; forwardWitnesses[y] = !xEdge.EdgeData.CanMoveBackward || !yEdge.EdgeData.CanMoveForward; backwardWitnesses[y] = !xEdge.EdgeData.CanMoveForward || !yEdge.EdgeData.CanMoveBackward; weights.Add(forwardWeight); Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> edgeTuple; if (edgesToY.TryGetValue(yEdge.Neighbour, out edgeTuple)) { if (!forwardWitnesses[y]) { // check 1-hop witnesses. if (edgeTuple.Item4 <= forwardWeight) { forwardWitnesses[y] = true; } } if (!backwardWitnesses[y]) { // check 1-hop witnesses. if (edgeTuple.Item5 <= forwardWeight) { backwardWitnesses[y] = true; } } } forwardUnknown = !forwardWitnesses[y] || forwardUnknown; backwardUnknown = !backwardWitnesses[y] || backwardUnknown; } else { // already set this to true, not use calculating it's witness. forwardWitnesses[y] = true; backwardWitnesses[y] = true; weights.Add(0); } } // calculate witnesses. if (_witnessCalculator.HopLimit > 1) { // 1-hops already checked. if (forwardUnknown || backwardUnknown) { _witnessCalculator.Exists(_data, xEdge.Neighbour, tos, weights, int.MaxValue, ref forwardWitnesses, ref backwardWitnesses, vertex); } } for (int y = 0; y < x; y++) { // loop over all elements. var yEdge = edgesForContractions[y]; // add the combinations of these edges. if (xEdge.Neighbour != yEdge.Neighbour) { // there is a connection from x to y and there is no witness path. // create x-to-y data and edge. var canMoveForward = !forwardWitnesses[y] && (xEdge.EdgeData.CanMoveBackward && yEdge.EdgeData.CanMoveForward); var canMoveBackward = !backwardWitnesses[y] && (xEdge.EdgeData.CanMoveForward && yEdge.EdgeData.CanMoveBackward); if (canMoveForward || canMoveBackward) { // add the edge if there is usefull info or if there needs to be a neighbour relationship. // add contracted edges like normal. // calculate the total weights. var weight = (float)xEdge.EdgeData.Weight + (float)yEdge.EdgeData.Weight; // there are a few options now: // 1) No edges yet between xEdge.Neighbour and yEdge.Neighbour. // 1) There is no other contracted edge: just add as a duplicate. // 2) There is at least on other contracted edge: optimize information because there can only be 4 case between two vertices: // - One bidirectional edge. // - Two directed edges with different weights. // - One forward edge. // - One backward edge. // => all available information needs to be combined. // check existing data. var existingCanMoveForward = false; var existingCanMoveBackward = false; var existingForwardWeight = float.MaxValue; var existingBackwardWeight = float.MaxValue; uint existingForwardContracted = 0; uint existingBackwardContracted = 0; Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> edgeTuple; if (edgesToY.TryGetValue(yEdge.Neighbour, out edgeTuple)) { //var existingEdges = _data.GetEdges(xEdge.Neighbour, yEdge.Neighbour); existingEdgesToRemove.Clear(); // remove all existing stuff. var existingEdge = new CHEdgeData(); for (int idx = 0; idx < 3; idx++) { switch (idx) { case 0: existingEdge = edgeTuple.Item1.Value; break; case 1: if (!edgeTuple.Item2.HasValue) { idx = 2; break; } existingEdge = edgeTuple.Item2.Value; break; case 2: if (!edgeTuple.Item3.HasValue) { idx = 2; break; } existingEdge = edgeTuple.Item3.Value; break; } var existingEdgeData = existingEdge; if (existingEdgeData.IsContracted) { // this edge is contracted, collect it's information. existingEdgesToRemove.Add(existingEdgeData); if (existingEdgeData.CanMoveForward) { // can move forward, so at least one edge that can move forward. existingCanMoveForward = true; if (existingForwardWeight > existingEdgeData.Weight) { // update forward weight. existingForwardWeight = existingEdgeData.Weight; existingForwardContracted = existingEdgeData.ContractedId; } } if (existingEdgeData.CanMoveBackward) { // can move backward, so at least one edge that can move backward. existingCanMoveBackward = true; if (existingBackwardWeight > existingEdgeData.Weight) { // update backward weight. existingBackwardWeight = existingEdgeData.Weight; existingBackwardContracted = existingEdgeData.ContractedId; } } } } } if (existingCanMoveForward || existingCanMoveBackward) { // there is already another contraced edge. uint forwardContractedId = vertex; float forwardWeight = weight; // merge with existing data. if (existingCanMoveForward && ((weight > existingForwardWeight) || !canMoveForward)) { // choose the smallest weight. canMoveForward = true; forwardContractedId = existingForwardContracted; forwardWeight = existingForwardWeight; } uint backwardContractedId = vertex; float backwardWeight = weight; // merge with existing data. if (existingCanMoveBackward && ((weight > existingBackwardWeight) || !canMoveBackward)) { // choose the smallest weight. canMoveBackward = true; backwardContractedId = existingBackwardContracted; backwardWeight = existingBackwardWeight; } // add one of the 4 above case. forwardEdges[0] = null; forwardEdges[1] = null; backwardEdges[0] = null; backwardEdges[1] = null; if (canMoveForward && canMoveBackward && forwardWeight == backwardWeight && forwardContractedId == backwardContractedId) { // just add one edge. forwardEdges[0] = new CHEdgeData(forwardContractedId, true, true, forwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(forwardContractedId, true, true, forwardWeight)); backwardEdges[0] = new CHEdgeData(backwardContractedId, true, true, backwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(backwardContractedId, true, true, backwardWeight)); } else if (canMoveBackward && canMoveForward) { // add two different edges. forwardEdges[0] = new CHEdgeData(forwardContractedId, true, false, forwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(forwardContractedId, true, false, forwardWeight)); backwardEdges[0] = new CHEdgeData(forwardContractedId, false, true, forwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(forwardContractedId, false, true, forwardWeight)); forwardEdges[1] = new CHEdgeData(backwardContractedId, false, true, backwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(backwardContractedId, false, true, backwardWeight)); backwardEdges[1] = new CHEdgeData(backwardContractedId, true, false, backwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(backwardContractedId, true, false, backwardWeight)); } else if (canMoveForward) { // only add one forward edge. forwardEdges[0] = new CHEdgeData(forwardContractedId, true, false, forwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(forwardContractedId, true, false, forwardWeight)); backwardEdges[0] = new CHEdgeData(forwardContractedId, false, true, forwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(forwardContractedId, false, true, forwardWeight)); } else if (canMoveBackward) { // only add one backward edge. forwardEdges[0] = new CHEdgeData(backwardContractedId, false, true, backwardWeight); //_target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(backwardContractedId, false, true, backwardWeight)); backwardEdges[0] = new CHEdgeData(backwardContractedId, true, false, backwardWeight); //_target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(backwardContractedId, true, false, backwardWeight)); } // remove all existing stuff. foreach (var existingEdgeToRemove in existingEdgesToRemove) { if (forwardEdges[0].Equals(existingEdgeToRemove)) { // this forward edge is to be kept. forwardEdges[0] = null; // it's already there. } else if (forwardEdges[1] != null && !forwardEdges[1].Equals(existingEdgeToRemove)) { // this forward edge is to be kept. forwardEdges[1] = null; // it's already there. } else { // yup, just remove it now. removedEdges++; } var existingEdgeToRemoveBackward = (CHEdgeData)existingEdgeToRemove.Reverse(); if (backwardEdges[0].Equals(existingEdgeToRemoveBackward)) { // this backward edge is to be kept. backwardEdges[0] = null; // it's already there. } else if (backwardEdges[1] != null && !backwardEdges[1].Equals(existingEdgeToRemoveBackward)) { // this backward edge is to be kept. backwardEdges[1] = null; // it's already there. } else { // yup, just remove it now. removedEdges++; } } // add remaining edges. if (forwardEdges[0].HasValue) { newEdges++; } if (forwardEdges[1].HasValue) { newEdges++; } if (backwardEdges[0].HasValue) { newEdges++; } if (backwardEdges[1].HasValue) { newEdges++; } } else { // there is no edge, just add the data. newEdges = newEdges + 2; } } } } } // get the depth. _depth.TryGetValue(vertex, out depth); return(1 * (newEdges - removedEdges) + (2 * depth) + (1 * contracted)); }