/// <inheritdoc/>
        public void TraceInconstructibleTheorem(RankedTheorem rankedTheorem, AnalyticException exception)
        {
            // If logging is allowed, log it with the reference to more detail in the file
            if (_settings.LogFailures)
            {
                Log.Warning("Problem while drawing a ranked theorem. See {path} for more detail.", _settings.FailureFilePath);
            }

            // Open the stream writer for the file
            using var streamWriter = new StreamWriter(_settings.FailureFilePath, append: true);

            // Prepare the formatter
            var rankedTheoremFormatter = new OutputFormatter(rankedTheorem.Configuration.AllObjects);

            // Write initial info
            streamWriter.WriteLine($"Problem while constructing the theorem:\n");

            // Write the configuration
            streamWriter.WriteLine(rankedTheoremFormatter.FormatConfiguration(rankedTheorem.Configuration));

            // Write the theorem
            streamWriter.WriteLine($"\n{rankedTheoremFormatter.FormatTheorem(rankedTheorem.Theorem)}");

            // Write the exception
            streamWriter.WriteLine($"\nException: {exception}");

            // Separator
            streamWriter.WriteLine("--------------------------------------------------\n");
        }
        /// <summary>
        /// Converts given theorems to a string, optionally with their proofs.
        /// </summary>
        /// <param name="formatter">The formatter of the configuration where the theorems hold.</param>
        /// <param name="analyzerOutput">The analyzer output to be converted to a string.</param>
        /// <param name="writeProofs">Indicates whether we should format theorem proofs.</param>
        /// <returns>The string representing the analyzer output.</returns>
        private static string AnalyzerOutputToString(OutputFormatter formatter, GeneratedProblemAnalyzerOutputBase analyzerOutput, bool writeProofs)
        {
            // Prepare the result
            var result = "";

            // Prepare a local theorem index
            var localTheoremIndex = 1;

            #region Theorem proofs

            // If we should write proofs and there are any
            if (writeProofs)
            {
                // Get them
                var proofs = ((GeneratedProblemAnalyzerOutputWithProofs)analyzerOutput).TheoremProofs;

                // If there are any
                if (proofs.Any())
                {
                    // Add the header
                    result += $"\n\nProved theorems:\n\n";

                    // Append theorem proofs by taking them
                    result += proofs
                              // Sorting by the statement of the proved theorem
                              .OrderBy(pair => formatter.FormatTheorem(pair.Key))
                              // Write proof for each with a local id
                              .Select(pair => $" {localTheoremIndex}. {formatter.FormatTheoremProof(pair.Value, tag: $"{localTheoremIndex++}.")}")
        /// <summary>
        /// Converts given ranked theorems to a string.
        /// </summary>
        /// <param name="rankedTheorems">The ranked theorems to be converted.</param>
        /// <returns>The string representing the ranked theorems.</returns>
        private static string RankedTheoremsToString(IEnumerable <RankedTheorem> rankedTheorems)
        // Go through the theorems
        => rankedTheorems.Select((rankedTheorem, index) =>
        {
            // Prepare the formatter of the configuration
            var formatter = new OutputFormatter(rankedTheorem.Configuration.AllObjects);

            // Prepare the header
            var header = $"Theorem {index + 1}";

            // Prepare the result where the header is framed in dashes
            var result = $"{new string('-', header.Length)}\n{header}\n{new string('-', header.Length)}\n\n";

            // Add the configuration
            result += formatter.FormatConfiguration(rankedTheorem.Configuration);

            // Add the theorem
            result += $"\n\n{formatter.FormatTheorem(rankedTheorem.Theorem)}" +
                      // Add the total ranking
                      $" - total ranking {rankedTheorem.Ranking.TotalRanking.ToStringWithDecimalDot()}\n\n";

            // Add the ranking
            result += TheoremRankingToString(rankedTheorem.Ranking);

            // Finally return the result
            return(result);
        })
        // Make each on a separate line
        .ToJoinedString("\n\n");
Example #4
0
        /// <inheritdoc/>
        public void MarkInvalidInferrence(Configuration configuration, Theorem invalidConclusion, InferenceRule inferenceRule, Theorem[] negativeAssumptions, Theorem[] possitiveAssumptions)
        {
            // Prepare the file path for the rule with the name of the rule
            var filePath = Path.Combine(_settings.InvalidInferenceFolder, $"{inferenceRule.ToString().Replace(Path.DirectorySeparatorChar, '_')}.{_settings.FileExtension}");

            // If adding this inference would reach the maximal number of written inferences, we're done
            if (_invalidInferencesPerFile.GetValueOrDefault(filePath) + 1 > _settings.MaximalNumberOfInvalidInferencesPerFile)
            {
                return;
            }

            // Otherwise create or get the file in the invalid inference folder
            using var writer = new StreamWriter(filePath, append: true);

            // Prepare the formatter of the configuration
            var formatter = new OutputFormatter(configuration.AllObjects);

            // Write the configuration
            writer.WriteLine(formatter.FormatConfiguration(configuration));

            // An empty line
            writer.WriteLine();

            // Write the incorrect theorem
            writer.WriteLine($" {formatter.FormatTheorem(invalidConclusion)}");

            // Write its assumptions
            possitiveAssumptions.ForEach(assumption => writer.WriteLine($"  - {formatter.FormatTheorem(assumption)}"));

            // As well as negative ones
            negativeAssumptions.ForEach(assumption => writer.WriteLine($"  ! {formatter.FormatTheorem(assumption)}"));

            // Separator
            writer.WriteLine("--------------------------------------------------\n");

            // Mark that we've used this inference
            _invalidInferencesPerFile[filePath] = _invalidInferencesPerFile.GetValueOrDefault(filePath) + 1;
        }
        /// <summary>
        /// Converts an original <see cref="RankedTheorem"/> object into an intermediate object to be serialized.
        /// </summary>
        /// <param name="rankedTheorem">The object to be converted.</param>
        /// <returns>The result of the conversion.</returns>
        public static RankedTheoremIntermediate Convert(RankedTheorem rankedTheorem)
        {
            // Prepare the formatter for the configuration
            var formatter = new OutputFormatter(rankedTheorem.Configuration.AllObjects);

            // Format the configuration
            var configurationString = formatter.FormatConfiguration(rankedTheorem.Configuration)
                                      // Replace all curly braces that are not supported by the parser (and don't matter after all)
                                      .Replace("{", "").Replace("}", "");

            // Format the theorem
            var theoremString = formatter.FormatTheorem(rankedTheorem.Theorem)
                                // Replace all curly braces that are not supported by the parser (and don't matter after all)
                                .Replace("{", "").Replace("}", "");

            // Return the final object
            return(new RankedTheoremIntermediate(theoremString, rankedTheorem.Ranking, configurationString));
        }
Example #6
0
        /// <summary>
        /// The entry method of the application.
        /// </summary>
        /// <param name="arguments">The three arguments:
        /// <list type="number">
        /// <item>Path to the inference rule folder.</item>
        /// <item>The extension of the inference rule files.</item>
        /// <item>Path to the object introduction rule file.</item>
        /// </list>
        /// </param>
        private static async Task Main(string[] arguments)
        {
            #region Kernel preparation

            // Prepare the settings for the inference rule provider
            var inferenceRuleProviderSettings = new InferenceRuleProviderSettings(ruleFolderPath: arguments[0], fileExtension: arguments[1]);

            // Prepare the settings for the object introduction rule provider
            var objectIntroductionRuleProviderSettings = new ObjectIntroductionRuleProviderSettings(filePath: arguments[2]);

            // Prepare the kernel
            var kernel = Infrastructure.NinjectUtilities.CreateKernel()
                         // That constructors configurations
                         .AddConstructor()
                         // That can find theorems
                         .AddTheoremFinder(new TheoremFindingSettings
                                           (
                                               // Look for theorems of any type
                                               soughtTheoremTypes: Enum.GetValues(typeof(TheoremType)).Cast <TheoremType>()
                                               // Except for the EqualObjects that don't have a finder
                                               .Except(TheoremType.EqualObjects.ToEnumerable())
                                               // Enumerate
                                               .ToArray(),

                                               // Exclude in-picture tangencies
                                               new TangentCirclesTheoremFinderSettings(excludeTangencyInsidePicture: true),
                                               new LineTangentToCircleTheoremFinderSettings(excludeTangencyInsidePicture: true)
                                           ))
                         // That can prove theorems
                         .AddTheoremProver(new TheoremProvingSettings
                                           (
                                               // Use the provider to find the inference rules
                                               new InferenceRuleManagerData(await new InferenceRuleProvider.InferenceRuleProvider(inferenceRuleProviderSettings).GetInferenceRulesAsync()),

                                               // Use the provider to find the object introduction rules
                                               new ObjectIntroducerData(await new ObjectIntroductionRuleProvider.ObjectIntroductionRuleProvider(objectIntroductionRuleProviderSettings).GetObjectIntroductionRulesAsync()),

                                               // Setup the prover
                                               new TheoremProverSettings
                                               (
                                                   // We will be strict and don't assume simplifiable theorems
                                                   assumeThatSimplifiableTheoremsAreTrue: false,

                                                   // We will find trivial theorems for all objects
                                                   findTrivialTheoremsOnlyForLastObject: false
                                               )
                                           ));

            #endregion

            #region Tests

            // Take the tests
            new[]
            {
                PerpendicularBisectorsAreConcurrent(),
                IncenterAndTangentLine(),
                Midpoints(),
                Parallelogram(),
                HiddenExcenter(),
                HiddenMidpoint(),
                LineTangentToCircle(),
                ConcurrencyViaObjectIntroduction(),
                SimpleLineSegments()
            }
            // Perform each
            .ForEach(configuration =>
            {
                #region Finding theorems

                // Prepare 3 pictures in which the configuration is drawn
                var pictures = kernel.Get <IGeometryConstructor>().ConstructWithUniformLayout(configuration, numberOfPictures: 3).pictures;

                // Prepare a contextual picture
                var contextualPicture = new ContextualPicture(pictures);

                // Find all theorems
                var theorems = kernel.Get <ITheoremFinder>().FindAllTheorems(contextualPicture);

                #endregion

                #region Writing theorems

                // Prepare the formatter of all the output
                var formatter = new OutputFormatter(configuration.AllObjects);

                // Prepare a local function that converts given theorems to a string
                string TheoremString(IEnumerable <Theorem> theorems) =>
                // If there are no theorems
                theorems.IsEmpty()
                // Then return an indication of it
                        ? "nothing"
                // Otherwise format each theorem
                        : theorems.Select(formatter.FormatTheorem)
                // Order alphabetically
                .Ordered()
                // Add the index
                .Select((theoremString, index) => $"[{index + 1}] {theoremString}")
                // Make each on a separate line
                .ToJoinedString("\n");

                // Write the configuration and theorems
                Console.WriteLine($"\nConfiguration:\n\n{formatter.FormatConfiguration(configuration).Indent(2)}\n");
                Console.WriteLine($"Theorems:\n\n{TheoremString(theorems.AllObjects).Indent(2)}\n");

                #endregion

                #region Proving theorems

                // Prepare a timer
                var totalTime = new Stopwatch();

                // Start it
                totalTime.Start();

                // Perform the theorem finding with proofs, without any assumed theorems
                var proverOutput = kernel.Get <ITheoremProver>().ProveTheoremsAndConstructProofs(new TheoremMap(), theorems, contextualPicture);

                // Stop the timer
                totalTime.Stop();

                #endregion

                #region Writing results

                // Get the proofs
                var proofString = proverOutput
                                  // Sort by the statement
                                  .OrderBy(pair => formatter.FormatTheorem(pair.Key))
                                  // Format each
                                  .Select(pair => formatter.FormatTheoremProof(pair.Value))
                                  // Trim
                                  .Select(proofString => proofString.Trim())
                                  // Make an empty line between each
                                  .ToJoinedString("\n\n");

                // Write it
                Console.WriteLine(proofString);

                // Write the unproven theorems too
                Console.WriteLine($"\nUnproved:\n\n{TheoremString(theorems.AllObjects.Except(proverOutput.Keys)).Indent(2)}\n");

                // Report time
                Console.WriteLine($"Total time: {totalTime.ElapsedMilliseconds}");
                Console.WriteLine("----------------------------------------------");

                #endregion
            });

            #endregion
        }
        /// <summary>
        /// Creates a formatted string describing a given theorem proof.
        /// </summary>
        /// <param name="formatter">The output formatter.</param>
        /// <param name="proof">The theorem proof to be formatted.</param>
        /// <param name="tag">The starting tag of the theorem string. It is empty by default.</param>
        /// <returns>The string representing the theorem proof.</returns>
        public static string FormatTheoremProof(this OutputFormatter formatter, TheoremProof proof, string tag = "")
        {
            // Prepare a dictionary of theorem tags that are used to avoid repetition in the proof tree
            var theoremTags = new Dictionary <Theorem, string>();

            // Local function that recursively converts a given proof to a string, starting the
            // explanation with a given tag
            string FormatTheoremProof(TheoremProof proof, string tag)
            {
                // Start composing the result by formatting the theorem and the proof explanation
                var result = $"{formatter.FormatTheorem(proof.Theorem)} - {GetProofExplanation(proof, formatter)}";

                // If there is nothing left to write, we're done
                if (proof.ProvedAssumptions.Count == 0)
                {
                    return(result);
                }

                // Otherwise we want an empty line
                result += "\n\n";

                // Create an enumerable of reports of the proven assumptions
                var assumptionsString = proof.ProvedAssumptions
                                        // Ordered by theorem
                                        .OrderBy(assumptionProof => formatter.FormatTheorem(assumptionProof.Theorem))
                                        // Process a given one
                                        .Select((assumptionProof, index) =>
                {
                    // Get the theorem for comfort
                    var theorem = assumptionProof.Theorem;

                    // Construct the new tag from the previous one and the ordinal number of the assumption
                    var newTag = $"  {tag}{index + 1}.";

                    // Find out if the theorem already has a tag
                    var theoremIsUntagged = !theoremTags.ContainsKey(theorem);

                    // If the theorem is not tagged yet, tag it
                    if (theoremIsUntagged)
                    {
                        theoremTags.Add(theorem, newTag.Trim());
                    }

                    // Find out the reasoning for the theorem
                    var reasoning = theoremIsUntagged ?
                                    // If it's untagged, recursively find the proof string for it
                                    FormatTheoremProof(assumptionProof, newTag) :
                                    // Otherwise just state it again and add the explanation and the reference to it
                                    $"{formatter.FormatTheorem(theorem)} - {GetProofExplanation(assumptionProof, formatter)} - theorem {theoremTags[theorem]}";

                    // The final result is the new tag (even if it's tagged already) and the reasoning
                    return($"{newTag} {reasoning}");
                });

                // Append the particular assumptions, each on a separate line, while making
                // sure there is exactly one line break at the end
                return($"{result}{assumptionsString.ToJoinedString("\n").TrimEnd()}\n");
            }

            // Call the local recursive function with the passed tag
            return(FormatTheoremProof(proof, tag));
        }