示例#1
0
            /// <summary>
            /// Initializes a new instance of the <see cref="Condensation"/> class.
            /// </summary>
            /// <param name="automaton">The automaton.</param>
            /// <param name="root">The root of the condensation DAG.</param>
            /// <param name="transitionFilter">
            /// A function specifying whether the transition should be treated as an edge
            /// of the automaton graph while building the condensation.
            /// </param>
            /// <param name="useApproximateClosure">
            /// Specifies whether <see cref="Weight.ApproximateClosure"/> should be used
            /// instead of <see cref="Weight.Closure"/> in semiring computations.
            /// </param>
            internal Condensation(
                Automaton <TSequence, TElement, TElementDistribution, TSequenceManipulator, TThis> automaton,
                State root,
                Func <Transition, bool> transitionFilter, bool useApproximateClosure)
            {
                Debug.Assert(transitionFilter != null, "A valid transition filter must be provided.");

                this.automaton             = automaton;
                this.Root                  = root;
                this.transitionFilter      = transitionFilter;
                this.useApproximateClosure = useApproximateClosure;

                this.components = this.FindStronglyConnectedComponents();

                this.stateInfo = PreallocatedAutomataObjects.LeaseComputeCondensationState();

                for (int i = 0; i < this.components.Count; ++i)
                {
                    StronglyConnectedComponent component = this.components[i];
                    for (int j = 0; j < component.Size; ++j)
                    {
                        this.stateInfo.Add(component.GetStateByIndex(j).Index, CondensationStateInfo.Default);
                    }
                }
            }
            /// <summary>
            /// Optimizes the automaton by removing all states which can't reach end states.
            /// </summary>
            public bool RemoveDeadStates()
            {
                var builder = this.builder;

                var(edgesStart, edges) = BuildReversedGraph();

                //// Now run a depth-first search to label all reachable nodes
                var(stack, visited) = PreallocatedAutomataObjects.LeaseRemoveDeadStatesState(builder.StatesCount);

                for (var i = 0; i < builder.StatesCount; ++i)
                {
                    if (!visited[i] && builder[i].CanEnd)
                    {
                        visited[i] = true;
                        stack.Push(i);
                        while (stack.Count != 0)
                        {
                            var stateIndex = stack.Pop();
                            for (var j = edgesStart[stateIndex]; j < edgesStart[stateIndex + 1]; ++j)
                            {
                                var destinationIndex = edges[j];
                                if (!visited[destinationIndex])
                                {
                                    visited[destinationIndex] = true;
                                    stack.Push(destinationIndex);
                                }
                            }
                        }
                    }
                }

                if (!visited[builder.StartStateIndex])
                {
                    builder.Clear();
                    builder.StartStateIndex = builder.AddState().Index;
                    return(true);
                }

                return(this.builder.RemoveStates(visited, false) > 0);

                (int[] edgesStart, int[] edges) BuildReversedGraph()
                {
                    // [edgesStart[i]; edgesStart[i+1]) is a range `edges` array which corresponds to incoming edges for state `i`
                    // edges1 is incoming edges for state. Represented as index of source state
                    var(edgesStart1, edges1) = PreallocatedAutomataObjects.LeaseBuildReversedGraphState(
                        builder.StatesCount + 1, builder.TransitionsCount);

                    // first populate edges
                    for (var i = 0; i < builder.StatesCount; ++i)
                    {
                        for (var iterator = builder[i].TransitionIterator; iterator.Ok; iterator.Next())
                        {
                            ++edgesStart1[iterator.Value.DestinationStateIndex];
                        }
                    }

                    // calculate commutative sums. Now edgesStart[i] contains end of range
                    for (var i = 0; i < builder.StatesCount; ++i)
                    {
                        edgesStart1[i + 1] += edgesStart1[i];
                    }

                    // Fill ranges and adjust start indices. Now edgesStart[i] contains begining of the range
                    for (var i = 0; i < builder.StatesCount; ++i)
                    {
                        for (var iterator = builder[i].TransitionIterator; iterator.Ok; iterator.Next())
                        {
                            var index = --edgesStart1[iterator.Value.DestinationStateIndex];
                            edges1[index] = i;
                        }
                    }

                    return(edgesStart1, edges1);
                }
            }
