/// <summary>
            /// For each state of the component, computes the total weight of all paths starting at the root
            /// and ending at that state. Ending weights are not taken into account.
            /// </summary>
            /// <remarks>The weights are computed using dynamic programming, going down from the root to leafs.</remarks>
            private void ComputeWeightsFromRoot()
            {
                CondensationStateInfo rootInfo = this.stateIdToInfo[this.Root.Index];

                rootInfo.UpwardWeightFromRoot       = Weight.One;
                this.stateIdToInfo[this.Root.Index] = rootInfo;

                // Iterate in the topological order
                for (int currentComponentIndex = this.components.Count - 1; currentComponentIndex >= 0; --currentComponentIndex)
                {
                    StronglyConnectedComponent currentComponent = this.components[currentComponentIndex];

                    // Propagate weights inside the component
                    for (int srcStateIndex = 0; srcStateIndex < currentComponent.Size; ++srcStateIndex)
                    {
                        State srcState = currentComponent.GetStateByIndex(srcStateIndex);
                        CondensationStateInfo srcStateInfo = this.stateIdToInfo[srcState.Index];
                        if (srcStateInfo.UpwardWeightFromRoot.IsZero)
                        {
                            continue;
                        }

                        for (int destStateIndex = 0; destStateIndex < currentComponent.Size; ++destStateIndex)
                        {
                            State destState = currentComponent.GetStateByIndex(destStateIndex);
                            CondensationStateInfo destStateInfo = this.stateIdToInfo[destState.Index];
                            destStateInfo.WeightFromRoot +=
                                srcStateInfo.UpwardWeightFromRoot * currentComponent.GetWeight(srcStateIndex, destStateIndex);
                            this.stateIdToInfo[destState.Index] = destStateInfo;
                        }
                    }

                    // Compute weight contributions to downward components
                    for (int srcStateIndex = 0; srcStateIndex < currentComponent.Size; ++srcStateIndex)
                    {
                        State srcState = currentComponent.GetStateByIndex(srcStateIndex);
                        CondensationStateInfo srcStateInfo = this.stateIdToInfo[srcState.Index];
                        if (srcStateInfo.WeightFromRoot.IsZero)
                        {
                            continue;
                        }

                        // Aggregate weights of all the outgoing transitions from this state
                        foreach (var transition in srcState.Transitions)
                        {
                            State destState = this.automaton.States[transition.DestinationStateIndex];
                            if (this.transitionFilter(transition) && !currentComponent.HasState(destState))
                            {
                                CondensationStateInfo destStateInfo = this.stateIdToInfo[destState.Index];
                                destStateInfo.UpwardWeightFromRoot += srcStateInfo.WeightFromRoot * transition.Weight;
                                this.stateIdToInfo[transition.DestinationStateIndex] = destStateInfo;
                            }
                        }
                    }
                }

                this.weightsFromRootComputed = true;
            }
            /// <summary>
            /// Initializes a new instance of the <see cref="Condensation"/> class.
            /// </summary>
            /// <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(State root, Func <Transition, bool> transitionFilter, bool useApproximateClosure)
            {
                Debug.Assert(root != null, "A valid root node must be provided.");
                Debug.Assert(transitionFilter != null, "A valid transition filter must be provided.");

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

                this.components = new List <StronglyConnectedComponent>();
                var stateIdStack        = new Stack <State>();
                var stateIdToTarjanInfo = new Dictionary <int, TarjanStateInfo>();
                int traversalIndex      = 0;

                this.FindStronglyConnectedComponents(this.Root, ref traversalIndex, stateIdToTarjanInfo, stateIdStack);

                this.stateIdToInfo = new Dictionary <int, CondensationStateInfo>(stateIdToTarjanInfo.Count);
                for (int i = 0; i < this.components.Count; ++i)
                {
                    StronglyConnectedComponent component = this.components[i];
                    for (int j = 0; j < component.Size; ++j)
                    {
                        this.stateIdToInfo.Add(component.GetStateByIndex(j).Index, CondensationStateInfo.Default);
                    }
                }
            }
