예제 #1
0
        /// <summary>
        /// Checks to see if <paramref name="currentSymbolInTarget"/> matches the symbol at <paramref name="currentIndexInMatch"/> in the <paramref name="seriesMatch"/> string.
        ///     And also if the parent at <paramref name="currentParentIndexInTarget"/> maps to the parent of <paramref name="currentIndexInMatch"/>
        /// </summary>
        /// <param name="seriesMatch"></param>
        /// <param name="targetIndexesToMatchIndexes"></param>
        /// <param name="currentParentIndexInTarget"></param>
        /// <param name="currentSymbolInTarget"></param>
        /// <param name="currentIndexInMatch"></param>
        /// <returns></returns>
        private bool TargetSymbolMatchesAndParentMatches(
            SymbolSeriesSuffixMatcher seriesMatch,
            NativeHashMap <int, int> targetIndexesToMatchIndexes,
            int currentParentIndexInTarget,
            int currentIndexInTarget,
            int currentIndexInMatch,
            SymbolString <float> symbolString
            )
        {
            var symbolInMatch = nativeRuleData.suffixMatcherGraphNodeData[currentIndexInMatch + seriesMatch.graphNodeMemSpace.index].mySymbol;

            if (
                symbolInMatch.targetSymbol == symbolString[currentIndexInTarget] &&
                symbolInMatch.parameterLength == symbolString.ParameterSize(currentIndexInTarget))
            {
                var parentIndexInMatch = nativeRuleData.suffixMatcherGraphNodeData[currentIndexInMatch + seriesMatch.graphNodeMemSpace.index].parentIndex;
                if (parentIndexInMatch == -1)
                {
                    // if the parent is the origin, always match.
                    return(true);
                }
                var parentIndexInTarget = currentParentIndexInTarget;
                var indexInMatchOfTargetParentMapped = targetIndexesToMatchIndexes[parentIndexInTarget];
                // check to ensure the parent of this node in the target graph
                //  is already mapped to the parent of the node in the
                if (parentIndexInMatch == indexInMatchOfTargetParentMapped)
                {
                    return(true);
                }
            }
            return(false);
        }
