private GraphComponent GetCycleComponent(PartialDecomposition decomposition, List <TNode> face)
        {
            var nodes           = new List <TNode>();
            var notCoveredNodes = face.Where(x => !decomposition.IsCovered(x)).ToList();
            var nodeOrder       = new Dictionary <TNode, int>();

            while (notCoveredNodes.Count != 0)
            {
                var nodeIndex = notCoveredNodes
                                .MinBy(
                    x => Graph
                    .GetNeighbours(x)
                    .Min(y =>
                         decomposition.IsCovered(y)
                                    ? -1
                                    : nodeOrder.ContainsKey(y) ? nodeOrder[y] : int.MaxValue));

                nodeOrder[notCoveredNodes[nodeIndex]] = nodeOrder.Count;
                nodes.Add(notCoveredNodes[nodeIndex]);
                notCoveredNodes.RemoveAt(nodeIndex);
            }

            return(new GraphComponent()
            {
                Nodes = nodes,
                IsFromFace = true,
                MinimumNeighborChainNumber = GetMinimumNeighborChainNumber(decomposition, nodes),
            });
        }
        private GraphComponent GetDfsTreeComponent(PartialDecomposition decomposition, List <TNode> startingNodes)
        {
            var nodes = new List <TNode>();
            var stack = new Stack <TNode>();

            nodes.AddRange(startingNodes);
            foreach (var startingNode in startingNodes)
            {
                stack.Push(startingNode);
            }

            while (stack.Count != 0 && nodes.Count < maxTreeSize)
            {
                var node = stack.Pop();

                if (decomposition.GetRemainingFaces().Any(x => x.Contains(node)))
                {
                    continue;
                }

                var neighbors = Graph.GetNeighbours(node);

                foreach (var neighbor in neighbors)
                {
                    if (!nodes.Contains(neighbor) && !decomposition.IsCovered(neighbor))
                    {
                        nodes.Add(neighbor);
                        stack.Push(neighbor);

                        if (nodes.Count >= maxTreeSize)
                        {
                            break;
                        }
                    }
                }
            }

            return(new GraphComponent()
            {
                Nodes = nodes,
                IsFromFace = false,
                MinimumNeighborChainNumber = GetMinimumNeighborChainNumber(decomposition, nodes),
            });
        }
        private PartialDecomposition ExtendDecomposition(PartialDecomposition decomposition)
        {
            var remainingFace = decomposition.GetRemainingFaces();
            var blacklist     = new List <TNode>();
            var components    = new List <GraphComponent>();

            foreach (var node in decomposition.GetAllCoveredVertices())
            {
                var neighbors           = Graph.GetNeighbours(node);
                var notCoveredNeighbors = neighbors.Where(x => !decomposition.IsCovered(x));
                var treeStartingNodes   = new List <TNode>();

                foreach (var neighbor in notCoveredNeighbors)
                {
                    if (blacklist.Contains(neighbor))
                    {
                        continue;
                    }

                    var foundFace = false;
                    foreach (var face in remainingFace)
                    {
                        if (!face.Contains(neighbor))
                        {
                            continue;
                        }

                        var cycleComponent = GetCycleComponent(decomposition, face);
                        components.Add(cycleComponent);
                        blacklist.AddRange(cycleComponent.Nodes);
                        foundFace = true;

                        break;
                    }

                    if (foundFace)
                    {
                        continue;
                    }

                    treeStartingNodes.Add(neighbor);
                }

                if (treeStartingNodes.Count != 0)
                {
                    if (startTreeWithMultipleVertices)
                    {
                        var treeComponent = GetTreeComponent(decomposition, treeStartingNodes);
                        components.Add(treeComponent);
                        blacklist.AddRange(treeComponent.Nodes);
                    }
                    else
                    {
                        foreach (var startingNode in treeStartingNodes)
                        {
                            var treeComponent = GetTreeComponent(decomposition, startingNode);
                            components.Add(treeComponent);
                            blacklist.AddRange(treeComponent.Nodes);
                        }
                    }
                }
            }

            logger.WriteLine();
            logger.WriteLine("Extending decomposition");
            logger.WriteLine("Candidates:");

            foreach (var component in components)
            {
                logger.WriteLine(component);
            }

            logger.WriteLine();

            var cycleComponents = components.Where(x => x.IsFromFace).ToList();

            if (cycleComponents.Count != 0)
            {
                var nextCycleIndex = preferSmallCycles ? cycleComponents.MinBy(x => x.Nodes.Count) : cycleComponents.MaxBy(x => x.Nodes.Count);
                var nextCycle      = cycleComponents[nextCycleIndex];

                logger.WriteLine("Adding smallest cycle component");
                logger.WriteLine(nextCycle);

                return(decomposition.AddChain(nextCycle.Nodes, true));
            }

            var treeComponents = components
                                 .Where(x => !x.IsFromFace)
                                 .OrderBy(x => x.MinimumNeighborChainNumber)
                                 .ThenByDescending(x => x.Nodes.Count)
                                 .ToList();

            var biggestTree = treeComponents[0];

            if (mergeSmallChains)
            {
                if (biggestTree.Nodes.Count < maxTreeSize)
                {
                    for (var i = 1; i < treeComponents.Count; i++)
                    {
                        var component = treeComponents[i];

                        if (component.Nodes.Count + biggestTree.Nodes.Count <= maxTreeSize)
                        {
                            biggestTree.Nodes.AddRange(component.Nodes);
                        }
                    }
                }
            }

            logger.WriteLine("Adding biggest oldest tree component");
            logger.WriteLine(biggestTree);

            return(decomposition.AddChain(biggestTree.Nodes, false));
        }