示例#3
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>
            /// For each state of the component, computes the total weight of all paths starting at that state.
            /// Ending weights are taken into account.
            /// </summary>
            /// <remarks>The weights are computed using dynamic programming, going up from leafs to the root.</remarks>
            private void ComputeWeightsToEnd()
            {
                // Iterate in the reverse topological order
                for (int currentComponentIndex = 0; currentComponentIndex < this.components.Count; ++currentComponentIndex)
                {
                    StronglyConnectedComponent currentComponent = this.components[currentComponentIndex];

                    // Update end weights in this component based on outgoing transitions to downward components
                    for (int stateIndex = 0; stateIndex < currentComponent.Size; ++stateIndex)
                    {
                        State state = currentComponent.GetStateByIndex(stateIndex);

                        // Aggregate weights of all the outgoing transitions from this state
                        Weight weightToAdd = state.EndWeight;
                        for (int transitionIndex = 0; transitionIndex < state.TransitionCount; ++transitionIndex)
                        {
                            Transition transition = state.GetTransition(transitionIndex);
                            State      destState  = state.Owner.states[transition.DestinationStateIndex];
                            if (this.transitionFilter(transition) && !currentComponent.HasState(destState))
                            {
                                weightToAdd = Weight.Sum(
                                    weightToAdd,
                                    Weight.Product(transition.Weight, this.stateIdToInfo[transition.DestinationStateIndex].WeightToEnd));
                            }
                        }

                        // We can go from any state of the component to the current state
                        if (!weightToAdd.IsZero)
                        {
                            for (int updatedStateIndex = 0; updatedStateIndex < currentComponent.Size; ++updatedStateIndex)
                            {
                                State updatedState = currentComponent.GetStateByIndex(updatedStateIndex);
                                CondensationStateInfo updatedStateInfo = this.stateIdToInfo[updatedState.Index];
                                updatedStateInfo.WeightToEnd = Weight.Sum(
                                    updatedStateInfo.WeightToEnd,
                                    Weight.Product(currentComponent.GetWeight(updatedStateIndex, stateIndex), weightToAdd));
                                this.stateIdToInfo[updatedState.Index] = updatedStateInfo;
                            }
                        }
                    }
                }

                this.weightsToEndComputed = true;
            }
示例#5
0
            /// <summary>
            /// For each state of the component, computes the total weight of all paths starting at that state.
            /// Ending weights are taken into account.
            /// </summary>
            /// <remarks>The weights are computed using dynamic programming, going up from leafs to the root.</remarks>
            private void ComputeWeightsToEnd()
            {
                // Iterate in the reverse topological order
                for (int currentComponentIndex = 0; currentComponentIndex < this.components.Count; ++currentComponentIndex)
                {
                    StronglyConnectedComponent currentComponent = this.components[currentComponentIndex];

                    // Update end weights in this component based on outgoing transitions to downward components
                    for (int stateIndex = 0; stateIndex < currentComponent.Size; ++stateIndex)
                    {
                        State state = currentComponent.GetStateByIndex(stateIndex);

                        // Aggregate weights of all the outgoing transitions from this state
                        Weight weightToAdd = state.EndWeight;
                        foreach (var transition in state.Transitions)
                        {
                            State destState = this.automaton.States[transition.DestinationStateIndex];
                            if (this.transitionFilter(transition) && !currentComponent.HasState(destState))
                            {
                                weightToAdd += transition.Weight * this.stateInfo[transition.DestinationStateIndex].WeightToEnd;
                            }
                        }

                        // We can go from any state of the component to the current state
                        if (!weightToAdd.IsZero)
                        {
                            for (int updatedStateIndex = 0; updatedStateIndex < currentComponent.Size; ++updatedStateIndex)
                            {
                                State updatedState = currentComponent.GetStateByIndex(updatedStateIndex);
                                CondensationStateInfo updatedStateInfo = this.stateInfo[updatedState.Index];
                                updatedStateInfo.WeightToEnd +=
                                    currentComponent.GetWeight(updatedStateIndex, stateIndex) * weightToAdd;
                                this.stateInfo.Update(updatedState.Index, updatedStateInfo);
                            }
                        }
                    }
                }

                this.weightsToEndComputed = true;
            }
