Exemple #1
0
        /// <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);
        }
Exemple #2
0
        /// <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);
        }