/// <inheritdoc/> public bool IsTrueInAllPictures(Pictures pictures, Theorem theorem) { #region Ensure all inner objects are constructed // Go through the inner objects var objectsToConstruct = theorem.GetInnerConfigurationObjects() // And the object needed to construct them .GetDefiningObjects() // That are constructible .OfType <ConstructedConfigurationObject>() // That are not already constructed .Where(innerObject => !pictures.First().Contains(innerObject)); // Construct all of them foreach (var constructedObject in objectsToConstruct) { // Safely perform var data = GeneralUtilities.TryExecute( // The construction of the object () => _constructor.Construct(pictures, constructedObject, addToPictures: true), // Ignore any exception in this step (it will be solved in the next one) (InconsistentPicturesException _) => { }); // If there has been an inconsistency, we're sad and say this theorem is not true if (data == null) { return(false); } // If there is an inconstructible object, the same if (data.InconstructibleObject != null) { return(false); } } #endregion // If we got here, all needed objects are constructed. We need the theorem objects var theoremObjects = new Dictionary <TheoremObject, Dictionary <Picture, IAnalyticObject> >(); #region Construct theorem objects // Get the inner base theorem objects, i.e. Line / Circle / Point // Then we will reconstruct the other i.e., LineSegment later... var baseTheoremObjects = theorem.InvolvedObjects // Each theorem object can bring more of them .SelectMany(theoremObject => theoremObject switch { // If the object is already base, we return it BaseTheoremObject _ => theoremObject.ToEnumerable(), // If we have a line segment, then its inner objects are points LineSegmentTheoremObject lineSegment => lineSegment.PointSet, // Unhandled cases _ => throw new ConstructorException($"Unhandled type of {nameof(TheoremObject)}: {theoremObject.GetType()}") })
/// <inheritdoc/> public (Theorem newTheorem, Configuration newConfiguration)? Simplify(Theorem theorem, Configuration configuration) { // Prepare the dictionary of replaced theorem objects var replacedTheoremObjects = new Dictionary <TheoremObject, TheoremObject>(); #region Mapping theorem objects // We will try to replace each theorem object foreach (var theoremObject in theorem.InvolvedObjects) { // We're going to try to use some simplification rule for it foreach (var simplifcationRule in _data.Rules) { // If the template simplifiable object has a different type, then we can't do much if (!theoremObject.GetType().Equals(simplifcationRule.SimplifableObject.GetType())) { continue; } // Otherwise switch based on object type switch (theoremObject) { // Point simplification is not handled, let's move on case PointTheoremObject _: continue; // With objects with points (lines / circles) we can try to map those points case TheoremObjectWithPoints objectWithPoints: // If this object doesn't have a point, we can't do much if (!objectWithPoints.DefinedByPoints) { continue; } #region Mapping line / circle // Get the original points var originalPoints = objectWithPoints.PointsList; // Get the template points var templatePoints = (TheoremObjectWithPoints)simplifcationRule.SimplifableObject; // Go through the permutations of template points, each representing // a possible mapping between them and original points foreach (var orderedTemplatePoints in templatePoints.PointsList.Permutations()) { #region Trying various mappings // Enumerate them foreach (var mapping in Map(orderedTemplatePoints, originalPoints)) { #region Mapping the simplified object // Otherwise we can use it to come up with the new theorem object // First we must include its objects in the mapping (since Remap method requires it) simplifcationRule.SimplifiedObject.GetInnerConfigurationObjects() // Only those that aren't there yet .Where(configurationObject => !mapping.ContainsKey(configurationObject)) // They are definitely constructed (loose should have been mapped by now) .Cast <ConstructedConfigurationObject>() // Remap each .Select(constructedObject => (originalObject: constructedObject, mappedObject: new ConstructedConfigurationObject ( // The construction stays the same construction: constructedObject.Construction, // Map its arguments one by one input: constructedObject.PassedArguments.FlattenedList.Select(innerObject => mapping[innerObject]).ToArray() ))) // Add them to the mapping .ForEach(pair => mapping.Add(pair.originalObject, pair.mappedObject)); // Now we can finally map the simplified object var newTheoremObject = simplifcationRule.SimplifiedObject.Remap(mapping); #endregion #region Checking if the mapping doesn't increase the number of configuration objects // We need to find how many configuration objects we would need if we did the replaced // In order to find out take the theorem objects var neededObjects = theorem.InvolvedObjects // Exclude the one to be replaced .Except(theoremObject.ToEnumerable()) // Include the new one .Concat(newTheoremObject) // Find the inner configuration objects for each theorem object .SelectMany(theoremObject => theoremObject.GetInnerConfigurationObjects()) // Use our helper method to find all the objects needed to define these .GetDefiningObjects() // And simply take their count .Count; // If this replacement would complicate the theorem, we need to keep looking... if (neededObjects > configuration.AllObjects.Count) { continue; } #endregion // At this point the mapping is okay and we can add the object replacedTheoremObjects.Add(theoremObject, newTheoremObject); // We don't have to look for another one break; } #endregion // If the mapping has been successful, we don't have to look for another one if (replacedTheoremObjects.ContainsKey(theoremObject)) { break; } } #endregion break; // Unhandled cases default: throw new TheoremSimplifierException($"Unhandled type of {nameof(TheoremObjectWithPoints)}: {theoremObject.GetType()}"); } // If the mapping has been successful, we don't have to look for another one if (replacedTheoremObjects.ContainsKey(theoremObject)) { break; } } } #endregion #region Constructing the final result // If no object has been mapped, then we cannot simplify the theorem if (replacedTheoremObjects.IsEmpty()) { return(null); } // Otherwise we can recreate the theorem var newTheorem = new Theorem(theorem.Type, theorem.InvolvedObjects // Each object is either preserved or taken from the mapping .Select(theoremObject => replacedTheoremObjects.GetValueOrDefault(theoremObject) ?? theoremObject)); // Now we need to find the new configuration. We do that by finding // the objects that are now unnecessary with respect to the new theorem var unnecessaryObjects = newTheorem.GetUnnecessaryObjects(configuration); // Now we create the new configuration by copying its objects in their order var newConfiguration = new Configuration(configuration.LooseObjectsHolder, configuration.ConstructedObjects // With the exclusion of the objects that are now not necessary .Except(unnecessaryObjects) // And the inclusion the new objects that are taken from the inner objects of the new theorem .Concat(newTheorem.GetInnerConfigurationObjects() // And are constructed .OfType <ConstructedConfigurationObject>() // With the exclusion of those that already are there .Where(innerObject => !configuration.ConstructedObjectsSet.Contains(innerObject))) // They are constructed .Cast <ConstructedConfigurationObject>() // Now we can enumerate .ToArray()); // Finally we can return the result return(newTheorem, newConfiguration); #endregion }