//        )  | 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(CircleSegmentIntersection inter, Perpendicular perp, GroundedClause original)
        {
            List<EdgeAggregator> newGrounded = new List<EdgeAggregator>();

            // The intersection points must be the same.
            if (!inter.intersect.StructurallyEquals(perp.intersect)) return newGrounded;

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

            if (radius == null) return newGrounded;

            // Two intersections, not a tangent situation.
            if (garbage != null) return newGrounded;

            // The radius can't be the same as the Circ-Inter segment.
            if (inter.segment.HasSubSegment(radius)) return newGrounded;

            // Does this perpendicular apply to this Arc intersection?
            if (!perp.HasSegment(radius) || !perp.HasSegment(inter.segment)) return newGrounded;

            Strengthened newTangent = new Strengthened(inter, new Tangent(inter));

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

            newGrounded.Add(new EdgeAggregator(antecedent, newTangent, 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;
        }