// 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;
        }
        public dNeighborhood CopyAndUpdateVector(BitSet vector, bool increment)
        {
            // initialize an empty dNeighborhood in O(|Vector|) time
            dNeighborhood nx = new dNeighborhood(vector);

            BitSet iterateOver = increment ? Vector : vector;
            foreach (int v in iterateOver)
                nx.Occurrences[v] = Occurrences[v];

            return nx;
        }
 /*************************/
 // Basic operations
 /*************************/
 // When adding a new entry we check if the neighborhood is already contained in the set
 // If true, then we might replace the previous representative that is not connected to this neighborhood if the new one is lexicographically smaller
 public void Update(BitSet representative, dNeighborhood neighborhood)
 {
     Map.Add(representative.Copy(), neighborhood);
 }
 // Returns the representative belonging to a given neighborhood
 public BitSet GetRepresentative(dNeighborhood neighborhood)
 {
     return Map.Reverse[neighborhood];
 }
 public bool ContainsNeighborhood(dNeighborhood neighborhood)
 {
     return Map.ContainsValue(neighborhood);
 }
        // Recursively fills all tables for each node of the decomposition tree in a bottom up fashion
        // Node W is the current node we are working on
        private void FillTable(BitSet node)
        {
            // Initialize a new table of node W
            Tables[node] = new Table();

            // All vertices of the graph
            BitSet VG = Graph.Vertices;
            int n = Graph.Size;

            // The base case for leaf nodes is handled seperately
            if (node.Count == 1)
            {
                FillLeaf(node);
                return;
            }

            // If the node has a size >1 then there it has child nodes
            BitSet leftChild = Tree.LeftChild[node];
            BitSet rightChild = Tree.RightChild[node];

            // We work in a bottom-up fashion, so we first recurse on the two children of this node
            // We know that this node is not a leaf since we already passed the check for leaf-nodes
            // We also know that this node has two children, since having 1 child in a boolean decomposition means that the parent and child node are the same and thus redundant
            FillTable(leftChild);
            FillTable(rightChild);

            // Initially set all combinations of representatives to the worst value, meaning that no solution exists
            foreach (BitSet representative in Cuts[node])
                foreach (BitSet _representative in Cuts[VG - node])
                    Tables[node][representative, _representative] = Optimum.PessimalValue;

            // All representatives of the cut G[leftChild, V \ leftChild]
            foreach (BitSet representative_a in Cuts[leftChild])
            {
                // All representatives of the cut G[rightChild, V \ rightChild]
                foreach (BitSet representative_b in Cuts[rightChild])
                {
                    // All representatives of the cut G[V \ node, node]
                    foreach (BitSet _representative in Cuts[VG - node])
                    {
                        // Find the representative Ra_ of the class [Rb ∪ Rw_]≡Va_
                        dNeighborhood dna = new dNeighborhood(representative_b + _representative, leftChild, Graph);
                        BitSet _representative_a = Cuts[VG - leftChild].GetRepresentative(dna);

                        // Find the representative Rb_ of the class [Ra ∪ Rw_]≡Vb_
                        dNeighborhood dnb = new dNeighborhood(representative_a + _representative, rightChild, Graph);
                        BitSet _representative_b = Cuts[VG - rightChild].GetRepresentative(dnb);

                        // Find the representative Rw of the class [Ra ∪ Rb]≡Vw
                        dNeighborhood dnw = new dNeighborhood(representative_a + representative_b, VG - node, Graph);
                        BitSet representative = Cuts[node].GetRepresentative(dnw);

                        // Optimal size of this sigma,rho set in the left and right child
                        int leftValue = Tables[leftChild][representative_a, _representative_a];
                        int rightValue = Tables[rightChild][representative_b, _representative_b];

                        // Some hoops to avoid integer overflowing
                        int combination = leftValue == Optimum.PessimalValue || rightValue == Optimum.PessimalValue ?
                                                Optimum.PessimalValue : leftValue + rightValue;

                        // Fill the optimal value that we can find in the current entry
                        Tables[node][representative, _representative] = Optimum.Optimal(Tables[node][representative, _representative], combination);
                    }
                }
            }
        }
        // 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);
        }