コード例 #1
0
        /// <summary>
        /// Find all theorems that hold true for the loose objects and the construction output of a given composed construction.
        /// </summary>
        /// <param name="composedConstruction">The composed construction to be examined.</param>
        /// <returns>The theorems holding true for the loose objects and the construction output.</returns>
        private IReadOnlyList <Theorem> FindTheoremsForComposedConstruction(ComposedConstruction composedConstruction)
        {
            // Local function that throws an exception
            void ThrowIncorrectConstructionException(string message, Exception innerException = null)
            // informing about the examination failure
            => throw new TheoremProverException($"Cannot examine construction {composedConstruction.Name}. {message}", innerException);

            // Create a helper constructed object that simulates the composed construction
            var helperConstructedObject = new ConstructedConfigurationObject(composedConstruction,
                                                                             // Its arguments will be the loose objects of the composed construction's configuration
                                                                             composedConstruction.Configuration.LooseObjects.Cast <ConfigurationObject>().ToArray());

            // Prepare the configuration that simulates the composed construction
            var helperConfiguration = new Configuration(composedConstruction.Configuration.LooseObjectsHolder, new[] { helperConstructedObject });

            // Safely execute
            var(pictures, data) = GeneralUtilities.TryExecute(
                // Construction of the new configuration
                () => _constructor.ConstructWithUniformLayout(helperConfiguration, NumberOfPicturesForFindingTrivialTheorems),
                // While making sure any exception is caught and re-thrown
                (InconsistentPicturesException e) => ThrowIncorrectConstructionException("The defining configuration couldn't be drawn.", e));

            // Make sure it has no inconstructible objects
            if (data.InconstructibleObject != default)
            {
                ThrowIncorrectConstructionException("The defining configuration contains an inconstructible object.");
            }

            // Make sure it has no duplicates
            if (data.Duplicates != default)
            {
                ThrowIncorrectConstructionException("The defining configuration contains duplicate objects.");
            }

            // Safely execute
            var contextualPicture = GeneralUtilities.TryExecute(
                // Construction of the contextual picture
                () => new ContextualPicture(pictures),
                // While making sure any exception is caught and re-thrown
                (InconsistentPicturesException e) => ThrowIncorrectConstructionException("The contextual picture for the defining configuration couldn't be drawn.", e));

            // Find the theorems
            return(_finder.FindAllTheorems(contextualPicture).AllObjects
                   // Take those that say something about the last object
                   // (there might be theorems in the layout as well, for example in RightTriangle)
                   .Where(theorem => theorem.GetInnerConfigurationObjects().Contains(helperConstructedObject))
                   // We need to remap the helper constructed object to the one from the underlying configuration
                   .Select(theorem =>
            {
                // Prepare the mapping dictionary
                var mapping = new Dictionary <ConfigurationObject, ConfigurationObject>
                {
                    // That already has the helper object remapped to the construction output
                    { helperConstructedObject, composedConstruction.ConstructionOutput }
                };

                // Add the loose objects to the mapping as identities
                composedConstruction.Configuration.LooseObjects.ForEach(looseObject => mapping.Add(looseObject, looseObject));

                // Do the mapping
                return theorem.Remap(mapping);
            })
                   // Enumerate
                   .ToList());
        }
