/*************************/ // Selecting initial vertices /*************************/ // Returns a vertex on the last level of a Breadth-first search (BFS) public static int BFS(Graph graph, int init) { // BFS working queue Queue<int> queue = new Queue<int>(); // Vertices that have already been visited Set<int> visited = new Set<int>(); // Initial vertex is given as input visited.Add(init); queue.Enqueue(init); int current = init; // While there is still a vertex in the queue... while (queue.Count > 0) { //... select the first vertex and process it current = queue.Dequeue(); foreach (int w in graph.OpenNeighborhood(current)) { // Enqueue all neighbors that have not been processed yet if (!visited.Contains(w)) { visited.Add(w); queue.Enqueue(w); } } } // This is the last vertex that has been processed, thus a vertex that is on the last level of the BFS search return current; }
// Constructor for creating a new representative table. We directly fill the table depending on the given sequence. public RepresentativeTable(Graph graph, Tree tree) { // Initialize the table Table = new Dictionary<BitSet, RepresentativeList>(); Queue<BitSet> queue = new Queue<BitSet>(); queue.Enqueue(tree.Root); Table[new BitSet(0, graph.Size)] = new RepresentativeList(); int i = 0; while (queue.Count != 0) { BitSet node = queue.Dequeue(); FillTable(graph, node); FillTable(graph, graph.Vertices - node); if (tree.LeftChild.ContainsKey(node)) { queue.Enqueue(tree.LeftChild[node]); } if (tree.RightChild.ContainsKey(node)) { queue.Enqueue(tree.RightChild[node]); } } }
// Uses depth-first search to check if the graph induced by the subgraph given as a parameter is connected // In other words, we retreive all edges from the original graph and check the subgraph for connectedness public static bool Connected(Graph graph, BitSet subgraph) { // Vertices that are visited Set<int> visited = new Set<int>(); // Stack of vertices yet to visit Stack<int> stack = new Stack<int>(); // Initial vertex int s = subgraph.First(); stack.Push(s); // Continue while there are vertices on the stack while (stack.Count > 0) { int v = stack.Pop(); // If we have not encountered this vertex before, 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 if (!visited.Contains(v)) { visited.Add(v); foreach (int w in graph.OpenNeighborhood(v)) if (subgraph.Contains(w)) stack.Push(w); } } // If we visited an equal number of vertices as there are vertices in the subgraph then the subgraph is connected return visited.Count == subgraph.Count; }
// Counts the number of independent sets in a graph, such that: // - The vertices in P are legal choices for our IS, initially set to all vertices in the graph // - None of the vertices in X are used, initially empty // The performDFS boolean is used to check if we should perform a check for connectedness on this level of the recursion private static long Compute(Graph graph, BitSet P, BitSet X, bool performDFS) { // Base case, when P and X are both empty we cannot expand the IS if (P.IsEmpty && X.IsEmpty) return 1; // Base case, if a vertex w in X has no neighbor in P, then it means that this IS will never get maximal // since we could always include w. Thus, the IS will not be valid and we return 0. foreach (int w in X) if ((graph.OpenNeighborhood(w) * P).IsEmpty) return 0; long count = 0; // If a DFS is needed we check if the graph induced by (P + X) is still connected. // If the graph is disconnected, in components c1,...,cn then we can simply count the IS of all these components // after which we simply multiply these numbers. if (performDFS) { if (!DepthFirstSearch.Connected(graph, P + X)) { count = 1; foreach (BitSet component in DepthFirstSearch.ConnectedComponents(graph, P + X)) count *= Compute(graph, component * P, component * X, false); return count; } } // Select a pivot in P to branch on // In this case we pick the vertex with the largest degree int maxDegree = -1; ; int pivot = -1; foreach (int u in P) { int deg = graph.Degree(u); if (deg > maxDegree) { maxDegree = deg; pivot = u; } } // There should always be a pivot after the selection procedure if (pivot == -1) throw new Exception("Pivot has not been selected"); // We branch on the pivot, one branch we include the pivot in the IS. // This might possibly disconnect the subgraph G(P + X), thus we set the performDFS boolean to true. count = Compute(graph, P - graph.ClosedNeighborhood(pivot), X - graph.OpenNeighborhood(pivot), true); // One branch we exclude the pivot of the IS. This will not cause the graph to get possibly disconnected count += Compute(graph, P - pivot, X + pivot, false); return count; }
/*************************/ // Computing Exact Decompositions /*************************/ public static Decomposition Compute(Graph graph) { Initialize(graph.Size); // Construct the table with the correct width values ConstructTree(graph, graph.Vertices); // Retrieve a sequence that will result in our bound not being exceeded Tree tree = RetrieveTree(graph); return new Decomposition(graph, tree); }
/*************************/ // Computing Exact Linear Decompositions /*************************/ public static LinearDecomposition ExactlinearDecomposition(Graph graph) { Initialize(graph.Size); // Construct the table with the correct width values ConstructSequence(graph, graph.Vertices); // Retrieve a sequence that will result in our bound not being exceeded List<int> sequence = RetrieveSequence(graph, graph.Vertices); return new LinearDecomposition(graph, sequence); }
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; }
// This constructor returns a new bipartite graph by putting all vertices in 'left' on one side, and 'right' on the other side // There will be an edge between two vertices if there was an edge in the original graph public BipartiteGraph(Graph graph, BitSet _left, BitSet _right) : this(_left, _right, _left.Count + _right.Count) { Dictionary<int, int> mapping = new Dictionary<int, int>(); int i = 0; foreach (int v in left + right) mapping[v] = i++; foreach (int v in left) foreach (int w in graph.OpenNeighborhood(v) * right) Connect(mapping[v], mapping[w]); }
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; } }
// Builds a neighborhood for a set X from the ground on up, without relying on what has been saved previously in O(n^2) time public dNeighborhood(BitSet X, BitSet vector, Graph graph) { // O(n) time copy Vector = vector.Copy(); Occurrences = new Dictionary<int, int>(); // Loops in O(|Vector|) time over all vertices in the vector foreach (int v in Vector) { // Bitset operation of O(n) time BitSet nv = graph.OpenNeighborhood(v) * X; Occurrences[v] = Math.Min(nv.Count, dValue); } }
// Given a vertex w, we can update the dNeighborhood of a set X to reflect the dNeighborhood of the set X + w in O(n) time public dNeighborhood CopyAndUpdate(Graph graph, int w) { // initialize an empty dNeighborhood in O(|Vector|) time dNeighborhood nx = new dNeighborhood(Vector); // Copy all values in O(|Vector|) time foreach (int v in Vector) nx.Occurrences[v] = Occurrences[v]; // Foreach vertex in N(w) * Vector they will appear one extra time in the multiset // This operation take O(n) time because of the bitset operation foreach (int v in graph.OpenNeighborhood(w) * Vector) nx.Occurrences[v] = Math.Min(dValue, nx.Occurrences[v] + 1); return nx; }
// Implementation of Algorithm 1 of 'Fast dynamic programming for locally checkable vertex subset and vertex partitioning problems' (Bui-Xuan et al.) // Used to compute the representatives and their corresponding dNeighborhoods for a given node of the decomposition tree private void FillTable(Graph graph, BitSet cut) { int n = graph.Size; BitSet _cut = graph.Vertices - cut; // Lists of representatives that we keep track of on each level of the algorithm RepresentativeList representatives = new RepresentativeList(); RepresentativeList lastLevel = new RepresentativeList(); // Initial insertions, the empty set always has the empty neighborhood set as a representative initially dNeighborhood dInitial = new dNeighborhood(_cut); representatives.Update(new BitSet(0, n), dInitial); lastLevel.Update(new BitSet(0, n), dInitial); while (lastLevel.Count > 0) { RepresentativeList nextLevel = new RepresentativeList(); foreach (BitSet r in lastLevel) { foreach (int v in cut) { // avoid that r_ = r, since we already saved all sets of that size if (r.Contains(v)) continue; BitSet r_ = r + v; dNeighborhood dn = representatives.GetNeighborhood(r).CopyAndUpdate(graph, v); if (!representatives.ContainsNeighborhood(dn) && !dn.Equals(representatives.GetNeighborhood(r))) { nextLevel.Update(r_, dn); representatives.Update(r_, dn); } } } // Update the values for the next iteration lastLevel = nextLevel; } // Save the representatives at the current cut in the table Table[cut.Copy()] = representatives; // Save the maximum size that we encounter during all iterations; this will be the boolean dimension of the graph is d = 1. MaxDimension = Math.Max(MaxDimension, representatives.Count); }
// 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; }
// 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; }
public static LinearDecomposition Compute(Graph graph, CandidateStrategy candidateStrategy, InitialVertexStrategy initialVertexStrategy) { List<BitSet> connectedComponents = DepthFirstSearch.ConnectedComponents(graph); List<int> sequence = new List<int>(); int tempValue; foreach (BitSet connectedComponent in connectedComponents) { switch (initialVertexStrategy) { case InitialVertexStrategy.All: { List<int> minList = null; int minValue = int.MaxValue; foreach (int vertex in connectedComponent) { List<int> temp = ComputeSequence(graph, connectedComponent, candidateStrategy, vertex, out tempValue); if (tempValue < minValue) { minValue = tempValue; minList = temp; } } sequence.AddRange(minList); } break; case InitialVertexStrategy.BFS: { int init = Heuristics.BFS(graph, connectedComponent.Last()); sequence.AddRange(ComputeSequence(graph, connectedComponent, candidateStrategy, init, out tempValue)); } break; case InitialVertexStrategy.DoubleBFS: { int init = Heuristics.BFS(graph, Heuristics.BFS(graph, connectedComponent.Last())); sequence.AddRange(ComputeSequence(graph, connectedComponent, candidateStrategy, init, out tempValue)); } break; } } return new LinearDecomposition(graph, sequence); }
// Constructor for creating a new representative table. We directly fill the table depending on the given sequence. public LinearRepresentativeTable(Graph graph, List<int> sequence) { // Initialize the table Table = new Dictionary<BitSet, LinearRepresentativeList>(); int n = graph.Size; // Save these initial representatives for the cut(empty, V(G)) LinearRepresentativeList reps = new LinearRepresentativeList(); reps.Update(new BitSet(0, n), new BitSet(0, n)); Table[new BitSet(0, n)] = reps; Table[graph.Vertices] = reps; FillTable(graph, sequence); List<int> reverseSequence = new List<int>(); for (int i = sequence.Count - 1; i >= 0; i--) reverseSequence.Add(sequence[i]); FillTable(graph, reverseSequence); }
// Constructs the actual width values // The idea is the following: If we want to know the optimal width for a certain cut A, thus Width[A], then we can obtain this by // either taking the max(Cuts[A], the minimum over all widths of Width[A - a]), which is our recurrence relation. private static void ConstructSequence(Graph graph, BitSet A) { // min saves the minimum size of all neighborhoods of the cut [A - a], where a can be any vertex in A long min = long.MaxValue; // v will be the optimal choice to leave out in the previous iteration in order to obtain A's full neighborhood int v = -1; foreach (int a in A) { BitSet previous = A - a; // If we have not constructed the previous step yet, then go in recursion and do so if (!Neighborhoods.ContainsKey(previous)) ConstructSequence(graph, previous); // Save the minimum value if (Width[previous] < min) { min = Width[previous]; v = a; } } // Obtain the neighborhood of v BitSet nv = graph.OpenNeighborhood(v) * (graph.Vertices - A); // We save the full set of neighborhood vertices at cut A. It does not matter that v was chosen arbitrarely; we always end up in the same collection of neighboring vertices for the set A Set<BitSet> un = new Set<BitSet>(); foreach (BitSet _base in Neighborhoods[A - v]) { un.Add(_base - v); // previous neighbor without v is a possible new neighborhood un.Add((_base - v) + nv); // previous neighbor without v, unioned with the neighborhood of v is a possible new neighborhood } // Save all entries Neighborhoods[A] = un; // List of all neighbors at cut A Cuts[A] = Neighborhoods[A].Count; // Dimension at this cut Width[A] = Math.Max(min, Cuts[A]); // Actual possible width to get to this cut }
// 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; }
/*************************/ // Trivial cases /*************************/ public static int TrivialCases(Graph graph, BitSet left, BitSet right) { int chosen = -1; // Check if any vertex in right belongs to one of the trivial cases, if yes then we can add this vertex directly to the sequence foreach (int v in right) { // Trivial case 1. If the neighbors of a vertex v in right are all contained in left, then select v // What this means is that v has an empty neighborhood, thus it will not add anything to the boolean-dimension if ((graph.OpenNeighborhood(v) - left).IsEmpty) { chosen = v; break; } bool stop = false; // 2. If there are two vertices, v in right and u in left, such that N(v) * right == (N(u)\v) * right, // then v is selected as our next vertex // What this means is that all neighbors of v are already 'represented' by u, thus making the choice for v will not add anything to the dimension foreach (int u in left) { BitSet nv = graph.OpenNeighborhood(v) * right; // N(v) * right BitSet nu = (graph.OpenNeighborhood(u) - v) * right; // (N(u)\v) * right if (nv.Equals(nu)) { chosen = v; stop = true; break; } } if (stop) break; } return chosen; }
/*************************/ // Candidate strategy /*************************/ public static BitSet Candidates(Graph graph, BitSet left, BitSet right, CandidateStrategy candidateStrategy) { BitSet nl = graph.Neighborhood(left) * right; return candidateStrategy == CandidateStrategy.All ? right.Copy() : (nl + graph.Neighborhood(nl)) * right; }
// Retreives the actual ordering of a certain ordering that will not validate our bound private static List<int> RetrieveSequence(Graph graph, BitSet A) { List<int> sequence = new List<int>(); // We know that the value saved at Width[graph.Vertices] will be the best value that we can get // Furthermore, we know that there is a possibility to remove a vertex and get a smaller or equal Width value, in other words Width[A - a] <= Width[A] // This way we navigate through the table and find a sequence that never will exceed the bound that is set, and we know for sure // that such a path exists. foreach (int a in A) { BitSet previous = A - a; if (Width[previous] <= Width[graph.Vertices]) { sequence.Add(a); sequence.AddRange(RetrieveSequence(graph, previous)); break; } } return sequence; }
public static bool Connected(Graph graph) { return Connected(graph, graph.Vertices); }
// Implementation of Algorithm 13 of the PhD thesis by Sadia Sharmin // The LeastCutValue selection method picks the next vertex based on a greedy choice, namely what is the vertex that will have the least // influence on the boolean dimension at this point. // While this generally gives great results, the runtime is very high because we construct multiple bipartite graphs during every iteration. private static int LeastCutValue(Graph graph, BitSet left, BitSet right) { // Minimum boolean dimension that we can have for our next cut long minBoolDim = long.MaxValue; // Vertex that we will choose int chosen = -1; // Foreach candidate vertex we construct a bipartite graph and count the number of minimal independent sets in this bipartite graph //This number is equal to the boolean-dimension at this cut foreach (int v in right) { // Construct the bipartite graph BipartiteGraph bg = new BipartiteGraph(graph, left + v, right - v); // Count the number of MIS in the bipartite graph long boolDim = CC_MIS.Compute(bg); // Possibly update the minimum value found so far if (boolDim < minBoolDim) { chosen = v; minBoolDim = boolDim; } } return chosen; }
/*************************/ // Constructor /*************************/ public Decomposition(Graph graph, Tree tree) { Tree = tree; Graph = graph; }
public static List<BitSet> ConnectedComponents(Graph graph) { return ConnectedComponents(graph, graph.Vertices); }
// Basic constructor public LinearDecomposition(Graph graph, List<int> sequence) { Sequence = sequence; Graph = graph; }
// Initial call public static long Compute(Graph graph) { return Compute(graph, new BitSet(0, graph.Size), graph.Vertices, new BitSet(0, graph.Size)); }
// Constructs the actual width values private static void ConstructTree(Graph graph, BitSet A) { long min = A.Count == 1 ? 0 : long.MaxValue; int n = graph.Size; int v = -1; // v is the vertex that if we remove it from A, we have the smallest number of neighbors BitSet optimal = new BitSet(0, n); Set<BitSet> subsets = new Set<BitSet>(new BitSet(0, n)); foreach (int a in A) { Set<BitSet> newSubsets = new Set<BitSet>(); foreach (BitSet j in subsets) { BitSet subset = j + a; BitSet inverse = A - subset; if (subset.Equals(A)) continue; // only consider strict subsets if (!Width.ContainsKey(subset)) ConstructTree(graph, subset); if (!Width.ContainsKey(inverse)) ConstructTree(graph, inverse); newSubsets.Add(subset); // add this for the next iteration long max = Math.Max(Width[subset], Width[inverse]); // either S or A\S will be the bottleneck if (max < min) { min = max; optimal = subset; // it doesn't matter if we take j + a or A - (j + a), since when retrieving the tree we split them anyway if (inverse.Count == 1) v = inverse.First(); } } subsets.AddRange(newSubsets); } v = v == -1 ? A.First() : v; BitSet nv = graph.OpenNeighborhood(v) * (graph.Vertices - (A - v)); Set<BitSet> un = new Set<BitSet>(); foreach (BitSet _base in Neighborhoods[A - v]) { un.Add(_base - v); // previous neighbor without v is a possible new neighborhood un.Add((_base - v) + nv); // previous neighbor without v, unioned with the neighborhood of v is a possible new neighborhood } Neighborhoods[A] = un; Cuts[A] = Neighborhoods[A].Count; Width[A] = Math.Max(min, Cuts[A]); // Actual possible width to get to this cut OptimalChild[A] = optimal; }
// Parses a file of DGF format, from which we can build a graph public static Graph ParseGraph(string filename) { StreamReader sr = new StreamReader (filename); string line; int nVertices = 0; // First we parse the number of vertices while ((line = sr.ReadLine ()) != null) { // Skip everything until we find the first useful line if (!line.StartsWith ("p ")) continue; // First line always reads 'p edges {n} {e}' string[] def = line.Split (); nVertices = int.Parse (def[2]); // number of vertices break; } // Initialize the graph Graph graph = new Graph (nVertices); Dictionary<int, int> identifiers = new Dictionary <int, int>(); int counter = 0; bool renamed = false; while ((line = sr.ReadLine ()) != null) { // Skip comments if (line.StartsWith ("c ")) continue; // If a line starts with an n it means we do not work with integers [1,...,n], but we use an arbitrary set of integers // This means we need to keep track of which edges we should create internally, since we use [0,...,n) if (line.StartsWith ("n ")) { renamed = true; string[] node = line.Split(); int id = int.Parse(node[1]); // actual identifier identifiers[id] = counter++; // counter will be the internal identifier } // Parsing of the edges if (line.StartsWith ("e ")) { string[] edge = line.Split(' '); int i = int.Parse(edge[1]); int j = int.Parse(edge[2]); // If there were arbitrary numbers used, look them up to find what we will use internally if (renamed) { i = identifiers[i]; j = identifiers[j]; } // If no other identifiers are given, we have only have to an element // DGF files use the range [1...n], while internally we use [0...n), thus a simple minus 1 will suffice else { i--; j--; } // Create the edge graph.Connect (i, j); } } sr.Close (); return graph; }
// Retreives the actual ordering of a certain ordering that will not validate our bound private static Tree RetrieveTree(Graph graph) { Tree tree = new Tree(); Queue<BitSet> queue = new Queue<BitSet>(); queue.Enqueue(graph.Vertices); while (queue.Count != 0) { BitSet A = queue.Dequeue(); tree.Insert(A); if (OptimalChild[A].IsEmpty) continue; queue.Enqueue(OptimalChild[A]); queue.Enqueue(A - OptimalChild[A]); } return tree; }