/// <summary> /// Creates an automaton for validating the correctness of argument placeholders for a given argument. /// </summary> /// <param name="argToValidateIndex">The index of the argument to validate.</param> /// <param name="argNames">The names of all arguments.</param> /// <returns>The created automaton.</returns> private static StringAutomaton GetArgumentValidatingAutomaton(int argToValidateIndex, IReadOnlyList <string> argNames) { Debug.Assert( argNames != null && argNames.All(name => !string.IsNullOrEmpty(name)), "A valid array of argument names must be provided."); Debug.Assert( argToValidateIndex >= 0 && argToValidateIndex < argNames.Count, "The provided argument index must be a valid index in the argument name array."); string argListKey = ArgumentListToDictionaryKey(argToValidateIndex, argNames); StringAutomaton result; if (ArgsToValidatingAutomaton.TryGetValue(argListKey, out result)) { return(result); } // Accepts placeholder for the current argument StringAutomaton checkBracesForCurrentArg = StringAutomaton.ConstantOn(1.0, "{" + argNames[argToValidateIndex] + "}"); StringAutomaton checkBracesForOtherArgs = DisallowBracesAutomaton.Clone(); if (argNames.Count > 1) { // Skips placeholders for every argument except the current one StringAutomaton skipOtherArgs = StringAutomaton.ConstantOnElement(1.0, '{'); skipOtherArgs.AppendInPlace(StringAutomaton.ConstantOn(1.0, argNames.Where((arg, index) => index != argToValidateIndex))); skipOtherArgs.AppendInPlace(StringAutomaton.ConstantOnElement(1.0, '}')); // Accepts placeholders for arguments other than current, with arbitrary intermediate text checkBracesForOtherArgs.AppendInPlace(skipOtherArgs); checkBracesForOtherArgs = StringAutomaton.Repeat(checkBracesForOtherArgs, minTimes: 0); checkBracesForOtherArgs.AppendInPlace(DisallowBracesAutomaton); } // Checks the placeholder for the current argument, then skips placeholders for other arguments StringAutomaton validateArgumentThenOtherArguments = checkBracesForCurrentArg.Clone(); validateArgumentThenOtherArguments.AppendInPlace(checkBracesForOtherArgs); if (!RequirePlaceholderForEveryArgument) { // Make this block optional validateArgumentThenOtherArguments = StringAutomaton.Sum( validateArgumentThenOtherArguments, StringAutomaton.ConstantOn(1.0, string.Empty)); } // Accepts placeholders for arguments other then current, then for the current argument, then again other placeholders result = checkBracesForOtherArgs.Clone(); result.AppendInPlace(validateArgumentThenOtherArguments); result.TryDeterminize(); ArgsToValidatingAutomaton[argListKey] = result; return(result); }
public void NonNormalizableLoop3() { StringAutomaton automaton = StringAutomaton.Zero(); automaton.Start.AddTransition('a', Weight.FromValue(2.0), automaton.Start); automaton.Start.EndWeight = Weight.FromValue(5.0); StringAutomaton copyOfAutomaton = automaton.Clone(); Assert.Throws <InvalidOperationException>(() => automaton.NormalizeValues()); Assert.False(copyOfAutomaton.TryNormalizeValues()); ////Assert.Equal(f, copyOfF); // TODO: fix equality first }
/// <summary> /// Tests if the weights of all outgoing transitions sum to one for each state of a given automaton. /// </summary> /// <param name="automaton">The automaton.</param> private static void AssertStochastic(StringAutomaton automaton) { StringAutomaton automatonClone = automaton.Clone(); automatonClone.RemoveDeadStates(); for (int i = 0; i < automatonClone.States.Count; ++i) { Weight weightSum = automatonClone.States[i].EndWeight; for (int j = 0; j < automatonClone.States[i].Transitions.Count; ++j) { weightSum += automatonClone.States[i].Transitions[j].Weight; } Assert.Equal(0.0, weightSum.LogValue, 1e-6); } }
public void NonNormalizableLoop2() { StringAutomaton automaton = StringAutomaton.Zero(); var endState = automaton.Start.AddTransition('a', Weight.FromValue(2.0)); endState.EndWeight = Weight.FromValue(5.0); endState.AddTransition('b', Weight.FromValue(0.1), automaton.Start); endState.AddTransition('c', Weight.FromValue(0.05), automaton.Start); endState.AddSelfTransition('!', Weight.FromValue(0.75)); StringAutomaton copyOfAutomaton = automaton.Clone(); Assert.Throws <InvalidOperationException>(() => copyOfAutomaton.NormalizeValues()); Assert.False(copyOfAutomaton.TryNormalizeValues()); ////Assert.Equal(f, copyOfF); // TODO: fix equality first }
public void NonNormalizableLoop4() { StringAutomaton automaton = StringAutomaton.Zero(); automaton.Start.AddSelfTransition('a', Weight.FromValue(0.1)); var branch1 = automaton.Start.AddTransition('a', Weight.FromValue(2.0)); branch1.AddSelfTransition('a', Weight.FromValue(2.0)); branch1.SetEndWeight(Weight.One); var branch2 = automaton.Start.AddTransition('a', Weight.FromValue(2.0)); branch2.SetEndWeight(Weight.One); StringAutomaton copyOfAutomaton = automaton.Clone(); Assert.Throws <InvalidOperationException>(() => automaton.NormalizeValues()); Assert.False(copyOfAutomaton.TryNormalizeValues()); ////Assert.Equal(f, copyOfF); // TODO: fix equality first }
public void NormalizeValuesWithNonTrivialLoop() { StringAutomaton automaton = StringAutomaton.Zero(); var endState = automaton.Start.AddTransition('a', Weight.FromValue(2.0)); endState.EndWeight = Weight.FromValue(5.0); endState.AddTransition('b', Weight.FromValue(0.1), automaton.Start); endState.AddTransition('c', Weight.FromValue(0.05), automaton.Start); endState.AddSelfTransition('!', Weight.FromValue(0.5)); var normalizedAutomaton = automaton.Clone(); double logNormalizer = normalizedAutomaton.NormalizeValues(); Assert.Equal(Math.Log(50.0), logNormalizer, 1e-6); Assert.Equal(Math.Log(50.0), GetLogNormalizerByGetValue(automaton), 1e-6); Assert.Equal(Math.Log(50.0), GetLogNormalizerByGetValueWithTransducers(automaton), 1e-6); AssertStochastic(normalizedAutomaton); foreach (var str in new[] { "a!!", "abaca", "a!ba!!ca!!!!" }) { Assert.False(double.IsNegativeInfinity(automaton.GetLogValue(str))); Assert.Equal(automaton.GetLogValue(str), normalizedAutomaton.GetLogValue(str) + logNormalizer, 1e-6); } }