Пример #1
0
        public void Copy()
        {
            StringTransducer copy = StringTransducer.Copy();

            StringInferenceTestUtilities.TestTransducerValue(copy, "important", "important", 1.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "important", "i", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "important", "imp", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "important", "t", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "important", "mpo", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, string.Empty, string.Empty, 1.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "important", string.Empty, 0.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, string.Empty, "important", 0.0);

            //// Test that projection on Copy() doesn't change the automaton

            StringAutomaton automaton = StringAutomaton.ConstantOn(2.0, "a", "ab", "ac");

            automaton = automaton.Sum(StringAutomaton.ConstantOn(1.0, "a"));
            automaton = automaton.Sum(StringAutomaton.Constant(2.0));
            automaton = automaton.Product(StringAutomaton.Constant(3.0));

            StringAutomaton automatonClone = copy.ProjectSource(automaton);

            Assert.Equal(automaton, automatonClone);
        }
Пример #2
0
        public void CopyElement()
        {
            StringTransducer copy = StringTransducer.CopyElement(DiscreteChar.OneOf('a', 'b'));

            StringInferenceTestUtilities.TestTransducerValue(copy, "a", "a", 1.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "b", "b", 1.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "a", "b", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "b", "a", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, string.Empty, string.Empty, 0.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "bb", "bb", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "bab", "bab", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "bab", "ba", 0.0);

            //// Tests that projection on CopyElement(elements) shrinks the support

            StringAutomaton automaton = StringAutomaton.ConstantOn(2.0, "a", "ab", "ac");

            automaton = automaton.Sum(StringAutomaton.ConstantOn(1.0, "a"));
            automaton = automaton.Sum(StringAutomaton.Constant(2.0));
            automaton = automaton.Product(StringAutomaton.Constant(3.0));

            for (int i = 0; i < 2; ++i)
            {
                StringInferenceTestUtilities.TestValue(automaton, 15, "a");
                StringInferenceTestUtilities.TestValue(automaton, 6.0, "b");
                StringInferenceTestUtilities.TestValue(automaton, i == 0 ? 6.0 : 0.0, string.Empty);
                StringInferenceTestUtilities.TestValue(automaton, i == 0 ? 12.0 : 0.0, "ac", "ab");

                automaton = copy.ProjectSource(automaton);
            }
        }
Пример #3
0
        public void PointMassDetection()
        {
            StringDistribution s1     = StringDistribution.OneOf("hello", "world", "people");
            StringDistribution s2     = StringDistribution.OneOf("greetings", "people", "animals");
            StringDistribution point1 = s1.Product(s2);

            Assert.True(point1.IsPointMass);
            Assert.Equal("people", point1.Point);

            StringDistribution point2 = StringDistribution.OneOf(new Dictionary <string, double> {
                { "a", 3.0 }, { "b", 0.0 }
            });

            Assert.True(point2.IsPointMass);
            Assert.Equal("a", point2.Point);

            StringDistribution point3 = StringDistribution.CaseInvariant("123");

            Assert.True(point3.IsPointMass);
            Assert.Equal("123", point3.Point);

            StringDistribution point4 = StringDistribution.Char('Z');

            Assert.True(point4.IsPointMass);
            Assert.Equal("Z", point4.Point);

            StringDistribution point5 = StringDistribution.OneOf(1.0, StringDistribution.String("!"), 0.0, StringDistribution.Any());

            Assert.True(point5.IsPointMass);
            Assert.Equal("!", point5.Point);

            StringDistribution point6 = StringDistribution.Repeat('@', minTimes: 3, maxTimes: 3);

            Assert.True(point6.IsPointMass);
            Assert.Equal("@@@", point6.Point);

            StringDistribution point7 = StringDistribution.String("hello").Append(StringDistribution.String(" world"));

            Assert.True(point7.IsPointMass);
            Assert.Equal("hello world", point7.Point);

            string          point           = string.Empty;
            StringAutomaton point8Automaton = StringAutomaton.Empty();

            for (int i = 0; i < 22; ++i)
            {
                const string PointElement = "a";
                point8Automaton.AppendInPlace(StringAutomaton.ConstantOn(1.0, PointElement, PointElement));
                point += PointElement;
            }

            StringDistribution point8 = StringDistribution.FromWeightFunction(point8Automaton);

            Assert.True(point8.IsPointMass);
            Assert.Equal(point, point8.Point);
        }
