Esempio n. 1
0
 /// <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));
 }
Esempio n. 2
0
        /// <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());
        }
Esempio n. 3
0
        /// <inheritdoc/>
        public RankedTheorem Rank(Theorem theorem, Configuration configuration, TheoremMap allTheorems)
        {
            // Prepare the ranking dictionary by applying every ranker
            var rankings = _rankers.Select(ranker => (ranker.RankedAspect, ranking: ranker.Rank(theorem, configuration, allTheorems)))
                           // And wrapping the result to a dictionary together with the coefficient from the settings
                           .ToDictionary(pair => pair.RankedAspect, pair => new RankingData(pair.ranking, _settings.RankingCoefficients[pair.RankedAspect]));

            // Wrap the final ranking in a ranking object
            var ranking = new TheoremRanking(rankings);

            // Now we can return the ranked theorem
            return(new RankedTheorem(theorem, ranking, configuration));
        }
Esempio n. 4
0
        /// <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)));
        }
Esempio n. 5
0
        /// <inheritdoc/>
        public override double Rank(Theorem theorem, Configuration configuration, TheoremMap allTheorems)
        {
            // Find the number of possible symmetry mappings of loose objects
            var allSymmetryMappingsCount = configuration.LooseObjectsHolder.GetSymmetricMappings().Count();

            // If there is no symmetry mapping for the layout, then 0 seems
            // like a good ranking
            if (allSymmetryMappingsCount == 0)
            {
                return(0);
            }

            // Otherwise find the number of actual symmetry mappings that
            // preserve both configuration and theorem
            var validSymmetryMappingsCount = theorem.GetSymmetryMappings(configuration).Count();

            // The symmetry ranking is the percentage of valid mappings
            return((double)validSymmetryMappingsCount / allSymmetryMappingsCount);
        }
Esempio n. 6
0
        /// <inheritdoc/>
        public override double Rank(Theorem theorem, Configuration configuration, TheoremMap allTheorems)
        {
            // Pull the number of constructed objects for comfort
            var n = configuration.ConstructedObjects.Count;

            // If there is at most 1 constructed object, let the level be 1
            // This should practically not happen, because we are supposed to be ranking
            // actual interesting problems...
            if (n <= 1)
            {
                return(1);
            }

            // Otherwise calculate the levels of objects
            var levels = configuration.CalculateObjectLevels();

            // And apply the formula from the documentations, i.e. 1 - 6[(l1^2+...+ln^2) - n] / [n(n-1)(2n+5)]
            return(1 - 6d * (levels.Values.Select(level => level * level).Sum() - n) / (n * (n - 1) * (2 * n + 5)));
        }
Esempio n. 7
0
 /// <inheritdoc/>
 public override double Rank(Theorem theorem, Configuration configuration, TheoremMap allTheorems)
 // Simply return the number of theorems, excluding the one we cannot prove
 => allTheorems.AllObjects.Count - 1;
 /// <inheritdoc/>
 public abstract double Rank(Theorem theorem, Configuration configuration, TheoremMap allTheorems);
 /// <summary>
 /// Converts given initial theorems to a string.
 /// </summary>
 /// <param name="initialFormatter">The formatter of the initial configuration.</param>
 /// <param name="initialTheorems">The theorems found in the initial configuration.</param>
 /// <returns>The string representing the theorems.</returns>
 private static string InitialTheoremsToString(OutputFormatter initialFormatter, TheoremMap initialTheorems)
 // Process every theorem
 => initialTheorems.AllObjects
 // Use formatter for each
 .Select(initialFormatter.FormatTheorem)
 // Sort them alphabetically
 .Ordered()
 // Append an index to each
 .Select((theoremString, index) => $" {index + 1,2}. {theoremString}")
 // Make each on a separate line
 .ToJoinedString("\n");
