protected ArraySegmentation <Elements, BoxedVariable <Variable>, BoxedExpression> MaterializeArray <Elements>(
                    APC postPC, ArraySegmentationEnvironment <Elements, BoxedVariable <Variable>, BoxedExpression> preState,
                    Func <BoxedExpression, FlatAbstractDomain <bool> > CheckIfNonZero, Variable arrayValue, Elements initialValue, Elements bottom)
                    where Elements : class, IAbstractDomainForArraySegmentationAbstraction <Elements, BoxedVariable <Variable> >
                {
                    Contract.Requires(preState != null);
                    Contract.Requires(initialValue != null);

                    var boxSym = new BoxedVariable <Variable>(arrayValue);

                    ArraySegmentation <Elements, BoxedVariable <Variable>, BoxedExpression> arraySegment;

                    if (preState.TryGetValue(boxSym, out arraySegment))
                    {
                        return(arraySegment); // already materialized
                    }

                    Variable array_Length;

                    if (this.Context.ValueContext.TryGetArrayLength(postPC, arrayValue, out array_Length))
                    {
                        var isNonEmpty = CheckIfNonZero(this.ToBoxedExpression(postPC, array_Length)).IsTrue();

                        var limits = new NonNullList <SegmentLimit <BoxedVariable <Variable> > >()
                        {
                            new SegmentLimit <BoxedVariable <Variable> >(NormalizedExpression <BoxedVariable <Variable> > .For(0), false),                                               // { 0 }
                            new SegmentLimit <BoxedVariable <Variable> >(NormalizedExpression <BoxedVariable <Variable> > .For(new BoxedVariable <Variable>(array_Length)), !isNonEmpty) // { symb.Length }
                        };

                        var elements = new NonNullList <Elements>()
                        {
                            initialValue
                        };

                        var newSegment = new ArraySegmentation <Elements, BoxedVariable <Variable>, BoxedExpression>(
                            limits, elements,
                            bottom,
                            this.ExpressionManager);

                        preState.AddElement(new BoxedVariable <Variable>(arrayValue), newSegment);

                        return(newSegment);
                    }

                    return(null);
                }
                public override ArrayState Assume(APC pc, string tag, Variable source, object provenance, ArrayState data)
                {
                    Contract.Assume(data != null);

                    if (tag != "false")
                    {
                        data = this.Assert(pc, "assume", source, provenance, data);

                        Contract.Assert(data != null);

                        var convertedExp = ToBoxedExpression(pc, source);

                        if (convertedExp == null)
                        {
                            // abort
                            return(data);
                        }

                        Variable        v1, v2;
                        BoxedExpression bLeft, bRight, x;
                        int             k;
                        if (convertedExp.IsCheckExp1EqExp2(out bLeft, out bRight) && // bLeft == bRight
                            bRight.IsCheckExp1EqConst(out x, out k) &&                  // bRight == x + 1
                            bLeft.TryGetFrameworkVariable(out v1) &&
                            x.TryGetFrameworkVariable(out v2)
                            )
                        {
                            var vNormExp = NormalizedExpression <BoxedVariable <Variable> > .For(new BoxedVariable <Variable>(v1));

                            var sumNormExp = NormalizedExpression <BoxedVariable <Variable> > .For(new BoxedVariable <Variable>(v2), k);

                            var mySubState = Select(data);
                            mySubState = mySubState.TestTrueEqualAsymmetric(vNormExp, sumNormExp);
                            mySubState = mySubState.TestTrueEqualAsymmetric(sumNormExp, vNormExp);

                            data = data.UpdatePluginAt(this.Id, mySubState);
                        }
                    }

                    return(data.UpdatePluginAt(this.Id, Select(data).ReduceWith(data.Numerical)));
                }
                public override ArrayState Binary(APC pc, BinaryOperator op, Variable dest, Variable s1, Variable s2, ArrayState data)
                {
                    Variable var;
                    int      k;

                    if (TryMatchVariableConstant(pc, op, Strip(pc, s1), Strip(pc, s2), data.Numerical, out var, out k) && k != Int32.MinValue)
                    {
                        var mySubState = Select(data);

                        var normExpression = NormalizedExpression <BoxedVariable <Variable> > .For(new BoxedVariable <Variable>(var), k);

                        var normVariable = NormalizedExpression <BoxedVariable <Variable> > .For(new BoxedVariable <Variable>(dest));

                        var array = mySubState.TestTrueEqualAsymmetric(normVariable, normExpression);

                        normExpression = NormalizedExpression <BoxedVariable <Variable> > .For(new BoxedVariable <Variable>(dest), -k);

                        normVariable = NormalizedExpression <BoxedVariable <Variable> > .For(new BoxedVariable <Variable>(var));

                        return(data.UpdatePluginAt(this.Id, mySubState.TestTrueEqualAsymmetric(normExpression, normVariable)));
                    }

                    return(data);
                }
                static public NormalizedExpression <BoxedVariable <Variable> > ToNormalizedExpression(Variable v)
                {
                    Contract.Ensures(Contract.Result <NormalizedExpression <BoxedVariable <Variable> > >() != null);

                    return(NormalizedExpression <BoxedVariable <Variable> > .For(new BoxedVariable <Variable>(v)));
                }
                ArrayCounterInitialization <AbstractDomain>(APC pc, Local local,
                                                            Variable source, ArrayState resultState, ArraySegmentationEnvironment <AbstractDomain, BoxedVariable <Variable>, BoxedExpression> mySubState)
                    where AbstractDomain : class, IAbstractDomainForArraySegmentationAbstraction <AbstractDomain, BoxedVariable <Variable> >
                {
                    Contract.Ensures(Contract.Result <ArraySegmentationEnvironment <AbstractDomain, BoxedVariable <Variable>, BoxedExpression> >() != null);

                    var sourceExp = ToBoxedExpression(pc, source);

                    // we look for loop initializations i == var
                    Variable localValue;

                    if (sourceExp.IsVariable
                        &&
                        this.Context.ValueContext.TryLocalValue(this.Context.MethodContext.CFG.Post(pc), local, out localValue))
                    {
                        // If source >= 0, we check if source <= arr.Length, for some array 'arr'
                        // If this is the case, then we can try to refine the segmentation including source and locValue
                        if (resultState.Numerical.CheckIfGreaterEqualThanZero(sourceExp).IsTrue())
                        {
                            var sourceNorm = ToNormalizedExpression(source);

                            var toUpdate = new Dictionary <BoxedVariable <Variable>, ArraySegmentation <AbstractDomain, BoxedVariable <Variable>, BoxedExpression> >();

                            foreach (var pair in mySubState.Elements)
                            {
                                if (!pair.Value.IsEmptyArray && pair.Value.IsNormal
                                    &&
                                    // We do the trick only for arrays {0} val {Len} as otherwise we should be more careful where we refine the segmentation, as for instance the update below may be too rough. However, I haven't find any interesting non-artificial example for it
                                    pair.Value.Elements.Count() == 1)
                                {
                                    foreach (var limit in pair.Value.LastLimit)
                                    {
                                        if (resultState.Numerical.CheckIfLessEqualThan(sourceExp, limit.Convert(this.Encoder)).IsTrue())
                                        {
                                            IAbstractDomain abstractValue;
                                            if (pair.Value.TryGetAbstractValue(
                                                    NormalizedExpression <BoxedVariable <Variable> > .For(0), sourceNorm,
                                                    resultState.Numerical,
                                                    out abstractValue)
                                                &&
                                                abstractValue is AbstractDomain)
                                            {
                                                ArraySegmentation <AbstractDomain, BoxedVariable <Variable>, BoxedExpression> newSegment;
                                                if (pair.Value.TrySetAbstractValue(sourceNorm, (AbstractDomain)abstractValue, resultState.Numerical,
                                                                                   out newSegment))
                                                {
                                                    toUpdate.Add(pair.Key, newSegment);
                                                    break; // We've already updated this segmentation
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            foreach (var pair in toUpdate)
                            {
                                mySubState[pair.Key] = pair.Value;
                            }
                        }
                    }
                    return(mySubState);
                }
                protected ArrayState UpdateArrayAbstractValue(APC pc, BoxedVariable <Variable> arr, NormalizedExpression <BoxedVariable <Variable> > index,
                                                              NonRelationalValueAbstraction <BoxedVariable <Variable>, BoxedExpression> ael, ArrayState prevState)
                {
                    Contract.Requires(prevState != null);
                    Contract.Ensures(Contract.Result <ArrayState>() != null);

                    ArraySegmentation <NonRelationalValueAbstraction <BoxedVariable <Variable>, BoxedExpression>, BoxedVariable <Variable>, BoxedExpression>
                    prev, updated;

                    if (prevState.Array.TryGetValue(arr, out prev))
                    {
                        if (index != null)
                        {
                            IAbstractDomain prevAel;

                            if (prev.TryGetAbstractValue(index, prevState.Numerical, out prevAel) &&
                                prevAel is NonRelationalValueAbstraction <BoxedVariable <Variable>, BoxedExpression> )
                            {
                                ael = ael.Meet(prevAel as NonRelationalValueAbstraction <BoxedVariable <Variable>, BoxedExpression>);
                            }

                            if (prev.TrySetAbstractValue(index, ael, prevState.Numerical, out updated))
                            {
                                prevState.Array[arr] = updated;
                            }
                        }
                    }

                    return(prevState);
                }
                protected bool TryCreateArraySegment(BoxedExpression low, BoxedExpression upp, Variable arrayLen,
                                                     AbstractDomain intv,
                                                     INumericalAbstractDomain <BoxedVariable <Variable>, BoxedExpression> numDom,
                                                     out ArraySegmentation <AbstractDomain, BoxedVariable <Variable>, BoxedExpression> arraySegmentation)
                {
                    #region Contracts

                    Contract.Requires(low != null);
                    Contract.Requires(upp != null);
                    Contract.Requires(intv != null);
                    Contract.Requires(arrayLen != null);
                    Contract.Requires(numDom != null);

                    Contract.Ensures(!Contract.Result <bool>() || Contract.ValueAtReturn(out arraySegmentation) != null);

                    #endregion

                    var lowerBounds = new Set <NormalizedExpression <BoxedVariable <Variable> > >();

                    lowerBounds.AddIfNotNull(low.ToNormalizedExpression <Variable>());

                    var upperBounds = new Set <NormalizedExpression <BoxedVariable <Variable> > >();

                    upperBounds.AddIfNotNull(upp.ToNormalizedExpression <Variable>());
                    upperBounds.AddIfNotNull(upp.ToNormalizedExpression <Variable>(true));
                    upperBounds.AddIfNotNull(upp.Simplify(this.DecoderForMetaData).ToNormalizedExpression <Variable>());
                    upperBounds.AddIfNotNull(this.Decoder.Stripped(upp).ToNormalizedExpression <Variable>());

                    if (lowerBounds.Count == 0 || upperBounds.Count == 0)
                    {
                        arraySegmentation = null;
                        return(false);
                    }

                    var segments = new NonNullList <SegmentLimit <BoxedVariable <Variable> > >();

                    var elements = new NonNullList <AbstractDomain>();

                    #region Build the prefix

                    // Check if low is zero
                    int lowValue;
                    if (low.IsConstantInt(out lowValue))
                    {
                        if (lowValue < 0)
                        {
                            arraySegmentation = default(ArraySegmentation <AbstractDomain, BoxedVariable <Variable>, BoxedExpression>);
                            return(false);
                        }

                        // { 0 } Top { lowValue }
                        if (lowValue > 0)
                        {
                            segments.Add(new SegmentLimit <BoxedVariable <Variable> >(NormalizedExpression <BoxedVariable <Variable> > .For(0), false));
                            elements.Add((AbstractDomain)intv.Top);
                        }

                        //  .. { lowValue } intv
                        segments.Add(new SegmentLimit <BoxedVariable <Variable> >(lowerBounds, false));
                        elements.Add(intv);
                    }
                    else if (numDom.CheckIfGreaterEqualThanZero(low).IsTrue())
                    {
                        // { 0 } Top { low }?
                        segments.Add(new SegmentLimit <BoxedVariable <Variable> >(NormalizedExpression <BoxedVariable <Variable> > .For(0), false));
                        elements.Add((AbstractDomain)intv.Top);

                        // intv { upp }?
                        segments.Add(new SegmentLimit <BoxedVariable <Variable> >(lowerBounds, true)); // F: we can improve precision by asking if low != 0
                        elements.Add(intv);
                    }
                    else
                    {
                        arraySegmentation = default(ArraySegmentation <AbstractDomain, BoxedVariable <Variable>, BoxedExpression>);
                        return(false);
                    }

                    #endregion

                    #region Build the suffix
                    // ... { upperBounds }
                    if (arrayLen.Equals(upp.UnderlyingVariable) || arrayLen.Equals(this.Decoder.Stripped(upp).UnderlyingVariable))
                    {
                        segments.Add(new SegmentLimit <BoxedVariable <Variable> >(upperBounds, false));
                    }
                    else // ... { upperBounds } Top { arrayLen }?
                    {
                        segments.Add(new SegmentLimit <BoxedVariable <Variable> >(upperBounds, false));
                        elements.Add((AbstractDomain)intv.Top);
                        segments.Add(
                            new SegmentLimit <BoxedVariable <Variable> >(
                                NormalizedExpression <BoxedVariable <Variable> > .For(new BoxedVariable <Variable>(arrayLen)), true));
                    }
                    #endregion

                    arraySegmentation = new ArraySegmentation <AbstractDomain, BoxedVariable <Variable>, BoxedExpression>(
                        segments, elements,
                        (AbstractDomain)intv.Bottom, this.ExpressionManager);

                    return(true);
                }
                public override ArrayState Stelem(
                    APC pc, Type type, Variable array, Variable index, Variable value, ArrayState data)
                {
                    Contract.Assume(data != null);

                    var state  = Select(data);
                    var bArray = new BoxedVariable <Variable>(array);

                    ArraySegmentation <TwoValuesLattice <BoxedVariable <Variable> >, BoxedVariable <Variable>, BoxedExpression> segment, newSegment;

                    if (state.TryGetValue(bArray, out segment))
                    {
                        var indexExp     = ToBoxedExpression(pc, index);
                        var indexNormExp = indexExp.ToNormalizedExpression <Variable>();

                        if (indexNormExp == null)
                        {
                            // Try to find a numerical bounds
                            var indexValue = data.Numerical.BoundsFor(indexExp).AsInterval;
                            if (indexValue.IsSingleton && indexValue.LowerBound.IsInteger)
                            {
                                indexNormExp = NormalizedExpression <BoxedVariable <Variable> > .For((Int32)indexValue.LowerBound);

                                Contract.Assert(indexNormExp != null);
                            }
                            else
                            {
                                // We have a range of addresses
                                Int32 low, upp;
                                if (indexValue.IsFiniteAndInt32(out low, out upp))
                                {
                                    var lowExp = NormalizedExpression <BoxedVariable <Variable> > .For(low);

                                    var uppExp = NormalizedExpression <BoxedVariable <Variable> > .For(upp);

                                    if (segment.TrySetAbstractValue(lowExp, uppExp,
                                                                    MAYBEMODIFIED,
                                                                    data.Numerical, out newSegment))
                                    {
                                        state.Update(new BoxedVariable <Variable>(array), newSegment);

                                        return(data.UpdatePluginAt(this.Id, state));
                                    }
                                }
                                state.RemoveElement(new BoxedVariable <Variable>(array));

                                return(data.UpdatePluginAt(this.Id, state));
                            }
                        }

                        if (segment.TrySetAbstractValue(indexNormExp, MAYBEMODIFIED, data.Numerical, out newSegment))
                        {
                            // We explicty add the constant for indexNormExp, if we have one
                            Rational val;
                            if (data.Numerical.BoundsFor(indexExp).TryGetSingletonValue(out val) && val.IsInteger)
                            {
                                var k = (Int32)val;
                                // Add k == indexNormExp
                                newSegment = newSegment.TestTrueEqualAsymmetric(NormalizedExpression <BoxedVariable <Variable> > .For(k), indexNormExp);
                            }

                            // Add the sv = constants informations
                            newSegment = newSegment.TestTrueWithIntConstants(data.Numerical.IntConstants.ToNormalizedExpressions());

                            state.Update(new BoxedVariable <Variable>(array), newSegment);
                        }
                        else // For some reason, we were unable to set the abstract value, so we smash all the array to one
                        {
                            state.RemoveElement(new BoxedVariable <Variable>(array));
                        }
                    }

                    return(data.UpdatePluginAt(this.Id, state));
                }