public static List<GenericInstantiator.EdgeAggregator> GeneratePerpendicularBisector(GroundedClause tri, AngleBisector ab, Intersection inter)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            IsoscelesTriangle isoTri = (tri is Strengthened ? (tri as Strengthened).strengthened : tri) as IsoscelesTriangle;

            if (tri is EquilateralTriangle)
            {

            }

            // Does the Angle Bisector occur at the vertex angle (non-base angles) of the Isosceles triangle?
            try
            {
                if (!ab.angle.GetVertex().Equals(isoTri.GetVertexAngle().GetVertex())) return newGrounded;
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.ToString());
            }

            // Is the intersection point between the endpoints of the base of the triangle?
            if (!Segment.Between(inter.intersect, isoTri.baseSegment.Point1, isoTri.baseSegment.Point2)) return newGrounded;

            // Does this intersection define this angle bisector situation? That is, the bisector and base must align with the intersection
            if (!inter.ImpliesRay(ab.bisector)) return newGrounded;
            if (!inter.HasSegment(isoTri.baseSegment)) return newGrounded;

            List<GroundedClause> antecedent = new List<GroundedClause>();
            antecedent.Add(tri);
            antecedent.Add(ab);
            antecedent.Add(inter);

            // PerpendicularBisector(M, Segment(M, C), Segment(A, B))
            Strengthened newPerpB = new Strengthened(inter, new PerpendicularBisector(inter, ab.bisector));
            newGrounded.Add(new EdgeAggregator(antecedent, newPerpB, annotation));

            return newGrounded;
        }
        //                    \ A
        //                     \
        //                      \
        //   center: O          / P
        //                     /
        //                    / B
        //
        // Tangent(Circle(O), Segment(B, P)),
        // Tangent(Circle(O), Segment(A, P)),
        // Intersection(AP, BP) -> Congruent(Segment(A, P), Segment(P, B))
        //
        private static List<EdgeAggregator> InstantiateTheorem(Tangent tangent1, Tangent tangent2, Intersection inter, GroundedClause original1, GroundedClause original2)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // Do the tangents apply to the same circle?
            if (!tangent1.intersection.theCircle.StructurallyEquals(tangent2.intersection.theCircle)) return newGrounded;

            // Do the tangents have components the are part of the third intersection
            if (!inter.HasSegment((tangent1.intersection as CircleSegmentIntersection).segment)) return newGrounded;
            if (!inter.HasSegment((tangent2.intersection as CircleSegmentIntersection).segment)) return newGrounded;

            Segment segment1 = Segment.GetFigureSegment(inter.intersect, tangent1.intersection.intersect);
            Segment segment2 = Segment.GetFigureSegment(inter.intersect, tangent2.intersection.intersect);

            GeometricCongruentSegments gcs = new GeometricCongruentSegments(segment1, segment2);

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

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

            return newGrounded;
        }
        //
        //    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;
        }
        private static List<EdgeAggregator> InstantiateFromAltitude(Intersection inter, Altitude altitude)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // The intersection should contain the altitude segment
            if (!inter.HasSegment(altitude.segment)) return newGrounded;

            // The triangle should contain the other segment in the intersection
            Segment triangleSide = altitude.triangle.CoincidesWithASide(inter.OtherSegment(altitude.segment));
            if (triangleSide == null) return newGrounded;
            if (!inter.OtherSegment(altitude.segment).HasSubSegment(triangleSide)) return newGrounded;

            //
            // Create the Perpendicular relationship
            //
            Strengthened streng = new Strengthened(inter, new Perpendicular(inter));

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

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

            return newGrounded;
        }
        //        )  | B
        //         ) |
        // O        )| S
        //         ) |
        //        )  |
        //       )   | A
        // Tangent(Circle(O, R), Segment(A, B)), Intersection(OS, AB) -> Perpendicular(Segment(A,B), Segment(O, S))
        //
        private static List<EdgeAggregator> InstantiateTheorem(Tangent tangent, Intersection inter, GroundedClause original)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            CircleSegmentIntersection tanInter = tangent.intersection as CircleSegmentIntersection;

            // Does this tangent segment apply to this intersection?
            if (!inter.HasSegment(tanInter.segment)) return newGrounded;

            // Get the radius--if it exists
            Segment radius = null;
            Segment garbage = null;
            tanInter.GetRadii(out radius, out garbage);

            if (radius == null) return newGrounded;

            // Does this radius apply to this intersection?
            if (!inter.HasSubSegment(radius)) return newGrounded;

            Strengthened newPerp = new Strengthened(inter, new Perpendicular(inter));

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

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

            return newGrounded;
        }
        //
        // Take the angle congruence and bisector and create the AngleBisector relation
        //              \
        //               \
        //     B ---------V---------A
        //                 \
        //                  \
        //                   C
        //
        private static List<EdgeAggregator> InstantiateToDef(Point intersectionPoint, Intersection inter, CongruentSegments cs)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // Does the given point of intersection apply to this actual intersection object
            if (!intersectionPoint.Equals(inter.intersect)) return newGrounded;

            // The entire segment AB
            Segment overallSegment = new Segment(cs.cs1.OtherPoint(intersectionPoint), cs.cs2.OtherPoint(intersectionPoint));

            // The segment must align completely with one of the intersection segments
            Segment interCollinearSegment = inter.GetCollinearSegment(overallSegment);
            if (interCollinearSegment == null) return newGrounded;

            // Does this intersection have the entire segment AB
            if (!inter.HasSegment(overallSegment)) return newGrounded;

            Segment bisector = inter.OtherSegment(overallSegment);
            Segment bisectedSegment = inter.GetCollinearSegment(overallSegment);

            // Check if the bisected segment extends is the exact same segment as the overall segment AB
            if (!bisectedSegment.StructurallyEquals(overallSegment))
            {
                if (overallSegment.PointLiesOnAndBetweenEndpoints(bisectedSegment.Point1) &&
                    overallSegment.PointLiesOnAndBetweenEndpoints(bisectedSegment.Point2)) return newGrounded;
            }

            SegmentBisector newSB = new SegmentBisector(inter, bisector);

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

            newGrounded.Add(new EdgeAggregator(antecedent, newSB, annotation));
            return newGrounded;
        }
        //               A
        //              |)
        //              | )
        //              |  )
        // Q------- O---X---) D
        //              |  )
        //              | )
        //              |)
        //               C
        //
        // Perpendicular(Segment(Q, D), Segment(A, C)) -> Congruent(Arc(A, D), Arc(D, C)) -> Congruent(Segment(AX), Segment(XC))
        //
        private static List<EdgeAggregator> InstantiateTheorem(Intersection inter, CircleSegmentIntersection arcInter, Perpendicular perp, GroundedClause original)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

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

            // Is this too restrictive?
            if (!((inter.HasSegment(perp.lhs) && inter.HasSegment(perp.rhs)) && (perp.HasSegment(inter.lhs) && perp.HasSegment(inter.rhs)))) return newGrounded;

            //
            // Does this perpendicular intersection apply to a given circle?
            //
            // Acquire the circles for which the segments are secants.
            List<Circle> secantCircles1 = Circle.GetSecantCircles(perp.lhs);
            List<Circle> secantCircles2 = Circle.GetSecantCircles(perp.rhs);

            List<Circle> intersection = Utilities.Intersection<Circle>(secantCircles1, secantCircles2);

            if (!intersection.Any()) return newGrounded;

            //
            // Find the single, unique circle that has as chords the components of the perpendicular intersection
            //
            Circle theCircle = null;
            Segment chord1 = null;
            Segment chord2 = null;
            foreach (Circle circle in intersection)
            {
                chord1 = circle.GetChord(perp.lhs);
                chord2 = circle.GetChord(perp.rhs);
                if (chord1 != null && chord2 != null)
                {
                    theCircle = circle;
                    break;
                }
            }

            Segment diameter = chord1.Length > chord2.Length ? chord1 : chord2;
            Segment chord = chord1.Length < chord2.Length ? chord1 : chord2;

            //
            // Does the arc intersection apply?
            //
            if (!arcInter.HasSegment(diameter)) return newGrounded;
            if (!theCircle.StructurallyEquals(arcInter.theCircle)) return newGrounded;

            //
            // Create the bisector
            //
            Strengthened sb = new Strengthened(inter, new SegmentBisector(inter, diameter));
            Strengthened ab = new Strengthened(arcInter, new ArcSegmentBisector(arcInter));

            // For hypergraph
            List<GroundedClause> antecedentArc = new List<GroundedClause>();
            antecedentArc.Add(arcInter);
            antecedentArc.Add(original);
            antecedentArc.Add(theCircle);

            newGrounded.Add(new EdgeAggregator(antecedentArc, ab, annotation));

            List<GroundedClause> antecedentSegment = new List<GroundedClause>();
            antecedentSegment.Add(inter);
            antecedentSegment.Add(original);
            antecedentSegment.Add(theCircle);

            newGrounded.Add(new EdgeAggregator(antecedentSegment, sb, annotation));

            return newGrounded;
        }