private static ProofOutcome SimplifyInternal <Local, Parameter, Method, Field, Property, Event, Type, Attribute, Assembly, Expression, Variable, LogOptions>
        (
            BoxedExpression exp,
            INumericalAbstractDomain <BoxedVariable <Variable>, BoxedExpression> oracle,
            IMethodDriver <Local, Parameter, Method, Field, Property, Event, Type, Attribute, Assembly, Expression, Variable, LogOptions> mdriver,
            out BoxedExpression simplified
        )
            where Expression : IEquatable <Expression>
            where Variable : IEquatable <Variable>
            where LogOptions : IFrameworkLogOptions
            where Type : IEquatable <Type>
        {
            BinaryOperator  bop;
            BoxedExpression left, right;

            if (exp.IsBinaryExpression(out bop, out left, out right))
            {
                BoxedExpression simplifiedLeft, simplifiedRight;
                switch (bop)
                {
                case BinaryOperator.LogicalAnd:
                {
                    var tLeft = SimplifyInternal(left, oracle, mdriver, out simplifiedLeft);
                    if (tLeft == ProofOutcome.False)
                    {
                        simplified = BoxedExpression.Const(0, mdriver.MetaDataDecoder.System_Boolean, mdriver.MetaDataDecoder);
                        return(ProofOutcome.False);
                    }

                    var tRight = SimplifyInternal(right, oracle, mdriver, out simplifiedRight);
                    if (tRight == ProofOutcome.False)
                    {
                        simplified = BoxedExpression.Const(0, mdriver.MetaDataDecoder.System_Boolean, mdriver.MetaDataDecoder);
                        return(ProofOutcome.False);
                    }

                    if (tLeft == ProofOutcome.True)
                    {
                        simplified = simplifiedRight;
                        return(tRight);
                    }

                    if (tRight == ProofOutcome.True)
                    {
                        simplified = simplifiedLeft;
                        return(tLeft);
                    }

                    simplified = BoxedExpression.BinaryLogicalAnd(simplifiedLeft, simplifiedRight);
                    return(ProofOutcome.Top);
                }

                case BinaryOperator.LogicalOr:
                {
                    var tLeft = SimplifyInternal(left, oracle, mdriver, out simplifiedLeft);
                    if (tLeft == ProofOutcome.True)
                    {
                        simplified = BoxedExpression.Const(1, mdriver.MetaDataDecoder.System_Boolean, mdriver.MetaDataDecoder);
                        return(ProofOutcome.True);
                    }

                    var tRight = SimplifyInternal(right, oracle, mdriver, out simplifiedRight);
                    if (tRight == ProofOutcome.True)
                    {
                        simplified = BoxedExpression.Const(1, mdriver.MetaDataDecoder.System_Boolean, mdriver.MetaDataDecoder);
                        return(ProofOutcome.True);
                    }

                    if (tLeft == ProofOutcome.False)
                    {
                        simplified = simplifiedRight;
                        return(tRight);
                    }

                    if (tRight == ProofOutcome.False)
                    {
                        simplified = simplifiedLeft;
                        return(tLeft);
                    }

                    simplified = BoxedExpression.BinaryLogicalOr(simplifiedLeft, simplifiedRight);
                    return(ProofOutcome.Top);
                }

                case BinaryOperator.Ceq:
                {
                    var r = oracle.CheckIfEqual(left, right);

                    return(ProcessOutcome(r, exp, mdriver, out simplified));
                }

                case BinaryOperator.Cge:
                case BinaryOperator.Cge_Un:
                {
                    var r = oracle.CheckIfLessEqualThan(right, left);

                    return(ProcessOutcome(r, exp, mdriver, out simplified));
                }

                case BinaryOperator.Cgt:
                case BinaryOperator.Cgt_Un:
                {
                    var r = oracle.CheckIfLessThan(right, left);

                    return(ProcessOutcome(r, exp, mdriver, out simplified));
                }

                case BinaryOperator.Cle:
                case BinaryOperator.Cle_Un:
                {
                    var r = oracle.CheckIfLessEqualThan(left, right);

                    return(ProcessOutcome(r, exp, mdriver, out simplified));
                }

                case BinaryOperator.Clt:
                case BinaryOperator.Clt_Un:
                {
                    var r = oracle.CheckIfLessThan(left, right);

                    return(ProcessOutcome(r, exp, mdriver, out simplified));
                }

                case BinaryOperator.Cne_Un:
                {
                    var r1 = oracle.CheckIfLessThan(left, right);

                    if (r1.IsNormal())
                    {
                        simplified = BoxedExpression.Const(1, mdriver.MetaDataDecoder.System_Boolean, mdriver.MetaDataDecoder);
                        return(ProofOutcome.True);
                    }

                    var r2 = oracle.CheckIfLessThan(right, left);
                    if (r2.IsNormal())
                    {
                        simplified = BoxedExpression.Const(1, mdriver.MetaDataDecoder.System_Boolean, mdriver.MetaDataDecoder);
                        return(ProofOutcome.True);
                    }

                    simplified = exp;
                    return(ProofOutcome.Top);
                }
                }
            }

            if (exp.IsUnary)
            {
                var r = oracle.CheckIfHolds(exp);
                if (r.IsTrue())
                {
                    simplified = BoxedExpression.Const(1, mdriver.MetaDataDecoder.System_Boolean, mdriver.MetaDataDecoder);
                    return(ProofOutcome.True);
                }
                if (r.IsFalse())
                {
                    simplified = BoxedExpression.Const(0, mdriver.MetaDataDecoder.System_Boolean, mdriver.MetaDataDecoder);
                    return(ProofOutcome.False);
                }
            }

            simplified = exp;
            return(ProofOutcome.Top);
        }