//
        //    A \
        //       \    B
        //        \  /
        //  O      \/ X
        //         /\
        //        /  \
        //     C /    D
        //
        // Two tangents:
        // Intersection(X, AD, BC), Tangent(Circle(O), BC), Tangent(Circle(O), AD) -> 2 * Angle(AXC) = MajorArc(AC) - MinorArc(AC)
        //
        public static List<EdgeAggregator> InstantiateTwoTangentsTheorem(Tangent tangent1, Tangent tangent2, Intersection inter, GroundedClause original1, GroundedClause original2)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            CircleSegmentIntersection tan1 = tangent1.intersection as CircleSegmentIntersection;
            CircleSegmentIntersection tan2 = tangent2.intersection as CircleSegmentIntersection;

            if (tan1.StructurallyEquals(tan2)) return newGrounded;

            // Do the tangents apply to the same circle?
            if (!tan1.theCircle.StructurallyEquals(tan2.theCircle)) return newGrounded;

            Circle circle = tan1.theCircle;

            // Do these tangents work with this intersection?
            if (!inter.HasSegment(tan1.segment) || !inter.HasSegment(tan2.segment)) return newGrounded;

            // Overkill? Do the tangents intersect at the same point as the intersection's intersect point?
            if (!tan1.segment.FindIntersection(tan2.segment).StructurallyEquals(inter.intersect)) return newGrounded;

            //
            // Get the arcs
            //
            Arc minorArc = new MinorArc(circle, tan1.intersect, tan2.intersect);
            Arc majorArc = new MajorArc(circle, tan1.intersect, tan2.intersect);

            Angle theAngle = new Angle(tan1.intersect, inter.intersect, tan2.intersect);

            //
            // Construct the new relationship
            //
            NumericValue two = new NumericValue(2);

            GeometricAngleArcEquation gaaeq = new GeometricAngleArcEquation(new Multiplication(two, theAngle), new Subtraction(majorArc, minorArc));

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(original1);
            antecedent.Add(original2);
            antecedent.Add(inter);
            antecedent.Add(majorArc);
            antecedent.Add(minorArc);

            newGrounded.Add(new EdgeAggregator(antecedent, gaaeq, annotation));

            return newGrounded;
        }
        //
        //    A \
        //       \    B
        //        \  /
        //  O      \/ X
        //         /\
        //        /  \
        //     C /    D
        //
        // One Secant, One Tangent
        // Intersection(X, AD, BC), Tangent(Circle(O), BC) -> 2 * Angle(AXC) = MajorArc(AC) - MinorArc(AC)
        //
        public static List<EdgeAggregator> InstantiateOneSecantOneTangentTheorem(Intersection inter, Tangent tangent, GroundedClause original)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            CircleSegmentIntersection tan = tangent.intersection as CircleSegmentIntersection;

            // Is the tangent segment part of the intersection?
            if (!inter.HasSegment(tan.segment)) return newGrounded;

            // Acquire the chord that the intersection creates.
            Segment secant = inter.OtherSegment(tan.segment);

            Circle circle = tan.theCircle;
            Segment chord = circle.ContainsChord(secant);

            // Check if this segment never intersects the circle or doesn't create a chord.
            if (chord == null) return newGrounded;

            //
            // Get the near / far points out of the chord
            //
            Point closeChordPt = null;
            Point farChordPt = null;
            if (Segment.Between(chord.Point1, chord.Point2, inter.intersect))
            {
                closeChordPt = chord.Point1;
                farChordPt = chord.Point2;
            }
            else
            {
                closeChordPt = chord.Point2;
                farChordPt = chord.Point1;
            }

            //
            // Acquire the arcs
            //
            // Get the close arc first which we know exactly how it is constructed AND that it's a minor arc.
            Arc closeArc = Arc.GetFigureMinorArc(circle, closeChordPt, tan.intersect);

            // The far arc MAY be a major arc; if it is, the first candidate arc will contain the close arc.
            Arc farArc = Arc.GetFigureMinorArc(circle, farChordPt, tan.intersect);

            if (farArc.HasMinorSubArc(closeArc))
            {
                farArc = Arc.GetFigureMajorArc(circle, farChordPt, tan.intersect);
            }

            Angle theAngle = Angle.AcquireFigureAngle(new Angle(closeChordPt, inter.intersect, tan.intersect));

            //
            // Construct the new relationship
            //
            NumericValue two = new NumericValue(2);

            GeometricAngleArcEquation gaaeq = new GeometricAngleArcEquation(new Multiplication(two, theAngle), new Subtraction(farArc, closeArc));

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(original);
            antecedent.Add(inter);
            antecedent.Add(closeArc);
            antecedent.Add(farArc);

            newGrounded.Add(new EdgeAggregator(antecedent, gaaeq, annotation));

            return newGrounded;
        }
        //
        //    A \
        //       \    B
        //        \  /
        //  O      \/ X
        //         /\
        //        /  \
        //     C /    D
        //
        // Two Secants
        // Intersection(X, AD, BC) -> 2 * Angle(AXC) = MajorArc(AC) - MinorArc(AC)
        //
        public static List<EdgeAggregator> InstantiateTwoSecantsTheorem(Intersection inter, Circle circle)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // Is this intersection explicitly outside the circle? That is, the point of intersection exterior?
            if (!circle.PointIsExterior(inter.intersect)) return newGrounded;

            //
            // Get the chords
            //
            Segment chord1 = circle.ContainsChord(inter.lhs);
            Segment chord2 = circle.ContainsChord(inter.rhs);

            if (chord1 == null || chord2 == null) return newGrounded;

            Point closeChord1Pt = null;
            Point closeChord2Pt = null;
            Point farChord1Pt = null;
            Point farChord2Pt = null;
            if (Segment.Between(chord1.Point1, chord1.Point2, inter.intersect))
            {
                closeChord1Pt = chord1.Point1;
                farChord1Pt = chord1.Point2;
            }
            else
            {
                closeChord1Pt = chord1.Point2;
                farChord1Pt = chord1.Point1;
            }

            if (Segment.Between(chord2.Point1, chord2.Point2, inter.intersect))
            {
                closeChord2Pt = chord2.Point1;
                farChord2Pt = chord2.Point2;
            }
            else
            {
                closeChord2Pt = chord2.Point2;
                farChord2Pt = chord2.Point1;
            }

            //
            // Get the arcs
            //
            Arc closeArc = Arc.GetFigureMinorArc(circle, closeChord1Pt, closeChord2Pt);
            Arc farArc = Arc.GetFigureMinorArc(circle, farChord1Pt, farChord2Pt);

            Angle theAngle = Angle.AcquireFigureAngle(new Angle(closeChord1Pt, inter.intersect, closeChord2Pt));

            //
            // Construct the new relationship
            //
            NumericValue two = new NumericValue(2);

            //GeometricAngleEquation gaeq = new GeometricAngleEquation(new Multiplication(two, theAngle), new Subtraction(farArc, closeArc));
            GeometricAngleArcEquation gaaeq = new GeometricAngleArcEquation(new Multiplication(two, theAngle), new Subtraction(farArc, closeArc));

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(inter);
            antecedent.Add(circle);
            antecedent.Add(closeArc);
            antecedent.Add(farArc);

            newGrounded.Add(new EdgeAggregator(antecedent, gaaeq, annotation));

            return newGrounded;
        }