Пример #4
0
        /// <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);
        }
Пример #5
0
 /// <summary>
 /// Tests if a transducer projects each of given strings to a zero function.
 /// </summary>
 /// <param name="transducer">The transducer.</param>
 /// <param name="strings">The strings to test.</param>
 public static void TestIfTransducerRejects(StringTransducer transducer, params string[] strings)
 {
     foreach (string str in strings)
     {
         var res = transducer.ProjectSource(StringAutomaton.ConstantOn(1.0, str));
         Assert.True(res.IsZero());
         var res2 = transducer.ProjectSource(str);
         Assert.True(res2.IsZero());
     }
 }
Пример #6
0
        public void Repeat4()
        {
            StringAutomaton automaton = StringAutomaton.ConstantOn(2.0, "aa");

            automaton = StringAutomaton.Repeat(automaton, minTimes: 0);

            StringInferenceTestUtilities.TestValue(automaton, 0.0, "a", "aaa");
            StringInferenceTestUtilities.TestValue(automaton, 1.0, string.Empty);
            StringInferenceTestUtilities.TestValue(automaton, 2.0, "aa");
            StringInferenceTestUtilities.TestValue(automaton, 4.0, "aaaa");
        }
Пример #7
0
        public void Repeat1()
        {
            StringAutomaton  automaton = StringAutomaton.ConstantOn(2.0, "a");
            StringTransducer repeat    = StringTransducer.Repeat(StringTransducer.Consume(automaton), 1, 3);

            StringInferenceTestUtilities.TestTransducerValue(repeat, "a", string.Empty, 2.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, "aa", string.Empty, 4.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, "aaa", string.Empty, 8.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, "aaaa", string.Empty, 0.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, string.Empty, string.Empty, 0.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, string.Empty, "aaa", 0.0);
        }
Пример #8
0
        public void Repeat2()
        {
            StringAutomaton  automaton = StringAutomaton.ConstantOn(2.0, "a", string.Empty);
            StringTransducer repeat    = StringTransducer.Repeat(StringTransducer.Copy(automaton), 1, 2);

            StringInferenceTestUtilities.TestTransducerValue(repeat, "a", "a", 10.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, "aa", "aa", 4.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, string.Empty, string.Empty, 6.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, "aaa", "aaa", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, "aa", "a", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, string.Empty, "a", 0.0);
        }
Пример #9
0
        public void Repeat1()
        {
            StringAutomaton automaton = StringAutomaton.ConstantOn(1.0, "abc");

            automaton.AppendInPlace(StringAutomaton.Constant(2.0, DiscreteChar.Upper()));
            StringInferenceTestUtilities.TestValue(automaton, 0.0, string.Empty, "ab", "abcab", "XYZ");
            StringInferenceTestUtilities.TestValue(automaton, 2.0, "abc", "abcX", "abcXXYZ");

            StringAutomaton loopyAutomaton = StringAutomaton.Repeat(automaton);

            StringInferenceTestUtilities.TestValue(loopyAutomaton, 0.0, string.Empty, "ab", "abcab", "XYZ");
            StringInferenceTestUtilities.TestValue(loopyAutomaton, 2.0, "abc", "abcA");
            StringInferenceTestUtilities.TestValue(loopyAutomaton, 4.0, "abcabc", "abcabcX", "abcABCabc", "abcXabcYZ");
            StringInferenceTestUtilities.TestValue(loopyAutomaton, 8.0, "abcabcabc", "abcXabcYabcZZ");
        }
