/// <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); // remove all informative edges. neighbours = neighbours.RemoveInformativeEdges(); // 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(_data, 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> /// 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); }