private static bool IsFinite(PairNonNull <Rational, Rational> point)
 {
     return(!point.One.IsInfinity && !point.Two.IsInfinity);
 }
        [ContractVerification(false)] // The analysis of this method takes forever. Should consider refactoring
        internal Set <Polynomial <Variable, Expression> > ConvexHullHelper(
            IntervalEnvironment <Variable, Expression> other, Variable slack, SubPolyhedra.JoinConstraintInference inference)
        {
            Contract.Requires(other != null);

            var result = new Set <Polynomial <Variable, Expression> >();

            var commonVariables = this.VariablesNonSlack.SetIntersection(other.VariablesNonSlack);

            var oct = false;

            if (commonVariables.Count <= SubPolyhedra.MaxVariablesInOctagonsConstraintInference)
            {
                oct = true;
            }
            else if (inference == SubPolyhedra.JoinConstraintInference.Standard)
            {
                return(result);
            }

            bool CH =
                inference == SubPolyhedra.JoinConstraintInference.CHOct ||
                inference == SubPolyhedra.JoinConstraintInference.ConvexHull2D;

            oct =
                oct ||
                inference == SubPolyhedra.JoinConstraintInference.CHOct ||
                inference == SubPolyhedra.JoinConstraintInference.Octagons;

            int i = 0, j = 0;

            var this_Bounds  = new Dictionary <Variable, Interval>();
            var other_Bounds = new Dictionary <Variable, Interval>();

            foreach (var e1 in commonVariables)
            {
                i++;

                Interval e1Left, e1Right;

                if (
                    !TryEvalWithCache(this, e1, this_Bounds, out e1Left) ||
                    !TryEvalWithCache(other, e1, other_Bounds, out e1Right))
                {
                    continue;
                }

                j = 0;
                foreach (var e2 in commonVariables)
                {
                    j++;

                    // either e1 == e2 or we already have relations between e1 and e2
                    if (e1.Equals(e2) || j <= i)
                    {
                        continue;
                    }

                    Interval e2Left, e2Right;
                    if (
                        !TryEvalWithCache(this, e2, this_Bounds, out e2Left) ||
                        !TryEvalWithCache(other, e2, other_Bounds, out e2Right))
                    {
                        continue;
                    }

                    if (oct)
                    {
                        #region Adding octogonal constraints to get at least as much precision as octagons

                        var monomials = new Monomial <Variable>[] { new Monomial <Variable>(e1), new Monomial <Variable>(-1, e2), new Monomial <Variable>(slack) };

                        Polynomial <Variable, Expression> pol;
                        if (!Polynomial <Variable, Expression> .TryToPolynomialForm(true, monomials, out pol))
                        {
                            throw new AbstractInterpretationException("Impossible case");
                        }

                        result.Add(pol);

                        #endregion
                    }


                    if (CH)
                    {
                        #region Convex Hull

                        // adaptation of the Monotone Chain algorithm

                        var vertices = new PairNonNull <Rational, Rational>[8]
                        {
                            new PairNonNull <Rational, Rational>(e1Left.LowerBound, e2Left.LowerBound),
                            new PairNonNull <Rational, Rational>(e1Left.LowerBound, e2Left.UpperBound),
                            new PairNonNull <Rational, Rational>(e1Left.UpperBound, e2Left.LowerBound),
                            new PairNonNull <Rational, Rational>(e1Left.UpperBound, e2Left.UpperBound),
                            new PairNonNull <Rational, Rational>(e1Right.LowerBound, e2Right.LowerBound),
                            new PairNonNull <Rational, Rational>(e1Right.LowerBound, e2Right.UpperBound),
                            new PairNonNull <Rational, Rational>(e1Right.UpperBound, e2Right.LowerBound),
                            new PairNonNull <Rational, Rational>(e1Right.UpperBound, e2Right.UpperBound)
                        };

                        try
                        {
                            Array.Sort(vertices,
                                       delegate(PairNonNull <Rational, Rational> x, PairNonNull <Rational, Rational> y)
                            {
                                if ((x.One - y.One).Sign == 0)
                                {
                                    return((x.Two - y.Two).Sign);
                                }
                                else
                                {
                                    return((x.One - y.One).Sign);
                                }
                            });
                        }
                        catch (InvalidOperationException)
                        {
                            return(result);
                        }

                        var IsInHull = new bool[8];
                        try
                        {
                            Polynomial <Variable, Expression> pol;
                            #region Computation of the Lower Hull
                            IsInHull[0] = IsFinite(vertices[0]);
                            IsInHull[2] = IsFinite(vertices[2]);
                            IsInHull[4] = IsFinite(vertices[4]);

                            if (IsInHull[0] && IsInHull[2] && IsInHull[4] &&
                                (vertices[2].One - vertices[0].One) * (vertices[4].Two - vertices[0].Two) <= (vertices[4].One - vertices[0].One) * (vertices[2].Two - vertices[0].Two))
                            {
                                IsInHull[2] = false;
                            }

                            IsInHull[6] = IsFinite(vertices[6]);

                            if (IsInHull[2] && IsInHull[4] && IsInHull[6] &&
                                (vertices[4].One - vertices[2].One) * (vertices[6].Two - vertices[2].Two) <= (vertices[6].One - vertices[2].One) * (vertices[4].Two - vertices[2].Two))
                            {
                                IsInHull[4] = false;
                            }

                            if (IsInHull[0] && IsInHull[4] && IsInHull[6] &&
                                (vertices[4].One - vertices[0].One) * (vertices[6].Two - vertices[0].Two) <= (vertices[6].One - vertices[0].One) * (vertices[4].Two - vertices[0].Two))
                            {
                                IsInHull[4] = false;
                            }

                            if (IsInHull[0] && IsInHull[2] && IsInHull[6] &&
                                (vertices[2].One - vertices[0].One) * (vertices[6].Two - vertices[0].Two) <= (vertices[6].One - vertices[0].One) * (vertices[2].Two - vertices[0].Two))
                            {
                                IsInHull[2] = false;
                            }
                            #endregion

                            #region Computation of the Upper Hull
                            IsInHull[1] = IsFinite(vertices[1]);

                            IsInHull[3] = IsFinite(vertices[3]);

                            IsInHull[5] = IsFinite(vertices[5]);

                            if (IsInHull[1] && IsInHull[3] && IsInHull[5] &&
                                (vertices[3].One - vertices[1].One) * (vertices[5].Two - vertices[1].Two) >= (vertices[5].One - vertices[1].One) * (vertices[3].Two - vertices[1].Two))
                            {
                                IsInHull[3] = false;
                            }

                            IsInHull[7] = IsFinite(vertices[7]);

                            if (IsInHull[3] && IsInHull[5] && IsInHull[7] &&
                                (vertices[5].One - vertices[3].One) * (vertices[7].Two - vertices[3].Two) >= (vertices[7].One - vertices[3].One) * (vertices[5].Two - vertices[3].Two))
                            {
                                IsInHull[5] = false;
                            }

                            if (IsInHull[1] && IsInHull[5] && IsInHull[7] &&
                                (vertices[5].One - vertices[1].One) * (vertices[7].Two - vertices[1].Two) >= (vertices[7].One - vertices[1].One) * (vertices[5].Two - vertices[1].Two))
                            {
                                IsInHull[5] = false;
                            }

                            if (IsInHull[1] && IsInHull[3] && IsInHull[7] &&
                                (vertices[3].One - vertices[1].One) * (vertices[7].Two - vertices[1].Two) >= (vertices[7].One - vertices[1].One) * (vertices[3].Two - vertices[1].Two))
                            {
                                IsInHull[3] = false;
                            }
                            #endregion

                            #region Removing points that are in the hull of the subset of finite points but not in the hull due to infinite extreme points
                            int index = 0;
                            var value = Rational.For(0);

                            if (vertices[0].One.IsInfinity)
                            {
                                index = 2;
                                value = vertices[2].Two;
                                for (int n = 4; n < 8; n += 2)
                                {
                                    if (vertices[n].Two <= value)
                                    {
                                        for (int m = index; m < n; m += 2)
                                        {
                                            IsInHull[m] = false;
                                        }
                                        index = n;
                                        value = vertices[n].Two;
                                    }
                                }
                            }

                            if (vertices[6].One.IsInfinity)
                            {
                                index = 4;
                                value = vertices[4].Two;
                                for (int n = 2; n >= 0; n -= 2)
                                {
                                    if (vertices[n].Two <= value)
                                    {
                                        for (int m = index; m > n; m -= 2)
                                        {
                                            IsInHull[m] = false;
                                        }
                                        index = n;
                                        value = vertices[n].Two;
                                    }
                                }
                            }

                            if (vertices[1].One.IsInfinity)
                            {
                                index = 3;
                                value = vertices[3].Two;
                                for (int n = 5; n < 8; n += 2)
                                {
                                    if (vertices[n].Two >= value)
                                    {
                                        for (int m = index; m < n; m += 2)
                                        {
                                            IsInHull[m] = false;
                                        }
                                        index = n;
                                        value = vertices[n].Two;
                                    }
                                }
                            }

                            if (vertices[7].One.IsInfinity)
                            {
                                index = 5;
                                value = vertices[5].Two;
                                for (int n = 3; n >= 0; n -= 2)
                                {
                                    if (vertices[n].Two >= value)
                                    {
                                        for (int m = index; m > n; m -= 2)
                                        {
                                            IsInHull[m] = false;
                                        }
                                        index = n;
                                        value = vertices[n].Two;
                                    }
                                }
                            }
                            #endregion

                            #region Adding to the result the Polynomials for the edges that are in the hull and neither horizontal nor vertical
                            var      point = new PairNonNull <Rational, Rational>();
                            Rational c;
                            int      numberOfPointsInHull = 0;

                            for (int k = 0; k < 8; k += 2)
                            {
                                if (IsInHull[k])
                                {
                                    if (numberOfPointsInHull > 0 && point.One != vertices[k].One && point.Two != vertices[k].Two)
                                    {
                                        try
                                        {
                                            c = (vertices[k].One - point.One) / (point.Two - vertices[k].Two);
                                        }
                                        catch (ArithmeticExceptionRational)
                                        {
                                            continue;
                                        }

                                        var list = new Monomial <Variable>[] { new Monomial <Variable>(e1), new Monomial <Variable>(c, e2), new Monomial <Variable>(slack) };

                                        if (!Polynomial <Variable, Expression> .TryToPolynomialForm(true, list, out pol))
                                        {
                                            throw new AbstractInterpretationException("Impossible case");
                                        }
                                        result.Add(pol);
                                    }
                                    point = vertices[k];
                                    numberOfPointsInHull++;
                                }
                            }
                            for (int k = 1; k < 8; k += 2)
                            {
                                if (IsInHull[k])
                                {
                                    if (numberOfPointsInHull > 0 && point.One != vertices[k].One && point.Two != vertices[k].Two)
                                    {
                                        try
                                        {
                                            c = (vertices[k].One - point.One) / (point.Two - vertices[k].Two);
                                        }
                                        catch (ArithmeticExceptionRational)
                                        {
                                            continue;
                                        }

                                        var list = new Monomial <Variable>[] { new Monomial <Variable>(e1), new Monomial <Variable>(c, e2), new Monomial <Variable>(slack) };

                                        if (!Polynomial <Variable, Expression> .TryToPolynomialForm(true, list, out pol))
                                        {
                                            throw new AbstractInterpretationException("Impossible case");
                                        }

                                        result.Add(pol);
                                    }
                                    point = vertices[k];
                                    numberOfPointsInHull++;
                                }
                            }
                            #endregion
                        }
                        catch (ArithmeticExceptionRational)
                        {
                            // Ignore the constraint
                        }
                        #endregion
                    }
                }
            }
            return(result);
        }