/*************************/ // Construction /*************************/ // Constructor for a new graph of size n public Graph(int n) { vertices = new BitSet(0, n); AdjacencyMatrix = new BitSet[n]; Size = n; for (int i = 0; i < n; i++) { vertices.Add(i); AdjacencyMatrix[i] = new BitSet(0, n); } }
// Counts the number of independent sets in a graph, such that: // - All vertices in R are included in the independent set, initially empty // - Some of the vertices in P are included in the independent set, initially all vertices of the graph // - None of the vertices in X are included in the independent set, initially empty private static int Compute(Graph graph, BitSet R, BitSet P, BitSet X) { // Base case, when P and X are both empty we cannot expand the IS if (P.IsEmpty && X.IsEmpty) return 1; int count = 0; BitSet copy = P.Copy(); // Foreach vertex v in P we include it in the IS and compute how many maximal IS will include v by going into recursion. foreach (int v in copy) { count += Compute(graph, R + v, P - graph.ClosedNeighborhood(v), X - graph.OpenNeighborhood(v)); P.Remove(v); X.Add(v); } return count; }
// Parses a decomposition given the filename of the decomposition and the graph files. public static Decomposition ParseDecomposition(string decompositionFilename, string graphFilename) { Graph graph = ParseGraph(graphFilename); StreamReader sr = new StreamReader(decompositionFilename); string line; Tree tree = new Tree(); // Each line is simply an integer, which is the sequence of the linear decomposition while ((line = sr.ReadLine()) != null) { // Skip comments if (line.StartsWith("c ")) continue; string[] s = line.Trim().Split(' '); BitSet node = new BitSet(0, graph.Size); foreach (string vertex in s) node.Add(int.Parse(vertex) - 1); // -1 because internally we work with [0,...,n) tree.Insert(node); } return new Decomposition(graph, tree); }
// Counts the number of independent sets in a graph, such that: // - All vertices in R are included in the independent set, initially empty // - Some of the vertices in P are included in the independent set, initially all vertices of the graph // - None of the vertices in X are included in the independent set, initially empty private static long Compute(Graph graph, BitSet R, BitSet P, BitSet X) { // Base case, when P and X are both empty we cannot expand the IS if (P.IsEmpty && X.IsEmpty) return 1; long count = 0; int pivot = -1; int min = int.MaxValue; // Procedure to find a pivot // The idea is that in any maximal IS, either vertex u or a neighbor of u is included (else we could expand by adding u to the IS) // We find the u with the smallest neighborhood, so that we will keep the number of branches low foreach (int u in (P + X)) { int size = (P * graph.OpenNeighborhood(u)).Count; if (size < min) { min = size; pivot = u; } } // There should always be a pivot after the selection procedure, else P and X should both have been empty if (pivot == -1) throw new Exception("Pivot has not been selected"); // Foreach vertex v in the set containing the legal choices of the the closed neighborhood of the pivot, // we include each choice in the IS and compute how many maximal IS will include v by going into recursion foreach (int v in (P * graph.ClosedNeighborhood(pivot))) { count += Compute(graph, R + v, P - graph.ClosedNeighborhood(v), X - graph.OpenNeighborhood(v)); P.Remove(v); X.Add(v); } return count; }
// Alternative way of calculating the boolean width of a decomposition by counting the number of maximal independent sets in bipartite graphs, // constructed for each cut of the decomposition private long CalculateBooleanWidthBiPartite() { BitSet left = new BitSet(0, Graph.Size); BitSet right = Graph.Vertices; long max = int.MinValue; foreach (int v in Sequence) { left.Add(v); right.Remove(v); // Construct the bipartite graph BipartiteGraph bg = new BipartiteGraph(Graph, left, right); // Count the number of maximal independent sets in this bipartite graph max = Math.Max(max, CC_MIS.Compute(bg)); } return max; }
public static int Compute(LinearDecomposition decomposition) { Graph graph = decomposition.Graph; int n = graph.Size; List<int> sequence = decomposition.Sequence; BitSet left = new BitSet(0, graph.Size); BitSet right = graph.Vertices; BitSet VG = graph.Vertices; LinearRepresentativeTable cuts = new LinearRepresentativeTable(graph, sequence); LookupTable table = new LookupTable(); // first initialize the very first leaf node int l = sequence[0]; left.Add(l); right.Remove(l); // Base cases BitSet leaf = new BitSet(0, n) { l }; BitSet nleaf = new BitSet(0, n) { graph.OpenNeighborhood(l).First() }; table[new BitSet(0, n), new BitSet(0, n)] = int.MaxValue; table[leaf, new BitSet(0, n)] = 1; table[leaf, nleaf] = 1; table[new BitSet(0, n), nleaf] = 0; for (int i = 1; i < sequence.Count; i++) { int v = sequence[i]; left.Add(v); right.Remove(v); LinearRepresentativeList LRw = cuts[left]; LinearRepresentativeList LRw_ = cuts[right]; LinearRepresentativeList LRa = cuts[left - v]; LinearRepresentativeList LRa_ = cuts[right + v]; LookupTable newTable = new LookupTable(); foreach (BitSet outside in LRw_) { foreach (BitSet inside in LRa) { BitSet nrw_ = graph.Neighborhood(outside) * (left - v); BitSet ra_ = LRa_.GetRepresentative(nrw_); BitSet nra = graph.Neighborhood(inside) * right; BitSet rw = LRw.GetRepresentative(nra); int savedValue = newTable[rw, outside]; int newValue = table[inside, ra_]; BitSet raw_ = inside + outside; BitSet nraw_ = graph.Neighborhood(raw_); if (!nraw_.Contains(v)) newValue = int.MaxValue; int min = Math.Min(savedValue, newValue); newTable[rw, outside] = min; //-------- nrw_ = graph.Neighborhood(outside + v) * (left - v); ra_ = LRa_.GetRepresentative(nrw_); nra = graph.Neighborhood(inside + v) * right; rw = LRw.GetRepresentative(nra); savedValue = newTable[rw, outside]; newValue = table[inside, ra_]; newValue = newValue == int.MaxValue ? newValue : newValue + 1; min = Math.Min(savedValue, newValue); newTable[rw, outside] = min; } } table = newTable; } return table[new BitSet(0, graph.Size), new BitSet(0, graph.Size)]; }
private void FillTable(Graph graph, List<int> sequence) { int n = graph.Size; // Processed vertices BitSet left = new BitSet(0, n); // Unprocessed vertices BitSet right = graph.Vertices; // Lists of representatives that we keep track of on each level of the algorithm LinearRepresentativeList reps = new LinearRepresentativeList(); // Initial insertions, the empty set always has the empty neighborhood set as a representative initially reps.Update(new BitSet(0, n), new BitSet(0, n)); for (int i = 0; i < sequence.Count; i++) { /// We give v the possibility to be a representative instead of being contained in neighborhoods int v = sequence[i]; // Actually move v from one set to the other set left.Add(v); right.Remove(v); // We don't want to disturb any pointers so we create new empty datastructures to save everything for the next iteration LinearRepresentativeList nextReps = new LinearRepresentativeList(); // We are iterating over all representatives saved inside the list of the previous step. For each entry there are only two possibilities to create a new neighborhood foreach (BitSet representative in reps) { // Case 1: The neighborhood possibly contained v (thus v has to be removed), but is still valid BitSet neighborhood = reps.GetNeighborhood(representative) - v; nextReps.Update(representative, neighborhood); // Case 2: The union of the old neighborhood, together with v's neighborhood, creates a new entry. The representative is uniond together with v and saved. BitSet representative_ = representative + v; BitSet neighborhood_ = neighborhood + (graph.OpenNeighborhood(v) * right); nextReps.Update(representative_, neighborhood_); } // Update the values for the next iteration reps = nextReps; // Save the maximum size that we encounter during all iterations; this will be the boolean dimension of the graph. MaxDimension = Math.Max(MaxDimension, reps.Count); // Save the representatives at the current cut in the table Table[left.Copy()] = reps; } }
public static void Compute(LinearDecomposition decomposition) { Graph graph = decomposition.Graph; List<int> sequence = decomposition.Sequence; int n = graph.Size; BitSet right = graph.Vertices; BitSet left = new BitSet(0, n); LookupTable table = new LookupTable(n); LinearRepresentativeTable cuts = new LinearRepresentativeTable(graph, sequence); table[new BitSet(0, n), 0] = 1; table[new BitSet(0, n), 1] = 0; for (int i = 0; i < sequence.Count; i++) { int v = sequence[i]; left.Add(v); right.Remove(v); LinearRepresentativeList LRw = cuts[left]; LinearRepresentativeList LRa = cuts[left - v]; LookupTable newTable = new LookupTable(n); foreach (BitSet ra in LRa) { BitSet nra = graph.Neighborhood(ra) * right; BitSet rw = LRw.GetRepresentative(nra); int maxValue = int.MinValue; int limit = (left - v).Count; for (int k = 0; k <= limit; k++) if (table[ra, k] > 0) maxValue = Math.Max(maxValue, k); for (int j = 0; j <= maxValue; j++) { newTable[rw, j] = newTable[rw, j] + table[ra, j]; } //------------ // ra + {v} is not a valid independent set if (LRa.GetNeighborhood(ra).Contains(v)) continue; //------------ // add {v} to the independent set BitSet nrav = graph.Neighborhood(ra + v) * right; BitSet rwv = LRw.GetRepresentative(nrav); for (int j = 0; j <= maxValue; j++) { newTable[rwv, j + 1] = newTable[rwv, j + 1] + table[ra, j]; } } table = newTable; } return; }
// Returns all connected components in a certain subgraph, where we define a subgraph by the vertices that are contained in it // We apply multiple dfs searches to find all connected parts of the graph public static List<BitSet> ConnectedComponents(Graph graph, BitSet subgraph) { // Each connected component is defined as a bitset, thus the result is a list of these bitsets List<BitSet> result = new List<BitSet>(); // Working stack for the dfs algorithm Stack<int> stack = new Stack<int>(); // Each vertex of the subgraph will either be explored, or it will be the starting point of a new dfs search BitSet todo = subgraph.Copy(); while (!todo.IsEmpty) { int s = todo.First(); stack.Push(s); // Start tracking the new component BitSet component = new BitSet(0, graph.Size); // Default dfs exploring part of the graph while (stack.Count > 0) { int v = stack.Pop(); // If we have not encountered this vertex before (meaning it isn't in this component), then we check for all neighbors if they are part of the subgraph // If a neighbor is part of the subgraph it means that we have to push it on the stack to explore it at a later stage for this component if (!component.Contains(v)) { component.Add(v); // Remove this vertex from the 'todo' list, since it can never be the starting point of a new component todo.Remove(v); foreach (int w in graph.OpenNeighborhood(v)) if (subgraph.Contains(w)) stack.Push(w); } } // The whole connected component has been found, so we can add it to the list of results result.Add(component); } return result; }
public static LinearDecomposition Compute(Graph graph, ScoreFunction scoreFunction) { // We solve finding an ordering for each connected component of the graph seperately List<BitSet> connectedComponents = DepthFirstSearch.ConnectedComponents(graph); // The final sequence that we will return List<int> sequence = new List<int>(); // Shorthand notation int n = graph.Size; foreach (BitSet connectedComponent in connectedComponents) { // Set of unprocessed vertices BitSet right = connectedComponent.Copy(); // Set of processed vertices BitSet left = new BitSet(0, n); // The initial is selected by a certain strategy (in this case a double BFS) int init = Heuristics.BFS(graph, Heuristics.BFS(graph, connectedComponent.Last())); // Place init in the sequence sequence.Add(init); left.Add(init); right.Remove(init); // Continue while not all unprocessed vertices are moved while (!right.IsEmpty) { int chosen = Heuristics.TrivialCases(graph, left, right); // If chosen has not been set it means that no trivial case was found // Depending on the criteria for the next vertex we call a different algorithm if (chosen == -1) { switch (scoreFunction) { case ScoreFunction.LeastUncommonNeighbor: chosen = LeastUncommonNeighbor(graph, left, right); break; case ScoreFunction.RelativeNeighborhood: chosen = RelativeNeighborhood(graph, left, right); break; case ScoreFunction.LeastCutValue: chosen = LeastCutValue(graph, left, right); break; } } // This should never happen; a selection criteria should always return some vertex if (chosen == -1) throw new Exception("No vertex is chosen for next step in the heuristic"); // Add/remove the next vertex in the appropiate sets sequence.Add(chosen); left.Add(chosen); right.Remove(chosen); } } return new LinearDecomposition(graph, sequence); }
public static int Compute(LinearDecomposition decomposition) { Graph graph = decomposition.Graph; List<int> sequence = decomposition.Sequence; // Left is the set of vertices that have been processed so far. BitSet left = new BitSet(0, graph.Size); // Right is the set of vertices that we have yet to process, initially set to all vertices in the graph. BitSet right = graph.Vertices; // The leftneighborset contains ISN elements, that save the size of each independent set in Left, and the corresponding neighborhood in Right that belongs to this IS. LookupTable table = new LookupTable(); // Insert the initial neighborhood and IS of size 0 and an empty neighborhood. table.Update(new ISN(new BitSet(0, graph.Size), 0)); // maxIS saves the largest independent set that we have encountered so far. int maxIS = 0; // Loop over all vertices in the sequence; we have to process all of them. for (int i = 0; i < sequence.Count; i++) { // Take the next vertex in the sequence. int v = sequence[i]; //Save all updated element in a new neighborset, so that we do not disturb any looping over elements. LookupTable newTable = new LookupTable(); foreach (ISN iset in table) { // If a neighborhood Right contains the currently selected element, then we have to remove it from the neighborhood. // The corresponding IS in Left is still valid, but it simply belongs to a smaller neighborhood in Right (hence the removal of v). if (iset.Elements.Contains(v)) { iset.Elements.Remove(v); newTable.Update(iset); } // If the neighborhood does not contain v, then there are two cases that have to be handled. else { // Case a: If v is not an element of the largest IS, then the previous IS is still valid. // We have no risk of v being contained in the neighborhood of Right, because if that would be the case we would not be in the else-part of the if-statement. // Thus, we simply add an unmodified copy of j to the new list of neighborhoodsets. newTable.Update(iset); // Case b: If v is an element of the largest IS, then we should include a new entry for this newly created IS. // The size of this IS will increase by one (adding v will cause this). // The neighborhood of this IS is the old neighborhood, plus any vertices in Right that are in the neighborhood of v. Vertex v causes the addition of these vertices. // The largest saved IS might change because of this addition of a new erlement. ISN newIset = new ISN(iset.Elements.Copy(), iset.Size); newIset.Size++; newIset.Elements = newIset.Elements + (graph.OpenNeighborhood(v) * right); maxIS = Math.Max(maxIS, newIset.Size); newTable.Update(newIset); } } // Safely update all sets that we are working with left.Add(v); right.Remove(v); table = newTable; } // The largest IS that we have encountered is the one we will return return maxIS; }
public static void Compute(LinearDecomposition decomposition) { Graph graph = decomposition.Graph; List<int> sequence = decomposition.Sequence; int n = graph.Size; BitSet right = graph.Vertices; BitSet left = new BitSet(0, n); LookupTable table = new LookupTable(n); LinearRepresentativeTable cuts = new LinearRepresentativeTable(graph, sequence); int l = sequence[0]; BitSet leaf = new BitSet(0, n) { l }; BitSet nleaf = new BitSet(0, n) { graph.OpenNeighborhood(l).First() }; table[leaf, new BitSet(0, n), 1] = 1; table[leaf, nleaf, 1] = 1; table[new BitSet(0, n), nleaf, 0] = 1; left.Add(l); right.Remove(l); for (int i = 1; i < sequence.Count; i++) { int v = sequence[i]; left.Add(v); right.Remove(v); LinearRepresentativeList LRw = cuts[left]; LinearRepresentativeList LRw_ = cuts[right]; LinearRepresentativeList LRa = cuts[left - v]; LinearRepresentativeList LRa_ = cuts[right + v]; LookupTable newTable = new LookupTable(n); foreach (BitSet outside in LRw_) { foreach (BitSet inside in LRa) { BitSet nrw_ = graph.Neighborhood(outside) * (left - v); BitSet ra_ = LRa_.GetRepresentative(nrw_); BitSet nra = graph.Neighborhood(inside) * right; BitSet rw = LRw.GetRepresentative(nra); BitSet ra = inside; BitSet rw_ = outside; BitSet raw_ = inside + outside; BitSet nraw_ = graph.Neighborhood(raw_); if (nraw_.Contains(v)) // this means rb_ exists ==> multiplier is equal to 1 { for (int ka = 0; ka < n; ka++) { newTable[rw, rw_, ka] = newTable[rw, rw_, ka] + table[ra, ra_, ka]; } } //-------- nrw_ = graph.Neighborhood(outside + v) * (left - v); ra_ = LRa_.GetRepresentative(nrw_); nra = graph.Neighborhood(inside + v) * right; rw = LRw.GetRepresentative(nra); for (int ka = 0; ka < n; ka++) { newTable[rw, rw_, ka + 1] = newTable[rw, rw_, ka + 1] + table[ra, ra_, ka]; } } } table = newTable; } return; }
private static List<int> ComputeSequence(Graph graph, BitSet connectedComponent, CandidateStrategy candidateStrategy, int init, out int value) { int n = graph.Size; List<int> sequence = new List<int>() { init }; BitSet left = new BitSet(0, n) { init }; BitSet right = connectedComponent - init; // Initially we store the empty set and the set with init as the representative, ie N(init) * right Set<BitSet> UN_left = new Set<BitSet>() { new BitSet(0, n), graph.OpenNeighborhood(init) * right }; value = int.MinValue; while (!right.IsEmpty) { Set<BitSet> UN_chosen = new Set<BitSet>(); int chosen = Heuristics.TrivialCases(graph, left, right); if (chosen != -1) { UN_chosen = IncrementUN(graph, left, UN_left, chosen); } // If chosen has not been set it means that no trivial case was found // Depending on the criteria for the next vertex we call a different algorithm else { BitSet candidates = Heuristics.Candidates(graph, left, right, candidateStrategy); int min = int.MaxValue; foreach (int v in candidates) { Set<BitSet> UN_v = IncrementUN(graph, left, UN_left, v); if (UN_v.Count < min) { chosen = v; UN_chosen = UN_v; min = UN_v.Count; } } } // This should never happen if (chosen == -1) throw new Exception("No vertex is chosen for next step in the heuristic"); // Add/remove the next vertex in the appropiate sets sequence.Add(chosen); left.Add(chosen); right.Remove(chosen); UN_left = UN_chosen; value = Math.Max(UN_chosen.Count, value); } return sequence; }