Esempio n. 10
0
        /// <summary>
        /// Performs the analysis of a given generator output.
        /// </summary>
        /// <param name="output">The generator output to be analyzed.</param>
        /// <param name="mode">Indicates how we handle asymmetric problems with regards to generation.</param>
        /// <param name="constructProofs">Indicates whether we should construct proofs or not, which affects the type of result.</param>
        /// <returns>The result depending on whether we're constructing proofs or not.</returns>
        private dynamic Analyze(ProblemGeneratorOutput output, SymmetryGenerationMode mode, bool constructProofs)
        {
            // Call the prover
            var proverOutput = constructProofs
                               // If we should construct proofs, do so
                ? (object)_prover.ProveTheoremsAndConstructProofs(output.OldTheorems, output.NewTheorems, output.ContextualPicture)
                               // If we shouldn't construct proofs, don't do it
                : _prover.ProveTheorems(output.OldTheorems, output.NewTheorems, output.ContextualPicture);

            // Find the proved theorems
            var provedTheorems = constructProofs
                                 // If we have constructed proofs, there is a dictionary
                ? (IReadOnlyCollection <Theorem>)((IReadOnlyDictionary <Theorem, TheoremProof>)proverOutput).Keys
                                 // Otherwise there is a collection directly
                : (IReadOnlyCollection <Theorem>)proverOutput;

            // Get the unproven theorems by taking all the new theorems
            var interestingTheorems = output.NewTheorems.AllObjects
                                      // Excluding those that are proven
                                      .Where(theorem => !provedTheorems.Contains(theorem))
                                      // Enumerate
                                      .ToArray();

            // Find the problems that should excluded based on symmetry
            var notInterestingTheorems = mode switch
            {
                // No restrictions
                SymmetryGenerationMode.GenerateBothSymmetricAndAsymmetric => (IReadOnlyList <Theorem>)Array.Empty <Theorem>(),

                // Detect symmetric theorems
                SymmetryGenerationMode.GenerateOnlySymmetric => interestingTheorems.Where(theorem => !theorem.IsSymmetric(output.Configuration)).ToArray(),

                // Detect fully symmetric theorems
                SymmetryGenerationMode.GenerateOnlyFullySymmetric => interestingTheorems.Where(theorem => !theorem.IsFullySymmetric(output.Configuration)).ToArray(),

                // Unhandled cases
                _ => throw new GeoGenException($"Unhandled value of {nameof(SymmetryGenerationMode)}: {mode}"),
            };

            // Interesting theorems can now be reseted
            interestingTheorems = interestingTheorems
                                  // By the exclusion of not interesting asymmetric ones
                                  .Except(notInterestingTheorems)
                                  // Enumerate
                                  .ToArray();

            // Prepare the map of all theorems
            var allTheorems = new TheoremMap(output.OldTheorems.AllObjects.Concat(output.NewTheorems.AllObjects));

            // Rank the interesting theorems
            var rankedInterestingTheorems = interestingTheorems
                                            // Rank given one
                                            .Select(theorem => _ranker.Rank(theorem, output.Configuration, allTheorems))
                                            // By rankings ASC (that's why -)
                                            .OrderBy(rankedTheorem => - rankedTheorem.Ranking.TotalRanking)
                                            // Enumerate
                                            .ToArray();

            // Now we can finally return the result
            return(constructProofs
                   // If we're constructing proofs, then we have a proof dictionary
                ? new GeneratedProblemAnalyzerOutputWithProofs(rankedInterestingTheorems, notInterestingTheorems, (IReadOnlyDictionary <Theorem, TheoremProof>)proverOutput)
                   // If we're not constructing proofs, then we have just a proved theorem collection
                : (GeneratedProblemAnalyzerOutputBase) new GeneratedProblemAnalyzerOutputWithoutProofs(rankedInterestingTheorems, notInterestingTheorems, (IReadOnlyCollection <Theorem>)proverOutput));
        }
