private PartialDecomposition(PartialDecomposition oldDecomposition, List <TNode> chain, bool isFromFace)
            {
                coveredVertices = new Dictionary <TNode, int>(oldDecomposition.coveredVertices);

                // Cover chain
                var numberOfChains = oldDecomposition.NumberOfChains;

                foreach (var node in chain)
                {
                    coveredVertices[node] = numberOfChains;
                }

                // Remove covered faces
                remainingFaces = oldDecomposition
                                 .remainingFaces
                                 .Where(face => face.Any(node => !coveredVertices.ContainsKey(node)))
                                 .ToList();

                chains = oldDecomposition.chains.Select(x => new Chain <TNode>(x.Nodes.ToList(), x.Number)
                {
                    IsFromFace = x.IsFromFace
                }).ToList();
                chains.Add(new Chain <TNode>(chain, chains.Count)
                {
                    IsFromFace = isFromFace,
                });
            }
        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),
            });
        }
        /// <inheritdoc />
        public override List <Chain <TNode> > GetChains(IGraph <TNode> graph)
        {
            Initialize(graph);

            if (Faces.Count != 0)
            {
                // Get faces and remove the largest one
                Faces.RemoveAt(Faces.MaxBy(x => x.Count));
            }

            var decomposition = new PartialDecomposition(Faces);

            decomposition = GetFirstComponent(decomposition);

            while (decomposition.GetAllCoveredVertices().Count != Graph.VerticesCount)
            {
                decomposition = ExtendDecomposition(decomposition);
            }

            var chains = decomposition.GetFinalDecomposition();

            logger.WriteLine("Final decomposition:");
            foreach (var chain in chains)
            {
                logger.WriteLine($"[{string.Join(",", chain.Nodes)}]");
            }

            return(chains);
        }
 private GraphComponent GetTreeComponent(PartialDecomposition decomposition, TNode startingNode)
 {
     return(GetTreeComponent(decomposition, new List <TNode>()
     {
         startingNode
     }));
 }
        private int GetMinimumNeighborChainNumber(PartialDecomposition decomposition, List <TNode> nodes)
        {
            var coveredNeighbors = nodes
                                   .SelectMany(Graph.GetNeighbours)
                                   .Where(decomposition.IsCovered)
                                   .ToList();

            if (coveredNeighbors.Count != 0)
            {
                return(coveredNeighbors.Min(decomposition.GetChainNumber));
            }

            return(-1);
        }
        private GraphComponent GetTreeComponent(PartialDecomposition decomposition, List <TNode> startingNodes)
        {
            switch (treeComponentStrategy)
            {
            case TreeComponentStrategy.BreadthFirst:
                return(GetBfsTreeComponent(decomposition, startingNodes));

            case TreeComponentStrategy.DepthFirst:
                return(GetDfsTreeComponent(decomposition, startingNodes));

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
        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 GetFirstComponent(PartialDecomposition decomposition)
        {
            var faces = decomposition.GetRemainingFaces();

            if (Faces.Count != 0)
            {
                List <TNode> firstFace;

                if (preferSmallCycles)
                {
                    var smallestFaceIndex = faces.MinBy(x => x.Count);
                    firstFace = faces[smallestFaceIndex];
                }
                else
                {
                    var largestFaceIndex = faces.MaxBy(x => x.Count);
                    firstFace = faces[largestFaceIndex];
                }

                var cycleComponent = new GraphComponent()
                {
                    Nodes      = firstFace,
                    IsFromFace = true,
                    MinimumNeighborChainNumber = 0,
                };

                logger.WriteLine("Starting with cycle");
                logger.WriteLine(cycleComponent);

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

            var startingNode  = Graph.Vertices.First(x => Graph.GetNeighbours(x).Count() == 1);
            var treeComponent = GetTreeComponent(decomposition, startingNode);

            logger.WriteLine("Starting with tree");
            logger.WriteLine(treeComponent);

            return(decomposition.AddChain(treeComponent.Nodes, false));
        }
        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));
        }