예제 #2
0
        /// <summary>
        /// partial, semi-ordered tree matching algorithm.
        ///
        /// iterate over target string, no backtracking
        /// maintain data about matches in series match:
        ///     indexes which are valid branched matches for the current index in target
        ///     record of which leaves in the matcher have been matched
        /// </summary>
        /// <param name="indexInSymbolTarget"></param>
        /// <param name="seriesMatch"></param>
        /// <returns>a mapping from all symbols in seriesMatch back into the target string</returns>
        public bool MatchesForward(
            NativeMultipleHashSets.HashSetSlice includeSymbolsSet,
            int indexInSymbolTarget,
            SymbolSeriesSuffixMatcher seriesMatch,
            SymbolString <float> symbolString,
            int firstParameterCopyIndex,
            NativeArray <float> parameterCopyMemory,
            out byte paramsCopiedToMem,
            TmpNativeStack <BranchEventData> helperStack
            )
        {
            if (!seriesMatch.HasGraphIndexes)
            {
                // this should be done in the parsing/compiling phase. should only have to happen once for the whole system, per matching rule.
                throw new System.Exception("graph indexes should be precomputed");
                //seriesMatch.ComputeGraphIndexes(branchOpenSymbol, branchCloseSymbol);
            }

            // keep count of how many more matches are required at each level of the tree.
            //  starts out as a copy of the child count array. each leaf will be at 0, and will go negative when matched.
            //var remainingMatchesAtIndexes = seriesMatch.childrenCounts.Clone() as int[];
            return(MatchesForwardsAtIndexOrderingInvariant(
                       includeSymbolsSet,
                       indexInSymbolTarget,
                       seriesMatch,
                       symbolString,
                       firstParameterCopyIndex,
                       parameterCopyMemory,
                       out paramsCopiedToMem,
                       helperStack));
        }
        public SymbolSeriesSuffixMatcher BuildIntoManagedMemory(
            SystemLevelRuleNativeData nativeData,
            SymbolSeriesMatcherNativeDataWriter dataWriter,
            Allocator allocator = Allocator.Persistent)
        {
            var matcher = new SymbolSeriesSuffixMatcher();

            matcher.graphNodeMemSpace = new JaggedIndexing
            {
                index  = dataWriter.indexInSuffixNodes,
                length = (ushort)RequiredGraphNodeMemSpace
            };

            dataWriter.indexInSuffixNodes += RequiredGraphNodeMemSpace;
            for (int i = 0; i < nodes.Count; i++)
            {
                var sourceNode = nodes[i];
                nativeData.suffixMatcherGraphNodeData[i + matcher.graphNodeMemSpace.index] = new SymbolMatcherGraphNode
                {
                    parentIndex             = sourceNode.parentIndex,
                    myIndexInParentChildren = sourceNode.myIndexInParentChildren,
                    mySymbol = targetSymbolSeries[i].AsBlittable()
                };
            }

            matcher.childrenOfRoot = new JaggedIndexing
            {
                index  = dataWriter.indexInSuffixChildren,
                length = (ushort)rootChildren.Count
            };

            var childrenAsArray    = nodes.Select(x => x.childrenIndexes.ToArray()).ToArray();
            var tmpIndexInChildren = 0;

            foreach (var rootChild in rootChildren)
            {
                nativeData.suffixMatcherChildrenDataArray[tmpIndexInChildren + dataWriter.indexInSuffixChildren] = rootChild;
                tmpIndexInChildren++;
            }
            JaggedNativeArray <int> .WriteJaggedIndexing(
                (indexInJagged, jaggedIndexing) =>
            {
                var node = nativeData.suffixMatcherGraphNodeData[indexInJagged + matcher.graphNodeMemSpace.index];
                node.childrenIndexing = jaggedIndexing;
                nativeData.suffixMatcherGraphNodeData[indexInJagged + matcher.graphNodeMemSpace.index] = node;
            },
                childrenAsArray,
                nativeData.suffixMatcherChildrenDataArray,
                dataWriter.indexInSuffixChildren + tmpIndexInChildren
                );

            dataWriter.indexInSuffixChildren += RequiredChildrenMemSpace;

            matcher.HasGraphIndexes = true;
            matcher.IsCreated       = true;

            return(matcher);
        }
 public DepthFirstSearchState(
     SymbolSeriesSuffixMatcher source,
     int currentIndex,
     SystemLevelRuleNativeData nativeDataPointer)
 {
     this.source       = source;
     this.currentIndex = currentIndex;
     nativeData        = nativeDataPointer;
 }
