/// <summary> /// Calculates the edge-difference if u would be contracted. /// </summary> /// <param name="vertex"></param> /// <returns></returns> public float Calculate(uint vertex) { // get the neighbours. KeyValuePair <uint, CHEdgeData>[] neighbours = _data.GetArcs(vertex); // simulate the construction of new edges. int new_edges = 0; int removed = neighbours.Length; // loop over all neighbours and check for witnesses. foreach (KeyValuePair <uint, CHEdgeData> from in neighbours) { // loop over all incoming neighbours foreach (KeyValuePair <uint, CHEdgeData> to in neighbours) { // loop over all outgoing neighbours if (to.Key != from.Key) { // the neighbours point to different vertices. // a new edge is needed. if (!_witness_calculator.Exists(from.Key, to.Key, vertex, (float)from.Value.Weight + (float)to.Value.Weight, int.MaxValue)) { // no witness exists. new_edges++; } } } } return(new_edges - removed); }
/// <summary> /// Calculates the edge-difference if u would be contracted. /// </summary> /// <param name="vertex"></param> /// <returns></returns> public float Calculate(uint vertex) { short contracted = 0; _contraction_count.TryGetValue(vertex, out contracted); // get the neighbours. var neighbours = _data.GetEdges(vertex); // simulate the construction of new edges. int new_edges = 0; int removed = neighbours.Length; // loop over all neighbours and check for witnesses. foreach (KeyValuePair <uint, CHEdgeData> from in neighbours) { // loop over all incoming neighbours if (!from.Value.Backward) { continue; } foreach (KeyValuePair <uint, CHEdgeData> to in neighbours) { // loop over all outgoing neighbours if (to.Key != from.Key && to.Value.Forward) { // the neighbours point to different vertices. // a new edge is needed. if (!_witness_calculator.Exists(_data, from.Key, to.Key, vertex, (float)from.Value.Weight + (float)to.Value.Weight, 1000)) { // no witness exists. new_edges++; } } } } // get the depth. long depth = 0; _depth.TryGetValue(vertex, out depth); return((((new_edges) - removed)) + (2 * contracted)); //return (new_edges - removed) + depth; }
/// <summary> /// Calculates the edge-difference if u would be contracted. /// </summary> /// <param name="vertex"></param> /// <returns></returns> public float Calculate(uint vertex) { // get the neighbours. var neighbours = _data.GetEdges(vertex); // simulate the construction of new edges. int newEdges = 0; int removed = 0; var edgesForContractions = new List <KeyValuePair <uint, CHEdgeData> >(neighbours.Length); foreach (var neighbour in neighbours) { if (!neighbour.Value.ToLower && !neighbour.Value.ToHigher) { edgesForContractions.Add(neighbour); removed++; } } // loop over all neighbours and check for witnesses. foreach (var from in edgesForContractions) { // loop over all incoming neighbours foreach (var to in edgesForContractions) { // loop over all outgoing neighbours if (to.Key != from.Key && to.Value.Forward && from.Value.Backward) { // the neighbours point to different vertices. // a new edge is needed. if (!_witnessCalculator.Exists(_data, from.Key, to.Key, vertex, (float)from.Value.Weight + (float)to.Value.Weight, 1000)) { // no witness exists. newEdges++; } } } } return((2 * newEdges) - removed); }
/// <summary> /// Contracts the given vertex. /// </summary> /// <param name="vertex"></param> public void Contract(uint vertex) { if (_contracted.Length > vertex && _contracted[vertex]) { throw new Exception("Is already contracted!"); } // keep the neighbours. HashSet <KeyValuePair <uint, CHEdgeData> > neighbours = new HashSet <KeyValuePair <uint, CHEdgeData> >(); // get all information from the source. KeyValuePair <uint, CHEdgeData>[] edges = _target.GetArcs(vertex); // remove all informative edges. edges = edges.RemoveInformativeEdges(); // report the before contraction event. this.OnBeforeContraction(vertex, edges); // remove the edges from the neighbours to the target. foreach (KeyValuePair <uint, CHEdgeData> edge in edges) { // remove the edge. _target.DeleteArc(edge.Key, vertex); // keep the neighbour. if (_keepDirectNeighbours && !edge.Value.HasContractedVertex) { // edge does represent a neighbour relation. neighbours.Add( new KeyValuePair <uint, CHEdgeData>(edge.Key, edge.Value.ConvertToInformative())); } } // loop over each combination of edges just once. for (int x = 1; x < edges.Length; x++) { // loop over all elements first. KeyValuePair <uint, CHEdgeData> xEdge = edges[x]; if (xEdge.Value.IsInformative) { continue; } for (int y = 0; y < x; y++) { // loop over all elements. KeyValuePair <uint, CHEdgeData> yEdge = edges[y]; if (yEdge.Value.IsInformative) { continue; } // calculate the total weight. float weight = xEdge.Value.Weight + yEdge.Value.Weight; // add the combinations of these edges. if (((xEdge.Value.Backward && yEdge.Value.Forward) || (yEdge.Value.Backward && xEdge.Value.Forward)) && (xEdge.Key != yEdge.Key)) { // there is a connection from x to y and there is no witness path. bool witnessXToY = _witnessCalculator.Exists(_target, xEdge.Key, yEdge.Key, vertex, weight, 100); bool witnessYToX = _witnessCalculator.Exists(_target, yEdge.Key, xEdge.Key, vertex, weight, 100); // create x-to-y data and edge. CHEdgeData dataXToY = new CHEdgeData(); bool forward = (xEdge.Value.Backward && yEdge.Value.Forward) && !witnessXToY; bool backward = (yEdge.Value.Backward && xEdge.Value.Forward) && !witnessYToX; dataXToY.SetDirection(forward, backward, true); dataXToY.Weight = weight; dataXToY.ContractedVertexId = vertex; if ((dataXToY.Forward || dataXToY.Backward) || !_target.HasArc(xEdge.Key, yEdge.Key)) { // add the edge if there is usefull info or if there needs to be a neighbour relationship. _target.AddArc(xEdge.Key, yEdge.Key, dataXToY, _comparer); } // create y-to-x data and edge. CHEdgeData dataYToX = new CHEdgeData(); forward = (yEdge.Value.Backward && xEdge.Value.Forward) && !witnessYToX; backward = (xEdge.Value.Backward && yEdge.Value.Forward) && !witnessXToY; dataYToX.SetDirection(forward, backward, true); dataYToX.Weight = weight; dataYToX.ContractedVertexId = vertex; if ((dataYToX.Forward || dataYToX.Backward) || !_target.HasArc(yEdge.Key, xEdge.Key)) { // add the edge if there is usefull info or if there needs to be a neighbour relationship. _target.AddArc(yEdge.Key, xEdge.Key, dataYToX, _comparer); } } } } // mark the vertex as contracted. this.MarkContracted(vertex); // notify a contracted neighbour. _calculator.NotifyContracted(vertex); // add contracted neighbour edges again. if (_keepDirectNeighbours) { foreach (KeyValuePair <uint, CHEdgeData> neighbour in neighbours) { _target.AddArc(neighbour.Key, vertex, neighbour.Value, null); } } // report the after contraction event. this.OnAfterContraction(vertex, edges); }
/// <summary> /// Contracts the given vertex. /// </summary> /// <param name="vertex"></param> public void Contract(uint vertex) { if (this.IsContracted(vertex)) { throw new Exception("Is already contracted!"); } // get all information from the source. var edges = _target.GetEdges(vertex).ToList(); // report the before contraction event. this.OnBeforeContraction(vertex, edges); // build the list of edges to replace. var allNeigbours = 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. allNeigbours.Add(edge); tos.Add(edge.Neighbour); tosSet.Add(edge.Neighbour); // remove the edge in downwards direction and on the edge with the same data. _target.RemoveEdge(edge.Neighbour, vertex); } //// build the list of pairs and make sure duplicates don't count. //var allNeighbourPairs = new Dictionary<Tuple<uint, uint>, Tuple<float, float>>(); //for(int x = 1; x < allNeigbours.Count; x++) //{ // var xEdge = allNeigbours[x]; // var xEdgeForwardWeight = xEdge.EdgeData.CanMoveBackward ? xEdge.EdgeData.Weight : float.MaxValue; // var xEdgeBackwardWeight = xEdge.EdgeData.CanMoveForward ? xEdge.EdgeData.Weight : float.MaxValue; // for(int y = 0; y < x; y++) // { // var yEdge = allNeigbours[x]; // //var yEdgeForwardWeight = yEdge.EdgeData.CanMoveBackward ? yEdge.EdgeData.Weight : float.MaxValue; // //var yEdgeBackwardWeight = yEdge.EdgeData.CanMoveForward ? yEdge.EdgeData.Weight : float.MaxValue; // float forwardWeight = float.MaxValue; // float backwardWeight = float.MaxValue; // if(xEdge.Neighbour < yEdge.Neighbour) // { // if (xEdge.EdgeData.CanMoveBackward && yEdge.EdgeData.CanMoveForward) // { // forwardWeight = xEdgeBackwardWeight + yEdge.EdgeData.Weight; // } // if (xEdge.EdgeData.CanMoveForward && yEdge.EdgeData.CanMoveBackward) // { // backwardWeight = xEdgeForwardWeight + yEdge.EdgeData.Weight; // } // } // else if(xEdge.Neighbour > yEdge.Neighbour) // { // if (xEdge.EdgeData.CanMoveBackward && yEdge.EdgeData.CanMoveForward) // { // backwardWeight = xEdgeBackwardWeight + yEdge.EdgeData.Weight; // } // if (xEdge.EdgeData.CanMoveForward && yEdge.EdgeData.CanMoveBackward) // { // forwardWeight = xEdgeForwardWeight + yEdge.EdgeData.Weight; // } // } // Tuple<float, float> existingWeights; // Tuple<uint, uint> neighbourPair = new Tuple<uint,uint>(xEdge.Neighbour, yEdge.Neighbour); // if(!allNeighbourPairs.TryGetValue(neighbourPair, out existingWeights)) // { // if (existingWeights.Item1 < forwardWeight) // { // forwardWeight = existingWeights.Item1; // } // if (existingWeights.Item2 < backwardWeight) // { // backwardWeight = existingWeights.Item2; // } // } // allNeighbourPairs[neighbourPair] = new Tuple<float, float>(forwardWeight, backwardWeight); // } //} 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[allNeigbours.Count]; var backwardWitnesses = new bool[allNeigbours.Count]; var weights = new List <float>(allNeigbours.Count); var edgesToY = new Dictionary <uint, Tuple <CHEdgeData?, CHEdgeData?, CHEdgeData?, float, float> >(allNeigbours.Count); for (int x = 1; x < allNeigbours.Count; x++) { // loop over all elements first. var xEdge = allNeigbours[x]; // get edges. edgesToY.Clear(); var rawEdgesToY = _target.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 = allNeigbours[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 (forwardUnknown || backwardUnknown) { _contractionWitnessCalculator.Exists(_target, xEdge.Neighbour, tos, weights, int.MaxValue, ref forwardWitnesses, ref backwardWitnesses); } for (int y = 0; y < x; y++) { // loop over all elements. var yEdge = allNeigbours[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. // 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 existingForwardWeight = float.MaxValue; var existingBackwardWeight = float.MaxValue; uint existingForwardContracted = 0; uint existingBackwardContracted = 0; var existingCanMoveForward = false; var existingCanMoveBackward = false; var existingEdges = _target.GetEdges(xEdge.Neighbour, yEdge.Neighbour); existingEdgesToRemove.Clear(); while (existingEdges.MoveNext()) { var existingEdgeData = existingEdges.EdgeData; 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. _target.RemoveEdge(xEdge.Neighbour, yEdge.Neighbour, existingEdgeToRemove); } 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. _target.RemoveEdge(yEdge.Neighbour, xEdge.Neighbour, existingEdgeToRemoveBackward); } } // add remaining edges. if (forwardEdges[0].HasValue) { _target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, forwardEdges[0].Value); } if (forwardEdges[1].HasValue) { _target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, forwardEdges[1].Value); } if (backwardEdges[0].HasValue) { _target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, backwardEdges[0].Value); } if (backwardEdges[1].HasValue) { _target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, backwardEdges[1].Value); } toRequeue.Add(xEdge.Neighbour); toRequeue.Add(yEdge.Neighbour); } else { // there is no edge, just add the data. // add contracted edges like normal. _target.AddEdge(xEdge.Neighbour, yEdge.Neighbour, new CHEdgeData(vertex, canMoveForward, canMoveBackward, weight)); _target.AddEdge(yEdge.Neighbour, xEdge.Neighbour, new CHEdgeData(vertex, canMoveBackward, canMoveForward, weight)); toRequeue.Add(xEdge.Neighbour); toRequeue.Add(yEdge.Neighbour); } } } } } // mark the vertex as contracted. this.MarkContracted(vertex); // notify a contracted neighbour. _calculator.NotifyContracted(vertex); // report the after contraction event. this.OnAfterContraction(vertex, allNeigbours); //// update priority of direct neighbours. //foreach (var neighbour in toRequeue) //{ // this.ReQueue(neighbour); //} }
/// <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> /// Contracts the given vertex. /// </summary> /// <param name="vertex"></param> public void Contract(uint vertex) { if (_contracted.Length > vertex && _contracted[vertex]) { throw new Exception("Is already contracted!"); } // keep the neighbours. var neighbours = new HashSet <KeyValuePair <uint, CHEdgeData> >(); // get all information from the source. var edges = _target.GetEdges(vertex); // report the before contraction event. this.OnBeforeContraction(vertex, edges); // replace the adjacent edges with edges that are point up. var edgesForContractions = new List <KeyValuePair <uint, CHEdgeData> >(edges.Length); foreach (var edge in edges) { if (!edge.Value.ToLower && !edge.Value.ToHigher) { // the edge is not to lower or higher. // use this edge for contraction. edgesForContractions.Add(edge); // overwrite the old edge making it point 'to higher' only. _target.AddEdge(vertex, edge.Key, new CHEdgeData(edge.Value.Weight, edge.Value.Forward, edge.Value.Backward, true, edge.Value.ContractedVertexId, edge.Value.Tags), null); } } // loop over each combination of edges just once. for (int x = 1; x < edgesForContractions.Count; x++) { // loop over all elements first. var xEdge = edgesForContractions[x]; for (int y = 0; y < x; y++) { // loop over all elements. var yEdge = edgesForContractions[y]; // calculate the total weight. var weight = xEdge.Value.Weight + yEdge.Value.Weight; // add the combinations of these edges. if (((xEdge.Value.Backward && yEdge.Value.Forward) || (yEdge.Value.Backward && xEdge.Value.Forward)) && (xEdge.Key != yEdge.Key)) { // there is a connection from x to y and there is no witness path. var witnessXToY = _contractionWitnessCalculator.Exists(_target, xEdge.Key, yEdge.Key, vertex, weight, int.MaxValue); var witnessYToX = _contractionWitnessCalculator.Exists(_target, yEdge.Key, xEdge.Key, vertex, weight, int.MaxValue); // create x-to-y data and edge. var dataXToY = new CHEdgeData(); var forward = (xEdge.Value.Backward && yEdge.Value.Forward) && !witnessXToY; var backward = (yEdge.Value.Backward && xEdge.Value.Forward) && !witnessYToX; if ((forward || backward) || !_target.ContainsEdge(xEdge.Key, yEdge.Key)) { // add the edge if there is usefull info or if there needs to be a neighbour relationship. dataXToY.SetDirection(forward, backward); dataXToY.Weight = weight; dataXToY.ContractedVertexId = vertex; _target.AddEdge(xEdge.Key, yEdge.Key, dataXToY, null, _comparer); } } } } // mark the vertex as contracted. this.MarkContracted(vertex); // notify a contracted neighbour. _calculator.NotifyContracted(vertex); // report the after contraction event. this.OnAfterContraction(vertex, edges); }