/// <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");
/// <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)); }
/// <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)); }