コード例 #2
0
        /// <inheritdoc/>
        public (TheoremMap initialTheorems, IEnumerable <ProblemGeneratorOutput> generationOutputs) Generate(ProblemGeneratorInput input)
        {
            #region Preparing variables

            // Prepare the stack for pictures of configurations that will be extended
            var picturesCache = new Stack <PicturesOfConfiguration>();

            // Prepare the stack for contextual pictures of configurations that will be extended
            var contextualPictureCache = new Stack <ContextualPicture>();

            // Prepare the stack for theorems of configurations that will be extended
            var theoremMapCache = new Stack <TheoremMap>();

            #endregion

            #region Initial configuration

            // Safely execute
            var(initialPictures, initialData) = GeneralUtilities.TryExecute(
                // Constructing the configuration
                () => _constructor.ConstructWithUniformLayout(input.InitialConfiguration, _settings.NumberOfPictures),
                // Make sure a potential exception is caught and re-thrown
                (InconsistentPicturesException e) => throw new InitializationException("Drawing the initial configuration failed.", e));

            // Make sure it is constructible
            if (initialData.InconstructibleObject != default)
            {
                throw new InitializationException($"The initial configuration contains an inconstructible object.");
            }

            // Make sure there are no duplicates...
            if (initialData.Duplicates != default)
            {
                throw new InitializationException($"The initial configuration contains duplicate objects.");
            }

            // Cache the pictures
            picturesCache.Push(initialPictures);

            // Safely execute
            var initialContextualPicture = GeneralUtilities.TryExecute(
                // Creating the contextual picture
                () => new ContextualPicture(initialPictures),
                // Make sure a potential exception is caught and re-thrown
                (InconsistentPicturesException e) => throw new InitializationException("Drawing the contextual container for the initial configuration failed.", e));

            // Cache the contextual picture
            contextualPictureCache.Push(initialContextualPicture);

            // Find the initial theorems for the initial configuration
            var initialTheorems = _finder.FindAllTheorems(initialContextualPicture);

            // Cache the initial theorems
            theoremMapCache.Push(initialTheorems);

            #endregion

            #region Configuration verification function

            // Prepare a function that does geometric verification of a generated configuration
            // While doing so it construct pictures that we can reuse further for finding theorems
            bool VerifyConfigurationCorrectness(GeneratedConfiguration configuration)
            {
                #region Handling cache

                // We assume that the generator uses a memory-efficient DFS approach, i.e.
                // we need to remember only the last N-1 configurations, where N is the number
                // of the current iteration.

                // We got a configuration. We need to make sure that our cache contains only
                // objects belonging to the previous configurations of this. There final number
                // should be configuration.IterationIndex, therefore we know how many we should remove
                GeneralUtilities.ExecuteNTimes(picturesCache.Count - configuration.IterationIndex, () =>
                {
                    // Remove the last pictures / contextual picture / theorems map from the cache
                    picturesCache.Pop();
                    contextualPictureCache.Pop();
                    theoremMapCache.Pop();
                });

                #endregion

                #region Exclusion based on symmetry

                // Find out if we should exclude this configuration because of symmetry
                // That can happen only if we are told to do so...
                var excludeBecauseOfSymmetry = input.SymmetryGenerationMode != SymmetryGenerationMode.GenerateBothSymmetricAndAsymmetric &&
                                               // And it is not true that we can generate some objects that would make this configuration symmetric
                                               // To find all options that would do so, we need to distinguish the symmetry mode
                                               !(input.SymmetryGenerationMode switch
                {
                    // Standard symmetry yields a list of options (i.e. object lists)
                    SymmetryGenerationMode.GenerateOnlySymmetric => configuration.GetObjectsThatWouldMakeThisConfigurationSymmetric(),

                    // Full symmetry yields only one object list
                    SymmetryGenerationMode.GenerateOnlyFullySymmetric => configuration.GetObjectsThatWouldMakeThisConfigurationFullySymmetric().ToEnumerable(),

                    // Unhandled cases
                    _ => throw new GeoGenException($"Unhandled value of {nameof(SymmetryGenerationMode)}: {input.SymmetryGenerationMode}"),
                })
                                               // Find out if given objects to be added could really be added
                                               .Any(objectsToBeAdded =>
                {
                    // If we don't have enough iterations to add that many objects, then we're done
                    if (configuration.IterationIndex + objectsToBeAdded.Count > input.NumberOfIterations)
                    {
                        return(false);
                    }

                    // Otherwise find out if we have the needed constructions by taking the objects
                    var doWeHaveNeededConstructions = objectsToBeAdded
                                                      // Their constructions
                                                      .Select(objectToBeAdded => objectToBeAdded.Construction)
                                                      // All of them must be among the ones we're using to extend objects
                                                      .All(input.Constructions.Contains);

                    // If we don't have the needed constructions, these objects can't be generated
                    if (!doWeHaveNeededConstructions)
                    {
                        return(false);
                    }

                    // Otherwise categorize objects to be added by taking them
                    return(objectsToBeAdded
                           // Grouping by their type
                           .GroupBy(objectToBeAdded => objectToBeAdded.ObjectType)
                           // It needs to be true that we can add that many objects from every type
                           .All(group =>
                    {
                        // Get the type
                        var type = group.Key;

                        // Get the needed count
                        var neededObjectsOfThisTypeCount = group.Count();

                        // Get the number of already added objects of this type by taking all objects of this type
                        var addedObjectsOfThisTypeCount = configuration.ObjectMap.GetObjectsForKeys(type).Count()
                                                          // And subtracting objects of this type from the initial configuration
                                                          - input.InitialConfiguration.ObjectMap.GetObjectsForKeys(type).Count();

                        // We can add these objects if and only if we will not exceed the maximal number of objects to add
                        return neededObjectsOfThisTypeCount + addedObjectsOfThisTypeCount <= input.MaximalNumbersOfObjectsToAdd[type];
                    }));
                });

                // If we should exclude this configuration because of symmetry, do it
                if (excludeBecauseOfSymmetry)
                {
                    return(false);
                }

                #endregion

                #region Pictures construction

                // Get the previous pictures
                var previousPictures = picturesCache.Peek();

                // Safely execute
                var(newPictures, constructionData) = GeneralUtilities.TryExecute(
                    // Constructing the pictures for the configuration
                    () => _constructor.ConstructByCloning(previousPictures, configuration),
                    // While tracing a possible failure (such configurations will be discarded in the next step)
                    (InconsistentPicturesException e) => _tracer.InconstructiblePicturesByCloning(previousPictures, configuration, e));

                // The configuration is incorrect if it couldn't be carried out...
                var isConfigurationIncorrect = newPictures == default
                                               // Or if it contains an inconstructible object
                                               || constructionData.InconstructibleObject != default
                                               // Or if it contains the same object twice
                                               || constructionData.Duplicates != default;

                // Exclude incorrect configuration
                if (isConfigurationIncorrect)
                {
                    return(false);
                }

                // We have to remember the pictures for further use
                picturesCache.Push(newPictures);

                #endregion

                #region Contextual picture construction

                // Get the previous contextual picture
                var previousContextualPicture = contextualPictureCache.Peek();

                // Safely execute
                var newContextualPicture = GeneralUtilities.TryExecute(
                    // Constructing the new contextual picture by cloning
                    () => previousContextualPicture.ConstructByCloning(newPictures),
                    // While tracing a possible failure (such configurations will be discarded in the next step)
                    (InconsistentPicturesException e) => _tracer.InconstructibleContextualPictureByCloning(previousContextualPicture, newPictures, e));

                // If the construction of the picture cannot be done...
                if (newContextualPicture == default)
                {
                    // We need to make sure the already constructed pictures are discarded
                    picturesCache.Pop();

                    // And we say the configuration is incorrect
                    return(false);
                }

                // We have to remember the contextual picture for further use
                contextualPictureCache.Push(newContextualPicture);

                #endregion

                // If we got here, everything's fine
                return(true);
            }