Exemplo n.º 1
0
            /// <summary>
            /// Recursively increases the value of this automaton on <paramref name="sequence"/> by <paramref name="weight"/>.
            /// </summary>
            /// <param name="stateIndex">Index of currently traversed state.</param>
            /// <param name="isNewState">Indicates whether state <paramref name="stateIndex"/> was just created.</param>
            /// <param name="selfLoopAlreadyMatched">Indicates whether self-loop on state <paramref name="stateIndex"/> was just matched.</param>
            /// <param name="firstAllowedStateIndex">The minimum index of an existing state that can be used for the sequence.</param>
            /// <param name="currentSequencePos">The current position in the generalized sequence.</param>
            /// <param name="sequence">The generalized sequence.</param>
            /// <param name="weight">The weight of the sequence.</param>
            /// <returns>
            /// <see langword="true"/> if the subsequence starting at <paramref name="currentSequencePos"/> has been successfully merged in,
            /// <see langword="false"/> otherwise.
            /// </returns>
            /// <remarks>
            /// This function attempts to add as few new states and transitions as possible.
            /// Its implementation is conceptually similar to adding string to a trie.
            /// </remarks>
            private bool DoAddGeneralizedSequence(
                int stateIndex,
                bool isNewState,
                bool selfLoopAlreadyMatched,
                int firstAllowedStateIndex,
                int currentSequencePos,
                GeneralizedSequence sequence,
                Weight weight)
            {
                bool success;
                var  builder = this.builder;
                var  state   = builder[stateIndex];

                if (currentSequencePos == sequence.Count)
                {
                    if (!selfLoopAlreadyMatched)
                    {
                        // We can't finish in a state with a self-loop
                        for (var iterator = state.TransitionIterator; iterator.Ok; iterator.Next())
                        {
                            if (iterator.Value.DestinationStateIndex == state.Index)
                            {
                                return(false);
                            }
                        }
                    }

                    state.SetEndWeight(Weight.Sum(state.EndWeight, weight));
                    return(true);
                }

                var element = sequence[currentSequencePos];

                // Treat self-loops elements separately
                if (element.LoopWeight.HasValue)
                {
                    if (selfLoopAlreadyMatched)
                    {
                        // Previous element was also a self-loop, we should try to find an espilon transition
                        for (var iterator = state.TransitionIterator; iterator.Ok; iterator.Next())
                        {
                            var transition = iterator.Value;
                            if (transition.DestinationStateIndex != state.Index &&
                                transition.IsEpsilon &&
                                transition.DestinationStateIndex >= firstAllowedStateIndex)
                            {
                                if (this.DoAddGeneralizedSequence(
                                        transition.DestinationStateIndex,
                                        false,
                                        false,
                                        firstAllowedStateIndex,
                                        currentSequencePos,
                                        sequence,
                                        Weight.Product(weight, Weight.Inverse(transition.Weight))))
                                {
                                    return(true);
                                }
                            }
                        }

                        // Epsilon transition not found, let's create a new one
                        var destination = state.AddEpsilonTransition(Weight.One);
                        success = this.DoAddGeneralizedSequence(
                            destination.Index, true, false, firstAllowedStateIndex, currentSequencePos, sequence, weight);
                        Debug.Assert(success, "This call must always succeed.");
                        return(true);
                    }

                    // Find a matching self-loop
                    for (var iterator = state.TransitionIterator; iterator.Ok; iterator.Next())
                    {
                        var transition = iterator.Value;

                        if (transition.IsEpsilon && transition.DestinationStateIndex != state.Index && transition.DestinationStateIndex >= firstAllowedStateIndex)
                        {
                            // Try this epsilon transition
                            if (this.DoAddGeneralizedSequence(
                                    transition.DestinationStateIndex, false, false, firstAllowedStateIndex, currentSequencePos, sequence, weight))
                            {
                                return(true);
                            }
                        }

                        // Is it a self-loop?
                        if (transition.DestinationStateIndex == state.Index)
                        {
                            // Do self-loops match?
                            if ((transition.Weight == element.LoopWeight.Value) &&
                                (element.Group == transition.Group) &&
                                ((transition.IsEpsilon && element.IsEpsilonSelfLoop) || (!transition.IsEpsilon && !element.IsEpsilonSelfLoop && transition.ElementDistribution.Equals(element.ElementDistribution))))
                            {
                                // Skip the element in the sequence, remain in the same state
                                success = this.DoAddGeneralizedSequence(
                                    stateIndex, false, true, firstAllowedStateIndex, currentSequencePos + 1, sequence, weight);
                                Debug.Assert(success, "This call must always succeed.");
                                return(true);
                            }

                            // StateIndex also has a self-loop, but the two doesn't match
                            return(false);
                        }
                    }

                    if (!isNewState)
                    {
                        // Can't add self-loop to an existing state, it will change the language accepted by the state
                        return(false);
                    }

                    // Add a new self-loop
                    state.AddTransition(element.ElementDistribution, element.LoopWeight.Value, stateIndex, element.Group);
                    success = this.DoAddGeneralizedSequence(stateIndex, false, true, firstAllowedStateIndex, currentSequencePos + 1, sequence, weight);
                    Debug.Assert(success, "This call must always succeed.");
                    return(true);
                }

                // Try to find a transition for the element
                for (var iterator = state.TransitionIterator; iterator.Ok; iterator.Next())
                {
                    var transition = iterator.Value;

                    if (transition.IsEpsilon && transition.DestinationStateIndex != state.Index && transition.DestinationStateIndex >= firstAllowedStateIndex)
                    {
                        // Try this epsilon transition
                        if (this.DoAddGeneralizedSequence(
                                transition.DestinationStateIndex, false, false, firstAllowedStateIndex, currentSequencePos, sequence, weight))
                        {
                            return(true);
                        }
                    }

                    // Is it a self-loop?
                    if (transition.DestinationStateIndex == state.Index)
                    {
                        if (selfLoopAlreadyMatched)
                        {
                            // The self-loop was checked or added by the caller
                            continue;
                        }

                        // Can't go through an existing self-loop, it will allow undesired sequences to be accepted
                        return(false);
                    }

                    if (transition.DestinationStateIndex < firstAllowedStateIndex ||
                        element.Group != transition.Group ||
                        !element.ElementDistribution.Equals(transition.ElementDistribution))
                    {
                        continue;
                    }

                    // Skip the element in the sequence, move to the destination state
                    // Weight of the existing transition must be taken into account
                    // This case can fail if the next element is a self-loop and the destination state already has a different one
                    if (this.DoAddGeneralizedSequence(
                            transition.DestinationStateIndex,
                            false,
                            false,
                            firstAllowedStateIndex,
                            currentSequencePos + 1,
                            sequence,
                            Weight.Product(weight, Weight.Inverse(transition.Weight))))
                    {
                        return(true);
                    }
                }

                // Add a new transition
                var newChild = state.AddTransition(element.ElementDistribution, Weight.One, null, element.Group);

                success = this.DoAddGeneralizedSequence(
                    newChild.Index, true, false, firstAllowedStateIndex, currentSequencePos + 1, sequence, weight);
                Debug.Assert(success, "This call must always succeed.");
                return(true);
            }
