/// <summary> /// Traces that a given contextual picture couldn't be cloned and extended with the new object /// already drawn in pictures representing some configuration. /// </summary> /// <param name="previousContextualPicture">The contextual picture that was correct and failed to add the new object.</param> /// <param name="newConfigurationPictures">The pictures holding geometry data of the new object that was added.</param> /// <param name="exception">The inner inconsistency exception that caused the issue.</param> public void InconstructibleContextualPictureByCloning(ContextualPicture previousContextualPicture, PicturesOfConfiguration newConfigurationPictures, InconsistentPicturesException exception) { // Prepare the initial information string var infoString = $"Undrawable object into a contextual picture."; // If logging is allowed, log it with the reference to more detail in the file if (_settings.LogFailures) { Log.Warning("Object generation: {info} See {path} for more detail.", infoString, _settings.FailureFilePath); } // Prepare the formatter for the configuration var formatter = new OutputFormatter(newConfigurationPictures.Configuration.AllObjects); // Add the data about how the object can be drawn infoString += $"\n\nThe object is the last object of the following defining configuration:\n\n{formatter.FormatConfiguration(newConfigurationPictures.Configuration).Indent(2)}"; // Add the exception infoString += $"\n\nThe details of the exception: {exception.Format(formatter)}\n"; // Open the stream writer for the file using var streamWriter = new StreamWriter(_settings.FailureFilePath, append: true); // Write indented message to the file streamWriter.WriteLine($"- {infoString.Indent(3).TrimStart()}"); }
/// <inheritdoc/> protected override IEnumerable<GeometricObject[]> GetAllOptions(ContextualPicture contextualPicture) { // Get lines as a list var allLines = contextualPicture.AllLines.ToList(); // Go through all unordered pairs for (var i = 0; i < allLines.Count; i++) { for (var j = i + 1; j < allLines.Count; j++) { // Get the lines for comfort var line1 = allLines[i]; var line2 = allLines[j]; // If they have a common point, exclude them right away if (line1.CommonPointsWith(line2).Any()) continue; // Otherwise go through the remaining lines for (var k = j + 1; k < allLines.Count; k++) { // Get the third line for comfort var line3 = allLines[k]; // If it has any common point with our two, skip it if (line3.CommonPointsWith(line1).Any() || line3.CommonPointsWith(line2).Any()) continue; // Otherwise return this triple yield return new[] { line1, line2, line3 }; } } } }
/// <inheritdoc/> protected override IEnumerable <GeometricObject[]> GetAllOptions(ContextualPicture contextualPicture) { // If we are excluding tangencies inside picture, we // don't have to consider circles with a common point if (_settings.ExcludeTangencyInsidePicture) { // Combine all circles with themselves foreach (var circles in contextualPicture.AllCircles.Subsets(2)) { if (circles[0].CommonPointsWith(circles[1]).IsEmpty()) { yield return(circles); } } } // Otherwise we don't have to consider circles with 2 common points else { // Combine all circles with themselves foreach (var circles in contextualPicture.AllCircles.Subsets(2)) { if (circles[0].CommonPointsWith(circles[1]).Count() != 2) { yield return(circles); } } } }
/// <inheritdoc/> protected override IEnumerable <GeometricObject[]> GetNewOptions(ContextualPicture contextualPicture) { // Find new lines var newLines = contextualPicture.NewLines.ToList(); // Find old lines var oldLines = contextualPicture.OldLines.ToList(); // Combine the new lines with themselves foreach (var(newLine1, newLine2) in newLines.UnorderedPairs()) { yield return new[] { newLine1, newLine2 } } ; // Combine the new lines with the old ones foreach (var newLine in newLines) { foreach (var oldLine in oldLines) { yield return new[] { newLine, oldLine } } } ; }
/// <inheritdoc/> protected override IEnumerable <GeometricObject[]> GetNewOptions(ContextualPicture contextualPicture) { // Find new circles. var newCircles = contextualPicture.NewCircles.ToList(); // Find old circles. var oldCircles = contextualPicture.OldCircles.ToList(); // If we are excluding tangencies inside picture, we // don't have to consider circles with a common point if (_settings.ExcludeTangencyInsidePicture) { // Combine the new circles with themselves foreach (var circles in newCircles.Subsets(2)) { if (circles[0].CommonPointsWith(circles[1]).IsEmpty()) { yield return(circles); } } // Combine the new circles with the old ones foreach (var newCircle in newCircles) { foreach (var oldCircle in oldCircles) { if (newCircle.CommonPointsWith(oldCircle).IsEmpty()) { yield return new[] { newCircle, oldCircle } } } } ; } // Otherwise we don't have to consider circles with 2 common points else { // Combine the new circles with themselves foreach (var circles in newCircles.Subsets(2)) { if (circles[0].CommonPointsWith(circles[1]).Count() != 2) { yield return(circles); } } // Combine the new circles with the old ones foreach (var newCircle in newCircles) { foreach (var oldCircle in oldCircles) { if (newCircle.CommonPointsWith(oldCircle).Count() != 2) { yield return new[] { newCircle, oldCircle } } } } ; } }
/// <summary> /// Initializes a new instance of the <see cref="ProblemGeneratorOutput"/> class. /// </summary> /// <param name="configuration">The generated configuration.</param> /// <param name="contextualPicture">The contextual picture where the configuration is drawn.</param> /// <param name="oldTheorems">The found theorems for the configurations that don't use the last object of the configuration.</param> /// <param name="newTheorems">The found theorems for the configurations that use the last object of the configuration.</param> public ProblemGeneratorOutput(GeneratedConfiguration configuration, ContextualPicture contextualPicture, TheoremMap oldTheorems, TheoremMap newTheorems) { Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); ContextualPicture = contextualPicture ?? throw new ArgumentNullException(nameof(contextualPicture)); OldTheorems = oldTheorems ?? throw new ArgumentNullException(nameof(oldTheorems)); NewTheorems = newTheorems ?? throw new ArgumentNullException(nameof(newTheorems)); }
/// <inheritdoc/> public override IEnumerable <Theorem> FindNewTheorems(ContextualPicture contextualPicture) // Take new options => GetNewOptions(contextualPicture) // That represent a true theorem .Where(objects => RepresentsTrueTheorem(contextualPicture, objects)) // Cast each to theorems .SelectMany(ToTheorems);
/// <inheritdoc/> public TheoremMap FindNewTheorems(ContextualPicture contextualPicture, TheoremMap oldTheorems, out Theorem[] invalidOldTheorems) { // Set no invalid theorems invalidOldTheorems = Array.Empty <Theorem>(); // Return an empty theorem map return(new TheoremMap()); }
/// <inheritdoc/> public override bool ValidateOldTheorem(ContextualPicture contextualPicture, Theorem oldTheorem) { // If we don't care whether the intersection point is outside or inside of the picture, // then there is no reason to say a theorem is invalid if (!ExpectAnyExternalIntersection) { return(true); } // Otherwise it might have happened that the new point is the one where the old theorem // stated an intersection theorem. We need to check this. Let's take the new point var newPoint = contextualPicture.NewPoints.FirstOrDefault(); // If the last object hasn't been a point, then nothing as explained could have happened if (newPoint == null) { return(true); } // Otherwise we need to check whether the old theorem doesn't state that some objects // have an intersection point equal to the new point return(oldTheorem.InvolvedObjects // We know the objects are with points .Cast <TheoremObjectWithPoints>() // For each we will find the corresponding geometric object definable by points .Select(objectWithPoints => { // If the object is defined explicitly, then we simply ask the picture to do the job if (objectWithPoints.DefinedByExplicitObject) { return (DefinableByPoints)contextualPicture.GetGeometricObject(objectWithPoints.ConfigurationObject); } // Otherwise we need to find the inner points var innerPoints = objectWithPoints.Points // As geometric objects .Select(contextualPicture.GetGeometricObject) // They are points .Cast <PointObject>() // Enumerate .ToArray(); // Base on the type of object we will take all lines / circles passing through the first point return (objectWithPoints switch { // If we have a line, take lines LineTheoremObject _ => innerPoints[0].Lines.Cast <DefinableByPoints>(), // If we have a circle, take circles CircleTheoremObject _ => innerPoints[0].Circles, // Unhandled cases _ => throw new TheoremFinderException($"Unhandled type of {nameof(TheoremObjectWithPoints)}: {objectWithPoints.GetType()}") }) // Take the first line or circle that contains all the points .First(lineOrCircle => lineOrCircle.ContainsAll(innerPoints)); })
/// <inheritdoc/> public override IEnumerable <Theorem> FindAllTheorems(ContextualPicture contextualPicture) // Take all lines => contextualPicture.AllLines // That have at least three points .Where(line => line.Points.Count >= 3) // For each take all triples of its points .SelectMany(line => line.Points.Subsets(3)) // Get the configuration objects .Select(points => points.Select(point => point.ConfigurationObject).ToArray()) // Each of these triples makes a theorem .Select(points => new Theorem(Type, points));
/// <inheritdoc/> protected override IEnumerable <GeometricObject[]> GetAllOptions(ContextualPicture contextualPicture) { // Get all points return(contextualPicture.AllPoints.ToList() // And all its pairs .UnorderedPairs().ToList() // And all pairs of these pairs .UnorderedPairs() // Each represents 4 points .Select(points => new[] { points.Item1.Item1, points.Item1.Item2, points.Item2.Item1, points.Item2.Item2 })); }
/// <inheritdoc/> public override IEnumerable <Theorem> FindAllTheorems(ContextualPicture contextualPicture) // Take all circles => contextualPicture.AllCircles // That have at least four points .Where(circle => circle.Points.Count >= 4) // For each take all quadruples of its points .SelectMany(circle => circle.Points.Subsets(4)) // Get the configuration objects .Select(points => points.Select(point => point.ConfigurationObject).ToArray()) // Each of these quadruples makes a theorem .Select(points => new Theorem(Type, points));
/// <summary> /// Runs the algorithm on the configuration to find old theorems (i.e. those who are true in the configuration /// with the last object removed), the new theorems (i.e. those that use the last object), the invalidated old /// theorems (see <see cref="ITheoremFinder.FindNewTheorems(ContextualPicture, TheoremMap, out Theorem[])"/>, /// and all theorems find via <see cref="ITheoremFinder.FindAllTheorems(ContextualPicture)"/>. /// </summary> /// <param name="configuration">The configuration where we're looking for theorems.</param> /// <returns>The old, new, invalidated all, and all theorems.</returns> private static (TheoremMap oldTheorems, TheoremMap newTheorems, Theorem[] invalidOldTheorems, TheoremMap allTheorems) FindTheorems(Configuration configuration) { // Prepare the kernel var kernel = NinjectUtilities.CreateKernel() // With constructor .AddConstructor() // Look for only some types .AddTheoremFinder(new TheoremFindingSettings(soughtTheoremTypes: new[] { ParallelLines, PerpendicularLines, EqualLineSegments, TangentCircles, LineTangentToCircle, Incidence, ConcurrentLines }, // No exclusion of inside-picture tangencies tangentCirclesTheoremFinderSettings: new TangentCirclesTheoremFinderSettings(excludeTangencyInsidePicture: false), // Exclusion of inside-picture tangencies lineTangentToCircleTheoremFinderSettings: new LineTangentToCircleTheoremFinderSettings(excludeTangencyInsidePicture: true))); // Create the finder var finder = kernel.Get <ITheoremFinder>(); // Create the old configuration, so we can find its theorems var oldConfiguration = new Configuration(configuration.LooseObjectsHolder, // We just don't want to include the last object configuration.ConstructedObjects.Except(new[] { configuration.LastConstructedObject }).ToList()); // Construct the old configuration var oldPictures = kernel.Get <IGeometryConstructor>().ConstructWithUniformLayout(oldConfiguration, numberOfPictures: 5).pictures; // Construct the old contextual picture var oldContextualPicture = new ContextualPicture(oldPictures); // Finally get the old theorems var oldTheorems = finder.FindAllTheorems(oldContextualPicture); // Create the pictures for the current configuration var pictures = kernel.Get <IGeometryConstructor>().ConstructWithUniformLayout(configuration, numberOfPictures: 5).pictures; // Create the contextual picture for the current configuration var contextualPicture = new ContextualPicture(pictures); // Run both algorithms var newTheorems = finder.FindNewTheorems(contextualPicture, oldTheorems, out var invalidOldTheorems); var allTheorems = finder.FindAllTheorems(contextualPicture); // Return everything return(oldTheorems, newTheorems, invalidOldTheorems, allTheorems); }
/// <inheritdoc/> public override IEnumerable <Theorem> FindAllTheorems(ContextualPicture contextualPicture) // Take all objects => contextualPicture.Pictures.Configuration.AllObjects // That are explicit lines / circles .Where(configurationObject => configurationObject.ObjectType == Line || configurationObject.ObjectType == Circle) // For each found the corresponding geometric object .Select(contextualPicture.GetGeometricObject) // We know they have points .Cast <DefinableByPoints>() // We can now access its points .SelectMany(geometricObject => geometricObject.Points // Every one of them makes an incidence .Select(point => new Theorem(Type, geometricObject.ConfigurationObject, point.ConfigurationObject)));
/// <inheritdoc/> protected override IEnumerable <GeometricObject[]> GetNewOptions(ContextualPicture contextualPicture) { // Find new points var newPoints = contextualPicture.NewPoints.ToList(); // Find old points var oldPoints = contextualPicture.OldPoints.ToList(); #region Getting new line segments // Prepare the list of new line segments var newLineSegments = new List <(PointObject, PointObject)>(); // Combine the new points with themselves foreach (var pairOfPoints in newPoints.UnorderedPairs()) { newLineSegments.Add(pairOfPoints); } // Combine the new points with the old ones foreach (var newPoint in newPoints) { foreach (var oldPoint in oldPoints) { newLineSegments.Add((newPoint, oldPoint)); } } #endregion // Get the old line segments var oldLineSegments = oldPoints.UnorderedPairs().ToList(); // Combine the new line segments with themselves foreach (var((point1, point2), (point3, point4)) in newLineSegments.UnorderedPairs()) { yield return new[] { point1, point2, point3, point4 } } ; // Combine the new line segments with the old ones foreach (var(point1, point2) in newLineSegments) { foreach (var(point3, point4) in oldLineSegments) { yield return new[] { point1, point2, point3, point4 } } } ; }
/// <inheritdoc/> public TheoremMap FindNewTheorems(ContextualPicture contextualPicture, TheoremMap oldTheorems, out Theorem[] invalidOldTheorems) { // Find invalid theorems first by taking the old theorems invalidOldTheorems = oldTheorems // For each [type, theorems] pair .SelectMany(pair => { // Find the right theorem finder var finder = _finders.First(finder => finder.Type == pair.Key); // And for every theorem answer the question whether it is no longer valid return(pair.Value.Where(oldTheorem => !finder.ValidateOldTheorem(contextualPicture, oldTheorem))); }) // Enumerate .ToArray(); // Reuse all the finders to find the theorems that are geometrically new in the configuration var uniqueNewTheorems = _finders.SelectMany(finder => finder.FindNewTheorems(contextualPicture)); // We still need to find the new theorems that are not new, due to geometric properties // such as collinearity or concyclity, but can now be stated using the new object // For that we are going to take every old theorem var redefinedNewTheorems = oldTheorems.AllObjects // That is valid .Except(invalidOldTheorems) // And return possibly new versions of it .SelectMany(theorem => // If we have an incidence, we don't want to do anything // (it's not needed to state that A lies on line AB) theorem.Type == TheoremType.Incidence ? Enumerable.Empty <Theorem>() : // Otherwise for each theorem we take its objects theorem.InvolvedObjects // Find the possible definition changes for each // (this includes the option of not changing the definition at all) .Select(theoremObject => FindDefinitionChangeOptions(theoremObject, contextualPicture)) // Combine these definitions in every possible way .Combine() // For every option create a new theorem .Select(objects => new Theorem(theorem.Type, objects))) // We might have gotten even old theorems (when all the definition option changes were // 'no change'. Also we might have gotten duplicates. This call will solve both problems .Except(oldTheorems.AllObjects); // Concatenate these two types of theorems and wrap the result in a map (which will enumerate it) return(new TheoremMap(uniqueNewTheorems.Concat(redefinedNewTheorems))); }
/// <summary> /// Runs the algorithm on the configuration to find new and all theorems. /// </summary> /// <param name="configuration">The configuration where we're looking for theorems.</param> /// <param name="instanceFactory">The factory for creating an instance of the finder. If it's null, the default constructor is used.</param> /// <returns>The new and all theorems.</returns> protected (List <Theorem> newTheorems, List <Theorem> allTheorems) FindTheorems(Configuration configuration, Func <T> instanceFactory = null) { // Prepare the kernel with the constructor module var kernel = NinjectUtilities.CreateKernel().AddConstructor(); // Create the pictures var pictures = kernel.Get <IGeometryConstructor>().ConstructWithUniformLayout(configuration, numberOfPictures: 5).pictures; // Create the contextual picture var contextualPicture = new ContextualPicture(pictures); // If the instance factory is specified var finder = instanceFactory != null? // Invoke it instanceFactory() : // Otherwise use reflection to call the parameterless constructor Activator.CreateInstance <T>(); // Run both algorithms return(finder.FindNewTheorems(contextualPicture).ToList(), finder.FindAllTheorems(contextualPicture).ToList()); }
/// <inheritdoc/> public override IEnumerable <Theorem> FindNewTheorems(ContextualPicture contextualPicture) { // Take the new point var point = contextualPicture.NewPoints.FirstOrDefault(); // If there's none, we can't do more if (point == null) { return(Enumerable.Empty <Theorem>()); } // Otherwise take its circles return(point.Circles // That have at least 4 points .Where(circle => circle.Points.Count >= 4) // For each take all triples of its points distinct from our point + append our point .SelectMany(circle => circle.Points.Where(_point => _point != point).Subsets(3).Select(subset => subset.Concat(point))) // Get the configuration objects .Select(points => points.Select(point => point.ConfigurationObject).ToArray()) // Each of these quadruples makes a theorem .Select(points => new Theorem(Type, points))); }
/// <inheritdoc/> public override IEnumerable <Theorem> FindNewTheorems(ContextualPicture contextualPicture) { // Get the last object of the configuration var lastConfigurationObject = contextualPicture.Pictures.Configuration.LastConstructedObject; // Distinguish cases bases on its type switch (lastConfigurationObject.ObjectType) { // If we have a point case Point: // We find its geometric version var geometricPoint = (PointObject)contextualPicture.GetGeometricObject(lastConfigurationObject); // Take all circles and lines return(geometricPoint.Lines.Cast <DefinableByPoints>().Concat(geometricPoint.Circles) // That are defined explicitly .Where(lineCircle => lineCircle.ConfigurationObject != null) // Each makes a valid incidence .Select(lineCircle => new Theorem(Type, lineCircle.ConfigurationObject, lastConfigurationObject))); // If we have a line or circle case Line: case Circle: // We find its geometric version var geometricLineCircle = (DefinableByPoints)contextualPicture.GetGeometricObject(lastConfigurationObject); // Take its points return(geometricLineCircle.Points // Each makes a valid incidence theorem .Select(point => new Theorem(Type, point.ConfigurationObject, lastConfigurationObject))); // Unhandled cases default: throw new TheoremFinderException($"Unhandled value of {nameof(ConfigurationObjectType)}: {lastConfigurationObject.ObjectType}"); } }
/// <inheritdoc/> protected override IEnumerable <GeometricObject[]> GetAllOptions(ContextualPicture contextualPicture) { // If we are excluding tangencies inside picture, we // don't have to consider lines and circles with a common point if (_settings.ExcludeTangencyInsidePicture) { // Combine the new lines with all the circles foreach (var line in contextualPicture.AllLines) { foreach (var circle in contextualPicture.AllCircles) { if (line.CommonPointsWith(circle).IsEmpty()) { yield return new GeometricObject[] { line, circle } } } } ; } // Otherwise we don't have to consider lines and circles with 2 common points else { // Combine the new lines with all the circles foreach (var line in contextualPicture.AllLines) { foreach (var circle in contextualPicture.AllCircles) { if (line.CommonPointsWith(circle).Count() != 2) { yield return new GeometricObject[] { line, circle } } } } ; } }
/// <inheritdoc/> public override bool ValidateOldTheorem(ContextualPicture contextualPicture, Theorem oldTheorem) // No restrictions => true;
/// <inheritdoc/> public abstract IEnumerable <Theorem> FindNewTheorems(ContextualPicture contextualPicture);
/// <inheritdoc/> public abstract bool ValidateOldTheorem(ContextualPicture contextualPicture, Theorem oldTheorem);
/// <inheritdoc/> protected override bool RepresentsTrueTheorem(ContextualPicture contextualPicture, GeometricObject[] objects) // Return if the theorem is true in all pictures => contextualPicture.Pictures.All(picture => // To find out if it's true in the given one we use our abstract method IsTrue(objects.Select(geometricObject => contextualPicture.GetAnalyticObject(geometricObject, picture)).ToArray()));
/// <inheritdoc/> protected override IEnumerable <GeometricObject[]> GetAllOptions(ContextualPicture contextualPicture) // Get all pairs of lines => contextualPicture.AllLines.Subsets(2);
/// <inheritdoc/> protected override IEnumerable<GeometricObject[]> GetNewOptions(ContextualPicture contextualPicture) { // Find new lines var newLines = contextualPicture.NewLines.ToList(); // Find old lines var oldLines = contextualPicture.OldLines.ToList(); #region Three new lines // Go through all unordered pairs for (var i = 0; i < newLines.Count; i++) { for (var j = i + 1; j < newLines.Count; j++) { // Get the lines for comfort var line1 = newLines[i]; var line2 = newLines[j]; // If they have a common point, exclude them right away if (line1.CommonPointsWith(line2).Any()) continue; // Otherwise go through the remaining lines for (var k = j + 1; k < newLines.Count; k++) { // Get the third line for comfort var line3 = newLines[k]; // If it has any common point with our two, skip it if (line3.CommonPointsWith(line1).Any() || line3.CommonPointsWith(line2).Any()) continue; // Otherwise return this triple yield return new[] { line1, line2, line3 }; } } } #endregion #region Two new lines, one old // Take new line pairs and combine them with the old ones foreach (var (newLine1, newLine2) in newLines.UnorderedPairs()) if (newLine1.CommonPointsWith(newLine2).IsEmpty()) foreach (var oldLine in oldLines) if (oldLine.CommonPointsWith(newLine1).IsEmpty() && oldLine.CommonPointsWith(newLine2).IsEmpty()) yield return new[] { newLine1, newLine2, oldLine }; #endregion #region One new line, two old // Take old line pairs and combine them with the new ones foreach (var (oldLine1, oldLine2) in oldLines.UnorderedPairs()) if (oldLine1.CommonPointsWith(oldLine2).IsEmpty()) foreach (var newLine in newLines) if (newLine.CommonPointsWith(oldLine1).IsEmpty() && newLine.CommonPointsWith(oldLine2).IsEmpty()) yield return new[] { oldLine1, oldLine2, newLine }; #endregion }
/// <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 }
/// <inheritdoc/> public TheoremMap FindAllTheorems(ContextualPicture contextualPicture) // Simply reuse all the finders and wrap the theorems in a map (which will enumerate it) => new TheoremMap(_finders.SelectMany(finder => finder.FindAllTheorems(contextualPicture)));
/// <summary> /// Finds all options for changing the definition of a given old theorem object based on the new (last) /// configuration object, which might have geometric properties related to this old object (for example, /// if the new object is a point and the old one is a line/circle, then it might lie on it). This includes /// even an option of not changing the definition at all, i.e. returning the original old object. /// </summary> /// <param name="oldTheoremObject">The old theorem object for which we're looking for definition change options.</param> /// <param name="contextualPicture">The contextual picture that represents the configuration.</param> /// <returns>The enumeration of all possible definition changes, including no change.</returns> private static IEnumerable <TheoremObject> FindDefinitionChangeOptions(TheoremObject oldTheoremObject, ContextualPicture contextualPicture) { // Find the new object of the configuration var newConfigurationObject = contextualPicture.Pictures.Configuration.LastConstructedObject; // Find its geometric version var newGeometricObject = contextualPicture.GetGeometricObject(newConfigurationObject); // Switch based on the type of old object switch (oldTheoremObject) { // If we have a point or line segment (internally consisting of points...) case PointTheoremObject _: case LineSegmentTheoremObject _: // Then there is no way to find a new definition of the object, // i.e. we return the 'no change of definition' option return(new[] { oldTheoremObject }); // If we have an object with points... case TheoremObjectWithPoints objectWithPoints: #region Find its geometric version // We're going to find the corresponding geometric version DefinableByPoints geometricObjectWithPoints = default; // If our object is defined explicitly if (objectWithPoints.DefinedByExplicitObject) { // Use the internal configuration object to get the definition directly geometricObjectWithPoints = (DefinableByPoints)contextualPicture.GetGeometricObject(objectWithPoints.ConfigurationObject); } // Otherwise it's defined by points else { // Get the points corresponding to its points var geometricPoints = objectWithPoints.Points // For each find the geometric point .Select(contextualPicture.GetGeometricObject) // We know they're points .Cast <PointObject>() // Enumerate .ToArray(); // Find the right object based on the type of the theorem object with points geometricObjectWithPoints = (objectWithPoints switch { // Looking for the line that contains our points // It certainly passes through the first point LineTheoremObject _ => geometricPoints[0].Lines.First(line => line.ContainsAll(geometricPoints)) as DefinableByPoints, // Looking for the circle that contains our points // It certainly passes through the first point CircleTheoremObject _ => geometricPoints[0].Circles.First(circle => circle.ContainsAll(geometricPoints)), // Unhandled cases _ => throw new TheoremFinderException($"Unhandled type of {nameof(TheoremObjectWithPoints)}: {objectWithPoints.GetType()}") }); }
/// <inheritdoc/> public void InconstructibleContextualPictureByCloning(ContextualPicture previousContextualPicture, PicturesOfConfiguration newConfigurationPictures, InconsistentPicturesException exception) { }