Пример #10
0
        public void Repeat3()
        {
            StringAutomaton  automaton = StringAutomaton.ConstantOn(2.0, "a", "aa");
            StringTransducer repeat    = StringTransducer.Repeat(StringTransducer.Replace(automaton, automaton), minTimes: 0);

            StringInferenceTestUtilities.TestTransducerValue(repeat, string.Empty, string.Empty, 1.0); // TODO: it's not clear from the definition that this should hold
            StringInferenceTestUtilities.TestTransducerValue(repeat, "a", "a", 4.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, "a", "aa", 4.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, "aa", "aa", 20.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, "aaa", "aa", 32.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, "aa", "aaa", 32.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, "a", "aaa", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, string.Empty, "a", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(repeat, "b", "b", 0.0);
        }
Пример #11
0
        /// <summary>
        /// Tests if a transducer has the desired value on a given pair of strings.
        /// </summary>
        /// <param name="transducer">The transducer.</param>
        /// <param name="string1">The first string.</param>
        /// <param name="string2">The second string.</param>
        /// <param name="trueValue">The desired value of the transducer on the strings.</param>
        public static void TestTransducerValue(
            StringTransducer transducer, string string1, string string2, double trueValue)
        {
            // Test ProjectSource(sequence)
            var result = transducer.ProjectSource(string1);

            TestValue(result, trueValue, string2);

            // Test ProjectSource(func)
            TestTransducerProjection(transducer, StringAutomaton.ConstantOn(1.0, string1), string2, trueValue);

            // Test GetValue()
            double value = transducer.GetValue(string1, string2);

            Assert.Equal(trueValue, value, LogValueEps);
        }
Пример #12
0
        public void CopyAutomaton()
        {
            StringAutomaton automaton = StringAutomaton.ConstantOn(1.0, "prefix1", "prefix2");

            automaton.AppendInPlace(StringAutomaton.Constant(1.0, DiscreteChar.Lower()));
            automaton.AppendInPlace(StringAutomaton.Constant(1.0, DiscreteChar.Upper()));
            automaton.AppendInPlace("!");

            StringTransducer copy = StringTransducer.Copy(automaton);

            StringInferenceTestUtilities.TestTransducerValue(copy, "prefix1!", "prefix1!", 1.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "prefix2!", "prefix2!", 1.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "prefix1lower!", "prefix1lower!", 1.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "prefix2UPPER!", "prefix2UPPER!", 1.0);
            StringInferenceTestUtilities.TestTransducerValue(copy, "prefix1lowerUPPER!", "prefix1lowerUPPER!", 1.0);
            StringInferenceTestUtilities.TestIfTransducerRejects(copy, "prefix1lower", "prefix2UPPER", "!", "prefix1lowerUPPER");

            StringInferenceTestUtilities.TestTransducerProjection(copy, automaton, "prefix1!", 1.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, automaton, "prefix2!", 1.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, automaton, "prefix1lower!", 1.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, automaton, "prefix2UPPER!", 1.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, automaton, "prefix1lowerUPPER!", 1.0);

            StringAutomaton subsetAutomaton = StringAutomaton.ConstantOn(2.0, "prefix1");

            subsetAutomaton.AppendInPlace(StringAutomaton.ConstantOn(3.0, "lll", "mmm"));
            subsetAutomaton.AppendInPlace(StringAutomaton.ConstantOn(1.5, "!", "U!"));
            StringInferenceTestUtilities.TestTransducerProjection(copy, subsetAutomaton, "prefix1lll!", 9.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, subsetAutomaton, "prefix1mmmU!", 9.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, subsetAutomaton, "prefix1!", 0.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, subsetAutomaton, "prefix2lower!", 0.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, subsetAutomaton, "prefix2U!", 0.0);

            StringAutomaton supersetAutomaton = StringAutomaton.ConstantOn(1.5, "pr");

            supersetAutomaton.AppendInPlace(StringAutomaton.Constant(2.0));
            StringInferenceTestUtilities.TestTransducerProjection(copy, supersetAutomaton, "prefix1!", 3.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, supersetAutomaton, "prefix2!", 3.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, supersetAutomaton, "prefix1lower!", 3.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, supersetAutomaton, "prefix2UPPER!", 3.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, supersetAutomaton, "prefix1lowerUPPER!", 3.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, supersetAutomaton, "prefix11!", 0.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, supersetAutomaton, "prefix1lowerUPPERlower!", 0.0);
            StringInferenceTestUtilities.TestTransducerProjection(copy, supersetAutomaton, "prrrrr!", 0.0);
        }
Пример #13
0
        public void Product3()
        {
            StringAutomaton weights1 = StringAutomaton.Sum(
                StringAutomaton.ConstantOn(1.0, "a"),
                StringAutomaton.ConstantOn(2.0, "b"),
                StringAutomaton.ConstantOn(4.0, "c"));
            StringAutomaton weights2 = StringAutomaton.Sum(
                StringAutomaton.ConstantOn(2.0, "a"),
                StringAutomaton.ConstantOn(5.0, "b"),
                StringAutomaton.ConstantOn(7.0, "c"));
            StringDistribution dist1   = StringDistribution.FromWeightFunction(weights1);
            StringDistribution dist2   = StringDistribution.FromWeightFunction(weights2);
            StringDistribution product = dist1.Product(dist2);

            StringInferenceTestUtilities.TestProbability(product, 2.0 / 40.0, "a");
            StringInferenceTestUtilities.TestProbability(product, 10.0 / 40.0, "b");
            StringInferenceTestUtilities.TestProbability(product, 28.0 / 40.0, "c");
        }
Пример #14
0
        public void CopySequence1()
        {
            StringTransducer copySequence = StringTransducer.Copy("important");

            StringInferenceTestUtilities.TestTransducerValue(copySequence, "important", "important", 1.0);
            StringInferenceTestUtilities.TestTransducerValue(copySequence, "important", "imp", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(copySequence, "important", "ortant", 0.0);
            StringInferenceTestUtilities.TestTransducerValue(copySequence, "important", string.Empty, 0.0);
            StringInferenceTestUtilities.TestTransducerProjection(copySequence, StringAutomaton.ConstantOn(3.0, "important"), "important", 3.0);
            StringInferenceTestUtilities.TestTransducerProjection(copySequence, StringAutomaton.ConstantOn(1.5, "important", "not important"), "important", 1.5);
            StringInferenceTestUtilities.TestTransducerProjection(copySequence, StringAutomaton.Constant(2.0), "important", 2.0);
            StringInferenceTestUtilities.TestTransducerProjection(
                copySequence,
                StringAutomaton.Constant(2.0).Append(StringAutomaton.ConstantOn(3.0, "nt")),
                "important",
                6.0);
            StringInferenceTestUtilities.TestIfTransducerRejects(copySequence, string.Empty, "nothing is important", "importance", "imp", "ortant", "a");
        }
Пример #15
0
        public void Repeat3()
        {
            StringAutomaton automaton = StringAutomaton.ConstantOn(1.0, "a");

            automaton.AppendInPlace(StringAutomaton.ConstantOn(1.0, "a"));
            automaton = StringAutomaton.Sum(automaton, StringAutomaton.ConstantOn(1.0, "a"));
            StringInferenceTestUtilities.TestValue(automaton, 0.0, string.Empty, "aaa", "ab", "X");
            StringInferenceTestUtilities.TestValue(automaton, 1.0, "a", "aa");

            // Yep, it turns out you can compute the Fibonacci sequence with an automaton
            StringAutomaton loopyAutomaton = StringAutomaton.Repeat(automaton);

            StringInferenceTestUtilities.TestValue(loopyAutomaton, 0.0, string.Empty, "ab");
            StringInferenceTestUtilities.TestValue(loopyAutomaton, 1.0, "a");
            StringInferenceTestUtilities.TestValue(loopyAutomaton, 2.0, "aa");
            StringInferenceTestUtilities.TestValue(loopyAutomaton, 3.0, "aaa");
            StringInferenceTestUtilities.TestValue(loopyAutomaton, 5.0, "aaaa");
            StringInferenceTestUtilities.TestValue(loopyAutomaton, 8.0, "aaaaa");
        }
Пример #16
0
        /// <summary>
        /// An implementation of <see cref="StrAverageConditional(StringDistribution, IList{StringDistribution}, IReadOnlyList{string})"/>
        /// specialized for some cases for performance reasons.
        /// </summary>
        /// <param name="format">The message from <c>format</c>.</param>
        /// <param name="allowedArgs">The message from <c>args</c>, truncated to allowed values and converted to automata.</param>
        /// <param name="argNames">The names of the arguments.</param>
        /// <param name="withGroups">Whether the result should mark different arguments with groups.</param>
        /// <returns>
        /// Result distribution if there is an optimized implementation available for the provided parameters.
        /// <see langword="null"/> otherwise.
        /// </returns>
        /// <remarks>
        /// Supports the case of point mass <paramref name="format"/>.
        /// </remarks>
        private static StringDistribution TryOptimizedStrAverageConditionalImpl(
            StringDistribution format, IList <StringAutomaton> allowedArgs, IReadOnlyList <string> argNames, bool withGroups)
        {
            if (!format.IsPointMass)
            {
                // Fall back to the general case
                return(null);
            }

            // Check braces for correctness & replace placeholders with arguments simultaneously
            var result = StringAutomaton.Builder.ConstantOn(Weight.One, string.Empty);

            bool[] argumentSeen = new bool[allowedArgs.Count];
            int    openingBraceIndex = format.Point.IndexOf("{", StringComparison.Ordinal), closingBraceIndex = -1;

            while (openingBraceIndex != -1)
            {
                // Add the part of the format before the placeholder
                result.Append(StringAutomaton.ConstantOn(1.0, format.Point.Substring(closingBraceIndex + 1, openingBraceIndex - closingBraceIndex - 1)));

                // Find next opening and closing braces
                closingBraceIndex = format.Point.IndexOf("}", openingBraceIndex + 1, StringComparison.Ordinal);
                int nextOpeningBraceIndex = format.Point.IndexOf("{", openingBraceIndex + 1, StringComparison.Ordinal);

                // Opening brace must be followed by a closing brace
                if (closingBraceIndex == -1 || (nextOpeningBraceIndex != -1 && nextOpeningBraceIndex < closingBraceIndex))
                {
                    return(StringDistribution.Zero());
                }

                string argumentName  = format.Point.Substring(openingBraceIndex + 1, closingBraceIndex - openingBraceIndex - 1);
                int    argumentIndex = argNames.IndexOf(argumentName);

                // Unknown or previously seen argument found
                if (argumentIndex == -1 || argumentSeen[argumentIndex])
                {
                    return(StringDistribution.Zero());
                }

                // Replace the placeholder by the argument
                result.Append(allowedArgs[argumentIndex], withGroups ? argumentIndex + 1 : 0);

                // Mark the argument as 'seen'
                argumentSeen[argumentIndex] = true;

                openingBraceIndex = nextOpeningBraceIndex;
            }

            // There should be no closing braces after the last opening brace
            if (format.Point.IndexOf('}', closingBraceIndex + 1) != -1)
            {
                return(StringDistribution.Zero());
            }

            if (RequirePlaceholderForEveryArgument && argumentSeen.Any(seen => !seen))
            {
                // Some argument wasn't present although it was required
                return(StringDistribution.Zero());
            }

            // Append the part of the format after the last placeholder
            result.Append(StringAutomaton.ConstantOn(1.0, format.Point.Substring(closingBraceIndex + 1, format.Point.Length - closingBraceIndex - 1)));

            return(StringDistribution.FromWorkspace(result.GetAutomaton()));
        }
Пример #17
0
        /// <summary>
        /// An implementation of <see cref="FormatAverageConditional(StringDistribution, IList{StringDistribution}, IReadOnlyList{string})"/>
        /// specialized for some cases for performance reasons.
        /// </summary>
        /// <param name="str">The message from <c>str</c>.</param>
        /// <param name="allowedArgs">The message from <c>args</c>, truncated to allowed values and converted to automata.</param>
        /// <param name="argNames">The names of the arguments.</param>
        /// <param name="resultDist">The computed result.</param>
        /// <returns>
        /// <see langword="true"/> if there is an optimized implementation available for the provided parameters,
        /// and <paramref name="resultDist"/> has been computed using it.
        /// <see langword="false"/> otherwise.
        /// </returns>
        /// <remarks>
        /// Supports the case of point mass <paramref name="str"/> and <paramref name="allowedArgs"/>,
        /// where each of the arguments is present in <paramref name="str"/> at most once and the occurrences
        /// are non-overlapping.
        /// </remarks>
        private static bool TryOptimizedFormatAverageConditionalImpl(
            StringDistribution str, IList <StringAutomaton> allowedArgs, IReadOnlyList <string> argNames, out StringDistribution resultDist)
        {
            resultDist = null;

            string[] allowedArgPoints = Util.ArrayInit(allowedArgs.Count, i => allowedArgs[i].TryComputePoint());
            if (!str.IsPointMass || !allowedArgPoints.All(argPoint => argPoint != null && SubstringOccurrencesCount(str.Point, argPoint) <= 1))
            {
                // Fall back to the general case
                return(false);
            }

            // Obtain arguments present in 'str' (ordered by position)
            var argPositions =
                allowedArgPoints.Select((arg, argIndex) => Tuple.Create(argIndex, str.Point.IndexOf(arg, StringComparison.Ordinal)))
                .Where(t => t.Item2 != -1)
                .OrderBy(t => t.Item2)
                .ToList();

            if (RequirePlaceholderForEveryArgument && argPositions.Count != allowedArgs.Count)
            {
                // Some argument is not in 'str'
                resultDist = StringDistribution.Zero();
                return(true);
            }

            StringAutomaton result            = StringAutomaton.ConstantOn(1.0, string.Empty);
            int             curArgumentIndex  = -1;
            int             curArgumentPos    = -1;
            int             curArgumentLength = 1;

            for (int i = 0; i < argPositions.Count; ++i)
            {
                int prevArgumentIndex  = curArgumentIndex;
                int prevArgumentPos    = curArgumentPos;
                int prevArgumentLength = curArgumentLength;
                curArgumentIndex  = argPositions[i].Item1;
                curArgumentPos    = argPositions[i].Item2;
                curArgumentLength = allowedArgPoints[curArgumentIndex].Length;

                if (prevArgumentIndex != -1 && curArgumentPos < prevArgumentPos + prevArgumentLength)
                {
                    // It's easier to fall back to the general case in case of overlapping arguments
                    return(false);
                }

                // Append the contents of 'str' preceeding the current argument
                result.AppendInPlace(str.Point.Substring(prevArgumentPos + prevArgumentLength, curArgumentPos - prevArgumentPos - prevArgumentLength));

                // The format may have included either the text ot the placeholder
                string argName = "{" + argNames[curArgumentIndex] + "}";
                if (RequirePlaceholderForEveryArgument)
                {
                    result.AppendInPlace(StringAutomaton.ConstantOn(1.0, argName));
                }
                else
                {
                    result.AppendInPlace(StringAutomaton.ConstantOn(1.0, argName, allowedArgPoints[curArgumentIndex]));
                }
            }

            // Append the rest of 'str'
            result.AppendInPlace(str.Point.Substring(curArgumentPos + curArgumentLength, str.Point.Length - curArgumentPos - curArgumentLength));

            resultDist = StringDistribution.FromWorkspace(result);
            return(true);
        }