/// <summary>
        /// Evaluates expression with variable equal to var's lowerbound or upperbound.
        /// </summary>
        /// <param name="expr"></param>
        /// <param name="var"></param>
        /// <param name="intv"></param>
        /// <returns></returns>
        TInterval EvalWithExtremes(TExpr expr, TVar var, TInterval intv)
        {
            var evaluator = new EvaluateExpressionVisitor <IntervalEnvironmentBase <TVar, TExpr, TInterval, TNumeric>, TVar, TExpr, TInterval, TNumeric> (Decoder);

            var envLowerBound = With(var, Context.For(intv.LowerBound));
            // replace current intv with it's only lowerbound
            var withLowerBound = evaluator.Visit(expr, new Counter <IntervalEnvironmentBase <TVar, TExpr, TInterval, TNumeric> > (envLowerBound));

            var envUpperBound = With(var, Context.For(intv.UpperBound));
            // replace current intv with it's only upperBound
            var withUpperBound = evaluator.Visit(expr, new Counter <IntervalEnvironmentBase <TVar, TExpr, TInterval, TNumeric> > (envUpperBound));

            return(withLowerBound.Join(withUpperBound));
        }
        public TInterval Eval(TExpr expr)
        {
            int intValue;

            if (Decoder.IsConstantInt(expr, out intValue))
            {
                return(Context.For(intValue));
            }

            var evaluator = new EvaluateExpressionVisitor <IntervalEnvironmentBase <TVar, TExpr, TInterval, TNumeric>, TVar, TExpr, TInterval, TNumeric> (Decoder);
            var interval  = evaluator.Visit(expr, new Counter <IntervalEnvironmentBase <TVar, TExpr, TInterval, TNumeric> > (this));

            if (evaluator.DuplicatedOccurences.Length() >= 1)
            {
                var       noDuplicates = true;
                TInterval result       = null;
                foreach (var var in evaluator.DuplicatedOccurences.AsEnumerable())
                {
                    TInterval intv;
                    if (TryGetValue(var, out intv) && intv.IsFinite &&
                        Context.IsGreaterEqualThanZero(intv.LowerBound))
                    {
                        var extreme = EvalWithExtremes(expr, var, intv);
                        if (noDuplicates)
                        {
                            noDuplicates = false;
                            result       = extreme;
                        }
                        else
                        {
                            result = result.Join(extreme);
                        }
                    }
                }

                if (!noDuplicates)
                {
                    interval = result;
                }
            }

            return(interval);
        }