/// <summary> /// Computes the total weights between each pair of states in the component /// using the <a href="http://www.cs.nyu.edu/~mohri/pub/hwa.pdf">generalized Floyd's algorithm</a>. /// </summary> private void ComputePairwiseWeightsMatrix() { this.pairwiseWeights = Util.ArrayInit(this.Size, this.Size, (i, j) => Weight.Zero); for (int srcStateIndexInComponent = 0; srcStateIndexInComponent < this.Size; ++srcStateIndexInComponent) { State state = this.statesInComponent[srcStateIndexInComponent]; foreach (var transition in state.Transitions) { State destState = state.Owner.States[transition.DestinationStateIndex]; int destStateIndexInComponent; if (this.transitionFilter(transition) && (destStateIndexInComponent = this.GetIndexByState(destState)) != -1) { this.pairwiseWeights[srcStateIndexInComponent, destStateIndexInComponent] += transition.Weight; } } } for (int k = 0; k < this.Size; ++k) { Weight loopWeight = this.useApproximateClosure ? Weight.ApproximateClosure(this.pairwiseWeights[k, k]) : Weight.Closure(this.pairwiseWeights[k, k]); for (int i = 0; i < this.Size; ++i) { if (i == k || this.pairwiseWeights[i, k].IsZero) { continue; } for (int j = 0; j < this.Size; ++j) { if (j == k || this.pairwiseWeights[k, j].IsZero) { continue; } this.pairwiseWeights[i, j] += Weight.Product( this.pairwiseWeights[i, k], loopWeight, this.pairwiseWeights[k, j]); } } for (int i = 0; i < this.Size; ++i) { this.pairwiseWeights[i, k] *= loopWeight; this.pairwiseWeights[k, i] *= loopWeight; } this.pairwiseWeights[k, k] = loopWeight; } }
/// <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) { 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 = 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((componentState, condensation.GetWeightFromRoot(componentState))); } } this.EndWeight = condensation.GetWeightToEnd(state.Index); } }
/// <summary> /// Gets the total weight between two given states in the component. /// </summary> /// <param name="srcStateIndexInComponent">The index of the source state in the component.</param> /// <param name="destStateIndexInComponent">The index of the destination state in the component.</param> /// <returns>The total weight between the given states in the component.</returns> public Weight GetWeight(int srcStateIndexInComponent, int destStateIndexInComponent) { Argument.CheckIfInRange( srcStateIndexInComponent >= 0 && srcStateIndexInComponent < this.Size, nameof(srcStateIndexInComponent), "The given index is out of range."); Argument.CheckIfInRange( destStateIndexInComponent >= 0 && destStateIndexInComponent < this.Size, nameof(destStateIndexInComponent), "The given index is out of range."); if (this.Size == 1) { if (!this.singleStatePairwiseWeight.HasValue) { // Optimize for a common case State state = this.statesInComponent[0]; this.singleStatePairwiseWeight = Weight.Zero; foreach (var transition in state.Transitions) { if (this.transitionFilter(transition) && transition.DestinationStateIndex == state.Index) { this.singleStatePairwiseWeight += transition.Weight; } } this.singleStatePairwiseWeight = this.useApproximateClosure ? Weight.ApproximateClosure(this.singleStatePairwiseWeight.Value) : Weight.Closure(this.singleStatePairwiseWeight.Value); } return(this.singleStatePairwiseWeight.Value); } if (this.pairwiseWeights == null) { this.ComputePairwiseWeightsMatrix(); } return(this.pairwiseWeights[srcStateIndexInComponent, destStateIndexInComponent]); }