コード例 #1
0
        /// <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));
            })
コード例 #2
0
        /// <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()}")
                    });
                }
コード例 #3
0
        /// <inheritdoc/>
        public IReadOnlyList <Theorem> InferTrivialTheoremsFromObject(ConstructedConfigurationObject constructedObject)
        {
            // Get the flattened arguments of the object for comfort
            var objects = constructedObject.PassedArguments.FlattenedList;

            // Switch on the construction
            switch (constructedObject.Construction)
            {
            // If we have a predefined construction...
            case PredefinedConstruction predefinedConstruction:

                // Switch on its type
                switch (predefinedConstruction.Type)
                {
                // An angle bisector makes an incidence
                case InternalAngleBisector:
                {
                    // Create theorem objects
                    var line1    = new LineTheoremObject(objects[0], objects[1]);
                    var line2    = new LineTheoremObject(objects[0], objects[2]);
                    var bisector = new LineTheoremObject(constructedObject);

                    // Create the theorem
                    return(new[]
                        {
                            new Theorem(Incidence, objects[0], constructedObject)
                        });
                }

                // Point reflection makes collinear points and equally distanced points
                case PointReflection:

                    // Create the theorems
                    return(new[]
                    {
                        // Collinearity
                        new Theorem(CollinearPoints, objects[0], objects[1], constructedObject),

                        // Equal distances
                        new Theorem(EqualLineSegments, new TheoremObject[]
                        {
                            new LineSegmentTheoremObject(objects[1], objects[0]),
                            new LineSegmentTheoremObject(objects[1], constructedObject)
                        })
                    });

                // Point reflection makes collinear points and equally distanced points
                case Midpoint:

                    // Create the theorems
                    return(new[]
                    {
                        // Collinearity
                        new Theorem(CollinearPoints, objects[0], objects[1], constructedObject),

                        // Equal distances
                        new Theorem(EqualLineSegments, new TheoremObject[]
                        {
                            new LineSegmentTheoremObject(objects[0], constructedObject),
                            new LineSegmentTheoremObject(objects[1], constructedObject)
                        })
                    });

                // Perpendicular projection makes perpendicular lines and incidence
                case PerpendicularProjection:

                    // Create the theorem
                    return(new[]
                    {
                        // Perpendicular lines
                        new Theorem(PerpendicularLines, new TheoremObject[]
                        {
                            new LineTheoremObject(objects[0], constructedObject),
                            new LineTheoremObject(objects[1])
                        }),

                        // Incidence
                        new Theorem(Incidence, objects[1], constructedObject)
                    });

                // Perpendicular line makes (surprisingly) perpendicular lines and incidence
                case PerpendicularLine:

                    // Create the theorems
                    return(new[]
                    {
                        // Perpendicular lines
                        new Theorem(PerpendicularLines, new TheoremObject[]
                        {
                            new LineTheoremObject(constructedObject),
                            new LineTheoremObject(objects[1])
                        }),

                        // Incidence
                        new Theorem(Incidence, objects[0], constructedObject)
                    });

                // Parallel line makes (surprisingly) parallel lines and incidence
                case ParallelLine:

                    // Create the theorems
                    return(new[]
                    {
                        // Parallel lines
                        new Theorem(ParallelLines, new TheoremObject[]
                        {
                            new LineTheoremObject(constructedObject),
                            new LineTheoremObject(objects[1])
                        }),

                        // Incidence
                        new Theorem(Incidence, objects[0], constructedObject)
                    });

                // Second intersection of two circumcircles makes concyclic points
                case SecondIntersectionOfTwoCircumcircles:

                    // Create the theorems
                    return(new[]
                    {
                        new Theorem(ConcyclicPoints, constructedObject, objects[0], objects[1], objects[2]),
                        new Theorem(ConcyclicPoints, constructedObject, objects[0], objects[3], objects[4])
                    });

                // Second intersection of a circle and line from point make collinear and concyclic points
                case SecondIntersectionOfCircleAndLineFromPoints:

                    // Create the theorems
                    return(new[]
                    {
                        // Collinearity
                        new Theorem(CollinearPoints, constructedObject, objects[0], objects[1]),

                        // Concyclity
                        new Theorem(ConcyclicPoints, constructedObject, objects[0], objects[2], objects[3])
                    });

                // Line makes incidences
                case LineFromPoints:

                    // Create the theorems
                    return(new[]
                    {
                        new Theorem(Incidence, constructedObject, objects[0]),
                        new Theorem(Incidence, constructedObject, objects[1])
                    });

                // Circumcircle makes incidences
                case Circumcircle:

                    // Create the theorems
                    return(new[]
                    {
                        new Theorem(Incidence, constructedObject, objects[0]),
                        new Theorem(Incidence, constructedObject, objects[1]),
                        new Theorem(Incidence, constructedObject, objects[2])
                    });

                // Circle with center through point makes incidence
                case CircleWithCenterThroughPoint:

                    // Create the theorem
                    return(new[]
                    {
                        new Theorem(Incidence, constructedObject, objects[1])
                    });

                // Intersection of lines makes incidences
                case IntersectionOfLines:

                    // Create the theorems
                    return(new[]
                    {
                        new Theorem(Incidence, constructedObject, objects[0]),
                        new Theorem(Incidence, constructedObject, objects[1])
                    });

                // Center of circle brings nothing :/
                case CenterOfCircle:
                    return(Array.Empty <Theorem>());

                // Unhandled cases
                default:
                    throw new TheoremProverException($"Unhandled value of {nameof(PredefinedConstructionType)}: {predefinedConstruction.Type}");
                }

            // If we have a composed construction...
            case ComposedConstruction composedConstruction:

                // If we haven't found the theorems yet...
                if (!_originalInstances.ContainsKey(composedConstruction.Name))
                {
                    // Let the helper method do the job
                    var newTheorems = FindTheoremsForComposedConstruction(composedConstruction);

                    // Add them
                    _composedConstructionTheorems.Add(composedConstruction, newTheorems);

                    // Mark the used instance
                    _originalInstances.Add(composedConstruction.Name, composedConstruction);
                }

                // Get the original instance used for the theorems
                composedConstruction = _originalInstances[composedConstruction.Name];

                // Get the theorems
                var theorems = _composedConstructionTheorems[composedConstruction];

                // Create the mapping of loose objects of the template configuration
                var mapping = composedConstruction.Configuration.LooseObjects.Cast <ConfigurationObject>()
                              // and the template construction output
                              .Concat(composedConstruction.ConstructionOutput)
                              // to the actual objects that created the constructed object and the constructed object itself
                              .ZipToDictionary(objects.Concat(constructedObject));

                // Remap all the theorems
                return(theorems.Select(theorem => theorem.Remap(mapping)).ToList());

            // Unhandled cases
            default:
                throw new TheoremProverException($"Unhandled type of {nameof(Construction)}: {constructedObject.Construction.GetType()}");
            }
        }