public static Set <BoxedExpression> ConstantsIfLinearExpression(BoxedExpression exp)
            {
                Contract.Requires(exp != null);
                var visitor = new ConstantsInBoxedExpression();

                exp.Dispatch(visitor);

                Set <BoxedExpression> result;

                if (!visitor.TryGetConstants(out result))
                {
                    result = null;
                }

                return(result);
            }
        public bool TryMostGeneralSatisfaction(BoxedExpression input, BoxedExpression var, out BoxedExpression result)
        {
            BinaryOperator  bop;
            BoxedExpression left, right;

            if (input.IsBinaryExpression(out bop, out left, out right) && bop.IsComparisonBinaryOperator())
            {
                var leftVars  = left.Variables();
                var rightVars = right.Variables();

                var vIsLeft  = (leftVars.Count == 1 && rightVars.Count == 0);
                var vIsRight = (leftVars.Count == 0 && rightVars.Count == 1);
                if (vIsLeft || vIsRight)
                {
                    // do the swap
                    if (vIsLeft && bop.TryInvert(out bop))
                    {
                        var tmp = right;
                        right = left;
                        left  = tmp;
                    }

                    // Invariant:
                    //    + left has no variables
                    //    + right has exactly one variable

                    // Build a new expression
                    var newLeft = left.Sub(ConstantsInBoxedExpression.ConstantsIfLinearExpression(right)).EvaluateConstants(this.MetaDataDecoder);
                    if (newLeft != null)
                    {
                        var newRight = rightVars.PickAnElement();
                    }

                    switch (bop)
                    {
                    case BinaryOperator.Ceq:
                    case BinaryOperator.Cge:
                    case BinaryOperator.Cge_Un:
                    case BinaryOperator.Cle:
                    case BinaryOperator.Cle_Un:
                    {
                        result = newLeft.EvaluateConstants(this.MetaDataDecoder);
                        return(true);
                    }

                    case BinaryOperator.Cgt:
                    case BinaryOperator.Cgt_Un:
                    {
                        // k > x ==> x == k -1
                        result = MinusOne(newLeft);
                        return(true);
                    }

                    case BinaryOperator.Clt:
                    case BinaryOperator.Clt_Un:
                    { // k < x ==> x == k+1
                        result = PlusOne(newLeft);
                        return(true);
                    }
                    }
                }
                if (leftVars.Count == 1 && rightVars.Count == 1)
                {
                    left  = leftVars.PickAnElement();
                    right = rightVars.PickAnElement();

                    if (left.Equals(var) && bop.TryInvert(out bop))
                    {
                        left  = right;
                        right = var;
                    }

                    // invariant the invariant is on the right
                    if (right.Equals(var))
                    {
                        // TODO: merge with the switch above
                        switch (bop)
                        {
                        case BinaryOperator.Ceq:
                        case BinaryOperator.Cge:
                        case BinaryOperator.Cge_Un:
                        case BinaryOperator.Cle:
                        case BinaryOperator.Cle_Un:
                        {
                            result = left;
                            return(true);
                        }

                        case BinaryOperator.Cgt:
                        case BinaryOperator.Cgt_Un:
                        {
                            // k > x ==> x == k -1
                            result = MinusOne(left);
                            return(true);
                        }

                        case BinaryOperator.Clt:
                        case BinaryOperator.Clt_Un:
                        { // k < x ==> x == k+1
                            result = PlusOne(right);
                            return(true);
                        }
                        }
                    }
                }
            }

            result = null;
            return(false);
        }