/// <summary> /// Given a transition and the residual weight of its source state, adds weighted non-zero probability character segments /// associated with the transition to the list. /// </summary> /// <param name="transition">The transition.</param> /// <param name="sourceStateResidualWeight">The logarithm of the residual weight of the source state of the transition.</param> /// <param name="bounds">The list for storing numbered segment bounds.</param> private static void AddTransitionCharSegmentBounds( Transition transition, Weight sourceStateResidualWeight, List <ValueTuple <int, TransitionCharSegmentBound> > bounds) { var distribution = transition.ElementDistribution.Value; var ranges = distribution.Ranges; int commonValueStart = char.MinValue; Weight commonValue = Weight.FromValue(distribution.ProbabilityOutsideRanges); Weight weightBase = Weight.Product(transition.Weight, sourceStateResidualWeight); TransitionCharSegmentBound newSegmentBound; ////if (double.IsInfinity(weightBase.Value)) ////{ //// Console.WriteLine("Weight base infinity"); ////} foreach (var range in ranges) { if (range.StartInclusive > commonValueStart && !commonValue.IsZero) { // Add endpoints for the common value Weight segmentWeight = Weight.Product(commonValue, weightBase); newSegmentBound = new TransitionCharSegmentBound(commonValueStart, transition.DestinationStateIndex, segmentWeight, true); bounds.Add(new ValueTuple <int, TransitionCharSegmentBound>(bounds.Count, newSegmentBound)); newSegmentBound = new TransitionCharSegmentBound(range.StartInclusive, transition.DestinationStateIndex, segmentWeight, false); bounds.Add(new ValueTuple <int, TransitionCharSegmentBound>(bounds.Count, newSegmentBound)); } // Add segment endpoints Weight pieceValue = Weight.FromValue(range.Probability); if (!pieceValue.IsZero) { Weight segmentWeight = Weight.Product(pieceValue, weightBase); newSegmentBound = new TransitionCharSegmentBound(range.StartInclusive, transition.DestinationStateIndex, segmentWeight, true); bounds.Add(new ValueTuple <int, TransitionCharSegmentBound>(bounds.Count, newSegmentBound)); newSegmentBound = new TransitionCharSegmentBound(range.EndExclusive, transition.DestinationStateIndex, segmentWeight, false); bounds.Add(new ValueTuple <int, TransitionCharSegmentBound>(bounds.Count, newSegmentBound)); } commonValueStart = range.EndExclusive; } if (!commonValue.IsZero && (ranges.Count == 0 || ranges[ranges.Count - 1].EndExclusive != DiscreteChar.CharRangeEndExclusive)) { // Add endpoints for the last common value segment Weight segmentWeight = Weight.Product(commonValue, weightBase); newSegmentBound = new TransitionCharSegmentBound(commonValueStart, transition.DestinationStateIndex, segmentWeight, true); bounds.Add(new ValueTuple <int, TransitionCharSegmentBound>(bounds.Count, newSegmentBound)); newSegmentBound = new TransitionCharSegmentBound(char.MaxValue + 1, transition.DestinationStateIndex, segmentWeight, false); bounds.Add(new ValueTuple <int, TransitionCharSegmentBound>(bounds.Count, newSegmentBound)); } }
/// <summary> /// Given a transition and the residual weight of its source state, adds weighted non-zero probability character segments /// associated with the transition to the list. /// </summary> /// <param name="transition">The transition.</param> /// <param name="sourceStateResidualWeight">The logarithm of the residual weight of the source state of the transition.</param> /// <param name="bounds">The list for storing numbered segment bounds.</param> private static void AddTransitionCharSegmentBounds( Transition transition, Weight sourceStateResidualWeight, List <Tuple <int, TransitionCharSegmentBound> > bounds) { var probs = (PiecewiseVector)transition.ElementDistribution.GetProbs(); int commonValueStart = char.MinValue; Weight commonValue = Weight.FromValue(probs.CommonValue); Weight weightBase = Weight.Product(transition.Weight, sourceStateResidualWeight); TransitionCharSegmentBound newSegmentBound; ////if (double.IsInfinity(weightBase.Value)) ////{ //// Console.WriteLine("Weight base infinity"); ////} for (int i = 0; i < probs.Pieces.Count; ++i) { ConstantVector piece = probs.Pieces[i]; if (piece.Start > commonValueStart && !commonValue.IsZero) { // Add endpoints for the common value Weight segmentWeight = Weight.Product(commonValue, weightBase); newSegmentBound = new TransitionCharSegmentBound(commonValueStart, transition.DestinationStateIndex, segmentWeight, true); bounds.Add(new Tuple <int, TransitionCharSegmentBound>(bounds.Count, newSegmentBound)); newSegmentBound = new TransitionCharSegmentBound(piece.Start, transition.DestinationStateIndex, segmentWeight, false); bounds.Add(new Tuple <int, TransitionCharSegmentBound>(bounds.Count, newSegmentBound)); } // Add segment endpoints Weight pieceValue = Weight.FromValue(piece.Value); if (!pieceValue.IsZero) { Weight segmentWeight = Weight.Product(pieceValue, weightBase); newSegmentBound = new TransitionCharSegmentBound(piece.Start, transition.DestinationStateIndex, segmentWeight, true); bounds.Add(new Tuple <int, TransitionCharSegmentBound>(bounds.Count, newSegmentBound)); newSegmentBound = new TransitionCharSegmentBound(piece.End + 1, transition.DestinationStateIndex, segmentWeight, false); bounds.Add(new Tuple <int, TransitionCharSegmentBound>(bounds.Count, newSegmentBound)); } commonValueStart = piece.End + 1; } if (!commonValue.IsZero && (probs.Pieces.Count == 0 || probs.Pieces[probs.Pieces.Count - 1].End != char.MaxValue)) { // Add endpoints for the last common value segment Weight segmentWeight = Weight.Product(commonValue, weightBase); newSegmentBound = new TransitionCharSegmentBound(commonValueStart, transition.DestinationStateIndex, segmentWeight, true); bounds.Add(new Tuple <int, TransitionCharSegmentBound>(bounds.Count, newSegmentBound)); newSegmentBound = new TransitionCharSegmentBound(char.MaxValue + 1, transition.DestinationStateIndex, segmentWeight, false); bounds.Add(new Tuple <int, TransitionCharSegmentBound>(bounds.Count, newSegmentBound)); } }
/// <summary> /// Computes a set of outgoing transitions from a given state of the determinization result. /// </summary> /// <param name="sourceState">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="sourceState"/>. /// 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 List <(DiscreteChar, Weight, Determinization.WeightedStateSet)> GetOutgoingTransitionsForDeterminization( Determinization.WeightedStateSet sourceState) { const double LogEps = -35; // Don't add transitions with log-weight less than this as they have been produced by numerical inaccuracies // Build a list of numbered non-zero probability character segment bounds (they are numbered here due to perf. reasons) var segmentBounds = new List <ValueTuple <int, TransitionCharSegmentBound> >(); int transitionsProcessed = 0; foreach (KeyValuePair <int, Weight> stateIdWeight in sourceState) { var state = this.States[stateIdWeight.Key]; foreach (var transition in state.Transitions) { AddTransitionCharSegmentBounds(transition, stateIdWeight.Value, segmentBounds); } transitionsProcessed += state.Transitions.Count; } // Sort segment bounds left-to-right, start-to-end var sortedIndexedSegmentBounds = segmentBounds.ToArray(); if (transitionsProcessed > 1) { Array.Sort(sortedIndexedSegmentBounds, CompareSegmentBounds); int CompareSegmentBounds((int, TransitionCharSegmentBound) a, (int, TransitionCharSegmentBound) b) => a.Item2.CompareTo(b.Item2); } // Produce an outgoing transition for each unique subset of overlapping segments var result = new List <(DiscreteChar, Weight, Determinization.WeightedStateSet)>(); Weight currentSegmentStateWeightSum = Weight.Zero; var currentSegmentStateWeights = new Dictionary <int, Weight>(); foreach (var sb in segmentBounds) { currentSegmentStateWeights[sb.Item2.DestinationStateId] = Weight.Zero; } var activeSegments = new HashSet <TransitionCharSegmentBound>(); int currentSegmentStart = char.MinValue; foreach (var tup in sortedIndexedSegmentBounds) { TransitionCharSegmentBound segmentBound = tup.Item2; if (currentSegmentStateWeightSum.LogValue > LogEps && currentSegmentStart < segmentBound.Bound) { // Flush previous segment char segmentEnd = (char)(segmentBound.Bound - 1); int segmentLength = segmentEnd - currentSegmentStart + 1; DiscreteChar elementDist = DiscreteChar.InRange((char)currentSegmentStart, segmentEnd); var destinationState = new Determinization.WeightedStateSet(); foreach (KeyValuePair <int, Weight> stateIdWithWeight in currentSegmentStateWeights) { if (stateIdWithWeight.Value.LogValue > LogEps) { Weight stateWeight = Weight.Product(stateIdWithWeight.Value, Weight.Inverse(currentSegmentStateWeightSum)); destinationState.Add(stateIdWithWeight.Key, stateWeight); } } Weight transitionWeight = Weight.Product(Weight.FromValue(segmentLength), currentSegmentStateWeightSum); result.Add((elementDist, transitionWeight, destinationState)); } // Update current segment currentSegmentStart = segmentBound.Bound; if (segmentBound.IsStart) { activeSegments.Add(segmentBound); currentSegmentStateWeightSum = Weight.Sum(currentSegmentStateWeightSum, segmentBound.Weight); currentSegmentStateWeights[segmentBound.DestinationStateId] = Weight.Sum(currentSegmentStateWeights[segmentBound.DestinationStateId], segmentBound.Weight); } else { Debug.Assert(currentSegmentStateWeights.ContainsKey(segmentBound.DestinationStateId), "We shouldn't exit a state we didn't enter."); activeSegments.Remove(segmentBounds[tup.Item1 - 1].Item2); // End follows start in original. if (double.IsInfinity(segmentBound.Weight.Value)) { // Cannot subtract because of the infinities involved. currentSegmentStateWeightSum = activeSegments.Select(sb => sb.Weight).Aggregate(Weight.Zero, (acc, w) => Weight.Sum(acc, w)); currentSegmentStateWeights[segmentBound.DestinationStateId] = activeSegments.Where(sb => sb.DestinationStateId == segmentBound.DestinationStateId).Select(sb => sb.Weight).Aggregate(Weight.Zero, (acc, w) => Weight.Sum(acc, w)); } else { currentSegmentStateWeightSum = activeSegments.Count == 0 ? Weight.Zero : Weight.AbsoluteDifference(currentSegmentStateWeightSum, segmentBound.Weight); Weight prevStateWeight = currentSegmentStateWeights[segmentBound.DestinationStateId]; currentSegmentStateWeights[segmentBound.DestinationStateId] = Weight.AbsoluteDifference( prevStateWeight, segmentBound.Weight); } } } return(result); }