/// <summary> /// replaces the old adjacency list with a new one where all removed vertices no longer occupy a spot in the list. A mapping that maps the new vertices back to the old ones is returned. /// </summary> /// <param name="reconstructionIndexationMapping"></param> public void Reduce(out ReindexationMapping reconstructionIndexationMapping) { if (!isReduced) { reconstructionIndexationMapping = null; return; } BuildReindexationMappings(out reconstructionIndexationMapping, out Dictionary <int, int> reductionMapping); vertexCount = 0; edgeCount = 0; // use that mapping to reduce the adjacency list for this graph List <int>[] reducedAdjacencyList = new List <int> [reductionMapping.Count]; int vertex = -1; while ((vertex = notRemovedVertices.NextElement(vertex)) != -1) { vertexCount++; List <int> currentVertexAdjacencies = new List <int>(adjacencyList[vertex].Count); for (int j = 0; j < adjacencyList[vertex].Count; j++) { int neighbor = adjacencyList[vertex][j]; currentVertexAdjacencies.Add(reductionMapping[neighbor]); } reducedAdjacencyList[reductionMapping[vertex]] = currentVertexAdjacencies; edgeCount += currentVertexAdjacencies.Count; } edgeCount /= 2; notRemovedVertexCount = vertexCount; adjacencyList = reducedAdjacencyList; notRemovedVertices = BitSet.All(vertexCount); openNeighborhood = new BitSet[vertexCount]; closedNeighborhood = new BitSet[vertexCount]; for (int i = 0; i < vertexCount; i++) { openNeighborhood[i] = new BitSet(vertexCount, adjacencyList[i]); closedNeighborhood[i] = new BitSet(openNeighborhood[i]); closedNeighborhood[i][i] = true; } isReduced = false; if (verbose) { Console.WriteLine("reduced graph {0} to {1} vertices and {2} edges", graphID, reducedAdjacencyList.Length, edgeCount); } }
/// <summary> /// Constructs both a forward and a backward mapping between reduced vertex indices and original vertex indices. /// </summary> /// <param name="reindexationMapping">the mapping from reduced vertex indices back to original vertex indices</param> /// <param name="reductionMapping">the mapping from original vertex indices to reduced vertex indices</param> private void BuildReindexationMappings(out ReindexationMapping reindexationMapping, out Dictionary <int, int> reductionMapping) { reindexationMapping = new ReindexationMapping(vertexCount); reductionMapping = new Dictionary <int, int>(); int counter = 0; int vertex = -1; while ((vertex = notRemovedVertices.NextElement(vertex)) != -1) { reductionMapping.Add(vertex, counter); reindexationMapping.Add(vertex); counter++; } }
/// <summary> /// reindexes the vertices of this ptd that is a ptd of a reduced graph, so that they correctly represent the same vertices in the non-reduced graph. /// </summary> /// <param name="reindexationMapping">the mapping from the vertex indices in the current ptd to their original vertex indices within the original graph.</param> public void Reindex(ReindexationMapping reindexationMapping) { // initialize a stack of nodes Stack <PTD> nodeStack = new Stack <PTD>(); nodeStack.Push(this); // re-index all bags with the vertices they had before reduction while (nodeStack.Count > 0) { PTD currentNode = nodeStack.Pop(); BitSet reducedBag = currentNode.Bag; BitSet reconstructedBag = reindexationMapping.Reindex(reducedBag); currentNode.SetBag(reconstructedBag); // push children onto stack for (int i = 0; i < currentNode.children.Count; i++) { nodeStack.Push(currentNode.children[i]); } } }
/// <summary> /// separates the graph at a given safe separator into subgraphs. /// If a tree decomposition for one subgraph has already been calculated, the index of that subgraph is also given out /// </summary> /// <param name="separator">the safe separator</param> /// <param name="reconstructionIndexationMappings">the corresponding mapping for reindexing the vertices in the subgraphs back to their old indices within this graph</param> /// <param name="alreadyCalculatedComponent">Optionally, a component whose subgraph has an already calculated PTD. /// (This happens when a safe separator is found during the "HasTreewidth" calculation.)</param> /// <param name="alreadyCalculatedComponentIndex">-1, if no alreadyCalculatedComponent is passed, else the index in the list of subgraphs of the subgraph corresponding to that component</param> /// <returns>a list of the subgraphs</returns> public List <Graph> Separate(BitSet separator, out List <ReindexationMapping> reconstructionIndexationMappings, out int alreadyCalculatedComponentIndex, BitSet alreadyCalculatedComponent = null) { alreadyCalculatedComponentIndex = -1; List <Graph> subGraphs = new List <Graph>(); List <int> separatorVertices = separator.Elements(); reconstructionIndexationMappings = new List <ReindexationMapping>(); // for each component foreach ((BitSet component, BitSet _) in ComponentsAndNeighbors(separator)) { if (alreadyCalculatedComponent != null && component.Equals(alreadyCalculatedComponent)) { alreadyCalculatedComponentIndex = subGraphs.Count; } List <int> vertices = component.Elements(); component.UnionWith(separator); // map vertices from this graph to the new subgraph and vice versa Dictionary <int, int> reductionMapping = new Dictionary <int, int>(vertexCount + separatorVertices.Count); ReindexationMapping reconstructionIndexationMapping = new ReindexationMapping(vertexCount); reconstructionIndexationMappings.Add(reconstructionIndexationMapping); for (int i = 0; i < vertices.Count; i++) { reductionMapping[vertices[i]] = i; reconstructionIndexationMapping.Add(vertices[i]); } // don't forget the separator for (int i = 0; i < separatorVertices.Count; i++) { int u = separatorVertices[i]; reductionMapping[u] = vertices.Count + i; reconstructionIndexationMapping.Add(u); } // create new adjacency list List <int>[] subAdjacencyList = new List <int> [vertices.Count + separatorVertices.Count]; for (int i = 0; i < vertices.Count; i++) { int oldVertex = vertices[i]; int newVertex = reductionMapping[oldVertex]; subAdjacencyList[newVertex] = new List <int>(adjacencyList[oldVertex].Count); foreach (int oldNeighbor in adjacencyList[oldVertex]) { int newNeighbor = reductionMapping[oldNeighbor]; subAdjacencyList[newVertex].Add(newNeighbor); } } // also for the separator for (int i = 0; i < separatorVertices.Count; i++) { int u = separatorVertices[i]; subAdjacencyList[vertices.Count + i] = new List <int>(); foreach (int oldNeighbor in adjacencyList[u]) { if (component[oldNeighbor]) { int newNeighbor = reductionMapping[oldNeighbor]; subAdjacencyList[vertices.Count + i].Add(newNeighbor); } } } Graph subGraph = new Graph(subAdjacencyList); subGraphs.Add(subGraph); } // print some stats if (verbose) { Console.WriteLine("splitted graph {0} with {1} vertices and {2} edges into {3} smaller graphs:", graphID, vertexCount, edgeCount, subGraphs.Count); foreach (Graph subGraph in subGraphs) { Console.WriteLine(" graph {0} with {1} vertices and {2} edges", subGraph.graphID, subGraph.vertexCount, subGraph.edgeCount); } } return(subGraphs); }