public static INCRCliqueTree GenerateKTree(long n, int k, Random random)
        {
            var node       = new INCRNode(Enumerable.Range(0, k + 1).Select(i => (uint)i));
            var cliqueTree = new INCRCliqueTree()
            {
                MaximalCliques = 1,
                Edges          = k * (k + 1) / 2,
                Cardinalities  = new List <int>()
                {
                    k + 1
                },
                Cliques = new List <INCRNode>()
                {
                    node
                }
            };

            for (int u = 1; u < n - k; u++)
            {
                var i   = random.Next(cliqueTree.MaximalCliques);
                var y   = random.Next(cliqueTree.Cardinalities[i]);
                var sep = cliqueTree.Cliques[i].Where((x, ii) => ii != y);
                // var newSep = new List<ushort>(sep);
                var newNode = new INCRNode(sep);
                newNode.Add((uint)(u + k));

                cliqueTree.Cliques.Add(newNode);
                cliqueTree.Cardinalities.Add(k + 1);
                cliqueTree.MaximalCliques++;
                cliqueTree.Edges += k;
                cliqueTree.EdgesList.Add(new INCREdge(i, cliqueTree.Cliques.Count - 1, null, k));
            }

            return(cliqueTree);
        }
        public long SplitEdgesK(long upperBound, long n, Random random, int k = 1)
        {
            var loops  = 0;
            var disSet = new MVA.UnionFind <int>();

            for (int i = 0; i < this.MaximalCliques; i++)
            {
                var tmp = disSet[i];
            }

            while (this.EdgesList.Count > 0 && this.Edges < upperBound)
            {
                loops++;
                var rndEdgeI = random.Next(this.EdgesList.Count);
                var rndEdge = this.EdgesList[rndEdgeI];
                int i = disSet[rndEdge.Node1], j = disSet[rndEdge.Node2];

                var sep = new HashSet <uint>(this.Cliques[i]);
                sep.IntersectWith(this.Cliques[j]);

                var xSep = new HashSet <uint>(this.Cliques[i]); // O(n)
                xSep.ExceptWith(sep);

                var ySep = new HashSet <uint>(this.Cliques[j]); // O(n)
                ySep.ExceptWith(sep);

                if (xSep.Count == 0 && ySep.Count == 0)
                {
                    throw new Exception("Not a valid clique tree");
                }
                else if (xSep.Count <= k || ySep.Count <= k)
                {
                    // merge x,y
                    var edgesAdded  = xSep.Count * ySep.Count;
                    var mergedIndex = disSet.Union(rndEdge.Node1, rndEdge.Node2);
                    if (mergedIndex == i)
                    {
                        // Union find merged in i
                        this.Cliques[i].AddRange(ySep);
                        this.Cardinalities[i] += ySep.Count;
                        this.Cliques[j]        = null;
                        this.Cardinalities[j]  = 0;
                    }
                    else
                    {
                        this.Cliques[j].AddRange(xSep);
                        this.Cardinalities[j] += xSep.Count;
                        this.Cliques[i]        = null;
                        this.Cardinalities[i]  = 0;
                    }

                    this.Edges += edgesAdded;
                    this.MaximalCliques--;
                    this.EdgesList.RemoveAt(rndEdgeI);
                }
                else if (xSep.Count <= k)
                {
                    // merge x,z
                    var yLen    = random.Next(1, ySep.Count);
                    var yRandom = ySep.Take(yLen);

                    this.Cliques[i].AddRange(yRandom);
                    this.Cardinalities[i] += yLen;
                    // this.EdgesList[rndEdgeI].Seperator.Union(yRandom);
                    this.EdgesList[rndEdgeI].SeperatorWeight += yLen;
                }
                else if (ySep.Count <= k)
                {
                    //merge y,z
                    var xLen    = random.Next(1, xSep.Count);
                    var xRandom = xSep.Take(xLen);

                    this.Cliques[i].AddRange(xRandom);
                    this.Cardinalities[i] += xLen;
                    // this.EdgesList[rndEdgeI].Seperator.Union(xRandom);
                    this.EdgesList[rndEdgeI].SeperatorWeight += xLen;
                }
                else
                {
                    // make new z node
                    var xLen = random.Next(1, xSep.Count);
                    var yLen = random.Next(1, ySep.Count);

                    var xRandom = xSep.Take(xLen);
                    var yRandom = ySep.Take(yLen);

                    var z = new INCRNode(xRandom);
                    z.AddRange(yRandom);
                    z.AddRange(sep);

                    var edgesAdded = xLen * yLen;
                    this.Cliques.Add(z);
                    this.Cardinalities.Add(xLen + yLen + rndEdge.SeperatorWeight);

                    // var sep1 = new List<ushort>(xRandom); // Ο(n)
                    // sep1.AddRange(rndEdge.Seperator);
                    // this.EdgesList.Add(new INCREdge(rndEdge.Node1, this.Cliques.Count - 1, sep1, edgesAdded + rndEdge.SeperatorWeight));
                    this.EdgesList.Add(new INCREdge(rndEdge.Node1, this.Cliques.Count - 1, null, edgesAdded + rndEdge.SeperatorWeight));

                    // var sep2 = new List<ushort>(yRandom);
                    // sep2.AddRange(rndEdge.Seperator);
                    // this.EdgesList.Add(new INCREdge(rndEdge.Node2, this.Cliques.Count - 1, sep2, edgesAdded + rndEdge.SeperatorWeight));
                    this.EdgesList.Add(new INCREdge(rndEdge.Node2, this.Cliques.Count - 1, null, edgesAdded + rndEdge.SeperatorWeight));

                    this.MaximalCliques++;
                    this.Edges += edgesAdded;
                    this.EdgesList.RemoveAt(rndEdgeI);
                }
            }

            foreach (var edge in this.EdgesList)
            {
                edge.Node1 = disSet[edge.Node1];
                edge.Node2 = disSet[edge.Node2];
            }

            return(loops);
        }