示例#3
0
            /// <summary>
            /// Implements <a href="http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm">Tarjan's algorithm</a>
            /// for finding the strongly connected components of the automaton graph.
            /// </summary>
            private List <StronglyConnectedComponent> FindStronglyConnectedComponents()
            {
                var components = new List <StronglyConnectedComponent>();

                var states         = this.automaton.States;
                int traversalIndex = 0;

                var(stateIdStack, stateInfo, traversalStack, generation) =
                    PreallocatedAutomataObjects.LeaseFindStronglyConnectedComponentsState(states.Count);

                traversalStack.Push(new IntPair(this.Root.Index, 0));
                while (traversalStack.Count > 0)
                {
                    var(currentStateIndex, currentTransitionIndex) = traversalStack.Pop();
                    var currentState = states[currentStateIndex];
                    var transitions  = currentState.Transitions;

                    if (stateInfo[currentStateIndex].Generation != generation)
                    {
                        ++traversalIndex;
                        // Entered into processing of this state for the first time: create Tarjan info for it
                        // and push the state onto Tarjan stack.
                        stateInfo[currentStateIndex] = new TarjanStateInfo(generation, traversalIndex);
                        stateIdStack.Push(currentStateIndex);
                    }
                    else
                    {
                        // Just returned from recursion into 'currentTransitionIndex': update Lowlink
                        // and advance to next transition.
                        var lastDestination = transitions[currentTransitionIndex].DestinationStateIndex;
                        stateInfo[currentStateIndex].Lowlink = Math.Min(
                            stateInfo[currentStateIndex].Lowlink,
                            stateInfo[lastDestination].Lowlink);
                        ++currentTransitionIndex;
                    }

                    for (; currentTransitionIndex < transitions.Count; ++currentTransitionIndex)
                    {
                        var transition = transitions[currentTransitionIndex];
                        if (!this.transitionFilter(transition))
                        {
                            continue;
                        }

                        var destinationStateIndex = transition.DestinationStateIndex;
                        if (stateInfo[destinationStateIndex].Generation != generation)
                        {
                            // Return to this (state/transition) after destinationState is processed.
                            // Processing will resume from currentTransitionIndex.
                            traversalStack.Push(new IntPair(currentStateIndex, currentTransitionIndex));
                            // Process destination state.
                            traversalStack.Push(new IntPair(destinationStateIndex, 0));
                            // Do not process other transitions until destination state is processed.
                            break;
                        }

                        if (stateInfo[destinationStateIndex].InStack)
                        {
                            stateInfo[currentStateIndex].Lowlink = Math.Min(
                                stateInfo[currentStateIndex].Lowlink,
                                stateInfo[destinationStateIndex].TraversalIndex);
                        }
                    }

                    if (currentTransitionIndex < transitions.Count)
                    {
                        // Not all states processed: continue processing according to stack. Current state
                        // is already pushed onto it -> will be processed again.
                        continue;
                    }

                    if (stateInfo[currentStateIndex].Lowlink == stateInfo[currentStateIndex].TraversalIndex)
                    {
                        var statesInComponent = new List <State>();
                        while (true)
                        {
                            var stateIndex = stateIdStack.Pop();
                            stateInfo[stateIndex].InStack = false;
                            statesInComponent.Add(states[stateIndex]);
                            if (stateIndex == currentStateIndex)
                            {
                                break;
                            }
                        }

                        components.Add(new StronglyConnectedComponent(
                                           this.automaton, this.transitionFilter, statesInComponent, this.useApproximateClosure));
                        this.TotalStatesCount += statesInComponent.Count;
                    }
                }

                return(components);
            }
示例#4
0
 public void Dispose()
 {
     PreallocatedAutomataObjects.ReleaseComputeCondensationState(this.stateInfo);
 }
示例#5
0
            /// <summary>
            /// Removes a set of states from the automaton where the set is defined by labels not matching
            /// the <paramref name="removeLabel"/>.
            /// </summary>
            /// <param name="labels">State labels</param>
            /// <param name="removeLabel">Label which marks states which should be deleted</param>
            public int RemoveStates(bool[] labels, bool removeLabel)
            {
                var oldToNewStateIdMapping = PreallocatedAutomataObjects.LeaseRemoveStatesState(this.states.Count);

                var newStateId     = 0;
                var deadStateCount = 0;

                for (var stateId = 0; stateId < this.states.Count; ++stateId)
                {
                    if (labels[stateId] != removeLabel)
                    {
                        oldToNewStateIdMapping[stateId] = newStateId++;
                    }
                    else
                    {
                        oldToNewStateIdMapping[stateId] = -1;
                        ++deadStateCount;
                    }
                }

                if (deadStateCount == 0)
                {
                    return(0);
                }

                this.StartStateIndex = oldToNewStateIdMapping[this.StartStateIndex];

                // Caller must ensure that it doesn't try to delete start state. Because it will lead to
                // invalid automaton.
                Debug.Assert(this.StartStateIndex != -1);

                for (var i = 0; i < this.states.Count; ++i)
                {
                    var newId = oldToNewStateIdMapping[i];
                    if (newId == -1)
                    {
                        // remove all transitions
                        for (var iterator = this[i].TransitionIterator; iterator.Ok; iterator.Next())
                        {
                            iterator.Remove();
                        }

                        continue;
                    }

                    Debug.Assert(newId <= i);

                    this.states[newId] = this.states[i];

                    // Remap transitions
                    for (var iterator = this[newId].TransitionIterator; iterator.Ok; iterator.Next())
                    {
                        var transition            = iterator.Value;
                        var destinationStateIndex = oldToNewStateIdMapping[transition.DestinationStateIndex];
                        if (destinationStateIndex == -1)
                        {
                            iterator.Remove();
                        }
                        else
                        {
                            iterator.Value = transition.With(destinationStateIndex: destinationStateIndex);
                        }
                    }
                }

                this.states.RemoveRange(newStateId, this.states.Count - newStateId);

                return(deadStateCount);
            }