Esempio n. 11
0
        /// <summary>
        /// Proves given theorems that are true in the configuration drawn in a given picture.
        /// </summary>
        /// <param name="provenTheorems">The theorems that hold in the configuration without the last object.</param>
        /// <param name="theoremsToProve">The theorems that say something about the last object.</param>
        /// <param name="picture">The picture where the configuration in which the theorems hold is drawn.</param>
        /// <param name="shouldWeConstructProofs">Indicates whether we should construct proofs. This will affect the type of returned result.</param>
        /// <returns>
        /// Either the output as for <see cref="ProveTheoremsAndConstructProofs(TheoremMap, TheoremMap, ContextualPicture)"/>,
        /// if we are constructing proof, or the output as for <see cref="ProveTheorems(TheoremMap, TheoremMap, ContextualPicture)"/> otherwise.
        /// </returns>
        private dynamic ProveTheorems(TheoremMap provenTheorems, TheoremMap theoremsToProve, ContextualPicture picture, bool shouldWeConstructProofs)
        {
            // Pull the configuration for comfort
            var configuration = picture.Pictures.Configuration;

            // Find the trivial theorems based on whether we should do it only
            // for the last object of the configuration
            var trivialTheorems = _settings.FindTrivialTheoremsOnlyForLastObject
                                  // If yes, do so
                ? _producer.InferTrivialTheoremsFromObject(configuration.ConstructedObjects.Last())
                                  // Otherwise do it for all objects
                : configuration.ConstructedObjects.SelectMany(_producer.InferTrivialTheoremsFromObject)
                                  // And enumerate the results
                                  .ToList();

            #region Proof builder initialization

            // Prepare a proof builder in case we are supposed to construct proofs
            var proofBuilder = shouldWeConstructProofs ? new TheoremProofBuilder() : null;

            // Mark trivial theorems to the proof builder in case we are supposed to construct proofs
            trivialTheorems.ForEach(theorem => proofBuilder?.AddImplication(TrivialTheorem, theorem, assumptions: Array.Empty <Theorem>()));

            // Mark assumed theorems to the proof builder in case we are supposed to construct proofs
            provenTheorems.AllObjects.ForEach(theorem => proofBuilder?.AddImplication(AssumedProven, theorem, assumptions: Array.Empty <Theorem>()));

            #endregion

            #region Theorems definable simpler

            // Prepare the list of theorems definable simpler
            var theoremsDefinableSimpler = new List <Theorem>();

            // If we are supposed to assuming them proven...
            if (_settings.AssumeThatSimplifiableTheoremsAreTrue)
            {
                // Go through unproven theorems except for trivial ones
                foreach (var theoremToProve in theoremsToProve.AllObjects.Except(trivialTheorems))
                {
                    // Find the redundant objects
                    var redundantObjects = theoremToProve.GetUnnecessaryObjects(configuration);

                    // If there are none, then it cannot be defined simpler
                    if (redundantObjects.IsEmpty())
                    {
                        continue;
                    }

                    // Otherwise add it to the list
                    theoremsDefinableSimpler.Add(theoremToProve);

                    // And make sure the proof builder knows it
                    proofBuilder?.AddImplication(new DefinableSimplerInferenceData(redundantObjects), theoremToProve, assumptions: Array.Empty <Theorem>());
                }
            }

            #endregion

            #region Theorems inferable from symmetry

            // Prepare the set of theorems inferred from symmetry
            var theoremsInferredFromSymmetry = new List <Theorem>();

            // Go throw the theorems that are already inferred, i.e. assumed proven, trivial and definable simpler ones
            foreach (var provedTheorem in provenTheorems.AllObjects.Concat(trivialTheorems).Concat(theoremsDefinableSimpler))
            {
                // Try to infer new theorems using this one
                foreach (var inferredTheorem in provedTheorem.InferTheoremsFromSymmetry(configuration))
                {
                    // Add it to the list
                    theoremsInferredFromSymmetry.Add(inferredTheorem);

                    // Make sure the proof builds knows it
                    proofBuilder?.AddImplication(InferableFromSymmetry, inferredTheorem, assumptions: new[] { provedTheorem });
                }
            }

            #endregion

            #region Normalization helper initialization

            // Initially we are going to assume that the proved theorems are the passed ones
            var provedTheorems = provenTheorems.AllObjects
                                 // And trivial ones
                                 .Concat(trivialTheorems)
                                 // And ones with redundant objects
                                 .Concat(theoremsDefinableSimpler)
                                 // And ones inferred from symmetry
                                 .Concat(theoremsInferredFromSymmetry)
                                 // Distinct ones
                                 .Distinct();

            // The theorems to prove will be the new ones except for the proved ones
            var currentTheoremsToBeProven = theoremsToProve.AllObjects.Except(provedTheorems).ToArray();

            // Prepare the cloned pictures that will be used to numerically verify new theorems
            var clonedPictures = picture.Pictures.Clone();

            // Prepare a normalization helper with all this information
            var normalizationHelper = new NormalizationHelper(_verifier, clonedPictures, provedTheorems, currentTheoremsToBeProven);

            #endregion

            #region Scheduler initialization

            // Prepare a scheduler
            var scheduler = new Scheduler(_manager);

            // Do the initial scheduling
            scheduler.PerformInitialScheduling(currentTheoremsToBeProven, configuration);

            #endregion

            // Prepare the object introduction helper
            var objectIntroductionHelper = new ObjectIntroductionHelper(_introducer, normalizationHelper);

            #region Inference loop

            // Do until break
            while (true)
            {
                // Ask the scheduler for the next inference data to be used
                var data = scheduler.NextScheduledData();

                #region Object introduction

                // If there is no data, we will try to introduce objects
                if (data == null)
                {
                    // Call the introduction helper
                    var(removedObjects, introducedObject) = objectIntroductionHelper.IntroduceObject(
                        // With the theorems to prove obtained by excluding the proved ones
                        theoremsToProve: theoremsToProve.AllObjects.Except(normalizationHelper.ProvedTheorems));

                    // Invalidate removed objects
                    removedObjects.ForEach(scheduler.InvalidateObject);

                    // If there is something to be introduced
                    if (introducedObject != null)
                    {
                        // Call the appropriate method to handle introduced objects
                        HandleNewObject(introducedObject, normalizationHelper, scheduler, proofBuilder);

                        // Ask the scheduler for the next inference data to be used
                        data = scheduler.NextScheduledData();
                    }
                }

                #endregion

                // If all theorems are proven or there is no data even after object introduction, we're done
                if (!normalizationHelper.AnythingLeftToProve || data == null)
                {
                    // If we should construct proofs
                    return(shouldWeConstructProofs
                           // Build them for the theorems to be proven
                        ? (dynamic)proofBuilder.BuildProofs(theoremsToProve.AllObjects)
                           // Otherwise just take the theorems to be proven that happen to be proven
                        : theoremsToProve.AllObjects.Where(normalizationHelper.ProvedTheorems.Contains).ToReadOnlyHashSet());
                }

                #region Inference rule applier call

                // Try to apply the current scheduled data
                var applierResults = _applier.InferTheorems(new InferenceRuleApplierInput
                                                            (
                                                                // Pass the data provided by the scheduler
                                                                inferenceRule: data.InferenceRule,
                                                                premappedAssumption: data.PremappedAssumption,
                                                                premappedConclusion: data.PremappedConclusion,
                                                                premappedObject: data.PremappedObject,

                                                                // Pass the methods that the normalization helper offers
                                                                mappableTheoremsFactory: normalizationHelper.GetProvedTheoremOfType,
                                                                mappableObjectsFactory: normalizationHelper.GetObjectsWithConstruction,
                                                                equalObjectsFactory: normalizationHelper.GetEqualObjects,
                                                                normalizationFunction: normalizationHelper.GetNormalVersionOfObjectOrNull
                                                            ))
                                     // Enumerate results. This step is needed because the applier could iterate over the
                                     // collections of objects and theorems used by the normalization helper
                                     .ToArray();

                // Before handling results prepare a variable that will indicate whether there has been any change of the
                // normal version of an object.
                var anyNormalVersionChange = false;

                // Handle every inferred theorems
                foreach (var(theorem, negativeAssumptions, possitiveAssumptions) in applierResults)
                {
                    // If in some previous iteration there has been a change of the normal version of an object, then
                    // it might happen that some other theorems inferred in this loop no longer contain only correct objects,
                    // therefore we need to verify them. The reason why we don't have to worry about incorrect objects in other
                    // cases is that the normalization helper keeps everything normalized and the inference rule applier provides
                    // only normalized objects. However, if there is a change of normal versions and the applier is already called
                    // and the results are enumerated, then we have to check it manually
                    if (anyNormalVersionChange && normalizationHelper.DoesTheoremContainAnyIncorrectObject(theorem))
                    {
                        continue;
                    }

                    // We need to check negative assumptions. The inference should be accepted only if all of them are false
                    if (negativeAssumptions.Any(negativeAssumption => _verifier.IsTrueInAllPictures(clonedPictures, negativeAssumption)))
                    {
                        continue;
                    }

                    // Prepare the proof data in case we need to construct proofs
                    var proofData = shouldWeConstructProofs ? new ProofData(proofBuilder, new CustomInferenceData(data.InferenceRule), possitiveAssumptions) : null;

                    // Prepare the variable indicating whether the theorem is geometrically valid
                    bool isValid;

                    // If this is an equality
                    if (theorem.Type == EqualObjects)
                    {
                        // Call the appropriate method to handle it while finding out whether there has been any normal version change
                        HandleEquality(theorem, normalizationHelper, scheduler, proofData, out isValid, out var anyNormalVersionChangeInThisIteration);

                        // If yes, then we set the outer loop variable indicating the same thing for the whole loop
                        if (anyNormalVersionChangeInThisIteration)
                        {
                            anyNormalVersionChange = true;
                        }
                    }
                    // If this is a non-equality
                    else
                    {
                        // Call the appropriate method to handle it
                        HandleNonequality(theorem, normalizationHelper, scheduler, proofData, out isValid);
                    }

                    // If the theorem turns out not to be geometrically valid, trace it
                    if (!isValid)
                    {
                        _tracer.MarkInvalidInferrence(configuration, theorem, data.InferenceRule, negativeAssumptions, possitiveAssumptions);
                    }
                }

                #endregion
            }

            #endregion
        }
Esempio n. 12
0
 /// <inheritdoc/>
 public IReadOnlyDictionary <Theorem, TheoremProof> ProveTheoremsAndConstructProofs(TheoremMap provenTheorems, TheoremMap theoremsToProve, ContextualPicture picture)
 // Delegate the call to the general method and cast the result
 => ProveTheorems(provenTheorems, theoremsToProve, picture, shouldWeConstructProofs: true);
Esempio n. 13
0
 /// <inheritdoc/>
 public IReadOnlyHashSet <Theorem> ProveTheorems(TheoremMap provenTheorems, TheoremMap theoremsToProve, ContextualPicture picture)
 // Delegate the call to the general method and cast the result
 => ProveTheorems(provenTheorems, theoremsToProve, picture, shouldWeConstructProofs: false);
Esempio n. 14
0
 /// <inheritdoc/>
 public override double Rank(Theorem theorem, Configuration configuration, TheoremMap allTheorems)
 // Simply return the number of theorems of type ConcyclicPoints
 => allTheorems.GetObjectsForKeys(TheoremType.ConcyclicPoints).Count()
 // Potentially excluding the one we cannot prove, if it's of type ConcyclicPoints
 - (theorem.Type == TheoremType.ConcyclicPoints ? 1 : 0);