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)); }