/// <summary> /// Returns a string representation the explanation of how a theorem has been proved. /// </summary> /// <param name="proof">The theorem proof to be examined.</param> /// <param name="formatter">The formatter of the configuration where the proved theorem holds.</param> /// <returns>The explanation string.</returns> private static string GetProofExplanation(TheoremProof proof, OutputFormatter formatter) // Switch based on the type of the used inference rule => proof.Rule switch {
/// <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)); }