Ejemplo n.º 4
0
        //private static readonly string NAME = "Simplification";
        //
        // Given an equation, simplify algebraically using the following notions:
        //     A + A = B  -> 2A = B
        //     A + B = B + C -> A = C
        //     A + B = 2B + C -> A = B + C
        //
        public static Equation Simplify(Equation original)
        {
            // Do we have an equation?
            if (original == null) throw new ArgumentException();

            // Is the equation 0 = 0? This should be allowed at it indicates a tautology
            if (original.lhs.Equals(new NumericValue(0)) && original.rhs.Equals(new NumericValue(0)))
            {
                throw new ArgumentException("Should not have an equation that is 0 = 0: " + original.ToString());
            }

            //
            // Ideally, flattening would:
            // Remove all subtractions -> adding a negative instead
            // Distribute subtraction or multiplication over addition
            //
            // Flatten the equation so that each side is a sum of atomic expressions
            Equation copyEq = (Equation)original.DeepCopy();
            FlatEquation flattened = new FlatEquation(copyEq.lhs.CollectTerms(), copyEq.rhs.CollectTerms());

            //Debug.WriteLine("Equation prior to simplification: " + flattened.ToString());

            // Combine terms only on each side (do not cross =)
            FlatEquation combined = CombineLikeTerms(flattened);

            //Debug.WriteLine("Equation after like terms combined on both sides: " + combined);

            // Combine terms across the equal sign
            FlatEquation across = CombineLikeTermsAcrossEqual(combined);

             //Debug.WriteLine("Equation after simplifying both sides: " + across);

            FlatEquation constSimplify = SimplifyForMultipliersAndConstants(across);

            //
            // Inflate the equation
            //
            Equation inflated = null;
            GroundedClause singleLeftExp = InflateEntireSide(constSimplify.lhsExps);
            GroundedClause singleRightExp = InflateEntireSide(constSimplify.rhsExps);
            if (original is AlgebraicSegmentEquation)
            {
                inflated = new AlgebraicSegmentEquation(singleLeftExp, singleRightExp);
            }
            else if (original is GeometricSegmentEquation)
            {
                inflated = new GeometricSegmentEquation(singleLeftExp, singleRightExp);
            }
            else if (original is AlgebraicAngleEquation)
            {
                inflated = new AlgebraicAngleEquation(singleLeftExp, singleRightExp);
            }
            else if (original is GeometricAngleEquation)
            {
                inflated = new GeometricAngleEquation(singleLeftExp, singleRightExp);
            }
            else if (original is AlgebraicArcEquation)
            {
                inflated = new AlgebraicArcEquation(singleLeftExp, singleRightExp);
            }
            else if (original is GeometricArcEquation)
            {
                inflated = new GeometricArcEquation(singleLeftExp, singleRightExp);
            }
            else if (original is AlgebraicAngleArcEquation)
            {
                inflated = new AlgebraicAngleArcEquation(singleLeftExp, singleRightExp);
            }
            else if (original is GeometricAngleArcEquation)
            {
                inflated = new GeometricAngleArcEquation(singleLeftExp, singleRightExp);
            }

            // If simplifying didn't do anything, return the original equation
            if (inflated.Equals(original))
            {
                return original;
            }

            //
            // 0 = 0 should not be allowable.
            //
            if (inflated.lhs.Equals(new NumericValue(0)) && inflated.rhs.Equals(new NumericValue(0)))
            {
                return null;
            }

            return inflated;
        }
        //
        //    A \      / B
        //       \    /
        //        \  /
        //  O      \/ X
        //         /\
        //        /  \
        //     C /    \ D
        //
        // Intersection(Segment(AD), Segment(BC)) -> 2 * Angle(CXA) = Arc(A, C) + Arc(B, D),
        //                                           2 * Angle(BXD) = Arc(A, C) + Arc(B, D),
        //                                           2 * Angle(AXB) = Arc(A, B) + Arc(C, D),
        //                                           2 * Angle(CXD) = Arc(A, B) + Arc(C, D)
        //
        public static List<EdgeAggregator> InstantiateTheorem(Intersection inter, Circle circle)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // Is this intersection explicitly inside the circle? That is, the point of intersection interior?
            if (!circle.PointIsInterior(inter.intersect)) return newGrounded;

            //
            // Get the chords
            //
            Segment chord1 = circle.GetChord(inter.lhs);
            Segment chord2 = circle.GetChord(inter.rhs);

            if (chord1 == null || chord2 == null) return newGrounded;

            //
            // Group 1
            //
            Arc arc1 = Arc.GetFigureMinorArc(circle, chord1.Point1, chord2.Point1);
            Angle angle1 = Angle.AcquireFigureAngle(new Angle(chord1.Point1, inter.intersect, chord2.Point1));

            Arc oppArc1 = Arc.GetFigureMinorArc(circle, chord1.Point2, chord2.Point2);
            Angle oppAngle1 = Angle.AcquireFigureAngle(new Angle(chord1.Point2, inter.intersect, chord2.Point2));

            //
            // Group 2
            //
            Arc arc2 = Arc.GetFigureMinorArc(circle, chord1.Point1, chord2.Point2);
            Angle angle2 = Angle.AcquireFigureAngle(new Angle(chord1.Point1, inter.intersect, chord2.Point2));

            Arc oppArc2 = Arc.GetFigureMinorArc(circle, chord1.Point2, chord2.Point1);
            Angle oppAngle2 = Angle.AcquireFigureAngle(new Angle(chord1.Point2, inter.intersect, chord2.Point1));

            //
            // Construct each of the 4 equations.
            //
            NumericValue two = new NumericValue(2);

            GeometricAngleArcEquation gaeq1 = new GeometricAngleArcEquation(new Multiplication(two, angle1), new Addition(arc1, oppArc1));
            GeometricAngleArcEquation gaeq2 = new GeometricAngleArcEquation(new Multiplication(two, oppAngle1), new Addition(arc1, oppArc1));

            GeometricAngleArcEquation gaeq3 = new GeometricAngleArcEquation(new Multiplication(two, angle2), new Addition(arc2, oppArc2));
            GeometricAngleArcEquation gaeq4 = new GeometricAngleArcEquation(new Multiplication(two, oppAngle2), new Addition(arc2, oppArc2));

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(inter);
            antecedent.Add(circle);

            newGrounded.Add(new EdgeAggregator(antecedent, gaeq1, annotation));
            newGrounded.Add(new EdgeAggregator(antecedent, gaeq2, annotation));
            newGrounded.Add(new EdgeAggregator(antecedent, gaeq3, annotation));
            newGrounded.Add(new EdgeAggregator(antecedent, gaeq4, annotation));

            return newGrounded;
        }
        private static EdgeAggregator CreateClause(Intersection inter, GroundedClause original, Angle theAngle, Arc theArc)
        {
            Multiplication product = new Multiplication(new NumericValue(2), theAngle);
            GeometricAngleArcEquation angArcEq = new GeometricAngleArcEquation(product, theArc);

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(original);
            antecedent.Add(inter);

            return new EdgeAggregator(antecedent, angArcEq, annotation);
        }
        //
        //          C
        //         /)
        //        /  )
        //       / )
        //      / )
        //   A /)_________ B
        //
        // Tangent(Circle(O), Segment(AB)), Intersection(Segment(AC), Segment(AB)) -> 2 * Angle(CAB) = Arc(C, B)
        //
        public static List<EdgeAggregator> InstantiateTheorem(Intersection inter, Tangent tangent, GroundedClause original)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            CircleSegmentIntersection tan = tangent.intersection as CircleSegmentIntersection;

            //
            // Does this tangent apply to this intersection?
            //
            if (!inter.intersect.StructurallyEquals(tangent.intersection.intersect)) return newGrounded;

            Segment secant = null;
            Segment tanSegment = null;
            if (tan.HasSegment(inter.lhs))
            {
                secant = inter.rhs;
                tanSegment = inter.lhs;
            }
            else if (tan.HasSegment(inter.rhs))
            {
                secant = inter.lhs;
                tanSegment = inter.rhs;
            }
            else return newGrounded;

            //
            // Acquire the angle and intercepted arc.
            //
            Segment chord = tan.theCircle.GetChord(secant);
            if (chord == null) return newGrounded;
            //Segment chord = tan.theCircle.ContainsChord(secant);

            // Arc
            // We want the MINOR ARC only!
            if (tan.theCircle.DefinesDiameter(chord))
            {
                Arc theArc = null;
                Point midpt = PointFactory.GeneratePoint(tan.theCircle.Midpoint(chord.Point1, chord.Point2));
                Point opp = PointFactory.GeneratePoint(tan.theCircle.OppositePoint(midpt));

                Point tanPoint = tanSegment.OtherPoint(inter.intersect);

                if (tanPoint != null)
                {
                    // Angle; the smaller angle is always the chosen angle
                    Angle theAngle = new Angle(chord.OtherPoint(inter.intersect), inter.intersect, tanPoint);

                    theArc = new Semicircle(tan.theCircle, chord.Point1, chord.Point2, midpt, chord);
                    newGrounded.Add(CreateClause(inter, original, theAngle, theArc));

                    theArc = new Semicircle(tan.theCircle, chord.Point1, chord.Point2, opp, chord);
                    newGrounded.Add(CreateClause(inter, original, theAngle, theArc));
                }
                else
                {
                    // Angle; the smaller angle is always the chosen angle
                    Angle theAngle = new Angle(chord.OtherPoint(inter.intersect), inter.intersect, tanSegment.Point1);

                    theArc = new Semicircle(tan.theCircle, chord.Point1, chord.Point2, midpt, chord);
                    newGrounded.Add(CreateClause(inter, original, theAngle, theArc));

                    theArc = new Semicircle(tan.theCircle, chord.Point1, chord.Point2, opp, chord);
                    newGrounded.Add(CreateClause(inter, original, theAngle, theArc));

                    // Angle; the smaller angle is always the chosen angle
                    theAngle = new Angle(chord.OtherPoint(inter.intersect), inter.intersect, tanSegment.Point2);

                    theArc = new Semicircle(tan.theCircle, chord.Point1, chord.Point2, midpt, chord);
                    newGrounded.Add(CreateClause(inter, original, theAngle, theArc));

                    theArc = new Semicircle(tan.theCircle, chord.Point1, chord.Point2, opp, chord);
                    newGrounded.Add(CreateClause(inter, original, theAngle, theArc));

                }
            }
            else
            {
                Arc theArc = new MinorArc(tan.theCircle, chord.Point1, chord.Point2);

                // Angle; the smaller angle is always the chosen angle
                Point endPnt = (inter.intersect.StructurallyEquals(tanSegment.Point1)) ? tanSegment.Point2 : tanSegment.Point1;
                Angle theAngle = new Angle(chord.OtherPoint(inter.intersect), inter.intersect, endPnt);

                if (theAngle.measure > 90)
                {
                    //If the angle endpoint was already set to Point2, or if the intersect equals Point2, then the smaller angle does not exist
                    //In this case, should we create a major arc or return nothing?
                    if (endPnt.StructurallyEquals(tanSegment.Point2) || inter.intersect.StructurallyEquals(tanSegment.Point2)) return newGrounded;
                    theAngle = new Angle(chord.OtherPoint(inter.intersect), inter.intersect, tanSegment.Point2);
                }

                Multiplication product = new Multiplication(new NumericValue(2), theAngle);
                GeometricAngleArcEquation angArcEq = new GeometricAngleArcEquation(product, theArc);

                // For hypergraph
                List<GroundedClause> antecedent = new List<GroundedClause>();
                antecedent.Add(original);
                antecedent.Add(inter);
                antecedent.Add(theArc);
                antecedent.Add(theAngle);

                newGrounded.Add(new EdgeAggregator(antecedent, angArcEq, annotation));
            }

            return newGrounded;
        }
        //     /        A
        //    /         |)
        //   /          | )
        //  /           |  )
        // Q------- O---X---) D
        //   \          |  )
        //    \         | )
        //     \        |)
        //      \        C
        //
        // Inscribed Angle(AQC) -> Angle(AQC) = 2 * Arc(AC)
        //
        private static List<EdgeAggregator> InstantiateTheorem(Circle circle, Angle angle)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // Acquire all circles in which the angle is inscribed
            List<Circle> circles = Circle.IsInscribedAngle(angle);

            //
            // Get this particular inscribed circle.
            //
            Circle inscribed = null;
            foreach (Circle c in circles)
            {
                if (circle.StructurallyEquals(c)) inscribed = c;
            }

            if (inscribed == null) return newGrounded;

            // Get the intercepted arc
            Arc intercepted = Arc.GetInterceptedArc(inscribed, angle);

            //
            // Create the equation
            //
            Multiplication product = new Multiplication(new NumericValue(2), angle);
            GeometricAngleArcEquation gaaeq = new GeometricAngleArcEquation(product, intercepted);

            // For hypergraph
            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(circle);
            antecedent.Add(angle);
            antecedent.Add(intercepted);

            newGrounded.Add(new EdgeAggregator(antecedent, gaaeq, annotation));

            return newGrounded;
        }