diff --git a/src/SIL.Machine/FiniteState/Fst.cs b/src/SIL.Machine/FiniteState/Fst.cs index db44acd9..cd98a550 100644 --- a/src/SIL.Machine/FiniteState/Fst.cs +++ b/src/SIL.Machine/FiniteState/Fst.cs @@ -353,7 +353,7 @@ out IEnumerable> results } else if (_registerCount > 0) { - traversalMethod = new LazyNondeterministicFsaTraversalMethod( + traversalMethod = new TwoPassNondeterministicFsaTraversalMethod( this, data, varBindings, diff --git a/src/SIL.Machine/FiniteState/TraversalMethodBase.cs b/src/SIL.Machine/FiniteState/TraversalMethodBase.cs index bb7714b1..32584dc6 100644 --- a/src/SIL.Machine/FiniteState/TraversalMethodBase.cs +++ b/src/SIL.Machine/FiniteState/TraversalMethodBase.cs @@ -25,6 +25,8 @@ internal abstract class TraversalMethodBase : ITraversalM private readonly IDictionary> _commandUpdates; private readonly IDictionary> _outputs; private readonly TInst _finalInst; + private readonly Register _emptyRegister; + private readonly bool _canonicalizeOptionalAnnotations; protected TraversalMethodBase( Fst fst, @@ -32,7 +34,8 @@ protected TraversalMethodBase( VariableBindings varBindings, bool startAnchor, bool endAnchor, - bool useDefaults + bool useDefaults, + bool canonicalizeOptionalAnnotations = false ) { _fst = fst; @@ -70,6 +73,8 @@ bool useDefaults _commandUpdates = new Dictionary>(); _outputs = new Dictionary>(); _finalInst = CreateInstance(); + _emptyRegister = new Register(); + _canonicalizeOptionalAnnotations = canonicalizeOptionalAnnotations; } private int CompareAnnotations(Annotation x, Annotation y) @@ -116,7 +121,8 @@ public CommandUpdate( Arc arc, IEnumerable cmds, Register start, - Register end) + Register end + ) { Source = source; Arc = arc; @@ -201,7 +207,7 @@ Arc arc { if (arc.Target.IsAccepting && (!_endAnchor || inst.AnnotationIndex == _annotations.Count)) { - RecordCommands(inst, arc, arc.Target.Finishers, new Register(), new Register(), _finalInst); + RecordCommands(inst, arc, arc.Target.Finishers, _emptyRegister, _emptyRegister, _finalInst); } } @@ -247,7 +253,7 @@ IList priorities Annotation ann = annIndex < _annotations.Count ? _annotations[annIndex] : _data.Annotations.GetEnd(_fst.Direction); var matchRegisters = (Register[,])registers.Clone(); - ExecuteCommands(matchRegisters, arc.Target.Finishers, new Register(), new Register()); + ExecuteCommands(matchRegisters, arc.Target.Finishers, _emptyRegister, _emptyRegister); if (arc.Target.AcceptInfos.Count > 0) { foreach (AcceptInfo acceptInfo in arc.Target.AcceptInfos) @@ -468,7 +474,7 @@ protected IEnumerable Initialize( startInst.Registers[i, j] = registers[i, j]; } - ExecuteCommands(registers, cmds, new Register(offset, true), new Register()); + ExecuteCommands(registers, cmds, new Register(offset, true), _emptyRegister); for ( ; @@ -486,7 +492,7 @@ protected IEnumerable Initialize( inst.VariableBindings = _varBindings != null ? _varBindings.Clone() : new VariableBindings(); insts.Add(inst); initAnns.Add(annIndex); - RecordCommands(startInst, null, cmds, new Register(offset, true), new Register(), inst); + RecordCommands(startInst, null, cmds, new Register(offset, true), _emptyRegister, inst); } } @@ -537,19 +543,22 @@ protected IEnumerable Advance( TInst ti = CopyInstance(source); ti.AnnotationIndex = i; if (curResults == null) - RecordCommands(source, arc, null, new Register(), new Register(), ti); + RecordCommands(source, arc, null, _emptyRegister, _emptyRegister, ti); HashSet nextOptionalFeatureStructs = null; FeatureStruct annFS = null; - nextOptionalFeatureStructs = new HashSet(FreezableEqualityComparer.Default); - if (optionalFeatureStructs != null) - nextOptionalFeatureStructs.AddRange(optionalFeatureStructs); - if (!_frozenAnnotationFS.ContainsKey(i)) + if (_canonicalizeOptionalAnnotations) { - _frozenAnnotationFS[i] = _annotations[i].FeatureStruct.Clone(); - _frozenAnnotationFS[i].Freeze(); + nextOptionalFeatureStructs = new HashSet(FreezableEqualityComparer.Default); + if (optionalFeatureStructs != null) + nextOptionalFeatureStructs.AddRange(optionalFeatureStructs); + if (!_frozenAnnotationFS.ContainsKey(i)) + { + _frozenAnnotationFS[i] = _annotations[i].FeatureStruct.Clone(); + _frozenAnnotationFS[i].Freeze(); + } + annFS = _frozenAnnotationFS[i]; + nextOptionalFeatureStructs.Add(annFS); } - annFS = _frozenAnnotationFS[i]; - nextOptionalFeatureStructs.Add(annFS); foreach (TInst ni in Advance(ti, varBindings, arc, curResults, true, nextOptionalFeatureStructs)) { yield return ni; @@ -615,7 +624,7 @@ protected IEnumerable Advance( if (varBindings != null) inst.VariableBindings = cloneOutputs ? varBindings.Clone() : varBindings; if (curResults == null) - RecordCommands(inst, null, null, new Register(), new Register(), ni); + RecordCommands(inst, null, null, _emptyRegister, _emptyRegister, ni); yield return ni; cloneOutputs = true; first = false; diff --git a/src/SIL.Machine/FiniteState/LazyNondeterministicFsaTraversalMethod.cs b/src/SIL.Machine/FiniteState/TwoPassNondeterministicFsaTraversalMethod.cs similarity index 74% rename from src/SIL.Machine/FiniteState/LazyNondeterministicFsaTraversalMethod.cs rename to src/SIL.Machine/FiniteState/TwoPassNondeterministicFsaTraversalMethod.cs index c7993aeb..4dd50757 100644 --- a/src/SIL.Machine/FiniteState/LazyNondeterministicFsaTraversalMethod.cs +++ b/src/SIL.Machine/FiniteState/TwoPassNondeterministicFsaTraversalMethod.cs @@ -7,11 +7,11 @@ namespace SIL.Machine.FiniteState { - internal class LazyNondeterministicFsaTraversalMethod + internal class TwoPassNondeterministicFsaTraversalMethod : TraversalMethodBase> where TData : IAnnotatedData { - public LazyNondeterministicFsaTraversalMethod( + public TwoPassNondeterministicFsaTraversalMethod( Fst fst, TData data, VariableBindings varBindings, @@ -19,7 +19,7 @@ public LazyNondeterministicFsaTraversalMethod( bool endAnchor, bool useDefaults ) - : base(fst, data, varBindings, startAnchor, endAnchor, useDefaults) { } + : base(fst, data, varBindings, startAnchor, endAnchor, useDefaults, true) { } public override IEnumerable> Traverse( ref int annIndex, @@ -38,45 +38,29 @@ ISet initAnns var curResults = new List>(); var traversed = new Dictionary< Tuple, int, VariableBindings>, - NondeterministicFsaTraversalInstance> + NondeterministicFsaTraversalInstance + >( + AnonymousEqualityComparer.Create, int, VariableBindings>> ( - AnonymousEqualityComparer.Create, int, VariableBindings>> - ( - KeyEquals, - KeyGetHashCode - ) - ); + KeyEquals, + KeyGetHashCode + ) + ); while (instStack.Count != 0) { NondeterministicFsaTraversalInstance inst = instStack.Pop(); - bool releaseInstance = true; VariableBindings varBindings = null; int i = 0; foreach (Arc arc in inst.State.Arcs) { - bool isInstReusable = true; if (arc.Input.IsEpsilon) { if (!inst.Visited.Contains(arc.Target)) { - NondeterministicFsaTraversalInstance ti; - if (isInstReusable) - { - ti = inst; - } - else - { - ti = CopyInstance(inst); - if (inst.VariableBindings != null && varBindings == null) - varBindings = inst.VariableBindings.Clone(); - ti.VariableBindings = varBindings; - RecordCommands(inst, null, null, new Register(), new Register(), ti); - } - - ti.Visited.Add(arc.Target); + inst.Visited.Add(arc.Target); NondeterministicFsaTraversalInstance newInst = EpsilonAdvance( - ti, + inst, arc, null ); @@ -94,25 +78,18 @@ ISet initAnns instStack.Push(newInst); traversed[key] = newInst; } - if (isInstReusable) - releaseInstance = false; varBindings = null; } } else { if (inst.VariableBindings != null && varBindings == null) - varBindings = isInstReusable ? inst.VariableBindings : inst.VariableBindings.Clone(); + varBindings = inst.VariableBindings; if (CheckInputMatch(arc, inst.AnnotationIndex, varBindings)) { - NondeterministicFsaTraversalInstance ti = isInstReusable - ? inst - : CopyInstance(inst); - RecordCommands(inst, null, null, new Register(), new Register(), ti); - foreach ( NondeterministicFsaTraversalInstance newInst in Advance( - ti, + inst, varBindings, arc, null @@ -135,16 +112,11 @@ NondeterministicFsaTraversalInstance newInst in Advance( traversed[key] = newInst; } } - if (isInstReusable) - releaseInstance = false; varBindings = null; } } i++; } - - if (releaseInstance) - ReleaseInstance(inst); } GetFstResults(curResults);