/// <summary> /// Creates a transducer that replaces escaped argument placeholders with the corresponding arguments. /// </summary> /// <param name="escapedArgs">The list of arguments.</param> /// <param name="transpose">Specifies whether the created transducer should be transposed (useful for backward message computation).</param> /// <returns>The created transducer.</returns> private static StringTransducer GetPlaceholderReplacingTransducer(IList <StringAutomaton> escapedArgs, bool transpose) { var alternatives = new List <StringTransducer>(); for (int i = 0; i < escapedArgs.Count; ++i) { StringTransducer alternative = StringTransducer.ConsumeElement((char)('0' + i)); alternative.AppendInPlace(StringTransducer.Produce(escapedArgs[i]), (byte)(i + 1)); alternatives.Add(alternative); } StringTransducer result = DisallowBraceReplacersTransducer.Clone(); result.AppendInPlace(StringTransducer.ConsumeElement(LeftBraceReplacer)); result.AppendInPlace(StringTransducer.Sum(alternatives)); result.AppendInPlace(StringTransducer.ConsumeElement(RightBraceReplacer)); result = StringTransducer.Repeat(result, minTimes: 0); result.AppendInPlace(DisallowBraceReplacersTransducer); if (transpose) { result.TransposeInPlace(); } return(result); }
/// <summary> /// Creates a transducer that replaces braces surrounding the given argument placeholder /// with <see cref="LeftBraceReplacer"/> and <see cref="RightBraceReplacer"/>. /// </summary> /// <param name="argument">The index of the argument.</param> /// <param name="argumentCount">The total number of the arguments.</param> /// <param name="transpose">Specifies whether the created transducer should be transposed (useful for backward message computation).</param> /// <returns>The created transducer.</returns> private static StringTransducer GetArgumentEscapingTransducer(int argument, int argumentCount, bool transpose) { Debug.Assert(argumentCount >= 1 && argumentCount <= 10, "Up to 10 arguments currently supported."); Debug.Assert(argument >= 0 && argument < argumentCount, "Argument index must be less than the number of arguments."); List <Pair <StringTransducer, StringTransducer> > argumentToEscapingTransducers; if (!ArgumentCountToEscapingTransducers.TryGetValue(argumentCount, out argumentToEscapingTransducers)) { argumentToEscapingTransducers = new List <Pair <StringTransducer, StringTransducer> >(argumentCount); ArgumentCountToEscapingTransducers[argumentCount] = argumentToEscapingTransducers; for (int i = 0; i < argumentCount; ++i) { // Escapes braces in {i} StringTransducer replaceBracesForDigit = StringTransducer.ConsumeElement('{'); replaceBracesForDigit.AppendInPlace(StringTransducer.ProduceElement(LeftBraceReplacer)); replaceBracesForDigit.AppendInPlace(StringTransducer.CopyElement((char)('0' + i))); replaceBracesForDigit.AppendInPlace(StringTransducer.ConsumeElement('}')); replaceBracesForDigit.AppendInPlace(StringTransducer.ProduceElement(RightBraceReplacer)); // Skips any number of placeholders which differ from {i}, with arbitrary intermediate text DiscreteChar noBraces = DiscreteChar.UniformOver('{', '}').Complement(); StringTransducer braceReplacer = StringTransducer.Copy(noBraces); if (argumentCount > 1) { // Skips every placeholder except {i} StringTransducer skipOtherDigits = StringTransducer.CopyElement('{'); skipOtherDigits.AppendInPlace(StringTransducer.CopyElement(AllDigitsExcept(i, argumentCount - 1))); skipOtherDigits.AppendInPlace(StringTransducer.CopyElement('}')); braceReplacer.AppendInPlace(skipOtherDigits); braceReplacer = StringTransducer.Repeat(braceReplacer, minTimes: 0); braceReplacer.AppendInPlace(StringTransducer.Copy(noBraces)); } // Skips placeholders, then escapes {i} and skips placeholders StringTransducer escapeAndSkip = replaceBracesForDigit.Clone(); escapeAndSkip.AppendInPlace(braceReplacer); StringTransducer transducer = braceReplacer.Clone(); transducer.AppendInPlace(escapeAndSkip); // TODO: use Optional() here if {i} can be omitted StringTransducer transducerTranspose = StringTransducer.Transpose(transducer); argumentToEscapingTransducers.Add(Pair.Create(transducer, transducerTranspose)); } } return(transpose ? argumentToEscapingTransducers[argument].Second : argumentToEscapingTransducers[argument].First); }
/// <summary> /// Computes the normalizer via transducers. /// </summary> /// <param name="automaton">The automaton.</param> /// <returns>The logarithm of the normalizer.</returns> private static double GetLogNormalizerByGetValueWithTransducers(StringAutomaton automaton) { var one = StringAutomaton.Constant(1.0); StringTransducer transducer = StringTransducer.Consume(automaton); transducer.AppendInPlace(StringTransducer.Produce(one)); return(transducer.ProjectSource(one).GetLogValue("an arbitrary string")); // Now this will be exactly the normalizer }
/// <summary>EP message to <c>str2</c>.</summary> /// <param name="concat">Incoming message from <c>concat</c>.</param> /// <param name="str1">Incoming message from <c>str1</c>.</param> /// <returns>The outgoing EP message to the <c>str2</c> argument.</returns> /// <remarks> /// <para>The outgoing message is a distribution matching the moments of <c>str2</c> as the random arguments are varied. The formula is <c>proj[p(str2) sum_(concat,str1) p(concat,str1) factor(concat,str1,str2)]/p(str2)</c>.</para> /// </remarks> public static StringDistribution Str2AverageConditional(StringDistribution concat, StringDistribution str1) { Argument.CheckIfNotNull(concat, "concat"); Argument.CheckIfNotNull(str1, "str1"); StringTransducer transducer = StringTransducer.Consume(str1.GetProbabilityFunction()); transducer.AppendInPlace(StringTransducer.Copy()); return(StringDistribution.FromWorkspace(transducer.ProjectSource(concat))); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="StringConcatOp"]/message_doc[@name="Str1AverageConditional(StringDistribution, StringDistribution)"]/*'/> public static StringDistribution Str1AverageConditional(StringDistribution concat, StringDistribution str2) { Argument.CheckIfNotNull(concat, "concat"); Argument.CheckIfNotNull(str2, "str2"); StringTransducer transducer = StringTransducer.Copy(); transducer.AppendInPlace(StringTransducer.Consume(str2.ToAutomaton())); return(StringDistribution.FromWeightFunction(transducer.ProjectSource(concat.ToAutomaton()))); }
/// <include file='FactorDocs.xml' path='factor_docs/message_op_class[@name="StringConcatOp"]/message_doc[@name="Str1AverageConditional(StringDistribution, StringDistribution)"]/*'/> public static StringDistribution Str1AverageConditional(StringDistribution concat, StringDistribution str2) { Argument.CheckIfNotNull(concat, "concat"); Argument.CheckIfNotNull(str2, "str2"); StringTransducer transducer = StringTransducer.Copy(); transducer.AppendInPlace(StringTransducer.Consume(str2.GetWorkspaceOrPoint())); return(StringDistribution.FromWorkspace(transducer.ProjectSource(concat.GetWorkspaceOrPoint()))); }
/// <summary> /// Creates a transducer that replaces argument placeholders with the corresponding arguments. /// </summary> /// <param name="args">The list of arguments.</param> /// <param name="argNames">The list of argument names.</param> /// <param name="forBackwardMessage">Specifies whether the created transducer should be transposed so that the backward message can be computed.</param> /// <param name="withGroups">Specifies whether filled in arguments should be labeled with different groups.</param> /// <returns>The created transducer.</returns> private static StringTransducer GetPlaceholderReplacingTransducer( IList <StringAutomaton> args, IReadOnlyList <string> argNames, bool forBackwardMessage, bool withGroups) { var alternatives = new List <StringTransducer>(); for (int argumentIndex = 0; argumentIndex < args.Count; ++argumentIndex) { StringTransducer alternative; if (!forBackwardMessage) { alternative = StringTransducer.Consume(argNames[argumentIndex]); alternative.AppendInPlace(StringTransducer.Produce(args[argumentIndex]), withGroups ? argumentIndex + 1 : 0); } else { // After transposing 'Produce' will become 'Consume', // and starting from 'Consume' makes projection computations more efficeint because it allows to detect dead braches earlier Debug.Assert(!withGroups, "Groups are never needed for backward message."); alternative = StringTransducer.Produce(args[argumentIndex]); alternative.AppendInPlace(StringTransducer.Consume(argNames[argumentIndex])); } alternatives.Add(alternative); } StringTransducer result = DisallowBracesTransducer.Clone(); result.AppendInPlace(StringTransducer.ConsumeElement('{')); result.AppendInPlace(StringTransducer.Sum(alternatives)); result.AppendInPlace(StringTransducer.ConsumeElement('}')); result = StringTransducer.Repeat(result, minTimes: 0); result.AppendInPlace(DisallowBracesTransducer); if (forBackwardMessage) { result = StringTransducer.Transpose(result); } return(result); }
public void CopySequence2() { const int CopyCount = 10; const int LetterCount = 20; StringTransducer copy = StringTransducer.Copy(); for (int i = 0; i < CopyCount - 1; ++i) { copy.AppendInPlace(StringTransducer.Copy()); } var sequence = new string(Enumerable.Repeat('a', LetterCount).ToArray()); StringAutomaton result = copy.ProjectSource(sequence); var expectedLogValue = Math.Log(StringInferenceTestUtilities.Partitions(LetterCount, CopyCount)); Assert.Equal(expectedLogValue, result.GetLogValue(sequence), 1e-8); }