/// <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> /// Computes a set of outgoing transitions from a given state of the determinization result. /// </summary> /// <param name="sourceStateSet">The source state of the determinized automaton represented as /// a set of (stateId, weight) pairs, where state ids correspond to states of the original automaton.</param> /// <returns> /// A collection of (element distribution, weight, weighted state set) triples corresponding to outgoing /// transitions from <paramref name="sourceStateSet"/>. /// The first two elements of a tuple define the element distribution and the weight of a transition. /// The third element defines the outgoing state. /// </returns> protected override IEnumerable <Determinization.OutgoingTransition> GetOutgoingTransitionsForDeterminization( Determinization.WeightedStateSet sourceStateSet) { // Build a list of numbered non-zero probability character segment bounds (they are numbered here due to perf. reasons) var segmentBounds = new List <TransitionCharSegmentBound>(); for (var i = 0; i < sourceStateSet.Count; ++i) { var sourceState = sourceStateSet[i]; var state = this.States[sourceState.Index]; foreach (var transition in state.Transitions) { AddTransitionCharSegmentBounds(transition, sourceState.Weight, segmentBounds); } } segmentBounds.Sort(); // Produce an outgoing transition for each unique subset of overlapping segments var currentSegmentTotal = WeightSum.Zero(); var currentSegmentStateWeights = new Dictionary <int, WeightSum>(); var currentSegmentStart = (int)char.MinValue; var destinationStateSetBuilder = Determinization.WeightedStateSetBuilder.Create(); foreach (var segmentBound in segmentBounds) { if (currentSegmentTotal.Count != 0 && currentSegmentStart < segmentBound.Bound) { // Flush previous segment var segmentEnd = (char)(segmentBound.Bound - 1); var segmentLength = segmentEnd - currentSegmentStart + 1; var elementDist = DiscreteChar.InRange((char)currentSegmentStart, segmentEnd); var invTotalWeight = Weight.Inverse(currentSegmentTotal.Sum); destinationStateSetBuilder.Reset(); foreach (var stateIdWithWeight in currentSegmentStateWeights) { var stateWeight = stateIdWithWeight.Value.Sum * invTotalWeight; destinationStateSetBuilder.Add(stateIdWithWeight.Key, stateWeight); } var(destinationStateSet, destinationStateSetWeight) = destinationStateSetBuilder.Get(); var transitionWeight = Weight.Product( Weight.FromValue(segmentLength), currentSegmentTotal.Sum, destinationStateSetWeight); yield return(new Determinization.OutgoingTransition( elementDist, transitionWeight, destinationStateSet)); } // Update current segment currentSegmentStart = segmentBound.Bound; if (segmentBound.IsStart) { currentSegmentTotal += segmentBound.Weight; if (currentSegmentStateWeights.TryGetValue(segmentBound.DestinationStateId, out var stateWeight)) { currentSegmentStateWeights[segmentBound.DestinationStateId] = stateWeight + segmentBound.Weight; } else { currentSegmentStateWeights[segmentBound.DestinationStateId] = new WeightSum(segmentBound.Weight); } } else { Debug.Assert(currentSegmentStateWeights.ContainsKey(segmentBound.DestinationStateId), "We shouldn't exit a state we didn't enter."); Debug.Assert(!segmentBound.Weight.IsInfinity); currentSegmentTotal -= segmentBound.Weight; var prevStateWeight = currentSegmentStateWeights[segmentBound.DestinationStateId]; var newStateWeight = prevStateWeight - segmentBound.Weight; if (newStateWeight.Count == 0) { currentSegmentStateWeights.Remove(segmentBound.DestinationStateId); } else { currentSegmentStateWeights[segmentBound.DestinationStateId] = newStateWeight; } } } }