//-----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All Rights Reserved.
//
//-----------------------------------------------------------------------------
using System;
using System.Collections;
using System.Compiler.Analysis;
using Microsoft.AbstractInterpretationFramework.Collections;
using Microsoft.Contracts;
using Microsoft.Basetypes;
/////////////////////////////////////////////////////////////////////////////////
// An implementation of the interval abstract domain
/////////////////////////////////////////////////////////////////////////////////
namespace Microsoft.AbstractInterpretationFramework
{
public class IntervalLattice : MicroLattice
{
readonly ILinearExprFactory! factory;
public IntervalLattice(ILinearExprFactory! factory)
{
this.factory = factory;
// base();
}
public override bool UnderstandsBasicArithmetics
{
get
{
return true;
}
}
public override Element! Top
{
get
{
return IntervalElement.Top;
}
}
public override Element! Bottom
{
get
{
return IntervalElement.Bottom;
}
}
///
/// The paramter is the top?
///
public override bool IsTop(Element! element)
{
IntervalElement interval = (IntervalElement) element;
return interval.IsTop();
}
///
/// The parameter is the bottom?
///
public override bool IsBottom(Element! element)
{
IntervalElement interval = (IntervalElement) element;
return interval.IsBottom();
}
///
/// The classic, pointwise, join of intervals
///
public override Element! NontrivialJoin(Element! left, Element! right)
{
IntervalElement! leftInterval = (IntervalElement!) left;
IntervalElement! rightInterval = (IntervalElement) right;
ExtendedInt inf = ExtendedInt.Inf(leftInterval.Inf, rightInterval.Inf);
ExtendedInt sup = ExtendedInt.Sup(leftInterval.Sup, rightInterval.Sup);
IntervalElement! join = IntervalElement.Factory(inf, sup);
return join;
}
///
/// The classic, pointwise, meet of intervals
///
public override Element! NontrivialMeet(Element! left, Element! right)
{
IntervalElement! leftInterval = (IntervalElement!) left;
IntervalElement! rightInterval = (IntervalElement) right;
ExtendedInt inf = ExtendedInt.Sup(leftInterval.Inf, rightInterval.Inf);
ExtendedInt sup = ExtendedInt.Inf(leftInterval.Sup, rightInterval.Sup);
return IntervalElement.Factory(inf, sup);
}
///
/// The very simple widening of intervals, to be improved with thresholds
/// left is the PREVIOUS value in the iterations and right is the NEW one
///
public override Element! Widen(Element! left, Element! right)
{
IntervalElement! prevInterval = (IntervalElement!) left;
IntervalElement! nextInterval = (IntervalElement!) right;
ExtendedInt inf = nextInterval.Inf < prevInterval.Inf ? ExtendedInt.MinusInfinity : prevInterval.Inf;
ExtendedInt sup = nextInterval.Sup > prevInterval.Sup ? ExtendedInt.PlusInfinity : prevInterval.Sup;
IntervalElement widening = IntervalElement.Factory(inf, sup);
return widening;
}
///
/// Return true iff the interval left is containted in right
///
protected override bool AtMost(Element! left, Element! right)
{
IntervalElement! leftInterval = (IntervalElement!) left;
IntervalElement! rightInterval = (IntervalElement!) right;
if(leftInterval.IsBottom() || rightInterval.IsTop())
return true;
return rightInterval.Inf <= leftInterval.Inf && leftInterval.Sup <= rightInterval.Sup;
}
///
/// Return just null
///
public override IExpr GetFoldExpr(Element! element)
{
return null;
}
///
/// return a predicate inf "\leq x and x "\leq" sup (if inf [or sup] is not oo)
///
public override IExpr! ToPredicate(IVariable! var, Element! element)
{
IntervalElement! interval = (IntervalElement!) element;
IExpr lowerBound = null;
IExpr upperBound = null;
if(! (interval.Inf is InfinitaryInt))
{
IExpr constant = this.factory.Const(interval.Inf.Value);
lowerBound = this.factory.AtMost(constant, var); // inf <= var
}
if(! (interval.Sup is InfinitaryInt))
{
IExpr constant = this.factory.Const(interval.Sup.Value);
upperBound = this.factory.AtMost(var, constant); // var <= inf
}
if(lowerBound != null && upperBound != null)
return this.factory.And(lowerBound, upperBound); // inf <= var && var <= sup
else
if(lowerBound != null)
return lowerBound;
else
if(upperBound != null)
return upperBound;
else // If we reach this point, both lowerBound and upperBound are null, i.e. we have no bounds on var, so we return simply true...
return this.factory.True;
}
///
/// For the moment consider just equalities. Other case must be considered
///
public override bool Understands(IFunctionSymbol! f, IList /*
/// Evaluate the predicate passed as input according the semantics of intervals
///
public override Element! EvaluatePredicate(IExpr! pred)
{
return this.EvaluatePredicateWithState(pred, null);
}
///
/// Evaluate the predicate passed as input according the semantics of intervals and the given state.
/// Right now just basic arithmetic operations are supported. A future extension may consider an implementation of boolean predicates
///
public override Element! EvaluatePredicateWithState(IExpr! pred, IFunctionalMap/* Var -> Element */ state)
{
if(pred is IFunApp)
{
IFunApp fun = (IFunApp) pred;
if(fun.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) // if it is a symbol of equality
{
IExpr! leftArg = (IExpr!) fun.Arguments[0];
IExpr! rightArg = (IExpr!) fun.Arguments[1];
if (leftArg is IVariable) {
return Eval(rightArg, state);
} else if (rightArg is IVariable) {
return Eval(leftArg, state);
}
}
}
// otherwise we simply return Top
return IntervalElement.Top;
}
///
/// Evaluate the expression (that is assured to be an arithmetic expression, in the state passed as a parameter
///
private IntervalElement! Eval(IExpr! exp, IFunctionalMap/* Var -> Element */ state)
{
IntervalElement! retVal = (IntervalElement!) Top;
// Eval the expression by structural induction
if(exp is IVariable && state != null) // A variable
{
object lookup = state[exp];
if(lookup is IntervalElement)
retVal = (IntervalElement) lookup;
else
{
retVal = (IntervalElement) Top;
}
}
else if(exp is IFunApp)
{
IFunApp fun = (IFunApp) exp;
if(fun.FunctionSymbol is IntSymbol) // An integer
{
IntSymbol intSymb = (IntSymbol) fun.FunctionSymbol;
BigNum val = intSymb.Value;
retVal = IntervalElement.Factory(val);
}
else if(fun.FunctionSymbol.Equals(Int.Negate)) // An unary minus
{
IExpr! arg = (IExpr!) fun.Arguments[0];
IntervalElement! argEval = Eval(arg, state);
IntervalElement! zero = IntervalElement.Factory(BigNum.ZERO);
retVal = zero - argEval;
}
else if(fun.Arguments.Count == 2)
{
IExpr! left = (IExpr!) fun.Arguments[0];
IExpr! right = (IExpr!) fun.Arguments[1];
IntervalElement! leftVal = Eval(left, state);
IntervalElement! rightVal = Eval(right, state);
if(fun.FunctionSymbol.Equals(Int.Add))
retVal = leftVal + rightVal;
else if(fun.FunctionSymbol.Equals(Int.Sub))
retVal = leftVal - rightVal;
else if(fun.FunctionSymbol.Equals(Int.Mul))
retVal = leftVal * rightVal;
else if(fun.FunctionSymbol.Equals(Int.Div))
retVal = leftVal / rightVal;
else if(fun.FunctionSymbol.Equals(Int.Mod))
retVal = leftVal % rightVal;
}
}
return retVal;
}
///
/// Inner class standing for an interval on integers, possibly unbounded
///
private class IntervalElement : Element
{
protected static readonly IntervalElement! TopInterval = new IntervalElement(new MinusInfinity(), new PlusInfinity()); // Top = [-oo , +oo]
protected static readonly IntervalElement! BottomInterval = new IntervalElement(new PlusInfinity(), new MinusInfinity()); // Bottom = [+oo, -oo]
private readonly ExtendedInt! inf;
private readonly ExtendedInt! sup;
public ExtendedInt! Inf
{
get
{
return inf;
}
}
public ExtendedInt! Sup
{
get
{
return sup;
}
}
// Construct the inteval [val, val]
protected IntervalElement(BigNum val)
{
this.inf = this.sup = ExtendedInt.Factory(val);
// base();
}
// Construct the interval [inf, sup]
protected IntervalElement(BigNum infInt, BigNum supInt)
{
this.inf = ExtendedInt.Factory(infInt);
this.sup = ExtendedInt.Factory(supInt);
// base(); // to please the compiler...
}
protected IntervalElement(ExtendedInt! inf, ExtendedInt! sup)
{
this.inf = inf;
this.sup = sup;
// base();
}
// Construct an Interval
public static IntervalElement! Factory(ExtendedInt! inf, ExtendedInt! sup)
{
if(inf is MinusInfinity && sup is PlusInfinity)
return Top;
if(inf > sup)
return Bottom;
// otherwise...
return new IntervalElement(inf, sup);
}
public static IntervalElement! Factory(BigNum i)
{
return new IntervalElement(i);
}
public static IntervalElement! Factory(BigNum inf, BigNum sup)
{
ExtendedInt! i = ExtendedInt.Factory(inf);
ExtendedInt! s = ExtendedInt.Factory(sup);
return Factory(i, s);
}
static public IntervalElement! Top
{
get
{
return TopInterval;
}
}
static public IntervalElement! Bottom
{
get
{
return BottomInterval;
}
}
public bool IsTop()
{
return this.inf is MinusInfinity && this.sup is PlusInfinity;
}
public bool IsBottom()
{
return this.inf > this.sup;
}
#region Below are the arithmetic operations lifted to intervals
// Addition
public static IntervalElement! operator+(IntervalElement! a, IntervalElement! b)
{
ExtendedInt! inf = a.inf + b.inf;
ExtendedInt! sup = a.sup + b.sup;
return Factory(inf, sup);
}
// Subtraction
public static IntervalElement! operator-(IntervalElement! a, IntervalElement! b)
{
ExtendedInt! inf = a.inf - b.sup;
ExtendedInt! sup = a.sup - b.inf;
IntervalElement! sub = Factory(inf, sup);
return sub;
}
// Multiplication
public static IntervalElement! operator*(IntervalElement! a, IntervalElement! b)
{
ExtendedInt! infinf = a.inf * b.inf;
ExtendedInt! infsup = a.inf * b.sup;
ExtendedInt! supinf = a.sup * b.inf;
ExtendedInt! supsup = a.sup * b.sup;
ExtendedInt! inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup);
ExtendedInt! sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup);
return Factory(inf, sup);
}
// Division
public static IntervalElement! operator/(IntervalElement! a, IntervalElement! b)
{
if(b.inf.IsZero && b.sup.IsZero) // Check division by zero
return IntervalElement.Top;
ExtendedInt! infinf = a.inf / b.inf;
ExtendedInt! infsup = a.inf / b.sup;
ExtendedInt! supinf = a.sup / b.inf;
ExtendedInt! supsup = a.sup / b.sup;
ExtendedInt! inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup);
ExtendedInt! sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup);
return Factory(inf, sup);
}
// Division
public static IntervalElement! operator%(IntervalElement! a, IntervalElement! b)
{
if(b.inf.IsZero && b.sup.IsZero) // Check division by zero
return IntervalElement.Top;
ExtendedInt! infinf = a.inf % b.inf;
ExtendedInt! infsup = a.inf % b.sup;
ExtendedInt! supinf = a.sup % b.inf;
ExtendedInt! supsup = a.sup % b.sup;
ExtendedInt inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup);
ExtendedInt sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup);
return Factory(inf, sup);
}
#endregion
#region Overriden methods
public override Element! Clone()
{
// Real copying should not be needed because intervals are immutable?
return this;
/*
int valInf = this.inf.Value;
int valSup = this.sup.Value;
ExtendedInt clonedInf = ExtendedInt.Factory(valInf);
ExtendedInt clonedSup = ExtendedInt.Factory(valSup);
return Factory(clonedInf, clonedSup);
*/
}
[Pure]
public override System.Collections.Generic.ICollection! FreeVariables()
{
return (!) (new System.Collections.Generic.List()).AsReadOnly();
}
[Pure]
public override string! ToString()
{
return "[" + this.inf + ", " + this.sup + "]";
}
#endregion
}
}
/// The interface for an extended integer
abstract class ExtendedInt
{
private static readonly PlusInfinity! cachedPlusInf = new PlusInfinity();
private static readonly MinusInfinity! cachedMinusInf = new MinusInfinity();
static public ExtendedInt! PlusInfinity
{
get
{
return cachedPlusInf;
}
}
static public ExtendedInt! MinusInfinity
{
get
{
return cachedMinusInf;
}
}
public abstract BigNum Value { get; }
public abstract int Signum { get; }
public bool IsZero {
get {
return Signum == 0;
}
}
public bool IsPositive {
get {
return Signum > 0;
}
}
public bool IsNegative {
get {
return Signum < 0;
}
}
#region Below are the extensions of arithmetic operations on extended integers
// Addition
public static ExtendedInt! operator+(ExtendedInt! a, ExtendedInt! b)
{
if (a is InfinitaryInt) {
return a;
} else if (b is InfinitaryInt) {
return b;
} else {
return ExtendedInt.Factory(a.Value + b.Value);
}
}
// Subtraction
public static ExtendedInt! operator-(ExtendedInt! a, ExtendedInt! b)
{
if (a is InfinitaryInt) {
return a;
} else if (b is InfinitaryInt) {
return UnaryMinus(b);
} else {
return ExtendedInt.Factory(a.Value - b.Value);
}
}
// Unary minus
public static ExtendedInt! operator-(ExtendedInt! a)
{
// BUGBUG: Some compiler error prevents the unary minus operator from being used
return UnaryMinus(a);
}
// Unary minus
public static ExtendedInt! UnaryMinus(ExtendedInt! a)
{
if(a is PlusInfinity)
return cachedMinusInf;
if(a is MinusInfinity)
return cachedPlusInf;
else // a is a PureInteger
return new PureInteger(-a.Value);
}
// Multiplication
public static ExtendedInt! operator*(ExtendedInt! a, ExtendedInt! b)
{
if (a.IsZero) {
return a;
} else if (b.IsZero) {
return b;
} else if (a is InfinitaryInt) {
if (b.IsPositive) {
return a;
} else {
return UnaryMinus(a);
}
} else if (b is InfinitaryInt) {
if (a.IsPositive) {
return b;
} else {
return UnaryMinus(b);
}
} else {
return ExtendedInt.Factory(a.Value * b.Value);
}
}
// Division
public static ExtendedInt! operator/(ExtendedInt! a, ExtendedInt! b)
{
if(b.IsZero)
{
return a.IsPositive? (ExtendedInt) cachedPlusInf : cachedMinusInf;
}
if (a is InfinitaryInt) {
return a;
} else if (b is InfinitaryInt) {
return b;
} else {
return ExtendedInt.Factory(a.Value / b.Value);
}
}
// Modulo
public static ExtendedInt! operator%(ExtendedInt! a, ExtendedInt! b)
{
if(b.IsZero)
{
return a.IsPositive? (ExtendedInt) cachedPlusInf : cachedMinusInf;
}
if (a is InfinitaryInt) {
return a;
} else if (b is InfinitaryInt) {
return b;
} else {
return ExtendedInt.Factory(a.Value % b.Value);
}
}
#endregion
#region Inf and Sup operations
public abstract int CompareTo(ExtendedInt! that);
public static bool operator<(ExtendedInt! inf, ExtendedInt! sup)
{
return inf.CompareTo(sup) < 0;
}
public static bool operator>(ExtendedInt! inf, ExtendedInt! sup)
{
return inf.CompareTo(sup) > 0;
}
public static bool operator<=(ExtendedInt! inf, ExtendedInt! sup)
{
return inf.CompareTo(sup) <= 0;
}
public static bool operator>=(ExtendedInt! inf, ExtendedInt! sup)
requires inf != null && sup != null;
{
return inf.CompareTo(sup) >= 0;
}
public static ExtendedInt! Inf(ExtendedInt! inf, ExtendedInt! sup)
{
if(inf < sup)
return inf;
else
return sup;
}
public static ExtendedInt! Inf(ExtendedInt! a, ExtendedInt! b, ExtendedInt! c, ExtendedInt! d)
{
ExtendedInt! infab = Inf(a,b);
ExtendedInt! infcd = Inf(c,d);
return Inf(infab, infcd);
}
public static ExtendedInt! Sup(ExtendedInt! inf, ExtendedInt! sup)
{
if(inf > sup)
return inf;
else
return sup;
}
public static ExtendedInt! Sup(ExtendedInt! a, ExtendedInt! b, ExtendedInt! c, ExtendedInt! d)
{
ExtendedInt! supab = Sup(a,b);
ExtendedInt! supcd = Sup(c,d);
return Sup(supab, supcd);
}
#endregion
// Return the ExtendedInt corresponding to the value
public static ExtendedInt! Factory(BigNum val)
{
return new PureInteger(val);
}
}
// Stands for a normal (finite) integer x
class PureInteger : ExtendedInt
{
public PureInteger(BigNum i)
{
this.val = i;
}
[Pure]
public override string! ToString()
{
return this.Value.ToString();
}
private BigNum val;
public override BigNum Value {
get
{
return this.val;
}
}
public override int Signum {
get {
return val.Signum;
}
}
public override int CompareTo(ExtendedInt! that) {
if (that is PlusInfinity)
return -1;
else if (that is PureInteger)
return this.Value.CompareTo(that.Value);
else // then that is a MinusInfinity
return 1;
}
}
abstract class InfinitaryInt : ExtendedInt
{
public override BigNum Value
{
get {
throw new InvalidOperationException();
}
}
}
class PlusInfinity : InfinitaryInt
{
[Pure]
public override string! ToString()
{
return "+oo";
}
public override int Signum {
get {
return 1;
}
}
public override int CompareTo(ExtendedInt! that) {
if (that is PlusInfinity)
return 0;
else
return 1;
}
}
class MinusInfinity : InfinitaryInt
{
[Pure]
public override string! ToString()
{
return "-oo";
}
public override int Signum {
get {
return -1;
}
}
public override int CompareTo(ExtendedInt! that) {
if (that is MinusInfinity)
return 0;
else
return -1;
}
}
}