summaryrefslogtreecommitdiff
path: root/Source/AIFramework
diff options
context:
space:
mode:
authorGravatar mikebarnett <unknown>2009-07-15 21:03:41 +0000
committerGravatar mikebarnett <unknown>2009-07-15 21:03:41 +0000
commitce1c2de044c91624370411e23acab13b0381949b (patch)
tree592539996fe08050ead5ee210c973801611dde40 /Source/AIFramework
Initial set of files.
Diffstat (limited to 'Source/AIFramework')
-rw-r--r--Source/AIFramework/AIFramework.sscproj157
-rw-r--r--Source/AIFramework/CommonFunctionSymbols.ssc926
-rw-r--r--Source/AIFramework/Expr.ssc447
-rw-r--r--Source/AIFramework/Functional.ssc284
-rw-r--r--Source/AIFramework/Lattice.ssc685
-rw-r--r--Source/AIFramework/Logger.ssc49
-rw-r--r--Source/AIFramework/MultiLattice.ssc563
-rw-r--r--Source/AIFramework/Mutable.ssc117
-rw-r--r--Source/AIFramework/Polyhedra/LinearConstraint.ssc588
-rw-r--r--Source/AIFramework/Polyhedra/LinearConstraintSystem.ssc1856
-rw-r--r--Source/AIFramework/Polyhedra/PolyhedraAbstraction.ssc744
-rw-r--r--Source/AIFramework/Polyhedra/SimplexTableau.ssc717
-rw-r--r--Source/AIFramework/VariableMap/ConstantAbstraction.ssc210
-rw-r--r--Source/AIFramework/VariableMap/ConstantExpressions.ssc538
-rw-r--r--Source/AIFramework/VariableMap/DynamicTypeLattice.ssc475
-rw-r--r--Source/AIFramework/VariableMap/Intervals.ssc790
-rw-r--r--Source/AIFramework/VariableMap/MicroLattice.ssc79
-rw-r--r--Source/AIFramework/VariableMap/Nullness.ssc227
-rw-r--r--Source/AIFramework/VariableMap/VariableMapLattice.ssc749
19 files changed, 10201 insertions, 0 deletions
diff --git a/Source/AIFramework/AIFramework.sscproj b/Source/AIFramework/AIFramework.sscproj
new file mode 100644
index 00000000..dd79b9b8
--- /dev/null
+++ b/Source/AIFramework/AIFramework.sscproj
@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="utf-8"?>
+<VisualStudioProject>
+ <XEN ProjectType="Local"
+ SchemaVersion="1.0"
+ Name="AIFramework"
+ ProjectGuid="24b55172-ad8b-47d1-8952-5a95cfdb9b31"
+ >
+ <Build>
+ <Settings ApplicationIcon=""
+ AssemblyName="AIFramework"
+ OutputType="Library"
+ RootNamespace="AIFramework"
+ StartupObject=""
+ StandardLibraryLocation=""
+ TargetPlatform="v2"
+ TargetPlatformLocation=""
+ ShadowedAssembly=""
+ >
+ <Config Name="Debug"
+ AllowUnsafeBlocks="False"
+ BaseAddress="285212672"
+ CheckForOverflowUnderflow="False"
+ ConfigurationOverrideFile=""
+ DefineConstants="DEBUG;TRACE"
+ DocumentationFile=""
+ DebugSymbols="True"
+ FileAlignment="4096"
+ IncrementalBuild="True"
+ Optimize="False"
+ OutputPath="bin\debug"
+ RegisterForComInterop="False"
+ RemoveIntegerChecks="false"
+ TreatWarningsAsErrors="False"
+ WarningLevel="4"
+ RunProgramVerifier="False"
+ ProgramVerifierCommandLineOptions=""
+ ReferenceTypesAreNonNullByDefault="False"
+ RunProgramVerifierWhileEditing="False"
+ AllowPointersToManagedStructures="False"
+ CheckContractAdmissibility="True"
+ CheckPurity="False"
+ />
+ <Config Name="Release"
+ AllowUnsafeBlocks="false"
+ BaseAddress="285212672"
+ CheckForOverflowUnderflow="false"
+ ConfigurationOverrideFile=""
+ DefineConstants="TRACE"
+ DocumentationFile=""
+ DebugSymbols="false"
+ FileAlignment="4096"
+ IncrementalBuild="false"
+ Optimize="true"
+ OutputPath="bin\release"
+ RegisterForComInterop="false"
+ RemoveIntegerChecks="false"
+ TreatWarningsAsErrors="True"
+ WarningLevel="4"
+ />
+ </Settings>
+ <References>
+ <Reference Name="System"
+ AssemblyName="System"
+ Private="false"
+ />
+ <Reference Name="Basetypes"
+ Project="{0C692837-77EC-415F-BF04-395E3ED06E9A}"
+ Private="true"
+ />
+ </References>
+ </Build>
+ <Files>
+ <Include>
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="Expr.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="CommonFunctionSymbols.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="Lattice.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="Functional.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="Mutable.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="Logger.ssc"
+ />
+ <Folder RelPath="VariableMap\"
+ />
+ <Folder RelPath="Polyhedra\"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="VariableMap\MicroLattice.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="VariableMap\VariableMapLattice.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="MultiLattice.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="VariableMap\Nullness.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="VariableMap\ConstantAbstraction.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="VariableMap\DynamicTypeLattice.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="Polyhedra\SimplexTableau.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="Polyhedra\LinearConstraint.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="Polyhedra\LinearConstraintSystem.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="Polyhedra\PolyhedraAbstraction.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="..\version.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="VariableMap\Intervals.ssc"
+ />
+ <File BuildAction="Compile"
+ SubType="Code"
+ RelPath="VariableMap\ConstantExpressions.ssc"
+ />
+ </Include>
+ </Files>
+ </XEN>
+</VisualStudioProject> \ No newline at end of file
diff --git a/Source/AIFramework/CommonFunctionSymbols.ssc b/Source/AIFramework/CommonFunctionSymbols.ssc
new file mode 100644
index 00000000..4e38fbcb
--- /dev/null
+++ b/Source/AIFramework/CommonFunctionSymbols.ssc
@@ -0,0 +1,926 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using Microsoft.Contracts;
+ using System.Collections;
+ using Microsoft.SpecSharp.Collections;
+ using Microsoft.Basetypes;
+
+ /// <summary>
+ /// A basic class for function symbols.
+ /// </summary>
+ public class FunctionSymbol : IFunctionSymbol
+ {
+ private readonly string! display;
+ private readonly AIType! typ;
+
+ public FunctionSymbol(AIType! typ)
+ : this("FunctionSymbol", typ)
+ {
+ }
+
+ internal FunctionSymbol(string! display, AIType! typ)
+ {
+ this.display = display;
+ this.typ = typ;
+ // base();
+ }
+
+// public AIType! AIType { [Pure][Reads(ReadsAttribute.Reads.Owned)] get { return typ; } }
+ public AIType! AIType { [Pure][Reads(ReadsAttribute.Reads.Owned)] get { return typ; } }
+
+ [NoDefaultContract]
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override string! ToString()
+ {
+ return display;
+ }
+
+ }
+
+ /// <summary>
+ /// A class for integer constants.
+ /// </summary>
+ public class IntSymbol : FunctionSymbol
+ {
+ public readonly BigNum Value;
+
+ /// <summary>
+ /// The intention is that this constructor be called only from the Int.Const method.
+ /// </summary>
+ internal IntSymbol(BigNum x)
+ : base((!)x.ToString(), Int.Type)
+ {
+ this.Value = x;
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)]
+ public override bool Equals(object other)
+ {
+ IntSymbol isym = other as IntSymbol;
+ return isym != null && isym.Value.Equals(this.Value);
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override int GetHashCode()
+ {
+ return Value.GetHashCode();
+ }
+ }
+
+ /// <summary>
+ /// A class for bitvector constants.
+ /// </summary>
+ public class BvSymbol : FunctionSymbol
+ {
+ public readonly BigNum Value;
+ public readonly int Bits;
+
+ /// <summary>
+ /// The intention is that this constructor be called only from the Int.Const method.
+ /// </summary>
+ internal BvSymbol(BigNum x, int y)
+ : base(x + "bv" + y, Bv.Type)
+ {
+ this.Value = x;
+ this.Bits = y;
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)]
+ public override bool Equals(object other)
+ {
+ BvSymbol isym = other as BvSymbol;
+ return isym != null && isym.Value == this.Value && isym.Bits == this.Bits;
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override int GetHashCode()
+ {
+ unchecked {
+ return Value.GetHashCode() ^ Bits;
+ }
+ }
+ }
+
+ public class DoubleSymbol : FunctionSymbol
+ {
+ public readonly double Value;
+
+ /// <summary>
+ /// The intention is that this constructor be called only from the Double.Const method.
+ /// </summary>
+ internal DoubleSymbol(double x)
+ : base((!)x.ToString(), Double.Type)
+ {
+ this.Value = x;
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)]
+ public override bool Equals(object other)
+ {
+ DoubleSymbol dsym = other as DoubleSymbol;
+ return dsym != null && dsym.Value == this.Value;
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override int GetHashCode()
+ {
+ return Value.GetHashCode();
+ }
+ }
+
+ /// <summary>
+ /// Function symbol based on a string. Uses the string equality for determining equality
+ /// of symbol.
+ /// </summary>
+ public class NamedSymbol : FunctionSymbol
+ {
+ public string! Value { [NoDefaultContract] get { return (!) this.ToString(); } }
+
+ public NamedSymbol(string! symbol, AIType! typ)
+ : base(symbol, typ)
+ {
+ }
+
+ [NoDefaultContract]
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)]
+ public override bool Equals(object other)
+ {
+ NamedSymbol nsym = other as NamedSymbol;
+ return nsym != null && this.Value.Equals(nsym.Value);
+ }
+
+ [NoDefaultContract]
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override int GetHashCode()
+ {
+ return Value.GetHashCode();
+ }
+ }
+
+ //
+ // In the following, the classes like Value and Prop serve two
+ // roles. The primary role is to be the base types for AIType.
+ // The only objects of these classes are the representative
+ // objects that denote an AIType, which are given by the
+ // "Type" property. Subtypes in the AIType language are
+ // encoded by subclassing. This yields some "higher-orderness"
+ // for checking subtyping in the AIType language, by using
+ // the Spec#/C# subclassing checks.
+ //
+ // The other role is simply as a module for collecting like function
+ // symbols.
+ //
+
+ //-------------------------- Terms ----------------------------------
+
+ /// <summary>
+ /// A class with the equality symbol and the ValueType.Type.
+ /// </summary>
+ public class Value : AIType
+ {
+ private static readonly AIType! valtype = new Value();
+ public static AIType! Type { get { return valtype; } }
+
+ private static readonly FunctionType[]! funtypeCache = new FunctionType[5];
+ public static FunctionType! FunctionType(int inParameterCount)
+ requires 0 <= inParameterCount;
+ // ensures result.Arity == inParameterCount;
+ {
+ FunctionType result;
+ if (inParameterCount < funtypeCache.Length) {
+ result = funtypeCache[inParameterCount];
+ if (result != null) {
+ return result;
+ }
+ }
+ AIType[] signature = new AIType[1 + inParameterCount];
+ for (int i = 0; i < signature.Length; i++) {
+ signature[i] = valtype;
+ }
+ result = new FunctionType(signature);
+ if (inParameterCount < funtypeCache.Length) {
+ funtypeCache[inParameterCount] = result;
+ }
+ return result;
+ }
+
+ [Once] private static AIType! binreltype;
+ private static AIType! BinrelType {
+ get {
+ if (binreltype == null) {
+ binreltype = new FunctionType(Type, Type, Prop.Type);
+ }
+ return binreltype;
+ }
+ }
+
+ [Once] private static FunctionSymbol! _eq;
+ public static FunctionSymbol! Eq {
+ get {
+ if (_eq == null) {
+ _eq = new FunctionSymbol("=", BinrelType);
+ }
+ return _eq;
+ }
+ }
+ [Once] private static FunctionSymbol! _neq;
+ public static FunctionSymbol! Neq {
+ get {
+ if (_neq == null) {
+ _neq = new FunctionSymbol("!=", BinrelType);
+ }
+ return _neq;
+ }
+ }
+ [Once] private static FunctionSymbol! _subtype;
+ public static FunctionSymbol! Subtype {
+ get {
+ if (_subtype == null) {
+ _subtype = new FunctionSymbol("<:", BinrelType);
+ }
+ return _subtype;
+ }
+ }
+
+ [Once] private static AIType! typeof_type;
+ private static AIType! TypeofType {
+ get {
+ if (typeof_type == null) {
+ typeof_type = new FunctionType(Ref.Type, Type);
+ }
+ return typeof_type;
+ }
+ }
+ [Once] private static FunctionSymbol! _typeof;
+ public static FunctionSymbol! Typeof {
+ get {
+ if (_typeof == null) {
+ _typeof = new FunctionSymbol("typeof", TypeofType);
+ }
+ return _typeof;
+ }
+ }
+
+ /// <summary>
+ /// Value should not be instantiated from the outside, except perhaps in
+ /// subclasses.
+ /// </summary>
+ protected Value() { }
+
+ }
+
+ public class Int : Value
+ {
+ private static readonly AIType! inttype = new Int();
+ public static AIType! Type { get { return inttype; } }
+
+ private static readonly AIType! unaryinttype = new FunctionType(Type, Type);
+ private static readonly AIType! bininttype = new FunctionType(Type, Type, Type);
+ private static readonly AIType! relationtype = new FunctionType(Type, Type, Prop.Type);
+
+ private static readonly FunctionSymbol! _negate = new FunctionSymbol("~", unaryinttype);
+ private static readonly FunctionSymbol! _add = new FunctionSymbol("+", bininttype);
+ private static readonly FunctionSymbol! _sub = new FunctionSymbol("-", bininttype);
+ private static readonly FunctionSymbol! _mul = new FunctionSymbol("*", bininttype);
+ private static readonly FunctionSymbol! _div = new FunctionSymbol("/", bininttype);
+ private static readonly FunctionSymbol! _mod = new FunctionSymbol("%", bininttype);
+ private static readonly FunctionSymbol! _atmost = new FunctionSymbol("<=", relationtype);
+ private static readonly FunctionSymbol! _less = new FunctionSymbol("<", relationtype);
+ private static readonly FunctionSymbol! _greater = new FunctionSymbol(">", relationtype);
+ private static readonly FunctionSymbol! _atleast = new FunctionSymbol(">=", relationtype);
+
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Negate { get { return _negate; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Add { get { return _add; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Sub { get { return _sub; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Mul { get { return _mul; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Div { get { return _div; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Mod { get { return _mod; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! AtMost { get { return _atmost; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Less { get { return _less; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Greater { get { return _greater; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! AtLeast { get { return _atleast; } }
+
+ public static IntSymbol! Const(BigNum x)
+ {
+ // We could cache things here, but for now we don't.
+ return new IntSymbol(x);
+ }
+
+ /// <summary>
+ /// Int should not be instantiated from the outside, except perhaps in
+ /// subclasses.
+ /// </summary>
+ private Int() { }
+ }
+
+ public class Double : Value
+ {
+ private static readonly AIType! doubletype = new Double();
+ public static AIType! Type { get { return doubletype; } }
+
+ public static DoubleSymbol! Const(double x)
+ {
+ // We could cache things here, but for now we don't.
+ return new DoubleSymbol(x);
+ }
+
+ /// <summary>
+ /// Double should not be instantiated from the outside, except perhaps in
+ /// subclasses.
+ /// </summary>
+ private Double() { }
+ }
+
+ public class Bv : Value
+ {
+ private static readonly AIType! bvtype = new Bv();
+ public static AIType! Type { get { return bvtype; } }
+
+ private static readonly AIType! unaryinttype = new FunctionType(Type, Type);
+ private static readonly AIType! bininttype = new FunctionType(Type, Type, Type);
+ private static readonly AIType! relationtype = new FunctionType(Type, Type, Prop.Type);
+
+ private static readonly FunctionSymbol! _negate = new FunctionSymbol("~", unaryinttype);
+ private static readonly FunctionSymbol! _add = new FunctionSymbol("+", bininttype);
+ private static readonly FunctionSymbol! _sub = new FunctionSymbol("-", bininttype);
+ private static readonly FunctionSymbol! _mul = new FunctionSymbol("*", bininttype);
+ private static readonly FunctionSymbol! _div = new FunctionSymbol("/", bininttype);
+ private static readonly FunctionSymbol! _mod = new FunctionSymbol("%", bininttype);
+ private static readonly FunctionSymbol! _concat = new FunctionSymbol("$concat", bininttype);
+ private static readonly FunctionSymbol! _extract = new FunctionSymbol("$extract", unaryinttype);
+ private static readonly FunctionSymbol! _atmost = new FunctionSymbol("<=", relationtype);
+ private static readonly FunctionSymbol! _less = new FunctionSymbol("<", relationtype);
+ private static readonly FunctionSymbol! _greater = new FunctionSymbol(">", relationtype);
+ private static readonly FunctionSymbol! _atleast = new FunctionSymbol(">=", relationtype);
+
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Negate { get { return _negate; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Add { get { return _add; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Sub { get { return _sub; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Mul { get { return _mul; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Div { get { return _div; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Mod { get { return _mod; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! AtMost { get { return _atmost; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Less { get { return _less; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Greater { get { return _greater; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! AtLeast { get { return _atleast; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Extract { get { return _extract; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Concat { get { return _concat; } }
+
+ public static BvSymbol! Const(BigNum x, int y)
+ {
+ // We could cache things here, but for now we don't.
+ return new BvSymbol(x, y);
+ }
+
+ /// <summary>
+ /// Int should not be instantiated from the outside, except perhaps in
+ /// subclasses.
+ /// </summary>
+ private Bv() { }
+ }
+
+ public class Ref : Value
+ {
+ private static readonly AIType! reftype = new Ref();
+ public static AIType! Type { get { return reftype; } }
+
+ private static readonly FunctionSymbol! _null = new FunctionSymbol("null", Type);
+
+ public static FunctionSymbol! Null { get { return _null; } }
+
+ /// <summary>
+ /// Ref should not be instantiated from the outside, except perhaps in
+ /// subclasses.
+ /// </summary>
+ private Ref() { }
+ }
+
+ public class HeapStructure : Value
+ {
+ private static readonly AIType! reftype = new HeapStructure();
+ public static AIType! Type { get { return reftype; } }
+
+
+
+ /// <summary>
+ /// HeapStructure should not be instantiated from the outside, except perhaps in
+ /// subclasses.
+ /// </summary>
+ private HeapStructure() { }
+ }
+
+ public class FieldName : Value
+ {
+ private static readonly AIType! fieldnametype = new FieldName();
+ public static AIType! Type { get { return fieldnametype; } }
+
+ private static readonly FunctionSymbol! _allocated = new FunctionSymbol("$allocated", FieldName.Type);
+ public static FunctionSymbol! Allocated { get { return _allocated; } }
+
+ /// <summary>
+ /// Is this a boolean field that monotonically goes from false to true?
+ /// </summary>
+ public static bool IsBooleanMonotonicallyWeakening(IFunctionSymbol! f)
+ {
+ return f.Equals(Allocated);
+ }
+
+ /// <summary>
+ /// FieldName should not be instantiated from the outside, except perhaps in
+ /// subclasses.
+ /// </summary>
+ private FieldName() { }
+ }
+
+ public class Heap : Value
+ {
+ private static readonly AIType! heaptype = new Heap();
+ public static AIType! Type { get { return heaptype; } }
+
+ // the types in the following, select1, select2, are hard-coded;
+ // these types may not always be appropriate
+ private static readonly FunctionSymbol! _select1 = new FunctionSymbol("sel1",
+ // Heap x FieldName -> Prop
+ new FunctionType(Type, FieldName.Type, Prop.Type)
+ );
+ public static FunctionSymbol! Select1 { get { return _select1; } }
+
+ private static readonly FunctionSymbol! _select2 = new FunctionSymbol("sel2",
+ // Heap x Ref x FieldName -> Value
+ new FunctionType(Type, Ref.Type, FieldName.Type, Value.Type)
+ );
+ public static FunctionSymbol! Select2 { get { return _select2; } }
+
+ // the types in the following, store1, store2, are hard-coded;
+ // these types may not always be appropriate
+ private static readonly FunctionSymbol! _update1 = new FunctionSymbol("upd1",
+ // Heap x FieldName x Value -> Heap
+ new FunctionType(Type, FieldName.Type, Value.Type, Type)
+ );
+ public static FunctionSymbol! Update1 { get { return _update1; } }
+
+ private static readonly FunctionSymbol! _update2 = new FunctionSymbol("upd2",
+ // Heap x Ref x FieldName x Value -> Heap
+ new FunctionType(Type, Ref.Type, FieldName.Type, Value.Type, Type)
+ );
+ public static FunctionSymbol! Update2 { get { return _update2; } }
+
+ private static readonly FunctionSymbol! _unsupportedHeapOp =
+ new FunctionSymbol("UnsupportedHeapOp",
+ // Heap x FieldName -> Prop
+ new FunctionType(Type, FieldName.Type, Prop.Type)
+ );
+ public static FunctionSymbol! UnsupportedHeapOp { get { return _unsupportedHeapOp; } }
+
+ /// <summary>
+ /// Heap should not be instantiated from the outside, except perhaps in
+ /// subclasses.
+ /// </summary>
+ private Heap() { }
+ }
+
+// public class List : Value
+// {
+// private static IDictionary/*<AIType!,AIType!>*/! lists = new Hashtable();
+// public static AIType! Type(AIType! typeParameter)
+// {
+// if (lists.Contains(typeParameter))
+// return lists[typeParameter];
+// else
+// {
+// AIType! result = new List(typeParameter);
+// lists[typeParameter] = result;
+// return result;
+// }
+// }
+//
+// private static IDictionary/*<AIType!,AIType!>*/! nils = new Hashtable();
+// public static FunctionSymbol! Nil(AIType! typeParameter)
+// {
+// if (nils.Contains(typeParameter))
+// return nils[typeParameter];
+// else
+// {
+// FunctionSymbol! result = new FunctionSymbol(Type(typeParameter));
+// nils[typeParameter] = result;
+// return result;
+// }
+// }
+//
+// private static IDictionary/*<AIType!,AIType!>*/! cons = new Hashtable();
+// public static FunctionSymbol! Cons(AIType! typeParameter)
+// {
+// if (cons.Contains(typeParameter))
+// return cons[typeParameter];
+// else
+// {
+// FunctionSymbol! result = new FunctionSymbol(
+// new FunctionType(typeParameter, Type(typeParameter), Type(typeParameter))
+// );
+// cons[typeParameter] = result;
+// return result;
+// }
+// }
+//
+// private AIType! typeParameter;
+// public AIType! TypeParameter { get { return typeParameter; } }
+//
+// /// <summary>
+// /// List should not be instantiated from the outside.
+// /// </summary>
+// private List(AIType! typeParameter)
+// {
+// this.typeParameter = typeParameter;
+// }
+// }
+//
+// public class Pair : Value
+// {
+// private static IDictionary! pairs = new Hashtable();
+// public static AIType! Type(AIType! type1, AIType! type2)
+// {
+// Microsoft.AbstractInterpretationFramework.Collections.Pair typpair
+// = new Microsoft.AbstractInterpretationFramework.Collections.Pair(type1, type2);
+//
+// if (pairs.Contains(typpair))
+// return pairs[typpair];
+// else
+// {
+// AIType! result = new Pair(type1, type2);
+// pairs[typpair] = result;
+// return result;
+// }
+// }
+//
+// private static IDictionary! constructs = new Hashtable();
+// public static FunctionSymbol! Pair(AIType! type1, AIType! type2)
+// {
+// Microsoft.AbstractInterpretationFramework.Collections.Pair typpair
+// = new Microsoft.AbstractInterpretationFramework.Collections.Pair(type1, type2);
+//
+// if (constructs.Contains(typpair))
+// return constructs[typpair];
+// else
+// {
+// FunctionSymbol! result = new FunctionSymbol(
+// new FunctionType(type1, type2, Type(type1, type2))
+// );
+// constructs[typpair] = result;
+// return result;
+// }
+// }
+//
+// protected AIType! type1;
+// protected AIType! type2;
+//
+// public AIType! Type1 { get { return type1; } }
+// public AIType! Type2 { get { return type2; } }
+//
+// /// <summary>
+// /// Pair should not be instantiated from the outside, except by subclasses.
+// /// </summary>
+// protected Pair(AIType! type1, AIType! type2)
+// {
+// this.type1 = type1;
+// this.type2 = type2;
+// }
+// }
+
+ //-------------------------- Propositions ---------------------------
+
+
+ /// <summary>
+ /// A class with global propositional symbols and the Prop.Type.
+ /// </summary>
+ public sealed class Prop : AIType
+ {
+ private static readonly AIType! proptype = new Prop();
+ public static AIType! Type { get { return proptype; } }
+
+ private static readonly AIType! unaryproptype = new FunctionType(Type, Type);
+ private static readonly AIType! binproptype = new FunctionType(Type, Type, Type);
+ private static readonly AIType! quantifiertype =
+ new FunctionType(new FunctionType(Value.Type, Type), Type);
+
+ private static readonly FunctionSymbol! _false = new FunctionSymbol("false", Type);
+ private static readonly FunctionSymbol! _true = new FunctionSymbol("true", Type);
+ private static readonly FunctionSymbol! _not = new FunctionSymbol("!", unaryproptype);
+ private static readonly FunctionSymbol! _and = new FunctionSymbol("/\\", binproptype);
+ private static readonly FunctionSymbol! _or = new FunctionSymbol("\\/", binproptype);
+ private static readonly FunctionSymbol! _implies = new FunctionSymbol("==>", binproptype);
+ private static readonly FunctionSymbol! _exists = new FunctionSymbol("Exists", quantifiertype);
+ private static readonly FunctionSymbol! _forall = new FunctionSymbol("Forall", quantifiertype);
+
+
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! False { get { return _false; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! True { get { return _true; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Not { get { return _not; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! And { [Pure] get { return _and; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Or { get { return _or; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Implies { get { return _implies; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Exists { get { return _exists; } }
+ [Pure][Reads(ReadsAttribute.Reads.Nothing)] public static FunctionSymbol! Forall { get { return _forall; } }
+
+
+ /// <summary>
+ /// Prop should not be instantiated from the outside.
+ /// </summary>
+ private Prop() { }
+
+
+
+ //
+ // Utility Methods
+ //
+
+ public static IExpr! SimplifiedAnd(IPropExprFactory! factory, IExpr! e0, IExpr! e1)
+ {
+ IFunApp fun0 = e0 as IFunApp;
+ if (fun0 != null)
+ {
+ if (fun0.FunctionSymbol.Equals(Prop.True))
+ {
+ return e1;
+ }
+ else if (fun0.FunctionSymbol.Equals(Prop.False))
+ {
+ return e0;
+ }
+ }
+
+ IFunApp fun1 = e1 as IFunApp;
+ if (fun1 != null)
+ {
+ if (fun1.FunctionSymbol.Equals(Prop.True))
+ {
+ return e0;
+ }
+ else if (fun1.FunctionSymbol.Equals(Prop.False))
+ {
+ return e1;
+ }
+ }
+
+ return factory.And(e0, e1);
+ }
+
+ public static IExpr! SimplifiedAnd(IPropExprFactory! factory, IEnumerable/*<IExpr!>*/! exprs)
+ {
+ IExpr! result = factory.True;
+ foreach (IExpr! conjunct in exprs)
+ {
+ result = SimplifiedAnd(factory, result, conjunct);
+ }
+ return result;
+ }
+
+ public static IExpr! SimplifiedOr(IPropExprFactory! factory, IExpr! e0, IExpr! e1)
+ {
+ IFunApp fun0 = e0 as IFunApp;
+ if (fun0 != null)
+ {
+ if (fun0.FunctionSymbol.Equals(Prop.False))
+ {
+ return e1;
+ }
+ else if (fun0.FunctionSymbol.Equals(Prop.True))
+ {
+ return e0;
+ }
+ }
+
+ IFunApp fun1 = e1 as IFunApp;
+ if (fun1 != null)
+ {
+ if (fun1.FunctionSymbol.Equals(Prop.False))
+ {
+ return e0;
+ }
+ else if (fun1.FunctionSymbol.Equals(Prop.True))
+ {
+ return e1;
+ }
+ }
+
+ return factory.Or(e0, e1);
+ }
+
+ public static IExpr! SimplifiedOr(IPropExprFactory! factory, IEnumerable/*<IExpr!>*/! exprs)
+ {
+ IExpr! result = factory.False;
+ foreach (IExpr! disj in exprs)
+ {
+ result = SimplifiedOr(factory, result, disj);
+ }
+ return result;
+ }
+
+
+
+ /// <summary>
+ /// Break top-level conjuncts into a list of sub-expressions.
+ /// </summary>
+ /// <param name="e">The expression to examine.</param>
+ /// <returns>A list of conjuncts.</returns>
+ internal static IList/*<IExpr!>*/! BreakConjuncts(IExpr! e)
+ ensures forall{ IExpr sub in result; sub is IFunApp ==> !((IFunApp) sub).FunctionSymbol.Equals(Prop.And) };
+ {
+ return BreakJuncts(e, Prop.And);
+ }
+
+ /// <summary>
+ /// Break top-level disjuncts into a list of sub-expressions.
+ /// </summary>
+ /// <param name="e">The expression to examine.</param>
+ /// <returns>A list of conjuncts.</returns>
+ internal static IList/*<IExpr!>*/! BreakDisjuncts(IExpr! e)
+ ensures forall{ IExpr sub in result; sub is IFunApp ==> !((IFunApp) sub).FunctionSymbol.Equals(Prop.Or) };
+ {
+ return BreakJuncts(e, Prop.Or);
+ }
+
+ private static IList/*<IExpr!>*/! BreakJuncts(IExpr! e, IFunctionSymbol! sym)
+ ensures forall{ IExpr sub in result; sub is IFunApp ==> !((IFunApp) sub).FunctionSymbol.Equals(sym) };
+ {
+ ArrayList/*<IExpr!>*/! result = new ArrayList();
+
+ IFunApp f = e as IFunApp;
+ if (f != null)
+ {
+ // If it is a sym, go down into sub-expressions.
+ if (f.FunctionSymbol.Equals(sym))
+ {
+ foreach (IExpr! arg in f.Arguments)
+ {
+ result.AddRange(BreakJuncts(arg,sym));
+ }
+ }
+ // Otherwise, stop.
+ else
+ {
+ result.Add(e);
+ }
+ }
+ else
+ {
+ result.Add(e);
+ }
+
+ return result;
+ }
+ }
+
+ /// <summary>
+ /// A callback to produce a function body given the bound variable.
+ /// </summary>
+ /// <param name="var">The bound variable to use.</param>
+ /// <returns>The function body.</returns>
+ public delegate IExpr! FunctionBody(IVariable! var);
+
+ /// <summary>
+ /// An interface for constructing propositional expressions.
+ ///
+ /// This interface should be implemented by the client. An implementation of
+ /// of this class should generally be used as a singleton object.
+ /// </summary>
+ public interface IPropExprFactory
+ {
+ IFunApp! False { get /*ensures result.FunctionSymbol.Equals(Prop.False);*/; }
+ IFunApp! True { get /*ensures result.FunctionSymbol.Equals(Prop.True);*/; }
+
+ IFunApp! Not(IExpr! p) /*ensures result.FunctionSymbol.Equals(Prop.Not);*/;
+
+ IFunApp! And(IExpr! p, IExpr! q) /*ensures result.FunctionSymbol.Equals(Prop.And);*/;
+ IFunApp! Or(IExpr! p, IExpr! q) /*ensures result.FunctionSymbol.Equals(Prop.Or);*/;
+
+ IFunApp! Implies(IExpr! p, IExpr! q) /*ensures result.FunctionSymbol.Equals(Prop.Implies);*/;
+ }
+
+ /// <summary>
+ /// Like IPropExprFactory, but also with quantifiers.
+ /// </summary>
+ public interface IQuantPropExprFactory : IPropExprFactory {
+ /// <summary>
+ /// Produce an existential given the lambda-expression.
+ /// </summary>
+ /// <param name="p">The lambda-expression.</param>
+ /// <returns>The existential.</returns>
+ IFunApp! Exists(IFunction! p) /*ensures result.FunctionSymbol.Equals(Prop.Exists);*/;
+ IFunApp! Forall(IFunction! p) /*ensures result.FunctionSymbol.Equals(Prop.Forall);*/;
+
+ /// <summary>
+ /// Produce an existential given a callback that can produce a function body given the
+ /// bound variable to use. The implementer of this method is responsible for generating
+ /// a fresh new variable to pass to the FunctionBody callback to use as the bound variable.
+ /// </summary>
+ /// <param name="body">The function body callback.</param>
+ /// <returns>The existential.</returns>
+ IFunApp! Exists(AIType paramType, FunctionBody! body) /*ensures result.FunctionSymbol.Equals(Prop.Exists);*/;
+ IFunApp! Forall(AIType paramType, FunctionBody! body) /*ensures result.FunctionSymbol.Equals(Prop.Forall);*/;
+ }
+
+ /// <summary>
+ /// An interface for constructing value expressions.
+ ///
+ /// This interface should be implemented by the client. An implementation of
+ /// of this class should generally be used as a singleton object.
+ /// </summary>
+ public interface IValueExprFactory
+ {
+ IFunApp! Eq(IExpr! e0, IExpr! e1) /*ensures result.FunctionSymbol.Equals(Value.Eq);*/;
+ IFunApp! Neq(IExpr! e0, IExpr! e1) /*ensures result.FunctionSymbol.Equals(Value.Neq);*/;
+ }
+
+ /// <summary>
+ /// An interface for constructing value expressions having to with null.
+ ///
+ /// This interface should be implemented by the client. An implementation of
+ /// of this class should generally be used as a singleton object.
+ /// </summary>
+ public interface INullnessFactory
+ {
+ IFunApp! Eq(IExpr! e0, IExpr! e1) /*ensures result.FunctionSymbol.Equals(Value.Eq);*/;
+ IFunApp! Neq(IExpr! e0, IExpr! e1) /*ensures result.FunctionSymbol.Equals(Value.Neq);*/;
+ IFunApp! Null { get; /*ensures result.FunctionSymbol.Equals(Ref.Null);*/ }
+ }
+
+ /// <summary>
+ /// An interface for constructing integer expressions.
+ ///
+ /// This interface should be implemented by the client. An implementation of
+ /// of this class should generally be used as a singleton object.
+ /// </summary>
+ public interface IIntExprFactory : IValueExprFactory
+ {
+ IFunApp! Const(BigNum i) /*ensures result.FunctionSymbol.Equals(new IntSymbol(i));*/;
+ }
+
+ /// <summary>
+ /// An interface for constructing linear integer expressions.
+ ///
+ /// This interface should be implemented by the client. An implementation of
+ /// of this class should generally be used as a singleton object.
+ /// </summary>
+ public interface ILinearExprFactory : IIntExprFactory
+ {
+ IFunApp! AtMost(IExpr! e0, IExpr! e1) /*ensures result.FunctionSymbol.Equals(Value.AtMost);*/;
+ IFunApp! Add(IExpr! e0, IExpr! e1) /*ensures result.FunctionSymbol.Equals(Value.Add);*/;
+ /// <summary>
+ /// If "var" is null, returns an expression representing r.
+ /// Otherwise, returns an expression representing r*var.
+ /// </summary>
+ IExpr! Term(Microsoft.Basetypes.Rational r, IVariable var);
+
+ IFunApp! False { get /*ensures result.FunctionSymbol.Equals(Prop.False);*/; }
+ IFunApp! True { get /*ensures result.FunctionSymbol.Equals(Prop.True);*/; }
+ IFunApp! And(IExpr! p, IExpr! q) /*ensures result.FunctionSymbol.Equals(Prop.And);*/;
+ }
+
+ /// <summary>
+ /// An interface for constructing type expressions and performing some type operations.
+ /// The types are assumed to be arranged in a rooted tree.
+ ///
+ /// This interface should be implemented by the client. An implementation of
+ /// of this class should generally be used as a singleton object.
+ /// </summary>
+ public interface ITypeExprFactory
+ {
+ /// <summary>
+ /// Returns an expression denoting the top of the type hierarchy.
+ /// </summary>
+ IExpr! RootType { get; }
+
+ /// <summary>
+ /// Returns true iff "t" denotes a type constant.
+ /// </summary>
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ bool IsTypeConstant(IExpr! t);
+
+ /// <summary>
+ /// Returns true iff t0 and t1 are types such that t0 and t1 are equal.
+ /// </summary>
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ bool IsTypeEqual(IExpr! t0, IExpr! t1);
+
+ /// <summary>
+ /// Returns true iff t0 and t1 are types such that t0 is a subtype of t1.
+ /// </summary>
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ bool IsSubType(IExpr! t0, IExpr! t1);
+
+ /// <summary>
+ /// Returns the most derived supertype of both "t0" and "t1". A precondition is
+ /// that "t0" and "t1" both represent types.
+ /// </summary>
+ IExpr! JoinTypes(IExpr! t0, IExpr! t1);
+
+ IFunApp! IsExactlyA(IExpr! e, IExpr! type) /*requires IsTypeConstant(type); ensures result.FunctionSymbol.Equals(Value.Eq);*/;
+ IFunApp! IsA(IExpr! e, IExpr! type) /*requires IsTypeConstant(type); ensures result.FunctionSymbol.Equals(Value.Subtype);*/;
+ }
+
+}
diff --git a/Source/AIFramework/Expr.ssc b/Source/AIFramework/Expr.ssc
new file mode 100644
index 00000000..94dc4dc7
--- /dev/null
+++ b/Source/AIFramework/Expr.ssc
@@ -0,0 +1,447 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+// This file specifies the expression language used by the Abstract
+// Interpretation Framework.
+//
+// expressions e ::= x variables
+// | f(e1,...,en) uninterpreted functions
+// | \x:t.e lambda expressions
+//
+// types t ::= b user-defined/built-in base types
+// | t1 * ... * tn -> t' function type
+
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using System.Collections;
+ using Microsoft.Contracts;
+
+ //----------------------------- Expressions -----------------------------
+
+ /// <summary>
+ /// An interface for expressions. This expression language is specified
+ /// by interfaces to allow the client to be able to use their existing
+ /// AST nodes as AIF expressions.
+ ///
+ /// This only serves as a place for operations on expressions. Clients
+ /// should implement directly either IVariable or IFunApp.
+ /// </summary>
+ public interface IExpr
+ {
+ /// <summary>
+ /// Execute a visit over the expression.
+ /// </summary>
+ /// <param name="visitor">The expression visitor.</param>
+ /// <returns>The result of the visit.</returns>
+ [Pure][Reads(ReadsAttribute.Reads.Owned)] object DoVisit(ExprVisitor! visitor);
+
+ // TODO: Type checking of the expressions.
+ }
+
+ /// <summary>
+ /// An interface for variables.
+ ///
+ /// This interface should be implemented by the client.
+ /// </summary>
+ public interface IVariable : IExpr
+ {
+ string! Name { get; } // Each client must define the name for variables
+ }
+
+ /// <summary>
+ /// An interface for function applications.
+ ///
+ /// This interface should be implemented by the client.
+ /// </summary>
+ public interface IFunApp : IExpr
+ {
+ IFunctionSymbol! FunctionSymbol { [Pure][Reads(ReadsAttribute.Reads.Owned)] get; }
+ IList/*<IExpr!>*/! Arguments
+ {
+ [Pure][Reads(ReadsAttribute.Reads.Owned)][Rep] get
+ ensures result.IsReadOnly;
+ ;
+ }
+
+ /// <summary>
+ /// Provides a method to create a new uninterpreted function
+ /// with the same function symbol but with the arguments with
+ /// args.
+ /// </summary>
+ /// <param name="args">The new arguments.</param>
+ /// <returns>A copy of the function with the new arguments.</returns>
+ IFunApp! CloneWithArguments(IList/*<IExpr!>*/! args)
+ //TODO requires this.Arguments.Count == args.Count;
+ ;
+ }
+
+ /// <summary>
+ /// An interface for anonymous functions (i.e., lambda expressions)
+ /// </summary>
+ public interface IFunction : IExpr
+ {
+ IVariable! Param { [Pure][Reads(ReadsAttribute.Reads.Owned)] get; }
+ AIType! ParamType { [Pure][Reads(ReadsAttribute.Reads.Owned)] get; }
+ IExpr! Body { [Pure][Reads(ReadsAttribute.Reads.Owned)] get; }
+
+ IFunction! CloneWithBody(IExpr! body);
+ }
+
+ /// <summary>
+ /// An abstract class that provides an interface for expression visitors.
+ /// </summary>
+ public abstract class ExprVisitor
+ {
+ public abstract object Default(IExpr! expr);
+
+ public virtual object VisitVariable(IVariable! var)
+ {
+ return Default(var);
+ }
+
+ public virtual object VisitFunApp(IFunApp! funapp)
+ {
+ return Default(funapp);
+ }
+
+ public virtual object VisitFunction(IFunction! fun)
+ {
+ return Default(fun);
+ }
+ }
+
+ /// <summary>
+ /// A utility class for dealing with expressions.
+ /// </summary>
+ public sealed class ExprUtil
+ {
+ /// <summary>
+ /// Yield an expression that is 'inexpr' with 'var' replaced by 'subst'.
+ /// </summary>
+ /// <param name="subst">The expression to substitute.</param>
+ /// <param name="var">The variable to substitute for.</param>
+ /// <param name="inexpr">The expression to substitute into.</param>
+ public static IExpr! Substitute(IExpr! subst, IVariable! var, IExpr! inexpr)
+ {
+ IExpr result = null;
+
+ if (inexpr is IVariable)
+ {
+ result = inexpr.Equals(var) ? subst : inexpr;
+ }
+ else if (inexpr is IFunApp)
+ {
+ IFunApp! funapp = (IFunApp!)inexpr;
+ IList newargs = null;
+ newargs = new ArrayList{ IExpr! arg in funapp.Arguments; Substitute(subst, var, arg) };
+ result = funapp.CloneWithArguments(newargs);
+ }
+ else if (inexpr is IFunction)
+ {
+ IFunction! fun = (IFunction!)inexpr;
+
+ if (fun.Param.Equals(var))
+ result = fun;
+ else
+ result = fun.CloneWithBody(Substitute(subst, var, fun.Body));
+ }
+ else
+ {
+ assert false;
+ }
+
+ return result;
+ }
+
+
+ //
+ // Poor man's pattern matching.
+ //
+ // The methods below implement pattern matching for AI expressions.
+ //
+ // Example Usage:
+ // Match(e, Prop.Imp,
+ // (Matcher)delegate (IExpr e) { return Match(e, Prop.And, out x, out y); }
+ // out z)
+ // which sees if 'e' matches Prop.Imp(Prop.And(x,y),z) binding x,y,z to the subtrees.
+ //
+ public delegate bool Matcher(IExpr! expr);
+
+ private static IFunApp/*?*/ MatchFunctionSymbol(IExpr! expr, IFunctionSymbol! f)
+ {
+ IFunApp app = expr as IFunApp;
+ if (app != null)
+ {
+ if (app.FunctionSymbol.Equals(f))
+ return app;
+ else
+ return null;
+ }
+ else
+ return null;
+ }
+
+ public static bool Match(IExpr! expr, IFunctionSymbol! f, params Matcher[]! subs)
+ {
+ IFunApp app = MatchFunctionSymbol(expr,f);
+ if (app != null)
+ {
+ int i = 0; // Note ***0***
+ foreach (Matcher! s in subs)
+ {
+ if (!s((IExpr!)app.Arguments[i])) { return false; }
+ i++;
+ }
+ return true;
+ }
+ else { return false; }
+ }
+
+ // Unary Binding
+ public static bool Match(IExpr! expr, IFunctionSymbol! f, out IExpr arg0, params Matcher[]! subs)
+ {
+ arg0 = null;
+
+ IFunApp app = MatchFunctionSymbol(expr,f);
+ if (app != null)
+ {
+ arg0 = (IExpr!)app.Arguments[0];
+
+ int i = 1; // Note ***1***
+ foreach (Matcher! s in subs)
+ {
+ if (!s((IExpr!)app.Arguments[i])) { return false; }
+ i++;
+ }
+ return true;
+ }
+ else { return false; }
+ }
+
+ // Binary Binding
+ public static bool Match(IExpr! expr, IFunctionSymbol! f, Matcher! sub0, out IExpr arg1, params Matcher[]! subs)
+ {
+ arg1 = null;
+
+ IFunApp app = MatchFunctionSymbol(expr,f);
+ if (app != null)
+ {
+ if (!sub0((IExpr!)app.Arguments[0])) { return false; }
+
+ arg1 = (IExpr!)app.Arguments[1];
+
+ int i = 2; // Note ***2***
+ foreach (Matcher! s in subs)
+ {
+ if (!s((IExpr!)app.Arguments[i])) { return false; }
+ i++;
+ }
+ return true;
+ }
+ else { return false; }
+ }
+
+ public static bool Match(IExpr! expr, IFunctionSymbol! f, out IExpr arg0, out IExpr arg1, params Matcher[]! subs)
+ {
+ arg0 = null;
+ arg1 = null;
+
+ IFunApp app = MatchFunctionSymbol(expr,f);
+ if (app != null)
+ {
+ arg0 = (IExpr!)app.Arguments[0];
+ arg1 = (IExpr!)app.Arguments[1];
+
+ int i = 2; // Note ***2***
+ foreach (Matcher! s in subs)
+ {
+ if (!s((IExpr!)app.Arguments[i])) { return false; }
+ i++;
+ }
+ return true;
+ }
+ else { return false; }
+ }
+
+ // Ternary Binding
+ public static bool Match(IExpr! expr, IFunctionSymbol! f, out IExpr arg0, out IExpr arg1, out IExpr arg2, params Matcher[]! subs)
+ {
+ arg0 = null;
+ arg1 = null;
+ arg2 = null;
+
+ IFunApp app = MatchFunctionSymbol(expr,f);
+ if (app != null)
+ {
+ arg0 = (IExpr!)app.Arguments[0];
+ arg1 = (IExpr!)app.Arguments[1];
+ arg2 = (IExpr!)app.Arguments[2];
+
+ int i = 3; // Note ***3***
+ foreach (Matcher! s in subs)
+ {
+ if (!s((IExpr!)app.Arguments[i])) { return false; }
+ i++;
+ }
+ return true;
+ }
+ else { return false; }
+ }
+
+ /// <summary>
+ /// Not intended to be instantiated.
+ /// </summary>
+ private ExprUtil() { }
+ }
+
+ //------------------------------ Symbols --------------------------------
+
+ /// <summary>
+ /// An interface for function symbols. Constants are represented by
+ /// 0-ary function symbols.
+ ///
+ /// This interface should be implemented by abstract domains, but client
+ /// expressions need keep track of function symbols.
+ /// </summary>
+ public interface IFunctionSymbol
+ {
+ AIType! AIType { [Pure][Reads(ReadsAttribute.Reads.Owned)][Rep][ResultNotNewlyAllocated]
+ get; }
+ }
+
+ /// <summary>
+ /// The type of the arguments to ExprUtil.Match, a poor man's pattern
+ /// matching.
+ /// </summary>
+ public interface IMatchable
+ {
+ }
+
+ //-------------------------------- Types --------------------------------
+
+ /// <summary>
+ /// Types.
+ /// </summary>
+ public interface AIType
+ {
+ }
+
+ /// <summary>
+ /// Function type constructor.
+ /// </summary>
+ public sealed class FunctionType : AIType
+ {
+ /*[Own]*/ private readonly IList/*<Type!>*/! argTypes;
+ /*[Own]*/ private readonly AIType! retType;
+
+ public FunctionType(params AIType[]! types)
+ requires types.Length >= 2;
+ {
+ AIType type = types[types.Length-1];
+ assume type != null;
+ this.retType = type;
+ ArrayList argTypes = new ArrayList();
+ for (int i = 0; i < types.Length-1; i++)
+ {
+ type = types[i];
+ assume type != null;
+ argTypes.Add(types);
+ }
+ this.argTypes = ArrayList.ReadOnly(argTypes);
+ }
+
+ public IList/*<AIType!>*/! Arguments
+ {
+ [Pure][Reads(ReadsAttribute.Reads.Owned)][Rep]
+ get
+ ensures result.IsReadOnly;
+ {
+ return argTypes;
+ }
+ }
+
+ public int Arity
+ {
+ [Pure][Reads(ReadsAttribute.Reads.Owned)] get { return argTypes.Count; }
+ }
+
+ public AIType! ReturnType
+ {
+ [Pure][Reads(ReadsAttribute.Reads.Owned)] get { return retType; }
+ }
+
+ /* TODO Do we have the invariant that two functions are equal iff they're the same object.
+ public override bool Equals(object o)
+ {
+ if (o != null && o is FunctionType)
+ {
+ FunctionType other = (FunctionType) o;
+
+ if (Arity == other.Arity
+ && ReturnType.Equals(other.ReturnType))
+ {
+ for (int i = 0; i < Arity; i++)
+ {
+ if (!argTypes[i].Equals(other.argTypes[i]))
+ return false;
+ }
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+ }
+ */
+ }
+
+ //------------------------------ Queries -------------------------------
+
+ public enum Answer { Yes, No, Maybe };
+
+ /// <summary>
+ /// An interface that specifies a queryable object that can answer
+ /// whether a predicate holds.
+ /// </summary>
+ public interface IQueryable
+ {
+ /// <summary>
+ /// Answers the query whether the given predicate holds.
+ /// </summary>
+ /// <param name="pred">The given predicate.</param>
+ /// <returns>Yes, No, or Maybe.</returns>
+ Answer CheckPredicate(IExpr! pred);
+
+ /// <summary>
+ /// A simplified interface for disequalities. One can always
+ /// implement this by calling CheckPredicate, but it may be
+ /// more efficient with this method.
+ /// </summary>
+ Answer CheckVariableDisequality(IVariable! var1, IVariable! var2);
+ }
+
+ public static class QueryUtil
+ {
+ public static Answer Negate(Answer ans)
+ {
+ switch (ans)
+ {
+ case Answer.Yes:
+ return Answer.No;
+ case Answer.No:
+ return Answer.Yes;
+ default:
+ return Answer.Maybe;
+ }
+ }
+ }
+
+ //----------------------------- Exceptions -----------------------------
+
+ public class TypeError : CheckedException
+ {
+ }
+}
diff --git a/Source/AIFramework/Functional.ssc b/Source/AIFramework/Functional.ssc
new file mode 100644
index 00000000..4c4a5791
--- /dev/null
+++ b/Source/AIFramework/Functional.ssc
@@ -0,0 +1,284 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using Microsoft.Contracts;
+
+namespace Microsoft.AbstractInterpretationFramework.Collections
+{
+ using System.Collections;
+
+ /// <summary>Represents a functional collection of key/value pairs.</summary>
+ /// <filterpriority>2</filterpriority>
+ public interface IFunctionalMap : System.Collections.ICollection, System.Collections.IEnumerable
+ {
+ /// <summary>Adds an element with the provided key and value to the <see cref="T:Microsoft.AbstractInterpretationFramework.Collections.IFunctionalMap" />.</summary>
+ /// <param name="value">The <see cref="T:System.Object" /> to use as the value of the element to add. </param>
+ /// <param name="key">The <see cref="T:System.Object" /> to use as the key of the element to add. </param>
+ /// <filterpriority>2</filterpriority>
+ IFunctionalMap! Add(object! key, object value);
+
+ /// <summary>
+ /// Set the value of the key (that is already in the map)
+ /// </summary>
+ IFunctionalMap! Set(object! key, object value);
+
+ /// <summary>Determines whether the <see cref="T:Microsoft.AbstractInterpretationFramework.Collections.IFunctionalMap" /> contains an element with the specified key.</summary>
+ /// <returns>true if the <see cref="T:Microsoft.AbstractInterpretationFramework.Collections.IFunctionalMap" /> contains an element with the key; otherwise, false.</returns>
+ /// <param name="key">The key to locate in the <see cref="T:Microsoft.AbstractInterpretationFramework.Collections.IFunctionalMap" />. </param>
+ /// <filterpriority>2</filterpriority>
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ bool Contains(object! key);
+
+ /// <summary>Returns an <see cref="T:System.Collections.IDictionaryEnumerator" /> for the <see cref="T:Microsoft.AbstractInterpretationFramework.Collections.IFunctionalMap" />.</summary>
+ /// <returns>An <see cref="T:System.Collections.IDictionaryEnumerator" /> for the <see cref="T:Microsoft.AbstractInterpretationFramework.Collections.IFunctionalMap" />.</returns>
+ /// <filterpriority>2</filterpriority>
+ [Pure] [GlobalAccess(false)] [Escapes(true,false)]
+ new System.Collections.IDictionaryEnumerator GetEnumerator();
+
+ /// <summary>Gets an <see cref="T:System.Collections.ICollection" /> containing the keys of the <see cref="T:Microsoft.AbstractInterpretationFramework.Collections.IFunctionalMap" />.</summary>
+ /// <returns>An <see cref="T:System.Collections.ICollection" /> containing the keys of the <see cref="T:Microsoft.AbstractInterpretationFramework.Collections.IFunctionalMap" />.</returns>
+ /// <filterpriority>2</filterpriority>
+ System.Collections.ICollection Keys { get; }
+
+ /// <summary>Removes the element with the specified key from the <see cref="T:Microsoft.AbstractInterpretationFramework.Collections.IFunctionalMap" />.</summary>
+ /// <param name="key">The key of the element to remove. </param>
+ /// <filterpriority>2</filterpriority>
+ IFunctionalMap! Remove(object! key);
+
+ /// <summary>Gets an <see cref="T:System.Collections.ICollection" /> containing the values in the <see cref="T:Microsoft.AbstractInterpretationFramework.Collections.IFunctionalMap" />.</summary>
+ /// <returns>An <see cref="T:System.Collections.ICollection" /> containing the values in the <see cref="T:Microsoft.AbstractInterpretationFramework.Collections.IFunctionalMap" />.</returns>
+ /// <filterpriority>2</filterpriority>
+ System.Collections.ICollection Values { get; }
+
+ object this [object! key] { get; /*set;*/ }
+ }
+
+
+
+ /// <summary>
+ /// An implementation of the
+ /// <see cref="T:Microsoft.AbstractInterpretationFramework.Collections.IFunctionalMap" />
+ /// interface with a <see cref="T:System.Collections.Hashtable" /> as the backing store.
+ /// </summary>
+ class FunctionalHashtable : IFunctionalMap
+ {
+ private readonly Hashtable! h;
+
+ /// <summary>
+ /// Cannot directly construct an instance of a FunctionalHashtbl.
+ /// </summary>
+ private FunctionalHashtable()
+ {
+ this.h = new Hashtable();
+ // base();
+ }
+
+ /// <summary>
+ /// Cannot directly construct an instance of a FunctionalHashtbl.
+ /// </summary>
+ private FunctionalHashtable(Hashtable! h)
+ {
+ this.h = h;
+ // base();
+ }
+
+ private static readonly IFunctionalMap! empty = new FunctionalHashtable();
+ public static IFunctionalMap! Empty { get { return empty; } }
+
+ public IFunctionalMap! Add(object! key, object value)
+ {
+ Hashtable r = h.Clone() as Hashtable;
+ assume r != null;
+ r.Add(key, value);
+ return new FunctionalHashtable(r);
+ }
+
+ public IFunctionalMap! Set(object! key, object value)
+ {
+ Hashtable r = h.Clone() as Hashtable;
+
+ assume r != null;
+ assert this.Contains(key); // The entry must be defined
+
+ r[key] = value;
+ return new FunctionalHashtable(r);
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public bool Contains(object! key)
+ {
+ return h.Contains(key);
+ }
+
+ [Pure] [GlobalAccess(false)] [Escapes(true,false)]
+ IEnumerator! IEnumerable.GetEnumerator()
+ {
+ return h.GetEnumerator();
+ }
+
+ [Pure] [GlobalAccess(false)] [Escapes(true,false)]
+ IDictionaryEnumerator IFunctionalMap.GetEnumerator()
+ {
+ return h.GetEnumerator();
+ }
+
+ public ICollection Keys
+ {
+ get { return h.Keys; }
+ }
+
+ public IFunctionalMap! Remove(object! key)
+ {
+ Hashtable r = h.Clone() as Hashtable;
+ assume r != null;
+ r.Remove(key);
+ return new FunctionalHashtable(r);
+ }
+
+ public ICollection Values
+ {
+ get { return h.Values; }
+ }
+
+
+ public object this[object! key]
+ {
+ get { return h[key]; }
+ }
+
+ public int Count
+ {
+ [Pure] get { return h.Count; }
+ }
+
+ public bool IsSynchronized
+ {
+ [Pure] get { return h.IsSynchronized; }
+ }
+
+ public object! SyncRoot
+ {
+ [Pure] get { return h.SyncRoot; }
+ }
+
+ public void CopyTo(System.Array! a, int index)
+ {
+ h.CopyTo(a, index);
+ }
+ }
+
+ public struct Pair/*<T1,T2>*/
+ {
+ private object first;
+ private object second;
+
+ public object First { get { return first; } }
+ public object Second { get { return second; } }
+
+ public Pair(object first, object second)
+ {
+ this.first = first;
+ this.second = second;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null) return false;
+ if (!(obj is Pair)) return false;
+
+ Pair other = (Pair)obj;
+ return object.Equals(this.first, other.first) && object.Equals(this.second, other.second);
+ }
+
+ public override int GetHashCode()
+ {
+ int h = this.first == null ? 0 : this.first.GetHashCode();
+ h ^= this.second == null ? 0 : this.second.GetHashCode();
+ return h;
+ }
+ }
+}
+
+
+namespace Microsoft.AbstractInterpretationFramework.Collections.Generic
+{
+ using System.Collections.Generic;
+
+ public struct Pair<T1,T2>
+ {
+ private T1 first;
+ private T2 second;
+
+ public T1 First { get { return first; } }
+ public T2 Second { get { return second; } }
+
+ public Pair(T1 first, T2 second)
+ {
+ this.first = first;
+ this.second = second;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null) return false;
+ if (!(obj is Pair<T1,T2>)) return false;
+
+ Pair<T1,T2> other = (Pair<T1,T2>)obj;
+ return object.Equals(this.first, other.first) && object.Equals(this.second, other.second);
+ }
+
+ public override int GetHashCode()
+ {
+ int h = this.first == null ? 0 : this.first.GetHashCode();
+ h ^= this.second == null ? 0 : this.second.GetHashCode();
+ return h;
+ }
+
+ public override string! ToString()
+ {
+ return string.Format("({0},{1})", first, second);
+ }
+ }
+
+ public struct Triple<T1,T2,T3>
+ {
+ private T1 first;
+ private T2 second;
+ private T3 third;
+
+ public T1 First { get { return first; } }
+ public T2 Second { get { return second; } }
+ public T3 Third { get { return third; } }
+
+ public Triple(T1 first, T2 second, T3 third)
+ {
+ this.first = first;
+ this.second = second;
+ this.third = third;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null) return false;
+ if (!(obj is Triple<T1,T2,T3>)) return false;
+
+ Triple<T1,T2,T3> other = (Triple<T1,T2,T3>)obj;
+ return object.Equals(this.first, other.first) && object.Equals(this.second, other.second) && object.Equals(this.third, other.third);
+ }
+
+ public override int GetHashCode()
+ {
+ int h = this.first == null ? 0 : this.first.GetHashCode();
+ h ^= this.second == null ? 0 : this.second.GetHashCode();
+ h ^= this.third == null ? 0 : this.third.GetHashCode();
+ return h;
+ }
+
+ public override string! ToString()
+ {
+ return string.Format("({0},{1},{2})", first, second, third);
+ }
+ }
+}
diff --git a/Source/AIFramework/Lattice.ssc b/Source/AIFramework/Lattice.ssc
new file mode 100644
index 00000000..2b606492
--- /dev/null
+++ b/Source/AIFramework/Lattice.ssc
@@ -0,0 +1,685 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using Microsoft.Contracts;
+ using System.Collections;
+ using G = System.Collections.Generic;
+ using System.Diagnostics;
+ using Microsoft.AbstractInterpretationFramework.Collections;
+ using Microsoft.Boogie;
+ using IMutableSet = Microsoft.Boogie.Set;
+ using ISet = Microsoft.Boogie.Set;
+ using HashSet = Microsoft.Boogie.Set;
+ using ArraySet = Microsoft.Boogie.Set;
+
+
+
+ /// <summary>
+ /// Specifies the operations (e.g., join) on a mathematical lattice that depend
+ /// only on the elements of the lattice.
+ /// </summary>
+ public abstract class MathematicalLattice
+ {
+ /// <summary>
+ /// An element of the lattice. This class should be derived from in any
+ /// implementation of MathematicalLattice.
+ /// </summary>
+ public abstract class Element : System.ICloneable {
+ /// <summary>
+ /// Print out a debug-useful representation of the internal data structure of the lattice element.
+ /// </summary>
+ public virtual void Dump(string! msg) {
+ System.Console.WriteLine("Dump({0}) = {1}", msg, this);
+ }
+
+ public abstract Element! Clone();
+ object! System.ICloneable.Clone() { return this.Clone(); }
+
+ public abstract G.ICollection<IVariable!>! FreeVariables()
+ ensures result.IsReadOnly;
+ }
+
+ public abstract Element! Top { get; }
+ public abstract Element! Bottom { get; }
+
+ public abstract bool IsTop(Element! e);
+ public abstract bool IsBottom(Element! e);
+
+ /// <summary>
+ /// Returns true if a &lt;= this.
+ /// </summary>
+ protected abstract bool AtMost(Element! a, Element! b)
+ /* The following cases are handled elsewhere and need not be considered in subclass. */
+ // requires a.GetType() == b.GetType();
+ // requires ! a.IsTop;
+ // requires ! a.IsBottom;
+ // requires ! b.IsTop;
+ // requires ! b.IsBottom;
+ ;
+
+ protected Answer TrivialLowerThan(Element! a, Element! b)
+ {
+ if (a.GetType() != b.GetType())
+ {
+ throw new System.InvalidOperationException(
+ "operands to <= must be of same Element type"
+ );
+ }
+ if (IsBottom(a)) { return Answer.Yes; }
+ if (IsTop(b)) { return Answer.Yes; }
+ if (IsTop(a)) { return Answer.No; }
+ if (IsBottom(b)) { return Answer.No; }
+
+ return Answer.Maybe;
+ }
+
+ // Is 'a' better information than 'b'?
+ //
+ public bool LowerThan(Element! a, Element! b)
+ {
+ Answer ans = TrivialLowerThan(a,b);
+ return ans != Answer.Maybe ? ans == Answer.Yes : AtMost(a, b);
+ }
+
+ // Is 'a' worse information than 'b'?
+ //
+ public bool HigherThan(Element! a, Element! b)
+ {
+ return LowerThan(b, a);
+ }
+
+ // Are 'a' and 'b' equivalent?
+ //
+ public bool Equivalent(Element! a, Element! b)
+ {
+ return LowerThan(a, b) && LowerThan(b, a);
+ }
+
+ public abstract Element! NontrivialJoin(Element! a, Element! b)
+ /* The following cases are handled elsewhere and need not be considered in subclass. */
+ // requires a.GetType() == b.GetType();
+ // requires ! a.IsTop;
+ // requires ! a.IsBottom;
+ // requires ! b.IsTop;
+ // requires ! b.IsBottom;
+ ;
+
+ protected Element/*?*/ TrivialJoin(Element! a, Element! b)
+ {
+ if (a.GetType() != b.GetType())
+ {
+ throw new System.InvalidOperationException(
+ "operands to Join must be of same Lattice.Element type"
+ );
+ }
+ if (IsTop(a)) { return a; }
+ if (IsTop(b)) { return b; }
+ if (IsBottom(a)) { return b; }
+ if (IsBottom(b)) { return a; }
+
+ return null;
+ }
+
+ public Element! Join(Element! a, Element! b)
+ {
+ Element/*?*/ r = TrivialJoin(a,b);
+ return r != null ? r : NontrivialJoin(a, b);
+ }
+
+ public abstract Element! NontrivialMeet(Element! a, Element! b)
+ /* The following cases are handled elsewhere and need not be considered in subclass. */
+ // requires a.GetType() == b.GetType();
+ // requires ! a.IsTop;
+ // requires ! a.IsBottom;
+ // requires ! b.IsTop;
+ // requires ! b.IsBottom;
+ ;
+
+ protected Element/*?*/ TrivialMeet(Element! a, Element! b)
+ {
+ if (a.GetType() != b.GetType())
+ {
+ throw new System.InvalidOperationException(
+ "operands to Meet must be of same Lattice.Element type"
+ );
+ }
+ if (IsTop(a)) { return b; }
+ if (IsTop(b)) { return a; }
+ if (IsBottom(a)) { return a; }
+ if (IsBottom(b)) { return b; }
+
+ return null;
+ }
+
+ public Element! Meet(Element! a, Element! b)
+ {
+ Element/*?*/ r = TrivialMeet(a,b);
+ return r != null ? r : NontrivialMeet(a, b);
+ }
+
+ public abstract Element! Widen(Element! a, Element! b);
+
+ public virtual void Validate()
+ {
+ Debug.Assert(IsTop(Top));
+ Debug.Assert(IsBottom(Bottom));
+ Debug.Assert(!IsBottom(Top));
+ Debug.Assert(!IsTop(Bottom));
+
+ Debug.Assert(LowerThan(Top, Top));
+ Debug.Assert(LowerThan(Bottom, Top));
+ Debug.Assert(LowerThan(Bottom, Bottom));
+
+ Debug.Assert(IsTop(Join(Top, Top)));
+ Debug.Assert(IsBottom(Join(Bottom, Bottom)));
+ }
+ }
+
+
+ /// <summary>
+ /// Provides an abstract interface for the operations of a lattice specific
+ /// to abstract interpretation (i.e., that deals with the expression language).
+ /// </summary>
+ public abstract class Lattice : MathematicalLattice
+ {
+ internal readonly IValueExprFactory! valueExprFactory;
+
+ public Lattice(IValueExprFactory! valueExprFactory)
+ {
+ this.valueExprFactory = valueExprFactory;
+ // base();
+ }
+
+ #region Primitives that commands translate into
+
+ public abstract Element! Eliminate(Element! e, IVariable! variable);
+
+ public abstract Element! Rename(Element! e, IVariable! oldName, IVariable! newName);
+
+ public abstract Element! Constrain(Element! e, IExpr! expr);
+
+ #endregion
+
+
+// TODO keep this?
+// public Element! Eliminate(Element! e, VariableSeq! variables)
+// {
+// Lattice.Element result = e;
+// foreach (IVariable var in variables)
+// {
+// result = this.Eliminate(result, var);
+// }
+// return result;
+// }
+
+
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ // Note!
+ //
+ // Concrete classes that implement Lattice must implement one of the AtMost
+ // overloads. We provide here a default implementation for one given a "real"
+ // implementation of the other. Otherwise, there will be an infinite loop!
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ protected override bool AtMost(Element! a, Element! b)
+ {
+ return AtMost(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map);
+ }
+
+ protected virtual bool AtMost(Element! a, ICombineNameMap! aToResult, Element! b, ICombineNameMap! bToResult)
+ {
+ return AtMost(ApplyCombineNameMap(a,aToResult), ApplyCombineNameMap(b,bToResult));
+ }
+
+ public bool LowerThan(Element! a, ICombineNameMap! aToResult, Element! b, ICombineNameMap! bToResult)
+ {
+ Answer ans = TrivialLowerThan(a,b);
+ return ans != Answer.Maybe ? ans == Answer.Yes : AtMost(a, aToResult, b, bToResult);
+ }
+
+ public bool HigherThan(Element! a, ICombineNameMap! aToResult, Element! b, ICombineNameMap! bToResult)
+ {
+ return LowerThan(b, bToResult, a, aToResult);
+ }
+
+
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ // Note!
+ //
+ // Concrete classes that implement Lattice must implement one of the NontrivialJoin
+ // overloads. We provide here a default implementation for one given a "real"
+ // implementation of the other. Otherwise, there will be an infinite loop!
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ public override Element! NontrivialJoin(Element! a, Element! b)
+ {
+ return NontrivialJoin(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map);
+ }
+
+ public virtual Element! NontrivialJoin(Element! a, ICombineNameMap! aToResult, Element! b, ICombineNameMap! bToResult)
+ {
+ return NontrivialJoin(ApplyCombineNameMap(a,aToResult), ApplyCombineNameMap(b,bToResult));
+ }
+
+ public Element! Join(Element! a, ICombineNameMap! aToResult, Element! b, ICombineNameMap! bToResult)
+ {
+ Element/*?*/ r = TrivialJoin(a,b);
+ return r != null ? r : NontrivialJoin(a, aToResult, b, bToResult);
+ }
+
+
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ // Note!
+ //
+ // Concrete classes that implement Lattice must implement one of the Widen
+ // overloads. We provide here a default implementation for one given a "real"
+ // implementation of the other. Otherwise, there will be an infinite loop!
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ public override Element! Widen(Element! a, Element! b)
+ {
+ return Widen(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map);
+ }
+
+ public virtual Element! Widen(Element! a, ICombineNameMap! aToResult, Element! b, ICombineNameMap! bToResult)
+ {
+ return Widen(ApplyCombineNameMap(a,aToResult), ApplyCombineNameMap(b,bToResult));
+ }
+
+
+ /// <summary>
+ /// Returns the predicate that corresponds to the given lattice element.
+ /// </summary>
+ public abstract IExpr! ToPredicate(Element! e);
+
+ /// <summary>
+ /// Allows the lattice to specify whether it understands a particular function symbol.
+ ///
+ /// The lattice is always allowed to return "true" even when it really can't do anything
+ /// with such functions; however, it is advantageous to say "false" when possible to
+ /// avoid being called to do certain things.
+ ///
+ /// The arguments to a function are provided for context so that the lattice can say
+ /// true or false for the same function symbol in different situations. For example,
+ /// a lattice may understand the multiplication of a variable and a constant but not
+ /// of two variables. The implementation of a lattice should not hold on to the
+ /// arguments.
+ /// </summary>
+ /// <param name="f">The function symbol.</param>
+ /// <param name="args">The argument context.</param>
+ /// <returns>True if it may understand f, false if it does not understand f.</returns>
+ public abstract bool Understands(IFunctionSymbol! f, IList/*<IExpr!>*/! args);
+
+ /// <summary>
+ /// Return an expression that is equivalent to the given expression that does not
+ /// contain the given variable according to the lattice element and queryable.
+ /// </summary>
+ /// <param name="e">The lattice element.</param>
+ /// <param name="q">A queryable for asking addtional information.</param>
+ /// <param name="expr">The expression to find an equivalent expression.</param>
+ /// <param name="var">The variable to eliminate.</param>
+ /// <param name="prohibitedVars">The set of variables that can't be used in the resulting expression.</param>
+ /// <returns>
+ /// An equivalent expression to <paramref name="expr"/> without <paramref name="var"/>
+ /// or null if not possible.
+ /// </returns>
+ public abstract IExpr/*?*/ EquivalentExpr(Element! e, IQueryable! q, IExpr! expr, IVariable! var, Set/*<IVariable!>*/! prohibitedVars);
+
+ /// <summary>
+ /// Answers a query about whether the given predicate holds given the lattice element.
+ /// </summary>
+ /// <param name="e">The lattice element.</param>
+ /// <param name="pred">The predicate.</param>
+ /// <returns>Yes, No, or Maybe.</returns>
+ public abstract Answer CheckPredicate(Element! e, IExpr! pred);
+
+ /// <summary>
+ /// Answers a disequality about two variables. The same information could be obtained
+ /// by asking CheckPredicate, but a different implementation may be simpler and more
+ /// efficient.
+ /// </summary>
+ /// <param name="e">The lattice element.</param>
+ /// <param name="var1">The first variable.</param>
+ /// <param name="var2">The second variable.</param>
+ /// <returns>Yes, No, or Maybe.</returns>
+ public abstract Answer CheckVariableDisequality(Element! e, IVariable! var1, IVariable! var2);
+
+ /// <summary>
+ /// A default implementation of the <see cref="CheckVariableDisequality"/> given
+ /// the appropriate expression factories by calling CheckPredicate.
+ /// </summary>
+ protected Answer DefaultCheckVariableDisequality(
+ IPropExprFactory! propExprFactory, IValueExprFactory! valExprFactory,
+ Element! e, IVariable! var1, IVariable! var2)
+ {
+ return this.CheckPredicate(e, propExprFactory.Not(valExprFactory.Eq(var1, var2)));
+ }
+
+ private Element! ApplyCombineNameMap(Element! e, ICombineNameMap! eToResult)
+ {
+ Element! result = e;
+
+ foreach (G.KeyValuePair<IVariable!,ISet/*<IVariable!>*/!> entry in eToResult.GetSourceToResult())
+ {
+ IVariable! sourceName = entry.Key;
+ ISet/*<IVariable!*/! resultNames = entry.Value;
+
+ // Renaming s to r is okay if
+ // (1) s is not used in the result
+ // and (2) s has not been renamed already
+ bool renameOkay = !resultNames.Contains(sourceName);
+ IVariable! representative = sourceName;
+
+ foreach (IVariable! rname in resultNames)
+ {
+ // skip if sourceName and rname are the same
+ if (object.Equals(sourceName, rname)) { continue; }
+
+ if (renameOkay)
+ {
+ result = this.Rename(result, sourceName, rname);
+ representative = rname; // representative now rname
+ renameOkay = false; // no longer okay to rename
+ }
+ else
+ {
+ result = this.Constrain(result, valueExprFactory.Eq(representative, rname));
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private sealed class IdentityCombineNameMap : ICombineNameMap
+ {
+ public static readonly IdentityCombineNameMap! Map = new IdentityCombineNameMap();
+
+ private static readonly G.Dictionary<IVariable!,ISet/*<IVariable!>*/!>! emptyDictionary1 = new G.Dictionary<IVariable!,ISet/*<IVariable!>*/!>();
+ private static readonly G.Dictionary<IVariable!,IVariable!>! emptyDictionary2 = new G.Dictionary<IVariable!,IVariable!>();
+
+ public ISet/*<IVariable!>*//*?*/ GetResultNames(IVariable! srcname)
+ {
+ ArraySet a = new ArraySet();
+ a.Add(srcname);
+ return a;
+ }
+
+ public IVariable/*?*/ GetSourceName(IVariable! resname)
+ {
+ return resname;
+ }
+
+ //TODO: uncomment when works in compiler
+ //public G.IEnumerable<G.KeyValuePair<IVariable!,ISet/*<IVariable!>*/!>> GetSourceToResult()
+ public IEnumerable! GetSourceToResult()
+ {
+ return emptyDictionary1;
+ }
+
+ //public G.IEnumerable<G.KeyValuePair<IVariable!,IVariable!>> GetResultToSource()
+ public IEnumerable! GetResultToSource()
+ {
+ return emptyDictionary2;
+ }
+
+ private IdentityCombineNameMap() { }
+ }
+
+ public abstract string! ToString(Element! e); // for debugging
+
+ #region Support for MultiLattice to uniquely number every subclass of Lattice
+
+ private static Hashtable/*<System.Type,int>*/! indexMap = new Hashtable();
+ private static Hashtable/*<int,Lattice>*/! reverseIndexMap = new Hashtable();
+ private static int globalCount = 0;
+
+ protected virtual object! UniqueId { get { return (!)this.GetType(); } }
+
+ public int Index
+ {
+ get
+ {
+ object unique = this.UniqueId;
+ if (indexMap.ContainsKey(unique))
+ {
+ object index = indexMap[unique];
+ assert index != null; // this does nothing for nonnull analysis
+ if (index != null) { return (int)index; }
+ return 0;
+ }
+ else
+ {
+ int myIndex = globalCount++;
+ indexMap[unique] = myIndex;
+ reverseIndexMap[myIndex] = this;
+ return myIndex;
+ }
+ }
+ }
+
+ public static Lattice GetGlobalLattice(int i) { return reverseIndexMap[i] as Lattice; }
+ #endregion
+
+ public static bool LogSwitch = false;
+ }
+
+
+ /// <summary>
+ /// Defines the relation between names used in the respective input lattice elements to the
+ /// various combination operators (Join,Widen,Meet,AtMost) and the names that should be used
+ /// in the resulting lattice element.
+ /// </summary>
+ public interface ICombineNameMap
+ {
+ ISet/*<IVariable!>*//*?*/ GetResultNames(IVariable! srcname);
+ IVariable/*?*/ GetSourceName(IVariable! resname);
+
+ //TODO: uncommet when works in compiler
+ //G.IEnumerable<G.KeyValuePair<IVariable!,ISet/*<IVariable!>*/!>> GetSourceToResult();
+ IEnumerable! GetSourceToResult();
+ //G.IEnumerable<G.KeyValuePair<IVariable!,IVariable!>> GetResultToSource();
+ IEnumerable! GetResultToSource();
+ }
+
+ /// <summary>
+ /// Provides statistics on the number of times an operation is performed
+ /// and forwards the real operations to the given lattice in the constructor.
+ /// </summary>
+ public class StatisticsLattice : Lattice
+ {
+ readonly Lattice! lattice;
+ int eliminateCount;
+ int renameCount;
+ int constrainCount;
+ int toPredicateCount;
+ int atMostCount;
+ int topCount;
+ int bottomCount;
+ int isTopCount;
+ int isBottomCount;
+ int joinCount;
+ int meetCount;
+ int widenCount;
+ int understandsCount;
+ int equivalentExprCount;
+ int checkPredicateCount;
+ int checkVariableDisequalityCount;
+
+ public StatisticsLattice(Lattice! lattice)
+ : base(lattice.valueExprFactory)
+ {
+ this.lattice = lattice;
+ // base(lattice.valueExprFactory);
+ }
+
+ public override Element! Eliminate(Element! e, IVariable! variable)
+ {
+ eliminateCount++;
+ return lattice.Eliminate(e, variable);
+ }
+
+ public override Element! Rename(Element! e, IVariable! oldName, IVariable! newName)
+ {
+ renameCount++;
+ return lattice.Rename(e, oldName, newName);
+ }
+
+ public override Element! Constrain(Element! e, IExpr! expr)
+ {
+ constrainCount++;
+ return lattice.Constrain(e, expr);
+ }
+
+
+ public override bool Understands(IFunctionSymbol! f, IList! args)
+ {
+ understandsCount++;
+ return lattice.Understands(f, args);
+ }
+
+
+ public override IExpr/*?*/ EquivalentExpr(Element! e, IQueryable! q, IExpr! expr, IVariable! var, ISet/*<IVariable!>*/! prohibitedVars)
+ {
+ equivalentExprCount++;
+ return lattice.EquivalentExpr(e, q, expr, var, prohibitedVars);
+ }
+
+
+ public override Answer CheckPredicate(Element! e, IExpr! pred)
+ {
+ checkPredicateCount++;
+ return lattice.CheckPredicate(e, pred);
+ }
+
+
+ public override Answer CheckVariableDisequality(Element! e, IVariable! var1, IVariable! var2)
+ {
+ checkVariableDisequalityCount++;
+ return lattice.CheckVariableDisequality(e, var1, var2);
+ }
+
+
+
+ public override IExpr! ToPredicate(Element! e)
+ {
+ toPredicateCount++;
+ return lattice.ToPredicate(e);
+ }
+
+ public override string! ToString(Element! e)
+ {
+ return lattice.ToString(e);
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override string! ToString()
+ {
+ return string.Format(
+ "StatisticsLattice: #Eliminate={0} #Rename={1} #Constrain={2} #ToPredicate={3} " +
+ "#Understands={4} #EquivalentExpr={5} #CheckPredicate={6} #CheckVariableDisequality={7} " +
+ "#AtMost={8} #Top={9} #Bottom={9} #IsTop={10} #IsBottom={11} " +
+ "#NonTrivialJoin={12} #NonTrivialMeet={13} #Widen={14}",
+ eliminateCount, renameCount, constrainCount, toPredicateCount,
+ understandsCount, equivalentExprCount, checkPredicateCount, checkVariableDisequalityCount,
+ atMostCount, topCount, bottomCount, isTopCount, isBottomCount,
+ joinCount, meetCount, widenCount);
+ }
+
+ protected override bool AtMost(Element! a, Element! b)
+ {
+ atMostCount++;
+ return lattice.LowerThan(a, b);
+ }
+
+ public override Element! Top
+ {
+ get
+ {
+ topCount++;
+ return lattice.Top;
+ }
+ }
+ public override Element! Bottom
+ {
+ get
+ {
+ bottomCount++;
+ return lattice.Bottom;
+ }
+ }
+
+ public override bool IsTop(Element! e)
+ {
+ isTopCount++;
+ return lattice.IsTop(e);
+ }
+
+ public override bool IsBottom(Element! e)
+ {
+ isBottomCount++;
+ return lattice.IsBottom(e);
+ }
+
+ public override Element! NontrivialJoin(Element! a, Element! b)
+ {
+ joinCount++;
+ return lattice.NontrivialJoin(a, b);
+ }
+
+ public override Element! NontrivialMeet(Element! a, Element! b)
+ {
+ meetCount++;
+ return lattice.NontrivialMeet(a, b);
+ }
+
+ public override Element! Widen(Element! a, Element! b)
+ {
+ widenCount++;
+ return lattice.Widen(a, b);
+ }
+
+ public override void Validate()
+ {
+ base.Validate();
+ lattice.Validate();
+ }
+
+ protected override object! UniqueId
+ {
+ get
+ {
+ // use the base id, not the underlying-lattice id (is that the right thing to do?)
+ return base.UniqueId;
+ }
+ }
+ }
+
+
+ public sealed class LatticeQueryable : IQueryable
+ {
+ private Lattice! lattice;
+ private Lattice.Element! element;
+
+ public LatticeQueryable(Lattice! lattice, Lattice.Element! element)
+ {
+ this.lattice = lattice;
+ this.element = element;
+ // base();
+ }
+
+ public Answer CheckPredicate(IExpr! pred)
+ {
+ return lattice.CheckPredicate(element, pred);
+ }
+
+ public Answer CheckVariableDisequality(IVariable! var1, IVariable! var2)
+ {
+ return lattice.CheckVariableDisequality(element, var1, var2);
+ }
+ }
+}
diff --git a/Source/AIFramework/Logger.ssc b/Source/AIFramework/Logger.ssc
new file mode 100644
index 00000000..12c3ba08
--- /dev/null
+++ b/Source/AIFramework/Logger.ssc
@@ -0,0 +1,49 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using System;
+ using System.Diagnostics;
+
+ public class Logger
+ {
+ private string! dbgmsgContext;
+ private static int contextWidth = 0;
+
+ public bool Enabled = false;
+
+ public Logger(string! contextMsg)
+ {
+ this.dbgmsgContext = "[" + contextMsg + "] ";
+ contextWidth = Math.Max(contextWidth, contextMsg.Length + 3);
+ // base();
+ }
+
+ private static System.Text.StringBuilder! dbgmsgIndent = new System.Text.StringBuilder();
+ public void DbgMsgIndent() { dbgmsgIndent.Append(' ', 2); }
+ public void DbgMsgUnindent()
+ { if (dbgmsgIndent.Length >= 2) dbgmsgIndent.Remove(0,2); }
+
+ [ConditionalAttribute("DEBUG")]
+ public void DbgMsg(string msg)
+ {
+ if (Enabled)
+ Debug.WriteLine(dbgmsgContext.PadRight(contextWidth) + dbgmsgIndent + msg);
+ }
+ [ConditionalAttribute("DEBUG")]
+ public void DbgMsgNoLine(string msg)
+ {
+ if (Enabled)
+ Debug.Write(dbgmsgContext.PadRight(contextWidth) + dbgmsgIndent + msg);
+ }
+ [ConditionalAttribute("DEBUG")]
+ public void DbgMsgPlain(string msg)
+ {
+ if (Enabled)
+ Debug.Write(msg);
+ }
+ }
+}
diff --git a/Source/AIFramework/MultiLattice.ssc b/Source/AIFramework/MultiLattice.ssc
new file mode 100644
index 00000000..b6b6ba5e
--- /dev/null
+++ b/Source/AIFramework/MultiLattice.ssc
@@ -0,0 +1,563 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using Microsoft.Contracts;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using Microsoft.AbstractInterpretationFramework.Collections;
+
+ using Microsoft.Boogie;
+ using ISet = Microsoft.Boogie.Set;
+
+
+ /// <summary>
+ /// The cartesian product lattice.
+ /// </summary>
+ public class MultiLattice : Lattice, IEnumerable
+ {
+ internal class Elt : Element
+ {
+ public /*MaybeNull*/Element[] elementPerLattice;
+
+ public Elt(int domainCount, bool isBottom)
+ {
+ this.elementPerLattice = (domainCount == 0 && isBottom) ? null : new Element[domainCount];
+ }
+
+ private Elt(Elt! other)
+ {
+ Element[] otherEPL = other.elementPerLattice;
+ if (otherEPL != null)
+ {
+ Element[] newEPL = new Element[otherEPL.Length];
+ for (int i = 0; i < newEPL.Length; i++)
+ {
+ newEPL[i] = (Element) ((!)otherEPL[i]).Clone();
+ }
+ this.elementPerLattice = newEPL;
+ }
+ }
+
+ public override Element! Clone()
+ {
+ return new Elt(this);
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override string! ToString()
+ {
+// string s = "MultiLattice+Elt{";
+// string sep = "";
+// Element[] epl = this.elementPerLattice;
+// if (epl != null)
+// {
+// foreach (Element! e in epl)
+// {
+// s += sep + e.ToString();
+// sep = ", ";
+// }
+// }
+// return s + "}";
+ if (elementPerLattice == null) return "";
+ System.Text.StringBuilder buffer = new System.Text.StringBuilder();
+ for (int i = 0; i < this.Count; i++)
+ {
+ if (i > 0) buffer.Append("; ");
+ buffer.AppendFormat("{0}", elementPerLattice[i]);
+ }
+ return buffer.ToString();
+ }
+
+ public override void Dump(string! msg) {
+ System.Console.WriteLine("MultiLattice.Elt.Dump({0})", msg);
+ Element[] epl = this.elementPerLattice;
+ if (epl != null) {
+ foreach (Element! e in epl) {
+ e.Dump(msg);
+ }
+ }
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override ICollection<IVariable!>! FreeVariables()
+ {
+ List<IVariable!>! list = new List<IVariable!>();
+ for (int i = 0; i < this.Count; i++)
+ {
+ list.AddRange(((!)this[i]).FreeVariables());
+ }
+ return (!)list.AsReadOnly();
+ }
+
+ public static Elt! Top(ArrayList/*<Lattice>*/! lattices)
+ {
+ Elt multiValue = new Elt(lattices.Count, false);
+ for (int i = 0; i < lattices.Count; i++)
+ {
+ Lattice d = (Lattice!)lattices[i];
+ multiValue[d.Index] = d.Top;
+ }
+ Debug.Assert(multiValue.IsValid);
+ return multiValue;
+ }
+
+
+ public static Elt! Bottom(ArrayList/*<Lattice>*/! lattices)
+ {
+ Elt multiValue = new Elt(lattices.Count, true);
+ for (int i = 0; i < lattices.Count; i++)
+ {
+ Lattice d = (Lattice!)lattices[i];
+ multiValue[d.Index] = d.Bottom;
+ }
+ Debug.Assert(multiValue.IsValid);
+ return multiValue;
+ }
+
+ public bool IsValid
+ {
+ get
+ {
+ if (this.elementPerLattice == null) { return true; /*bottom*/ }
+
+ Element[] epl = this.elementPerLattice;
+ for (int i = 0; i < epl.Length; i++)
+ {
+ if (epl[i] == null) { return false; }
+ }
+ return true;
+ }
+ }
+
+ public int Count { get { return this.elementPerLattice == null ? 0 : this.elementPerLattice.Length; } }
+
+ public bool Contains(int i) { return 0 <= i && i < this.Count; }
+
+ public Element this[int i] // just syntactic sugar
+ {
+ get { Element[] epl = this.elementPerLattice; return epl == null ? null : epl[i]; }
+ set { Element[] epl = this.elementPerLattice; if (epl == null) return; epl[i] = value; }
+ }
+
+ } // class
+
+
+
+ ArrayList/*<Lattice>*/! lattices = new ArrayList();
+
+ private readonly IPropExprFactory! propExprFactory;
+
+
+ public MultiLattice(IPropExprFactory! propExprFactory, IValueExprFactory! valueExprFactory)
+ : base(valueExprFactory)
+ {
+ this.propExprFactory = propExprFactory;
+ // base(valueExprFactory);
+ }
+
+
+
+ public void AddLattice(Lattice lattice) { this.lattices.Add(lattice); }
+
+ private Lattice! SubLattice(int i) { return (Lattice!)this.lattices[i]; }
+
+
+ public override Element! Top { get { return Elt.Top(this.lattices); } }
+
+ public override Element! Bottom { get { return Elt.Bottom(this.lattices); } }
+
+
+
+
+ public override bool IsBottom(Element! element)
+ {
+ Elt e = (Elt)element;
+ // The program is errorneous/nonterminating if any subdomain knows it is.
+ //
+ if (e.elementPerLattice == null) { return true; }
+ for (int i = 0; i < e.Count; i++) { if (SubLattice(i).IsBottom((!)e[i])) { return true; } }
+ return false;
+ }
+
+ public override bool IsTop(Element! element)
+ {
+ Elt e = (Elt)element;
+ if (e.elementPerLattice == null) { return false; }
+ // The multidomain knows nothing about the program only if no subdomain
+ // knows anything about it.
+ //
+ for (int i = 0; i < e.Count; i++) { if (!SubLattice(i).IsTop((!)e[i])) { return false; } }
+ return true;
+ }
+
+ protected override bool AtMost(Element! first, Element! second)
+ {
+ Elt a = (Elt)first;
+ Elt b = (Elt)second;
+
+ for (int i = 0; i < a.Count; i++)
+ {
+ Element thisElement = (!) a[i];
+ Element thatElement = (!) b[i];
+ if (thisElement.GetType() != thatElement.GetType())
+ {
+ throw new System.InvalidOperationException(
+ "AtMost called on MultiDomain objects with different lattices"
+ );
+ }
+ if (!SubLattice(i).LowerThan(thisElement, thatElement)) { return false; }
+ }
+ return true;
+ }
+
+ protected override bool AtMost(Element! first, ICombineNameMap! firstToResult, Element! second, ICombineNameMap! secondToResult)
+ {
+ Elt a = (Elt)first;
+ Elt b = (Elt)second;
+
+ for (int i = 0; i < a.Count; i++)
+ {
+ Element thisElement = (!) a[i];
+ Element thatElement = (!) b[i];
+ if (thisElement.GetType() != thatElement.GetType())
+ {
+ throw new System.InvalidOperationException(
+ "AtMost called on MultiDomain objects with different lattices"
+ );
+ }
+ if (!SubLattice(i).LowerThan(thisElement, firstToResult, thatElement, secondToResult)) { return false; }
+ }
+ return true;
+ }
+
+
+ private enum CombineOp { Meet, Join, Widen }
+
+ private Element! Combine(Element! first, ICombineNameMap/*?*/ firstToResult, Element! second, ICombineNameMap/*?*/ secondToResult, CombineOp c)
+ {
+ Elt a = (Elt)first;
+ Elt b = (Elt)second;
+
+ int unionCount = System.Math.Max(a.Count, b.Count);
+ Elt combined = new Elt(unionCount, IsBottom(a) && IsBottom(b));
+ for (int i = 0; i < unionCount; i++)
+ {
+ bool thisExists = a.Contains(i);
+ bool thatExists = b.Contains(i);
+
+ if (thisExists && thatExists)
+ {
+ Lattice.Element suba = a[i];
+ Lattice.Element subb = b[i];
+ assert suba != null && subb != null;
+
+ switch (c)
+ {
+ case CombineOp.Meet:
+ combined[i] = SubLattice(i).Meet(suba, subb);
+ break;
+ case CombineOp.Join:
+ if (firstToResult != null && secondToResult != null)
+ combined[i] = SubLattice(i).Join(suba, firstToResult, subb, secondToResult);
+ else
+ combined[i] = SubLattice(i).Join(suba, subb);
+ break;
+ case CombineOp.Widen:
+ if (firstToResult != null && secondToResult != null)
+ combined[i] = SubLattice(i).Widen(suba, firstToResult, subb, secondToResult);
+ else
+ combined[i] = SubLattice(i).Widen(suba, subb);
+ break;
+ }
+ }
+ else if (thisExists)
+ {
+ combined[i] = a[i];
+ }
+ else
+ {
+ combined[i] = b[i];
+ }
+ }
+ Debug.Assert(combined.IsValid);
+ return combined;
+ }
+
+ public override Element! NontrivialJoin(Element! a, Element! b) { return this.Combine(a, null, b, null, CombineOp.Join); }
+
+ public override Element! NontrivialJoin(Element! a, ICombineNameMap! aToResult, Element! b, ICombineNameMap! bToResult) { return this.Combine(a, aToResult, b, bToResult, CombineOp.Join); }
+
+ public override Element! NontrivialMeet(Element! a, Element! b) { return this.Combine(a, null, b, null, CombineOp.Meet); }
+
+ public override Element! Widen(Element! a, Element! b) { return this.Combine(a, null, b, null, CombineOp.Widen); }
+
+ public override Element! Widen(Element! a, ICombineNameMap! aToResult, Element! b, ICombineNameMap! bToResult) { return this.Combine(a, aToResult, b, bToResult, CombineOp.Widen); }
+
+ public override Element! Eliminate(Element! element, IVariable! variable)
+ {
+ Elt e = (Elt)element;
+ if (IsBottom(e))
+ {
+ return e;
+ }
+ Elt newValue = new Elt(e.Count, false);
+ for (int i = 0; i < this.lattices.Count; i++)
+ {
+ newValue[i] = SubLattice(i).Eliminate((!) e[i], variable);
+ }
+ return newValue;
+ }
+
+
+ public override Element! Constrain(Element! element, IExpr! expr)
+ {
+ Elt e = (Elt)element;
+ if (IsBottom(e))
+ {
+ return e;
+ }
+ Elt newValue = new Elt(e.Count, false);
+ for (int i = 0; i < this.lattices.Count; i++)
+ {
+ newValue[i] = SubLattice(i).Constrain((!)e[i], expr);
+ }
+ return newValue;
+ }
+
+
+ public override Element! Rename(Element! element, IVariable! oldName, IVariable! newName)
+ {
+ Elt e = (Elt)element;
+ if (IsBottom(e))
+ {
+ return e;
+ }
+ Elt newValue = new Elt(e.Count, false);
+ for (int i = 0; i < this.lattices.Count; i++)
+ {
+ newValue[i] = SubLattice(i).Rename((!)e[i], oldName, newName);
+ }
+ return newValue;
+ }
+
+
+ public override bool Understands(IFunctionSymbol! f, IList! args)
+ {
+ bool result = false;
+
+ for (int i = 0; i < this.lattices.Count; i++)
+ {
+ result = (result || SubLattice(i).Understands(f, args));
+ }
+
+ return result;
+ }
+
+
+ public override string! ToString(Element! element)
+ {
+ Elt e = (Elt)element;
+ return e.ToString();
+ }
+
+
+ public override IExpr! ToPredicate(Element! element)
+ {
+ Elt e = (Elt)element;
+
+ IExpr result = propExprFactory.True;
+ for (int i = 0; i < e.Count; i++)
+ {
+ IExpr conjunct = SubLattice(i).ToPredicate((!)e[i]);
+ assert conjunct != null;
+
+ result = Prop.SimplifiedAnd(propExprFactory, conjunct, result);
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Return an expression that is equivalent to the given expression that does not
+ /// contain the given variable according to the lattice element and queryable.
+ ///
+ /// Simply asks each sublattice to try to generate an equivalent expression. We
+ /// do not try to combine information to infer new equivalences here.
+ /// </summary>
+ /// <param name="e">The lattice element.</param>
+ /// <param name="q">A queryable for asking addtional information.</param>
+ /// <param name="expr">The expression to find an equivalent expression.</param>
+ /// <param name="var">The variable to eliminate.</param>
+ /// <returns>
+ /// An equivalent expression to <paramref name="expr"/> without <paramref name="var"/>
+ /// or null if not possible.
+ /// </returns>
+ public override IExpr/*?*/ EquivalentExpr(Element! element, IQueryable! q, IExpr! expr, IVariable! var, Set/*<IVariable!>*/! prohibitedVars)
+ {
+ Elt! e = (Elt!)element;
+
+ for (int i = 0; i < e.Count; i++)
+ {
+ IExpr equivexpr = SubLattice(i).EquivalentExpr((!)e[i], q, expr, var, prohibitedVars);
+
+ if (equivexpr != null)
+ return equivexpr;
+ }
+
+ return null;
+ }
+
+
+ public override Answer CheckPredicate(Element! element, IExpr! pred)
+ {
+ Elt! e = (Elt!)element;
+
+ for (int i = 0; i < e.Count; i++)
+ {
+ Answer ans = SubLattice(i).CheckPredicate((!)e[i], pred);
+
+ if (ans == Answer.Yes || ans == Answer.No)
+ return ans;
+ }
+
+ return Answer.Maybe;
+ }
+
+
+ public override Answer CheckVariableDisequality(Element! element, IVariable! var1, IVariable! var2)
+ {
+ Elt! e = (Elt!)element;
+
+ for (int i = 0; i < e.Count; i++)
+ {
+ Answer ans = SubLattice(i).CheckVariableDisequality((!)e[i], var1, var2);
+
+ if (ans == Answer.Yes || ans == Answer.No)
+ return ans;
+ }
+
+ return Answer.Maybe;
+ }
+
+
+
+ public override void Validate()
+ {
+ base.Validate();
+ foreach (Lattice! l in lattices)
+ {
+ l.Validate();
+ }
+ }
+
+ /// <summary>
+ /// The enumeration over a MultiLattice is its sublattices.
+ /// </summary>
+ /// <returns>An enumerator over the sublattices.</returns>
+ [Pure] [GlobalAccess(false)] [Escapes(true,false)]
+ public IEnumerator/*<Lattice!>*/! GetEnumerator()
+ {
+ return lattices.GetEnumerator();
+ }
+
+ /// <summary>
+ /// Return an enumerable over a mapping of sublattices to the their corresponding
+ /// lattice elements given a MultiLattice element.
+ /// </summary>
+ /// <param name="element">The MultiLattice element.</param>
+ /// <returns>
+ /// An enumerable that yields an IDictionaryEnumerator over the
+ /// (Lattice, Lattice.Element) pairs.
+ /// </returns>
+ public IEnumerable! Subelements(Element! element)
+ {
+ return new SubelementsEnumerable(this, (Elt!) element);
+ }
+
+ /// <summary>
+ /// An enumerator over the sublattices and elements.
+ /// </summary>
+ private sealed class SubelementsEnumerable : IEnumerable
+ {
+ private sealed class SubelementsEnumerator : IDictionaryEnumerator
+ {
+ private readonly IEnumerator/*<Lattice!>*/! multiLatticeIter;
+ private readonly IEnumerator/*<Lattice.Element!>*/! multiElementIter;
+
+ public SubelementsEnumerator(MultiLattice! multiLattice, Elt! multiElement)
+ requires multiElement.elementPerLattice != null;
+ {
+ this.multiLatticeIter = multiLattice.lattices.GetEnumerator();
+ this.multiElementIter = multiElement.elementPerLattice.GetEnumerator();
+ // base();
+ }
+
+ public DictionaryEntry Entry
+ {
+ get
+ {
+ return new DictionaryEntry((!)multiLatticeIter.Current, multiElementIter.Current);
+ }
+ }
+
+ public object Key
+ {
+ get
+ {
+ return multiLatticeIter.Current;
+ }
+ }
+
+ public object Value
+ {
+ get
+ {
+ return multiElementIter.Current;
+ }
+ }
+
+ public object Current
+ {
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ get
+ {
+ return this.Entry;
+ }
+ }
+
+ public bool MoveNext()
+ {
+ return multiLatticeIter.MoveNext() && multiElementIter.MoveNext();
+ }
+
+ public void Reset()
+ {
+ multiLatticeIter.Reset();
+ multiElementIter.Reset();
+ }
+ }
+
+ private MultiLattice! multiLattice;
+ private Elt! multiElement;
+
+ public SubelementsEnumerable(MultiLattice! multiLattice, Elt! multiElement)
+ {
+ this.multiLattice = multiLattice;
+ this.multiElement = multiElement;
+ // base();
+ }
+
+ [Pure] [GlobalAccess(false)] [Escapes(true,false)]
+ public IEnumerator! GetEnumerator()
+ {
+ return new SubelementsEnumerator(multiLattice, multiElement);
+ }
+ }
+
+
+ }
+}
diff --git a/Source/AIFramework/Mutable.ssc b/Source/AIFramework/Mutable.ssc
new file mode 100644
index 00000000..894359ef
--- /dev/null
+++ b/Source/AIFramework/Mutable.ssc
@@ -0,0 +1,117 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+namespace Microsoft.AbstractInterpretationFramework.Collections
+{
+ using System.Collections;
+ using Microsoft.Contracts;
+
+ /// <summary>
+ /// Extend sets for using as a IWorkList.
+ /// </summary>
+ public class WorkSet : Microsoft.Boogie.Set, Microsoft.Boogie.IWorkList
+ {
+
+ // See Bug #148 for an explanation of why this is here.
+ // Without it, the contract inheritance rules will complain since it
+ // has nowhere to attach the out-of-band contract it gets from
+ // ICollection.Count that it gets from IWorkList.
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override int Count { get { return base.Count; } }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)] public bool IsEmpty()
+ {
+ return Count == 0;
+ }
+
+ /// <summary>
+ /// Pull an element out of the workset.
+ /// </summary>
+ public object Pull()
+ {
+ IEnumerator iter = GetEnumerator();
+ iter.MoveNext();
+
+ object result = (!)iter.Current;
+ Remove(result);
+
+ return result;
+ }
+
+ bool Microsoft.Boogie.IWorkList.Add(object o){
+ if (o == null) throw new System.ArgumentNullException();
+ this.Add(o);
+ return true;
+ }
+ bool Microsoft.Boogie.IWorkList.AddAll(IEnumerable objs){
+ if (objs == null) throw new System.ArgumentNullException();
+ return this.AddAll(objs);
+ }
+
+ // ICollection members
+ public void CopyTo (System.Array! a, int i) {
+ if (this.Count > a.Length - i) throw new System.ArgumentException();
+ int j = i;
+ foreach(object o in this){
+ a.SetValue(o, j++);
+ }
+ return;
+ }
+ object! ICollection.SyncRoot { [Pure] get { return this; } }
+ public bool IsSynchronized { get { return false; } }
+
+ }
+}
+
+namespace Microsoft.AbstractInterpretationFramework.Collections.Generic
+{
+ using System.Collections.Generic;
+
+ public class HashMultiset<T>
+ {
+ private readonly IDictionary<T,int>! dict;
+
+ //invariant forall{KeyValuePair<T,int> entry in dict; entry.Value >= 1};
+
+ public HashMultiset()
+ {
+ this.dict = new Dictionary<T,int>();
+ // base();
+ }
+
+ public HashMultiset(int size)
+ {
+ this.dict = new Dictionary<T,int>(size);
+ // base();
+ }
+
+ public void Add(T t)
+ { expose (this) {
+ if (dict.ContainsKey(t))
+ {
+ dict[t] = dict[t] + 1;
+ }
+ else
+ {
+ dict.Add(t,1);
+ }
+ }}
+
+ public void Remove(T t)
+ {
+ if (dict.ContainsKey(t))
+ { expose (this) {
+ int count = dict[t];
+ if (count == 1) { dict.Remove(t); }
+ else { dict[t] = count - 1; }
+ }}
+ }
+
+ public bool Contains(T t)
+ {
+ return dict.ContainsKey(t);
+ }
+ }
+}
diff --git a/Source/AIFramework/Polyhedra/LinearConstraint.ssc b/Source/AIFramework/Polyhedra/LinearConstraint.ssc
new file mode 100644
index 00000000..9ce1552b
--- /dev/null
+++ b/Source/AIFramework/Polyhedra/LinearConstraint.ssc
@@ -0,0 +1,588 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using Microsoft.Contracts;
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using System;
+ using System.Compiler;
+ using System.Collections;
+ using Microsoft.Basetypes;
+ using IMutableSet = Microsoft.Boogie.Set;
+ using HashSet = Microsoft.Boogie.Set;
+ using ISet = Microsoft.Boogie.Set;
+
+
+ /// <summary>
+ /// Represents a single linear constraint, coefficients are stored as Rationals.
+ /// </summary>
+ public class LinearConstraint
+ {
+
+ public enum ConstraintRelation
+ {
+ EQ, // equal
+ LE, // less-than or equal
+ }
+
+ public readonly ConstraintRelation Relation;
+ internal Hashtable /*IVariable->Rational*/! coefficients = new Hashtable /*IVariable->Rational*/ ();
+ internal Rational rhs;
+
+ public LinearConstraint (ConstraintRelation rel)
+ {
+ Relation = rel;
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override string! ToString()
+ {
+ string s = null;
+ foreach (DictionaryEntry /*IVariable->Rational*/ entry in coefficients)
+ {
+ if (s == null)
+ {
+ s = "";
+ }
+ else
+ {
+ s += " + ";
+ }
+ s += String.Format("{0}*{1}", entry.Value, entry.Key);
+ }
+ System.Diagnostics.Debug.Assert(s != null, "malformed LinearConstraint: no variables");
+ s += String.Format(" {0} {1}", Relation == ConstraintRelation.EQ ? "==" : "<=", rhs);
+ return s;
+ }
+
+
+#if DONT_KNOW_HOW_TO_TAKE_THE_TYPE_OF_AN_IVARIABLE_YET
+ public bool IsOverIntegers
+ {
+ get
+ {
+ foreach (DictionaryEntry /*IVariable->Rational*/ entry in coefficients)
+ {
+ IVariable var = (IVariable)entry.Key;
+ if ( ! var.TypedIdent.Type.IsInt) { return false; }
+ }
+ return true;
+ }
+ }
+#endif
+
+
+ /// <summary>
+ /// Note: This method requires that all dimensions are of type Variable, something that's
+ /// not required elsewhere in this class.
+ /// </summary>
+ /// <returns></returns>
+ public IExpr! ConvertToExpression(ILinearExprFactory! factory)
+ {
+ IExpr leftSum = null;
+ IExpr rightSum = null;
+ foreach (DictionaryEntry /*object->Rational*/ entry in coefficients)
+ {
+ IVariable var = (IVariable)entry.Key;
+ Rational coeff = (Rational) ((!)entry.Value);
+ if (coeff.IsPositive)
+ {
+ leftSum = AddTerm(factory, leftSum, coeff, var);
+ }
+ else if (coeff.IsNegative)
+ {
+ rightSum = AddTerm(factory, rightSum, -coeff, var);
+ }
+ else
+ {
+ // ignore the term is coeff==0
+ }
+ }
+
+ if (leftSum == null && rightSum == null)
+ {
+ // there are no variables in this constraint
+ if (Relation == ConstraintRelation.EQ ? rhs.IsZero : rhs.IsNonNegative) {
+ return factory.True;
+ } else {
+ return factory.False;
+ }
+ }
+
+ if (leftSum == null || (rightSum != null && rhs.IsNegative))
+ {
+ // show the constant on the left side
+ leftSum = AddTerm(factory, leftSum, -rhs, null);
+ }
+ else if (rightSum == null || rhs.IsPositive)
+ {
+ // show the constant on the right side
+ rightSum = AddTerm(factory, rightSum, rhs, null);
+ }
+
+ assert leftSum != null;
+ assert rightSum != null;
+ return Relation == ConstraintRelation.EQ ? factory.Eq(leftSum, rightSum) : factory.AtMost(leftSum, rightSum);
+ }
+
+ /// <summary>
+ /// Returns an expression that denotes sum + r*x.
+ /// If sum==null, drops the "sum +".
+ /// If x==null, drops the "*x".
+ /// if x!=null and r==1, drops the "r*".
+ /// </summary>
+ /// <param name="factory"></param>
+ /// <param name="sum"></param>
+ /// <param name="r"></param>
+ /// <param name="x"></param>
+ static IExpr! AddTerm(ILinearExprFactory! factory, /*MayBeNull*/ IExpr sum, Rational r, /*MayBeNull*/ IVariable x)
+ {
+ IExpr! product = factory.Term(r, x);
+ if (sum == null) {
+ return product;
+ } else {
+ return factory.Add(sum, product);
+ }
+ }
+
+ public ISet /*IVariable!*/! GetDefinedDimensions()
+ {
+ HashSet /*IVariable!*/ dims = new HashSet /*IVariable!*/ (coefficients.Count);
+ int j = 0;
+ foreach (IVariable! dim in coefficients.Keys)
+ {
+ dims.Add(dim);
+ j++;
+ }
+ System.Diagnostics.Debug.Assert(j == coefficients.Count);
+ return dims;
+ }
+
+ /// <summary>
+ /// Returns true iff all of the coefficients in the constraint are 0. In that
+ /// case, the constraint has the form 0 &lt;= C for some constant C; hence, the
+ /// constraint is either unsatisfiable or trivially satisfiable.
+ /// </summary>
+ /// <returns></returns>
+ public bool IsConstant()
+ {
+ foreach (Rational coeff in coefficients.Values)
+ {
+ if (coeff.IsNonZero)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// For an equality constraint, returns 0 == rhs.
+ /// For an inequality constraint, returns 0 &lt;= rhs.
+ /// </summary>
+ public bool IsConstantSatisfiable()
+ {
+ if (Relation == ConstraintRelation.EQ)
+ {
+ return rhs.IsZero;
+ }
+ else
+ {
+ return rhs.IsNonNegative;
+ }
+ }
+
+ /// <summary>
+ /// Returns 0 if "this" and "c" are not equivalent constraints. If "this" and "c"
+ /// are equivalent constraints, the non-0 return value "m" satisfies "this == m*c".
+ /// </summary>
+ /// <param name="c"></param>
+ /// <returns></returns>
+ public Rational IsEquivalent(LinearConstraint! c)
+ {
+ // "m" is the scale factor. If it is 0, it hasn't been used yet. If it
+ // is non-0, it will remain that value throughout, and it then says that
+ // for every dimension "d", "this[d] == m * c[d]".
+ Rational m = Rational.ZERO;
+
+ ArrayList /*IVariable*/ dd = new ArrayList /*IVariable*/ ();
+ foreach (IVariable! d in this.GetDefinedDimensions())
+ {
+ if (!dd.Contains(d)) { dd.Add(d); }
+ }
+ foreach (IVariable! d in c.GetDefinedDimensions())
+ {
+ if (!dd.Contains(d)) { dd.Add(d); }
+ }
+
+ foreach (IVariable! d in dd)
+ {
+ Rational a = this[d];
+ Rational b = c[d];
+
+ if (a.IsZero || b.IsZero)
+ {
+ if (a.IsNonZero || b.IsNonZero)
+ {
+ return Rational.ZERO; // not equivalent
+ }
+ }
+ else if (m.IsZero)
+ {
+ m = a / b;
+ }
+ else if (a != m * b)
+ {
+ return Rational.ZERO; // not equivalent
+ }
+ }
+
+ // we expect there to have been some non-zero coefficient, so "m" should have been used by now
+ System.Diagnostics.Debug.Assert(m.IsNonZero);
+
+ // finally, check the rhs
+ if (this.rhs == m * c.rhs)
+ {
+ return m; // equivalent
+ }
+ else
+ {
+ return Rational.ZERO; // not equivalent
+ }
+ }
+
+ /// <summary>
+ /// Splits an equality constraint into two inequality constraints, the conjunction of
+ /// which equals the equality constraint. Assumes "this" is a equality constraint.
+ /// </summary>
+ /// <param name="a"></param>
+ /// <param name="b"></param>
+ public void GenerateInequalityConstraints(out LinearConstraint a, out LinearConstraint b)
+ {
+ System.Diagnostics.Debug.Assert(this.Relation == ConstraintRelation.EQ);
+
+ a = new LinearConstraint(ConstraintRelation.LE);
+ a.coefficients = (Hashtable)this.coefficients.Clone();
+ a.rhs = this.rhs;
+
+ b = new LinearConstraint(ConstraintRelation.LE);
+ b.coefficients = new Hashtable /*IVariable->Rational*/ ();
+ foreach (DictionaryEntry entry in this.coefficients)
+ {
+ b.coefficients[entry.Key] = -(Rational) ((!)entry.Value);
+ }
+ b.rhs = -this.rhs;
+ }
+
+ public void SetCoefficient(IVariable! dimension, Rational coefficient)
+ {
+ coefficients[dimension] = coefficient;
+ }
+
+ /// <summary>
+ /// Removes dimension "dim" from the constraint. Only dimensions with coefficient 0 can
+ /// be removed.
+ /// </summary>
+ /// <param name="dim"></param>
+ public void RemoveDimension(IVariable! dim)
+ {
+ object val = coefficients[dim];
+ if (val != null)
+ {
+#if FIXED_SERIALIZER
+ assert ((Rational)val).IsZero;
+#endif
+ coefficients.Remove(dim);
+ }
+ }
+
+ /// <summary>
+ /// The getter returns 0 if the dimension is not present.
+ /// </summary>
+ public Rational this [IVariable! dimension]
+ {
+ get
+ {
+ object z = coefficients[dimension];
+ if (z == null)
+ {
+ return Rational.ZERO;
+ }
+ else
+ {
+ return (Rational)z;
+ }
+ }
+ set { SetCoefficient(dimension, value); }
+ }
+
+ public LinearConstraint Rename(IVariable! oldName, IVariable! newName)
+ {
+ object /*Rational*/ z = coefficients[oldName];
+ if (z == null)
+ {
+ return this;
+ }
+ else
+ {
+ System.Diagnostics.Debug.Assert(z is Rational);
+ Hashtable /*IVariable->Rational*/ newCoeffs = (Hashtable! /*IVariable->Rational*/)coefficients.Clone();
+ newCoeffs.Remove(oldName);
+ newCoeffs.Add(newName, z);
+
+ LinearConstraint lc = new LinearConstraint(this.Relation);
+ lc.coefficients = newCoeffs;
+ lc.rhs = this.rhs;
+ return lc;
+ }
+ }
+
+ public LinearConstraint Clone()
+ {
+ LinearConstraint z = new LinearConstraint(Relation);
+ z.coefficients = (Hashtable /*IVariable->Rational*/)this.coefficients.Clone();
+ z.rhs = this.rhs;
+ return z;
+ }
+
+ /// <summary>
+ /// Returns a constraint like "this", but with the given relation "r".
+ /// </summary>
+ /// <returns></returns>
+ public LinearConstraint! ChangeRelation(ConstraintRelation rel)
+ {
+ if (Relation == rel)
+ {
+ return this;
+ }
+ else
+ {
+ LinearConstraint z = new LinearConstraint(rel);
+ z.coefficients = (Hashtable)this.coefficients.Clone();
+ z.rhs = this.rhs;
+ return z;
+ }
+ }
+
+ /// <summary>
+ /// Returns a constraint like "this", but, conceptually, with the inequality relation >=.
+ /// </summary>
+ /// <returns></returns>
+ public LinearConstraint! ChangeRelationToAtLeast()
+ {
+ LinearConstraint z = new LinearConstraint(ConstraintRelation.LE);
+ foreach (DictionaryEntry /*IVariable->Rational*/ entry in this.coefficients)
+ {
+ z.coefficients.Add(entry.Key, -(Rational) ((!)entry.Value));
+ }
+ z.rhs = -this.rhs;
+ return z;
+ }
+
+ /// <summary>
+ /// Returns the left-hand side of the constraint evaluated at the point "v".
+ /// Any coordinate not present in "v" is treated as if it were 0.
+ /// Stated differently, this routine treats the left-hand side of the constraint
+ /// as a row vector and "v" as a column vector, and then returns the dot-product
+ /// of the two.
+ /// </summary>
+ /// <param name="v"></param>
+ /// <returns></returns>
+ public Rational EvaluateLhs(FrameElement! v)
+ {
+ Rational q = Rational.ZERO;
+ foreach (DictionaryEntry /*IVariable,Rational*/ term in coefficients)
+ {
+ IVariable dim = (IVariable!)term.Key;
+ Rational a = (Rational) ((!)term.Value);
+ Rational x = v[dim];
+ q += a * x;
+ }
+ return q;
+ }
+
+ /// <summary>
+ /// Determines whether or not a given vertex or ray saturates the constraint.
+ /// </summary>
+ /// <param name="fe"></param>
+ /// <param name="vertex">true if "fe" is a vertex; false if "fe" is a ray</param>
+ /// <returns></returns>
+ public bool IsSaturatedBy(FrameElement! fe, bool vertex)
+ {
+ Rational lhs = EvaluateLhs(fe);
+ Rational rhs = vertex ? this.rhs : Rational.ZERO;
+ return lhs == rhs;
+ }
+
+ /// <summary>
+ /// Changes the current constraint A*X &lt;= B into (A + m*aa)*X &lt;= B + m*bb,
+ /// where "cc" is the constraint aa*X &lt;= bb.
+ /// </summary>
+ /// <param name="m"></param>
+ /// <param name="cc"></param>
+ /// <returns></returns>
+ public void AddMultiple(Rational m, LinearConstraint! cc)
+ {
+ foreach (DictionaryEntry /*IVariable->Rational*/ entry in cc.coefficients)
+ {
+ IVariable dim = (IVariable)entry.Key;
+ Rational d = m * (Rational) ((!)entry.Value);
+ if (d.IsNonZero)
+ {
+ object prev = coefficients[dim];
+ if (prev == null)
+ {
+ coefficients[dim] = d;
+ }
+ else
+ {
+ coefficients[dim] = (Rational)prev + d;
+ }
+ }
+ }
+ rhs += m * cc.rhs;
+ }
+
+ /// <summary>
+ /// Try to reduce the magnitude of the coefficients used.
+ /// Has a side effect on the coefficients, but leaves the meaning of the linear constraint
+ /// unchanged.
+ /// </summary>
+ public void Normalize() {
+ // compute the gcd of the numerators and the gcd of the denominators
+ Rational gcd = rhs;
+ foreach (Rational r in coefficients.Values) {
+ gcd = Rational.Gcd(gcd, r);
+ }
+ // Change all coefficients, to divide their numerators with gcdNum and to
+ // divide their denominators with gcdDen.
+ Hashtable /*IVariable->Rational*/ newCoefficients = new Hashtable /*IVariable->Rational*/ (coefficients.Count);
+ foreach (DictionaryEntry /*IVarianble->Rational*/ e in coefficients) {
+ Rational r = (Rational) ((!)e.Value);
+ if (r.IsNonZero) {
+ newCoefficients.Add(e.Key, new Rational(r.Numerator / gcd.Numerator, r.Denominator / gcd.Denominator));
+ } else {
+ newCoefficients.Add(e.Key, r);
+ }
+ }
+
+ coefficients = newCoefficients;
+ rhs = rhs.IsNonZero ? (Rational)new Rational(rhs.Numerator / gcd.Numerator, rhs.Denominator / gcd.Denominator) : rhs;
+ }
+ }
+
+ /// <summary>
+ /// Represents a frame element (vector of dimension/value tuples). Used only
+ /// internally in class LinearConstraintSystem and its communication with class
+ /// LinearConstraint.
+ /// </summary>
+ public class FrameElement
+ {
+
+ Hashtable /*IVariable->Rational*/! terms = new Hashtable /*IVariable->Rational*/ ();
+
+ /// <summary>
+ /// Constructs an empty FrameElement. To add dimensions, call AddCoordinate after construction.
+ /// </summary>
+ public FrameElement()
+ {
+ }
+
+ /// <summary>
+ /// This method is to be thought of as being part of the FrameElement object's construction process.
+ /// Assumes "dimension" is not already in FrameElement.
+ /// </summary>
+ /// <param name="dimension"></param>
+ /// <param name="value"></param>
+ public void AddCoordinate(IVariable! dimension, Rational value)
+ {
+ terms.Add(dimension, value);
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override string! ToString()
+ {
+ string s = null;
+ foreach (DictionaryEntry item in terms)
+ {
+ if (s == null)
+ {
+ s = "(";
+ }
+ else
+ {
+ s += ", ";
+ }
+ s += String.Format("<{0},{1}>", item.Key, (Rational) ((!)item.Value));
+ }
+ if (s == null)
+ {
+ s = "(";
+ }
+ return s + ")";
+ }
+
+ public IMutableSet /*IVariable!*/! GetDefinedDimensions()
+ {
+ HashSet /*IVariable!*/! dims = new HashSet /*IVariable!*/ (terms.Count);
+ foreach (IVariable! dim in terms.Keys)
+ {
+ dims.Add(dim);
+ }
+ System.Diagnostics.Debug.Assert(dims.Count == terms.Count);
+ return dims;
+ }
+
+ /// <summary>
+ /// The getter returns the value at the given dimension, or 0 if that dimension is not defined.
+ /// </summary>
+ public Rational this [IVariable! dimension]
+ {
+ get
+ {
+ object z = terms[dimension];
+ if (z == null)
+ {
+ return Rational.ZERO;
+ }
+ else
+ {
+ return (Rational)z;
+ }
+ }
+ set
+ {
+ terms[dimension] = value;
+ }
+ }
+
+ public FrameElement Rename(IVariable! oldName, IVariable! newName)
+ {
+ object /*Rational*/ z = terms[oldName];
+ if (z == null)
+ {
+ return this;
+ }
+ else
+ {
+ System.Diagnostics.Debug.Assert(z is Rational);
+ Hashtable /*IVariable->Rational*/ newTerms = (Hashtable! /*IVariable->Rational*/)terms.Clone();
+ newTerms.Remove(oldName);
+ newTerms.Add(newName, z);
+
+ FrameElement fe = new FrameElement();
+ fe.terms = newTerms;
+ return fe;
+ }
+ }
+
+ public FrameElement Clone()
+ {
+ FrameElement z = new FrameElement();
+ z.terms = (Hashtable /*IVariable->Rational*/)this.terms.Clone();
+ return z;
+ }
+ }
+}
diff --git a/Source/AIFramework/Polyhedra/LinearConstraintSystem.ssc b/Source/AIFramework/Polyhedra/LinearConstraintSystem.ssc
new file mode 100644
index 00000000..b4e33a28
--- /dev/null
+++ b/Source/AIFramework/Polyhedra/LinearConstraintSystem.ssc
@@ -0,0 +1,1856 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System;
+ using Microsoft.SpecSharp.Collections;
+ using Microsoft.Contracts;
+ using Microsoft.Basetypes;
+ using IMutableSet = Microsoft.Boogie.Set;
+ using HashSet = Microsoft.Boogie.Set;
+ using ISet = Microsoft.Boogie.Set;
+
+ /// <summary>
+ /// Represents a system of linear constraints (constraint/frame representations).
+ /// </summary>
+ public class LinearConstraintSystem
+ {
+ // --------------------------------------------------------------------------------------------------------
+ // ------------------ Data structure ----------------------------------------------------------------------
+ // --------------------------------------------------------------------------------------------------------
+
+ public /*maybe null*/ ArrayList /*LinearConstraint!*/ Constraints;
+ /*maybe null*/ ArrayList /*FrameElement!*/ FrameVertices;
+ /*maybe null*/ ArrayList /*FrameElement!*/ FrameRays;
+ IMutableSet/*IVariable!*/! FrameDimensions;
+ /*maybe null*/ ArrayList /*FrameElement!*/ FrameLines;
+ // Invariant: Either all of Constraints, FrameVertices, FrameRays, and FrameLines are
+ // null, or all are non-null.
+ // Invariant: Any dimension mentioned in Constraints, FrameVertices, FrameRays, or
+ // FrameLines is mentioned in FrameDimensions.
+ // The meaning of FrameDimensions is that for any dimension x not in FrameDimensions,
+ // there is an implicit line along dimension x (that is, (<x,1>)).
+
+ void CheckInvariant()
+ {
+ if (Constraints == null)
+ {
+ System.Diagnostics.Debug.Assert(FrameVertices == null);
+ System.Diagnostics.Debug.Assert(FrameRays == null);
+ System.Diagnostics.Debug.Assert(FrameLines == null);
+ System.Diagnostics.Debug.Assert(FrameDimensions.Count == 0);
+ }
+ else
+ {
+ System.Diagnostics.Debug.Assert(FrameVertices != null);
+ System.Diagnostics.Debug.Assert(FrameRays != null);
+ System.Diagnostics.Debug.Assert(FrameLines != null);
+
+ foreach (LinearConstraint! cc in Constraints)
+ {
+#if FIXED_DESERIALIZER
+ assert Forall{IVariable! var in cc.GetDefinedDimensions(); FrameDimensions.Contains(var)};
+#endif
+ assert cc.coefficients.Count != 0;
+ }
+ foreach (ArrayList /*FrameElement*/! FrameComponent in new ArrayList /*FrameElement*/ [] {FrameVertices, FrameRays, FrameLines})
+ {
+ foreach (FrameElement fe in FrameComponent)
+ {
+ if (fe == null) continue;
+#if FIXED_DESERIALIZER
+ assert Forall{IVariable! var in fe.GetDefinedDimensions(); FrameDimensions.Contains(var)};
+#endif
+ }
+ }
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ // ------------------ Constructors ------------------------------------------------------------------------
+ // --------------------------------------------------------------------------------------------------------
+
+ /// <summary>
+ /// Creates a LinearConstraintSystem representing the bottom element, that is, representing
+ /// an unsatisfiable system of constraints.
+ /// </summary>
+ [NotDelayed]
+ public LinearConstraintSystem()
+ {
+ FrameDimensions = new HashSet /*IVariable!*/ ();
+ base();
+ CheckInvariant();
+ }
+
+ /// <summary>
+ /// Constructs a linear constraint system with constraints "cs".
+ /// The constructor captures all constraints in "cs".
+ /// </summary>
+ /// <param name="cs"></param>
+ [NotDelayed]
+ public LinearConstraintSystem(ArrayList /*LinearConstraint!*/! cs)
+#if BUG_159_HAS_BEEN_FIXED
+ requires Forall{LinearConstraint! cc in cs; cc.coefficients.Count != 0};
+#endif
+ {
+ ArrayList constraints = new ArrayList /*LinearConstraint!*/ (cs.Count);
+ foreach (LinearConstraint! cc in cs)
+ {
+ constraints.Add(cc);
+ }
+ Constraints = constraints;
+ FrameDimensions = new HashSet /*IVariable!*/ (); // to please compiler; this value will be overridden in the call to GenerateFrameConstraints below
+ base();
+
+ GenerateFrameFromConstraints();
+ SimplifyConstraints();
+ CheckInvariant();
+#if DEBUG_PRINT
+ Console.WriteLine("LinearConstraintSystem: constructor produced:");
+ Dump();
+#endif
+ }
+
+ /// <summary>
+ /// Constructs a linear constraint system corresponding to given vertex. This constructor
+ /// is only used in the test harness--it is not needed for abstract interpretation.
+ /// </summary>
+ /// <param name="v"></param>
+ [NotDelayed]
+ LinearConstraintSystem(FrameElement! v)
+ {
+ IMutableSet! frameDims = v.GetDefinedDimensions();
+ ArrayList /*LinearConstraint!*/ constraints = new ArrayList /*LinearConstraint!*/ ();
+ foreach (IVariable! dim in frameDims)
+ {
+ LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ);
+ lc.SetCoefficient(dim, Rational.ONE);
+ lc.rhs = v[dim];
+ constraints.Add(lc);
+ }
+ FrameDimensions = frameDims;
+ Constraints = constraints;
+
+ ArrayList /*FrameElement*/ frameVertices = new ArrayList /*FrameElement*/ ();
+ frameVertices.Add(v);
+ FrameVertices = frameVertices;
+
+ FrameRays = new ArrayList /*FrameElement*/ ();
+ FrameLines = new ArrayList /*FrameElement*/ ();
+
+ base();
+ CheckInvariant();
+ }
+
+ void ChangeIntoBottom()
+ {
+ Constraints = null;
+ FrameVertices = null;
+ FrameRays = null;
+ FrameLines = null;
+ IMutableSet ss;
+ FrameDimensions.Clear(); // no implicit lines
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ // ------------------ Public operations and their support routines ----------------------------------------
+ // --------------------------------------------------------------------------------------------------------
+
+ public bool IsBottom()
+ {
+ return Constraints == null;
+ }
+
+ public bool IsTop()
+ {
+ return Constraints != null && Constraints.Count == 0;
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override string! ToString()
+ {
+ if (Constraints == null)
+ {
+ return "<bottom>";
+ }
+ else if (Constraints.Count == 0)
+ {
+ return "<top>";
+ }
+ else
+ {
+ string z = null;
+ foreach (LinearConstraint! lc in Constraints)
+ {
+ string s = lc.ToString();
+ if (z == null)
+ {
+ z = s;
+ }
+ else
+ {
+ z += " AND " + s;
+ }
+ }
+ assert z != null;
+ return z;
+ }
+ }
+
+
+ public ICollection<IVariable!>! FreeVariables()
+ ensures result.IsReadOnly;
+ {
+ List<IVariable!> list = new List<IVariable!>();
+ foreach (IVariable! v in FrameDimensions) { list.Add(v); }
+ return (!)list.AsReadOnly();
+ }
+
+ /// <summary>
+ /// Note: This method requires that all dimensions are of type Variable, something that's
+ /// not required elsewhere in this class.
+ /// </summary>
+ /// <returns></returns>
+ public IExpr! ConvertToExpression(ILinearExprFactory! factory)
+ {
+ if (this.Constraints == null) {
+ return factory.False;
+ }
+ if (this.Constraints.Count == 0) {
+ return factory.True;
+ }
+
+ IExpr result = null;
+ foreach (LinearConstraint! lc in Constraints)
+ {
+ IExpr conjunct = lc.ConvertToExpression(factory);
+ result = (result == null) ? conjunct : (IExpr)factory.And(conjunct, result);
+ }
+ assert result != null;
+ return result;
+ }
+
+
+ /* IsSubset(): determines if 'lcs' is a subset of 'this'
+ * -- See Cousot/Halbwachs 1978, section
+ */
+ public bool IsSubset(LinearConstraintSystem! lcs)
+ {
+ if (lcs.IsBottom())
+ {
+ return true;
+ }
+ else if (this.IsBottom())
+ {
+ return false;
+#if DEBUG
+#else
+ } else if (this.IsTop()) { // optimization -- this case not needed for correctness
+ return true;
+ } else if (lcs.IsTop()) { // optimization -- this case not needed for correctness
+ return false;
+#endif
+ }
+ else
+ {
+ // phase 0: check if frame dimensions are a superset of the constraint dimensions
+ ISet /*IVariable!*/! frameDims = lcs.GetDefinedDimensions();
+#if DEBUG_PRINT
+ Console.WriteLine("DEBUG: IsSubset:");
+ Console.WriteLine(" --- this:");
+ this.Dump();
+ Console.WriteLine(" --- lcs:");
+ lcs.Dump();
+ Console.WriteLine(" ---");
+#endif
+ foreach (LinearConstraint! cc in (!)this.Constraints)
+ {
+#if DEBUG_PRINT
+ Console.WriteLine(" cc: {0}", cc);
+ Console.WriteLine(" cc.GetDefinedDimensions(): {0}", cc.GetDefinedDimensions());
+#endif
+ if (!forall{IVariable! var in cc.GetDefinedDimensions(); frameDims.Contains(var)})
+ {
+#if DEBUG_PRINT
+ Console.WriteLine(" ---> phase 0 subset violated, return false from IsSubset");
+#endif
+ return false;
+ }
+ }
+ }
+
+ // phase 1: check frame vertices against each constraint...
+ foreach (FrameElement! v in (!)lcs.FrameVertices)
+ {
+ foreach (LinearConstraint! cc in this.Constraints)
+ {
+ Rational q = cc.EvaluateLhs(v);
+ if (cc.Relation == LinearConstraint.ConstraintRelation.LE)
+ {
+ if (!(q <= cc.rhs))
+ {
+#if DEBUG_PRINT
+ Console.WriteLine(" ---> phase 1a subset violated, return false from IsSubset");
+#endif
+ return false;
+ }
+ }
+ else
+ {
+ if (!(q == cc.rhs))
+ {
+#if DEBUG_PRINT
+ Console.WriteLine(" ---> phase 1b subset violated, return false from IsSubset");
+#endif
+ return false;
+ }
+ }
+ }
+ }
+
+ // phase 2: check frame rays against each constraint...
+ // To check if a ray "r" falls within a constraint "cc", we add the vector "r" to
+ // any point "p" on the side of the half-space or plane described by constraint, and
+ // then check if the resulting point satisfies the constraint. That is, we check (for
+ // an inequality constraint with coefficients a1,a2,...,an and right-hand side
+ // constant C):
+ // a1*(r1+p1) + a2*(r2+p2) + ... + an*(rn+pn) <= C
+ // Equivalently:
+ // a1*r1 + a2*r2 + ... + an*rn + a1*p1 + a2*p2 + ... + an*pn <= C
+ // To find a point "p", we can pick out a coordinate, call it 1, with a non-zero
+ // coefficient in the constraint, and then choose "p" as the point that has the
+ // value C/a1 in coordinate 1 and has 0 in all other coordinates. We then check:
+ // a1*r1 + a2*r2 + ... + an*rn + a1*(C/a1) + a2*0 + ... + an*0 <= C
+ // which simplifies to:
+ // a1*r1 + a2*r2 + ... + an*rn + C <= C
+ // which in turn simplifies to:
+ // a1*r1 + a2*r2 + ... + an*rn <= 0
+ // If the constraint is an equality constraint, we simply replace "<=" with "=="
+ // above.
+ foreach (FrameElement! r in (!)lcs.FrameRays)
+ {
+ System.Diagnostics.Debug.Assert(r != null, "encountered a null ray...");
+ foreach (LinearConstraint! cc in this.Constraints)
+ {
+ System.Diagnostics.Debug.Assert(cc != null, "encountered an null constraint...");
+ Rational q = cc.EvaluateLhs(r);
+ if (cc.Relation == LinearConstraint.ConstraintRelation.LE)
+ {
+ if (q.IsPositive)
+ {
+#if DEBUG_PRINT
+ Console.WriteLine(" ---> phase 2a subset violated, return false from IsSubset");
+#endif
+ return false;
+ }
+ }
+ else
+ {
+ if (q.IsNonZero)
+ {
+#if DEBUG_PRINT
+ Console.WriteLine(" ---> phase 2b subset violated, return false from IsSubset");
+#endif
+ return false;
+ }
+ }
+ }
+ }
+
+ // phase 3: check frame lines against each constraint...
+ // To check if a line "L" falls within a constraint "cc", we check if both the
+ // vector "L" and "-L", interpreted as rays, fall within the constraint. From
+ // the discussion above, this means we check the following two properties:
+ // a1*L1 + a2*L2 + ... + an*Ln <= 0 (*)
+ // a1*(-L1) + a2*(-L2) + ... + an*(-Ln) <= 0
+ // The second of these lines can be rewritten as:
+ // - a1*L1 - a2*L2 - ... - an*Ln <= 0
+ // which is equivalent to:
+ // -1 * (a1*L1 + a2*L2 + ... + an*Ln) <= 0
+ // Multiplying both sides by -1 and flipping the direction of the inequality,
+ // we have:
+ // a1*L1 + a2*L2 + ... + an*Ln >= 0 (**)
+ // Putting (*) and (**) together, we conclude that we need to check:
+ // a1*L1 + a2*L2 + ... + an*Ln == 0
+ // If the constraint is an equality constraint, we end up with the same equation.
+ foreach (FrameElement! line in (!)lcs.FrameLines)
+ {
+ System.Diagnostics.Debug.Assert(line != null, "encountered a null line...");
+ foreach (LinearConstraint! cc in this.Constraints)
+ {
+ System.Diagnostics.Debug.Assert(cc != null, "encountered an null constraint...");
+ Rational q = cc.EvaluateLhs(line);
+ if (q.IsNonZero)
+ {
+#if DEBUG_PRINT
+ Console.WriteLine(" ---> phase 3 subset violated, return false from IsSubset");
+#endif
+ return false;
+ }
+ }
+ }
+
+#if DEBUG_PRINT
+ Console.WriteLine(" ---> IsSubset returns true");
+#endif
+ return true;
+ }
+
+ public LinearConstraintSystem! Meet(LinearConstraintSystem! lcs)
+ requires this.Constraints != null;
+ requires lcs.Constraints != null;
+ {
+ ArrayList /*LinearConstraint*/ clist = new ArrayList(this.Constraints.Count + lcs.Constraints.Count);
+ clist.AddRange(this.Constraints);
+ clist.AddRange(lcs.Constraints);
+ return new LinearConstraintSystem(clist);
+ }
+
+#if DEBUG_PRINT
+ public LinearConstraintSystem Join(LinearConstraintSystem lcs)
+ {
+ Console.WriteLine("===================================================================================");
+ Console.WriteLine("DEBUG: Join");
+ Console.WriteLine("Join: this=");
+ Dump();
+ Console.WriteLine("Join: lcs=");
+ lcs.Dump();
+ LinearConstraintSystem z = JoinX(lcs);
+ Console.WriteLine("----------Join------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
+ Console.WriteLine("Join: result=");
+ z.Dump();
+ Console.WriteLine("===================================================================================");
+ return z;
+ }
+#endif
+
+ /// <summary>
+ /// The join is computed as described in section 4.4 in Cousot and Halbwachs.
+ /// </summary>
+ /// <param name="lcs"></param>
+ /// <returns></returns>
+#if DEBUG_PRINT
+ public LinearConstraintSystem JoinX(LinearConstraintSystem lcs)
+#else
+ public LinearConstraintSystem! Join(LinearConstraintSystem! lcs)
+#endif
+ {
+ if (this.IsBottom())
+ {
+ return (!) lcs.Clone();
+ }
+ else if (lcs.IsBottom())
+ {
+ return (!) this.Clone();
+ }
+ else if (this.IsTop() || lcs.IsTop())
+ {
+ return new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ());
+ }
+ else
+ {
+ LinearConstraintSystem! z;
+ // Start from the "larger" of the two frames (this is just a heuristic measure intended
+ // to save work).
+ assume this.FrameVertices != null;
+ assume this.FrameRays != null;
+ assume this.FrameLines != null;
+ assume lcs.FrameVertices != null;
+ assume lcs.FrameRays != null;
+ assume lcs.FrameLines != null;
+ if (this.FrameVertices.Count + this.FrameRays.Count + this.FrameLines.Count - this.FrameDimensions.Count <
+ lcs.FrameVertices.Count + lcs.FrameRays.Count + lcs.FrameLines.Count - lcs.FrameDimensions.Count)
+ {
+ z = (!) lcs.Clone();
+ lcs = this;
+ }
+ else
+ {
+ z = (!) this.Clone();
+ }
+#if DEBUG_PRINT
+ Console.WriteLine("DEBUG: LinearConstraintSystem.Join ---------------");
+ Console.WriteLine("z:");
+ z.Dump();
+ Console.WriteLine("lcs:");
+ lcs.Dump();
+#endif
+
+ // Start by explicating the implicit lines of z for the dimensions dims(lcs)-dims(z).
+ foreach (IVariable! dim in lcs.FrameDimensions)
+ {
+ if (!z.FrameDimensions.Contains(dim))
+ {
+ z.FrameDimensions.Add(dim);
+ FrameElement line = new FrameElement();
+ line.AddCoordinate(dim, Rational.ONE);
+ // Note: AddLine is not called (because the line already exists in z--it's just that
+ // it was represented implicitly). Instead, just tack the explicit representation onto
+ // FrameLines.
+ assume z.FrameLines != null;
+ z.FrameLines.Add(line);
+#if DEBUG_PRINT
+ Console.WriteLine("Join: After explicating line: {0}", line);
+ z.Dump();
+#endif
+ }
+ }
+
+ // Now, the vertices, rays, and lines can be added.
+ foreach (FrameElement! v in lcs.FrameVertices)
+ {
+ z.AddVertex(v);
+#if DEBUG_PRINT
+ Console.WriteLine("Join: After adding vertex: {0}", v);
+ z.Dump();
+#endif
+ }
+ foreach (FrameElement! r in lcs.FrameRays)
+ {
+ z.AddRay(r);
+#if DEBUG_PRINT
+ Console.WriteLine("Join: After adding ray: {0}", r);
+ z.Dump();
+#endif
+ }
+ foreach (FrameElement! l in lcs.FrameLines)
+ {
+ z.AddLine(l);
+#if DEBUG_PRINT
+ Console.WriteLine("Join: After adding line: {0}", l);
+ z.Dump();
+#endif
+ }
+ // also add to z the implicit lines of lcs
+ foreach (IVariable! dim in z.FrameDimensions)
+ {
+ if (!lcs.FrameDimensions.Contains(dim))
+ {
+ // "dim" is a dimension that's explicit in "z" but implicit in "lcs"
+ FrameElement line = new FrameElement();
+ line.AddCoordinate(dim, Rational.ONE);
+ z.AddLine(line);
+#if DEBUG_PRINT
+ Console.WriteLine("Join: After adding lcs's implicit line: {0}", line);
+ z.Dump();
+#endif
+ }
+ }
+
+ z.SimplifyFrame();
+ z.SimplifyConstraints();
+ z.CheckInvariant();
+#if DEBUG_PRINT
+ Console.WriteLine("Join: Returning z:");
+ z.Dump();
+ Console.WriteLine("----------------------------------------");
+#endif
+ return z;
+ }
+ }
+
+#if DEBUG_PRINT
+ public LinearConstraintSystem Widen(LinearConstraintSystem lcs)
+ {
+ Console.WriteLine("===================================================================================");
+ Console.WriteLine("DEBUG: Widen");
+ Console.WriteLine("Widen: this=");
+ Dump();
+ Console.WriteLine("Widen: lcs=");
+ lcs.Dump();
+ LinearConstraintSystem z = WidenX(lcs);
+ Console.WriteLine("----------Widen------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
+ Console.WriteLine("Widen: result=");
+ z.Dump();
+ Console.WriteLine("===================================================================================");
+ return z;
+ }
+#endif
+
+#if DEBUG_PRINT
+ public LinearConstraintSystem WidenX(LinearConstraintSystem lcs)
+#else
+ public LinearConstraintSystem! Widen(LinearConstraintSystem! lcs)
+#endif
+ {
+ if (this.IsBottom())
+ {
+ return (!) lcs.Clone();
+ }
+ else if (lcs.IsBottom())
+ {
+ return (!) this.Clone();
+ }
+ else if (this.IsTop() || lcs.IsTop())
+ {
+ return new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ());
+ }
+
+ // create new LCS, we will add only verified constraints to this...
+ ArrayList /*LinearConstraint*/ newConstraints = new ArrayList /*LinearConstraint*/ ();
+ assume this.Constraints != null;
+ foreach (LinearConstraint! ccX in this.Constraints)
+ {
+ LinearConstraint cc = ccX;
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: Starting to check constraint: {0}", cc);
+#endif
+ if (cc.IsConstant())
+ {
+ // (Can this ever occur in the stable state of a LinearConstraintSystem? --KRML)
+ // constraint is unaffected by the frame components
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: --Adding it!");
+#endif
+ newConstraints.Add(cc);
+ continue;
+ }
+
+ // PHASE I: verify constraints against all frame vertices...
+
+ foreach (FrameElement! vertex in (!)lcs.FrameVertices)
+ {
+ Rational lhs = cc.EvaluateLhs(vertex);
+ if (lhs > cc.rhs)
+ {
+ // the vertex does not satisfy the inequality <=
+ if (cc.Relation == LinearConstraint.ConstraintRelation.LE)
+ {
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: throwing out because of vertex: {0}", vertex);
+#endif
+ goto CHECK_NEXT_CONSTRAINT;
+ }
+ else
+ {
+ // ... but it does satisfy the inequality >=
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: throwing out <= because of vertex: {0}", vertex);
+#endif
+ cc = cc.ChangeRelationToAtLeast();
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: left with constraint: {0}", cc);
+#endif
+ }
+ }
+ else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ && lhs < cc.rhs)
+ {
+ // the vertex does not satisfy the inequality >=, and the constraint is an equality constraint
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: throwing out >= because of vertex: {0}", vertex);
+#endif
+ cc = cc.ChangeRelation(LinearConstraint.ConstraintRelation.LE);
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: left with contraint: {0}", cc);
+#endif
+ }
+ }
+
+ // PHASE II: verify constraints against all frame rays...
+
+ foreach (FrameElement! ray in (!)lcs.FrameRays)
+ {
+ // The following assumes the constraint to have some dimension with a non-zero coefficient
+ Rational lhs = cc.EvaluateLhs(ray);
+ if (lhs.IsPositive)
+ {
+ // the ray does not satisfy the inequality <=
+ if (cc.Relation == LinearConstraint.ConstraintRelation.LE)
+ {
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: throwing out because of ray: {0}", ray);
+#endif
+ goto CHECK_NEXT_CONSTRAINT;
+ }
+ else
+ {
+ // ... but it does satisfy the inequality >=
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: throwing out <= because of ray: {0}", ray);
+#endif
+ cc = cc.ChangeRelationToAtLeast();
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: left with contraint: {0}", cc);
+#endif
+ }
+ }
+ else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ && lhs.IsNegative)
+ {
+ // the ray does not satisfy the inequality >=, and the constraint is an equality constraint
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: throwing out >= because of ray: {0}", ray);
+#endif
+ cc = cc.ChangeRelation(LinearConstraint.ConstraintRelation.LE);
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: left with constraint: {0}", cc);
+#endif
+ }
+ }
+
+ // PHASE III: verify constraints against all frame lines...
+
+ foreach (FrameElement! line in (!)lcs.FrameLines)
+ {
+ // The following assumes the constraint to have some dimension with a non-zero coefficient
+ Rational lhs = cc.EvaluateLhs(line);
+ if (!lhs.IsZero)
+ {
+ // The line satisfies neither the inequality <= nor the equality ==
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: throwing out because of line: {0}", line);
+#endif
+ goto CHECK_NEXT_CONSTRAINT;
+ }
+ }
+
+ // constraint has been verified, so add to new constraint system
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: --Adding it!");
+#endif
+ newConstraints.Add(cc);
+
+ CHECK_NEXT_CONSTRAINT: {}
+#if DEBUG_PRINT
+ Console.WriteLine("Widen checking: done with that constraint");
+#endif
+ }
+
+ return new LinearConstraintSystem(newConstraints);
+ }
+
+#if DEBUG_PRINT
+ public LinearConstraintSystem Project(IVariable! dim)
+ {
+ Console.WriteLine("===================================================================================");
+ Console.WriteLine("DEBUG: Project(dim={0})", dim);
+ Console.WriteLine("Project: this=");
+ Dump();
+ LinearConstraintSystem z = ProjectX(dim);
+ Console.WriteLine("----------Project------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
+ Console.WriteLine("Project: result=");
+ z.Dump();
+ Console.WriteLine("===================================================================================");
+ return z;
+ }
+#endif
+
+#if DEBUG_PRINT
+ public LinearConstraintSystem ProjectX(IVariable! dim)
+#else
+ public LinearConstraintSystem! Project(IVariable! dim)
+#endif
+ requires this.Constraints != null;
+ {
+ ArrayList /*LinearConstraint!*/! cc = Project(dim, Constraints);
+ return new LinearConstraintSystem(cc);
+ }
+
+#if DEBUG_PRINT
+ public LinearConstraintSystem Rename(IVariable! oldName, IVariable! newName)
+ {
+ Console.WriteLine("===================================================================================");
+ Console.WriteLine("DEBUG: Rename(oldName={0}, newName={1})", oldName, newName);
+ Console.WriteLine("Rename: this=");
+ Dump();
+ LinearConstraintSystem z = RenameX(oldName, newName);
+ Console.WriteLine("----------Rename------------------------------>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
+ Console.WriteLine("Rename: result=");
+ z.Dump();
+ Console.WriteLine("===================================================================================");
+ return z;
+ }
+#endif
+
+#if DEBUG_PRINT
+ public LinearConstraintSystem RenameX(IVariable! oldName, IVariable! newName)
+#else
+ public LinearConstraintSystem! Rename(IVariable! oldName, IVariable! newName)
+#endif
+ {
+ if (this.Constraints == null)
+ {
+ System.Diagnostics.Debug.Assert(this.FrameVertices == null);
+ System.Diagnostics.Debug.Assert(this.FrameRays == null);
+ System.Diagnostics.Debug.Assert(this.FrameLines == null);
+ return this;
+ }
+ IMutableSet /*IVariable!*/! dims = this.FrameDimensions;
+ if (!dims.Contains(oldName))
+ {
+ return this;
+ }
+
+ LinearConstraintSystem z = new LinearConstraintSystem();
+ z.FrameDimensions = (HashSet! /*IVariable!*/)dims.Clone();
+ z.FrameDimensions.Remove(oldName);
+ z.FrameDimensions.Add(newName);
+
+ z.Constraints = new ArrayList /*LinearConstraint!*/ (this.Constraints.Count);
+ foreach (LinearConstraint! lc in (!)this.Constraints)
+ {
+ z.Constraints.Add(lc.Rename(oldName, newName));
+ }
+ z.FrameVertices = RenameInFE((!)this.FrameVertices, oldName, newName);
+ z.FrameRays = RenameInFE((!)this.FrameRays, oldName, newName);
+ z.FrameLines = RenameInFE((!)this.FrameLines, oldName, newName);
+ return z;
+ }
+
+ static ArrayList /*FrameElement*/ RenameInFE(ArrayList! /*FrameElement*/ list, IVariable! oldName, IVariable! newName)
+ {
+ ArrayList/*FrameElement!*/! z = new ArrayList/*FrameElement!*/ (list.Count);
+ foreach (FrameElement! fe in list)
+ {
+ z.Add(fe.Rename(oldName, newName));
+ }
+ System.Diagnostics.Debug.Assert(z.Count == list.Count);
+ return z;
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ // ------------------ support routines --------------------------------------------------------------------
+ // --------------------------------------------------------------------------------------------------------
+
+ /// <summary>
+ /// Returns a set of constraints that is the given set of constraints with dimension "dim"
+ /// projected out. See Cousot and Halbwachs, section 3.3.1.1.
+ /// </summary>
+ /// <param name="dim"></param>
+ /// <param name="constraints"></param>
+ /// <returns></returns>
+ static ArrayList /*LinearConstraint!*/! Project(IVariable! dim, ArrayList /*LinearConstraint!*/! constraints)
+ {
+ // Sort the inequality constaints into ones where dimension "dim" is 0, negative, and
+ // positive, respectively. Put equality constraints with a non-0 "dim" into "eq".
+ ArrayList /*LinearConstraint!*/! final = new ArrayList /*LinearConstraint!*/ ();
+ ArrayList /*LinearConstraint!*/! negative = new ArrayList /*LinearConstraint!*/ ();
+ ArrayList /*LinearConstraint!*/! positive = new ArrayList /*LinearConstraint!*/ ();
+ ArrayList /*LinearConstraint!*/! eq = new ArrayList /*LinearConstraint!*/ ();
+ foreach (LinearConstraint! cc in constraints)
+ {
+ Rational coeff = cc[dim];
+ if (coeff.IsZero)
+ {
+ LinearConstraint lc = (!) cc.Clone();
+ if (!lc.IsConstant())
+ {
+ lc.RemoveDimension(dim);
+ final.Add(lc);
+ }
+ }
+ else if (cc.Relation == LinearConstraint.ConstraintRelation.EQ)
+ {
+ eq.Add(cc);
+ }
+ else if (coeff.IsNegative)
+ {
+ negative.Add(cc);
+ }
+ else
+ {
+ System.Diagnostics.Debug.Assert(coeff.IsPositive);
+ positive.Add(cc);
+ }
+ }
+
+ if (eq.Count != 0)
+ {
+ LinearConstraint eqConstraint = (LinearConstraint!)eq[eq.Count-1];
+ eq.RemoveAt(eq.Count-1);
+ Rational eqC = -eqConstraint[dim];
+
+ foreach (ArrayList /*LinearConstraint!*/! list in new ArrayList[]{eq, negative, positive})
+ {
+ foreach (LinearConstraint! lcX in list)
+ {
+ LinearConstraint lc = (!) lcX.Clone();
+ lc.AddMultiple(lc[dim]/eqC, eqConstraint);
+ System.Diagnostics.Debug.Assert(lc[dim].IsZero);
+ if (!lc.IsConstant())
+ {
+ lc.RemoveDimension(dim);
+ final.Add(lc);
+ }
+ else
+ {
+ System.Diagnostics.Debug.Assert(lc.IsConstantSatisfiable());
+ }
+ }
+ }
+ }
+ else
+ {
+ // Consider all pairs of constraints with (negative,positive) coefficients of "dim".
+ foreach (LinearConstraint! cn in negative)
+ {
+ Rational dn = -cn[dim];
+ System.Diagnostics.Debug.Assert(dn.IsNonNegative);
+ foreach (LinearConstraint! cp in positive)
+ {
+ Rational dp = cp[dim];
+
+ LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.LE);
+ lc.AddMultiple(dn, cp);
+ lc.AddMultiple(dp, cn);
+ System.Diagnostics.Debug.Assert(lc[dim].IsZero);
+ if (!lc.IsConstant())
+ {
+ lc.RemoveDimension(dim);
+ final.Add(lc);
+ }
+ else
+ {
+ System.Diagnostics.Debug.Assert(lc.IsConstantSatisfiable());
+ }
+ }
+ }
+ }
+
+ return final;
+ }
+
+ /// <summary>
+ /// Initializes FrameVertices, FrameRays, FrameLines, and FrameDimensions, see
+ /// Cousot and Halbwachs, section 3.4. Any previous values of these fields are
+ /// ignored and overwritten.
+ ///
+ /// If the set of Constraints is unsatisfiable, then "this" is changed into Bottom.
+ /// </summary>
+ void GenerateFrameFromConstraints()
+ {
+ if (Constraints == null)
+ {
+ FrameVertices = null;
+ FrameRays = null;
+ FrameLines = null;
+ FrameDimensions = new HashSet /*IVariable!*/ ();
+ return;
+ }
+
+ // Step 1 (see Cousot and Halbwachs, section 3.4.3): create a Simplex Tableau.
+#if DEBUG_PRINT
+ Console.WriteLine("DEBUG: --- GenerateFrameFromConstraint ---");
+ Console.WriteLine("Constraints:");
+ foreach (LinearConstraint cc in Constraints)
+ {
+ Console.WriteLine(" {0}", cc);
+ }
+#endif
+ SimplexTableau tableau = new SimplexTableau(Constraints);
+#if DEBUG_PRINT
+ Console.WriteLine("Initial tableau:");
+ tableau.Dump();
+#endif
+ FrameDimensions = tableau.GetDimensions();
+#if DEBUG_PRINT
+ Console.WriteLine("Dimensions:");
+ foreach (object dim in FrameDimensions)
+ {
+ Console.Write(" {0}", dim);
+ }
+ Console.WriteLine();
+#endif
+
+ // Step 3 and 2: Put as many initial variables as possible into basis, then check if
+ // we reached a feasible basis
+ tableau.AddInitialVarsToBasis();
+#if DEBUG_PRINT
+ Console.WriteLine("Tableau after Step 3:");
+ tableau.Dump();
+#endif
+ if (!tableau.IsFeasibleBasis)
+ {
+ // The polyhedron is empty (according to Cousot and Halbwachs)
+ ChangeIntoBottom();
+ return;
+ }
+
+ FrameVertices = new ArrayList /*FrameElement*/ ();
+ FrameRays = new ArrayList /*FrameElement*/ ();
+ FrameLines = new ArrayList /*FrameElement*/ ();
+ if (FrameDimensions.Count == 0)
+ {
+ // top element
+ return;
+ }
+
+ if (tableau.AllInitialVarsInBasis)
+ {
+ // All initial variables are in basis; there are no lines.
+#if DEBUG_PRINT
+ Console.WriteLine("Tableau after Steps 2 and 3 (all initial variables in basis):");
+ tableau.Dump();
+#endif
+ }
+ else
+ {
+ // There are lines
+#if DEBUG_PRINT
+ Console.WriteLine("Tableau after Steps 2 and 3 (NOT all initial variables in basis--there are lines):");
+ tableau.Dump();
+#endif
+ // Step 4.2: Pick out the lines, then produce the tableau for a new polyhedron without those lines.
+ ArrayList /*LinearConstraint*/ moreConstraints = (ArrayList! /*LinearConstraint*/) Constraints.Clone();
+ tableau.ProduceLines(FrameLines, moreConstraints);
+ tableau = new SimplexTableau(moreConstraints);
+#if DEBUG_PRINT
+ Console.WriteLine("Lines produced:");
+ foreach (FrameElement line in FrameLines)
+ {
+ Console.WriteLine(" {0}", line);
+ }
+ Console.WriteLine("The new list of constraints is:");
+ foreach (LinearConstraint c in moreConstraints)
+ {
+ Console.WriteLine(" {0}", c);
+ }
+ Console.WriteLine("Tableau after producing lines in Step 4.2:");
+ tableau.Dump();
+#endif
+
+ // Repeat step 3 for the new tableau.
+ // Since the new tableau contains no lines, the following call should cause all initial
+ // variables to be in basis (see step 4.2 in section 3.4.3 of Cousot and Halbwachs).
+ tableau.AddInitialVarsToBasis();
+ System.Diagnostics.Debug.Assert(tableau.AllInitialVarsInBasis);
+ System.Diagnostics.Debug.Assert(tableau.IsFeasibleBasis); // the new tableau represents a set of feasible constraints, so this basis should be found to be feasible
+#if DEBUG_PRINT
+ Console.WriteLine("Tableau after all initial variables have been moved into basis:");
+ tableau.Dump();
+#endif
+ }
+
+ // Step 4.1: One vertex has been found. Find all others, too.
+ tableau.TraverseVertices(FrameVertices, FrameRays);
+#if DEBUG_PRINT
+ Console.WriteLine("Tableau after vertex traversal:");
+ tableau.Dump();
+#endif
+ }
+
+ class LambdaDimension : IVariable
+ {
+ readonly int id;
+ static int count = 0;
+
+ /// <summary>
+ /// Return the name of the variable
+ /// </summary>
+ public string! Name
+ {
+ get
+ {
+ return this.ToString();
+ }
+ }
+
+ public LambdaDimension()
+ {
+ id = count;
+ count++;
+ }
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override string! ToString()
+ {
+ return "lambda" + id;
+ }
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public object DoVisit(ExprVisitor! visitor)
+ {
+ return visitor.VisitVariable(this);
+ }
+ }
+
+ /// <summary>
+ /// Adds a vertex to the frame of "this" and updates Constraints accordingly, see
+ /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify
+ /// Constraints after the operation; that remains the caller's responsibility (which
+ /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay,
+ /// and AddLine before calling SimplifyConstraints).
+ /// Assumes Constraints (and the frame fields) to be non-null.
+ /// </summary>
+ /// <param name="vertex"></param>
+ void AddVertex(FrameElement! vertex)
+ requires this.FrameVertices != null;
+ {
+#if DEBUG_PRINT
+ Console.WriteLine("DEBUG: AddVertex called on {0}", vertex);
+ Console.WriteLine(" Initial constraints:");
+ foreach (LinearConstraint cc in Constraints) {
+ Console.WriteLine(" {0}", cc);
+ }
+#endif
+
+ FrameVertices.Add(vertex.Clone());
+#if FIXED_DESERIALIZER
+ assert Forall{IVariable! var in vertex.GetDefinedDimensions(); FrameDimensions.Contains(var)};
+#endif
+
+ // We use a new temporary dimension.
+ IVariable! lambda = new LambdaDimension();
+
+ // We change the constraints A*X <= B into
+ // A*X + (A*vector - B)*lambda <= A*vector.
+ // That means that each row k in A (which corresponds to one LinearConstraint
+ // in Constraints) is changed by adding
+ // (A*vector - B)[k] * lambda
+ // to row k and changing the right-hand side of row k to
+ // (A*vector)[k]
+ // Note:
+ // (A*vector - B)[k]
+ // = { vector subtraction is pointwise }
+ // (A*vector)[k] - B[k]
+ // = { A*vector is a row vector whose every row i is the dot-product of
+ // row i of A with the column vector "vector" }
+ // A[k]*vector - B[k]
+ foreach (LinearConstraint! cc in (!)Constraints)
+ {
+ Rational d = cc.EvaluateLhs(vertex);
+ cc.SetCoefficient(lambda, d - cc.rhs);
+ cc.rhs = d;
+ }
+
+ // We also add the constraints that lambda lies between 0 ...
+ LinearConstraint la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE);
+ la.SetCoefficient(lambda, Rational.MINUS_ONE);
+ la.rhs = Rational.ZERO;
+ Constraints.Add(la);
+ // ... and 1.
+ la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE);
+ la.SetCoefficient(lambda, Rational.ONE);
+ la.rhs = Rational.ONE;
+ Constraints.Add(la);
+#if DEBUG_PRINT
+ Console.WriteLine(" Constraints after addition:");
+ foreach (LinearConstraint cc in Constraints) {
+ Console.WriteLine(" {0}", cc);
+ }
+#endif
+
+ // Finally, project out the dummy dimension.
+ Constraints = Project(lambda, Constraints);
+
+#if DEBUG_PRINT
+ Console.WriteLine(" Resulting constraints:");
+ foreach (LinearConstraint cc in Constraints) {
+ Console.WriteLine(" {0}", cc);
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Adds a ray to the frame of "this" and updates Constraints accordingly, see
+ /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify
+ /// Constraints after the operation; that remains the caller's responsibility (which
+ /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay,
+ /// and AddLine before calling SimplifyConstraints).
+ /// Assumes Constraints (and the frame fields) to be non-null.
+ /// </summary>
+ /// <param name="ray"></param>
+ void AddRay(FrameElement! ray)
+ requires this.FrameRays != null;
+ {
+#if DEBUG_PRINT
+ Console.WriteLine("DEBUG: AddRay called on {0}", ray);
+ Console.WriteLine(" Initial constraints:");
+ foreach (LinearConstraint cc in Constraints) {
+ Console.WriteLine(" {0}", cc);
+ }
+#endif
+
+ FrameRays.Add(ray.Clone());
+#if FIXED_DESERIALIZER
+ assert Forall{IVariable! var in ray.GetDefinedDimensions(); FrameDimensions.Contains(var)};
+#endif
+
+ // We use a new temporary dimension.
+ IVariable! lambda = new LambdaDimension();
+
+ // We change the constraints A*X <= B into
+ // A*X - (A*ray)*lambda <= B.
+ // That means that each row k in A (which corresponds to one LinearConstraint
+ // in Constraints) is changed by subtracting
+ // (A*ray)[k] * lambda
+ // from row k.
+ // Note:
+ // (A*ray)[k]
+ // = { A*ray is a row vector whose every row i is the dot-product of
+ // row i of A with the column vector "ray" }
+ // A[k]*ray
+ foreach (LinearConstraint! cc in (!)Constraints)
+ {
+ Rational d = cc.EvaluateLhs(ray);
+ cc.SetCoefficient(lambda, -d);
+ }
+
+ // We also add the constraints that lambda is at least 0.
+ LinearConstraint la = new LinearConstraint(LinearConstraint.ConstraintRelation.LE);
+ la.SetCoefficient(lambda, Rational.MINUS_ONE);
+ la.rhs = Rational.ZERO;
+ Constraints.Add(la);
+#if DEBUG_PRINT
+ Console.WriteLine(" Constraints after addition:");
+ foreach (LinearConstraint cc in Constraints) {
+ Console.WriteLine(" {0}", cc);
+ }
+#endif
+
+ // Finally, project out the dummy dimension.
+ Constraints = Project(lambda, Constraints);
+
+#if DEBUG_PRINT
+ Console.WriteLine(" Resulting constraints:");
+ foreach (LinearConstraint cc in Constraints) {
+ Console.WriteLine(" {0}", cc);
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Adds a line to the frame of "this" and updates Constraints accordingly, see
+ /// Cousot and Halbwachs, section 3.3.1.1. However, this method does not simplify
+ /// Constraints after the operation; that remains the caller's responsibility (which
+ /// gives the caller the opportunity to make multiple calls to AddVertex, AddRay,
+ /// and AddLine before calling SimplifyConstraints).
+ /// Assumes Constraints (and the frame fields) to be non-null.
+ /// </summary>
+ /// <param name="line"></param>
+ void AddLine(FrameElement! line)
+ requires this.FrameLines != null;
+ {
+ // Note: The code for AddLine is identical to that of AddRay, except the AddLine
+ // does not introduce the constraint 0 <= lambda. (One could imagine sharing the
+ // code between AddRay and AddLine.)
+#if DEBUG_PRINT
+ Console.WriteLine("DEBUG: AddLine called on {0}", line);
+ Console.WriteLine(" Initial constraints:");
+ foreach (LinearConstraint cc in Constraints) {
+ Console.WriteLine(" {0}", cc);
+ }
+#endif
+
+ FrameLines.Add(line.Clone());
+#if FIXED_DESERIALIZER
+ assert Forall{IVariable! var in line.GetDefinedDimensions(); FrameDimensions.Contains(var)};
+#endif
+
+ // We use a new temporary dimension.
+ IVariable! lambda = new LambdaDimension();
+
+ // We change the constraints A*X <= B into
+ // A*X - (A*line)*lambda <= B.
+ // That means that each row k in A (which corresponds to one LinearConstraint
+ // in Constraints) is changed by subtracting
+ // (A*line)[k] * lambda
+ // from row k.
+ // Note:
+ // (A*line)[k]
+ // = { A*line is a row vector whose every row i is the dot-product of
+ // row i of A with the column vector "line" }
+ // A[k]*line
+ foreach (LinearConstraint! cc in (!)Constraints)
+ {
+ Rational d = cc.EvaluateLhs(line);
+ cc.SetCoefficient(lambda, -d);
+ }
+
+#if DEBUG_PRINT
+ Console.WriteLine(" Constraints after addition:");
+ foreach (LinearConstraint cc in Constraints) {
+ Console.WriteLine(" {0}", cc);
+ }
+#endif
+
+ // Finally, project out the dummy dimension.
+ Constraints = Project(lambda, Constraints);
+
+#if DEBUG_PRINT
+ Console.WriteLine(" Resulting constraints:");
+ foreach (LinearConstraint cc in Constraints) {
+ Console.WriteLine(" {0}", cc);
+ }
+#endif
+ }
+
+ ISet /*IVariable!*/! GetDefinedDimensions()
+ {
+ HashSet /*IVariable!*/! dims = new HashSet /*IVariable!*/ ();
+ foreach (ArrayList p in new ArrayList[]{FrameVertices, FrameRays, FrameLines})
+ {
+ if (p != null)
+ {
+ foreach (FrameElement! element in p)
+ {
+ foreach (IVariable! dim in element.GetDefinedDimensions())
+ {
+ dims.Add(dim);
+ }
+ }
+ }
+ }
+ return dims;
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ // ------------------ Simplification routines -------------------------------------------------------------
+ // --------------------------------------------------------------------------------------------------------
+
+ /// <summary>
+ /// Uses the Constraints to simplify the frame. See section 3.4.4 of Cousot and Halbwachs.
+ /// </summary>
+ void SimplifyFrame()
+ requires this.Constraints != null;
+ {
+ SimplificationStatus[]! status;
+
+ SimplifyFrameElements((!)FrameVertices, true, Constraints, out status);
+ RemoveIrrelevantFrameElements(FrameVertices, status, null);
+
+ SimplifyFrameElements((!)FrameRays, false, Constraints, out status);
+ RemoveIrrelevantFrameElements(FrameRays, status, FrameLines);
+ }
+
+ enum SimplificationStatus { Irrelevant, Relevant, More };
+
+ /// <summary>
+ /// For each i, sets status[i] to:
+ /// <ul>
+ /// <li>Irrelevant if ff[i] is irrelevant</li>
+ /// <li>Relevant if ff[i] is irrelevant</li>
+ /// <li>More if vertices is true and ray ff[i] can be replaced by a line ff[i]</li>
+ /// </ul>
+ /// </summary>
+ /// <param name="ff"></param>
+ /// <param name="vertices">true if "ff" contains vertices; false if "ff" contains rays</param>
+ /// <param name="constraints"></param>
+ /// <param name="status"></param>
+ static void SimplifyFrameElements(ArrayList! /*FrameElement*/ ff, bool vertices,
+ ArrayList! /*LinearConstraint*/ constraints,
+ out SimplificationStatus[]! status)
+ {
+ status = new SimplificationStatus[ff.Count];
+ bool[,] sat = new bool[ff.Count, constraints.Count];
+ for (int i = 0; i < ff.Count; i++)
+ {
+ FrameElement f = (FrameElement!)ff[i];
+ int cnt = 0;
+ for (int c = 0; c < constraints.Count; c++)
+ {
+ LinearConstraint lc = (LinearConstraint!)constraints[c];
+ bool s = lc.IsSaturatedBy(f, vertices);
+ if (s)
+ {
+ sat[i,c] = true;
+ cnt++;
+ }
+ }
+ if (!vertices && cnt == constraints.Count)
+ {
+ status[i] = SimplificationStatus.More;
+ }
+ else
+ {
+ status[i] = SimplificationStatus.Relevant;
+ }
+ }
+
+ CheckPairSimplifications(sat, status);
+ }
+
+ /// <summary>
+ /// Requires sat.GetLength(0) == status.Length.
+ /// </summary>
+ /// <param name="sat"></param>
+ /// <param name="status"></param>
+ static void CheckPairSimplifications(bool[,]! sat, SimplificationStatus[]! status)
+ requires sat.GetLength(0) == status.Length;
+ {
+ int M = sat.GetLength(0);
+ int N = sat.GetLength(1);
+
+ for (int i = 0; i < M-1; i++)
+ {
+ if (status[i] != SimplificationStatus.Relevant)
+ {
+ continue;
+ }
+ for (int j = i+1; j < M; j++)
+ {
+ if (status[j] != SimplificationStatus.Relevant)
+ {
+ continue;
+ }
+ // check (sat[i,*] <= sat[j,*]) and (sat[i,*] >= sat[j,*])
+ int cmp = 0; // -1: (sat[i,*] <= sat[j,*]), 0: equal, 1: (sat[i,*] >= sat[j,*])
+ for (int c = 0; c < N; c++)
+ {
+ if (cmp < 0)
+ {
+ if (sat[i,c] && !sat[j,c])
+ {
+ // incomparable
+ goto NEXT_PAIR;
+ }
+ }
+ else if (0 < cmp)
+ {
+ if (!sat[i,c] && sat[j,c])
+ {
+ // incomparable
+ goto NEXT_PAIR;
+ }
+ }
+ else if (sat[i,c] != sat[j,c])
+ {
+ if (!sat[i,c])
+ {
+ cmp = -1;
+ }
+ else
+ {
+ cmp = 1;
+ }
+ }
+ }
+ if (cmp <= 0)
+ {
+ // sat[i,*] <= sat[j,*] holds, so mark i as irrelevant
+ status[i] = SimplificationStatus.Irrelevant;
+ goto NEXT_OUTER;
+ }
+ else
+ {
+ // sat[i,*] >= sat[j,*] holds, so mark j as irrelevant
+ status[j] = SimplificationStatus.Irrelevant;
+ }
+ NEXT_PAIR: {}
+ }
+ NEXT_OUTER: {}
+ }
+ }
+
+ static void RemoveIrrelevantFrameElements(ArrayList! /*FrameElement*/ ff, SimplificationStatus[]! status,
+ /*maybe null*/ ArrayList /*FrameElement*/ lines)
+ requires ff.Count == status.Length;
+ {
+ for (int j = ff.Count - 1; 0 <= j; j--)
+ {
+ switch (status[j])
+ {
+ case SimplificationStatus.Relevant:
+ break;
+ case SimplificationStatus.Irrelevant:
+#if DEBUG_PRINT
+ Console.WriteLine("Removing irrelevant {0}: {1}", lines == null ? "vertex" : "ray", ff[j]);
+#endif
+ ff.RemoveAt(j);
+ break;
+ case SimplificationStatus.More:
+ System.Diagnostics.Debug.Assert(lines != null);
+ FrameElement f = (FrameElement)ff[j];
+#if DEBUG_PRINT
+ Console.WriteLine("Changing ray into line: {0}", f);
+#endif
+ ff.RemoveAt(j);
+ assert lines != null;
+ lines.Add(f);
+ break;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Uses the frame to simplify Constraints. See section 3.3.1.2 of Cousot and Halbwachs.
+ ///
+ /// Note: This code does not necessarily eliminate all irrelevant equalities; Cousot and
+ /// Halbwachs only claim that the technique eliminates all irrelevant inequalities.
+ /// </summary>
+ void SimplifyConstraints()
+ {
+ if (Constraints == null)
+ {
+ return;
+ }
+ assume this.FrameVertices != null;
+ assume this.FrameRays != null;
+
+ SimplificationStatus[] status = new SimplificationStatus[Constraints.Count];
+ /*readonly*/ int feCount = FrameVertices.Count + FrameRays.Count;
+
+ // Create a table that keeps track of which constraints are satisfied by which vertices and rays
+ bool[,] sat = new bool[Constraints.Count, FrameVertices.Count + FrameRays.Count];
+ for (int i = 0; i < Constraints.Count; i++)
+ {
+ status[i] = SimplificationStatus.Relevant;
+ LinearConstraint lc = (LinearConstraint!)Constraints[i];
+ int cnt = 0; // number of vertices and rays that saturate lc
+ for (int j = 0; j < FrameVertices.Count; j++)
+ {
+ FrameElement vertex = (FrameElement!)FrameVertices[j];
+ if (lc.IsSaturatedBy(vertex, true))
+ {
+ sat[i,j] = true;
+ cnt++;
+ }
+ }
+ if (cnt == 0)
+ {
+ // no vertex saturates the constraint, so the constraint is irrelevant
+ status[i] = SimplificationStatus.Irrelevant;
+ continue;
+ }
+ for (int j = 0; j < FrameRays.Count; j++)
+ {
+ FrameElement ray = (FrameElement!)FrameRays[j];
+ if (lc.IsSaturatedBy(ray, false))
+ {
+ sat[i, FrameVertices.Count + j] = true;
+ cnt++;
+ }
+ }
+ if (cnt == feCount)
+ {
+ status[i] = SimplificationStatus.More;
+ }
+ else
+ {
+ // Cousot and Halbwachs says that all equalities are found in the way we just tested.
+ // If I understand that right, then we should not get here if the constraint is an
+ // equality constraint. The following assertion tests my understanding. --KRML
+ System.Diagnostics.Debug.Assert(lc.Relation == LinearConstraint.ConstraintRelation.LE);
+ }
+ }
+
+ CheckPairSimplifications(sat, status);
+
+ // Finally, make the changes to the list of constraints
+ for (int i = Constraints.Count - 1; 0 <= i; i--)
+ {
+ switch (status[i])
+ {
+ case SimplificationStatus.Relevant:
+ break;
+ case SimplificationStatus.Irrelevant:
+#if DEBUG_PRINT
+ Console.WriteLine("Removing irrelevant constraint: {0}", Constraints[i]);
+#endif
+ Constraints.RemoveAt(i);
+ break;
+ case SimplificationStatus.More:
+ LinearConstraint lc = (LinearConstraint!)Constraints[i];
+ if (lc.Relation == LinearConstraint.ConstraintRelation.LE)
+ {
+#if DEBUG_PRINT
+ Console.WriteLine("Converting the following constraint into an equality: {0}", lc);
+#endif
+ LinearConstraint lcEq = lc.ChangeRelation(LinearConstraint.ConstraintRelation.EQ);
+ Constraints[i] = lcEq;
+ }
+ break;
+ }
+ }
+
+ foreach (LinearConstraint! lc in Constraints) {
+ lc.Normalize();
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ // ------------------ Cloning routines --------------------------------------------------------------------
+ // --------------------------------------------------------------------------------------------------------
+
+ public LinearConstraintSystem! Clone()
+ {
+ LinearConstraintSystem z = new LinearConstraintSystem();
+ z.FrameDimensions = (IMutableSet /*IVariable!*/!)this.FrameDimensions.Clone();
+ if (this.Constraints != null)
+ {
+ z.Constraints = DeeperListCopy_LC(this.Constraints);
+ z.FrameVertices = DeeperListCopy_FE((!)this.FrameVertices);
+ z.FrameRays = DeeperListCopy_FE((!)this.FrameRays);
+ z.FrameLines = DeeperListCopy_FE((!)this.FrameLines);
+ }
+ else
+ {
+ System.Diagnostics.Debug.Assert(this.FrameVertices == null);
+ System.Diagnostics.Debug.Assert(this.FrameRays == null);
+ System.Diagnostics.Debug.Assert(this.FrameLines == null);
+ // the constructor should already have set these fields of z to null
+ System.Diagnostics.Debug.Assert(z.Constraints == null);
+ System.Diagnostics.Debug.Assert(z.FrameVertices == null);
+ System.Diagnostics.Debug.Assert(z.FrameRays == null);
+ System.Diagnostics.Debug.Assert(z.FrameLines == null);
+ }
+ return z;
+ }
+
+ /// <summary>
+ /// Clones "list" and the elements of "list".
+ /// </summary>
+ /// <param name="list"></param>
+ /// <returns></returns>
+ ArrayList /*LinearConstraint*/ DeeperListCopy_LC(ArrayList! /*LinearConstraint*/ list)
+ {
+ ArrayList /*LinearConstraint*/ z = new ArrayList /*LinearConstraint*/ (list.Count);
+ foreach (LinearConstraint! lc in list)
+ {
+ z.Add(lc.Clone());
+ }
+ System.Diagnostics.Debug.Assert(z.Count == list.Count);
+ return z;
+ }
+
+ /// <summary>
+ /// Clones "list" and the elements of "list".
+ /// </summary>
+ /// <param name="list"></param>
+ /// <returns></returns>
+ ArrayList /*FrameElement*/ DeeperListCopy_FE(ArrayList! /*FrameElement*/ list)
+ {
+ ArrayList /*FrameElement*/ z = new ArrayList /*FrameElement*/ (list.Count);
+ foreach (FrameElement! fe in list)
+ {
+ z.Add(fe.Clone());
+ }
+ System.Diagnostics.Debug.Assert(z.Count == list.Count);
+ return z;
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ // ------------------ Debugging and unit test routines ----------------------------------------------------
+ // --------------------------------------------------------------------------------------------------------
+
+ public void Dump()
+ {
+ Console.WriteLine(" Constraints:");
+ if (Constraints == null)
+ {
+ Console.WriteLine(" <bottom>");
+ }
+ else
+ {
+ foreach (LinearConstraint cc in Constraints)
+ {
+ Console.WriteLine(" {0}", cc);
+ }
+ }
+
+ Console.WriteLine(" FrameDimensions: {0}", FrameDimensions);
+
+ Console.WriteLine(" FrameVerticies:");
+ if (FrameVertices == null)
+ {
+ Console.WriteLine(" <null>");
+ }
+ else
+ {
+ foreach (FrameElement fe in FrameVertices)
+ {
+ Console.WriteLine(" {0}", fe);
+ }
+ }
+
+ Console.WriteLine(" FrameRays:");
+ if (FrameRays == null)
+ {
+ Console.WriteLine(" <null>");
+ }
+ else
+ {
+ foreach (FrameElement fe in FrameRays)
+ {
+ Console.WriteLine(" {0}", fe);
+ }
+ }
+
+ Console.WriteLine(" FrameLines:");
+ if (FrameLines == null)
+ {
+ Console.WriteLine(" <null>");
+ }
+ else
+ {
+ foreach (FrameElement fe in FrameLines)
+ {
+ Console.WriteLine(" {0}", fe);
+ }
+ }
+ }
+
+ class TestVariable : IVariable {
+ readonly string! name;
+
+ public string! Name
+ {
+ get
+ {
+ return name;
+ }
+ }
+
+ public TestVariable(string! name) {
+ this.name = name;
+ }
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public object DoVisit(ExprVisitor! visitor) {
+ return visitor.VisitVariable(this);
+ }
+ }
+
+ public static void RunValidationA()
+ {
+ IVariable! dim1 = new TestVariable("X");
+ IVariable! dim2 = new TestVariable("Y");
+ IVariable! dim3 = new TestVariable("Z");
+
+ FrameElement s1 = new FrameElement();
+ s1.AddCoordinate(dim1, Rational.ONE);
+ s1.AddCoordinate(dim2, Rational.MINUS_ONE);
+ s1.AddCoordinate(dim3, Rational.ZERO);
+ FrameElement s2 = new FrameElement();
+ s2.AddCoordinate(dim1, Rational.MINUS_ONE);
+ s2.AddCoordinate(dim2, Rational.ONE);
+ s2.AddCoordinate(dim3, Rational.ZERO);
+ FrameElement r1 = new FrameElement();
+ r1.AddCoordinate(dim1, Rational.ZERO);
+ r1.AddCoordinate(dim2, Rational.ZERO);
+ r1.AddCoordinate(dim3, Rational.ONE);
+ FrameElement d1 = new FrameElement();
+ d1.AddCoordinate(dim1, Rational.ONE);
+ d1.AddCoordinate(dim2, Rational.ONE);
+ d1.AddCoordinate(dim3, Rational.ZERO);
+
+ // create lcs from frame -- cf. Cousot/Halbwachs 1978, section 3.3.1.1
+ LinearConstraintSystem lcs = new LinearConstraintSystem(s1);
+ lcs.Dump();
+
+ lcs.AddVertex(s2);
+ lcs.Dump();
+
+ lcs.AddRay(r1);
+ lcs.Dump();
+
+ lcs.AddLine(d1);
+ lcs.Dump();
+
+ lcs.SimplifyConstraints();
+ lcs.Dump();
+
+#if LATER
+ lcs.GenerateFrameFromConstraints(); // should give us back the original frame...
+#endif
+ Console.WriteLine("IsSubset? {0}", lcs.IsSubset(lcs.Clone()));
+ lcs.Dump();
+ }
+
+ /// <summary>
+ /// Tests the example in section 3.4.3 of Cousot and Halbwachs.
+ /// </summary>
+ public static void RunValidationB()
+ {
+ IVariable! X = new TestVariable("X");
+ IVariable! Y = new TestVariable("Y");
+ IVariable! Z = new TestVariable("Z");
+ ArrayList /*LinearConstraint*/ cs = new ArrayList /*LinearConstraint*/ ();
+
+ LinearConstraint c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE);
+ c.SetCoefficient(X, Rational.MINUS_ONE);
+ c.SetCoefficient(Y, Rational.ONE);
+ c.SetCoefficient(Z, Rational.MINUS_ONE);
+ c.rhs = Rational.ZERO;
+ cs.Add(c);
+
+ c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE);
+ c.SetCoefficient(X, Rational.MINUS_ONE);
+ c.rhs = Rational.MINUS_ONE;
+ cs.Add(c);
+
+ c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE);
+ c.SetCoefficient(X, Rational.MINUS_ONE);
+ c.SetCoefficient(Y, Rational.MINUS_ONE);
+ c.SetCoefficient(Z, Rational.ONE);
+ c.rhs = Rational.ZERO;
+ cs.Add(c);
+
+ c = new LinearConstraint(LinearConstraint.ConstraintRelation.LE);
+ c.SetCoefficient(Y, Rational.MINUS_ONE);
+ c.SetCoefficient(Z, Rational.ONE);
+ c.rhs = Rational.FromInt(3);
+ cs.Add(c);
+
+ LinearConstraintSystem lcs = new LinearConstraintSystem(cs);
+ Console.WriteLine("==================== The final linear constraint system ====================");
+ lcs.Dump();
+ }
+
+ public static void RunValidationC()
+ {
+ // Run the example in section 3.4.3 of Cousot and Halbwachs backwards, that is, from
+ // from to constraints.
+ IVariable! dim1 = new TestVariable("X");
+ IVariable! dim2 = new TestVariable("Y");
+ IVariable! dim3 = new TestVariable("Z");
+
+ FrameElement s0 = new FrameElement();
+ s0.AddCoordinate(dim1, Rational.ONE);
+ s0.AddCoordinate(dim2, Rational.FromInts(1, 2));
+ s0.AddCoordinate(dim3, Rational.FromInts(-1, 2));
+
+ FrameElement s1 = new FrameElement();
+ s1.AddCoordinate(dim1, Rational.ONE);
+ s1.AddCoordinate(dim2, Rational.FromInts(-1, 2));
+ s1.AddCoordinate(dim3, Rational.FromInts(1, 2));
+
+ FrameElement s2 = new FrameElement();
+ s2.AddCoordinate(dim1, Rational.FromInt(3));
+ s2.AddCoordinate(dim2, Rational.FromInts(-3, 2));
+ s2.AddCoordinate(dim3, Rational.FromInts(3, 2));
+
+ FrameElement r0 = new FrameElement();
+ r0.AddCoordinate(dim1, Rational.ONE);
+ r0.AddCoordinate(dim2, Rational.FromInts(1, 2));
+ r0.AddCoordinate(dim3, Rational.FromInts(-1, 2));
+
+ FrameElement r1 = new FrameElement();
+ r1.AddCoordinate(dim1, Rational.ONE);
+ r1.AddCoordinate(dim2, Rational.ZERO);
+ r1.AddCoordinate(dim3, Rational.ZERO);
+
+ FrameElement d0 = new FrameElement();
+ d0.AddCoordinate(dim1, Rational.ZERO);
+ d0.AddCoordinate(dim2, Rational.ONE);
+ d0.AddCoordinate(dim3, Rational.ONE);
+
+ LinearConstraintSystem lcs = new LinearConstraintSystem(s0);
+ lcs.Dump();
+
+ lcs.AddVertex(s1);
+ lcs.Dump();
+
+ lcs.AddVertex(s2);
+ lcs.Dump();
+
+ lcs.AddRay(r0);
+ lcs.Dump();
+
+ lcs.AddRay(r1);
+ lcs.Dump();
+
+ lcs.AddLine(d0);
+ lcs.Dump();
+
+ lcs.SimplifyConstraints();
+ lcs.Dump();
+
+#if LATER
+ lcs.GenerateFrameFromConstraints(); // should give us back the original frame...
+#endif
+ }
+ }
+} \ No newline at end of file
diff --git a/Source/AIFramework/Polyhedra/PolyhedraAbstraction.ssc b/Source/AIFramework/Polyhedra/PolyhedraAbstraction.ssc
new file mode 100644
index 00000000..bcf9c64d
--- /dev/null
+++ b/Source/AIFramework/Polyhedra/PolyhedraAbstraction.ssc
@@ -0,0 +1,744 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using Microsoft.Contracts;
+ using Microsoft.Basetypes;
+
+ using ISet = Microsoft.Boogie.Set;
+ using HashSet = Microsoft.Boogie.Set;
+
+
+ /// <summary>
+ /// Represents an invariant over linear variable constraints, represented by a polyhedron.
+ /// </summary>
+ public class PolyhedraLattice : Lattice
+ {
+ private static readonly Logger! log = new Logger("Polyhedra");
+
+ private class PolyhedraLatticeElement : Element
+ {
+
+ public LinearConstraintSystem! lcs;
+
+ /// <summary>
+ /// Creates a top or bottom elements, according to parameter "top".
+ /// </summary>
+ public PolyhedraLatticeElement (bool top)
+ {
+ if (top)
+ {
+ lcs = new LinearConstraintSystem(new ArrayList /*LinearConstraint*/ ());
+ }
+ else
+ {
+ lcs = new LinearConstraintSystem();
+ }
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override string! ToString()
+ {
+ return lcs.ToString();
+ }
+
+ public override void Dump(string! msg) {
+ System.Console.WriteLine("PolyhedraLatticeElement.Dump({0}):", msg);
+ lcs.Dump();
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override ICollection<IVariable!>! FreeVariables()
+ {
+ return lcs.FreeVariables();
+ }
+
+ public PolyhedraLatticeElement (LinearConstraintSystem! lcs)
+ {
+ this.lcs = lcs;
+ }
+
+ public override Element! Clone ()
+ {
+ return new PolyhedraLatticeElement( (!) lcs.Clone());
+ }
+
+ } // class
+
+ readonly ILinearExprFactory! factory;
+ readonly IPropExprFactory! propFactory;
+
+ public PolyhedraLattice(ILinearExprFactory! linearFactory, IPropExprFactory! propFactory)
+ : base(linearFactory)
+ {
+ log.Enabled = Lattice.LogSwitch;
+ this.factory = linearFactory;
+ this.propFactory = propFactory;
+ // base(linearFactory);
+ }
+
+ public override Element! Top
+ {
+ get
+ {
+ return new PolyhedraLatticeElement(true);
+ }
+ }
+
+ public override Element! Bottom
+ {
+ get
+ {
+ return new PolyhedraLatticeElement(false);
+ }
+ }
+
+ public override bool IsBottom (Element! element)
+ {
+ PolyhedraLatticeElement e = (PolyhedraLatticeElement)element;
+ return e.lcs.IsBottom();
+ }
+
+ public override bool IsTop (Element! element)
+ {
+ PolyhedraLatticeElement e = (PolyhedraLatticeElement)element;
+ return e.lcs.IsTop();
+ }
+
+
+ /// <summary>
+ /// Returns true iff a is a subset of this.
+ /// </summary>
+ /// <param name="a"></param>
+ /// <returns></returns>
+ protected override bool AtMost (Element! first, Element! second) // this <= that
+ {
+ PolyhedraLatticeElement a = (PolyhedraLatticeElement) first;
+ PolyhedraLatticeElement b = (PolyhedraLatticeElement) second;
+ return b.lcs.IsSubset(a.lcs);
+ }
+
+
+ public override string! ToString (Element! e)
+ {
+ return ((PolyhedraLatticeElement)e).lcs.ToString();
+ }
+
+ public override IExpr! ToPredicate(Element! element)
+ {
+ PolyhedraLatticeElement e = (PolyhedraLatticeElement)element;
+ return e.lcs.ConvertToExpression(factory);
+ }
+
+
+
+ public override Lattice.Element! NontrivialJoin (Element! first, Element! second)
+ {
+ log.DbgMsg("Joining ..."); log.DbgMsgIndent();
+ PolyhedraLatticeElement aa = (PolyhedraLatticeElement) first;
+ PolyhedraLatticeElement bb = (PolyhedraLatticeElement) second;
+ PolyhedraLatticeElement result = new PolyhedraLatticeElement(aa.lcs.Join(bb.lcs));
+ log.DbgMsg(string.Format("{0} |_| {1} --> {2}", this.ToString(first), this.ToString(second), this.ToString(result)));
+ log.DbgMsgUnindent();
+ return result;
+ }
+
+
+ public override Lattice.Element! NontrivialMeet (Element! first, Element! second)
+ {
+ PolyhedraLatticeElement aa = (PolyhedraLatticeElement) first;
+ PolyhedraLatticeElement bb = (PolyhedraLatticeElement) second;
+ return new PolyhedraLatticeElement(aa.lcs.Meet(bb.lcs));
+ }
+
+
+ public override Lattice.Element! Widen (Element! first, Element! second)
+ {
+ log.DbgMsg("Widening ..."); log.DbgMsgIndent();
+ PolyhedraLatticeElement aa = (PolyhedraLatticeElement)first;
+ PolyhedraLatticeElement bb = (PolyhedraLatticeElement)second;
+
+ LinearConstraintSystem lcs = aa.lcs.Widen(bb.lcs);
+ PolyhedraLatticeElement result = new PolyhedraLatticeElement(lcs);
+ log.DbgMsg(string.Format("{0} |_| {1} --> {2}", this.ToString(first), this.ToString(second), this.ToString(result)));
+ log.DbgMsgUnindent();
+ return result;
+ }
+
+
+ public override Element! Eliminate (Element! e, IVariable! variable)
+ {
+ log.DbgMsg(string.Format("Eliminating {0} ...", variable));
+
+ PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e;
+ if (ple.lcs.IsBottom())
+ {
+ return ple;
+ }
+ return new PolyhedraLatticeElement(ple.lcs.Project(variable));
+ }
+
+
+ public override Element! Rename (Element! e, IVariable! oldName, IVariable! newName)
+ {
+ log.DbgMsg(string.Format("Renaming {0} to {1} in {2} ...", oldName, newName, this.ToString(e)));
+
+ PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e;
+ if (ple.lcs.IsBottom())
+ {
+ return ple;
+ }
+ return new PolyhedraLatticeElement(ple.lcs.Rename(oldName, newName));
+ }
+
+ public override bool Understands(IFunctionSymbol! f, IList/*<IExpr!>*/! args) {
+ return f is IntSymbol ||
+ f.Equals(Int.Add) ||
+ f.Equals(Int.Sub) ||
+ f.Equals(Int.Negate) ||
+ f.Equals(Int.Mul) ||
+ f.Equals(Int.Eq) ||
+ f.Equals(Int.Neq) ||
+ f.Equals(Prop.Not) ||
+ f.Equals(Int.AtMost) ||
+ f.Equals(Int.Less) ||
+ f.Equals(Int.Greater) ||
+ f.Equals(Int.AtLeast);
+ }
+
+ public override Answer CheckVariableDisequality(Element! e, IVariable! var1, IVariable! var2) {
+ PolyhedraLatticeElement! ple = (PolyhedraLatticeElement)e;
+ assume ple.lcs.Constraints != null;
+ ArrayList /*LinearConstraint!*/! clist = (ArrayList /*LinearConstraint!*/!)ple.lcs.Constraints.Clone();
+ LinearConstraint! lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ);
+ lc.SetCoefficient(var1, Rational.ONE);
+ lc.SetCoefficient(var2, Rational.MINUS_ONE);
+ clist.Add(lc);
+ LinearConstraintSystem newLcs = new LinearConstraintSystem(clist);
+ if (newLcs.IsBottom()) {
+ return Answer.Yes;
+ } else {
+ return Answer.Maybe;
+ }
+ }
+
+ public override Answer CheckPredicate(Element! e, IExpr! pred) {
+ PolyhedraLatticeElement! ple = (PolyhedraLatticeElement)Constrain(e, pred);
+ if (ple.lcs.IsBottom()) {
+ return Answer.No;
+ }
+
+ // Note, "pred" may contain expressions that are not understood by the propFactory (in
+ // particular, this may happen because--currently, and perhaps is a design we'll want
+ // to change in the future--propFactory deals with BoogiePL expressions whereas "pred"
+ // may also refer to Equivalences.UninterpFun expressions). Thus, we cannot just
+ // call propFactory.Not(pred) to get the negation of "pred".
+ pred = new PolyhedraLatticeNegation(pred);
+ ple = (PolyhedraLatticeElement)Constrain(e, pred);
+ if (ple.lcs.IsBottom()) {
+ return Answer.Yes;
+ } else {
+ return Answer.Maybe;
+ }
+ }
+
+ class PolyhedraLatticeNegation : IFunApp
+ {
+ IExpr! arg;
+
+ public PolyhedraLatticeNegation(IExpr! arg) {
+ this.arg = arg;
+ // base();
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)] public object DoVisit(ExprVisitor! visitor) {
+ return visitor.VisitFunApp(this);
+ }
+
+ public IFunctionSymbol! FunctionSymbol { [Pure][Reads(ReadsAttribute.Reads.Owned)] get { return Prop.Not; } }
+
+ public IList/*<IExpr!>*/! Arguments {
+ [Pure][Reads(ReadsAttribute.Reads.Owned)] get {
+ IExpr[] args = new IExpr[] { arg };
+ return ArrayList.ReadOnly(args);
+ }
+ }
+
+ public IFunApp! CloneWithArguments(IList/*<IExpr!>*/! args) {
+ assert args.Count == 1;
+ return new PolyhedraLatticeNegation((IExpr!)args[0]);
+ }
+ }
+
+ public override IExpr/*?*/ EquivalentExpr(Element! e, IQueryable! q, IExpr! expr, IVariable! var, ISet/*<IVariable!>*/! prohibitedVars) {
+ // BUGBUG: TODO: this method can be implemented in a more precise way
+ return null;
+ }
+
+
+ public override Element! Constrain (Element! e, IExpr! expr)
+ {
+ log.DbgMsg(string.Format("Constraining with {0} into {1} ...", expr, this.ToString(e)));
+
+ PolyhedraLatticeElement ple = (PolyhedraLatticeElement)e;
+ if (ple.lcs.IsBottom())
+ {
+ return ple;
+ }
+ LinearCondition le = LinearExpressionBuilder.AsCondition(expr);
+ if (le != null) {
+ // update the polyhedron according to the linear expression
+ assume ple.lcs.Constraints != null;
+ ArrayList /*LinearConstraint*/ clist = (ArrayList! /*LinearConstraint*/)ple.lcs.Constraints.Clone();
+ le.AddToConstraintSystem(clist);
+ LinearConstraintSystem newLcs = new LinearConstraintSystem(clist);
+
+ return new PolyhedraLatticeElement(newLcs);
+ }
+ return ple;
+ }
+
+ } // class
+
+
+ /// <summary>
+ /// A LinearCondition follows this grammar:
+ /// LinearCondition ::= unsatisfiable
+ /// | LinearConstraint
+ /// | ! LinearConstraint
+ /// Note that negations are distributed to the leaves.
+ /// </summary>
+ abstract class LinearCondition
+ {
+ /// <summary>
+ /// Adds constraints to the list "clist". If "this"
+ /// entails some disjunctive constraints, they may not be added.
+ /// </summary>
+ /// <param name="clist"></param>
+ public abstract void AddToConstraintSystem(ArrayList! /*LinearConstraint*/ clist);
+ }
+
+ class LCBottom : LinearCondition
+ {
+ public override void AddToConstraintSystem(ArrayList! /*LinearConstraint*/ clist)
+ {
+ // make an unsatisfiable constraint
+ LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ);
+ lc.rhs = Rational.FromInt(1);
+ clist.Add(lc);
+ }
+ }
+
+ class LinearConditionLiteral : LinearCondition
+ {
+ public readonly bool positive;
+ public readonly LinearConstraint! constraint;
+ /// <summary>
+ /// Precondition: positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ
+ /// </summary>
+ /// <param name="positive"></param>
+ /// <param name="constraint"></param>
+ public LinearConditionLiteral(bool positive, LinearConstraint! constraint)
+ requires positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ;
+ {
+ this.positive = positive;
+ this.constraint = constraint;
+ }
+ public override void AddToConstraintSystem(ArrayList! /*LinearConstraint*/ clist)
+ {
+ if (positive)
+ {
+ clist.Add(constraint);
+ }
+ else
+ {
+ assert constraint.Relation == LinearConstraint.ConstraintRelation.EQ;
+ // the constraint is disjunctive, so just ignore it
+ }
+ }
+ }
+
+ class LinearExpressionBuilder
+ {
+ /// <summary>
+ /// Builds a linear condition from "e", if possible; returns null if not possible.
+ /// </summary>
+ /// <param name="e"></param>
+ /// <returns></returns>
+ public static /*maybe null*/ LinearCondition AsCondition(IExpr e) /* throws ArithmeticException */
+ {
+ return GetCond(e, true);
+ }
+
+ static /*maybe null*/ LinearCondition GetCond(IExpr e, bool positive) /* throws ArithmeticException */
+ {
+ IFunApp funapp = e as IFunApp;
+ if (funapp == null) {
+ return null;
+ }
+ IFunctionSymbol! s = funapp.FunctionSymbol;
+ if ((positive && s.Equals(Prop.False)) ||
+ (!positive && s.Equals(Prop.True))) {
+ return new LCBottom();
+ } else if (s.Equals(Prop.Not)) {
+ assert funapp.Arguments.Count == 1;
+ return GetCond((IExpr!)funapp.Arguments[0], !positive);
+ } else if (funapp.Arguments.Count == 2) {
+ IExpr! arg0 = (IExpr!)funapp.Arguments[0];
+ IExpr! arg1 = (IExpr!)funapp.Arguments[1];
+ LinearExpr le0 = AsExpr(arg0);
+ if (le0 == null) {
+ return null;
+ }
+ LinearExpr le1 = AsExpr(arg1);
+ if (le1 == null) {
+ return null;
+ }
+
+ LinearConstraint constraint = null;
+ bool sense = true;
+ if ((positive && s.Equals(Int.Less)) || (!positive && s.Equals(Int.AtLeast)))
+ {
+ constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.LE, BigNum.ONE);
+ }
+ else if ((positive && s.Equals(Int.AtMost)) || (!positive && s.Equals(Int.Greater)))
+ {
+ constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.LE, BigNum.ZERO);
+ }
+ else if ((positive && s.Equals(Int.AtLeast)) || (!positive && s.Equals(Int.Less)))
+ {
+ constraint = MakeConstraint(le1, le0, LinearConstraint.ConstraintRelation.LE, BigNum.ZERO);
+ }
+ else if ((positive && s.Equals(Int.Greater)) || (!positive && s.Equals(Int.AtMost)))
+ {
+ constraint = MakeConstraint(le1, le0, LinearConstraint.ConstraintRelation.LE, BigNum.ONE);
+ }
+ else if (s.Equals(Int.Eq))
+ {
+ constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.EQ, BigNum.ZERO);
+ sense = positive;
+ }
+ else if (s.Equals(Int.Neq))
+ {
+ constraint = MakeConstraint(le0, le1, LinearConstraint.ConstraintRelation.EQ, BigNum.ZERO);
+ sense = !positive;
+ }
+ if (constraint != null) {
+ if (constraint.coefficients.Count != 0) {
+ return new LinearConditionLiteral(sense, constraint);
+ } else if (constraint.IsConstantSatisfiable()) {
+ return null;
+ } else {
+ return new LCBottom();
+ }
+ }
+ }
+ return null;
+ }
+
+ public static LinearConstraint MakeConstraint(LinearExpr! le0, LinearExpr! le1,
+ LinearConstraint.ConstraintRelation rel, BigNum constantOffset) /* throws ArithmeticException */
+ {
+ le1.Negate();
+ le0.Add(le1);
+ le0.AddConstant(constantOffset);
+ return le0.ToConstraint(rel);
+ }
+
+ /// <summary>
+ /// Builds a linear expression from "e", if possible; returns null if not possible.
+ /// </summary>
+ /// <param name="e"></param>
+ /// <returns></returns>
+ public static /*maybe null*/ LinearExpr AsExpr(IExpr! e) /* throws ArithmeticException */
+ {
+ if (e is IVariable) {
+ // Note, without a type for the variable, we don't know if the identifier is intended to hold an integer value.
+ // However, it seems that no harm can be caused by here treating the identifier as if it held an
+ // integer value, because other parts of this method will reject the expression as a linear expression
+ // if non-numeric operations other than equality are applied to the identifier.
+ return new LinearExpr((IVariable)e);
+ } else if (e is IFunApp) {
+ IFunApp! funapp = (IFunApp)e;
+ IFunctionSymbol! s = funapp.FunctionSymbol;
+
+ if (s is IntSymbol) {
+ return new LinearExpr(((IntSymbol)s).Value);
+ } else if (s.Equals(Int.Negate)) {
+ assert funapp.Arguments.Count == 1;
+ LinearExpr le = AsExpr((IExpr!)funapp.Arguments[0]);
+ if (le != null) {
+ le.Negate();
+ return le;
+ }
+ } else if (s.Equals(Int.Add) || s.Equals(Int.Sub) || s.Equals(Int.Mul)) {
+ assert funapp.Arguments.Count == 2;
+ IExpr! arg0 = (IExpr!)funapp.Arguments[0];
+ IExpr! arg1 = (IExpr!)funapp.Arguments[1];
+ LinearExpr le0 = AsExpr(arg0);
+ if (le0 == null) {
+ return null;
+ }
+ LinearExpr le1 = AsExpr(arg1);
+ if (le1 == null) {
+ return null;
+ }
+
+ if (s.Equals(Int.Add)) {
+ le0.Add(le1);
+ return le0;
+ } else if (s.Equals(Int.Sub)) {
+ le1.Negate();
+ le0.Add(le1);
+ return le0;
+ } else if (s.Equals(Int.Mul)) {
+ BigNum x;
+ if (le0.AsConstant(out x))
+ {
+ le1.Multiply(x);
+ return le1;
+ }
+ else if (le1.AsConstant(out x))
+ {
+ le0.Multiply(x);
+ return le0;
+ }
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+ class LinearExpr
+ {
+ BigNum constant;
+ Term terms;
+
+ class Term
+ {
+ public BigNum coeff; // non-0, if the node is used
+ public IVariable! var;
+ public Term next;
+
+ public Term(BigNum coeff, IVariable! var)
+ {
+ this.coeff = coeff;
+ this.var = var;
+ // base();
+ }
+ }
+
+ public LinearExpr(BigNum x)
+ {
+ constant = x;
+ }
+
+ public LinearExpr(IVariable! var)
+ {
+ constant = BigNum.ZERO;
+ terms = new Term(BigNum.ONE, var);
+ }
+
+ public ISet /*IVariable!*/ GetDefinedDimensions()
+ {
+ HashSet /*IVariable!*/! dims = new HashSet /*IVariable!*/ ();
+ for (Term current = terms; current != null; current = current.next)
+ {
+ dims.Add(current.var);
+ }
+ return dims;
+ }
+
+ public BigNum TermCoefficient(/*MayBeNull*/ IVariable! var)
+ {
+ BigNum z = BigNum.ZERO;
+ if (var == null)
+ {
+ z = this.constant;
+ }
+ else if (terms != null)
+ {
+ Term current = terms;
+ while (current != null)
+ {
+ if (current.var == var)
+ {
+ break;
+ }
+ current = current.next;
+ }
+ if (current != null)
+ {
+ z = current.coeff;
+ }
+ }
+ return z;
+ }
+
+ public bool AsConstant(out BigNum x)
+ {
+ if (terms == null)
+ {
+ x = constant;
+ return true;
+ }
+ else
+ {
+ x = BigNum.FromInt(-70022); // to please complier
+ return false;
+ }
+ }
+
+ public void Negate() /* throws ArithmeticException */
+ {
+ checked
+ {
+ constant = -constant;
+ }
+
+ for (Term t = terms; t != null; t = t.next)
+ {
+ checked
+ {
+ t.coeff = -t.coeff;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Adds "x" to "this".
+ /// </summary>
+ /// <param name="x"></param>
+ public void AddConstant(BigNum x) /* throws ArithmeticException */
+ {
+ checked
+ {
+ constant += x;
+ }
+ }
+
+ /// <summary>
+ /// Adds "le" to "this". Afterwards, "le" should not be used, because it will have been destroyed.
+ /// </summary>
+ /// <param name="le"></param>
+ public void Add(LinearExpr! le) /* throws ArithmeticException */
+ requires le != this;
+ {
+ checked
+ {
+ constant += le.constant;
+ }
+ le.constant = BigNum.FromInt(-70029); // "le" should no longer be used; assign it a strange value so that misuse is perhaps more easily detected
+
+ // optimization:
+ if (le.terms == null)
+ {
+ return;
+ }
+ else if (terms == null)
+ {
+ terms = le.terms;
+ le.terms = null;
+ return;
+ }
+
+ // merge the two term lists
+ // Use a nested loop, which is quadratic in time complexity, but we hope the lists will be small
+ Term newTerms = null;
+ while (le.terms != null)
+ {
+ // take off next term from "le"
+ Term t = le.terms;
+ le.terms = t.next;
+ t.next = null;
+
+ for (Term u = terms; u != null; u = u.next)
+ {
+ if (u.var == t.var)
+ {
+ checked
+ {
+ u.coeff += t.coeff;
+ }
+ goto NextOuter;
+ }
+ }
+ t.next = newTerms;
+ newTerms = t;
+
+ NextOuter: ;
+ }
+
+ // finally, include all non-0 terms
+ while (terms != null)
+ {
+ // take off next term from "this"
+ Term t = terms;
+ terms = t.next;
+
+ if (!t.coeff.IsZero)
+ {
+ t.next = newTerms;
+ newTerms = t;
+ }
+ }
+ terms = newTerms;
+ }
+
+ public void Multiply(BigNum x) /* throws ArithmeticException */
+ {
+ if (x.IsZero)
+ {
+ constant = BigNum.ZERO;
+ terms = null;
+ }
+ else
+ {
+ for (Term t = terms; t != null; t = t.next)
+ {
+ checked
+ {
+ t.coeff *= x;
+ }
+ }
+ checked
+ {
+ constant *= x;
+ }
+ }
+ }
+
+ public bool IsInvertible(IVariable! var)
+ {
+ for (Term t = terms; t != null; t = t.next)
+ {
+ if (t.var == var)
+ {
+ System.Diagnostics.Debug.Assert(!t.coeff.IsZero);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public LinearConstraint ToConstraint(LinearConstraint.ConstraintRelation rel) /* throws ArithmeticException */
+ {
+ LinearConstraint constraint = new LinearConstraint(rel);
+ for (Term t = terms; t != null; t = t.next)
+ {
+ constraint.SetCoefficient(t.var, t.coeff.ToRational);
+ }
+ BigNum rhs = -constant;
+ constraint.rhs = rhs.ToRational;
+ return constraint;
+ }
+ }
+}
diff --git a/Source/AIFramework/Polyhedra/SimplexTableau.ssc b/Source/AIFramework/Polyhedra/SimplexTableau.ssc
new file mode 100644
index 00000000..b6f4095c
--- /dev/null
+++ b/Source/AIFramework/Polyhedra/SimplexTableau.ssc
@@ -0,0 +1,717 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using System.Collections;
+ using System;
+ using Microsoft.Contracts;
+ using Microsoft.Basetypes;
+ using IMutableSet = Microsoft.Boogie.Set;
+ using HashSet = Microsoft.Boogie.Set;
+
+
+ /// <summary>
+ /// Used by LinearConstraintSystem.GenerateFrameFromConstraints.
+ /// </summary>
+ public class SimplexTableau
+ {
+ readonly int rows;
+ readonly int columns;
+ readonly Rational[,]! m;
+
+ readonly int numInitialVars;
+ readonly int numSlackVars;
+ readonly int rhsColumn;
+
+ readonly ArrayList /*IVariable!*/! dims;
+ readonly int[]! basisColumns;
+ readonly int[]! inBasis;
+ bool constructionDone = false;
+
+ void CheckInvariant()
+ {
+ assert(rows == m.GetLength(0));
+ assert(1 <= columns && columns == m.GetLength(1));
+ assert(0 <= numInitialVars);
+ assert(0 <= numSlackVars && numSlackVars <= rows);
+ assert(numInitialVars + numSlackVars + 1 == columns);
+ assert(rhsColumn == columns - 1);
+ assert(dims.Count == numInitialVars);
+ assert(basisColumns.Length == rows);
+ assert(inBasis.Length == numInitialVars + numSlackVars);
+
+ bool[] b = new bool[numInitialVars + numSlackVars];
+ int numColumnsInBasis = 0;
+ int numUninitializedRowInfo = 0;
+ for (int i = 0; i < rows; i++)
+ {
+ int c = basisColumns[i];
+ if (c == rhsColumn)
+ {
+ // all coefficients in this row are 0 (but the right-hand side may be non-0)
+ for (int j = 0; j < rhsColumn; j++)
+ {
+ assert m[i,j].IsZero;
+ }
+ numColumnsInBasis++;
+ }
+ else if (c == -1)
+ {
+ assert(!constructionDone);
+ numUninitializedRowInfo++;
+ }
+ else
+ {
+ // basis column is a column
+ assert(0 <= c && c < numInitialVars + numSlackVars);
+ // basis column is unique
+ assert(!b[c]);
+ b[c] = true;
+ // column is marked as being in basis
+ assert(inBasis[c] == i);
+ // basis column really is a basis column
+ for (int j = 0; j < rows; j++)
+ {
+ if (j == i)
+ {
+ assert m[j,c].HasValue(1);// == (Rational)new Rational(1));
+ }
+ else
+ {
+ assert m[j,c].IsZero;
+ }
+ }
+ }
+ }
+ // no other columns are marked as being in basis
+ foreach (int i in inBasis)
+ {
+ if (0 <= i)
+ {
+ assert(i < rows);
+ numColumnsInBasis++;
+ }
+ else
+ {
+ assert(i == -1);
+ }
+ }
+ assert(rows - numUninitializedRowInfo <= numColumnsInBasis && numColumnsInBasis <= rows);
+ assert(!constructionDone || numUninitializedRowInfo == 0);
+ }
+
+ /// <summary>
+ /// Constructs a matrix that represents the constraints "constraints", adding slack
+ /// variables for the inequalities among "constraints". Puts the matrix in canonical
+ /// form.
+ /// </summary>
+ /// <param name="constraints"></param>
+ [NotDelayed]
+ public SimplexTableau(ArrayList /*LinearConstraint*/! constraints)
+ {
+#if DEBUG_PRINT
+ Console.WriteLine("DEBUG: SimplexTableau constructor called with:");
+ foreach (LinearConstraint lc in constraints)
+ {
+ Console.WriteLine(" {0}", lc);
+ }
+#endif
+ // Note: This implementation is not particularly efficient, but it'll do for now.
+
+ ArrayList dims = this.dims = new ArrayList /*IVariable!*/ ();
+ int slacks = 0;
+ foreach (LinearConstraint! cc in constraints)
+ {
+ foreach (IVariable! dim in cc.coefficients.Keys)
+ {
+ if (!dims.Contains(dim))
+ {
+ dims.Add(dim);
+ }
+ }
+ if (cc.Relation == LinearConstraint.ConstraintRelation.LE)
+ {
+ slacks++;
+ }
+ }
+
+ int numInitialVars = this.numInitialVars = dims.Count;
+ int numSlackVars = this.numSlackVars = slacks;
+ int rows = this.rows = constraints.Count;
+ int columns = this.columns = numInitialVars + numSlackVars + 1;
+ this.m = new Rational[rows, columns];
+ this.rhsColumn = columns-1;
+ this.basisColumns = new int[rows];
+ this.inBasis = new int[columns-1];
+
+ base();
+
+ for (int i = 0; i < inBasis.Length; i++)
+ {
+ inBasis[i] = -1;
+ }
+
+ // Fill in the matrix
+ int r = 0;
+ int iSlack = 0;
+ foreach (LinearConstraint! cc in constraints)
+ {
+ for (int i = 0; i < dims.Count; i++)
+ {
+ m[r,i] = cc[(IVariable!)dims[i]];
+ }
+ if (cc.Relation == LinearConstraint.ConstraintRelation.LE)
+ {
+ m[r, numInitialVars + iSlack] = Rational.ONE;
+ basisColumns[r] = numInitialVars + iSlack;
+ inBasis[numInitialVars + iSlack] = r;
+ iSlack++;
+ }
+ else
+ {
+ basisColumns[r] = -1; // special value to communicate to Pivot that basis column i hasn't been set up yet
+ }
+ m[r,rhsColumn] = cc.rhs;
+ r++;
+ }
+ assert(r == constraints.Count);
+ assert(iSlack == numSlackVars);
+#if DEBUG_PRINT
+ Console.WriteLine("DEBUG: Intermediate tableau state in SimplexTableau constructor:");
+ Dump();
+#endif
+
+ // Go through the rows with uninitialized basis columns. These correspond to equality constraints.
+ // For each one, find an initial variable (non-slack variable) whose column we can make the basis
+ // column of the row.
+ for (int i = 0; i < rows; i++)
+ {
+ if (basisColumns[i] != -1)
+ {
+ continue;
+ }
+ // Find a non-0 column in row i that we can make a basis column. Since rows corresponding
+ // to equality constraints don't have slack variables and since the pivot operations performed
+ // by iterations of this loop don't introduce any non-0 coefficients in the slack-variable
+ // columns of these rows, we only need to look through the columns corresponding to initial
+ // variables.
+ for (int j = 0; j < numInitialVars; j++)
+ {
+ if (m[i,j].IsNonZero)
+ {
+#if DEBUG_PRINT
+ Console.WriteLine("-- About to Pivot({0},{1})", i, j);
+#endif
+ assert(inBasis[j] == -1);
+ Pivot(i,j);
+#if DEBUG_PRINT
+ Console.WriteLine("Tableau after Pivot:");
+ Dump();
+ #endif
+ goto SET_UP_NEXT_INBASIS_COLUMN;
+ }
+ }
+ // Check the assertion in the comment above, that is, that columns corresponding to slack variables
+ // are 0 in this row.
+ for (int j = numInitialVars; j < rhsColumn; j++)
+ {
+ assert m[i,j].IsZero;
+ }
+ // There is no column in this row that we can put into basis.
+ basisColumns[i] = rhsColumn;
+ SET_UP_NEXT_INBASIS_COLUMN: {}
+ }
+
+ constructionDone = true;
+ CheckInvariant();
+ }
+
+ public IMutableSet! /*IVariable!*/ GetDimensions()
+ {
+ HashSet /*IVariable!*/ z = new HashSet /*IVariable!*/ ();
+ foreach (IVariable! dim in dims)
+ {
+ z.Add(dim);
+ }
+ return z;
+ }
+
+ public Rational this [int r, int c]
+ {
+ get
+ {
+ return m[r,c];
+ }
+ set
+ {
+ m[r,c] = value;
+ }
+ }
+
+ /// <summary>
+ /// Applies the Pivot Operation on row "r" and column "c".
+ ///
+ /// This method can be called when !constructionDone, that is, at a time when not all basis
+ /// columns have been set up (indicated by -1 in basisColumns). This method helps set up
+ /// those basis columns.
+ ///
+ /// The return value is an undo record that can be used with UnPivot.
+ /// </summary>
+ /// <param name="r"></param>
+ /// <param name="c"></param>
+ public Rational[]! Pivot(int r, int c)
+ {
+ assert(0 <= r && r < rows);
+ assert(0 <= c && c < columns-1);
+ assert(m[r,c].IsNonZero);
+ assert(inBasis[c] == -1); // follows from invariant and m[r,c] != 0
+ assert(basisColumns[r] != rhsColumn); // follows from invariant and m[r,c] != 0
+
+ Rational[] undo = new Rational[rows+1];
+ for (int i = 0; i < rows; i++)
+ {
+ undo[i] = m[i,c];
+ }
+
+ // scale the pivot row
+ Rational q = m[r,c];
+ if (q != Rational.ONE)
+ {
+ for (int j = 0; j < columns; j++)
+ {
+ m[r,j] /= q;
+ }
+ }
+
+ // subtract a multiple of the pivot row from all other rows
+ for (int i = 0; i < rows; i++)
+ {
+ if (i != r)
+ {
+ q = m[i,c];
+ if (q.IsNonZero)
+ {
+ for (int j = 0; j < columns; j++)
+ {
+ m[i,j] -= q * m[r,j];
+ }
+ }
+ }
+ }
+
+ // update basis information
+ int prevCol = basisColumns[r];
+ undo[rows] = Rational.FromInt(prevCol);
+ basisColumns[r] = c;
+ if (prevCol != -1)
+ {
+ inBasis[prevCol] = -1;
+ }
+ inBasis[c] = r;
+
+ return undo;
+ }
+
+ /// <summary>
+ /// If the last operation applied to the tableau was:
+ /// undo = Pivot(i,j);
+ /// then UnPivot(i, j, undo) undoes the pivot operation.
+ /// Note: This operation is not supported for any call to Pivot before constructionDone
+ /// is set to true.
+ /// </summary>
+ /// <param name="r"></param>
+ /// <param name="c"></param>
+ /// <param name="undo"></param>
+ void UnPivot(int r, int c, Rational[]! undo)
+ {
+ assert(0 <= r && r < rows);
+ assert(0 <= c && c < columns-1);
+ assert(m[r,c].HasValue(1));
+ assert(undo.Length == rows+1);
+
+ // add a multiple of the pivot row to all other rows
+ for (int i = 0; i < rows; i++)
+ {
+ if (i != r)
+ {
+ Rational q = undo[i];
+ if (q.IsNonZero)
+ {
+ for (int j = 0; j < columns; j++)
+ {
+ m[i,j] += q * m[r,j];
+ }
+ }
+ }
+ }
+
+ // scale the pivot row
+ Rational p = undo[r];
+ for (int j = 0; j < columns; j++)
+ {
+ m[r,j] *= p;
+ }
+
+ // update basis information
+ int prevCol = undo[rows].AsInteger;
+ assert(prevCol != -1);
+ basisColumns[r] = prevCol;
+ inBasis[c] = -1;
+ inBasis[prevCol] = r;
+ }
+
+ /// <summary>
+ /// Returns true iff the current basis of the system of constraints modeled by the simplex tableau
+ /// is feasible. May have a side effect of performing a number of pivot operations on the tableau,
+ /// but any such pivot operation will be in the columns of slack variables (that is, this routine
+ /// does not change the set of initial-variable columns in basis).
+ ///
+ /// CAVEAT: I have no particular reason to believe that the algorithm used here will terminate. --KRML
+ /// </summary>
+ /// <returns></returns>
+ public bool IsFeasibleBasis
+ {
+ get
+ {
+ // while there is a slack variable in basis whose row has a negative right-hand side
+ while (true)
+ {
+ bool feasibleBasis = true;
+ for (int c = numInitialVars; c < rhsColumn; c++)
+ {
+ int k = inBasis[c];
+ if (0 <= k && k < rhsColumn && m[k,rhsColumn].IsNegative)
+ {
+ assert(m[k,c].HasValue(1)); // c is in basis
+ // Try to pivot on a different slack variable in this row
+ for (int i = numInitialVars; i < rhsColumn; i++)
+ {
+ if (m[k,i].IsNegative)
+ {
+ assert(c != i); // c is in basis, so m[k,c]==1, which is not negative
+ Pivot(k, i);
+#if DEBUG_PRINT
+ Console.WriteLine("Tableau after Pivot operation on ({0},{1}) in IsFeasibleBasis:", k, i);
+ Dump();
+#endif
+ assert(inBasis[c] == -1);
+ assert(inBasis[i] == k);
+ assert(m[k,rhsColumn].IsNonNegative);
+ goto START_ANEW;
+ }
+ }
+ feasibleBasis = false;
+ }
+ }
+ return feasibleBasis;
+ START_ANEW: ;
+ }
+ return false; // make compiler shut up
+ }
+ }
+
+ /// <summary>
+ /// Whether or not all initial variables (the non-slack variables) are in basis)
+ /// </summary>
+ public bool AllInitialVarsInBasis
+ {
+ get
+ {
+ for (int i = 0; i < numInitialVars; i++)
+ {
+ if (inBasis[i] == -1)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /// <summary>
+ /// Adds as many initial variables as possible to the basis.
+ /// </summary>
+ /// <returns></returns>
+ public void AddInitialVarsToBasis()
+ {
+ // while there exists an initial variable not in the basis and not satisfying
+ // condition 3.4.2.2 in Cousot and Halbwachs, perform a pivot operation
+ while (true)
+ {
+ for (int i = 0; i < numInitialVars; i++)
+ {
+ if (inBasis[i] == -1)
+ {
+ // initial variable i is not in the basis
+ for (int j = 0; j < rows; j++)
+ {
+ if (m[j,i].IsNonZero)
+ {
+ int k = basisColumns[j];
+ if (numInitialVars <= k && k < rhsColumn)
+ {
+ // slack variable k is in basis for row j
+ Pivot(j, i);
+ assert(inBasis[k] == -1);
+ assert(inBasis[i] == j && basisColumns[j] == i);
+ goto START_ANEW;
+ }
+ }
+ }
+ }
+ }
+ // No more initial variables can be moved into basis.
+ return;
+ START_ANEW: {}
+ }
+ }
+
+ /// <summary>
+ /// Adds to "lines" the lines implied by initial-variable columns not in basis
+ /// (see section 3.4.2 of Cousot and Halbwachs), and adds to "constraints" the
+ /// constraints to exclude those lines (see step 4.2 of section 3.4.3 of
+ /// Cousot and Halbwachs).
+ /// </summary>
+ /// <param name="lines"></param>
+ /// <param name="constraints"></param>
+ public void ProduceLines(ArrayList /*FrameElement*/! lines, ArrayList /*LinearConstraint*/! constraints)
+ {
+ // for every initial variable not in basis
+ for (int i0 = 0; i0 < numInitialVars; i0++)
+ {
+ if (inBasis[i0] == -1)
+ {
+ FrameElement fe = new FrameElement();
+ LinearConstraint lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ);
+ for (int i = 0; i < numInitialVars; i++)
+ {
+ if (i == i0)
+ {
+ fe.AddCoordinate((IVariable!)dims[i], Rational.ONE);
+ lc.SetCoefficient((IVariable!)dims[i], Rational.ONE);
+ }
+ else if (inBasis[i] != -1)
+ {
+ // i is a basis column
+ assert(m[inBasis[i],i].HasValue(1));
+ Rational val = -m[inBasis[i],i0];
+ fe.AddCoordinate((IVariable!)dims[i], val);
+ lc.SetCoefficient((IVariable!)dims[i], val);
+ }
+ }
+ lines.Add(fe);
+ constraints.Add(lc);
+ }
+ }
+ }
+
+ /// <summary>
+ /// From a feasible point where all initial variables are in the basis, traverses
+ /// all feasible bases containing all initial variables. For each such basis, adds
+ /// the vertices to "vertices" and adds to "rays" the extreme rays. See step 4.2
+ /// in section 3.4.3 of Cousot and Halbwachs.
+ /// A more efficient algorithm is found in the paper "An algorithm for
+ /// determining all extreme points of a convex polytope" by N. E. Dyer and L. G. Proll,
+ /// Mathematical Programming, 12, 1977.
+ /// Assumes that the tableau is in a state where all initial variables are in the basis.
+ /// This method has no net effect on the tableau.
+ /// Note: Duplicate vertices and rays may be added.
+ /// </summary>
+ /// <param name="vertices"></param>
+ /// <param name="rays"></param>
+ public void TraverseVertices(ArrayList! /*FrameElement*/ vertices, ArrayList! /*FrameElement*/ rays)
+ {
+ ArrayList /*bool[]*/ basesSeenSoFar = new ArrayList /*bool[]*/ ();
+ TraverseBases(basesSeenSoFar, vertices, rays);
+ }
+
+ /// <summary>
+ /// Worker method of TraverseVertices.
+ /// This method has no net effect on the tableau.
+ /// </summary>
+ /// <param name="basesSeenSoFar"></param>
+ /// <param name="vertices"></param>
+ /// <param name="rays"></param>
+ void TraverseBases(ArrayList /*bool[]*/! basesSeenSoFar, ArrayList /*FrameElement*/! vertices, ArrayList /*FrameElement*/! rays)
+ {
+ CheckInvariant();
+
+ bool[] thisBasis = new bool[numSlackVars];
+ for (int i = numInitialVars; i < rhsColumn; i++)
+ {
+ if (inBasis[i] != -1)
+ {
+ thisBasis[i-numInitialVars] = true;
+ }
+ }
+ foreach (bool[]! basis in basesSeenSoFar)
+ {
+ assert(basis.Length == numSlackVars);
+ for (int i = 0; i < numSlackVars; i++)
+ {
+ if (basis[i] != thisBasis[i])
+ {
+ goto COMPARE_WITH_NEXT_BASIS;
+ }
+ }
+ // thisBasis and basis are the same--that is, basisColumns has been visited before--so
+ // we don't traverse anything from here
+ return;
+ COMPARE_WITH_NEXT_BASIS: {}
+ }
+ // basisColumns has not been seen before; record thisBasis and continue with the traversal here
+ basesSeenSoFar.Add(thisBasis);
+
+#if DEBUG_PRINT
+ Console.Write("TraverseBases, new basis: ");
+ foreach (bool t in thisBasis) {
+ Console.Write("{0}", t ? "*" : ".");
+ }
+ Console.WriteLine();
+ Dump();
+#endif
+ // Add vertex
+ FrameElement v = new FrameElement();
+ for (int i = 0; i < rows; i++)
+ {
+ int j = basisColumns[i];
+ if (j < numInitialVars)
+ {
+ v.AddCoordinate((IVariable!)dims[j], m[i,rhsColumn]);
+ }
+ }
+#if DEBUG_PRINT
+ Console.WriteLine(" Adding vertex: {0}", v);
+#endif
+ vertices.Add(v);
+
+ // Add rays. Traverse all columns corresponding to slack variables that
+ // are not in basis (see second bullet of section 3.4.2 of Cousot and Halbwachs).
+ for (int i0 = numInitialVars; i0 < rhsColumn; i0++)
+ {
+ if (inBasis[i0] != -1)
+ {
+ // skip those slack-variable columns that are in basis
+ continue;
+ }
+ // check if slack-variable, non-basis column i corresponds to an extreme ray
+ for (int row = 0; row < rows; row++)
+ {
+ if (m[row,i0].IsPositive)
+ {
+ for (int k = numInitialVars; k < rhsColumn; k++)
+ {
+ if (inBasis[k] != -1 && m[row,k].IsNonZero)
+ {
+ // does not correspond to an extreme ray
+ goto CHECK_NEXT_SLACK_VAR;
+ }
+ }
+ }
+ }
+ // corresponds to an extreme ray
+ FrameElement ray = new FrameElement();
+ for (int i = 0; i < numInitialVars; i++)
+ {
+ int j0 = inBasis[i];
+ Rational val = -m[j0,i0];
+ ray.AddCoordinate((IVariable!)dims[i], val);
+ }
+#if DEBUG_PRINT
+ Console.WriteLine(" Adding ray: {0}", ray);
+#endif
+ rays.Add(ray);
+ CHECK_NEXT_SLACK_VAR: {}
+ }
+
+ // Continue traversal
+ for (int i = numInitialVars; i < rhsColumn; i++)
+ {
+ int j = inBasis[i];
+ if (j != -1)
+ {
+ // try moving i out of basis and some other slack-variable column into basis
+ for (int k = numInitialVars; k < rhsColumn; k++)
+ {
+ if (inBasis[k] == -1 && m[j,k].IsPositive)
+ {
+ Rational[] undo = Pivot(j, k);
+ // check if the new basis is feasible
+ for (int p = 0; p < rows; p++)
+ {
+ int c = basisColumns[p];
+ if (numInitialVars <= c && c < rhsColumn && m[p,rhsColumn].IsNegative)
+ {
+ // not feasible
+ goto AFTER_TRAVERSE;
+ }
+ }
+ TraverseBases(basesSeenSoFar, vertices, rays);
+ AFTER_TRAVERSE:
+ UnPivot(j, k, undo);
+ }
+ }
+ }
+ }
+ }
+
+ public void Dump()
+ {
+ // names
+ Console.Write(" ");
+ for (int i = 0; i < numInitialVars; i++)
+ {
+ Console.Write(" {0,4} ", dims[i]);
+ }
+ Console.WriteLine();
+ // numbers
+ Console.Write(" ");
+ for (int i = 0; i < columns; i++)
+ {
+ if (i == numInitialVars || i == rhsColumn)
+ {
+ Console.Write("|");
+ }
+ Console.Write(" {0,4}", i);
+ if (i < rhsColumn && inBasis[i] != -1)
+ {
+ Console.Write("* ");
+ assert(basisColumns[inBasis[i]] == i);
+ }
+ else
+ {
+ Console.Write(" ");
+ }
+ }
+ Console.WriteLine();
+ // line
+ Console.Write(" ");
+ for (int i = 0; i < columns; i++)
+ {
+ if (i == numInitialVars || i == rhsColumn)
+ {
+ Console.Write("+");
+ }
+ Console.Write("---------");
+ }
+ Console.WriteLine();
+
+ for (int j = 0; j < rows; j++)
+ {
+ Console.Write("{0,4}: ", basisColumns[j]);
+ for (int i = 0; i < columns; i++)
+ {
+ if (i == numInitialVars || i == rhsColumn)
+ {
+ Console.Write("|");
+ }
+ Console.Write(" {0,4:n1} ", m[j,i]);
+ }
+ Console.WriteLine();
+ }
+ }
+ }
+}
diff --git a/Source/AIFramework/VariableMap/ConstantAbstraction.ssc b/Source/AIFramework/VariableMap/ConstantAbstraction.ssc
new file mode 100644
index 00000000..7b7fd87e
--- /dev/null
+++ b/Source/AIFramework/VariableMap/ConstantAbstraction.ssc
@@ -0,0 +1,210 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using Microsoft.Contracts;
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using System.Collections;
+ using System.Diagnostics;
+ using System.Compiler.Analysis;
+ using Microsoft.Basetypes;
+
+ /// <summary>
+ /// Represents an invariant over constant variable assignments.
+ /// </summary>
+ public class ConstantLattice : MicroLattice
+ {
+ enum Value { Top, Bottom, Constant }
+
+ private class Elt : Element
+ {
+ public Value domainValue;
+ public BigNum constantValue; // valid iff domainValue == Value.Constant
+
+ public Elt (Value v) { this.domainValue = v; }
+
+ public Elt (BigNum i) { this.domainValue = Value.Constant; this.constantValue = i; }
+
+ public bool IsConstant { get { return this.domainValue == Value.Constant; } }
+
+ public BigNum Constant { get { return this.constantValue; } } // only when IsConstant
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override System.Collections.Generic.ICollection<IVariable!>! FreeVariables()
+ {
+ return (!) (new System.Collections.Generic.List<IVariable!>()).AsReadOnly();
+ }
+
+ public override Element! Clone()
+ {
+ if (this.IsConstant)
+ return new Elt(constantValue);
+ else
+ return new Elt(domainValue);
+ }
+ }
+
+ readonly IIntExprFactory! factory;
+
+ public ConstantLattice(IIntExprFactory! factory)
+ {
+ this.factory = factory;
+ // base();
+ }
+
+ public override Element! Top
+ {
+ get { return new Elt(Value.Top); }
+ }
+
+ public override Element! Bottom
+ {
+ get { return new Elt(Value.Bottom); }
+ }
+
+ public override bool IsTop (Element! element)
+ {
+ Elt e = (Elt)element;
+ return e.domainValue == Value.Top;
+ }
+
+ public override bool IsBottom (Element! element)
+ {
+ Elt e = (Elt)element;
+ return e.domainValue == Value.Bottom;
+ }
+
+ public override Element! NontrivialJoin (Element! first, Element! second)
+ {
+ Elt a = (Elt)first;
+ Elt b = (Elt)second;
+ Debug.Assert(a.domainValue == Value.Constant && b.domainValue == Value.Constant);
+ return (a.constantValue.Equals(b.constantValue)) ? a : (Elt)Top;
+ }
+
+ public override Element! NontrivialMeet (Element! first, Element! second)
+ {
+ Elt a = (Elt)first;
+ Elt b = (Elt)second;
+ Debug.Assert(a.domainValue == Value.Constant && b.domainValue == Value.Constant);
+ return (a.constantValue.Equals(b.constantValue)) ? a : (Elt)Bottom;
+ }
+
+ public override Element! Widen (Element! first, Element! second)
+ {
+ return Join(first,second);
+ }
+
+ protected override bool AtMost (Element! first, Element! second) // this <= that
+ {
+ Elt a = (Elt)first;
+ Elt b = (Elt)second;
+ return a.Constant.Equals(b.Constant);
+ }
+
+ public override IExpr! ToPredicate(IVariable! var, Element! element) {
+ return factory.Eq(var, (!)GetFoldExpr(element));
+ }
+
+ public override IExpr GetFoldExpr(Element! element) {
+ Elt e = (Elt)element;
+ assert e.domainValue == Value.Constant;
+ return factory.Const(e.constantValue);
+ }
+
+ public override bool Understands(IFunctionSymbol! f, IList/*<IExpr!>*/! args) {
+ return f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq);
+ }
+
+ public override Element! EvaluatePredicate(IExpr! e) {
+
+ IFunApp nary = e as IFunApp;
+ if (nary != null) {
+ if (nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) {
+ IList/*<IExpr!>*/! args = nary.Arguments;
+ assert args.Count == 2;
+ IExpr! arg0 = (IExpr!)args[0];
+ IExpr! arg1 = (IExpr!)args[1];
+
+ // Look for "x == const" or "const == x".
+ try {
+ if (arg0 is IVariable) {
+ BigNum z;
+ if (Fold(arg1, out z)) {
+ return new Elt(z);
+ }
+ } else if (arg1 is IVariable) {
+ BigNum z;
+ if (Fold(arg0, out z)) {
+ return new Elt(z);
+ }
+ }
+ } catch (System.ArithmeticException) {
+ // fall through and return Top. (Note, an alternative design may
+ // consider returning Bottom.)
+ }
+ }
+ }
+ return Top;
+ }
+
+ /// <summary>
+ /// Returns true if "expr" represents a constant integer expressions, in which case
+ /// "z" returns as that integer. Otherwise, returns false, in which case "z" should
+ /// not be used by the caller.
+ ///
+ /// This method throws an System.ArithmeticException in the event that folding the
+ /// constant expression results in an arithmetic overflow or division by zero.
+ /// </summary>
+ private bool Fold(IExpr! expr, out BigNum z)
+ {
+ IFunApp e = expr as IFunApp;
+ if (e == null) {
+ z = BigNum.ZERO;
+ return false;
+ }
+
+ if (e.FunctionSymbol is IntSymbol) {
+ z = ((IntSymbol)e.FunctionSymbol).Value;
+ return true;
+
+ } else if (e.FunctionSymbol.Equals(Int.Negate)) {
+ IList/*<IExpr!>*/! args = e.Arguments;
+ assert args.Count == 1;
+ IExpr! arg0 = (IExpr!)args[0];
+
+ if (Fold(arg0, out z)) {
+ z = z.Neg;
+ return true;
+ }
+
+ } else if (e.Arguments.Count == 2) {
+ IExpr! arg0 = (IExpr!)e.Arguments[0];
+ IExpr! arg1 = (IExpr!)e.Arguments[1];
+ BigNum z0, z1;
+ if (Fold(arg0, out z0) && Fold(arg1, out z1)) {
+ if (e.FunctionSymbol.Equals(Int.Add)) {
+ z = z0 + z1;
+ } else if (e.FunctionSymbol.Equals(Int.Sub)) {
+ z = z0 - z1;
+ } else if (e.FunctionSymbol.Equals(Int.Mul)) {
+ z = z0 * z1;
+ } else if (e.FunctionSymbol.Equals(Int.Div)) {
+ z = z0 / z1;
+ } else if (e.FunctionSymbol.Equals(Int.Mod)) {
+ z = z0 % z1;
+ } else {
+ z = BigNum.ZERO;
+ return false;
+ }
+ return true;
+ }
+ }
+
+ z = BigNum.ZERO;
+ return false;
+ }
+ }
+}
diff --git a/Source/AIFramework/VariableMap/ConstantExpressions.ssc b/Source/AIFramework/VariableMap/ConstantExpressions.ssc
new file mode 100644
index 00000000..306c4e8f
--- /dev/null
+++ b/Source/AIFramework/VariableMap/ConstantExpressions.ssc
@@ -0,0 +1,538 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+
+ /////////////////////////////////////////////////////////////////////////////////
+ // The Abstract domain for determining "constant" expressions
+ // i.e. It determines which expression are statically binded
+ /////////////////////////////////////////////////////////////////////////////////
+/*
+using System;
+
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using Microsoft.Contracts;
+ using System.Collections.Generic;
+ using Microsoft.AbstractInterpretationFramework;
+
+ /// <summary>
+ /// This is an abstract domain for inferring constant expressions
+ /// </summary>
+
+ public class ConstantExpressions : Lattice
+ {
+ /// <summary>
+ /// An abstract element is made of two maps:
+ /// + A map from variables to expressions \cup top ( i.e. for each variable, the expression it is binded )
+ /// + A map from variables to set of variabes ( i.e. for each variable, the set of variables that depends on its value )
+ /// </summary>
+ private class AbstractElement: Element
+ {
+ private Dictionary<IVariable!, BindExpr> variableBindings;
+ private Dictionary<IVariable!, List<IVariable>> variableDependences;
+
+ static private AbstractElement! bottom;
+ static public Element! Bottom
+ {
+ get
+ {
+ if(bottom == null)
+ {
+ bottom = new AbstractElement();
+ bottom.variableBindings = null;
+ bottom.variableDependences = null;
+ }
+ assert bottom.variableBindings == null && bottom.variableDependences == null;
+ return bottom;
+ }
+ }
+
+ static public Element! Top
+ {
+ get
+ {
+ return new AbstractElement();
+ }
+ }
+
+ AbstractElement()
+ {
+ this.variableBindings = new Dictionary<IVariable!, BindExpr>();
+ this.variableDependences = new Dictionary<IVariable!, List<IVariable>>();
+ }
+
+ /// <summary>
+ /// Our abstract element is top if and only if it has any constraint on variables
+ /// </summary>
+ public bool IsTop
+ {
+ get
+ {
+ return this.variableBindings.Keys.Count == 0 && this.variableDependences.Keys.Count == 0;
+ }
+ }
+
+ /// <summary>
+ /// Our abstract element is bottom if and only if the maps are null
+ /// </summary>
+ public bool IsBottom
+ {
+ get
+ {
+ assert (this.variableBindings == null) <==> (this.variableDependences == null);
+ return this.variableBindings == null && this.variableDependences == null;
+ }
+ }
+
+ /// <summary>
+ /// The pointwise join...
+ /// </summary>
+ public static AbstractElement! Join(AbstractElement! left, AbstractElement! right)
+ {
+ AbstractElement! result = new AbstractElement();
+
+ // Put all the variables in the left
+ foreach(IVariable! var in left.variableBindings.Keys)
+ {
+ BindExpr leftVal = left.variableBindings[var];
+ assert leftVal != null;
+
+ BindExpr rightVal = right.variableBindings[var];
+
+ if(rightVal== null) // the expression is not there
+ {
+ result.variableBindings.Add(var, leftVal);
+ }
+ else // both abstract elements have a definition for the variable....
+ {
+ result.variableBindings.Add(var, BindExpr.Join(leftVal, rightVal));
+ }
+ }
+
+ // Put all the variables in the right
+ foreach(IVariable! var in right.variableBindings.Keys)
+ {
+ BindExpr rightVal = right.variableBindings[var];
+ assert rightVal != null;
+
+ BindExpr leftVal = left.variableBindings[var];
+
+ if(rightVal== null) // the expression is not there
+ {
+ result.variableBindings.Add(var, rightVal);
+ }
+ else // both abstract elements have a definition for the variable....
+ {
+ result.variableBindings.Add(var, BindExpr.Join(rightVal, leftVal));
+ }
+ }
+
+ // Join the dependencies...
+ foreach(IVariable! var in left.variableDependences.Keys)
+ {
+ List<IVariable> dependencies = left.variableDependences[var];
+ List<IVariable> dup = new List<IVariable>(dependencies);
+
+ result.variableDependences.Add(var, dup);
+ }
+
+ foreach(IVariable! var in right.variableDependences.Keys)
+ {
+ if(result.variableDependences.ContainsKey(var))
+ {
+ List<IVariable> dependencies = result.variableDependences[var];
+ dependencies.AddRange(right.variableDependences[var]);
+ }
+ else
+ {
+ List<IVariable> dependencies = right.variableDependences[var];
+ List<IVariable> dup = new List<IVariable>(dependencies);
+
+ result.variableDependences.Add(var, dup);
+ }
+ }
+
+ // Normalize... i.e. for the variables such thas they point to an unknown expression (top) we have to update also their values
+ result.Normalize();
+
+ return result;
+ }
+
+
+ ///<summary>
+ /// Normalize the current abstract element, in that it propagetes the "dynamic" information throughtout the abstract element
+ ///</summary>
+ public void Normalize()
+ {
+ if(this.IsBottom)
+ return;
+ if(this.IsTop)
+ return;
+ assert this.variableBindings != null;
+
+ bool atFixpoint = false;
+
+ while(!atFixpoint)
+ {
+ atFixpoint = true; // guess that we've got the fixpoint...
+
+ foreach(IVariable x in this.variableBindings.Keys)
+ {
+ if(this.variableBindings[x].IsTop) // It means that the variable is tied to a dynamic expression
+ {
+ foreach(IVariable y in this.variableDependences[x]) // The all the variables that depend on x are also dynamic...
+ {
+ assert x != y; // A variable cannot depend on itself...
+ if(!this.variableBindings[y].IsTop)
+ {
+ this.variableBindings[y] = BindExpr.Top;
+ atFixpoint = false; // the assumption that we were at the fixpoint was false, we have still to propagate some information...
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// The pointwise meet...
+ /// </summary>
+ public static AbstractElement! Meet(AbstractElement! left, AbstractElement! right)
+ {
+ AbstractElement! result = new AbstractElement();
+
+ // Put the variables that are both in left and right
+ foreach(IVariable var in left.variableBindings.Keys)
+ {
+ if(right.variableBindings.ContainsKey(var))
+ {
+ result.variableBindings.Add(var, BindExpr.Meet(left.variableBindings[var], right.variableBindings[var]));
+ }
+ }
+
+ // Intersect the dependencies
+ foreach(IVariable var in result.variableBindings.Keys)
+ {
+ List<IVariable> depLeft = left.variableDependences[var];
+ List<IVariable> depRight = right.variableDependences[var];
+
+ // Intersect the two sets
+ result.variableDependences.Add(var, depLeft);
+ foreach(IVariable v in depRight)
+ {
+ if(!result.variableDependences.ContainsKey(v))
+ {
+ result.variableDependences.Remove(v);
+ }
+ }
+ }
+
+ // Now we remove the dependencies with variables not in variableBindings
+ List<IVariable>! varsToRemove = new List<IVariable>();
+
+ foreach(IVariable var in result.
+
+
+ }
+
+ /// <summary>
+ /// Clone the current abstract element
+ /// </summary>
+ public override Element! Clone()
+ {
+ AbstractElement cloned = new AbstractElement();
+ foreach(IVariable var in this.variableBindings.Keys)
+ {
+ cloned.variableBindings.Add(var, this.variableBindings[var]);
+ }
+
+ foreach(IVariable var in this.variableDependences.Keys)
+ {
+ List<IVariable> dependingVars = this.variableDependences[var];
+ List<IVariable> clonedDependingVars = new List<IVariable>(dependingVars);
+ cloned.variableDependences.Add(var, clonedDependingVars);
+ }
+ }
+
+ /// <summary>
+ /// Return the variables that have a binding
+ /// </summary>
+ public override ICollection<IVariable!>! FreeVariables()
+ {
+ List<IVariable!> vars = new List<IVariable!>(this.variableBindings.Keys);
+
+ return vars;
+ }
+
+ public override string! ToString()
+ {
+ string! retString = "";
+ retString += "Bindings";
+
+ foreach(IVariable var in this.variableBindings.Keys)
+ {
+ string! toAdd = var.ToString() + " -> " + this.variableBindings[var];
+ retString += toAdd + ",";
+ }
+
+ retString += "\nDependencies";
+ foreach(IVariable var in this.variableDependences.Keys)
+ {
+ string! toAdd = var.ToString() + " -> " + this.variableDependences[var];
+ retString += toAdd + ",";
+ }
+
+ return retString;
+ }
+ }
+
+ public override Element! Top
+ {
+ get
+ {
+ return AbstractElement.Top;
+ }
+ }
+
+ public override Element! Bottom
+ {
+ get
+ {
+ return AbstractElement.Bottom;
+ }
+ }
+
+ public override bool IsTop(Element! e)
+ {
+ assert e is AbstractElement;
+ AbstractElement! absElement = (AbstractElement) e;
+
+ return absElement.IsTop;
+ }
+
+ public override bool IsBottom(Element! e)
+ {
+ assert e is AbstractElement;
+ AbstractElement absElement = (AbstractElement) e;
+ return absElement.IsBottom;
+ }
+
+ /// <summary>
+ /// Perform the pointwise join of the two abstract elements
+ /// </summary>
+ public override Element! NontrivialJoin(Element! a, Element! b)
+ {
+ assert a is AbstractElement;
+ assert b is AbstractElement;
+
+ AbstractElement! left = (AbstractElement!) a;
+ AbstractElement! right = (AbstractElement!) b;
+
+ return AbstractElement.Join(left, right);
+ }
+
+ /// <summary>
+ /// Perform the pointwise meet of two abstract elements
+ /// </summary>
+ public override Element! NontrivialMeet(Element! a, Element!b)
+ {
+ assert a is AbstractElement;
+ assert b is AbstractElement;
+
+ AbstractElement! left = (AbstractElement!) a;
+ AbstractElement! right = (AbstractElement!) b;
+
+ return AbstractElement.Meet(left, right);
+ }
+
+
+ }
+
+ /// <summary>
+ /// A wrapper in order to have the algebraic datatype BindExpr := IExpr | Top
+ /// </summary>
+ abstract class BindExpr
+ {
+ /// <summary>
+ /// True iff this expression is instance of BindExprTop
+ /// </summary>
+ public bool IsTop
+ {
+ get
+ {
+ return this is BindExprTop;
+ }
+ }
+
+ static public BindExpr Top
+ {
+ get
+ {
+ return BindExprTop.UniqueTop;
+ }
+ }
+
+ /// <summary>
+ /// True iff this expression is instance of BindExprBottom
+ /// </summary>
+ public bool IsBottom
+ {
+ get
+ {
+ return this is BindExprBottom;
+ }
+ }
+
+ static public BindExpr Bottom
+ {
+ get
+ {
+ return BindExprBottom.UniqueBottom;
+ }
+ }
+
+ public static BindExpr! Join(BindExpr! left, BindExpr! right)
+ {
+ if(left.IsTop || right.IsTop)
+ {
+ return BindExpr.Top;
+ }
+ else if(left.IsBottom)
+ {
+ return right;
+ }
+ else if(right.IsBottom)
+ {
+ return left;
+ }
+ else if(left.EmbeddedExpr != right.EmbeddedExpr)
+ {
+ return BindExpr.Top;
+ }
+ else // left.EmbeddedExpr == right.EmbeddedExpr
+ {
+ return left;
+ }
+ }
+
+ public static BindExpr! Meet(BindExpr! left, BindExpr! right)
+ {
+ if(left.IsTop)
+ {
+ return right;
+ }
+ else if(right.IsTop)
+ {
+ return right;
+ }
+ else if(left.IsBottom || right.IsBottom)
+ {
+ return BindExpr.Bottom;
+ }
+ else if(left.EmbeddedExpr != right.EmbeddedExpr)
+ {
+ return BindExpr.Bottom;
+ }
+ else // left.EmbeddedExpr == right.EmbeddedExpr
+ {
+ return left;
+ }
+ }
+
+ abstract public IExpr! EmbeddedExpr
+ {
+ get;
+ }
+
+ }
+
+ /// <summary>
+ /// A wrapper for an integer
+ /// </summary>
+ class Expr : BindExpr
+ {
+ private IExpr! exp;
+
+ public Expr(IExpr! exp)
+ {
+ this.exp = exp;
+ }
+
+ override public IExpr! EmbeddedExpr
+ {
+ get
+ {
+ return this.exp;
+ }
+ }
+
+ public override string! ToString()
+ {
+ return this.exp.ToString();
+ }
+ }
+
+ /// <summary>
+ /// The dynamic expression
+ /// </summary>
+ class BindExprTop : BindExpr
+ {
+ private BindExprTop top = new BindExprTop();
+ static public BindExprTop! UniqueTop
+ {
+ get
+ {
+ return this.top;
+ }
+ }
+
+ private BindExprTop() {}
+
+ override public IExpr! EmbeddedExpr
+ {
+ get
+ {
+ assert false; // If we get there, we have an error
+ }
+ }
+
+ public override string! ToString()
+ {
+ return "<dynamic expression>";
+ }
+ }
+
+ /// <summary>
+ /// The unreachable expression
+ /// </summary>
+ class BindExprBottom : BindExpr
+ {
+ private BindExprBottom! bottom = new BindExprBottom();
+ static public BindExprBottom! UniqueBottom
+ {
+ get
+ {
+ return this.bottom;
+ }
+ }
+
+ private BindExprBottom() {}
+
+ override public IExpr! EmbeddedExpr
+ {
+ get
+ {
+ assert false;
+ }
+ }
+
+ public override string! ToString()
+ {
+ return "<unreachable expression>";
+ }
+ }
+
+} // end namespace Microsoft.AbstractInterpretationFramework
+*/ \ No newline at end of file
diff --git a/Source/AIFramework/VariableMap/DynamicTypeLattice.ssc b/Source/AIFramework/VariableMap/DynamicTypeLattice.ssc
new file mode 100644
index 00000000..b9d1a7a4
--- /dev/null
+++ b/Source/AIFramework/VariableMap/DynamicTypeLattice.ssc
@@ -0,0 +1,475 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using System.Collections;
+ using System.Diagnostics;
+ using System.Compiler.Analysis;
+ using Microsoft.SpecSharp.Collections;
+ using Microsoft.Contracts;
+
+ /// <summary>
+ /// Represents information about the dynamic type of a variable. In particular, for a
+ /// variable "v", represents either Bottom, "typeof(v)==T" for some type T, or a set
+ /// of constraints "typeof(v) subtype of T_i for some number of T_i's.
+ /// </summary>
+ public class DynamicTypeLattice : MicroLattice
+ {
+ enum What { Bottom, Exact, Bounds }
+
+ private class Elt : Element {
+ // Representation:
+ // - Bottom is represented by: what==What.Bottom
+ // - An exact type T is represented by: what==What.Exact && ty==T
+ // - A set of type constraints T0, T1, T2, ..., T{n-1} is represented by:
+ // -- if n==0: what==What.Bounds && ty==null && manyBounds==null
+ // -- if n==1: what==What.Bounds && ty==T0 && manyBounds==null
+ // -- if n>=2: what==What.Bounds && ty==null &&
+ // manyBounds!=null && manyBounds.Length==n &&
+ // manyBounds[0]==T0 && manyBounds[1]==T1 && ... && manyBounds[n-1]==T{n-1}
+ // The reason for keeping the one-and-only bound in "ty" in case n==1 is to try
+ // to prevent the need for allocating a whole array of bounds, since 1 bound is
+ // bound to be common.
+ // In the representation, there are no redundant bounds in manyBounds.
+ // It is assumed that the types can can occur as exact bounds form a single-inheritance
+ // hierarchy. That is, if T0 and T1 are types that can occur as exact types, then
+ // there is no v such that typeof(v) is a subtype of both T0 and T1, unless T0 and T1 are
+ // the same type.
+ public readonly What what;
+ public readonly IExpr ty;
+ [Rep]
+ public readonly IExpr[] manyBounds;
+ invariant what == What.Bottom ==> ty == null && manyBounds == null;
+ invariant manyBounds != null ==> what == What.Bounds;
+ invariant manyBounds != null ==> forall{int i in (0:manyBounds.Length); manyBounds[i] != null};
+
+ public Elt(What what, IExpr ty)
+ requires what == What.Bottom ==> ty == null;
+ requires what == What.Exact ==> ty != null;
+ {
+ this.what = what;
+ this.ty = ty;
+ this.manyBounds = null;
+ }
+
+ public Elt(IExpr[]! bounds)
+ requires forall{int i in (0:bounds.Length); bounds[i] != null};
+ {
+ this.what = What.Bounds;
+ if (bounds.Length == 0) {
+ this.ty = null;
+ this.manyBounds = null;
+ } else if (bounds.Length == 1) {
+ this.ty = bounds[0];
+ this.manyBounds = null;
+ } else {
+ this.ty = null;
+ this.manyBounds = bounds;
+ }
+ }
+
+ /// <summary>
+ /// Constructs an Elt with "n" bounds, namely the n non-null values of the "bounds" list.
+ /// </summary>
+ [NotDelayed]
+ public Elt(ArrayList /*IExpr*/! bounds, int n)
+ requires 0 <= n && n <= bounds.Count;
+ {
+ this.what = What.Bounds;
+ if (n > 1) {
+ this.manyBounds = new IExpr[n];
+ }
+ int k = 0;
+ foreach (IExpr bound in bounds) {
+ if (bound != null) {
+ assert k != n;
+ if (n == 1) {
+ assert this.ty == null;
+ this.ty = bound;
+ } else {
+ assume manyBounds != null;
+ manyBounds[k] = bound;
+ }
+ k++;
+ }
+ }
+ assert k == n;
+ }
+
+ public int BoundsCount
+ {
+ get
+ ensures 0 <= result;
+ {
+ if (manyBounds != null) {
+ return manyBounds.Length;
+ } else if (ty != null) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override System.Collections.Generic.ICollection<IVariable!>! FreeVariables()
+ {
+ return (!) (new System.Collections.Generic.List<IVariable!>()).AsReadOnly();
+ }
+
+ public override Element! Clone()
+ {
+ if (this.manyBounds != null)
+ return new Elt(this.manyBounds);
+ else
+ return new Elt(this.what, this.ty);
+ }
+ }
+
+ readonly ITypeExprFactory! factory;
+ readonly IPropExprFactory! propFactory;
+
+ public DynamicTypeLattice(ITypeExprFactory! factory, IPropExprFactory! propFactory)
+ {
+ this.factory = factory;
+ this.propFactory = propFactory;
+ // base();
+ }
+
+ public override Element! Top
+ {
+ get { return new Elt(What.Bounds, null); }
+ }
+
+ public override Element! Bottom
+ {
+ get { return new Elt(What.Bottom, null); }
+ }
+
+ public override bool IsTop (Element! element)
+ {
+ Elt e = (Elt)element;
+ return e.what == What.Bounds && e.ty == null && e.manyBounds == null;
+ }
+
+ public override bool IsBottom(Element! element)
+ {
+ Elt e = (Elt)element;
+ return e.what == What.Bottom;
+ }
+
+ public override Element! NontrivialJoin(Element! first, Element! second)
+ {
+ Elt a = (Elt)first;
+ Elt b = (Elt)second;
+ assert a.what != What.Bottom && b.what != What.Bottom;
+ if (a.what == What.Exact && b.what == What.Exact) {
+ assert a.ty != null && b.ty != null;
+ if (factory.IsTypeEqual(a.ty, b.ty)) {
+ return a;
+ } else {
+ return new Elt(What.Bounds, factory.JoinTypes(a.ty, b.ty));
+ }
+ }
+
+ // The result is going to be a Bounds, since at least one of the operands is a Bounds.
+ assert 1 <= a.BoundsCount && 1 <= b.BoundsCount; // a preconditions is that neither operand is Top
+ int n = a.BoundsCount + b.BoundsCount;
+
+ // Special case: a and b each has exactly one bound
+ if (n == 2) {
+ assert a.ty != null && b.ty != null;
+ IExpr! join = factory.JoinTypes(a.ty, b.ty);
+ if (join == a.ty && a.what == What.Bounds) {
+ return a;
+ } else if (join == b.ty && b.what == What.Bounds) {
+ return b;
+ } else {
+ return new Elt(What.Bounds, join);
+ }
+ }
+
+ // General case
+ ArrayList /*IExpr*/ allBounds = new ArrayList /*IExpr*/ (n); // final size
+ ArrayList /*IExpr!*/ result = new ArrayList /*IExpr!*/ (n); // a guess at the size, but could be as big as size(a)*size(b)
+ if (a.ty != null) {
+ allBounds.Add(a.ty);
+ } else {
+ allBounds.AddRange((!)a.manyBounds);
+ }
+ int bStart = allBounds.Count;
+ if (b.ty != null) {
+ allBounds.Add(b.ty);
+ } else {
+ allBounds.AddRange((!)b.manyBounds);
+ }
+ // compute the join of each pair, putting non-redundant joins into "result"
+ for (int i = 0; i < bStart; i++) {
+ IExpr! aBound = (IExpr!)allBounds[i];
+ for (int j = bStart; j < allBounds.Count; j++) {
+ IExpr! bBound = (IExpr!)allBounds[j];
+
+ IExpr! join = factory.JoinTypes(aBound, bBound);
+
+ int k = 0;
+ while (k < result.Count) {
+ IExpr! r = (IExpr!)result[k];
+ if (factory.IsSubType(join, r)) {
+ // "join" is more restrictive than a bound already placed in "result",
+ // so toss out "join" and compute the join of the next pair
+ goto NEXT_PAIR;
+ } else if (factory.IsSubType(r, join)) {
+ // "join" is less restrictive than a bound already placed in "result",
+ // so toss out that old bound
+ result.RemoveAt(k);
+ } else {
+ k++;
+ }
+ }
+ result.Add(join);
+ NEXT_PAIR: {}
+ }
+ }
+ return new Elt(result, result.Count);
+ }
+
+
+ public override Element! NontrivialMeet(Element! first, Element! second)
+ {
+ Elt a = (Elt)first;
+ Elt b = (Elt)second;
+ assert a.what != What.Bottom && b.what != What.Bottom;
+
+ if (a.what == What.Exact && b.what == What.Exact) {
+ assert a.ty != null && b.ty != null;
+ if (factory.IsTypeEqual(a.ty, b.ty)) {
+ return a;
+ } else {
+ return Bottom;
+ }
+
+ } else if (a.what == What.Exact || b.what == What.Exact) {
+ // One is Bounds, the other Exact. Make b be the Bounds one.
+ if (a.what == What.Bounds) {
+ Elt tmp = a;
+ a = b;
+ b = tmp;
+ }
+ assert a.what == What.Exact && b.what == What.Bounds;
+ // Check the exact type against all bounds. If the exact type is more restrictive
+ // than all bounds, then return it. If some bound is not met by the exact type, return
+ // bottom.
+ assert a.ty != null;
+ if (b.ty != null && !factory.IsSubType(a.ty, b.ty)) {
+ return Bottom;
+ }
+ if (b.manyBounds != null) {
+ foreach (IExpr! bound in b.manyBounds) {
+ if (!factory.IsSubType(a.ty, bound)) {
+ return Bottom;
+ }
+ }
+ }
+ return a;
+ }
+
+ else {
+ // Both operands are Bounds.
+ assert a.what == What.Bounds && b.what == What.Bounds;
+
+ // Take all the bounds, but prune those bounds that follow from others.
+ assert 1 <= a.BoundsCount && 1 <= b.BoundsCount; // a preconditions is that neither operand is Top
+ int n = a.BoundsCount + b.BoundsCount;
+ // Special case: a and b each has exactly one bound
+ if (n == 2) {
+ assert a.ty != null && b.ty != null;
+ if (factory.IsSubType(a.ty, b.ty)) {
+ // a is more restrictive
+ return a;
+ } else if (factory.IsSubType(b.ty, a.ty)) {
+ // b is more restrictive
+ return b;
+ } else {
+ IExpr[]! bounds = new IExpr[2];
+ bounds[0] = a.ty;
+ bounds[1] = b.ty;
+ return new Elt(bounds);
+ }
+ }
+
+ // General case
+ ArrayList /*IExpr*/ allBounds = new ArrayList /*IExpr*/ (n);
+ if (a.ty != null) {
+ allBounds.Add(a.ty);
+ } else {
+ allBounds.AddRange((!)a.manyBounds);
+ }
+ int bStart = allBounds.Count;
+ if (b.ty != null) {
+ allBounds.Add(b.ty);
+ } else {
+ allBounds.AddRange((!)b.manyBounds);
+ }
+ for (int i = 0; i < bStart; i++) {
+ IExpr! aBound = (IExpr!)allBounds[i];
+ for (int j = bStart; j < allBounds.Count; j++) {
+ IExpr bBound = (IExpr!)allBounds[j];
+ if (bBound == null) {
+ continue;
+ } else if (factory.IsSubType(aBound, bBound)) {
+ // a is more restrictive, so blot out the b bound
+ allBounds[j] = null;
+ n--;
+ } else if (factory.IsSubType(bBound, aBound)) {
+ // b is more restrictive, so blot out the a bound
+ allBounds[i] = null;
+ n--;
+ goto CONTINUE_OUTER_LOOP;
+ }
+ }
+ CONTINUE_OUTER_LOOP: {}
+ }
+ assert 1 <= n;
+ return new Elt(allBounds, n);
+ }
+ }
+
+ public override Element! Widen (Element! first, Element! second)
+ {
+ return Join(first,second);
+ }
+
+ protected override bool AtMost (Element! first, Element! second) // this <= that
+ {
+ Elt! a = (Elt!)first;
+ Elt! b = (Elt!)second;
+ assert a.what != What.Bottom && b.what != What.Bottom;
+
+ if (a.what == What.Exact && b.what == What.Exact) {
+ assert a.ty != null && b.ty != null;
+ return factory.IsTypeEqual(a.ty, b.ty);
+ } else if (b.what == What.Exact) {
+ return false;
+ } else if (a.what == What.Exact) {
+ assert a.ty != null;
+ if (b.ty != null) {
+ return factory.IsSubType(a.ty, b.ty);
+ } else {
+ return forall{IExpr! bound in b.manyBounds; factory.IsSubType(a.ty, bound)};
+ }
+ } else {
+ assert a.what == What.Bounds && b.what == What.Bounds;
+ assert a.ty != null || a.manyBounds != null; // a precondition is that a is not Top
+ assert b.ty != null || b.manyBounds != null; // a precondition is that b is not Top
+ // Return true iff: for each constraint in b, there is a stricter constraint in a.
+ if (a.ty != null && b.ty != null) {
+ return factory.IsSubType(a.ty, b.ty);
+ } else if (a.ty != null) {
+ return forall{IExpr! bound in b.manyBounds; factory.IsSubType(a.ty, bound)};
+ } else if (b.ty != null) {
+ return exists{IExpr! bound in a.manyBounds; factory.IsSubType(bound, b.ty)};
+ } else {
+ return forall{IExpr! bBound in b.manyBounds;
+ exists{IExpr! aBound in a.manyBounds; factory.IsSubType(aBound, bBound)}};
+ }
+ }
+ }
+
+ public override IExpr! ToPredicate(IVariable! var, Element! element) {
+ Elt e = (Elt)element;
+ switch (e.what) {
+ case What.Bottom:
+ return propFactory.False;
+ case What.Exact:
+ return factory.IsExactlyA(var, (!)e.ty);
+ case What.Bounds:
+ if (e.ty == null && e.manyBounds == null) {
+ return propFactory.True;
+ } else if (e.ty != null) {
+ return factory.IsA(var, e.ty);
+ } else {
+ IExpr! p = factory.IsA(var, (IExpr!)((!)e.manyBounds)[0]);
+ for (int i = 1; i < e.manyBounds.Length; i++) {
+ p = propFactory.And(p, factory.IsA(var, (IExpr!)e.manyBounds[i]));
+ }
+ return p;
+ }
+ default:
+ assert false;
+ throw new System.Exception();
+ }
+ }
+
+ public override IExpr GetFoldExpr(Element! e) {
+ // cannot fold into an expression that can be substituted for the variable
+ return null;
+ }
+
+ public override bool Understands(IFunctionSymbol! f, IList/*<IExpr!>*/! args) {
+ bool isEq = f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq);
+ if (isEq || f.Equals(Microsoft.AbstractInterpretationFramework.Value.Subtype)) {
+ assert args.Count == 2;
+ IExpr! arg0 = (IExpr!)args[0];
+ IExpr! arg1 = (IExpr!)args[1];
+
+ // Look for $typeof(var) == t or t == $typeof(var) or $typeof(var) <: t
+ if (isEq && factory.IsTypeConstant(arg0)) {
+ // swap the arguments
+ IExpr! tmp = arg0;
+ arg0 = arg1;
+ arg1 = tmp;
+ } else if (!factory.IsTypeConstant(arg1)) {
+ return false;
+ }
+ IFunApp typeofExpr = arg0 as IFunApp;
+ if (typeofExpr != null &&
+ typeofExpr.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Typeof)) {
+ assert typeofExpr.Arguments.Count == 1;
+ if (typeofExpr.Arguments[0] is IVariable) {
+ // we have a match
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public override Element! EvaluatePredicate(IExpr! e) {
+ IFunApp nary = e as IFunApp;
+ if (nary != null) {
+
+ bool isEq = nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq);
+ if (isEq || nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Subtype)) {
+ IList/*<IExpr!>*/! args = nary.Arguments;
+ assert args.Count == 2;
+ IExpr! arg0 = (IExpr!)args[0];
+ IExpr! arg1 = (IExpr!)args[1];
+
+ // Look for $typeof(var) == t or t == $typeof(var) or $typeof(var) <: t
+ if (isEq && factory.IsTypeConstant(arg0)) {
+ // swap the arguments
+ IExpr! tmp = arg0;
+ arg0 = arg1;
+ arg1 = tmp;
+ } else if (!factory.IsTypeConstant(arg1)) {
+ return Top;
+ }
+ IFunApp typeofExpr = arg0 as IFunApp;
+ if (typeofExpr != null &&
+ typeofExpr.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Typeof)) {
+ assert typeofExpr.Arguments.Count == 1;
+ if (typeofExpr.Arguments[0] is IVariable) {
+ // we have a match
+ return new Elt(isEq ? What.Exact : What.Bounds, arg1);
+ }
+ }
+ }
+ }
+ return Top;
+ }
+
+ }
+}
diff --git a/Source/AIFramework/VariableMap/Intervals.ssc b/Source/AIFramework/VariableMap/Intervals.ssc
new file mode 100644
index 00000000..721b175d
--- /dev/null
+++ b/Source/AIFramework/VariableMap/Intervals.ssc
@@ -0,0 +1,790 @@
+//-----------------------------------------------------------------------------
+//
+// 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;
+ }
+ }
+
+ /// <summary>
+ /// The paramter is the top?
+ /// </summary>
+ public override bool IsTop(Element! element)
+ {
+ IntervalElement interval = (IntervalElement) element;
+
+ return interval.IsTop();
+ }
+
+ /// <summary>
+ /// The parameter is the bottom?
+ /// </summary>
+ public override bool IsBottom(Element! element)
+ {
+ IntervalElement interval = (IntervalElement) element;
+
+ return interval.IsBottom();
+ }
+
+ /// <summary>
+ /// The classic, pointwise, join of intervals
+ /// </summary>
+ 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;
+ }
+
+ /// <summary>
+ /// The classic, pointwise, meet of intervals
+ /// </summary>
+ 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);
+ }
+
+
+ /// <summary>
+ /// 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
+ /// </summary>
+ 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;
+ }
+
+
+ /// <summary>
+ /// Return true iff the interval left is containted in right
+ /// </summary>
+ 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;
+ }
+
+ /// <summary>
+ /// Return just null
+ /// </summary>
+ public override IExpr GetFoldExpr(Element! element)
+ {
+ return null;
+ }
+
+ /// <summary>
+ /// return a predicate inf "\leq x and x "\leq" sup (if inf [or sup] is not oo)
+ /// </summary>
+ 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;
+ }
+
+ /// <summary>
+ /// For the moment consider just equalities. Other case must be considered
+ /// </summary>
+ public override bool Understands(IFunctionSymbol! f, IList /*<IExpr*/ ! args)
+ {
+ return f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq);
+ }
+
+
+ /// <summary>
+ /// Evaluate the predicate passed as input according the semantics of intervals
+ /// </summary>
+ public override Element! EvaluatePredicate(IExpr! pred)
+ {
+ return this.EvaluatePredicateWithState(pred, null);
+ }
+
+ /// <summary>
+ /// 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
+ /// </summary>
+ 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;
+ }
+
+ /// <summary>
+ /// Evaluate the expression (that is assured to be an arithmetic expression, in the state passed as a parameter
+ /// </summary>
+ 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;
+ }
+
+ /// <summary>
+ /// Inner class standing for an interval on integers, possibly unbounded
+ /// </summary>
+ 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][Reads(ReadsAttribute.Reads.Owned)]
+ public override System.Collections.Generic.ICollection<IVariable!>! FreeVariables()
+ {
+ return (!) (new System.Collections.Generic.List<IVariable!>()).AsReadOnly();
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ 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][Reads(ReadsAttribute.Reads.Owned)]
+ 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][Reads(ReadsAttribute.Reads.Owned)]
+ 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][Reads(ReadsAttribute.Reads.Owned)]
+ 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;
+ }
+ }
+}
diff --git a/Source/AIFramework/VariableMap/MicroLattice.ssc b/Source/AIFramework/VariableMap/MicroLattice.ssc
new file mode 100644
index 00000000..d38a37c0
--- /dev/null
+++ b/Source/AIFramework/VariableMap/MicroLattice.ssc
@@ -0,0 +1,79 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using Microsoft.Contracts;
+ using System.Collections;
+ using System.Diagnostics;
+ using System.Compiler;
+ using Microsoft.AbstractInterpretationFramework.Collections;
+
+ /// <summary>
+ /// Interface for a lattice that works on a per-variable basis.
+ /// </summary>
+ public abstract class MicroLattice : MathematicalLattice
+ {
+ /// <summary>
+ /// Returns the predicate on the given variable for the given
+ /// lattice element.
+ /// </summary>
+ public abstract IExpr! ToPredicate(IVariable! v, Element! e);
+ /* requires !e.IsBottom && !e.IsTop; */
+
+ /// <summary>
+ /// Allows the lattice to specify whether it understands a particular function symbol.
+ ///
+ /// The lattice is always allowed to "true" even when it really can't do anything with
+ /// such functions; however, it is advantageous to say "false" when possible to avoid
+ /// being called to do certain things.
+ ///
+ /// The arguments to a function are provided for context so that the lattice can say
+ /// true or false for the same function symbol in different situations. For example,
+ /// a lattice may understand the multiplication of a variable and a constant but not
+ /// of two variables. The implementation of a lattice should not hold on to the
+ /// arguments.
+ /// </summary>
+ /// <param name="f">The function symbol.</param>
+ /// <param name="args">The argument context.</param>
+ /// <returns>True if it may understand f, false if it does not understand f.</returns>
+ public abstract bool Understands(IFunctionSymbol! f, IList/*<IExpr!>*/! args);
+
+ /// <summary>
+ /// Set this property to true if the implemented MicroLattice can handle basic arithmetic.
+ /// Stated otherwise this property is set to true if the MicroLattice provides a transfer function for a predicate in a given state
+ /// </summary>
+ public virtual bool UnderstandsBasicArithmetics
+ {
+ get { return false; }
+ }
+
+ /// <summary>
+ /// Evaluate the predicate e and a yield the lattice element
+ /// that is implied by it.
+ /// </summary>
+ /// <param name="e">The predicate that is assumed to contain 1 variable.</param>
+ /// <returns>The most precise lattice element that is implied by the predicate.</returns>
+ public abstract Element! EvaluatePredicate(IExpr! e);
+
+ /// <summary>
+ /// Evaluate the predicate e and yield an overapproximation of the predicate under the state that is passed as a parameter
+ /// Note that unless the subclass implement it, the default behavior is to evaluate the predicate stateless, that implies that it
+ /// is evaluated in any possible context, i.e. it is an upper approximation
+ /// </summary>
+ public virtual Element! EvaluatePredicateWithState(IExpr! e, IFunctionalMap state)
+ {
+ return EvaluatePredicate(e);
+ }
+
+ /// <summary>
+ /// Give an expression (often a value) that can be used to substitute for
+ /// the variable.
+ /// </summary>
+ /// <param name="e">A lattice element.</param>
+ /// <returns>The null value if no such expression can be given.</returns>
+ public abstract IExpr GetFoldExpr(Element! e);
+ }
+} \ No newline at end of file
diff --git a/Source/AIFramework/VariableMap/Nullness.ssc b/Source/AIFramework/VariableMap/Nullness.ssc
new file mode 100644
index 00000000..63d637ce
--- /dev/null
+++ b/Source/AIFramework/VariableMap/Nullness.ssc
@@ -0,0 +1,227 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using Microsoft.Contracts;
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using System.Collections;
+ using System.Diagnostics;
+ using System.Compiler.Analysis;
+
+ public class NullnessLattice : MicroLattice
+ {
+ readonly INullnessFactory! factory;
+
+ public NullnessLattice(INullnessFactory! factory) {
+ this.factory = factory;
+ // base();
+ }
+
+ enum Value { Bottom, NotNull, Null, MayBeNull }
+
+ private class Elt : Element
+ {
+ public Value value;
+
+ public Elt (Value v) { this.value = v; }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override System.Collections.Generic.ICollection<IVariable!>! FreeVariables()
+ {
+ return (!) (new System.Collections.Generic.List<IVariable!>()).AsReadOnly();
+ }
+
+ public override Element! Clone()
+ {
+ return new Elt(this.value);
+ }
+ }
+
+
+ public override Element! Top
+ {
+ get { return new Elt(Value.MayBeNull); }
+ }
+
+ public override Element! Bottom
+ {
+ get { return new Elt(Value.Bottom); }
+ }
+
+ public static Element! Null
+ {
+ get { return new Elt(Value.Null); }
+ }
+
+ public static Element! NotNull
+ {
+ get { return new Elt(Value.NotNull); }
+ }
+
+ public override bool IsTop (Element! element)
+ {
+ Elt e = (Elt) element;
+ return e.value == Value.MayBeNull;
+ }
+
+ public override bool IsBottom (Element! element)
+ {
+ Elt e = (Elt) element;
+ return e.value == Value.Bottom;
+ }
+
+ public override Lattice.Element! NontrivialJoin (Element! first, Element! second)
+ {
+ Elt a = (Elt) first;
+ Elt b = (Elt) second;
+ return (a.value == b.value) ? a : (Elt)Top;
+ }
+
+ public override Lattice.Element! NontrivialMeet (Element! first, Element! second)
+ {
+ Elt a = (Elt) first;
+ Elt b = (Elt) second;
+ return (a.value == b.value) ? a : (Elt)Bottom;
+ }
+
+ public override Element! Widen (Element! first, Element! second)
+ {
+ return Join(first,second);
+ }
+
+ protected override bool AtMost (Element! first, Element! second) // this <= that
+ {
+ Elt a = (Elt) first;
+ Elt b = (Elt) second;
+ return a.value == b.value;
+ }
+
+ public override IExpr! ToPredicate(IVariable! var, Element! element) {
+ Elt e = (Elt)element;
+
+ if (e.value == Value.NotNull)
+ {
+ return factory.Neq(var, factory.Null);
+ }
+ if (e.value == Value.Null)
+ {
+ return factory.Eq(var, factory.Null);
+ }
+ assert false;
+ throw new System.Exception();
+ }
+
+ public override IExpr GetFoldExpr(Element! e) {
+ Elt elt = (Elt)e;
+ if (elt.value == Value.Null) {
+ return factory.Null;
+ } else {
+ // can't fold into an expression
+ return null;
+ }
+ }
+
+ public override bool Understands(IFunctionSymbol! f, IList/*<IExpr!>*/! args) {
+ if (f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq) ||
+ f.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) {
+
+ assert args.Count == 2;
+ IExpr! arg0 = (IExpr!)args[0];
+ IExpr! arg1 = (IExpr!)args[1];
+
+ // Look for "x OP null" or "null OP x" where OP is "==" or "!=".
+ if (arg0 is IVariable && arg1 is IFunApp && ((IFunApp)arg1).FunctionSymbol == Ref.Null) {
+ return true;
+ } else if (arg1 is IVariable && arg0 is IFunApp && ((IFunApp)arg0).FunctionSymbol == Ref.Null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public override Element! EvaluatePredicate(IExpr! e) {
+ IFunApp nary = e as IFunApp;
+ if (nary != null) {
+ bool isEq = nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq);
+ if (isEq || nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) {
+ IList/*<IExpr!>*/! args = nary.Arguments;
+ assert args.Count == 2;
+ IExpr! arg0 = (IExpr!)args[0];
+ IExpr! arg1 = (IExpr!)args[1];
+
+ // Look for "x OP null" or "null OP x" where OP is "==" or "!=".
+ IVariable var = null;
+ if (arg0 is IVariable && arg1 is IFunApp && ((IFunApp)arg1).FunctionSymbol == Ref.Null)
+ {
+ var = (IVariable)arg0;
+ }
+ else if (arg1 is IVariable && arg0 is IFunApp && ((IFunApp)arg0).FunctionSymbol == Ref.Null)
+ {
+ var = (IVariable)arg1;
+ }
+
+ if (var != null) // found the pattern
+ {
+ return isEq ? Null:NotNull;
+ }
+ }
+ }
+ return Top;
+ }
+ }
+
+#if false
+
+ public class NullnessMicroLattice : MicroLattice
+ {
+ public override MicroLatticeElement Top { get { return NullnessLatticeElement.Top; } }
+ public override MicroLatticeElement Bottom { get { return NullnessLatticeElement.Bottom; } }
+
+
+ public override MicroLatticeElement EvaluateExpression (Expr e, LookupValue lookup)
+ {
+ if (e is LiteralExpr && ((LiteralExpr)e).Val == null)
+ {
+ return NullnessLatticeElement.Null;
+ }
+ return Top;
+ }
+
+
+ public override MicroLatticeElement EvaluatePredicate (Expr e, LookupValue lookup)
+ {
+ NAryExpr nary = e as NAryExpr;
+ if (nary != null &&
+ (nary.Fun.FunctionName.Equals("==") || nary.Fun.FunctionName.Equals("!=")))
+ {
+ Debug.Assert(nary.Args.Length == 2);
+
+ Expr arg0 = nary.Args[0], arg1 = nary.Args[1];
+ Variable var = null;
+
+ // Look for "x OP null" or "null OP x" where OP is "==" or "!=".
+ if (arg0 is IdentifierExpr && arg1 is LiteralExpr && ((LiteralExpr)arg1).Val == null)
+ {
+ var = ((IdentifierExpr)arg0).Decl;
+ }
+ else if (arg1 is IdentifierExpr && arg0 is LiteralExpr && ((LiteralExpr)arg0).Val == null)
+ {
+ var = ((IdentifierExpr)arg1).Decl;
+ }
+
+ if (var != null) // found the pattern
+ {
+ return nary.Fun.FunctionName.Equals("==") ?
+ NullnessLatticeElement.Null :
+ NullnessLatticeElement.NotNull;
+ }
+ }
+ return Top;
+ }
+ }
+
+#endif
+
+}
diff --git a/Source/AIFramework/VariableMap/VariableMapLattice.ssc b/Source/AIFramework/VariableMap/VariableMapLattice.ssc
new file mode 100644
index 00000000..aa15f1e6
--- /dev/null
+++ b/Source/AIFramework/VariableMap/VariableMapLattice.ssc
@@ -0,0 +1,749 @@
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+namespace Microsoft.AbstractInterpretationFramework
+{
+ using Microsoft.Contracts;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+
+ using Microsoft.AbstractInterpretationFramework;
+ using Microsoft.AbstractInterpretationFramework.Collections;
+
+ using Microsoft.Boogie;
+ using IMutableSet = Microsoft.Boogie.Set;
+ using HashSet = Microsoft.Boogie.Set;
+ using ISet = Microsoft.Boogie.Set;
+
+ /// <summary>
+ /// Creates a lattice that works for several variables given a MicroLattice. Assumes
+ /// if one variable is bottom, then all variables are bottom.
+ /// </summary>
+ public class VariableMapLattice : Lattice
+ {
+ private class Elt : Element
+ {
+ /// <summary>
+ /// IsBottom(e) iff e.constraints == null
+ /// </summary>
+ /*MayBeNull*/
+ private IFunctionalMap constraints; // of type IVariable -> LATTICE_ELEMENT
+ public IFunctionalMap Constraints
+ {
+ get
+ {
+ return this.constraints;
+ }
+ }
+
+ private Elt(bool top) {
+ if (top) {
+ this.constraints = FunctionalHashtable.Empty;
+ } else {
+ this.constraints = null;
+ }
+ }
+
+ public override Element! Clone()
+ {
+ return new Elt(this.constraints);
+ }
+
+ public static Elt! Top = new Elt(true);
+ public static Elt! Bottom = new Elt(false);
+
+ public Elt(IFunctionalMap constraints)
+ {
+ this.constraints = constraints;
+ }
+
+ public bool IsBottom {
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ get {
+ return this.constraints == null;
+ }
+ }
+
+ public int Count { get { return this.constraints == null ? 0 : this.constraints.Count; } }
+
+ public IEnumerable/*<IVariable>*/! Variables {
+ get
+ requires !this.IsBottom;
+ {
+ assume this.constraints != null;
+ return (!) this.constraints.Keys;
+ }
+ }
+
+ public IEnumerable/*<IVariable>*/! SortedVariables(/*maybe null*/ IComparer variableComparer) {
+ if (variableComparer == null) {
+ return Variables;
+ } else {
+ ArrayList /*IVariable*/ vars = new ArrayList /*IVariable*/ (Count);
+ foreach (IVariable variable in Variables) {
+ vars.Add(variable);
+ }
+ vars.Sort(variableComparer);
+ return vars;
+ }
+ }
+
+ public Element Lookup(IVariable v)
+ {
+ if ((v == null) || (this.constraints == null)) { return null; }
+ return (Element)this.constraints[v];
+ }
+
+ public Element this [IVariable! key] {
+ get
+ requires !this.IsBottom;
+ {
+ assume this.constraints != null;
+ return (Element)constraints[key];
+ }
+ }
+
+ /// <summary>
+ /// Add a new entry in the functional map: var --> value.
+ /// If the variable is already there, throws an exception
+ /// </summary>
+ public Elt! Add(IVariable! var, Element! value, MicroLattice! microLattice)
+ requires !this.IsBottom;
+ {
+ assume this.constraints != null;
+ assert !this.constraints.Contains(var);
+
+ if (microLattice.IsBottom(value)) { return Bottom; }
+ if (microLattice.IsTop(value)) { return this.Remove(var, microLattice); }
+
+ return new Elt(this.constraints.Add(var, value));
+ }
+
+ /// <summary>
+ /// Set the value of the variable in the functional map
+ /// If the variable is not already there, throws an exception
+ /// </summary>
+ public Elt! Set(IVariable! var, Element! value, MicroLattice! microLattice)
+ {
+ if(microLattice.IsBottom(value)) { return Bottom; }
+ if(microLattice.IsTop(value)) { return this.Remove(var, microLattice); }
+
+ assume this.constraints != null;
+ assert this.constraints.Contains(var);
+
+ // this.constraints[var] = value;
+ IFunctionalMap newMap = this.constraints.Set(var, value);
+
+ return new Elt(newMap);
+ }
+
+ public Elt! Remove(IVariable! var, MicroLattice microLattice)
+ {
+ if (this.IsBottom) { return this; }
+ assume this.constraints != null;
+ return new Elt(this.constraints.Remove(var));
+ }
+
+ public Elt! Rename(IVariable! oldName, IVariable! newName, MicroLattice! microLattice)
+ requires !this.IsBottom;
+ {
+ Element value = this[oldName];
+ if (value == null) { return this; } // 'oldName' isn't in the map, so neither will be 'newName'
+ assume this.constraints != null;
+ IFunctionalMap newMap = this.constraints.Remove(oldName);
+ newMap = newMap.Add(newName, value);
+ return new Elt(newMap);
+ }
+
+ [Pure][Reads(ReadsAttribute.Reads.Owned)]
+ public override ICollection<IVariable!>! FreeVariables()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ } // class
+
+ private readonly MicroLattice! microLattice;
+
+ private readonly IPropExprFactory! propExprFactory;
+
+ private readonly /*maybe null*/IComparer variableComparer;
+
+ public VariableMapLattice(IPropExprFactory! propExprFactory, IValueExprFactory! valueExprFactory, MicroLattice! microLattice, /*maybe null*/IComparer variableComparer)
+ : base(valueExprFactory)
+ {
+ this.propExprFactory = propExprFactory;
+ this.microLattice = microLattice;
+ this.variableComparer = variableComparer;
+ // base(valueExprFactory);
+ }
+
+ protected override object! UniqueId { get { return this.microLattice.GetType(); } }
+
+ public override Element! Top { get { return Elt.Top; } }
+
+ public override Element! Bottom { get { return Elt.Bottom; } }
+
+ public override bool IsTop(Element! element)
+ {
+ Elt e = (Elt)element;
+ return !e.IsBottom && e.Count == 0;
+ }
+
+ public override bool IsBottom(Element! element)
+ {
+ return ((Elt)element).IsBottom;
+ }
+
+ protected override bool AtMost(Element! first, Element! second)
+ {
+ Elt a = (Elt)first;
+ Elt b = (Elt)second;
+
+ // return true iff every constraint in "this" is no weaker than the corresponding
+ // constraint in "that" and there are no additional constraints in "that"
+ foreach (IVariable! var in a.Variables)
+ {
+ Element thisValue = (!)a[var];
+
+ Element thatValue = b[var];
+ if (thatValue == null) { continue; } // it's okay for "a" to know something "b" doesn't
+
+ if (this.microLattice.LowerThan(thisValue, thatValue)) { continue; } // constraint for "var" satisfies AtMost relation
+
+ return false;
+ }
+ foreach (IVariable! var in b.Variables)
+ {
+ if (a.Lookup(var) != null) { continue; } // we checked this case in the loop above
+
+ Element thatValue = (!)b[var];
+ if (this.microLattice.IsTop(thatValue)) { continue; } // this is a trivial constraint
+
+ return false;
+ }
+ return true;
+ }
+
+ private Elt! AddConstraint(Element! element, IVariable! var, /*MicroLattice*/Element! newValue)
+ {
+ Elt e = (Elt)element;
+
+ if (!e.IsBottom && !this.microLattice.IsBottom(newValue)) // if we're not at bottom
+ {
+ /*MicroLattice*/Element currentValue = e[var];
+
+ if (currentValue == null)
+ {
+ // No information currently, so we just add the new info.
+ return e.Add(var, newValue, this.microLattice);
+ }
+ else
+ {
+ // Otherwise, take the meet of the new and current info.
+ //return e.Add(var, this.microLattice.Meet(currentValue, newValue), this.microLattice);
+ return e.Set(var, this.microLattice.Meet(currentValue, newValue), this.microLattice);
+ }
+ }
+ return e;
+ }
+
+ public override string! ToString(Element! element)
+ {
+ Elt e = (Elt)element;
+
+ if (IsTop(e)) { return "<top>"; }
+ if (IsBottom(e)) { return "<bottom>"; }
+
+ int k = 0;
+ System.Text.StringBuilder buffer = new System.Text.StringBuilder();
+ foreach (IVariable! key in e.SortedVariables(variableComparer))
+ {
+ if (k++ > 0) { buffer.Append("; "); }
+ buffer.AppendFormat("{0} = {1}", key, e[key]);
+ }
+ return buffer.ToString();
+ }
+
+ public override Element! NontrivialJoin(Element! first, Element! second)
+ {
+ Elt a = (Elt)first;
+ Elt b = (Elt)second;
+
+ IFunctionalMap newMap = FunctionalHashtable.Empty;
+ foreach (IVariable! key in a.Variables)
+ {
+ Element aValue = a[key];
+ Element bValue = b[key];
+
+ if (aValue != null && bValue != null)
+ {
+ // Keep only the variables known to both elements.
+ Element newValue = this.microLattice.Join(aValue, bValue);
+ newMap = newMap.Add(key, newValue);
+ }
+ }
+ Elt! join = new Elt(newMap);
+
+ // System.Console.WriteLine("{0} join {1} = {2} ", this.ToString(a), ToString(b), ToString(join));
+
+ return join;
+ }
+
+ public override Element! NontrivialMeet(Element! first, Element! second)
+ {
+ Elt a = (Elt)first;
+ Elt b = (Elt)second;
+
+ IFunctionalMap newMap = FunctionalHashtable.Empty;
+ foreach (IVariable! key in a.Variables)
+ {
+ Element! aValue = (!) a[key];
+ Element bValue = b[key];
+
+ Element newValue =
+ bValue == null ? aValue :
+ this.microLattice.Meet(aValue, bValue);
+
+ newMap = newMap.Add(key, newValue);
+ }
+ foreach (IVariable! key in b.Variables)
+ {
+ Element aValue = a[key];
+ Element bValue = b[key]; Debug.Assert(bValue != null);
+
+ if (aValue == null)
+ {
+ // It's a variable we didn't cover in the last loop.
+ newMap = newMap.Add(key, bValue);
+ }
+ }
+ return new Elt(newMap);
+ }
+
+ /// <summary>
+ /// Perform the pointwise widening of the elements in the map
+ /// </summary>
+ public override Element! Widen (Element! first, Element! second)
+ {
+ Elt a = (Elt)first;
+ Elt b = (Elt)second;
+
+ // Note we have to add those cases as we do not have a "NonTrivialWiden" method
+ if(a.IsBottom)
+ return new Elt(b.Constraints);
+ if(b.IsBottom)
+ return new Elt(a.Constraints);
+
+ IFunctionalMap newMap = FunctionalHashtable.Empty;
+ foreach (IVariable! key in a.Variables)
+ {
+ Element aValue = a[key];
+ Element bValue = b[key];
+
+ if (aValue != null && bValue != null)
+ {
+ // Keep only the variables known to both elements.
+ Element newValue = this.microLattice.Widen(aValue, bValue);
+ newMap = newMap.Add(key, newValue);
+ }
+ }
+ Element! widen= new Elt(newMap);
+
+ // System.Console.WriteLine("{0} widen {1} = {2} ", this.ToString(a), ToString(b), ToString(widen));
+
+ return widen;
+ }
+
+ internal static ISet/*<IVariable!>*/! VariablesInExpression(IExpr! e, ISet/*<IVariable!>*/! ignoreVars)
+ {
+ HashSet s = new HashSet();
+
+ IFunApp f = e as IFunApp;
+ IFunction lambda = e as IFunction;
+
+ if (e is IVariable)
+ {
+ if (!ignoreVars.Contains(e))
+ s.Add(e);
+ }
+ else if (f != null) // e is IFunApp
+ {
+ foreach (IExpr! arg in f.Arguments)
+ {
+ s.AddAll(VariablesInExpression(arg, ignoreVars));
+ }
+ }
+ else if (lambda != null)
+ {
+ IMutableSet x = new HashSet(1);
+ x.Add(lambda.Param);
+
+ // Ignore the bound variable
+ s.AddAll(VariablesInExpression(lambda.Body, (!) Set.Union(ignoreVars, x)));
+ }
+ else
+ {
+ Debug.Assert(false, "case not handled: " + e);
+ }
+ return s;
+ }
+
+
+ private static ArrayList/*<IExpr>*/! FindConjuncts(IExpr e)
+ {
+ ArrayList result = new ArrayList();
+
+ IFunApp f = e as IFunApp;
+ if (f != null)
+ {
+ if (f.FunctionSymbol.Equals(Prop.And))
+ {
+ foreach (IExpr arg in f.Arguments)
+ {
+ result.AddRange(FindConjuncts(arg));
+ }
+ }
+ else if (f.FunctionSymbol.Equals(Prop.Or)
+ || f.FunctionSymbol.Equals(Prop.Implies))
+ {
+ // Do nothing.
+ }
+ else
+ {
+ result.Add(e);
+ }
+ }
+ else
+ {
+ result.Add(e);
+ }
+
+ return result;
+ }
+
+ private static bool IsSimpleEquality(IExpr expr, out IVariable left, out IVariable right)
+ ensures result ==> left != null && right != null;
+ {
+ left = null;
+ right = null;
+
+ // See if we have an equality
+ IFunApp nary = expr as IFunApp;
+ if (nary == null || !nary.FunctionSymbol.Equals(Value.Eq)) { return false; }
+
+ // See if it is an equality of two variables
+ IVariable idLeft = nary.Arguments[0] as IVariable;
+ IVariable idRight = nary.Arguments[1] as IVariable;
+ if (idLeft == null || idRight == null) { return false; }
+
+ left = idLeft;
+ right = idRight;
+ return true;
+ }
+
+ /// <summary>
+ /// Returns true iff the expression is in the form var == arithmeticExpr
+ /// </summary>
+ private static bool IsArithmeticExpr(IExpr! expr)
+ {
+ // System.Console.WriteLine("\t\tIsArithmetic called with {0} of type {1}", expr, expr.GetType().ToString());
+
+ if(expr is IVariable) // expr is a variable
+ return true;
+ else if(expr is IFunApp) // may be ==, +, -, /, % or an integer
+ {
+ IFunApp fun = (IFunApp) expr;
+
+ if(fun.FunctionSymbol is IntSymbol) // it is an integer
+ return true;
+ else if(fun.FunctionSymbol.Equals(Int.Negate)) // it is an unary minus
+ return IsArithmeticExpr((IExpr!) fun.Arguments[0]);
+ else if(fun.Arguments.Count != 2) // A function of two or more operands is not arithmetic
+ return false;
+ else
+ {
+ IExpr! left = (IExpr!) fun.Arguments[0];
+ IExpr! right = (IExpr!) fun.Arguments[1];
+
+ if(!(left is IVariable || right is IVariable)) // At least one of the two operands must be a variable
+ return false;
+
+ if(fun.FunctionSymbol.Equals(Value.Eq)
+ || fun.FunctionSymbol.Equals(Int.Add)
+ || fun.FunctionSymbol.Equals(Int.Sub)
+ || fun.FunctionSymbol.Equals(Int.Mul)
+ || fun.FunctionSymbol.Equals(Int.Div)
+ || fun.FunctionSymbol.Equals(Int.Mod))
+ return IsArithmeticExpr(left) && IsArithmeticExpr(right);
+ else
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public override IExpr! ToPredicate(Element! element)
+ {
+ if (IsTop(element)) { return propExprFactory.True; }
+ if (IsBottom(element)) { return propExprFactory.False; }
+
+ Elt e = (Elt)element;
+ IExpr truth = propExprFactory.True;
+ IExpr result = truth;
+
+ foreach (IVariable! variable in e.SortedVariables(variableComparer))
+ {
+ Element value = (Element)e[variable];
+
+ if (value == null || this.microLattice.IsTop(value)) { continue; } // Skip variables about which we know nothing.
+ if (this.microLattice.IsBottom(value)) { return propExprFactory.False; }
+
+ IExpr conjunct = this.microLattice.ToPredicate(variable, value);
+
+ result = (result == truth) ? (IExpr)conjunct : (IExpr)propExprFactory.And(result, conjunct);
+ }
+ return result;
+ }
+
+
+ public override Element! Eliminate(Element! element, IVariable! variable)
+ {
+ return ((Elt!)element).Remove(variable, this.microLattice);
+ }
+
+ private delegate IExpr! OnUnableToInline(IVariable! var);
+ private IExpr! IdentityVarToExpr(IVariable! var)
+ {
+ return var;
+ }
+
+ /// <summary>
+ /// Return a new expression in which each variable has been
+ /// replaced by an expression representing what is known about
+ /// that variable.
+ /// </summary>
+ private IExpr! InlineVariables(Elt! element, IExpr! expr, ISet/*<IVariable!>*/! notInlineable,
+ OnUnableToInline! unableToInline)
+ {
+ IVariable var = expr as IVariable;
+ if (var != null)
+ {
+ /*MicroLattice*/Element value = element[var];
+ if (notInlineable.Contains(var) || value == null || this.microLattice.IsTop(value))
+ {
+ return unableToInline(var); // We don't know anything about this variable.
+ }
+ else
+ {
+ // GetFoldExpr returns null when it can yield an expression that
+ // can be substituted for the variable.
+ IExpr valueExpr = this.microLattice.GetFoldExpr(value);
+ return (valueExpr == null) ? var : valueExpr;
+ }
+ }
+
+ // else
+
+ IFunApp fun = expr as IFunApp;
+ if (fun != null)
+ {
+ IList newargs = new ArrayList();
+ foreach (IExpr! arg in fun.Arguments)
+ {
+ newargs.Add(InlineVariables(element, arg, notInlineable, unableToInline));
+ }
+ return fun.CloneWithArguments(newargs);
+ }
+
+ // else
+
+ IFunction lambda = expr as IFunction;
+ if (lambda != null)
+ {
+ IMutableSet x = new HashSet(1);
+ x.Add(lambda.Param);
+
+ // Don't inline the bound variable
+ return lambda.CloneWithBody(
+ InlineVariables(element, lambda.Body,
+ (!) Set.Union(notInlineable, x), unableToInline)
+ );
+ }
+
+ else
+ {
+ throw
+ new System.NotImplementedException("cannot inline identifies in expression " + expr);
+ }
+ }
+
+
+ public override Element! Constrain(Element! element, IExpr! expr)
+ {
+ Elt! result = (Elt)element;
+
+ if(IsBottom(element))
+ {
+ return result; // == element
+ }
+
+ expr = InlineVariables(result, expr, (!)Set.Empty, new OnUnableToInline(IdentityVarToExpr));
+
+ foreach (IExpr! conjunct in FindConjuncts(expr))
+ {
+ IVariable left, right;
+
+ if (IsSimpleEquality(conjunct, out left, out right))
+ {
+ #region The conjunct is a simple equality
+
+
+ assert left != null && right != null;
+
+ Element leftValue = result[left], rightValue = result[right];
+ if (leftValue == null) { leftValue = this.microLattice.Top; }
+ if (rightValue == null) { rightValue = this.microLattice.Top; }
+ Element newValue = this.microLattice.Meet(leftValue, rightValue);
+ result = AddConstraint(result, left, newValue);
+ result = AddConstraint(result, right, newValue);
+
+ #endregion
+ }
+ else
+ {
+ ISet/*<IVariable>*/ variablesInvolved = VariablesInExpression(conjunct, Set.Empty);
+
+ if (variablesInvolved.Count == 1)
+ {
+ #region We have just one variable
+
+ IVariable var = null;
+ foreach (IVariable! v in variablesInvolved) { var = v; } // why is there no better way to get the elements?
+ assert var != null;
+ Element! value = this.microLattice.EvaluatePredicate(conjunct);
+ result = AddConstraint(result, var, value);
+
+ #endregion
+ }
+ else if(IsArithmeticExpr(conjunct) && this.microLattice.UnderstandsBasicArithmetics)
+ {
+ #region We evalaute an arithmetic expression
+
+ IFunApp fun = (IFunApp) conjunct;
+ if(fun.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) // if it is a symbol of equality
+ {
+ // get the variable to be assigned
+ IExpr! leftArg = (IExpr!) fun.Arguments[0];
+ IExpr! rightArg = (IExpr!) fun.Arguments[1];
+ IExpr! var = (leftArg is IVariable) ? leftArg : rightArg;
+
+ Element! value = this.microLattice.EvaluatePredicateWithState(conjunct, result.Constraints);
+ result = AddConstraint(result, (IVariable!) var, value);
+ }
+ #endregion
+ }
+ }
+ }
+ return result;
+ }
+
+
+ public override Element! Rename(Element! element, IVariable! oldName, IVariable! newName)
+ {
+ if(IsBottom(element))
+ {
+ return element;
+ }
+ else
+ {
+ return ((Elt)element).Rename(oldName, newName, this.microLattice);
+ }
+ }
+
+
+ public override bool Understands(IFunctionSymbol! f, IList! args)
+ {
+ return f.Equals(Prop.And) ||
+ f.Equals(Value.Eq) ||
+ microLattice.Understands(f, args);
+ }
+
+ private sealed class EquivalentExprException : CheckedException { }
+ private sealed class EquivalentExprInlineCallback
+ {
+ private readonly IVariable! var;
+ public EquivalentExprInlineCallback(IVariable! var)
+ {
+ this.var = var;
+ // base();
+ }
+
+ public IExpr! ThrowOnUnableToInline(IVariable! othervar)
+ throws EquivalentExprException;
+ {
+ if (othervar.Equals(var))
+ throw new EquivalentExprException();
+ else
+ return othervar;
+ }
+ }
+
+ public override IExpr/*?*/ EquivalentExpr(Element! e, IQueryable! q, IExpr! expr, IVariable! var, ISet/*<IVariable!>*/! prohibitedVars)
+ {
+ try
+ {
+ EquivalentExprInlineCallback closure = new EquivalentExprInlineCallback(var);
+ return InlineVariables((Elt)e, expr, (!)Set.Empty,
+ new OnUnableToInline(closure.ThrowOnUnableToInline));
+ }
+ catch (EquivalentExprException)
+ {
+ return null;
+ }
+ }
+
+
+ /// <summary>
+ /// Check to see if the given predicate holds in the given lattice element.
+ ///
+ /// TODO: We leave this unimplemented for now and just return maybe.
+ /// </summary>
+ /// <param name="e">The lattice element.</param>
+ /// <param name="pred">The predicate.</param>
+ /// <returns>Yes, No, or Maybe</returns>
+ public override Answer CheckPredicate(Element! e, IExpr! pred)
+ {
+ return Answer.Maybe;
+ }
+
+ /// <summary>
+ /// Answers a disequality about two variables. The same information could be obtained
+ /// by asking CheckPredicate, but a different implementation may be simpler and more
+ /// efficient.
+ ///
+ /// TODO: We leave this unimplemented for now and just return maybe.
+ /// </summary>
+ /// <param name="e">The lattice element.</param>
+ /// <param name="var1">The first variable.</param>
+ /// <param name="var2">The second variable.</param>
+ /// <returns>Yes, No, or Maybe.</returns>
+ public override Answer CheckVariableDisequality(Element! e, IVariable! var1, IVariable! var2)
+ {
+ return Answer.Maybe;
+ }
+
+ public override void Validate()
+ {
+ base.Validate();
+ microLattice.Validate();
+ }
+
+ }
+}