예제 #5
0
        /// <summary>
        /// check for a match, enforcing the same ordering in the target match as defined in the matching pattern.
        /// </summary>
        /// <param name="originIndexInTarget"></param>
        /// <param name="seriesMatch"></param>
        /// <param name="consumedTargetIndexes"></param>
        /// <returns></returns>
        private bool MatchesForwardsAtIndexOrderingInvariant(
            NativeMultipleHashSets.HashSetSlice includeSymbolSet,
            int originIndexInTarget,
            SymbolSeriesSuffixMatcher seriesMatch,
            SymbolString <float> symbolString,
            int firstParameterCopyIndex,
            NativeArray <float> parameterCopyMemory,
            out byte paramsCopiedToMem,
            TmpNativeStack <BranchEventData> helperStack
            )
        {
            helperStack.Reset();
            var targetParentIndexStack = helperStack;// new TmpNativeStack<BranchEventData>(5);// new Stack<BranchEventData>();

            int currentParentIndexInTarget  = originIndexInTarget;
            var targetIndexesToMatchIndexes = new NativeHashMap <int, int>(seriesMatch.graphNodeMemSpace.length, Allocator.Temp);// new Dictionary<int, int>();

            paramsCopiedToMem = 0;

            var indexInMatchDFSState = seriesMatch.GetImmutableDepthFirstIterationState(nativeRuleData);

            targetIndexesToMatchIndexes.Add(originIndexInTarget, indexInMatchDFSState.currentIndex);
            if (!indexInMatchDFSState.Next(out indexInMatchDFSState))
            {
                return(true);
                // if the match is empty, automatically matches.
                //return targetIndexesToMatchIndexes;
            }


            for (int indexInTarget = originIndexInTarget + 1; indexInTarget < symbolString.Length; indexInTarget++)
            {
                var targetSymbol = symbolString[indexInTarget];

                if (!includeSymbolSet.Contains(targetSymbol))
                {
                    continue;
                }
                if (targetSymbol == branchOpenSymbol)
                {
                    targetParentIndexStack.Push(new BranchEventData
                    {
                        currentParentIndex      = currentParentIndexInTarget,
                        openBranchSymbolIndex   = indexInTarget,
                        paramsCopiedAtThisPoint = paramsCopiedToMem
                    });
                }
                else if (targetSymbol == branchCloseSymbol)
                {
                    // will encounter a close symbol in one of two cases:
                    //  1. the branch in target has exactly matched the branch in the matcher, and we should just step down
                    //  2. the branch in target has terminated early, meaning we must step down the branch chain and also
                    //      reverse the matcher DFS back to a common ancenstor
                    if (targetParentIndexStack.Count <= 0)
                    {
                        // if we encounter the end of the branch which contains the origin index before full match, fail.
                        return(false);
                    }
                    var lastBranch = targetParentIndexStack.Pop();
                    currentParentIndexInTarget = lastBranch.currentParentIndex;
                    //paramsCopiedToMem = lastBranch.paramsCopiedAtThisPoint;

                    var parentInMatch       = targetIndexesToMatchIndexes[currentParentIndexInTarget];
                    var parentOfSearchState = indexInMatchDFSState.GetParentIndex();
                    if (parentInMatch != parentOfSearchState)
                    {
                        // if the parents dont match, that means that the algo will be stepping backwards to the last branch sybmol.
                        paramsCopiedToMem = lastBranch.paramsCopiedAtThisPoint;
                    }
                }
                else
                {
                    // reverse the DFS in matcher, back to the last point which shares a parent with the current parent
                    // this acts to ensure the entry to the match has a shared parent, if at all possible.
                    //   the reversal is necessary when a branching structure failed to match in the last step
                    var parentInMatch = targetIndexesToMatchIndexes[currentParentIndexInTarget];
                    if (indexInMatchDFSState.FindPreviousWithParent(out var reversedMatchIndex, parentInMatch))
                    {
                        indexInMatchDFSState = reversedMatchIndex;
                    }

                    var indexInMatch = indexInMatchDFSState.currentIndex;
                    var currentTargetMatchesMatcher = TargetSymbolMatchesAndParentMatches(
                        seriesMatch,
                        targetIndexesToMatchIndexes,
                        currentParentIndexInTarget,
                        indexInTarget,
                        indexInMatch,
                        symbolString);
                    if (currentTargetMatchesMatcher)
                    {
                        targetIndexesToMatchIndexes.Add(indexInTarget, indexInMatch);

                        var paramsToCopy = symbolString.parameters[indexInTarget];
                        for (int paramIndex = 0; paramIndex < paramsToCopy.length; paramIndex++)
                        {
                            parameterCopyMemory[firstParameterCopyIndex + paramsCopiedToMem] = symbolString.parameters[paramsToCopy, paramIndex];
                            paramsCopiedToMem++;
                        }

                        currentParentIndexInTarget = indexInTarget; // series continuation includes implicit parenting
                        if (!indexInMatchDFSState.Next(out indexInMatchDFSState))
                        {
                            return(true);
                        }
                    }
                    else
                    {
                        // symbol in target isn't a valid match, so no further symbols in the current target branching structure can match.
                        // rewind back to the previous branching symbol, and skip this whole structure.
                        // Or if we're not in a nested structure, fail.
                        if (targetParentIndexStack.Count <= 0)
                        {
                            return(false);
                        }

                        var lastBranch = targetParentIndexStack.Pop();
                        currentParentIndexInTarget = lastBranch.currentParentIndex;
                        //paramsCopiedToMem = lastBranch.paramsCopiedAtThisPoint;
                        indexInTarget = FindClosingBranchIndexReadonly(lastBranch.openBranchSymbolIndex);


                        var parentInMatch1      = targetIndexesToMatchIndexes[currentParentIndexInTarget];
                        var parentOfSearchState = indexInMatchDFSState.GetParentIndex();
                        if (parentInMatch1 != parentOfSearchState)
                        {
                            // if the parents dont match, that means that the algo will be stepping backwards to the last branch sybmol on the next update.
                            paramsCopiedToMem = lastBranch.paramsCopiedAtThisPoint;
                        }
                    }
                }
            }
            return(false);
        }