private ExploreChildNodesResult ExploreChildNodes <TVertex>( QuiverWithPotential <TVertex> qp, TransformationRuleTreeNode <TVertex> transformationRuleTree, AnalysisStateForSingleStartingVertexOld <TVertex> state, SearchTreeNodeOld <TVertex> parentNode, QPAnalysisSettings settings) where TVertex : IEquatable <TVertex>, IComparable <TVertex> { bool pathHasNonzeroExtension = false; // Path has no nonzero extension until proven otherwise // Explore every child node (determine its equivalence class) foreach (var nextVertex in qp.Quiver.AdjacencyLists[parentNode.Vertex]) { var result = ExploreChildNode(transformationRuleTree, state, parentNode, nextVertex, settings); switch (result) { case ExploreChildNodeResult.NotZeroEquivalent: pathHasNonzeroExtension = true; break; case ExploreChildNodeResult.NonCancellativityDetected: return(ExploreChildNodesResult.NonCancellativityDetected); case ExploreChildNodeResult.TooLongPath: return(ExploreChildNodesResult.TooLongPath); } } return(pathHasNonzeroExtension ? ExploreChildNodesResult.PathHasNonzeroExtension : ExploreChildNodesResult.PathHasNoNonzeroExtension); }
internal AnalysisResultsForSingleStartingVertexOld( SearchTreeNodeOld <TVertex> zeroDummyNode, SearchTreeNodeOld <TVertex> searchTree, IEnumerable <SearchTreeNodeOld <TVertex> > maximalPathRepresentatives, DisjointSets <SearchTreeNodeOld <TVertex> > equivalenceClasses, bool nonCancellativityDetected, bool tooLongPathEncountered) { ZeroDummyNode = zeroDummyNode; SearchTree = searchTree; MaximalPathRepresentatives = maximalPathRepresentatives; EquivalenceClasses = equivalenceClasses; NonCancellativityDetected = nonCancellativityDetected; TooLongPathEncountered = tooLongPathEncountered; }
/// <returns>A boolean value indicating whether the node was found to be zero-equivalent. /// That is, the returned value is <see langword="true"/> <em>only</em> if the node is /// zero-equivalent but may be <see langword="false"/> even if the node is zero-equivalent.</returns> /// <remarks>A node is found to be zero-equivalent either if its path can be killed or if /// the path is equivalent to (up to replacement) to a path that has previously been /// determined to be zero-equivalent.</remarks> private static bool EquivClassExploreNode <TVertex>( TransformationRuleTreeNode <TVertex> transformationRuleTree, SearchTreeNodeOld <TVertex> node, AnalysisStateForSingleStartingVertexOld <TVertex> state, Stack <SearchTreeNodeOld <TVertex> > equivClassStack, SearchTreeNodeOld <TVertex> origin) where TVertex : IEquatable <TVertex>, IComparable <TVertex> { node.Explored = true; var trailingVertexPath = new List <TVertex>(); // In reversed order foreach (var endingNode in node.ReversePathOfNodes) // The last vertex of endingNode is the last vertex in the subpath { var transformationNode = transformationRuleTree; foreach (var startingNode in endingNode.ReversePathOfNodes) // The last vertex of startingNode is the first vertex in the subpath { var pathVertex = startingNode.Vertex; if (!transformationNode.Children.TryGetValue(pathVertex, out transformationNode)) { break; } if (transformationNode.CanBeKilled) { state.EquivalenceClasses.Union(node, state.ZeroDummyNode); return(true); } // If replacement is possible, do the replacement on the subpath // and add a search tree node for the entire resulting path if (transformationNode.CanBeReplaced) { // Add search tree nodes for replacement path // This doesn't work when pathNode is the root ... // var lastUnreplacedNode = pathNode.Parent; // var curNode = lastUnreplacedNode; // ... so instead do the following (with Skip), which assumes that the replacement // path has the same first vertex (which it does for the QPs under consideration) var firstReplacementNode = startingNode; var curNode = firstReplacementNode; foreach (var vertex in transformationNode.ReplacementPath.Vertices.Skip(1)) { curNode = state.GetInsertChildNode(curNode, vertex, origin); } // Add search tree nodes for the trailing path foreach (var vertex in trailingVertexPath.Reversed()) { curNode = state.GetInsertChildNode(curNode, vertex, origin); } var transformedNode = curNode; if (state.NodeIsZeroEquivalent(transformedNode)) { state.EquivalenceClasses.Union(node, transformedNode); return(true); } // transformedNode.Explored may be true and is then a node that we have // already encountered during the equivalence class search. // (It cannot be an explored node of some *other* equivalence class, // because then this current equivalence class search would not have // started in the first place.) //if (!transformedNode.Explored) if (!state.EquivalenceClasses.FindSet(node).Equals(state.EquivalenceClasses.FindSet(transformedNode))) { state.EquivalenceClasses.Union(node, transformedNode); equivClassStack.Push(transformedNode); } } } trailingVertexPath.Add(endingNode.Vertex); } return(false); }
/// <returns>A boolean value indicating whether the path correspondings to the explored /// child node is nonzero (up to equivalence).</returns> private ExploreChildNodeResult ExploreChildNode <TVertex>( TransformationRuleTreeNode <TVertex> transformationRuleTree, AnalysisStateForSingleStartingVertexOld <TVertex> state, SearchTreeNodeOld <TVertex> parentNode, TVertex nextVertex, QPAnalysisSettings settings) where TVertex : IEquatable <TVertex>, IComparable <TVertex> { // Either the child node has not already been discovered, or the child node was // discovered during an equivalence class search. if (parentNode.Children.TryGetValue(nextVertex, out var childNode)) { // The child node has already been discovered. // Do a non-cancellativity check (if we are to detect non-cancellativity): // If the child node is zero, everything is fine. // If a different arrow was added to the origin than to the parent to get child node (i.e., origin and parent have different last vertices), things are fine. // Else, make sure that the origin is equivalent to the parent // (otherwise, the QP is not cancellative). if ( settings.DetectCancellativityFailure && !state.NodeIsZeroEquivalent(childNode) && parentNode.Vertex.Equals(childNode.Origin.Vertex) && state.EquivalenceClasses.FindSet(parentNode) != state.EquivalenceClasses.FindSet(childNode.Origin)) { return(ExploreChildNodeResult.NonCancellativityDetected); } } else { // The child node has not been discovered, so let's discover it by inserting it // into the search tree. childNode = state.InsertChildNode(parentNode, nextVertex, parentNode); } if (childNode.Explored) { return(state.NodeIsZeroEquivalent(childNode) ? ExploreChildNodeResult.ZeroEquivalent : ExploreChildNodeResult.NotZeroEquivalent); } // Code for equivalence class searching begins here // Stack containing all the nodes to explore (by path transformation) var equivClassStack = new Stack <SearchTreeNodeOld <TVertex> >(state.EquivalenceClasses.GetSet(childNode)); // This could happen with the current code, namely when the current childNode was encountered // in a previous call to ExploreChildNodes (in EquivClassExploreNode, as transformationNode) // and 'node' was found to be zero equivalent (in which case the search is cancelled // before transformationNode is explored in EquivClassExploreNode) // Thought: Would probably be good to have several Explored properties (or an // enum-valued Explored property) containing information about the extent to which the // node is explored (explored-as-in-encountered-in-EquivClassExploreNode would be // useful here; more easily understood and maintained than this comment methinks) if (equivClassStack.Count != 1) { return(ExploreChildNodeResult.ZeroEquivalent); } while (equivClassStack.Count > 0) { var equivalentNode = equivClassStack.Pop(); if (equivalentNode.Explored) { continue; } if (settings.UseMaxLength && equivalentNode.PathLengthInVertices > settings.MaxPathLength + 1) { return(ExploreChildNodeResult.TooLongPath); } var exploredNodeWasFoundZeroEquivalent = EquivClassExploreNode(transformationRuleTree, equivalentNode, state, equivClassStack, parentNode); if (exploredNodeWasFoundZeroEquivalent) { return(ExploreChildNodeResult.ZeroEquivalent); } } // Child node was not zero-equivalent state.Stack.Push(childNode); return(ExploreChildNodeResult.NotZeroEquivalent); }