//        )  | 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);
        }