Exemplo n.º 2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="WeightedSequence"/> struct.
 /// </summary>
 /// <param name="sequence">The <see cref="GeneralizedSequence"/></param>
 /// <param name="weight">The <see cref="Weight"/> for the specified sequence</param>
 public WeightedSequence(GeneralizedSequence sequence, Weight weight)
     : this()
 {
     this.Sequence = sequence;
     this.Weight   = weight;
 }
Exemplo n.º 3
0
            /// <summary>
            /// Recursively builds a complete list of generalized sequences accepted by the simplifiable part of the automaton.
            /// </summary>
            /// <param name="stateIndex">The currently traversed state.</param>
            /// <param name="generalizedTreeNodes">The state labels obtained from <see cref="FindGeneralizedTrees"/>.</param>
            /// <param name="weightedSequences">The sequence list being built.</param>
            /// <param name="currentSequenceElements">The list of elements of the sequence currently being built.</param>
            /// <param name="currentWeight">The weight of the sequence currently being built.</param>
            private void DoBuildAcceptedSequenceList(
                int stateIndex,
                bool[] generalizedTreeNodes,
                List <WeightedSequence> weightedSequences,
                List <GeneralizedElement> currentSequenceElements,
                Weight currentWeight)
            {
                var stack = new Stack <StackItem>();

                stack.Push(new StateWeight(stateIndex, currentWeight));

                while (stack.Count > 0)
                {
                    var stackItem = stack.Pop();

                    if (stackItem is ElementItem elementItem)
                    {
                        if (elementItem.Element != null)
                        {
                            currentSequenceElements.Add(elementItem.Element.Value);
                        }
                        else
                        {
                            currentSequenceElements.RemoveAt(currentSequenceElements.Count - 1);
                        }
                        continue;
                    }

                    var stateAndWeight = stackItem as StateWeight;

                    stateIndex = stateAndWeight.StateIndex;
                    var state = this.builder[stateIndex];
                    currentWeight = stateAndWeight.Weight;

                    // Find a non-epsilon self-loop if there is one
                    Transition?selfLoop = null;
                    for (var iterator = state.TransitionIterator; iterator.Ok; iterator.Next())
                    {
                        var transition = iterator.Value;
                        if (transition.DestinationStateIndex == stateIndex)
                        {
                            Debug.Assert(
                                selfLoop == null,
                                "Multiple self-loops should have been merged by MergeParallelTransitions()");
                            selfLoop = transition;
                        }
                    }

                    // Push the found self-loop to the end of the current sequence
                    if (selfLoop != null)
                    {
                        currentSequenceElements.Add(new GeneralizedElement(
                                                        selfLoop.Value.ElementDistribution, selfLoop.Value.Group, selfLoop.Value.Weight));
                        stack.Push(new ElementItem(null));
                    }

                    // Can this state produce a sequence?
                    if (state.CanEnd && generalizedTreeNodes[stateIndex])
                    {
                        var sequence = new GeneralizedSequence(currentSequenceElements);
                        // TODO: use immutable data structure instead of copying sequences
                        weightedSequences.Add(new WeightedSequence(sequence, Weight.Product(currentWeight, state.EndWeight)));
                    }

                    // Traverse the outgoing transitions
                    for (var iterator = state.TransitionIterator; iterator.Ok; iterator.Next())
                    {
                        var transition = iterator.Value;
                        // Skip self-loops & disallowed states
                        if (transition.DestinationStateIndex == stateIndex ||
                            !generalizedTreeNodes[transition.DestinationStateIndex])
                        {
                            continue;
                        }

                        if (!transition.IsEpsilon)
                        {
                            // Non-epsilon transitions contribute to the sequence
                            stack.Push(new ElementItem(null));
                        }

                        stack.Push(
                            new StateWeight(
                                transition.DestinationStateIndex,
                                Weight.Product(currentWeight, transition.Weight)));

                        if (!transition.IsEpsilon)
                        {
                            stack.Push(
                                new ElementItem(
                                    new GeneralizedElement(transition.ElementDistribution, transition.Group, null)));
                        }
                    }
                }
            }