//
        // 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);
        }
        //     B ---------V---------A
        //                 \
        //                  \
        //                   \
        //                    C
        //
        // SegmentBisector(Segment(V, C), Segment(B, A)), Triangle(A, B, C) -> Median(Segment(V, C), Triangle(A, B, C))
        //
        private static List <EdgeAggregator> InstantiateToMedian(GroundedClause clause)
        {
            List <EdgeAggregator> newGrounded = new List <EdgeAggregator>();

            if (clause is Triangle)
            {
                Triangle tri = clause as Triangle;

                foreach (SegmentBisector sb in candidateBisector)
                {
                    newGrounded.AddRange(InstantiateToMedian(tri, sb, sb));
                }

                foreach (Strengthened streng in candidateStrengthened)
                {
                    newGrounded.AddRange(InstantiateToMedian(tri, streng.strengthened as SegmentBisector, streng));
                }

                candidateTriangle.Add(tri);
            }
            else if (clause is SegmentBisector)
            {
                SegmentBisector sb = clause as SegmentBisector;

                foreach (Triangle tri in candidateTriangle)
                {
                    newGrounded.AddRange(InstantiateToMedian(tri, sb, sb));
                }

                candidateBisector.Add(sb);
            }
            else if (clause is Strengthened)
            {
                Strengthened streng = clause as Strengthened;

                if (!(streng.strengthened is SegmentBisector))
                {
                    return(newGrounded);
                }

                foreach (Triangle tri in candidateTriangle)
                {
                    newGrounded.AddRange(InstantiateToMedian(tri, streng.strengthened as SegmentBisector, streng));
                }

                candidateStrengthened.Add(streng);
            }

            return(newGrounded);
        }
        //     B ---------V---------A
        //                 \
        //                  \
        //                   \
        //                    C
        //
        // SegmentBisector(Segment(V, C), Segment(B, A)) -> Midpoint(V, Segment(B, A))
        //
        public static List <EdgeAggregator> InstantiateFromSegmentBisector(GroundedClause clause)
        {
            List <EdgeAggregator> newGrounded = new List <EdgeAggregator>();

            if (clause is SegmentBisector)
            {
                SegmentBisector sb = clause as SegmentBisector;

                foreach (InMiddle im in candidateInMiddle)
                {
                    newGrounded.AddRange(InstantiateFromSegmentBisector(im, sb, sb));
                }

                candidateSegmentBisector.Add(sb);
            }
            else if (clause is Strengthened)
            {
                Strengthened streng = clause as Strengthened;

                if (!(streng.strengthened is SegmentBisector))
                {
                    return(newGrounded);
                }

                foreach (InMiddle im in candidateInMiddle)
                {
                    newGrounded.AddRange(InstantiateFromSegmentBisector(im, streng.strengthened as SegmentBisector, streng));
                }
                candidateStrengthened.Add(streng);
            }
            else if (clause is InMiddle)
            {
                InMiddle newIm = clause as InMiddle;

                foreach (SegmentBisector sb in candidateSegmentBisector)
                {
                    newGrounded.AddRange(InstantiateFromSegmentBisector(newIm, sb, sb));
                }

                foreach (Strengthened streng in candidateStrengthened)
                {
                    newGrounded.AddRange(InstantiateFromSegmentBisector(newIm, streng.strengthened as SegmentBisector, streng));
                }

                candidateInMiddle.Add(newIm);
            }

            return(newGrounded);
        }
        //
        // Take the angle congruence and bisector and create the AngleBisector relation
        //
        private static List <EdgeAggregator> InstantiateToMedian(Triangle tri, SegmentBisector sb, GroundedClause original)
        {
            List <EdgeAggregator> newGrounded = new List <EdgeAggregator>();

            // The Bisector cannot be a side of the triangle.
            if (tri.CoincidesWithASide(sb.bisector) != null)
            {
                return(newGrounded);
            }

            // Acquire the intersection segment that coincides with the base of the triangle
            Segment triangleBaseCandidate = sb.bisected.OtherSegment(sb.bisector);
            Segment triangleBase          = tri.CoincidesWithASide(triangleBaseCandidate);

            if (triangleBase == null)
            {
                return(newGrounded);
            }

            // The candidate base and the actual triangle side must equate exactly
            if (!triangleBase.HasSubSegment(triangleBaseCandidate) || !triangleBaseCandidate.HasSubSegment(triangleBase))
            {
                return(newGrounded);
            }

            // The point opposite the base of the triangle must be within the endpoints of the bisector
            Point oppPoint = tri.OtherPoint(triangleBase);

            if (!sb.bisector.PointLiesOnAndBetweenEndpoints(oppPoint))
            {
                return(newGrounded);
            }

            // -> Median(Segment(V, C), Triangle(A, B, C))
            Median newMedian = new Median(sb.bisector, tri);

            // For hypergraph
            List <GroundedClause> antecedent = new List <GroundedClause>();

            antecedent.Add(tri);
            antecedent.Add(original);

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

            return(newGrounded);
        }
        public static List <EdgeAggregator> InstantiateFromSegmentBisector(InMiddle im, SegmentBisector sb, GroundedClause original)
        {
            List <EdgeAggregator> newGrounded = new List <EdgeAggregator>();

            // Does this bisector apply to this InMiddle? Check point of intersection
            if (!im.point.StructurallyEquals(sb.bisected.intersect))
            {
                return(newGrounded);
            }

            // Segments must equate
            if (!im.segment.StructurallyEquals(sb.bisected.OtherSegment(sb.bisector)))
            {
                return(newGrounded);
            }

            // Create the midpoint
            Strengthened newMidpoint = new Strengthened(im, new Midpoint(im));

            // For hypergraph
            List <GroundedClause> antecedent = Utilities.MakeList <GroundedClause>(original);

            antecedent.Add(im);

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

            return(newGrounded);
        }
        //     A _________________ B
        //      /                /
        //     /                /
        //    /                /
        // D /________________/ C
        //
        // Parallelogram(A, B, C, D) -> SegmentBisector(Segment(A, C), Segment(B, D)), SegmentBisector(Segment(B, D), Segment(A, C)),
        //
        public static List <EdgeAggregator> Instantiate(GroundedClause clause)
        {
            annotation.active = EngineUIBridge.JustificationSwitch.DIAGONALS_BISECT_EACH_OTHER_IMPLY_PARALLELOGRAM;

            List <EdgeAggregator> newGrounded = new List <EdgeAggregator>();

            if (clause is Quadrilateral)
            {
                Quadrilateral quad = clause as Quadrilateral;

                if (!quad.IsStrictQuadrilateral())
                {
                    return(newGrounded);
                }

                for (int i = 0; i < candidateBisectors.Count - 1; i++)
                {
                    for (int j = i + 1; j < candidateBisectors.Count; j++)
                    {
                        newGrounded.AddRange(InstantiateToTheorem(quad, candidateBisectors[i], candidateBisectors[j], candidateBisectors[i], candidateBisectors[j]));
                    }
                }

                for (int i = 0; i < candidateStrengthened.Count - 1; i++)
                {
                    for (int j = i + 1; j < candidateStrengthened.Count; j++)
                    {
                        newGrounded.AddRange(InstantiateToTheorem(quad, candidateStrengthened[i].strengthened as SegmentBisector,
                                                                  candidateStrengthened[j].strengthened as SegmentBisector,
                                                                  candidateStrengthened[i], candidateStrengthened[j]));
                    }
                }

                foreach (Strengthened oldStreng in candidateStrengthened)
                {
                    foreach (SegmentBisector oldSB in candidateBisectors)
                    {
                        newGrounded.AddRange(InstantiateToTheorem(quad, oldStreng.strengthened as SegmentBisector, oldSB, oldStreng, oldSB));
                    }
                }

                candidateQuadrilaterals.Add(quad);
            }
            else if (clause is SegmentBisector)
            {
                SegmentBisector newSB = clause as SegmentBisector;

                foreach (Quadrilateral quad in candidateQuadrilaterals)
                {
                    foreach (SegmentBisector oldSB in candidateBisectors)
                    {
                        newGrounded.AddRange(InstantiateToTheorem(quad, newSB, oldSB, newSB, oldSB));
                    }
                }

                foreach (Quadrilateral quad in candidateQuadrilaterals)
                {
                    foreach (Strengthened streng in candidateStrengthened)
                    {
                        newGrounded.AddRange(InstantiateToTheorem(quad, newSB, streng.strengthened as SegmentBisector, newSB, streng));
                    }
                }

                candidateBisectors.Add(newSB);
            }
            else if (clause is Strengthened)
            {
                Strengthened newStreng = clause as Strengthened;

                if (!(newStreng.strengthened is SegmentBisector))
                {
                    return(newGrounded);
                }

                foreach (Quadrilateral quad in candidateQuadrilaterals)
                {
                    foreach (SegmentBisector oldSB in candidateBisectors)
                    {
                        newGrounded.AddRange(InstantiateToTheorem(quad, newStreng.strengthened as SegmentBisector, oldSB, newStreng, oldSB));
                    }
                }

                foreach (Quadrilateral quad in candidateQuadrilaterals)
                {
                    foreach (Strengthened oldStreng in candidateStrengthened)
                    {
                        newGrounded.AddRange(InstantiateToTheorem(quad, newStreng.strengthened as SegmentBisector, oldStreng.strengthened as SegmentBisector, newStreng, oldStreng));
                    }
                }

                candidateStrengthened.Add(newStreng);
            }

            return(newGrounded);
        }
        //     A _________________ B
        //      /                /
        //     /     \/         /
        //    /      /\        /
        // D /________________/ C
        //
        // Quadrilateral(A, B, C, D), SegmentBisector(Segment(A, C), Segment(B, D)),
        //                            SegmentBisector(Segment(B, D), Segment(A, C)) -> Parallelogram(A, B, C, D)
        //
        private static List <EdgeAggregator> InstantiateToTheorem(Quadrilateral quad, SegmentBisector sb1, SegmentBisector sb2, GroundedClause originalSB1, GroundedClause originalSB2)
        {
            List <EdgeAggregator> newGrounded = new List <EdgeAggregator>();

            // The two segment bisectors must intersect at the same point
            if (!sb1.bisected.intersect.StructurallyEquals(sb2.bisected.intersect))
            {
                return(newGrounded);
            }

            // The bisectors must be part of the other segment bisector.
            if (!sb1.bisected.HasSegment(sb2.bisector))
            {
                return(newGrounded);
            }
            if (!sb2.bisected.HasSegment(sb1.bisector))
            {
                return(newGrounded);
            }

            // Do these segment bisectors define the diagonals of the quadrilateral?
            if (!sb1.bisector.HasSubSegment(quad.topLeftBottomRightDiagonal) && !sb2.bisector.HasSubSegment(quad.topLeftBottomRightDiagonal))
            {
                return(newGrounded);
            }
            if (!sb1.bisector.HasSubSegment(quad.bottomLeftTopRightDiagonal) && !sb2.bisector.HasSubSegment(quad.bottomLeftTopRightDiagonal))
            {
                return(newGrounded);
            }

            // Determine the CongruentSegments opposing sides and output that.
            Strengthened newParallelogram = new Strengthened(quad, new Parallelogram(quad));

            // For hypergraph
            List <GroundedClause> antecedent = new List <GroundedClause>();

            antecedent.Add(quad);
            antecedent.Add(originalSB1);
            antecedent.Add(originalSB2);

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

            return(newGrounded);
        }