示例#6
0
            /// <summary>
            /// Initializes a new instance of the <see cref="EpsilonClosure"/> class.
            /// </summary>
            /// <param name="automaton">The automaton from to which <paramref name="state"/> belongs.</param>
            /// <param name="state">The state, which epsilon closure this instance will represent.</param>
            internal EpsilonClosure(
                Automaton <TSequence, TElement, TElementDistribution, TSequenceManipulator, TThis> automaton,
                State state)
            {
                this.weightedStates = new List <(State, Weight)>(DefaultStateListCapacity);

                // Optimize for a very common case: a single-node closure
                bool   singleNodeClosure = true;
                Weight selfLoopWeight    = Weight.Zero;

                foreach (var transition in state.Transitions)
                {
                    if (transition.IsEpsilon)
                    {
                        if (transition.DestinationStateIndex != state.Index)
                        {
                            singleNodeClosure = false;
                            break;
                        }

                        selfLoopWeight += transition.Weight;
                    }
                }

                if (singleNodeClosure)
                {
                    Weight stateWeight = Weight.ApproximateClosure(selfLoopWeight);
                    this.weightedStates.Add((state, stateWeight));
                    this.EndWeight = stateWeight * state.EndWeight;
                }
                else
                {
                    Condensation condensation = automaton.ComputeCondensation(state, tr => tr.IsEpsilon, true);
                    for (int i = 0; i < condensation.ComponentCount; ++i)
                    {
                        StronglyConnectedComponent component = condensation.GetComponent(i);
                        for (int j = 0; j < component.Size; ++j)
                        {
                            State componentState = component.GetStateByIndex(j);
                            this.weightedStates.Add((componentState, condensation.GetWeightFromRoot(componentState)));
                        }
                    }

                    this.EndWeight = condensation.GetWeightToEnd(state.Index);
                }
            }
示例#7
0
            /// <summary>
            /// Initializes a new instance of the <see cref="EpsilonClosure"/> class.
            /// </summary>
            /// <param name="state">The state, which epsilon closure this instance will represent.</param>
            internal EpsilonClosure(State state)
            {
                Argument.CheckIfValid(!state.IsNull, nameof(state));

                // Optimize for a very common case: a single-node closure
                bool   singleNodeClosure = true;
                Weight selfLoopWeight    = Weight.Zero;

                for (int i = 0; i < state.TransitionCount; ++i)
                {
                    Transition transition = state.GetTransition(i);
                    if (transition.IsEpsilon)
                    {
                        if (transition.DestinationStateIndex != state.Index)
                        {
                            singleNodeClosure = false;
                            break;
                        }

                        selfLoopWeight = Weight.Sum(selfLoopWeight, transition.Weight);
                    }
                }

                if (singleNodeClosure)
                {
                    Weight stateWeight = Weight.ApproximateClosure(selfLoopWeight);
                    this.weightedStates.Add(Pair.Create(state, stateWeight));
                    this.EndWeight = Weight.Product(stateWeight, state.EndWeight);
                }
                else
                {
                    Condensation condensation = state.Owner.ComputeCondensation(state, tr => tr.IsEpsilon, true);
                    for (int i = 0; i < condensation.ComponentCount; ++i)
                    {
                        StronglyConnectedComponent component = condensation.GetComponent(i);
                        for (int j = 0; j < component.Size; ++j)
                        {
                            State componentState = component.GetStateByIndex(j);
                            this.weightedStates.Add(Pair.Create(componentState, condensation.GetWeightFromRoot(componentState)));
                        }
                    }

                    this.EndWeight = condensation.GetWeightToEnd(state);
                }
            }
示例#8
0
            /// <summary>
            /// Initializes a new instance of the <see cref="Condensation"/> class.
            /// </summary>
            /// <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(State root, Func <Transition, bool> transitionFilter, bool useApproximateClosure)
            {
                Debug.Assert(transitionFilter != null, "A valid transition filter must be provided.");

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

                this.components = this.FindStronglyConnectedComponents();

                this.stateIdToInfo = new Dictionary <int, CondensationStateInfo>();
                for (int i = 0; i < this.components.Count; ++i)
                {
                    StronglyConnectedComponent component = this.components[i];
                    for (int j = 0; j < component.Size; ++j)
                    {
                        this.stateIdToInfo.Add(component.GetStateByIndex(j).Index, CondensationStateInfo.Default);
                    }
                }
            }