diff options
Diffstat (limited to 'Source/AIFramework')
20 files changed, 11566 insertions, 11566 deletions
diff --git a/Source/AIFramework/AIFramework.csproj b/Source/AIFramework/AIFramework.csproj index a809b8bf..a04074a6 100644 --- a/Source/AIFramework/AIFramework.csproj +++ b/Source/AIFramework/AIFramework.csproj @@ -1,204 +1,204 @@ -<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>9.0.21022</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
- <ProjectGuid>{39B0658D-C955-41C5-9A43-48C97A1EF5FD}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>AIFramework</RootNamespace>
- <AssemblyName>AIFramework</AssemblyName>
- <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
- <FileAlignment>512</FileAlignment>
- <CodeContractsAssemblyMode>1</CodeContractsAssemblyMode>
- <SignAssembly>true</SignAssembly>
- <AssemblyOriginatorKeyFile>..\InterimKey.snk</AssemblyOriginatorKeyFile>
- <FileUpgradeFlags>
- </FileUpgradeFlags>
- <OldToolsVersion>3.5</OldToolsVersion>
- <UpgradeBackupLocation />
- <PublishUrl>publish\</PublishUrl>
- <Install>true</Install>
- <InstallFrom>Disk</InstallFrom>
- <UpdateEnabled>false</UpdateEnabled>
- <UpdateMode>Foreground</UpdateMode>
- <UpdateInterval>7</UpdateInterval>
- <UpdateIntervalUnits>Days</UpdateIntervalUnits>
- <UpdatePeriodically>false</UpdatePeriodically>
- <UpdateRequired>false</UpdateRequired>
- <MapFileExtensions>true</MapFileExtensions>
- <ApplicationRevision>0</ApplicationRevision>
- <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
- <IsWebBootstrapper>false</IsWebBootstrapper>
- <UseApplicationTrust>false</UseApplicationTrust>
- <BootstrapperEnabled>true</BootstrapperEnabled>
- <TargetFrameworkProfile Condition=" '$(OS)' == 'Windows_NT'" >Client</TargetFrameworkProfile>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
- <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
- <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
- <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
- <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
- <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
- <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
- <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
- <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
- <CodeContractsContainerAnalysis>False</CodeContractsContainerAnalysis>
- <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
- <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
- <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
- <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
- <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
- <CodeContractsCustomRewriterAssembly>
- </CodeContractsCustomRewriterAssembly>
- <CodeContractsCustomRewriterClass>
- </CodeContractsCustomRewriterClass>
- <CodeContractsLibPaths>
- </CodeContractsLibPaths>
- <CodeContractsExtraRewriteOptions>
- </CodeContractsExtraRewriteOptions>
- <CodeContractsExtraAnalysisOptions>
- </CodeContractsExtraAnalysisOptions>
- <CodeContractsBaseLineFile>
- </CodeContractsBaseLineFile>
- <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
- <CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'z3apidebug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\z3apidebug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <DebugType>full</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <CodeAnalysisRuleAssemblies>
- </CodeAnalysisRuleAssemblies>
- <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
- <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>Migrated rules for AIFramework.ruleset</CodeAnalysisRuleSet>
- <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Checked|AnyCPU'">
- <DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\Checked\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <DebugType>full</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <CodeAnalysisLogFile>bin\Debug\AIFramework.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
- <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
- <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
- <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
- <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
- <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
- <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
- <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
- <CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
- <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
- <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
- <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
- <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
- <CodeContractsEnumObligations>False</CodeContractsEnumObligations>
- <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
- <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
- <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
- <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
- <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
- <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
- <CodeContractsCustomRewriterAssembly />
- <CodeContractsCustomRewriterClass />
- <CodeContractsLibPaths />
- <CodeContractsExtraRewriteOptions />
- <CodeContractsExtraAnalysisOptions />
- <CodeContractsBaseLineFile />
- <CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
- <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
- <CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
- <CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="..\version.cs">
- <Link>version.cs</Link>
- </Compile>
- <Compile Include="CommonFunctionSymbols.cs" />
- <Compile Include="Expr.cs" />
- <Compile Include="Functional.cs" />
- <Compile Include="Lattice.cs" />
- <Compile Include="Logger.cs" />
- <Compile Include="MultiLattice.cs" />
- <Compile Include="Mutable.cs" />
- <Compile Include="Polyhedra\LinearConstraint.cs" />
- <Compile Include="Polyhedra\LinearConstraintSystem.cs" />
- <Compile Include="Polyhedra\PolyhedraAbstraction.cs" />
- <Compile Include="Polyhedra\SimplexTableau.cs" />
- <Compile Include="VariableMap\ConstantAbstraction.cs" />
- <Compile Include="VariableMap\DynamicTypeLattice.cs" />
- <Compile Include="VariableMap\Intervals.cs" />
- <Compile Include="VariableMap\MicroLattice.cs" />
- <Compile Include="VariableMap\Nullness.cs" />
- <Compile Include="VariableMap\VariableMapLattice.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\Basetypes\Basetypes.csproj">
- <Project>{43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}</Project>
- <Name>Basetypes</Name>
- </ProjectReference>
- <ProjectReference Include="..\CodeContractsExtender\CodeContractsExtender.csproj">
- <Project>{ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}</Project>
- <Name>CodeContractsExtender</Name>
- </ProjectReference>
- </ItemGroup>
- <ItemGroup>
- <Folder Include="Properties\" />
- </ItemGroup>
- <ItemGroup>
- <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
- <Visible>False</Visible>
- <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
- <Install>false</Install>
- </BootstrapperPackage>
- <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
- <Visible>False</Visible>
- <ProductName>.NET Framework 3.5 SP1</ProductName>
- <Install>true</Install>
- </BootstrapperPackage>
- <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
- <Visible>False</Visible>
- <ProductName>Windows Installer 3.1</ProductName>
- <Install>true</Install>
- </BootstrapperPackage>
- </ItemGroup>
- <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
- <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
- Other similar extension points exist, see Microsoft.Common.targets.
- <Target Name="BeforeBuild">
- </Target>
- <Target Name="AfterBuild">
- </Target>
- -->
+<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>9.0.21022</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{39B0658D-C955-41C5-9A43-48C97A1EF5FD}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>AIFramework</RootNamespace> + <AssemblyName>AIFramework</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <CodeContractsAssemblyMode>1</CodeContractsAssemblyMode> + <SignAssembly>true</SignAssembly> + <AssemblyOriginatorKeyFile>..\InterimKey.snk</AssemblyOriginatorKeyFile> + <FileUpgradeFlags> + </FileUpgradeFlags> + <OldToolsVersion>3.5</OldToolsVersion> + <UpgradeBackupLocation /> + <PublishUrl>publish\</PublishUrl> + <Install>true</Install> + <InstallFrom>Disk</InstallFrom> + <UpdateEnabled>false</UpdateEnabled> + <UpdateMode>Foreground</UpdateMode> + <UpdateInterval>7</UpdateInterval> + <UpdateIntervalUnits>Days</UpdateIntervalUnits> + <UpdatePeriodically>false</UpdatePeriodically> + <UpdateRequired>false</UpdateRequired> + <MapFileExtensions>true</MapFileExtensions> + <ApplicationRevision>0</ApplicationRevision> + <ApplicationVersion>1.0.0.%2a</ApplicationVersion> + <IsWebBootstrapper>false</IsWebBootstrapper> + <UseApplicationTrust>false</UseApplicationTrust> + <BootstrapperEnabled>true</BootstrapperEnabled> + <TargetFrameworkProfile Condition=" '$(OS)' == 'Windows_NT'" >Client</TargetFrameworkProfile> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking> + <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface> + <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure> + <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires> + <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis> + <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations> + <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations> + <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations> + <CodeContractsPointerObligations>False</CodeContractsPointerObligations> + <CodeContractsContainerAnalysis>False</CodeContractsContainerAnalysis> + <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions> + <CodeContractsRunInBackground>True</CodeContractsRunInBackground> + <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies> + <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine> + <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs> + <CodeContractsCustomRewriterAssembly> + </CodeContractsCustomRewriterAssembly> + <CodeContractsCustomRewriterClass> + </CodeContractsCustomRewriterClass> + <CodeContractsLibPaths> + </CodeContractsLibPaths> + <CodeContractsExtraRewriteOptions> + </CodeContractsExtraRewriteOptions> + <CodeContractsExtraAnalysisOptions> + </CodeContractsExtraAnalysisOptions> + <CodeContractsBaseLineFile> + </CodeContractsBaseLineFile> + <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel> + <CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly> + <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'z3apidebug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <OutputPath>bin\z3apidebug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <DebugType>full</DebugType> + <PlatformTarget>AnyCPU</PlatformTarget> + <CodeAnalysisRuleAssemblies> + </CodeAnalysisRuleAssemblies> + <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression> + <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>Migrated rules for AIFramework.ruleset</CodeAnalysisRuleSet> + <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Checked|AnyCPU'"> + <DebugSymbols>true</DebugSymbols> + <OutputPath>bin\Checked\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <DebugType>full</DebugType> + <PlatformTarget>AnyCPU</PlatformTarget> + <CodeAnalysisLogFile>bin\Debug\AIFramework.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile> + <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression> + <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> + <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories> + <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories> + <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking> + <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface> + <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure> + <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires> + <CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers> + <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis> + <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations> + <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations> + <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations> + <CodeContractsEnumObligations>False</CodeContractsEnumObligations> + <CodeContractsPointerObligations>False</CodeContractsPointerObligations> + <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions> + <CodeContractsRunInBackground>True</CodeContractsRunInBackground> + <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies> + <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine> + <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs> + <CodeContractsCustomRewriterAssembly /> + <CodeContractsCustomRewriterClass /> + <CodeContractsLibPaths /> + <CodeContractsExtraRewriteOptions /> + <CodeContractsExtraAnalysisOptions /> + <CodeContractsBaseLineFile /> + <CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults> + <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel> + <CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly> + <CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + </ItemGroup> + <ItemGroup> + <Compile Include="..\version.cs"> + <Link>version.cs</Link> + </Compile> + <Compile Include="CommonFunctionSymbols.cs" /> + <Compile Include="Expr.cs" /> + <Compile Include="Functional.cs" /> + <Compile Include="Lattice.cs" /> + <Compile Include="Logger.cs" /> + <Compile Include="MultiLattice.cs" /> + <Compile Include="Mutable.cs" /> + <Compile Include="Polyhedra\LinearConstraint.cs" /> + <Compile Include="Polyhedra\LinearConstraintSystem.cs" /> + <Compile Include="Polyhedra\PolyhedraAbstraction.cs" /> + <Compile Include="Polyhedra\SimplexTableau.cs" /> + <Compile Include="VariableMap\ConstantAbstraction.cs" /> + <Compile Include="VariableMap\DynamicTypeLattice.cs" /> + <Compile Include="VariableMap\Intervals.cs" /> + <Compile Include="VariableMap\MicroLattice.cs" /> + <Compile Include="VariableMap\Nullness.cs" /> + <Compile Include="VariableMap\VariableMapLattice.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\Basetypes\Basetypes.csproj"> + <Project>{43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}</Project> + <Name>Basetypes</Name> + </ProjectReference> + <ProjectReference Include="..\CodeContractsExtender\CodeContractsExtender.csproj"> + <Project>{ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}</Project> + <Name>CodeContractsExtender</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <Folder Include="Properties\" /> + </ItemGroup> + <ItemGroup> + <BootstrapperPackage Include="Microsoft.Net.Client.3.5"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName> + <Install>false</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.5 SP1</ProductName> + <Install>true</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1"> + <Visible>False</Visible> + <ProductName>Windows Installer 3.1</ProductName> + <Install>true</Install> + </BootstrapperPackage> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> </Project>
\ No newline at end of file diff --git a/Source/AIFramework/CommonFunctionSymbols.cs b/Source/AIFramework/CommonFunctionSymbols.cs index 6f7a9f93..6a287810 100644 --- a/Source/AIFramework/CommonFunctionSymbols.cs +++ b/Source/AIFramework/CommonFunctionSymbols.cs @@ -1,1232 +1,1232 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-namespace Microsoft.AbstractInterpretationFramework
-{
- using System.Diagnostics.Contracts;
- using System.Collections;
- using System.Collections.Generic;
- //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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(display != null);
- Contract.Invariant(typ != null);
- }
-
-
- public FunctionSymbol(AIType/*!*/ typ)
- : this("FunctionSymbol", typ) {
- Contract.Requires(typ != null);
- }
-
- internal FunctionSymbol(string/*!*/ display, AIType/*!*/ typ) {
- Contract.Requires(typ != null);
- Contract.Requires(display != null);
- this.display = display;
- this.typ = typ;
- // base();
- }
-
- public AIType/*!*/ AIType { get { Contract.Ensures(Contract.Result<AIType>() != null); return typ; } }
-
- [NoDefaultContract]
- [Pure]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- 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(cce.NonNull(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]
- 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]
- 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(cce.NonNull(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]
- 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 { Contract.Ensures(Contract.Result<string>() != null); return cce.NonNull(this.ToString()); } }
-
- public NamedSymbol(string/*!*/ symbol, AIType/*!*/ typ)
- : base(symbol, typ) {
- Contract.Requires(typ != null);
- Contract.Requires(symbol != null);
- }
-
- [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]
- 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 { Contract.Ensures(Contract.Result<AIType>() != null); return valtype; } }
-
- private static readonly FunctionType[]/*!*/ funtypeCache = new FunctionType[5];
- public static FunctionType/*!*/ FunctionType(int inParameterCount) {
- Contract.Requires((0 <= inParameterCount));
- Contract.Ensures(Contract.Result<FunctionType>() != null);
- // Contract.Ensures(Contract.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 {
- Contract.Ensures(Contract.Result<AIType>() != null);
- if (binreltype == null) {
- binreltype = new FunctionType(Type, Type, Prop.Type);
- }
- return binreltype;
- }
- }
-
- [Once]
- private static FunctionSymbol/*!*/ _eq;
- public static FunctionSymbol/*!*/ Eq {
- get {
- Contract.Ensures(Contract.Result<FunctionSymbol>() != null);
- if (_eq == null) {
- _eq = new FunctionSymbol("=", BinrelType);
- }
- return _eq;
- }
- }
- [Once]
- private static FunctionSymbol/*!*/ _neq;
- public static FunctionSymbol/*!*/ Neq {
- get {
- Contract.Ensures(Contract.Result<FunctionSymbol>() != null);
- if (_neq == null) {
- _neq = new FunctionSymbol("!=", BinrelType);
- }
- return _neq;
- }
- }
- [Once]
- private static FunctionSymbol/*!*/ _subtype;
- public static FunctionSymbol/*!*/ Subtype {
- get {
- Contract.Ensures(Contract.Result<FunctionSymbol>() != null);
- if (_subtype == null) {
- _subtype = new FunctionSymbol("<:", BinrelType);
- }
- return _subtype;
- }
- }
-
- [Once]
- private static AIType/*!*/ typeof_type;
- private static AIType/*!*/ TypeofType {
- get {
- Contract.Ensures(Contract.Result<AIType>() != null);
- if (typeof_type == null) {
- typeof_type = new FunctionType(Ref.Type, Type);
- }
- return typeof_type;
- }
- }
- [Once]
- private static FunctionSymbol/*!*/ _typeof;
- public static FunctionSymbol/*!*/ Typeof {
- get {
- Contract.Ensures(Contract.Result<FunctionSymbol>() != null);
- 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _negate; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Add { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _add; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Sub { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _sub; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Mul { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _mul; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Div { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _div; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Mod { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _mod; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ AtMost { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _atmost; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Less { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _less; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Greater { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _greater; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ AtLeast { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _atleast; } }
-
- public static IntSymbol/*!*/ Const(BigNum x) {
- Contract.Ensures(Contract.Result<IntSymbol>() != null);
- // 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); return doubletype; } }
-
- public static DoubleSymbol/*!*/ Const(double x) {
- Contract.Ensures(Contract.Result<DoubleSymbol>() != null);
- // 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _negate; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Add { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _add; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Sub { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _sub; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Mul { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _mul; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Div { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _div; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Mod { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _mod; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ AtMost { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _atmost; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Less { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _less; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Greater { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _greater; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ AtLeast { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _atleast; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Extract { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _extract; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Concat { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _concat; } }
-
- public static BvSymbol/*!*/ Const(BigNum x, int y) {
- Contract.Ensures(Contract.Result<BvSymbol>() != null);
- // 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); return reftype; } }
-
- private static readonly FunctionSymbol/*!*/ _null = new FunctionSymbol("null", Type);
-
- public static FunctionSymbol/*!*/ Null { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); return fieldnametype; } }
-
- private static readonly FunctionSymbol/*!*/ _allocated = new FunctionSymbol("$allocated", FieldName.Type);
- public static FunctionSymbol/*!*/ Allocated { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _allocated; } }
-
- /// <summary>
- /// Is this a boolean field that monotonically goes from false to true?
- /// </summary>
- public static bool IsBooleanMonotonicallyWeakening(IFunctionSymbol/*!*/ f) {
- Contract.Requires(f != null);
- 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); 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/*!*/ ){
- //Contract.Requires( != null);
- //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/*!*/ ){
- //Contract.Requires( != null);
- // return type1; } }
- // public AIType(Type2/*!*/ ){
- //Contract.Requires( != null);
- // 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 { Contract.Ensures(Contract.Result<AIType>() != null); 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);
- private static readonly FunctionSymbol/*!*/ _lambda = new FunctionSymbol("Lambda", quantifiertype);
-
-
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ False { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _false; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ True { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _true; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Not { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _not; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ And { [Pure] get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _and; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Or { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _or; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Implies { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _implies; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Exists { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _exists; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Forall { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _forall; } }
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public static FunctionSymbol/*!*/ Lambda { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _lambda; } }
-
-
- /// <summary>
- /// Prop should not be instantiated from the outside.
- /// </summary>
- private Prop() { }
-
-
-
- //
- // Utility Methods
- //
-
- public static IExpr/*!*/ SimplifiedAnd(IPropExprFactory/*!*/ factory, IExpr/*!*/ e0, IExpr/*!*/ e1) {
- Contract.Requires(e1 != null);
- Contract.Requires(e0 != null);
- Contract.Requires(factory != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- 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) {
- Contract.Requires(exprs != null);
- Contract.Requires(factory != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- IExpr/*!*/ result = factory.True;
- Contract.Assert(result != null);
- foreach (IExpr/*!*/ conjunct in exprs) {
- Contract.Assert(conjunct != null);
- result = SimplifiedAnd(factory, result, conjunct);
- }
- return result;
- }
-
- public static IExpr/*!*/ SimplifiedOr(IPropExprFactory/*!*/ factory, IExpr/*!*/ e0, IExpr/*!*/ e1) {
- Contract.Requires(e1 != null);
- Contract.Requires(e0 != null);
- Contract.Requires(factory != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- 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) {
- Contract.Requires(exprs != null);
- Contract.Requires(factory != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- IExpr/*!*/ result = factory.False;
- Contract.Assert(result != null);
- foreach (IExpr/*!*/ disj in exprs) {
- Contract.Assert(disj != null);
- 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) {
- Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<IList>() != null);
- Contract.Ensures(Contract.ForAll(0, Contract.Result<IList>().Count, i => {
- var sub = Contract.Result<IList>()[i];
- return !(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) {
- Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<IList>() != null);
- Contract.Ensures(Contract.ForAll(0, Contract.Result<IList>().Count, i => {
- var sub = Contract.Result<IList>()[i];
- return !(sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(Prop.Or);
- }));
- return BreakJuncts(e, Prop.Or);
- }
-
- private static IList/*<IExpr!>*//*!*/ BreakJuncts(IExpr/*!*/ e, IFunctionSymbol/*!*/ sym) {
- Contract.Requires(sym != null);
- Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<IList>() != null);
- Contract.Ensures(Contract.ForAll(0, Contract.Result<IList>().Count, i => {
- var sub = Contract.Result<IList>()[i];
- return (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) {
- Contract.Assert(arg != null);
- 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>
- ///
- [ContractClass(typeof(IPropExprFactoryContracts))]
- 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);*/;
- }
- [ContractClassFor(typeof(IPropExprFactory))]
- public abstract class IPropExprFactoryContracts : IPropExprFactory
- {
- #region IPropExprFactory Members
- IFunApp IPropExprFactory.Implies(IExpr p, IExpr q) {
- Contract.Requires(p != null);
- Contract.Requires(q != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
- IFunApp IPropExprFactory.False {
-
- get { Contract.Ensures(Contract.Result<IFunApp>() != null); throw new System.NotImplementedException(); }
- }
-
- IFunApp IPropExprFactory.True {
- get { Contract.Ensures(Contract.Result<IFunApp>() != null); throw new System.NotImplementedException(); }
- }
-
- IFunApp IPropExprFactory.Not(IExpr p) {
- Contract.Requires(p != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
- IFunApp IPropExprFactory.And(IExpr p, IExpr q) {
- Contract.Requires(p != null);
- Contract.Requires(q != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
- IFunApp IPropExprFactory.Or(IExpr p, IExpr q) {
- Contract.Requires(p != null);
- Contract.Requires(q != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
-
-
- #endregion
- }
-
- /// <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>
- ///
- [ContractClass(typeof(IValueExprFactoryContracts))]
- 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);*/;
- }
- [ContractClassFor(typeof(IValueExprFactory))]
- public abstract class IValueExprFactoryContracts : IValueExprFactory
- {
- #region IValueExprFactory Members
-
- IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) {
- Contract.Requires(e0 != null);
- Contract.Requires(e1 != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
- IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) {
- Contract.Requires(e0 != null);
- Contract.Requires(e1 != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
- #endregion
- }
-
- /// <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>
- ///
- [ContractClass(typeof(INullnessFactoryContracts))]
- 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);*/ }
- }
- [ContractClassFor(typeof(INullnessFactory))]
- public abstract class INullnessFactoryContracts : INullnessFactory
- {
- #region INullnessFactory Members
-
- IFunApp INullnessFactory.Eq(IExpr e0, IExpr e1) {
- Contract.Requires(e0 != null);
- Contract.Requires(e1 != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
- IFunApp INullnessFactory.Neq(IExpr e0, IExpr e1) {
- Contract.Requires(e0 != null);
- Contract.Requires(e1 != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
- IFunApp INullnessFactory.Null {
- get {
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
- }
-
- #endregion
- }
-
- /// <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>
- ///
- [ContractClass(typeof(IIntExprFactoryContracts))]
- public interface IIntExprFactory : IValueExprFactory
- {
- IFunApp/*!*/ Const(BigNum i) /*ensures result.FunctionSymbol.Equals(new IntSymbol(i));*/;
- }
- [ContractClassFor(typeof(IIntExprFactory))]
- public abstract class IIntExprFactoryContracts : IIntExprFactory
- {
-
- #region IIntExprFactory Members
-
- IFunApp IIntExprFactory.Const(BigNum i) {
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
- #endregion
-
- #region IValueExprFactory Members
-
- IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) {
- throw new System.NotImplementedException();
- }
-
- IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) {
- throw new System.NotImplementedException();
- }
-
- #endregion
- }
-
- /// <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>
- ///
- [ContractClass(typeof(ILinearExprFactoryContracts))]
- 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);*/;
- }
- [ContractClassFor(typeof(ILinearExprFactory))]
- public abstract class ILinearExprFactoryContracts : ILinearExprFactory
- {
-
- #region ILinearExprFactory Members
-
- IFunApp ILinearExprFactory.AtMost(IExpr e0, IExpr e1) {
- Contract.Requires(e0 != null);
- Contract.Requires(e1 != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
- IFunApp ILinearExprFactory.Add(IExpr e0, IExpr e1) {
- Contract.Requires(e0 != null);
- Contract.Requires(e1 != null); Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
- IExpr ILinearExprFactory.Term(Rational r, IVariable var) {
- Contract.Ensures(Contract.Result<IExpr>() != null);
- throw new System.NotImplementedException();
- }
-
- IFunApp ILinearExprFactory.False {
- get { Contract.Ensures(Contract.Result<IFunApp>() != null); throw new System.NotImplementedException(); }
- }
-
- IFunApp ILinearExprFactory.True {
- get { Contract.Ensures(Contract.Result<IFunApp>() != null); throw new System.NotImplementedException(); }
- }
-
- IFunApp ILinearExprFactory.And(IExpr p, IExpr q) {
- Contract.Requires(p != null);
- Contract.Requires(q != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
- #endregion
-
- #region IIntExprFactory Members
-
- IFunApp IIntExprFactory.Const(BigNum i) {
- throw new System.NotImplementedException();
- }
-
- #endregion
-
- #region IValueExprFactory Members
-
- IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) {
- throw new System.NotImplementedException();
- }
-
- IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) {
- throw new System.NotImplementedException();
- }
-
- #endregion
- }
-
- /// <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>
- ///
- [ContractClass(typeof(ITypeExprFactoryContracts))]
- 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]
- bool IsTypeConstant(IExpr/*!*/ t);
-
- /// <summary>
- /// Returns true iff t0 and t1 are types such that t0 and t1 are equal.
- /// </summary>
- [Pure]
- 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]
- 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);*/;
- }
- [ContractClassFor(typeof(ITypeExprFactory))]
- public abstract class ITypeExprFactoryContracts : ITypeExprFactory
- {
-
- #region ITypeExprFactory Members
-
- IExpr ITypeExprFactory.RootType {
- get { Contract.Ensures(Contract.Result<IExpr>() != null); throw new System.NotImplementedException(); }
- }
-
- bool ITypeExprFactory.IsTypeConstant(IExpr t) {
- Contract.Requires(t != null);
- throw new System.NotImplementedException();
- }
-
- bool ITypeExprFactory.IsTypeEqual(IExpr t0, IExpr t1) {
- Contract.Requires(t0 != null);
- Contract.Requires(t1 != null);
- throw new System.NotImplementedException();
- }
-
- bool ITypeExprFactory.IsSubType(IExpr t0, IExpr t1) {
- Contract.Requires(t0 != null);
- Contract.Requires(t1 != null);
- throw new System.NotImplementedException();
- }
-
- IExpr ITypeExprFactory.JoinTypes(IExpr t0, IExpr t1) {
- Contract.Requires(t0 != null);
- Contract.Requires(t1 != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- throw new System.NotImplementedException();
- }
-
- IFunApp ITypeExprFactory.IsExactlyA(IExpr e, IExpr type) {
- Contract.Requires(e != null);
- Contract.Requires(type != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
- IFunApp ITypeExprFactory.IsA(IExpr e, IExpr type) {
- Contract.Requires(e != null);
- Contract.Requires(type != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- throw new System.NotImplementedException();
- }
-
- #endregion
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework +{ + using System.Diagnostics.Contracts; + using System.Collections; + using System.Collections.Generic; + //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; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(display != null); + Contract.Invariant(typ != null); + } + + + public FunctionSymbol(AIType/*!*/ typ) + : this("FunctionSymbol", typ) { + Contract.Requires(typ != null); + } + + internal FunctionSymbol(string/*!*/ display, AIType/*!*/ typ) { + Contract.Requires(typ != null); + Contract.Requires(display != null); + this.display = display; + this.typ = typ; + // base(); + } + + public AIType/*!*/ AIType { get { Contract.Ensures(Contract.Result<AIType>() != null); return typ; } } + + [NoDefaultContract] + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result<string>() != null); + 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(cce.NonNull(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] + 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] + 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(cce.NonNull(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] + 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 { Contract.Ensures(Contract.Result<string>() != null); return cce.NonNull(this.ToString()); } } + + public NamedSymbol(string/*!*/ symbol, AIType/*!*/ typ) + : base(symbol, typ) { + Contract.Requires(typ != null); + Contract.Requires(symbol != null); + } + + [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] + 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 { Contract.Ensures(Contract.Result<AIType>() != null); return valtype; } } + + private static readonly FunctionType[]/*!*/ funtypeCache = new FunctionType[5]; + public static FunctionType/*!*/ FunctionType(int inParameterCount) { + Contract.Requires((0 <= inParameterCount)); + Contract.Ensures(Contract.Result<FunctionType>() != null); + // Contract.Ensures(Contract.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 { + Contract.Ensures(Contract.Result<AIType>() != null); + if (binreltype == null) { + binreltype = new FunctionType(Type, Type, Prop.Type); + } + return binreltype; + } + } + + [Once] + private static FunctionSymbol/*!*/ _eq; + public static FunctionSymbol/*!*/ Eq { + get { + Contract.Ensures(Contract.Result<FunctionSymbol>() != null); + if (_eq == null) { + _eq = new FunctionSymbol("=", BinrelType); + } + return _eq; + } + } + [Once] + private static FunctionSymbol/*!*/ _neq; + public static FunctionSymbol/*!*/ Neq { + get { + Contract.Ensures(Contract.Result<FunctionSymbol>() != null); + if (_neq == null) { + _neq = new FunctionSymbol("!=", BinrelType); + } + return _neq; + } + } + [Once] + private static FunctionSymbol/*!*/ _subtype; + public static FunctionSymbol/*!*/ Subtype { + get { + Contract.Ensures(Contract.Result<FunctionSymbol>() != null); + if (_subtype == null) { + _subtype = new FunctionSymbol("<:", BinrelType); + } + return _subtype; + } + } + + [Once] + private static AIType/*!*/ typeof_type; + private static AIType/*!*/ TypeofType { + get { + Contract.Ensures(Contract.Result<AIType>() != null); + if (typeof_type == null) { + typeof_type = new FunctionType(Ref.Type, Type); + } + return typeof_type; + } + } + [Once] + private static FunctionSymbol/*!*/ _typeof; + public static FunctionSymbol/*!*/ Typeof { + get { + Contract.Ensures(Contract.Result<FunctionSymbol>() != null); + 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _negate; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Add { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _add; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Sub { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _sub; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Mul { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _mul; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Div { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _div; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Mod { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _mod; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ AtMost { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _atmost; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Less { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _less; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Greater { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _greater; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ AtLeast { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _atleast; } } + + public static IntSymbol/*!*/ Const(BigNum x) { + Contract.Ensures(Contract.Result<IntSymbol>() != null); + // 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); return doubletype; } } + + public static DoubleSymbol/*!*/ Const(double x) { + Contract.Ensures(Contract.Result<DoubleSymbol>() != null); + // 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _negate; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Add { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _add; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Sub { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _sub; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Mul { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _mul; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Div { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _div; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Mod { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _mod; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ AtMost { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _atmost; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Less { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _less; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Greater { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _greater; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ AtLeast { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _atleast; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Extract { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _extract; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Concat { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _concat; } } + + public static BvSymbol/*!*/ Const(BigNum x, int y) { + Contract.Ensures(Contract.Result<BvSymbol>() != null); + // 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); return reftype; } } + + private static readonly FunctionSymbol/*!*/ _null = new FunctionSymbol("null", Type); + + public static FunctionSymbol/*!*/ Null { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); return fieldnametype; } } + + private static readonly FunctionSymbol/*!*/ _allocated = new FunctionSymbol("$allocated", FieldName.Type); + public static FunctionSymbol/*!*/ Allocated { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _allocated; } } + + /// <summary> + /// Is this a boolean field that monotonically goes from false to true? + /// </summary> + public static bool IsBooleanMonotonicallyWeakening(IFunctionSymbol/*!*/ f) { + Contract.Requires(f != null); + 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 new AIType/*!*/ Type { get { Contract.Ensures(Contract.Result<AIType>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); 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 { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); 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/*!*/ ){ + //Contract.Requires( != null); + //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/*!*/ ){ + //Contract.Requires( != null); + // return type1; } } + // public AIType(Type2/*!*/ ){ + //Contract.Requires( != null); + // 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 { Contract.Ensures(Contract.Result<AIType>() != null); 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); + private static readonly FunctionSymbol/*!*/ _lambda = new FunctionSymbol("Lambda", quantifiertype); + + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ False { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _false; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ True { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _true; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Not { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _not; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ And { [Pure] get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _and; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Or { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _or; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Implies { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _implies; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Exists { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _exists; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Forall { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _forall; } } + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public static FunctionSymbol/*!*/ Lambda { get { Contract.Ensures(Contract.Result<FunctionSymbol>() != null); return _lambda; } } + + + /// <summary> + /// Prop should not be instantiated from the outside. + /// </summary> + private Prop() { } + + + + // + // Utility Methods + // + + public static IExpr/*!*/ SimplifiedAnd(IPropExprFactory/*!*/ factory, IExpr/*!*/ e0, IExpr/*!*/ e1) { + Contract.Requires(e1 != null); + Contract.Requires(e0 != null); + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + 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) { + Contract.Requires(exprs != null); + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + IExpr/*!*/ result = factory.True; + Contract.Assert(result != null); + foreach (IExpr/*!*/ conjunct in exprs) { + Contract.Assert(conjunct != null); + result = SimplifiedAnd(factory, result, conjunct); + } + return result; + } + + public static IExpr/*!*/ SimplifiedOr(IPropExprFactory/*!*/ factory, IExpr/*!*/ e0, IExpr/*!*/ e1) { + Contract.Requires(e1 != null); + Contract.Requires(e0 != null); + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + 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) { + Contract.Requires(exprs != null); + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + IExpr/*!*/ result = factory.False; + Contract.Assert(result != null); + foreach (IExpr/*!*/ disj in exprs) { + Contract.Assert(disj != null); + 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) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result<IList>() != null); + Contract.Ensures(Contract.ForAll(0, Contract.Result<IList>().Count, i => { + var sub = Contract.Result<IList>()[i]; + return !(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) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result<IList>() != null); + Contract.Ensures(Contract.ForAll(0, Contract.Result<IList>().Count, i => { + var sub = Contract.Result<IList>()[i]; + return !(sub is IFunApp) || !((IFunApp)sub).FunctionSymbol.Equals(Prop.Or); + })); + return BreakJuncts(e, Prop.Or); + } + + private static IList/*<IExpr!>*//*!*/ BreakJuncts(IExpr/*!*/ e, IFunctionSymbol/*!*/ sym) { + Contract.Requires(sym != null); + Contract.Requires(e != null); + Contract.Ensures(Contract.Result<IList>() != null); + Contract.Ensures(Contract.ForAll(0, Contract.Result<IList>().Count, i => { + var sub = Contract.Result<IList>()[i]; + return (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) { + Contract.Assert(arg != null); + 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> + /// + [ContractClass(typeof(IPropExprFactoryContracts))] + 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);*/; + } + [ContractClassFor(typeof(IPropExprFactory))] + public abstract class IPropExprFactoryContracts : IPropExprFactory + { + #region IPropExprFactory Members + IFunApp IPropExprFactory.Implies(IExpr p, IExpr q) { + Contract.Requires(p != null); + Contract.Requires(q != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + IFunApp IPropExprFactory.False { + + get { Contract.Ensures(Contract.Result<IFunApp>() != null); throw new System.NotImplementedException(); } + } + + IFunApp IPropExprFactory.True { + get { Contract.Ensures(Contract.Result<IFunApp>() != null); throw new System.NotImplementedException(); } + } + + IFunApp IPropExprFactory.Not(IExpr p) { + Contract.Requires(p != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + IFunApp IPropExprFactory.And(IExpr p, IExpr q) { + Contract.Requires(p != null); + Contract.Requires(q != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + IFunApp IPropExprFactory.Or(IExpr p, IExpr q) { + Contract.Requires(p != null); + Contract.Requires(q != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + + + #endregion + } + + /// <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> + /// + [ContractClass(typeof(IValueExprFactoryContracts))] + 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);*/; + } + [ContractClassFor(typeof(IValueExprFactory))] + public abstract class IValueExprFactoryContracts : IValueExprFactory + { + #region IValueExprFactory Members + + IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + #endregion + } + + /// <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> + /// + [ContractClass(typeof(INullnessFactoryContracts))] + 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);*/ } + } + [ContractClassFor(typeof(INullnessFactory))] + public abstract class INullnessFactoryContracts : INullnessFactory + { + #region INullnessFactory Members + + IFunApp INullnessFactory.Eq(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + IFunApp INullnessFactory.Neq(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + IFunApp INullnessFactory.Null { + get { + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + } + + #endregion + } + + /// <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> + /// + [ContractClass(typeof(IIntExprFactoryContracts))] + public interface IIntExprFactory : IValueExprFactory + { + IFunApp/*!*/ Const(BigNum i) /*ensures result.FunctionSymbol.Equals(new IntSymbol(i));*/; + } + [ContractClassFor(typeof(IIntExprFactory))] + public abstract class IIntExprFactoryContracts : IIntExprFactory + { + + #region IIntExprFactory Members + + IFunApp IIntExprFactory.Const(BigNum i) { + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + #endregion + + #region IValueExprFactory Members + + IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { + throw new System.NotImplementedException(); + } + + IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { + throw new System.NotImplementedException(); + } + + #endregion + } + + /// <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> + /// + [ContractClass(typeof(ILinearExprFactoryContracts))] + 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);*/; + } + [ContractClassFor(typeof(ILinearExprFactory))] + public abstract class ILinearExprFactoryContracts : ILinearExprFactory + { + + #region ILinearExprFactory Members + + IFunApp ILinearExprFactory.AtMost(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + IFunApp ILinearExprFactory.Add(IExpr e0, IExpr e1) { + Contract.Requires(e0 != null); + Contract.Requires(e1 != null); Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + IExpr ILinearExprFactory.Term(Rational r, IVariable var) { + Contract.Ensures(Contract.Result<IExpr>() != null); + throw new System.NotImplementedException(); + } + + IFunApp ILinearExprFactory.False { + get { Contract.Ensures(Contract.Result<IFunApp>() != null); throw new System.NotImplementedException(); } + } + + IFunApp ILinearExprFactory.True { + get { Contract.Ensures(Contract.Result<IFunApp>() != null); throw new System.NotImplementedException(); } + } + + IFunApp ILinearExprFactory.And(IExpr p, IExpr q) { + Contract.Requires(p != null); + Contract.Requires(q != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + #endregion + + #region IIntExprFactory Members + + IFunApp IIntExprFactory.Const(BigNum i) { + throw new System.NotImplementedException(); + } + + #endregion + + #region IValueExprFactory Members + + IFunApp IValueExprFactory.Eq(IExpr e0, IExpr e1) { + throw new System.NotImplementedException(); + } + + IFunApp IValueExprFactory.Neq(IExpr e0, IExpr e1) { + throw new System.NotImplementedException(); + } + + #endregion + } + + /// <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> + /// + [ContractClass(typeof(ITypeExprFactoryContracts))] + 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] + bool IsTypeConstant(IExpr/*!*/ t); + + /// <summary> + /// Returns true iff t0 and t1 are types such that t0 and t1 are equal. + /// </summary> + [Pure] + 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] + 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);*/; + } + [ContractClassFor(typeof(ITypeExprFactory))] + public abstract class ITypeExprFactoryContracts : ITypeExprFactory + { + + #region ITypeExprFactory Members + + IExpr ITypeExprFactory.RootType { + get { Contract.Ensures(Contract.Result<IExpr>() != null); throw new System.NotImplementedException(); } + } + + bool ITypeExprFactory.IsTypeConstant(IExpr t) { + Contract.Requires(t != null); + throw new System.NotImplementedException(); + } + + bool ITypeExprFactory.IsTypeEqual(IExpr t0, IExpr t1) { + Contract.Requires(t0 != null); + Contract.Requires(t1 != null); + throw new System.NotImplementedException(); + } + + bool ITypeExprFactory.IsSubType(IExpr t0, IExpr t1) { + Contract.Requires(t0 != null); + Contract.Requires(t1 != null); + throw new System.NotImplementedException(); + } + + IExpr ITypeExprFactory.JoinTypes(IExpr t0, IExpr t1) { + Contract.Requires(t0 != null); + Contract.Requires(t1 != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + throw new System.NotImplementedException(); + } + + IFunApp ITypeExprFactory.IsExactlyA(IExpr e, IExpr type) { + Contract.Requires(e != null); + Contract.Requires(type != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + IFunApp ITypeExprFactory.IsA(IExpr e, IExpr type) { + Contract.Requires(e != null); + Contract.Requires(type != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + throw new System.NotImplementedException(); + } + + #endregion + } +} diff --git a/Source/AIFramework/Expr.cs b/Source/AIFramework/Expr.cs index 58473592..ae2bd4b7 100644 --- a/Source/AIFramework/Expr.cs +++ b/Source/AIFramework/Expr.cs @@ -1,640 +1,640 @@ -//-----------------------------------------------------------------------------
-//
-// 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 System;
- using System.Diagnostics.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 IVariable, IFunApp, ...
- /// </summary>
- [ContractClass(typeof(IExprContracts))]
- 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] object DoVisit(ExprVisitor/*!*/ visitor);
-
- // TODO: Type checking of the expressions.
- }
- [ContractClassFor(typeof(IExpr))]
- public abstract class IExprContracts:IExpr{
- #region IExpr Members
-
-public object DoVisit(ExprVisitor visitor)
-{
- Contract.Requires(visitor != null);
- throw new System.NotImplementedException();
-}
-
-#endregion
-}
-
- /// <summary>
- /// An interface for variables.
- ///
- /// This interface should be implemented by the client.
- /// </summary>
- [ContractClass(typeof(IVariableContracts))]
- public interface IVariable : IExpr
- {
- string/*!*/ Name { get; } // Each client must define the name for variables
- }
- [ContractClassFor(typeof(IVariable))]
- public abstract class IVariableContracts:IVariable{
- string IVariable.Name{get{Contract.Ensures(Contract.Result<string>() != null);throw new NotImplementedException();}
-
- }
-
- #region IExpr Members
-
- object IExpr.DoVisit(ExprVisitor visitor) {
- throw new NotImplementedException();
- }
-
- #endregion
- }
-
- /// <summary>
- /// An interface for function applications.
- ///
- /// This interface should be implemented by the client.
- /// </summary>
- ///
- [ContractClass(typeof(IFunAppContracts))]
- public interface IFunApp : IExpr
- {
- IFunctionSymbol/*!*/ FunctionSymbol { get; }
- IList/*<IExpr!>*//*!*/ Arguments
- {
- [Pure][Rep] get;
-
- }
-
- /// <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 Contract.Requires(this.Arguments.Count == args.Count);
- ;
- }
- [ContractClassFor(typeof(IFunApp))]
-public abstract class IFunAppContracts:IFunApp{
-
-#region IFunApp Members
-
-public IFunctionSymbol FunctionSymbol
-{
- get {Contract.Ensures(Contract.Result<IFunctionSymbol>() != null);
- throw new System.NotImplementedException(); }
-}
-
-public IList Arguments
-{
- get {Contract.Ensures(Contract.Result<IList>() != null);
- Contract.Ensures(Contract.Result<IList>().IsReadOnly);
- throw new System.NotImplementedException(); }
-}
-
-public IFunApp CloneWithArguments(IList args)
-{
- Contract.Requires(args != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
-
-
- throw new System.NotImplementedException();
-}
-
-#endregion
-
-#region IExpr Members
-
-object IExpr.DoVisit(ExprVisitor visitor) {
- throw new NotImplementedException();
-}
-
-#endregion
-}
-
- /// <summary>
- /// An interface for anonymous functions (i.e., lambda expressions)
- /// </summary>
- [ContractClass(typeof(IFunctionContracts))]
- public interface IFunction : IExpr
- {
- IVariable/*!*/ Param { get; }
- AIType/*!*/ ParamType { get; }
- IExpr/*!*/ Body { get; }
-
- IFunction/*!*/ CloneWithBody(IExpr/*!*/ body);
- }
- [ContractClassFor(typeof(IFunction))]
- public abstract class IFunctionContracts:IFunction{
-
- #region IFunction Members
-
- IVariable IFunction.Param {
- get {
- Contract.Ensures(Contract.Result<IVariable>() != null);
- throw new NotImplementedException();
- }
- }
-
- AIType IFunction.ParamType {
- get {
- Contract.Ensures(Contract.Result<AIType>() != null);
- throw new NotImplementedException();
- }
- }
-
- IExpr IFunction.Body {
- get {
- Contract.Ensures(Contract.Result<IExpr>() != null);
- throw new NotImplementedException();
- }
- }
-
- IFunction IFunction.CloneWithBody(IExpr body) {
- Contract.Requires(body != null);
- Contract.Ensures(Contract.Result<IFunction>() != null);
- throw new NotImplementedException();
- }
-
- #endregion
-
- #region IExpr Members
-
- object IExpr.DoVisit(ExprVisitor visitor) {
- throw new NotImplementedException();
- }
-
- #endregion
- }
-
- /// <summary>
- /// An interface representing an expression that at any moment could, in principle, evaluate
- /// to a different value. That is, the abstract interpreter should treat these IExpr's
- /// as unknown values. They are used when there is no other IExpr corresponding to the
- /// expression to be modeled.
- /// </summary>
- public interface IUnknown : IExpr {}
-
- /// <summary>
- /// An abstract class that provides an interface for expression visitors.
- /// </summary>
- [ContractClass(typeof(ExprVisitorContracts))]
- public abstract class ExprVisitor
- {
- public abstract object Default(IExpr/*!*/ expr);
-
- public virtual object VisitVariable(IVariable/*!*/ var){
-Contract.Requires(var != null);
- return Default(var);
- }
-
- public virtual object VisitFunApp(IFunApp/*!*/ funapp){
-Contract.Requires(funapp != null);
- return Default(funapp);
- }
-
- public virtual object VisitFunction(IFunction/*!*/ fun){
-Contract.Requires(fun != null);
- return Default(fun);
- }
- }
- [ContractClassFor(typeof(ExprVisitor))]
- public abstract class ExprVisitorContracts:ExprVisitor{
- public override object Default(IExpr expr)
-{
- Contract.Requires(expr != null); throw new NotImplementedException();
-}}
-
- /// <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){
-Contract.Requires(inexpr != null);
-Contract.Requires(var != null);
-Contract.Requires(subst != null);
-Contract.Ensures(Contract.Result<IExpr>() != null);
- IExpr result = null;
-
- if (inexpr is IVariable)
- {
- result = inexpr.Equals(var) ? subst : inexpr;
- }
- else if (inexpr is IFunApp)
- {
- IFunApp/*!*/ funapp = (IFunApp/*!*/)cce.NonNull(inexpr);
- IList newargs = null;
-
- var x = new System.Collections.Generic.List<IExpr>();
- foreach (IExpr arg in funapp.Arguments){
- x.Add(Substitute(subst,var, arg));
- }
- newargs = new ArrayList(x);
- //newargs = new ArrayList{ IExpr/*!*/ arg in funapp.Arguments; Substitute(subst, var, arg) };
- result = funapp.CloneWithArguments(newargs);
- }
- else if (inexpr is IFunction)
- {
- IFunction/*!*/ fun = (IFunction/*!*/)cce.NonNull(inexpr);
-
- if (fun.Param.Equals(var))
- result = fun;
- else
- result = fun.CloneWithBody(Substitute(subst, var, fun.Body));
- }
- else if (inexpr is IUnknown)
- {
- result = inexpr;
- }
- else
- {
- {Contract.Assert(false);throw new cce.UnreachableException();}
- }
-
- 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){
-Contract.Requires(f != null);
-Contract.Requires(expr != null);
- 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){
-Contract.Requires(subs != null);
-Contract.Requires(f != null);
-Contract.Requires(expr != null);
- IFunApp app = MatchFunctionSymbol(expr,f);
- if (app != null)
- {
- int i = 0; // Note ***0***
- foreach(Matcher/*!*/ s in subs){
-Contract.Assert(s != null);
- if (!s(cce.NonNull((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){
-Contract.Requires(subs != null);
-Contract.Requires(f != null);
-Contract.Requires(expr != null);
- arg0 = null;
-
- IFunApp app = MatchFunctionSymbol(expr,f);
- if (app != null)
- {
- arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]);
-
- int i = 1; // Note ***1***
- foreach(Matcher/*!*/ s in subs){
-Contract.Assert(s != null);
- if (!s(cce.NonNull((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){
-Contract.Requires(subs != null);
-Contract.Requires(sub0 != null);
-Contract.Requires(f != null);
-Contract.Requires(expr != null);
- arg1 = null;
-
- IFunApp app = MatchFunctionSymbol(expr,f);
- if (app != null)
- {
- if (!sub0(cce.NonNull((IExpr/*!*/)app.Arguments[0]))) { return false; }
-
- arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]);
-
- int i = 2; // Note ***2***
- foreach(Matcher/*!*/ s in subs){
-Contract.Assert(s != null);
- if (!s(cce.NonNull((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){
-Contract.Requires(subs != null);
-Contract.Requires(f != null);
-Contract.Requires(expr != null);
- arg0 = null;
- arg1 = null;
-
- IFunApp app = MatchFunctionSymbol(expr,f);
- if (app != null)
- {
- arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]);
- arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]);
-
- int i = 2; // Note ***2***
- foreach(Matcher/*!*/ s in subs){
-Contract.Assert(s != null);
- if (!s(cce.NonNull((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){
-Contract.Requires(subs != null);
-Contract.Requires(f != null);
-Contract.Requires(expr != null);
- arg0 = null;
- arg1 = null;
- arg2 = null;
-
- IFunApp app = MatchFunctionSymbol(expr,f);
- if (app != null)
- {
- arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]);
- arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]);
- arg2 = (IExpr/*!*/)cce.NonNull(app.Arguments[2]);
-
- int i = 3; // Note ***3***
- foreach(Matcher/*!*/ s in subs){
-Contract.Assert(s != null);
- if (!s(cce.NonNull((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>
- [ContractClass(typeof(IFunctionSymbolContracts))]
- public interface IFunctionSymbol
- {
- AIType/*!*/ AIType { [Rep][ResultNotNewlyAllocated]
- get; }
- }
- [ContractClassFor(typeof(IFunctionSymbol))]
- public abstract class IFunctionSymbolContracts:IFunctionSymbol{
- #region IFunctionSymbol Members
-
- AIType IFunctionSymbol.AIType {
- get {
- Contract.Ensures(Contract.Result<AIType>() != null);
- throw new NotImplementedException();
- }
- }
-
- #endregion
- }
-
- /// <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;
- [ContractInvariantMethod]
-void ObjectInvariant()
-{
- Contract.Invariant(argTypes != null);
- Contract.Invariant(retType != null);
-}
-
-
- public FunctionType(params AIType[]/*!*/ types){
-Contract.Requires(types != null);
- Contract.Requires(types.Length >= 2);
- AIType type = types[types.Length-1];
- Contract.Assume(type != null);
- this.retType = type;
- ArrayList argTypes = new ArrayList();
- for (int i = 0; i < types.Length-1; i++)
- {
- type = types[i];
- Contract.Assume(type != null);
- argTypes.Add(types);
- }
- this.argTypes = ArrayList.ReadOnly(argTypes);
- }
-
- public IList/*<AIType!>*//*!*/ Arguments
- {
- [Pure][Rep]
- get
- {
- Contract.Ensures(Contract.Result<IList>() != null);
- Contract.Ensures(Contract.Result<IList>().IsReadOnly);
- return argTypes;
- }
- }
-
- public int Arity
- {
- get { return argTypes.Count; }
- }
-
- public AIType/*!*/ ReturnType
- {
- get {Contract.Ensures(Contract.Result<AIType>() != null); 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>
- ///
- [ContractClass(typeof(IQueryableContracts))]
- 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);
- }
- [ContractClassFor(typeof(IQueryable))]
- public abstract class IQueryableContracts : IQueryable {
- #region IQueryable Members
-
- public Answer CheckPredicate(IExpr pred) {
- Contract.Requires(pred != null);
- throw new NotImplementedException();
- }
-
- public Answer CheckVariableDisequality(IVariable var1, IVariable var2) {
- Contract.Requires(var1 != null);
- Contract.Requires(var2 != null);
- throw new NotImplementedException();
- }
-
- #endregion
- }
-
- 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 CheckedException : System.Exception {
- }
- public class TypeError : CheckedException
- {
- }
-}
+//----------------------------------------------------------------------------- +// +// 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 System; + using System.Diagnostics.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 IVariable, IFunApp, ... + /// </summary> + [ContractClass(typeof(IExprContracts))] + 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] object DoVisit(ExprVisitor/*!*/ visitor); + + // TODO: Type checking of the expressions. + } + [ContractClassFor(typeof(IExpr))] + public abstract class IExprContracts:IExpr{ + #region IExpr Members + +public object DoVisit(ExprVisitor visitor) +{ + Contract.Requires(visitor != null); + throw new System.NotImplementedException(); +} + +#endregion +} + + /// <summary> + /// An interface for variables. + /// + /// This interface should be implemented by the client. + /// </summary> + [ContractClass(typeof(IVariableContracts))] + public interface IVariable : IExpr + { + string/*!*/ Name { get; } // Each client must define the name for variables + } + [ContractClassFor(typeof(IVariable))] + public abstract class IVariableContracts:IVariable{ + string IVariable.Name{get{Contract.Ensures(Contract.Result<string>() != null);throw new NotImplementedException();} + + } + + #region IExpr Members + + object IExpr.DoVisit(ExprVisitor visitor) { + throw new NotImplementedException(); + } + + #endregion + } + + /// <summary> + /// An interface for function applications. + /// + /// This interface should be implemented by the client. + /// </summary> + /// + [ContractClass(typeof(IFunAppContracts))] + public interface IFunApp : IExpr + { + IFunctionSymbol/*!*/ FunctionSymbol { get; } + IList/*<IExpr!>*//*!*/ Arguments + { + [Pure][Rep] get; + + } + + /// <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 Contract.Requires(this.Arguments.Count == args.Count); + ; + } + [ContractClassFor(typeof(IFunApp))] +public abstract class IFunAppContracts:IFunApp{ + +#region IFunApp Members + +public IFunctionSymbol FunctionSymbol +{ + get {Contract.Ensures(Contract.Result<IFunctionSymbol>() != null); + throw new System.NotImplementedException(); } +} + +public IList Arguments +{ + get {Contract.Ensures(Contract.Result<IList>() != null); + Contract.Ensures(Contract.Result<IList>().IsReadOnly); + throw new System.NotImplementedException(); } +} + +public IFunApp CloneWithArguments(IList args) +{ + Contract.Requires(args != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + + + throw new System.NotImplementedException(); +} + +#endregion + +#region IExpr Members + +object IExpr.DoVisit(ExprVisitor visitor) { + throw new NotImplementedException(); +} + +#endregion +} + + /// <summary> + /// An interface for anonymous functions (i.e., lambda expressions) + /// </summary> + [ContractClass(typeof(IFunctionContracts))] + public interface IFunction : IExpr + { + IVariable/*!*/ Param { get; } + AIType/*!*/ ParamType { get; } + IExpr/*!*/ Body { get; } + + IFunction/*!*/ CloneWithBody(IExpr/*!*/ body); + } + [ContractClassFor(typeof(IFunction))] + public abstract class IFunctionContracts:IFunction{ + + #region IFunction Members + + IVariable IFunction.Param { + get { + Contract.Ensures(Contract.Result<IVariable>() != null); + throw new NotImplementedException(); + } + } + + AIType IFunction.ParamType { + get { + Contract.Ensures(Contract.Result<AIType>() != null); + throw new NotImplementedException(); + } + } + + IExpr IFunction.Body { + get { + Contract.Ensures(Contract.Result<IExpr>() != null); + throw new NotImplementedException(); + } + } + + IFunction IFunction.CloneWithBody(IExpr body) { + Contract.Requires(body != null); + Contract.Ensures(Contract.Result<IFunction>() != null); + throw new NotImplementedException(); + } + + #endregion + + #region IExpr Members + + object IExpr.DoVisit(ExprVisitor visitor) { + throw new NotImplementedException(); + } + + #endregion + } + + /// <summary> + /// An interface representing an expression that at any moment could, in principle, evaluate + /// to a different value. That is, the abstract interpreter should treat these IExpr's + /// as unknown values. They are used when there is no other IExpr corresponding to the + /// expression to be modeled. + /// </summary> + public interface IUnknown : IExpr {} + + /// <summary> + /// An abstract class that provides an interface for expression visitors. + /// </summary> + [ContractClass(typeof(ExprVisitorContracts))] + public abstract class ExprVisitor + { + public abstract object Default(IExpr/*!*/ expr); + + public virtual object VisitVariable(IVariable/*!*/ var){ +Contract.Requires(var != null); + return Default(var); + } + + public virtual object VisitFunApp(IFunApp/*!*/ funapp){ +Contract.Requires(funapp != null); + return Default(funapp); + } + + public virtual object VisitFunction(IFunction/*!*/ fun){ +Contract.Requires(fun != null); + return Default(fun); + } + } + [ContractClassFor(typeof(ExprVisitor))] + public abstract class ExprVisitorContracts:ExprVisitor{ + public override object Default(IExpr expr) +{ + Contract.Requires(expr != null); throw new NotImplementedException(); +}} + + /// <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){ +Contract.Requires(inexpr != null); +Contract.Requires(var != null); +Contract.Requires(subst != null); +Contract.Ensures(Contract.Result<IExpr>() != null); + IExpr result = null; + + if (inexpr is IVariable) + { + result = inexpr.Equals(var) ? subst : inexpr; + } + else if (inexpr is IFunApp) + { + IFunApp/*!*/ funapp = (IFunApp/*!*/)cce.NonNull(inexpr); + IList newargs = null; + + var x = new System.Collections.Generic.List<IExpr>(); + foreach (IExpr arg in funapp.Arguments){ + x.Add(Substitute(subst,var, arg)); + } + newargs = new ArrayList(x); + //newargs = new ArrayList{ IExpr/*!*/ arg in funapp.Arguments; Substitute(subst, var, arg) }; + result = funapp.CloneWithArguments(newargs); + } + else if (inexpr is IFunction) + { + IFunction/*!*/ fun = (IFunction/*!*/)cce.NonNull(inexpr); + + if (fun.Param.Equals(var)) + result = fun; + else + result = fun.CloneWithBody(Substitute(subst, var, fun.Body)); + } + else if (inexpr is IUnknown) + { + result = inexpr; + } + else + { + {Contract.Assert(false);throw new cce.UnreachableException();} + } + + 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){ +Contract.Requires(f != null); +Contract.Requires(expr != null); + 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){ +Contract.Requires(subs != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + int i = 0; // Note ***0*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((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){ +Contract.Requires(subs != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + arg0 = null; + + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); + + int i = 1; // Note ***1*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((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){ +Contract.Requires(subs != null); +Contract.Requires(sub0 != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + arg1 = null; + + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + if (!sub0(cce.NonNull((IExpr/*!*/)app.Arguments[0]))) { return false; } + + arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); + + int i = 2; // Note ***2*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((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){ +Contract.Requires(subs != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + arg0 = null; + arg1 = null; + + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); + arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); + + int i = 2; // Note ***2*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((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){ +Contract.Requires(subs != null); +Contract.Requires(f != null); +Contract.Requires(expr != null); + arg0 = null; + arg1 = null; + arg2 = null; + + IFunApp app = MatchFunctionSymbol(expr,f); + if (app != null) + { + arg0 = (IExpr/*!*/)cce.NonNull(app.Arguments[0]); + arg1 = (IExpr/*!*/)cce.NonNull(app.Arguments[1]); + arg2 = (IExpr/*!*/)cce.NonNull(app.Arguments[2]); + + int i = 3; // Note ***3*** + foreach(Matcher/*!*/ s in subs){ +Contract.Assert(s != null); + if (!s(cce.NonNull((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> + [ContractClass(typeof(IFunctionSymbolContracts))] + public interface IFunctionSymbol + { + AIType/*!*/ AIType { [Rep][ResultNotNewlyAllocated] + get; } + } + [ContractClassFor(typeof(IFunctionSymbol))] + public abstract class IFunctionSymbolContracts:IFunctionSymbol{ + #region IFunctionSymbol Members + + AIType IFunctionSymbol.AIType { + get { + Contract.Ensures(Contract.Result<AIType>() != null); + throw new NotImplementedException(); + } + } + + #endregion + } + + /// <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; + [ContractInvariantMethod] +void ObjectInvariant() +{ + Contract.Invariant(argTypes != null); + Contract.Invariant(retType != null); +} + + + public FunctionType(params AIType[]/*!*/ types){ +Contract.Requires(types != null); + Contract.Requires(types.Length >= 2); + AIType type = types[types.Length-1]; + Contract.Assume(type != null); + this.retType = type; + ArrayList argTypes = new ArrayList(); + for (int i = 0; i < types.Length-1; i++) + { + type = types[i]; + Contract.Assume(type != null); + argTypes.Add(types); + } + this.argTypes = ArrayList.ReadOnly(argTypes); + } + + public IList/*<AIType!>*//*!*/ Arguments + { + [Pure][Rep] + get + { + Contract.Ensures(Contract.Result<IList>() != null); + Contract.Ensures(Contract.Result<IList>().IsReadOnly); + return argTypes; + } + } + + public int Arity + { + get { return argTypes.Count; } + } + + public AIType/*!*/ ReturnType + { + get {Contract.Ensures(Contract.Result<AIType>() != null); 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> + /// + [ContractClass(typeof(IQueryableContracts))] + 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); + } + [ContractClassFor(typeof(IQueryable))] + public abstract class IQueryableContracts : IQueryable { + #region IQueryable Members + + public Answer CheckPredicate(IExpr pred) { + Contract.Requires(pred != null); + throw new NotImplementedException(); + } + + public Answer CheckVariableDisequality(IVariable var1, IVariable var2) { + Contract.Requires(var1 != null); + Contract.Requires(var2 != null); + throw new NotImplementedException(); + } + + #endregion + } + + 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 CheckedException : System.Exception { + } + public class TypeError : CheckedException + { + } +} diff --git a/Source/AIFramework/Functional.cs b/Source/AIFramework/Functional.cs index 3b8237bf..51d8562a 100644 --- a/Source/AIFramework/Functional.cs +++ b/Source/AIFramework/Functional.cs @@ -1,430 +1,430 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System.Diagnostics.Contracts;
-
-namespace Microsoft.AbstractInterpretationFramework.Collections {
- using System.Collections;
-
- /// <summary>Represents a functional collection of key/value pairs.</summary>
- /// <filterpriority>2</filterpriority>
- [ContractClass(typeof(IFunctionalMapContracts))]
- 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]
- 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;*/
- }
- }
- [ContractClassFor(typeof(IFunctionalMap))]
- public abstract class IFunctionalMapContracts : IFunctionalMap {
-
- #region IFunctionalMap Members
-
- IFunctionalMap IFunctionalMap.Add(object key, object value) {
- Contract.Requires(key != null);
- Contract.Ensures(Contract.Result<IFunctionalMap>() != null);
-
- throw new System.NotImplementedException();
- }
-
- IFunctionalMap IFunctionalMap.Set(object key, object value) {
- Contract.Requires(key != null);
- Contract.Ensures(Contract.Result<IFunctionalMap>() != null);
-
- throw new System.NotImplementedException();
- }
-
- bool IFunctionalMap.Contains(object key) {
- Contract.Requires(key != null);
-
- throw new System.NotImplementedException();
- }
-
- IDictionaryEnumerator IFunctionalMap.GetEnumerator() {
- throw new System.NotImplementedException();
- }
-
- ICollection IFunctionalMap.Keys {
- get {
- throw new System.NotImplementedException();
- }
- }
-
- IFunctionalMap IFunctionalMap.Remove(object key) {
- Contract.Requires(key != null);
- Contract.Ensures(Contract.Result<IFunctionalMap>() != null);
-
- throw new System.NotImplementedException();
- }
-
- ICollection IFunctionalMap.Values {
- get {
- throw new System.NotImplementedException();
- }
- }
-
- object IFunctionalMap.this[object key] {
- get {
- Contract.Requires(key != null);
- throw new System.NotImplementedException();
- }
- }
-
- #endregion
-
- #region ICollection Members
-
- void ICollection.CopyTo(System.Array array, int index) {
- throw new System.NotImplementedException();
- }
-
- int ICollection.Count {
- get {
- throw new System.NotImplementedException();
- }
- }
-
- bool ICollection.IsSynchronized {
- get {
- throw new System.NotImplementedException();
- }
- }
-
- object ICollection.SyncRoot {
- get {
- throw new System.NotImplementedException();
- }
- }
-
- #endregion
-
- #region IEnumerable Members
-
- IEnumerator IEnumerable.GetEnumerator() {
- throw new System.NotImplementedException();
- }
-
- #endregion
- }
-
-
-
- /// <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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(h != null);
- }
-
-
- /// <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) {
- Contract.Requires(h != null);
- this.h = h;
- // base();
- }
-
- private static readonly IFunctionalMap/*!*/ empty = new FunctionalHashtable();
- public static IFunctionalMap/*!*/ Empty {
- get {
- Contract.Ensures(Contract.Result<IFunctionalMap>() != null);
- return empty;
- }
- }
-
- public IFunctionalMap/*!*/ Add(object/*!*/ key, object value) {
- //Contract.Requires(key != null);
- Contract.Ensures(Contract.Result<IFunctionalMap>() != null);
- Hashtable r = h.Clone() as Hashtable;
- Contract.Assume(r != null);
- r.Add(key, value);
- return new FunctionalHashtable(r);
- }
-
- public IFunctionalMap/*!*/ Set(object/*!*/ key, object value) {
- //Contract.Requires(key != null);
- Contract.Ensures(Contract.Result<IFunctionalMap>() != null);
- Hashtable r = h.Clone() as Hashtable;
-
- Contract.Assume(r != null);
- Contract.Assert(this.Contains(key)); // The entry must be defined
-
- r[key] = value;
- return new FunctionalHashtable(r);
- }
-
- [Pure]
- public bool Contains(object/*!*/ key) {
- //Contract.Requires(key != null);
- return h.Contains(key);
- }
-
- [Pure]
- [GlobalAccess(false)]
- [Escapes(true, false)]
- IEnumerator/*!*/ IEnumerable.GetEnumerator() {
- Contract.Ensures(Contract.Result<IEnumerator>() != null);
-
- 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) {
- //Contract.Requires(key != null);
- Contract.Ensures(Contract.Result<IFunctionalMap>() != null);
- Hashtable r = h.Clone() as Hashtable;
- Contract.Assume(r != null);
- r.Remove(key);
- return new FunctionalHashtable(r);
- }
-
- public ICollection Values {
- get {
- return h.Values;
- }
- }
-
-
- public object this[object/*!*/ key] {
- get {
- //Contract.Requires(key != null);
- return h[key];
- }
- }
-
- public int Count {
- [Pure]
- get {
- return h.Count;
- }
- }
-
- public bool IsSynchronized {
- [Pure]
- get {
- return h.IsSynchronized;
- }
- }
-
- public object/*!*/ SyncRoot {
- [Pure]
- get {
- Contract.Ensures(Contract.Result<object>() != null);
- return h.SyncRoot;
- }
- }
-
- public void CopyTo(System.Array/*!*/ a, int index) {
- //Contract.Requires(a != null);
- 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() {
- Contract.Ensures(Contract.Result<string>() != null);
- 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() {
- Contract.Ensures(Contract.Result<string>() != null);
- return string.Format("({0},{1},{2})", first, second, third);
- }
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; + +namespace Microsoft.AbstractInterpretationFramework.Collections { + using System.Collections; + + /// <summary>Represents a functional collection of key/value pairs.</summary> + /// <filterpriority>2</filterpriority> + [ContractClass(typeof(IFunctionalMapContracts))] + 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] + 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;*/ + } + } + [ContractClassFor(typeof(IFunctionalMap))] + public abstract class IFunctionalMapContracts : IFunctionalMap { + + #region IFunctionalMap Members + + IFunctionalMap IFunctionalMap.Add(object key, object value) { + Contract.Requires(key != null); + Contract.Ensures(Contract.Result<IFunctionalMap>() != null); + + throw new System.NotImplementedException(); + } + + IFunctionalMap IFunctionalMap.Set(object key, object value) { + Contract.Requires(key != null); + Contract.Ensures(Contract.Result<IFunctionalMap>() != null); + + throw new System.NotImplementedException(); + } + + bool IFunctionalMap.Contains(object key) { + Contract.Requires(key != null); + + throw new System.NotImplementedException(); + } + + IDictionaryEnumerator IFunctionalMap.GetEnumerator() { + throw new System.NotImplementedException(); + } + + ICollection IFunctionalMap.Keys { + get { + throw new System.NotImplementedException(); + } + } + + IFunctionalMap IFunctionalMap.Remove(object key) { + Contract.Requires(key != null); + Contract.Ensures(Contract.Result<IFunctionalMap>() != null); + + throw new System.NotImplementedException(); + } + + ICollection IFunctionalMap.Values { + get { + throw new System.NotImplementedException(); + } + } + + object IFunctionalMap.this[object key] { + get { + Contract.Requires(key != null); + throw new System.NotImplementedException(); + } + } + + #endregion + + #region ICollection Members + + void ICollection.CopyTo(System.Array array, int index) { + throw new System.NotImplementedException(); + } + + int ICollection.Count { + get { + throw new System.NotImplementedException(); + } + } + + bool ICollection.IsSynchronized { + get { + throw new System.NotImplementedException(); + } + } + + object ICollection.SyncRoot { + get { + throw new System.NotImplementedException(); + } + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() { + throw new System.NotImplementedException(); + } + + #endregion + } + + + + /// <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; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(h != null); + } + + + /// <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) { + Contract.Requires(h != null); + this.h = h; + // base(); + } + + private static readonly IFunctionalMap/*!*/ empty = new FunctionalHashtable(); + public static IFunctionalMap/*!*/ Empty { + get { + Contract.Ensures(Contract.Result<IFunctionalMap>() != null); + return empty; + } + } + + public IFunctionalMap/*!*/ Add(object/*!*/ key, object value) { + //Contract.Requires(key != null); + Contract.Ensures(Contract.Result<IFunctionalMap>() != null); + Hashtable r = h.Clone() as Hashtable; + Contract.Assume(r != null); + r.Add(key, value); + return new FunctionalHashtable(r); + } + + public IFunctionalMap/*!*/ Set(object/*!*/ key, object value) { + //Contract.Requires(key != null); + Contract.Ensures(Contract.Result<IFunctionalMap>() != null); + Hashtable r = h.Clone() as Hashtable; + + Contract.Assume(r != null); + Contract.Assert(this.Contains(key)); // The entry must be defined + + r[key] = value; + return new FunctionalHashtable(r); + } + + [Pure] + public bool Contains(object/*!*/ key) { + //Contract.Requires(key != null); + return h.Contains(key); + } + + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + IEnumerator/*!*/ IEnumerable.GetEnumerator() { + Contract.Ensures(Contract.Result<IEnumerator>() != null); + + 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) { + //Contract.Requires(key != null); + Contract.Ensures(Contract.Result<IFunctionalMap>() != null); + Hashtable r = h.Clone() as Hashtable; + Contract.Assume(r != null); + r.Remove(key); + return new FunctionalHashtable(r); + } + + public ICollection Values { + get { + return h.Values; + } + } + + + public object this[object/*!*/ key] { + get { + //Contract.Requires(key != null); + return h[key]; + } + } + + public int Count { + [Pure] + get { + return h.Count; + } + } + + public bool IsSynchronized { + [Pure] + get { + return h.IsSynchronized; + } + } + + public object/*!*/ SyncRoot { + [Pure] + get { + Contract.Ensures(Contract.Result<object>() != null); + return h.SyncRoot; + } + } + + public void CopyTo(System.Array/*!*/ a, int index) { + //Contract.Requires(a != null); + 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() { + Contract.Ensures(Contract.Result<string>() != null); + 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() { + Contract.Ensures(Contract.Result<string>() != null); + return string.Format("({0},{1},{2})", first, second, third); + } + } +} diff --git a/Source/AIFramework/Lattice.cs b/Source/AIFramework/Lattice.cs index ab10be9a..1796f1f6 100644 --- a/Source/AIFramework/Lattice.cs +++ b/Source/AIFramework/Lattice.cs @@ -1,960 +1,960 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-namespace Microsoft.AbstractInterpretationFramework {
- using System;
- using System.Diagnostics.Contracts;
- using System.Collections;
- using G = System.Collections.Generic;
- using System.Diagnostics;
- using Microsoft.AbstractInterpretationFramework.Collections;
- using Microsoft.Boogie;
-
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System; + using System.Diagnostics.Contracts; + using System.Collections; + using G = System.Collections.Generic; + using System.Diagnostics; + using Microsoft.AbstractInterpretationFramework.Collections; + using Microsoft.Boogie; + using ArraySet = Microsoft.Boogie.GSet<object>; - using IMutableSet = Microsoft.Boogie.GSet<object>;
- using HashSet = Microsoft.Boogie.GSet<object>;
- using ISet = Microsoft.Boogie.GSet<object>;
- using Set = Microsoft.Boogie.GSet<object>;
-
-
- /// <summary>
- /// Specifies the operations (e.g., join) on a mathematical lattice that depend
- /// only on the elements of the lattice.
- /// </summary>
- [ContractClass(typeof(MathematicalLatticeContracts))]
- public abstract class MathematicalLattice {
- #region Element
- /// <summary>
- /// An element of the lattice. This class should be derived from in any
- /// implementation of MathematicalLattice.
- /// </summary>
- [ContractClass(typeof(ElementContracts))]
- 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) {
- Contract.Requires(msg != null);
- 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();
-
- }
- [ContractClassFor(typeof(Element))]
- public abstract class ElementContracts : Element {
- public override Element Clone() {
- Contract.Ensures(Contract.Result<Element>() != null);
- throw new NotImplementedException();
-
- }
-
- public override System.Collections.Generic.ICollection<IVariable> FreeVariables() {
- Contract.Ensures(cce.NonNullElements(Contract.Result<G.ICollection<IVariable>>()));
- Contract.Ensures(Contract.Result<System.Collections.Generic.ICollection<IVariable>>().IsReadOnly);
- throw new System.NotImplementedException();
- }
- }
- #endregion
-
- 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 <= 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) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- 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) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- 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) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- return LowerThan(b, a);
- }
-
- // Are 'a' and 'b' equivalent?
- //
- public bool Equivalent(Element/*!*/ a, Element/*!*/ b) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- 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) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- 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) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- 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) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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)));
- }
- }
- [ContractClassFor(typeof(MathematicalLattice))]
- public abstract class MathematicalLatticeContracts : MathematicalLattice {
- public override MathematicalLattice.Element Top {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- throw new NotImplementedException();
- }
- }
-
- public override MathematicalLattice.Element Bottom {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- throw new NotImplementedException();
- }
- }
-
- public override bool IsTop(MathematicalLattice.Element e) {
- Contract.Requires(e != null);
- throw new NotImplementedException();
- }
-
- public override bool IsBottom(MathematicalLattice.Element e) {
- Contract.Requires(e != null);
- throw new NotImplementedException();
- }
-
- protected override bool AtMost(MathematicalLattice.Element a, MathematicalLattice.Element b) {
- Contract.Requires(a != null);
- Contract.Requires(b != null);
- throw new NotImplementedException();
- }
-
- public override MathematicalLattice.Element NontrivialJoin(MathematicalLattice.Element a, MathematicalLattice.Element b) {
- Contract.Requires(a != null);
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- throw new NotImplementedException();
- }
-
- public override MathematicalLattice.Element NontrivialMeet(MathematicalLattice.Element a, MathematicalLattice.Element b) {
- Contract.Requires(a != null);
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- throw new NotImplementedException();
- }
-
- public override MathematicalLattice.Element Widen(MathematicalLattice.Element a, MathematicalLattice.Element b) {
- Contract.Requires(a != null);
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- throw new NotImplementedException();
- }
- }
-
-
- /// <summary>
- /// Provides an abstract interface for the operations of a lattice specific
- /// to abstract interpretation (i.e., that deals with the expression language).
- /// </summary>
- [ContractClass(typeof(LatticeContracts))]
- public abstract class Lattice : MathematicalLattice {
- internal readonly IValueExprFactory/*!*/ valueExprFactory;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(valueExprFactory != null);
- }
-
-
- public Lattice(IValueExprFactory/*!*/ valueExprFactory) {
- Contract.Requires(valueExprFactory != null);
- 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) {
- //Contract.Requires(b != null);
- //Contract.Requires(a != null);
- return AtMost(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map);
- }
-
- protected virtual bool AtMost(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) {
- Contract.Requires(bToResult != null);
- Contract.Requires(b != null);
- Contract.Requires(aToResult != null);
- Contract.Requires(a != null);
- return AtMost(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult));
- }
-
- public bool LowerThan(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) {
- Contract.Requires(bToResult != null);
- Contract.Requires(b != null);
- Contract.Requires(aToResult != null);
- Contract.Requires(a != null);
- 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) {
- Contract.Requires(bToResult != null);
- Contract.Requires(b != null);
- Contract.Requires(aToResult != null);
- Contract.Requires(a != null);
- 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) {
- //Contract.Requires(b != null);
- //Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- return NontrivialJoin(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map);
- }
-
- public virtual Element/*!*/ NontrivialJoin(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) {
- Contract.Requires(bToResult != null);
- Contract.Requires(b != null);
- Contract.Requires(aToResult != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- return NontrivialJoin(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult));
- }
-
- public Element/*!*/ Join(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) {
- Contract.Requires(bToResult != null);
- Contract.Requires(b != null);
- Contract.Requires(aToResult != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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) {
- //Contract.Requires(b != null);
- //Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- return Widen(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map);
- }
-
- public virtual Element/*!*/ Widen(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) {
- Contract.Requires(bToResult != null);
- Contract.Requires(b != null);
- Contract.Requires(aToResult != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- return Widen(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult));
- }
-
-
-
- /// <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) {
- Contract.Requires(propExprFactory != null);
- Contract.Requires(valExprFactory != null);
- Contract.Requires(e != null);
- Contract.Requires(var1 != null);
- Contract.Requires(var2 != null);
- return this.CheckPredicate(e, propExprFactory.Not(valExprFactory.Eq(var1, var2)));
- }
-
- private Element/*!*/ ApplyCombineNameMap(Element/*!*/ e, ICombineNameMap/*!*/ eToResult) {
- Contract.Requires(eToResult != null);
- Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- Element/*!*/ result = e;
-
- foreach (G.KeyValuePair<IVariable/*!*/, ISet/*<IVariable!>*//*!*/> entry in eToResult.GetSourceToResult()) {
- IVariable/*!*/ sourceName = entry.Key;
- Contract.Assert(sourceName != null);
- ISet/*<IVariable!*//*!*/ resultNames = entry.Value;
- Contract.Assert(resultNames != null);
- // 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;
- Contract.Assert(representative != null);
-
- foreach (IVariable/*!*/ rname in resultNames) {
- Contract.Assert(rname != null);
- // 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/*!*/>();
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Map != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary1) && Contract.ForAll(emptyDictionary1.Values, set =>/*cce.NonNullElements(set)*/set != null));
- Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary2));
- Contract.Invariant(indexMap != null);
- Contract.Invariant(reverseIndexMap != null);
-
- }
-
-
- public ISet/*<IVariable!>*//*?*/ GetResultNames(IVariable/*!*/ srcname) {
- //Contract.Requires(srcname != null);
- ArraySet a = new ArraySet();
- a.Add(srcname);
- return a;
- }
-
- public IVariable/*?*/ GetSourceName(IVariable/*!*/ resname) {
- //Contract.Requires(resname != null);
- return resname;
- }
-
- //TODO: uncomment when works in compiler
- //public G.IEnumerable<G.KeyValuePair<IVariable!,ISet/*<IVariable!>*/!>> GetSourceToResult()
- public IEnumerable/*!*/ GetSourceToResult() {
- Contract.Ensures(Contract.Result<IEnumerable>() != null);
- return emptyDictionary1;
- }
-
- //public G.IEnumerable<G.KeyValuePair<IVariable!,IVariable!>> GetResultToSource()
- public IEnumerable/*!*/ GetResultToSource() {
- Contract.Ensures(Contract.Result<IEnumerable>() != null);
- return emptyDictionary2;
- }
-
- private IdentityCombineNameMap() {
- }
- }
-
- #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 {
- Contract.Ensures(Contract.Result<object>() != null);
- return cce.NonNull(this.GetType());
- }
- }
-
- public int Index {
- get {
- object unique = this.UniqueId;
- if (indexMap.ContainsKey(unique)) {
- object index = indexMap[unique];
- Contract.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>
- /// 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);
-
- public abstract string/*!*/ ToString(Element/*!*/ e); // for debugging
-
- }
- [ContractClassFor(typeof(Lattice))]
- abstract class LatticeContracts : Lattice {
- public LatticeContracts()
- : base(null) {
- }
- public override IExpr ToPredicate(MathematicalLattice.Element e) {
- Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- throw new NotImplementedException();
- }
- public override bool Understands(IFunctionSymbol f, IList args) {
- Contract.Requires(f != null);
- Contract.Requires(args != null);
- throw new NotImplementedException();
- }
- public override IExpr EquivalentExpr(MathematicalLattice.Element e, IQueryable q, IExpr expr, IVariable var, Set prohibitedVars) {
- Contract.Requires(e != null);
- Contract.Requires(q != null);
- Contract.Requires(expr != null);
- Contract.Requires(var != null);
- Contract.Requires(prohibitedVars != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- throw new NotImplementedException();
- }
- public override Answer CheckPredicate(MathematicalLattice.Element e, IExpr pred) {
- Contract.Requires(e != null);
- Contract.Requires(pred != null);
- throw new NotImplementedException();
- }
- public override Answer CheckVariableDisequality(MathematicalLattice.Element e, IVariable var1, IVariable var2) {
- Contract.Requires(e != null);
- Contract.Requires(var1 != null);
- Contract.Requires(var2 != null);
- throw new NotImplementedException();
- }
- public override string ToString(Element e) {
- Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<string>() != null);
- throw new NotImplementedException();
- }
- public override MathematicalLattice.Element Eliminate(MathematicalLattice.Element e, IVariable variable) {
- Contract.Requires(e != null);
- Contract.Requires(variable != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- throw new NotImplementedException();
- }
- public override MathematicalLattice.Element Rename(MathematicalLattice.Element e, IVariable oldName, IVariable newName) {
- Contract.Requires(e != null);
- Contract.Requires(oldName != null);
- Contract.Requires(newName != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- throw new NotImplementedException();
- }
- public override MathematicalLattice.Element Constrain(MathematicalLattice.Element e, IExpr expr) {
- Contract.Requires(e != null);
- Contract.Requires(expr != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- throw new NotImplementedException();
- }
- }
-
- /// <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>
- [ContractClass(typeof(ICombineNameMapContracts))]
- 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();
- }
- [ContractClassFor(typeof(ICombineNameMap))]
- public abstract class ICombineNameMapContracts : ICombineNameMap {
- #region ICombineNameMap Members
-
- public Set GetResultNames(IVariable srcname) {
- Contract.Requires(srcname != null);
- throw new NotImplementedException();
- }
-
- public IVariable GetSourceName(IVariable resname) {
- Contract.Requires(resname != null);
- throw new NotImplementedException();
- }
-
- public IEnumerable GetSourceToResult() {
- Contract.Ensures(Contract.Result<IEnumerable>() != null);
- throw new NotImplementedException();
- }
-
- public IEnumerable GetResultToSource() {
- Contract.Ensures(Contract.Result<IEnumerable>() != null);
- throw new NotImplementedException();
- }
-
- #endregion
- }
-
- /// <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 {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(lattice != null);
- }
-
- 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) {
- Contract.Requires(lattice != null);
- this.lattice = lattice;
- // base(lattice.valueExprFactory);
- }
-
- public override Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable) {
- //Contract.Requires(variable != null);
- //Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- eliminateCount++;
- return lattice.Eliminate(e, variable);
- }
-
- public override Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName) {
- //Contract.Requires(newName != null);
- //Contract.Requires(oldName != null);
- //Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- renameCount++;
- return lattice.Rename(e, oldName, newName);
- }
-
- public override Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr) {
- //Contract.Requires(expr != null);
- //Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- constrainCount++;
- return lattice.Constrain(e, expr);
- }
-
-
- public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) {
- //Contract.Requires(args != null);
- //Contract.Requires(f != null);
- understandsCount++;
- return lattice.Understands(f, args);
- }
-
-
- public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/*<IVariable!>*//*!*/ prohibitedVars) {
- //Contract.Requires(prohibitedVars != null);
- //Contract.Requires(var != null);
- //Contract.Requires(expr != null);
- //Contract.Requires(q != null);
- //Contract.Requires(e != null);
- equivalentExprCount++;
- return lattice.EquivalentExpr(e, q, expr, var, prohibitedVars);
- }
-
-
- public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) {
- //Contract.Requires(pred != null);
- //Contract.Requires(e != null);
- checkPredicateCount++;
- return lattice.CheckPredicate(e, pred);
- }
-
-
- public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) {
- //Contract.Requires(var2 != null);
- //Contract.Requires(var1 != null);
- //Contract.Requires(e != null);
- checkVariableDisequalityCount++;
- return lattice.CheckVariableDisequality(e, var1, var2);
- }
-
-
-
- public override IExpr/*!*/ ToPredicate(Element/*!*/ e) {
- //Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- toPredicateCount++;
- return lattice.ToPredicate(e);
- }
-
- public override string/*!*/ ToString(Element/*!*/ e) {
- //Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<string>() != null);
- return lattice.ToString(e);
- }
-
- [Pure]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- 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) {
- //Contract.Requires(b != null);
- //Contract.Requires(a != null);
- atMostCount++;
- return lattice.LowerThan(a, b);
- }
-
- public override Element/*!*/ Top {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- topCount++;
- return lattice.Top;
- }
- }
- public override Element/*!*/ Bottom {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- bottomCount++;
- return lattice.Bottom;
- }
- }
-
- public override bool IsTop(Element/*!*/ e) {
- //Contract.Requires(e != null);
- isTopCount++;
- return lattice.IsTop(e);
- }
-
- public override bool IsBottom(Element/*!*/ e) {
- //Contract.Requires(e != null);
- isBottomCount++;
- return lattice.IsBottom(e);
- }
-
- public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) {
- //Contract.Requires(b != null);
- //Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- joinCount++;
- return lattice.NontrivialJoin(a, b);
- }
-
- public override Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) {
- //Contract.Requires(b != null);
- //Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- meetCount++;
- return lattice.NontrivialMeet(a, b);
- }
-
- public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) {
- //Contract.Requires(b != null);
- //Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- widenCount++;
- return lattice.Widen(a, b);
- }
-
- public override void Validate() {
- base.Validate();
- lattice.Validate();
- }
-
- protected override object/*!*/ UniqueId {
- get {
- Contract.Ensures(Contract.Result<object>() != null);
- // 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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(lattice != null);
- Contract.Invariant(element != null);
- }
-
-
- public LatticeQueryable(Lattice/*!*/ lattice, Lattice.Element/*!*/ element) {
- Contract.Requires(element != null);
- Contract.Requires(lattice != null);
- this.lattice = lattice;
- this.element = element;
- // base();
- }
-
- public Answer CheckPredicate(IExpr/*!*/ pred) {
- //Contract.Requires(pred != null);
- return lattice.CheckPredicate(element, pred);
- }
-
- public Answer CheckVariableDisequality(IVariable/*!*/ var1, IVariable/*!*/ var2) {
- //Contract.Requires(var2 != null);
- //Contract.Requires(var1 != null);
- return lattice.CheckVariableDisequality(element, var1, var2);
- }
- }
-}
+ using IMutableSet = Microsoft.Boogie.GSet<object>; + using HashSet = Microsoft.Boogie.GSet<object>; + using ISet = Microsoft.Boogie.GSet<object>; + using Set = Microsoft.Boogie.GSet<object>; + + + /// <summary> + /// Specifies the operations (e.g., join) on a mathematical lattice that depend + /// only on the elements of the lattice. + /// </summary> + [ContractClass(typeof(MathematicalLatticeContracts))] + public abstract class MathematicalLattice { + #region Element + /// <summary> + /// An element of the lattice. This class should be derived from in any + /// implementation of MathematicalLattice. + /// </summary> + [ContractClass(typeof(ElementContracts))] + 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) { + Contract.Requires(msg != null); + 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(); + + } + [ContractClassFor(typeof(Element))] + public abstract class ElementContracts : Element { + public override Element Clone() { + Contract.Ensures(Contract.Result<Element>() != null); + throw new NotImplementedException(); + + } + + public override System.Collections.Generic.ICollection<IVariable> FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result<G.ICollection<IVariable>>())); + Contract.Ensures(Contract.Result<System.Collections.Generic.ICollection<IVariable>>().IsReadOnly); + throw new System.NotImplementedException(); + } + } + #endregion + + 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 <= 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) { + Contract.Requires(b != null); + Contract.Requires(a != null); + 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) { + Contract.Requires(b != null); + Contract.Requires(a != null); + 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) { + Contract.Requires(b != null); + Contract.Requires(a != null); + return LowerThan(b, a); + } + + // Are 'a' and 'b' equivalent? + // + public bool Equivalent(Element/*!*/ a, Element/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + 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) { + Contract.Requires(b != null); + Contract.Requires(a != null); + 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) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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) { + Contract.Requires(b != null); + Contract.Requires(a != null); + 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) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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))); + } + } + [ContractClassFor(typeof(MathematicalLattice))] + public abstract class MathematicalLatticeContracts : MathematicalLattice { + public override MathematicalLattice.Element Top { + get { + Contract.Ensures(Contract.Result<Element>() != null); + throw new NotImplementedException(); + } + } + + public override MathematicalLattice.Element Bottom { + get { + Contract.Ensures(Contract.Result<Element>() != null); + throw new NotImplementedException(); + } + } + + public override bool IsTop(MathematicalLattice.Element e) { + Contract.Requires(e != null); + throw new NotImplementedException(); + } + + public override bool IsBottom(MathematicalLattice.Element e) { + Contract.Requires(e != null); + throw new NotImplementedException(); + } + + protected override bool AtMost(MathematicalLattice.Element a, MathematicalLattice.Element b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + throw new NotImplementedException(); + } + + public override MathematicalLattice.Element NontrivialJoin(MathematicalLattice.Element a, MathematicalLattice.Element b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + Contract.Ensures(Contract.Result<Element>() != null); + throw new NotImplementedException(); + } + + public override MathematicalLattice.Element NontrivialMeet(MathematicalLattice.Element a, MathematicalLattice.Element b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + Contract.Ensures(Contract.Result<Element>() != null); + throw new NotImplementedException(); + } + + public override MathematicalLattice.Element Widen(MathematicalLattice.Element a, MathematicalLattice.Element b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + Contract.Ensures(Contract.Result<Element>() != null); + throw new NotImplementedException(); + } + } + + + /// <summary> + /// Provides an abstract interface for the operations of a lattice specific + /// to abstract interpretation (i.e., that deals with the expression language). + /// </summary> + [ContractClass(typeof(LatticeContracts))] + public abstract class Lattice : MathematicalLattice { + internal readonly IValueExprFactory/*!*/ valueExprFactory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(valueExprFactory != null); + } + + + public Lattice(IValueExprFactory/*!*/ valueExprFactory) { + Contract.Requires(valueExprFactory != null); + 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) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + return AtMost(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); + } + + protected virtual bool AtMost(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + return AtMost(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); + } + + public bool LowerThan(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + 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) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + 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) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result<Element>() != null); + return NontrivialJoin(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); + } + + public virtual Element/*!*/ NontrivialJoin(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<Element>() != null); + return NontrivialJoin(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); + } + + public Element/*!*/ Join(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result<Element>() != null); + return Widen(a, IdentityCombineNameMap.Map, b, IdentityCombineNameMap.Map); + } + + public virtual Element/*!*/ Widen(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + Contract.Requires(bToResult != null); + Contract.Requires(b != null); + Contract.Requires(aToResult != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<Element>() != null); + return Widen(ApplyCombineNameMap(a, aToResult), ApplyCombineNameMap(b, bToResult)); + } + + + + /// <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) { + Contract.Requires(propExprFactory != null); + Contract.Requires(valExprFactory != null); + Contract.Requires(e != null); + Contract.Requires(var1 != null); + Contract.Requires(var2 != null); + return this.CheckPredicate(e, propExprFactory.Not(valExprFactory.Eq(var1, var2))); + } + + private Element/*!*/ ApplyCombineNameMap(Element/*!*/ e, ICombineNameMap/*!*/ eToResult) { + Contract.Requires(eToResult != null); + Contract.Requires(e != null); + Contract.Ensures(Contract.Result<Element>() != null); + Element/*!*/ result = e; + + foreach (G.KeyValuePair<IVariable/*!*/, ISet/*<IVariable!>*//*!*/> entry in eToResult.GetSourceToResult()) { + IVariable/*!*/ sourceName = entry.Key; + Contract.Assert(sourceName != null); + ISet/*<IVariable!*//*!*/ resultNames = entry.Value; + Contract.Assert(resultNames != null); + // 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; + Contract.Assert(representative != null); + + foreach (IVariable/*!*/ rname in resultNames) { + Contract.Assert(rname != null); + // 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/*!*/>(); + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Map != null); + Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary1) && Contract.ForAll(emptyDictionary1.Values, set =>/*cce.NonNullElements(set)*/set != null)); + Contract.Invariant(cce.NonNullDictionaryAndValues(emptyDictionary2)); + Contract.Invariant(indexMap != null); + Contract.Invariant(reverseIndexMap != null); + + } + + + public ISet/*<IVariable!>*//*?*/ GetResultNames(IVariable/*!*/ srcname) { + //Contract.Requires(srcname != null); + ArraySet a = new ArraySet(); + a.Add(srcname); + return a; + } + + public IVariable/*?*/ GetSourceName(IVariable/*!*/ resname) { + //Contract.Requires(resname != null); + return resname; + } + + //TODO: uncomment when works in compiler + //public G.IEnumerable<G.KeyValuePair<IVariable!,ISet/*<IVariable!>*/!>> GetSourceToResult() + public IEnumerable/*!*/ GetSourceToResult() { + Contract.Ensures(Contract.Result<IEnumerable>() != null); + return emptyDictionary1; + } + + //public G.IEnumerable<G.KeyValuePair<IVariable!,IVariable!>> GetResultToSource() + public IEnumerable/*!*/ GetResultToSource() { + Contract.Ensures(Contract.Result<IEnumerable>() != null); + return emptyDictionary2; + } + + private IdentityCombineNameMap() { + } + } + + #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 { + Contract.Ensures(Contract.Result<object>() != null); + return cce.NonNull(this.GetType()); + } + } + + public int Index { + get { + object unique = this.UniqueId; + if (indexMap.ContainsKey(unique)) { + object index = indexMap[unique]; + Contract.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> + /// 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); + + public abstract string/*!*/ ToString(Element/*!*/ e); // for debugging + + } + [ContractClassFor(typeof(Lattice))] + abstract class LatticeContracts : Lattice { + public LatticeContracts() + : base(null) { + } + public override IExpr ToPredicate(MathematicalLattice.Element e) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + throw new NotImplementedException(); + } + public override bool Understands(IFunctionSymbol f, IList args) { + Contract.Requires(f != null); + Contract.Requires(args != null); + throw new NotImplementedException(); + } + public override IExpr EquivalentExpr(MathematicalLattice.Element e, IQueryable q, IExpr expr, IVariable var, Set prohibitedVars) { + Contract.Requires(e != null); + Contract.Requires(q != null); + Contract.Requires(expr != null); + Contract.Requires(var != null); + Contract.Requires(prohibitedVars != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + throw new NotImplementedException(); + } + public override Answer CheckPredicate(MathematicalLattice.Element e, IExpr pred) { + Contract.Requires(e != null); + Contract.Requires(pred != null); + throw new NotImplementedException(); + } + public override Answer CheckVariableDisequality(MathematicalLattice.Element e, IVariable var1, IVariable var2) { + Contract.Requires(e != null); + Contract.Requires(var1 != null); + Contract.Requires(var2 != null); + throw new NotImplementedException(); + } + public override string ToString(Element e) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result<string>() != null); + throw new NotImplementedException(); + } + public override MathematicalLattice.Element Eliminate(MathematicalLattice.Element e, IVariable variable) { + Contract.Requires(e != null); + Contract.Requires(variable != null); + Contract.Ensures(Contract.Result<Element>() != null); + throw new NotImplementedException(); + } + public override MathematicalLattice.Element Rename(MathematicalLattice.Element e, IVariable oldName, IVariable newName) { + Contract.Requires(e != null); + Contract.Requires(oldName != null); + Contract.Requires(newName != null); + Contract.Ensures(Contract.Result<Element>() != null); + throw new NotImplementedException(); + } + public override MathematicalLattice.Element Constrain(MathematicalLattice.Element e, IExpr expr) { + Contract.Requires(e != null); + Contract.Requires(expr != null); + Contract.Ensures(Contract.Result<Element>() != null); + throw new NotImplementedException(); + } + } + + /// <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> + [ContractClass(typeof(ICombineNameMapContracts))] + 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(); + } + [ContractClassFor(typeof(ICombineNameMap))] + public abstract class ICombineNameMapContracts : ICombineNameMap { + #region ICombineNameMap Members + + public Set GetResultNames(IVariable srcname) { + Contract.Requires(srcname != null); + throw new NotImplementedException(); + } + + public IVariable GetSourceName(IVariable resname) { + Contract.Requires(resname != null); + throw new NotImplementedException(); + } + + public IEnumerable GetSourceToResult() { + Contract.Ensures(Contract.Result<IEnumerable>() != null); + throw new NotImplementedException(); + } + + public IEnumerable GetResultToSource() { + Contract.Ensures(Contract.Result<IEnumerable>() != null); + throw new NotImplementedException(); + } + + #endregion + } + + /// <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 { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(lattice != null); + } + + 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) { + Contract.Requires(lattice != null); + this.lattice = lattice; + // base(lattice.valueExprFactory); + } + + public override Element/*!*/ Eliminate(Element/*!*/ e, IVariable/*!*/ variable) { + //Contract.Requires(variable != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result<Element>() != null); + eliminateCount++; + return lattice.Eliminate(e, variable); + } + + public override Element/*!*/ Rename(Element/*!*/ e, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + //Contract.Requires(newName != null); + //Contract.Requires(oldName != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result<Element>() != null); + renameCount++; + return lattice.Rename(e, oldName, newName); + } + + public override Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr) { + //Contract.Requires(expr != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result<Element>() != null); + constrainCount++; + return lattice.Constrain(e, expr); + } + + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + understandsCount++; + return lattice.Understands(f, args); + } + + + public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/*<IVariable!>*//*!*/ prohibitedVars) { + //Contract.Requires(prohibitedVars != null); + //Contract.Requires(var != null); + //Contract.Requires(expr != null); + //Contract.Requires(q != null); + //Contract.Requires(e != null); + equivalentExprCount++; + return lattice.EquivalentExpr(e, q, expr, var, prohibitedVars); + } + + + public override Answer CheckPredicate(Element/*!*/ e, IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + //Contract.Requires(e != null); + checkPredicateCount++; + return lattice.CheckPredicate(e, pred); + } + + + public override Answer CheckVariableDisequality(Element/*!*/ e, IVariable/*!*/ var1, IVariable/*!*/ var2) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + //Contract.Requires(e != null); + checkVariableDisequalityCount++; + return lattice.CheckVariableDisequality(e, var1, var2); + } + + + + public override IExpr/*!*/ ToPredicate(Element/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + toPredicateCount++; + return lattice.ToPredicate(e); + } + + public override string/*!*/ ToString(Element/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result<string>() != null); + return lattice.ToString(e); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result<string>() != null); + 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) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + atMostCount++; + return lattice.LowerThan(a, b); + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result<Element>() != null); + topCount++; + return lattice.Top; + } + } + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result<Element>() != null); + bottomCount++; + return lattice.Bottom; + } + } + + public override bool IsTop(Element/*!*/ e) { + //Contract.Requires(e != null); + isTopCount++; + return lattice.IsTop(e); + } + + public override bool IsBottom(Element/*!*/ e) { + //Contract.Requires(e != null); + isBottomCount++; + return lattice.IsBottom(e); + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result<Element>() != null); + joinCount++; + return lattice.NontrivialJoin(a, b); + } + + public override Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result<Element>() != null); + meetCount++; + return lattice.NontrivialMeet(a, b); + } + + public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires(b != null); + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result<Element>() != null); + widenCount++; + return lattice.Widen(a, b); + } + + public override void Validate() { + base.Validate(); + lattice.Validate(); + } + + protected override object/*!*/ UniqueId { + get { + Contract.Ensures(Contract.Result<object>() != null); + // 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; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(lattice != null); + Contract.Invariant(element != null); + } + + + public LatticeQueryable(Lattice/*!*/ lattice, Lattice.Element/*!*/ element) { + Contract.Requires(element != null); + Contract.Requires(lattice != null); + this.lattice = lattice; + this.element = element; + // base(); + } + + public Answer CheckPredicate(IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + return lattice.CheckPredicate(element, pred); + } + + public Answer CheckVariableDisequality(IVariable/*!*/ var1, IVariable/*!*/ var2) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + return lattice.CheckVariableDisequality(element, var1, var2); + } + } +} diff --git a/Source/AIFramework/Logger.cs b/Source/AIFramework/Logger.cs index aa7c5979..5b455ab0 100644 --- a/Source/AIFramework/Logger.cs +++ b/Source/AIFramework/Logger.cs @@ -1,56 +1,56 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-namespace Microsoft.AbstractInterpretationFramework {
- using System;
- using System.Diagnostics;
- using System.Diagnostics.Contracts;
-
- public class Logger {
- private string/*!*/ dbgmsgContext;
- private static int contextWidth = 0;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(dbgmsgContext != null);
- Contract.Invariant(dbgmsgIndent != null);
- }
-
-
- public bool Enabled = false;
-
- public Logger(string/*!*/ contextMsg) {
- Contract.Requires(contextMsg != null);
- 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);
- }
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System; + using System.Diagnostics; + using System.Diagnostics.Contracts; + + public class Logger { + private string/*!*/ dbgmsgContext; + private static int contextWidth = 0; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(dbgmsgContext != null); + Contract.Invariant(dbgmsgIndent != null); + } + + + public bool Enabled = false; + + public Logger(string/*!*/ contextMsg) { + Contract.Requires(contextMsg != null); + 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.cs b/Source/AIFramework/MultiLattice.cs index ba9aa752..4c9de5f0 100644 --- a/Source/AIFramework/MultiLattice.cs +++ b/Source/AIFramework/MultiLattice.cs @@ -1,647 +1,647 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-namespace Microsoft.AbstractInterpretationFramework {
- using System.Diagnostics.Contracts;
- using System.Collections;
- using System.Collections.Generic;
- using System.Diagnostics;
- using Microsoft.AbstractInterpretationFramework.Collections;
-
- using Microsoft.Boogie;
-
- using ISet = Microsoft.Boogie.GSet<object>;
- using Set = Microsoft.Boogie.GSet<object>;
-
-
- /// <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) {
- Contract.Requires(other != null);
- Element[] otherEPL = other.elementPerLattice;
- if (otherEPL != null) {
- Element[] newEPL = new Element[otherEPL.Length];
- for (int i = 0; i < newEPL.Length; i++) {
- newEPL[i] = (Element)(cce.NonNull(otherEPL[i])).Clone();
- }
- this.elementPerLattice = newEPL;
- }
- }
-
- public override Element/*!*/ Clone() {
- Contract.Ensures(Contract.Result<Element>() != null);
- return new Elt(this);
- }
-
- [Pure]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- // 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) {
- //Contract.Requires(msg != null);
- System.Console.WriteLine("MultiLattice.Elt.Dump({0})", msg);
- Element[] epl = this.elementPerLattice;
- if (epl != null) {
- foreach (Element/*!*/ e in epl) {
- Contract.Assert(e != null);
- e.Dump(msg);
- }
- }
- }
-
- [Pure]
- public override ICollection<IVariable/*!*/>/*!*/ FreeVariables() {
- Contract.Ensures(cce.NonNullElements(Contract.Result<ICollection<IVariable>>()));
- List<IVariable/*!*/>/*!*/ list = new List<IVariable/*!*/>();
- for (int i = 0; i < this.Count; i++) {
- list.AddRange(cce.NonNull(this[i]).FreeVariables());
- }
- return cce.NonNull(list.AsReadOnly());
- }
-
- public static Elt/*!*/ Top(ArrayList/*<Lattice>*//*!*/ lattices) {
- Contract.Requires(lattices != null);
- Contract.Ensures(Contract.Result<Elt>() != null);
- Elt multiValue = new Elt(lattices.Count, false);
- for (int i = 0; i < lattices.Count; i++) {
- Lattice d = (Lattice/*!*/)cce.NonNull(lattices[i]);
- multiValue[d.Index] = d.Top;
- }
- Debug.Assert(multiValue.IsValid);
- return multiValue;
- }
-
-
- public static Elt/*!*/ Bottom(ArrayList/*<Lattice>*//*!*/ lattices) {
- Contract.Requires(lattices != null);
- Contract.Ensures(Contract.Result<Elt>() != null);
- Elt multiValue = new Elt(lattices.Count, true);
- for (int i = 0; i < lattices.Count; i++) {
- Lattice d = (Lattice/*!*/)cce.NonNull(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
-
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(lattices != null);
- Contract.Invariant(propExprFactory != null);
- }
-
- ArrayList/*<Lattice>*//*!*/ lattices = new ArrayList();
-
- private readonly IPropExprFactory/*!*/ propExprFactory;
-
-
- public MultiLattice(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valueExprFactory)
- : base(valueExprFactory) {
- Contract.Requires(valueExprFactory != null);
- Contract.Requires(propExprFactory != null);
- this.propExprFactory = propExprFactory;
- // base(valueExprFactory);
- }
-
-
-
- public void AddLattice(Lattice lattice) {
- this.lattices.Add(lattice);
- }
-
- private Lattice/*!*/ SubLattice(int i) {
- Contract.Ensures(Contract.Result<Lattice>() != null);
- return (Lattice/*!*/)cce.NonNull(this.lattices[i]);
- }
-
-
- public override Element/*!*/ Top {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- return Elt.Top(this.lattices);
- }
- }
-
- public override Element/*!*/ Bottom {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- return Elt.Bottom(this.lattices);
- }
- }
-
-
-
-
- public override bool IsBottom(Element/*!*/ element) {
- //Contract.Requires(element != null);
- 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(cce.NonNull(e[i]))) {
- return true;
- }
- }
- return false;
- }
-
- public override bool IsTop(Element/*!*/ element) {
- //Contract.Requires(element != null);
- 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(cce.NonNull(e[i]))) {
- return false;
- }
- }
- return true;
- }
-
- protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Elt a = (Elt)first;
- Elt b = (Elt)second;
-
- for (int i = 0; i < a.Count; i++) {
- Element thisElement = cce.NonNull(a[i]);
- Element thatElement = cce.NonNull(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) {
- //Contract.Requires(secondToResult != null);
- //Contract.Requires(second != null);
- //Contract.Requires(firstToResult != null);
- //Contract.Requires(first != null);
- Elt a = (Elt)first;
- Elt b = (Elt)second;
-
- for (int i = 0; i < a.Count; i++) {
- Element thisElement = cce.NonNull(a[i]);
- Element thatElement = cce.NonNull(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) {
- Contract.Requires(second != null);
- Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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];
- Contract.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) {
- //Contract.Requires((b != null));
- //Contract.Requires((a != null));
- Contract.Ensures(Contract.Result<Element>() != null);
- return this.Combine(a, null, b, null, CombineOp.Join);
- }
-
- public override Element/*!*/ NontrivialJoin(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) {
- //Contract.Requires((bToResult != null));
- //Contract.Requires((b != null));
- //Contract.Requires((aToResult != null));
- //Contract.Requires((a != null));
- Contract.Ensures(Contract.Result<Element>() != null);
- return this.Combine(a, aToResult, b, bToResult, CombineOp.Join);
- }
-
- public override Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) {
- //Contract.Requires((b != null));
- //Contract.Requires((a != null));
- Contract.Ensures(Contract.Result<Element>() != null);
- return this.Combine(a, null, b, null, CombineOp.Meet);
- }
-
- public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) {
- //Contract.Requires((b != null));
- //Contract.Requires((a != null));
- Contract.Ensures(Contract.Result<Element>() != null);
- return this.Combine(a, null, b, null, CombineOp.Widen);
- }
-
- public override Element/*!*/ Widen(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) {
- //Contract.Requires((bToResult != null));
- //Contract.Requires((b != null));
- //Contract.Requires((aToResult != null));
-
- //Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- return this.Combine(a, aToResult, b, bToResult, CombineOp.Widen);
- }
-
- public override Element/*!*/ Eliminate(Element/*!*/ element, IVariable/*!*/ variable) {
- //Contract.Requires(variable != null);
- //Contract.Requires(element != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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(cce.NonNull(e[i]), variable);
- }
- return newValue;
- }
-
-
- public override Element/*!*/ Constrain(Element/*!*/ element, IExpr/*!*/ expr) {
- //Contract.Requires(expr != null);
- //Contract.Requires(element != null);
- //Contract.Ensures(Contract.Result<Element>() != null);
- 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(cce.NonNull(e[i]), expr);
- }
- return newValue;
- }
-
-
- public override Element/*!*/ Rename(Element/*!*/ element, IVariable/*!*/ oldName, IVariable/*!*/ newName) {
- //Contract.Requires(newName != null);
- //Contract.Requires(oldName != null);
- //Contract.Requires(element != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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(cce.NonNull(e[i]), oldName, newName);
- }
- return newValue;
- }
-
-
- public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) {
- //Contract.Requires(args != null);
- //Contract.Requires(f != null);
- 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) {
- //Contract.Requires(element != null);
- Contract.Ensures(Contract.Result<string>() != null);
- Elt e = (Elt)element;
- return e.ToString();
- }
-
-
- public override IExpr/*!*/ ToPredicate(Element/*!*/ element) {
- //Contract.Requires(element != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- Elt e = (Elt)element;
-
- IExpr result = propExprFactory.True;
- for (int i = 0; i < e.Count; i++) {
- IExpr conjunct = SubLattice(i).ToPredicate(cce.NonNull(e[i]));
- Contract.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) {
- //Contract.Requires(prohibitedVars != null);
- //Contract.Requires(var != null);
- //Contract.Requires(expr != null);
- //Contract.Requires(q != null);
- //Contract.Requires(element != null);
- Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element);
-
- for (int i = 0; i < e.Count; i++) {
- IExpr equivexpr = SubLattice(i).EquivalentExpr(cce.NonNull(e[i]), q, expr, var, prohibitedVars);
-
- if (equivexpr != null)
- return equivexpr;
- }
-
- return null;
- }
-
-
- public override Answer CheckPredicate(Element/*!*/ element, IExpr/*!*/ pred) {
- //Contract.Requires(pred != null);
- //Contract.Requires(element != null);
- Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element);
-
- for (int i = 0; i < e.Count; i++) {
- Answer ans = SubLattice(i).CheckPredicate(cce.NonNull(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) {
- //Contract.Requires(var2 != null);
- //Contract.Requires(var1 != null);
- //Contract.Requires(element != null);
- Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element);
-
- for (int i = 0; i < e.Count; i++) {
- Answer ans = SubLattice(i).CheckVariableDisequality(cce.NonNull(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) {
- Contract.Assert(l != null);
- 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() {
- Contract.Ensures(Contract.Result<IEnumerator>() != null);
- 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) {
- Contract.Requires(element != null);
- Contract.Ensures(Contract.Result<IEnumerable>() != null);
- return new SubelementsEnumerable(this, (Elt/*!*/)cce.NonNull(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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(multiElementIter != null);
- Contract.Invariant(multiLatticeIter != null);
- }
-
-
- public SubelementsEnumerator(MultiLattice/*!*/ multiLattice, Elt/*!*/ multiElement) {
- Contract.Requires(multiElement != null);
- Contract.Requires(multiLattice != null);
- Contract.Requires(multiElement.elementPerLattice != null);
- this.multiLatticeIter = multiLattice.lattices.GetEnumerator();
- this.multiElementIter = multiElement.elementPerLattice.GetEnumerator();
- // base();
- }
-
- public DictionaryEntry Entry {
- get {
- return new DictionaryEntry(cce.NonNull(multiLatticeIter.Current), multiElementIter.Current);
- }
- }
-
- public object Key {
- get {
- return multiLatticeIter.Current;
- }
- }
-
- public object Value {
- get {
- return multiElementIter.Current;
- }
- }
-
- public object Current {
- 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) {
- Contract.Requires(multiElement != null);
- Contract.Requires(multiLattice != null);
- this.multiLattice = multiLattice;
- this.multiElement = multiElement;
- // base();
- }
-
- [Pure]
- [GlobalAccess(false)]
- [Escapes(true, false)]
- public IEnumerator/*!*/ GetEnumerator() {
- Contract.Ensures(Contract.Result<IEnumerator>() != null);
- return new SubelementsEnumerator(multiLattice, multiElement);
- }
- }
-
-
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System.Diagnostics.Contracts; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using Microsoft.AbstractInterpretationFramework.Collections; + + using Microsoft.Boogie; + + using ISet = Microsoft.Boogie.GSet<object>; + using Set = Microsoft.Boogie.GSet<object>; + + + /// <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) { + Contract.Requires(other != null); + Element[] otherEPL = other.elementPerLattice; + if (otherEPL != null) { + Element[] newEPL = new Element[otherEPL.Length]; + for (int i = 0; i < newEPL.Length; i++) { + newEPL[i] = (Element)(cce.NonNull(otherEPL[i])).Clone(); + } + this.elementPerLattice = newEPL; + } + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result<Element>() != null); + return new Elt(this); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result<string>() != null); + // 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) { + //Contract.Requires(msg != null); + System.Console.WriteLine("MultiLattice.Elt.Dump({0})", msg); + Element[] epl = this.elementPerLattice; + if (epl != null) { + foreach (Element/*!*/ e in epl) { + Contract.Assert(e != null); + e.Dump(msg); + } + } + } + + [Pure] + public override ICollection<IVariable/*!*/>/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result<ICollection<IVariable>>())); + List<IVariable/*!*/>/*!*/ list = new List<IVariable/*!*/>(); + for (int i = 0; i < this.Count; i++) { + list.AddRange(cce.NonNull(this[i]).FreeVariables()); + } + return cce.NonNull(list.AsReadOnly()); + } + + public static Elt/*!*/ Top(ArrayList/*<Lattice>*//*!*/ lattices) { + Contract.Requires(lattices != null); + Contract.Ensures(Contract.Result<Elt>() != null); + Elt multiValue = new Elt(lattices.Count, false); + for (int i = 0; i < lattices.Count; i++) { + Lattice d = (Lattice/*!*/)cce.NonNull(lattices[i]); + multiValue[d.Index] = d.Top; + } + Debug.Assert(multiValue.IsValid); + return multiValue; + } + + + public static Elt/*!*/ Bottom(ArrayList/*<Lattice>*//*!*/ lattices) { + Contract.Requires(lattices != null); + Contract.Ensures(Contract.Result<Elt>() != null); + Elt multiValue = new Elt(lattices.Count, true); + for (int i = 0; i < lattices.Count; i++) { + Lattice d = (Lattice/*!*/)cce.NonNull(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 + + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(lattices != null); + Contract.Invariant(propExprFactory != null); + } + + ArrayList/*<Lattice>*//*!*/ lattices = new ArrayList(); + + private readonly IPropExprFactory/*!*/ propExprFactory; + + + public MultiLattice(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valueExprFactory) + : base(valueExprFactory) { + Contract.Requires(valueExprFactory != null); + Contract.Requires(propExprFactory != null); + this.propExprFactory = propExprFactory; + // base(valueExprFactory); + } + + + + public void AddLattice(Lattice lattice) { + this.lattices.Add(lattice); + } + + private Lattice/*!*/ SubLattice(int i) { + Contract.Ensures(Contract.Result<Lattice>() != null); + return (Lattice/*!*/)cce.NonNull(this.lattices[i]); + } + + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result<Element>() != null); + return Elt.Top(this.lattices); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result<Element>() != null); + return Elt.Bottom(this.lattices); + } + } + + + + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + 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(cce.NonNull(e[i]))) { + return true; + } + } + return false; + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + 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(cce.NonNull(e[i]))) { + return false; + } + } + return true; + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + for (int i = 0; i < a.Count; i++) { + Element thisElement = cce.NonNull(a[i]); + Element thatElement = cce.NonNull(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) { + //Contract.Requires(secondToResult != null); + //Contract.Requires(second != null); + //Contract.Requires(firstToResult != null); + //Contract.Requires(first != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + for (int i = 0; i < a.Count; i++) { + Element thisElement = cce.NonNull(a[i]); + Element thatElement = cce.NonNull(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) { + Contract.Requires(second != null); + Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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]; + Contract.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) { + //Contract.Requires((b != null)); + //Contract.Requires((a != null)); + Contract.Ensures(Contract.Result<Element>() != null); + return this.Combine(a, null, b, null, CombineOp.Join); + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + //Contract.Requires((bToResult != null)); + //Contract.Requires((b != null)); + //Contract.Requires((aToResult != null)); + //Contract.Requires((a != null)); + Contract.Ensures(Contract.Result<Element>() != null); + return this.Combine(a, aToResult, b, bToResult, CombineOp.Join); + } + + public override Element/*!*/ NontrivialMeet(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires((b != null)); + //Contract.Requires((a != null)); + Contract.Ensures(Contract.Result<Element>() != null); + return this.Combine(a, null, b, null, CombineOp.Meet); + } + + public override Element/*!*/ Widen(Element/*!*/ a, Element/*!*/ b) { + //Contract.Requires((b != null)); + //Contract.Requires((a != null)); + Contract.Ensures(Contract.Result<Element>() != null); + return this.Combine(a, null, b, null, CombineOp.Widen); + } + + public override Element/*!*/ Widen(Element/*!*/ a, ICombineNameMap/*!*/ aToResult, Element/*!*/ b, ICombineNameMap/*!*/ bToResult) { + //Contract.Requires((bToResult != null)); + //Contract.Requires((b != null)); + //Contract.Requires((aToResult != null)); + + //Contract.Requires(a != null); + Contract.Ensures(Contract.Result<Element>() != null); + return this.Combine(a, aToResult, b, bToResult, CombineOp.Widen); + } + + public override Element/*!*/ Eliminate(Element/*!*/ element, IVariable/*!*/ variable) { + //Contract.Requires(variable != null); + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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(cce.NonNull(e[i]), variable); + } + return newValue; + } + + + public override Element/*!*/ Constrain(Element/*!*/ element, IExpr/*!*/ expr) { + //Contract.Requires(expr != null); + //Contract.Requires(element != null); + //Contract.Ensures(Contract.Result<Element>() != null); + 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(cce.NonNull(e[i]), expr); + } + return newValue; + } + + + public override Element/*!*/ Rename(Element/*!*/ element, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + //Contract.Requires(newName != null); + //Contract.Requires(oldName != null); + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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(cce.NonNull(e[i]), oldName, newName); + } + return newValue; + } + + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + 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) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result<string>() != null); + Elt e = (Elt)element; + return e.ToString(); + } + + + public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + Elt e = (Elt)element; + + IExpr result = propExprFactory.True; + for (int i = 0; i < e.Count; i++) { + IExpr conjunct = SubLattice(i).ToPredicate(cce.NonNull(e[i])); + Contract.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) { + //Contract.Requires(prohibitedVars != null); + //Contract.Requires(var != null); + //Contract.Requires(expr != null); + //Contract.Requires(q != null); + //Contract.Requires(element != null); + Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); + + for (int i = 0; i < e.Count; i++) { + IExpr equivexpr = SubLattice(i).EquivalentExpr(cce.NonNull(e[i]), q, expr, var, prohibitedVars); + + if (equivexpr != null) + return equivexpr; + } + + return null; + } + + + public override Answer CheckPredicate(Element/*!*/ element, IExpr/*!*/ pred) { + //Contract.Requires(pred != null); + //Contract.Requires(element != null); + Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); + + for (int i = 0; i < e.Count; i++) { + Answer ans = SubLattice(i).CheckPredicate(cce.NonNull(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) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + //Contract.Requires(element != null); + Elt/*!*/ e = (Elt/*!*/)cce.NonNull(element); + + for (int i = 0; i < e.Count; i++) { + Answer ans = SubLattice(i).CheckVariableDisequality(cce.NonNull(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) { + Contract.Assert(l != null); + 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() { + Contract.Ensures(Contract.Result<IEnumerator>() != null); + 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) { + Contract.Requires(element != null); + Contract.Ensures(Contract.Result<IEnumerable>() != null); + return new SubelementsEnumerable(this, (Elt/*!*/)cce.NonNull(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; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(multiElementIter != null); + Contract.Invariant(multiLatticeIter != null); + } + + + public SubelementsEnumerator(MultiLattice/*!*/ multiLattice, Elt/*!*/ multiElement) { + Contract.Requires(multiElement != null); + Contract.Requires(multiLattice != null); + Contract.Requires(multiElement.elementPerLattice != null); + this.multiLatticeIter = multiLattice.lattices.GetEnumerator(); + this.multiElementIter = multiElement.elementPerLattice.GetEnumerator(); + // base(); + } + + public DictionaryEntry Entry { + get { + return new DictionaryEntry(cce.NonNull(multiLatticeIter.Current), multiElementIter.Current); + } + } + + public object Key { + get { + return multiLatticeIter.Current; + } + } + + public object Value { + get { + return multiElementIter.Current; + } + } + + public object Current { + 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) { + Contract.Requires(multiElement != null); + Contract.Requires(multiLattice != null); + this.multiLattice = multiLattice; + this.multiElement = multiElement; + // base(); + } + + [Pure] + [GlobalAccess(false)] + [Escapes(true, false)] + public IEnumerator/*!*/ GetEnumerator() { + Contract.Ensures(Contract.Result<IEnumerator>() != null); + return new SubelementsEnumerator(multiLattice, multiElement); + } + } + + + } +} diff --git a/Source/AIFramework/Mutable.cs b/Source/AIFramework/Mutable.cs index 7592aa6a..fff0476e 100644 --- a/Source/AIFramework/Mutable.cs +++ b/Source/AIFramework/Mutable.cs @@ -1,137 +1,137 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System.Diagnostics.Contracts;
-namespace Microsoft.AbstractInterpretationFramework.Collections {
- using System.Collections;
- using System.Diagnostics.Contracts;
-
- /// <summary>
- /// Extend sets for using as a IWorkList.
- /// </summary>
- public class WorkSet : Microsoft.Boogie.GSet<object>, 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.
- public override int Count {
- get {
- return base.Count;
- }
- }
-
- [Pure]
- 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 = cce.NonNull(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) {
- //Contract.Requires(a != null);
- 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 {
- Contract.Ensures(Contract.Result<object>() != null);
- return this;
- }
- }
- public bool IsSynchronized {
- get {
- return false;
- }
- }
-
- }
-}
-
-namespace Microsoft.AbstractInterpretationFramework.Collections.Generic {
- using System.Collections.Generic;
-
- public class HashMultiset<T> {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(dict != null);
- }
-
- private readonly IDictionary<T, int>/*!*/ dict;
-
- //Contract.Invariant(Contract.ForAll(dict , entry => 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) {
- cce.BeginExpose(this);
- {
- if (dict.ContainsKey(t)) {
- dict[t] = dict[t] + 1;
- } else {
- dict.Add(t, 1);
- }
- }
- cce.EndExpose();
- }
-
- public void Remove(T t) {
- if (dict.ContainsKey(t)) {
- cce.BeginExpose(this);
- {
- int count = dict[t];
- if (count == 1) {
- dict.Remove(t);
- } else {
- dict[t] = count - 1;
- }
- }
- cce.EndExpose();
- }
- }
-
- public bool Contains(T t) {
- return dict.ContainsKey(t);
- }
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; +namespace Microsoft.AbstractInterpretationFramework.Collections { + using System.Collections; + using System.Diagnostics.Contracts; + + /// <summary> + /// Extend sets for using as a IWorkList. + /// </summary> + public class WorkSet : Microsoft.Boogie.GSet<object>, 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. + public override int Count { + get { + return base.Count; + } + } + + [Pure] + 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 = cce.NonNull(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) { + //Contract.Requires(a != null); + 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 { + Contract.Ensures(Contract.Result<object>() != null); + return this; + } + } + public bool IsSynchronized { + get { + return false; + } + } + + } +} + +namespace Microsoft.AbstractInterpretationFramework.Collections.Generic { + using System.Collections.Generic; + + public class HashMultiset<T> { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(dict != null); + } + + private readonly IDictionary<T, int>/*!*/ dict; + + //Contract.Invariant(Contract.ForAll(dict , entry => 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) { + cce.BeginExpose(this); + { + if (dict.ContainsKey(t)) { + dict[t] = dict[t] + 1; + } else { + dict.Add(t, 1); + } + } + cce.EndExpose(); + } + + public void Remove(T t) { + if (dict.ContainsKey(t)) { + cce.BeginExpose(this); + { + int count = dict[t]; + if (count == 1) { + dict.Remove(t); + } else { + dict[t] = count - 1; + } + } + cce.EndExpose(); + } + } + + public bool Contains(T t) { + return dict.ContainsKey(t); + } + } +} diff --git a/Source/AIFramework/Polyhedra/LinearConstraint.cs b/Source/AIFramework/Polyhedra/LinearConstraint.cs index ab5e14f8..82264364 100644 --- a/Source/AIFramework/Polyhedra/LinearConstraint.cs +++ b/Source/AIFramework/Polyhedra/LinearConstraint.cs @@ -1,545 +1,545 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System.Diagnostics.Contracts;
-namespace Microsoft.AbstractInterpretationFramework {
- using System;
- //using System.Compiler;
- using System.Collections;
- using Microsoft.Basetypes;
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; +namespace Microsoft.AbstractInterpretationFramework { + using System; + //using System.Compiler; + using System.Collections; + using Microsoft.Basetypes; using Set = Microsoft.Boogie.GSet<object>; - using IMutableSet = Microsoft.Boogie.GSet<object>;
- using HashSet = Microsoft.Boogie.GSet<object>;
- using ISet = Microsoft.Boogie.GSet<object>;
-
-
- /// <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
- }
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(coefficients != null);
- }
-
- public readonly ConstraintRelation Relation;
- internal Hashtable /*IVariable->Rational*//*!*/ coefficients = new Hashtable /*IVariable->Rational*/ ();
- internal Rational rhs;
-
- public LinearConstraint(ConstraintRelation rel) {
- Relation = rel;
- }
-
- [Pure]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- 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) {
- Contract.Requires(factory != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- IExpr leftSum = null;
- IExpr rightSum = null;
- foreach (DictionaryEntry /*object->Rational*/ entry in coefficients) {
- IVariable var = (IVariable)entry.Key;
- Rational coeff = (Rational)(cce.NonNull(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);
- }
-
- Contract.Assert(leftSum != null);
- Contract.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) {
- Contract.Requires(factory != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- IExpr/*!*/ product = factory.Term(r, x);
- Contract.Assert(product != null);
- if (sum == null) {
- return product;
- } else {
- return factory.Add(sum, product);
- }
- }
- public System.Collections.Generic.IEnumerable<IVariable> GetDefinedDimensionsGeneric() {
- Contract.Ensures(Contract.Result<System.Collections.Generic.IEnumerable<IVariable>>() != null);
- foreach (IVariable/*!*/ dim in coefficients.Keys) {
- Contract.Assert(dim != null);
- yield return dim;
- }
- }
- public ISet /*IVariable!*//*!*/ GetDefinedDimensions() {
- Contract.Ensures(Contract.Result<ISet>() != null);
- HashSet /*IVariable!*/ dims = new HashSet /*IVariable!*/ (coefficients.Count);
- int j = 0;
- foreach (IVariable/*!*/ dim in coefficients.Keys) {
- Contract.Assert(dim != null);
- 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 <= 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 <= 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) {
- Contract.Requires(c != null);
- // "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()) {
- Contract.Assert(d != null);
- if (!dd.Contains(d)) {
- dd.Add(d);
- }
- }
- foreach (IVariable/*!*/ d in c.GetDefinedDimensions()) {
- Contract.Assert(d != null);
- if (!dd.Contains(d)) {
- dd.Add(d);
- }
- }
-
- foreach (IVariable/*!*/ d in dd) {
- Contract.Assert(d != null);
- 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)(cce.NonNull(entry.Value));
- }
- b.rhs = -this.rhs;
- }
-
- public void SetCoefficient(IVariable/*!*/ dimension, Rational coefficient) {
- Contract.Requires(dimension != null);
- 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) {
- Contract.Requires(dim != null);
- object val = coefficients[dim];
- if (val != null) {
-#if FIXED_SERIALIZER
- Contract.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 {
- Contract.Requires(dimension != null);
-
-
- 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) {
- Contract.Requires(newName != null);
- Contract.Requires(oldName != null);
- 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*/)cce.NonNull(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) {
- Contract.Ensures(Contract.Result<LinearConstraint>() != null);
- 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() {
- Contract.Ensures(Contract.Result<LinearConstraint>() != null);
- LinearConstraint z = new LinearConstraint(ConstraintRelation.LE);
- foreach (DictionaryEntry /*IVariable->Rational*/ entry in this.coefficients) {
- z.coefficients.Add(entry.Key, -(Rational)(cce.NonNull(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) {
- Contract.Requires(v != null);
- Rational q = Rational.ZERO;
- foreach (DictionaryEntry /*IVariable,Rational*/ term in coefficients) {
- IVariable dim = (IVariable/*!*/)cce.NonNull(term.Key);
- Rational a = (Rational)(cce.NonNull(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) {
- Contract.Requires(fe != null);
- Rational lhs = EvaluateLhs(fe);
- Rational rhs = vertex ? this.rhs : Rational.ZERO;
- return lhs == rhs;
- }
-
- /// <summary>
- /// Changes the current constraint A*X <= B into (A + m*aa)*X <= B + m*bb,
- /// where "cc" is the constraint aa*X <= bb.
- /// </summary>
- /// <param name="m"></param>
- /// <param name="cc"></param>
- /// <returns></returns>
- public void AddMultiple(Rational m, LinearConstraint/*!*/ cc) {
- Contract.Requires(cc != null);
- foreach (DictionaryEntry /*IVariable->Rational*/ entry in cc.coefficients) {
- IVariable dim = (IVariable)entry.Key;
- Rational d = m * (Rational)(cce.NonNull(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)(cce.NonNull(e.Value));
- if (r.IsNonZero) {
- newCoefficients.Add(e.Key, Rational.FromBignums(r.Numerator / gcd.Numerator, r.Denominator / gcd.Denominator));
- } else {
- newCoefficients.Add(e.Key, r);
- }
- }
-
- coefficients = newCoefficients;
- rhs = rhs.IsNonZero ? Rational.FromBignums(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 {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(terms != null);
- }
-
- 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) {
- Contract.Requires(dimension != null);
- terms.Add(dimension, value);
- }
-
- [Pure]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- string s = null;
- foreach (DictionaryEntry item in terms) {
- if (s == null) {
- s = "(";
- } else {
- s += ", ";
- }
- s += String.Format("<{0},{1}>", item.Key, (Rational)(cce.NonNull(item.Value)));
- }
- if (s == null) {
- s = "(";
- }
- return s + ")";
- }
-
- public IMutableSet /*IVariable!*//*!*/ GetDefinedDimensions() {
- Contract.Ensures(Contract.Result<IMutableSet>() != null);
- HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (terms.Count);
- foreach (IVariable/*!*/ dim in terms.Keys) {
- Contract.Assert(dim != null);
- 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 {
- //Contract.Ensures(Contract.Result<Rational>() != null);
- 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) {
- Contract.Requires(newName != null);
- Contract.Requires(oldName != null);
- 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*/)cce.NonNull(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;
- }
- }
-}
+ using IMutableSet = Microsoft.Boogie.GSet<object>; + using HashSet = Microsoft.Boogie.GSet<object>; + using ISet = Microsoft.Boogie.GSet<object>; + + + /// <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 + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(coefficients != null); + } + + public readonly ConstraintRelation Relation; + internal Hashtable /*IVariable->Rational*//*!*/ coefficients = new Hashtable /*IVariable->Rational*/ (); + internal Rational rhs; + + public LinearConstraint(ConstraintRelation rel) { + Relation = rel; + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result<string>() != null); + 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) { + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + IExpr leftSum = null; + IExpr rightSum = null; + foreach (DictionaryEntry /*object->Rational*/ entry in coefficients) { + IVariable var = (IVariable)entry.Key; + Rational coeff = (Rational)(cce.NonNull(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); + } + + Contract.Assert(leftSum != null); + Contract.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) { + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + IExpr/*!*/ product = factory.Term(r, x); + Contract.Assert(product != null); + if (sum == null) { + return product; + } else { + return factory.Add(sum, product); + } + } + public System.Collections.Generic.IEnumerable<IVariable> GetDefinedDimensionsGeneric() { + Contract.Ensures(Contract.Result<System.Collections.Generic.IEnumerable<IVariable>>() != null); + foreach (IVariable/*!*/ dim in coefficients.Keys) { + Contract.Assert(dim != null); + yield return dim; + } + } + public ISet /*IVariable!*//*!*/ GetDefinedDimensions() { + Contract.Ensures(Contract.Result<ISet>() != null); + HashSet /*IVariable!*/ dims = new HashSet /*IVariable!*/ (coefficients.Count); + int j = 0; + foreach (IVariable/*!*/ dim in coefficients.Keys) { + Contract.Assert(dim != null); + 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 <= 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 <= 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) { + Contract.Requires(c != null); + // "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()) { + Contract.Assert(d != null); + if (!dd.Contains(d)) { + dd.Add(d); + } + } + foreach (IVariable/*!*/ d in c.GetDefinedDimensions()) { + Contract.Assert(d != null); + if (!dd.Contains(d)) { + dd.Add(d); + } + } + + foreach (IVariable/*!*/ d in dd) { + Contract.Assert(d != null); + 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)(cce.NonNull(entry.Value)); + } + b.rhs = -this.rhs; + } + + public void SetCoefficient(IVariable/*!*/ dimension, Rational coefficient) { + Contract.Requires(dimension != null); + 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) { + Contract.Requires(dim != null); + object val = coefficients[dim]; + if (val != null) { +#if FIXED_SERIALIZER + Contract.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 { + Contract.Requires(dimension != null); + + + 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) { + Contract.Requires(newName != null); + Contract.Requires(oldName != null); + 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*/)cce.NonNull(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) { + Contract.Ensures(Contract.Result<LinearConstraint>() != null); + 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() { + Contract.Ensures(Contract.Result<LinearConstraint>() != null); + LinearConstraint z = new LinearConstraint(ConstraintRelation.LE); + foreach (DictionaryEntry /*IVariable->Rational*/ entry in this.coefficients) { + z.coefficients.Add(entry.Key, -(Rational)(cce.NonNull(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) { + Contract.Requires(v != null); + Rational q = Rational.ZERO; + foreach (DictionaryEntry /*IVariable,Rational*/ term in coefficients) { + IVariable dim = (IVariable/*!*/)cce.NonNull(term.Key); + Rational a = (Rational)(cce.NonNull(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) { + Contract.Requires(fe != null); + Rational lhs = EvaluateLhs(fe); + Rational rhs = vertex ? this.rhs : Rational.ZERO; + return lhs == rhs; + } + + /// <summary> + /// Changes the current constraint A*X <= B into (A + m*aa)*X <= B + m*bb, + /// where "cc" is the constraint aa*X <= bb. + /// </summary> + /// <param name="m"></param> + /// <param name="cc"></param> + /// <returns></returns> + public void AddMultiple(Rational m, LinearConstraint/*!*/ cc) { + Contract.Requires(cc != null); + foreach (DictionaryEntry /*IVariable->Rational*/ entry in cc.coefficients) { + IVariable dim = (IVariable)entry.Key; + Rational d = m * (Rational)(cce.NonNull(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)(cce.NonNull(e.Value)); + if (r.IsNonZero) { + newCoefficients.Add(e.Key, Rational.FromBignums(r.Numerator / gcd.Numerator, r.Denominator / gcd.Denominator)); + } else { + newCoefficients.Add(e.Key, r); + } + } + + coefficients = newCoefficients; + rhs = rhs.IsNonZero ? Rational.FromBignums(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 { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(terms != null); + } + + 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) { + Contract.Requires(dimension != null); + terms.Add(dimension, value); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result<string>() != null); + string s = null; + foreach (DictionaryEntry item in terms) { + if (s == null) { + s = "("; + } else { + s += ", "; + } + s += String.Format("<{0},{1}>", item.Key, (Rational)(cce.NonNull(item.Value))); + } + if (s == null) { + s = "("; + } + return s + ")"; + } + + public IMutableSet /*IVariable!*//*!*/ GetDefinedDimensions() { + Contract.Ensures(Contract.Result<IMutableSet>() != null); + HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (terms.Count); + foreach (IVariable/*!*/ dim in terms.Keys) { + Contract.Assert(dim != null); + 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 { + //Contract.Ensures(Contract.Result<Rational>() != null); + 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) { + Contract.Requires(newName != null); + Contract.Requires(oldName != null); + 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*/)cce.NonNull(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.cs b/Source/AIFramework/Polyhedra/LinearConstraintSystem.cs index 74e36eae..59aadb86 100644 --- a/Source/AIFramework/Polyhedra/LinearConstraintSystem.cs +++ b/Source/AIFramework/Polyhedra/LinearConstraintSystem.cs @@ -1,1756 +1,1756 @@ -//-----------------------------------------------------------------------------
-//
-// 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 System.Diagnostics.Contracts;
- using Microsoft.Basetypes;
-
- using IMutableSet = Microsoft.Boogie.GSet<object>;
- using ISet = Microsoft.Boogie.GSet<object>;
- using HashSet = Microsoft.Boogie.GSet<object>;
-
- /// <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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(FrameDimensions != null);
- }
-
- /*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) {
- Contract.Assert(cc != null);
-#if FIXED_DESERIALIZER
- Contract.Assert(Contract.ForAll(cc.GetDefinedDimensions() , var=> FrameDimensions.Contains(var)));
-#endif
- Contract.Assert(cc.coefficients.Count != 0);
- }
- foreach (ArrayList /*FrameElement*//*!*/ FrameComponent in new ArrayList /*FrameElement*/ [] { FrameVertices, FrameRays, FrameLines }) {
- Contract.Assert(FrameComponent != null);
- foreach (FrameElement fe in FrameComponent) {
- if (fe == null)
- continue;
-#if FIXED_DESERIALIZER
- Contract.Assert(Contract.ForAll(fe.GetDefinedDimensions() , var=> 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) {
- Contract.Requires(cs != null);
-#if BUG_159_HAS_BEEN_FIXED
- Contract.Requires(Contract.ForAll(cs) , cc=> cc.coefficients.Count != 0);
-#endif
-
- ArrayList constraints = new ArrayList /*LinearConstraint!*/ (cs.Count);
- foreach (LinearConstraint/*!*/ cc in cs) {
- Contract.Assert(cc != null);
- 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) {
- Contract.Requires(v != null);
- IMutableSet/*!*/ frameDims = v.GetDefinedDimensions();
- Contract.Assert(frameDims != null);
- ArrayList /*LinearConstraint!*/ constraints = new ArrayList /*LinearConstraint!*/ ();
- foreach (IVariable/*!*/ dim in frameDims) {
- Contract.Assert(dim != null);
- 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;
- 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]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- if (Constraints == null) {
- return "<bottom>";
- } else if (Constraints.Count == 0) {
- return "<top>";
- } else {
- string z = null;
- foreach (LinearConstraint/*!*/ lc in Constraints) {
- Contract.Assert(lc != null);
- string s = lc.ToString();
- if (z == null) {
- z = s;
- } else {
- z += " AND " + s;
- }
- }
- Contract.Assert(z != null);
- return z;
- }
- }
-
-
- public ICollection<IVariable/*!*/>/*!*/ FreeVariables() {
- Contract.Ensures(cce.NonNullElements(Contract.Result<ICollection<IVariable>>()));
- Contract.Ensures(Contract.Result<ICollection<IVariable>>().IsReadOnly);
- List<IVariable/*!*/> list = new List<IVariable/*!*/>();
- foreach (IVariable/*!*/ v in FrameDimensions) {
- Contract.Assert(v != null);
- list.Add(v);
- }
- return cce.NonNull(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) {
- Contract.Requires(factory != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- if (this.Constraints == null) {
- return factory.False;
- }
- if (this.Constraints.Count == 0) {
- return factory.True;
- }
-
- IExpr result = null;
- foreach (LinearConstraint/*!*/ lc in Constraints) {
- Contract.Assert(lc != null);
- IExpr conjunct = lc.ConvertToExpression(factory);
- result = (result == null) ? conjunct : (IExpr)factory.And(conjunct, result);
- }
- Contract.Assert(result != null);
- return result;
- }
-
-
- /* IsSubset(): determines if 'lcs' is a subset of 'this'
- * -- See Cousot/Halbwachs 1978, section
- */
- public bool IsSubset(LinearConstraintSystem/*!*/ lcs) {
- Contract.Requires(lcs != null);
- 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();
- Contract.Assert(frameDims != null);
-#if DEBUG_PRINT
- Console.WriteLine("DEBUG: IsSubset:");
- Console.WriteLine(" --- this:");
- this.Dump();
- Console.WriteLine(" --- lcs:");
- lcs.Dump();
- Console.WriteLine(" ---");
-#endif
- foreach (LinearConstraint/*!*/ cc in cce.NonNull(this.Constraints)) {
- Contract.Assert(cc != null);
-#if DEBUG_PRINT
- Console.WriteLine(" cc: {0}", cc);
- Console.WriteLine(" cc.GetDefinedDimensions(): {0}", cc.GetDefinedDimensions());
-#endif
-
- if (!Contract.ForAll(cc.GetDefinedDimensionsGeneric(), var => 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 cce.NonNull(lcs.FrameVertices)) {
- Contract.Assert(v != null);
- foreach (LinearConstraint/*!*/ cc in this.Constraints) {
- Contract.Assert(cc != null);
- 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 cce.NonNull(lcs.FrameRays)) {
- Contract.Assert(r != null);
- System.Diagnostics.Debug.Assert(r != null, "encountered a null ray...");
- foreach (LinearConstraint/*!*/ cc in this.Constraints) {
- Contract.Assert(cc != null);
- 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 cce.NonNull(lcs.FrameLines)) {
- Contract.Assert(line != null);
- System.Diagnostics.Debug.Assert(line != null, "encountered a null line...");
- foreach (LinearConstraint/*!*/ cc in this.Constraints) {
- Contract.Assert(cc != null);
- 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) {
- Contract.Requires(lcs != null);
- Contract.Requires((this.Constraints != null));
- Contract.Requires((lcs.Constraints != null));
- Contract.Ensures(Contract.Result<LinearConstraintSystem>() != 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) {
- Contract.Requires(lcs != null);
- Contract.Ensures(Contract.Result<LinearConstraintSystem>() != null);
-#endif
-
- if (this.IsBottom()) {
- return cce.NonNull(lcs.Clone());
- } else if (lcs.IsBottom()) {
- return cce.NonNull(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).
- Contract.Assume(this.FrameVertices != null);
- Contract.Assume(this.FrameRays != null);
- Contract.Assume(this.FrameLines != null);
- Contract.Assume(lcs.FrameVertices != null);
- Contract.Assume(lcs.FrameRays != null);
- Contract.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 = cce.NonNull(lcs.Clone());
- lcs = this;
- } else {
- z = cce.NonNull(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) {
- Contract.Assert(dim != null);
- 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.
- Contract.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) {
- Contract.Assert(v != null);
- z.AddVertex(v);
-#if DEBUG_PRINT
- Console.WriteLine("Join: After adding vertex: {0}", v);
- z.Dump();
-#endif
- }
- foreach (FrameElement/*!*/ r in lcs.FrameRays) {
- Contract.Assert(r != null);
- z.AddRay(r);
-#if DEBUG_PRINT
- Console.WriteLine("Join: After adding ray: {0}", r);
- z.Dump();
-#endif
- }
- foreach (FrameElement/*!*/ l in lcs.FrameLines) {
- Contract.Assert(l != null);
- 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) {
- Contract.Assert(dim != null);
- 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) {
- Contract.Requires(lcs != null);
- Contract.Ensures(Contract.Result<LinearConstraintSystem>() != null);
-#endif
- if (this.IsBottom()) {
- return cce.NonNull(lcs.Clone());
- } else if (lcs.IsBottom()) {
- return cce.NonNull(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*/ ();
- Contract.Assume(this.Constraints != null);
- foreach (LinearConstraint/*!*/ ccX in this.Constraints) {
- Contract.Assert(ccX != null);
- 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 cce.NonNull(lcs.FrameVertices)) {
- Contract.Assert(vertex != null);
- 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 cce.NonNull(lcs.FrameRays)) {
- Contract.Assert(ray != null);
- // 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 cce.NonNull(lcs.FrameLines)) {
- Contract.Assert(line != null);
- // 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){
-Contract.Requires(dim != null);
- 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){Contract.Requires(dim != null);Contract.Requires(this.Constraints != null);
-#else
- public LinearConstraintSystem/*!*/ Project(IVariable/*!*/ dim) {
- Contract.Requires(dim != null);
- Contract.Requires(this.Constraints != null);
- Contract.Ensures(Contract.Result<LinearConstraintSystem>() != null);
-#endif
-
-
- ArrayList /*LinearConstraint!*//*!*/ cc = Project(dim, Constraints);
- Contract.Assert(cc != null);
- return new LinearConstraintSystem(cc);
- }
-
-#if DEBUG_PRINT
- public LinearConstraintSystem Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName){
-Contract.Requires(newName != null);
-Contract.Requires(oldName != null);
- 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){Contract.Requires(oldName != null);Contract.Requires(newName != null);
-#else
- public LinearConstraintSystem/*!*/ Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) {
- Contract.Requires(oldName != null);
- Contract.Requires(newName != null);
- Contract.Ensures(Contract.Result<LinearConstraintSystem>() != null);
-#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;
- Contract.Assert(dims != null);
- if (!dims.Contains(oldName)) {
- return this;
- }
-
- LinearConstraintSystem z = new LinearConstraintSystem();
- z.FrameDimensions = cce.NonNull((HashSet/*!*/ /*IVariable!*/)dims.Clone());
- z.FrameDimensions.Remove(oldName);
- z.FrameDimensions.Add(newName);
-
- z.Constraints = new ArrayList /*LinearConstraint!*/ (this.Constraints.Count);
- foreach (LinearConstraint/*!*/ lc in cce.NonNull(this.Constraints)) {
- Contract.Assert(lc != null);
- z.Constraints.Add(lc.Rename(oldName, newName));
- }
- z.FrameVertices = RenameInFE(cce.NonNull(this.FrameVertices), oldName, newName);
- z.FrameRays = RenameInFE(cce.NonNull(this.FrameRays), oldName, newName);
- z.FrameLines = RenameInFE(cce.NonNull(this.FrameLines), oldName, newName);
- return z;
- }
-
- static ArrayList /*FrameElement*/ RenameInFE(ArrayList/*!*/ /*FrameElement*/ list, IVariable/*!*/ oldName, IVariable/*!*/ newName) {
- Contract.Requires(list != null);
- Contract.Requires(newName != null);
- Contract.Requires(oldName != null);
- ArrayList/*FrameElement!*//*!*/ z = new ArrayList/*FrameElement!*/ (list.Count);
- Contract.Assert(z != null);
- foreach (FrameElement/*!*/ fe in list) {
- Contract.Assert(fe != null);
- 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) {
- Contract.Requires(constraints != null);
- Contract.Requires(dim != null);
- Contract.Ensures(Contract.Result<ArrayList>() != null);
- // 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) {
- Contract.Assert(cc != null);
- Rational coeff = cc[dim];
- if (coeff.IsZero) {
- LinearConstraint lc = cce.NonNull(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/*!*/)cce.NonNull(eq[eq.Count - 1]);
- eq.RemoveAt(eq.Count - 1);
- Rational eqC = -eqConstraint[dim];
-
- foreach (ArrayList /*LinearConstraint!*/ list in new ArrayList[] { eq, negative, positive }) {
- Contract.Assert(list != null);
- foreach (LinearConstraint/*!*/ lcX in list) {
- Contract.Assert(lcX != null);
- LinearConstraint lc = cce.NonNull(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) {
- Contract.Assert(cn != null);
- Rational dn = -cn[dim];
- System.Diagnostics.Debug.Assert(dn.IsNonNegative);
- foreach (LinearConstraint/*!*/ cp in positive) {
- Contract.Assert(cp != null);
- 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 = cce.NonNull((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 {
- Contract.Ensures(Contract.Result<string>() != null);
-
- return this.ToString();
- }
- }
-
- public LambdaDimension() {
- id = count;
- count++;
- }
- [Pure]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- return "lambda" + id;
- }
- [Pure]
- public object DoVisit(ExprVisitor/*!*/ visitor) {
- //Contract.Requires(visitor != null);
- 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) {
- Contract.Requires(vertex != null);
- Contract.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
- Contract.Assert(Contract.ForAll(vertex.GetDefinedDimensions() , var=> 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 cce.NonNull(Constraints)) {
- Contract.Assert(cc != null);
- 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) {
- Contract.Requires(ray != null);
- Contract.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
- Contract.Assert(Contract.ForAll(ray.GetDefinedDimensions() , var=> 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 cce.NonNull(Constraints)) {
- Contract.Assert(cc != null);
- 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) {
- Contract.Requires(line != null);
- Contract.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
- Contract.Assert(Contract.ForAll(line.GetDefinedDimensions() , var=> 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 cce.NonNull(Constraints)) {
- Contract.Assert(cc != null);
- 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() {
- Contract.Ensures(Contract.Result<ISet>() != null);
- HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ ();
- foreach (ArrayList p in new ArrayList[] { FrameVertices, FrameRays, FrameLines }) {
- if (p != null) {
- foreach (FrameElement/*!*/ element in p) {
- Contract.Assert(element != null);
- foreach (IVariable/*!*/ dim in element.GetDefinedDimensions()) {
- Contract.Assert(dim != null);
- 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() {
- Contract.Requires(this.Constraints != null);
- SimplificationStatus[]/*!*/ status;
-
- SimplifyFrameElements(cce.NonNull(FrameVertices), true, Constraints, out status);
- RemoveIrrelevantFrameElements(FrameVertices, status, null);
-
- SimplifyFrameElements(cce.NonNull(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) {
- Contract.Requires(ff != null);
- Contract.Requires(constraints != null);
- Contract.Ensures(Contract.ValueAtReturn(out status) != null);
- status = new SimplificationStatus[ff.Count];
- bool[,] sat = new bool[ff.Count, constraints.Count];
- for (int i = 0; i < ff.Count; i++) {
- FrameElement f = (FrameElement/*!*/)cce.NonNull(ff[i]);
- int cnt = 0;
- for (int c = 0; c < constraints.Count; c++) {
- LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(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) {
- Contract.Requires(status != null);
- Contract.Requires(sat != null);
- Contract.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) {
- Contract.Requires(ff != null);
- Contract.Requires(status != null);
- Contract.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);
- Contract.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;
- }
- Contract.Assume(this.FrameVertices != null);
- Contract.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/*!*/)cce.NonNull(Constraints[i]);
- int cnt = 0; // number of vertices and rays that saturate lc
- for (int j = 0; j < FrameVertices.Count; j++) {
- FrameElement vertex = (FrameElement/*!*/)cce.NonNull(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/*!*/)cce.NonNull(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/*!*/)cce.NonNull(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) {
- Contract.Assert(lc != null);
- lc.Normalize();
- }
- }
-
- // --------------------------------------------------------------------------------------------------------
- // ------------------ Cloning routines --------------------------------------------------------------------
- // --------------------------------------------------------------------------------------------------------
-
- public LinearConstraintSystem/*!*/ Clone() {
- Contract.Ensures(Contract.Result<LinearConstraintSystem>() != null);
- LinearConstraintSystem z = new LinearConstraintSystem();
- z.FrameDimensions = (IMutableSet /*IVariable!*//*!*/)cce.NonNull(this.FrameDimensions.Clone());
- if (this.Constraints != null) {
- z.Constraints = DeeperListCopy_LC(this.Constraints);
- z.FrameVertices = DeeperListCopy_FE(cce.NonNull(this.FrameVertices));
- z.FrameRays = DeeperListCopy_FE(cce.NonNull(this.FrameRays));
- z.FrameLines = DeeperListCopy_FE(cce.NonNull(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) {
- Contract.Requires(list != null);
- ArrayList /*LinearConstraint*/ z = new ArrayList /*LinearConstraint*/ (list.Count);
- foreach (LinearConstraint/*!*/ lc in list) {
- Contract.Assert(lc != null);
- 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) {
- Contract.Requires(list != null);
- ArrayList /*FrameElement*/ z = new ArrayList /*FrameElement*/ (list.Count);
- foreach (FrameElement/*!*/ fe in list) {
- Contract.Assert(fe != null);
- 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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(name != null);
- }
-
-
- public string/*!*/ Name {
- get {
- Contract.Ensures(Contract.Result<string>() != null);
-
- return name;
- }
- }
-
- public TestVariable(string/*!*/ name) {
- Contract.Requires(name != null);
- this.name = name;
- }
- [Pure]
- public object DoVisit(ExprVisitor/*!*/ visitor) {
- //Contract.Requires(visitor != null);
- return visitor.VisitVariable(this);
- }
- }
-
- public static void RunValidationA() {
- IVariable/*!*/ dim1 = new TestVariable("X");
- IVariable/*!*/ dim2 = new TestVariable("Y");
- IVariable/*!*/ dim3 = new TestVariable("Z");
- Contract.Assert(dim1 != null);
- Contract.Assert(dim2 != null);
- Contract.Assert(dim3 != null);
-
- 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");
- Contract.Assert(X != null);
- Contract.Assert(Y != null);
- Contract.Assert(Z != null);
- 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");
- Contract.Assert(dim1 != null);
- Contract.Assert(dim2 != null);
- Contract.Assert(dim3 != null);
-
- 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
- }
- }
+//----------------------------------------------------------------------------- +// +// 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 System.Diagnostics.Contracts; + using Microsoft.Basetypes; + + using IMutableSet = Microsoft.Boogie.GSet<object>; + using ISet = Microsoft.Boogie.GSet<object>; + using HashSet = Microsoft.Boogie.GSet<object>; + + /// <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; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(FrameDimensions != null); + } + + /*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) { + Contract.Assert(cc != null); +#if FIXED_DESERIALIZER + Contract.Assert(Contract.ForAll(cc.GetDefinedDimensions() , var=> FrameDimensions.Contains(var))); +#endif + Contract.Assert(cc.coefficients.Count != 0); + } + foreach (ArrayList /*FrameElement*//*!*/ FrameComponent in new ArrayList /*FrameElement*/ [] { FrameVertices, FrameRays, FrameLines }) { + Contract.Assert(FrameComponent != null); + foreach (FrameElement fe in FrameComponent) { + if (fe == null) + continue; +#if FIXED_DESERIALIZER + Contract.Assert(Contract.ForAll(fe.GetDefinedDimensions() , var=> 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) { + Contract.Requires(cs != null); +#if BUG_159_HAS_BEEN_FIXED + Contract.Requires(Contract.ForAll(cs) , cc=> cc.coefficients.Count != 0); +#endif + + ArrayList constraints = new ArrayList /*LinearConstraint!*/ (cs.Count); + foreach (LinearConstraint/*!*/ cc in cs) { + Contract.Assert(cc != null); + 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) { + Contract.Requires(v != null); + IMutableSet/*!*/ frameDims = v.GetDefinedDimensions(); + Contract.Assert(frameDims != null); + ArrayList /*LinearConstraint!*/ constraints = new ArrayList /*LinearConstraint!*/ (); + foreach (IVariable/*!*/ dim in frameDims) { + Contract.Assert(dim != null); + 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; + 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] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result<string>() != null); + if (Constraints == null) { + return "<bottom>"; + } else if (Constraints.Count == 0) { + return "<top>"; + } else { + string z = null; + foreach (LinearConstraint/*!*/ lc in Constraints) { + Contract.Assert(lc != null); + string s = lc.ToString(); + if (z == null) { + z = s; + } else { + z += " AND " + s; + } + } + Contract.Assert(z != null); + return z; + } + } + + + public ICollection<IVariable/*!*/>/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result<ICollection<IVariable>>())); + Contract.Ensures(Contract.Result<ICollection<IVariable>>().IsReadOnly); + List<IVariable/*!*/> list = new List<IVariable/*!*/>(); + foreach (IVariable/*!*/ v in FrameDimensions) { + Contract.Assert(v != null); + list.Add(v); + } + return cce.NonNull(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) { + Contract.Requires(factory != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + if (this.Constraints == null) { + return factory.False; + } + if (this.Constraints.Count == 0) { + return factory.True; + } + + IExpr result = null; + foreach (LinearConstraint/*!*/ lc in Constraints) { + Contract.Assert(lc != null); + IExpr conjunct = lc.ConvertToExpression(factory); + result = (result == null) ? conjunct : (IExpr)factory.And(conjunct, result); + } + Contract.Assert(result != null); + return result; + } + + + /* IsSubset(): determines if 'lcs' is a subset of 'this' + * -- See Cousot/Halbwachs 1978, section + */ + public bool IsSubset(LinearConstraintSystem/*!*/ lcs) { + Contract.Requires(lcs != null); + 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(); + Contract.Assert(frameDims != null); +#if DEBUG_PRINT + Console.WriteLine("DEBUG: IsSubset:"); + Console.WriteLine(" --- this:"); + this.Dump(); + Console.WriteLine(" --- lcs:"); + lcs.Dump(); + Console.WriteLine(" ---"); +#endif + foreach (LinearConstraint/*!*/ cc in cce.NonNull(this.Constraints)) { + Contract.Assert(cc != null); +#if DEBUG_PRINT + Console.WriteLine(" cc: {0}", cc); + Console.WriteLine(" cc.GetDefinedDimensions(): {0}", cc.GetDefinedDimensions()); +#endif + + if (!Contract.ForAll(cc.GetDefinedDimensionsGeneric(), var => 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 cce.NonNull(lcs.FrameVertices)) { + Contract.Assert(v != null); + foreach (LinearConstraint/*!*/ cc in this.Constraints) { + Contract.Assert(cc != null); + 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 cce.NonNull(lcs.FrameRays)) { + Contract.Assert(r != null); + System.Diagnostics.Debug.Assert(r != null, "encountered a null ray..."); + foreach (LinearConstraint/*!*/ cc in this.Constraints) { + Contract.Assert(cc != null); + 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 cce.NonNull(lcs.FrameLines)) { + Contract.Assert(line != null); + System.Diagnostics.Debug.Assert(line != null, "encountered a null line..."); + foreach (LinearConstraint/*!*/ cc in this.Constraints) { + Contract.Assert(cc != null); + 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) { + Contract.Requires(lcs != null); + Contract.Requires((this.Constraints != null)); + Contract.Requires((lcs.Constraints != null)); + Contract.Ensures(Contract.Result<LinearConstraintSystem>() != 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) { + Contract.Requires(lcs != null); + Contract.Ensures(Contract.Result<LinearConstraintSystem>() != null); +#endif + + if (this.IsBottom()) { + return cce.NonNull(lcs.Clone()); + } else if (lcs.IsBottom()) { + return cce.NonNull(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). + Contract.Assume(this.FrameVertices != null); + Contract.Assume(this.FrameRays != null); + Contract.Assume(this.FrameLines != null); + Contract.Assume(lcs.FrameVertices != null); + Contract.Assume(lcs.FrameRays != null); + Contract.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 = cce.NonNull(lcs.Clone()); + lcs = this; + } else { + z = cce.NonNull(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) { + Contract.Assert(dim != null); + 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. + Contract.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) { + Contract.Assert(v != null); + z.AddVertex(v); +#if DEBUG_PRINT + Console.WriteLine("Join: After adding vertex: {0}", v); + z.Dump(); +#endif + } + foreach (FrameElement/*!*/ r in lcs.FrameRays) { + Contract.Assert(r != null); + z.AddRay(r); +#if DEBUG_PRINT + Console.WriteLine("Join: After adding ray: {0}", r); + z.Dump(); +#endif + } + foreach (FrameElement/*!*/ l in lcs.FrameLines) { + Contract.Assert(l != null); + 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) { + Contract.Assert(dim != null); + 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) { + Contract.Requires(lcs != null); + Contract.Ensures(Contract.Result<LinearConstraintSystem>() != null); +#endif + if (this.IsBottom()) { + return cce.NonNull(lcs.Clone()); + } else if (lcs.IsBottom()) { + return cce.NonNull(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*/ (); + Contract.Assume(this.Constraints != null); + foreach (LinearConstraint/*!*/ ccX in this.Constraints) { + Contract.Assert(ccX != null); + 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 cce.NonNull(lcs.FrameVertices)) { + Contract.Assert(vertex != null); + 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 cce.NonNull(lcs.FrameRays)) { + Contract.Assert(ray != null); + // 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 cce.NonNull(lcs.FrameLines)) { + Contract.Assert(line != null); + // 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){ +Contract.Requires(dim != null); + 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){Contract.Requires(dim != null);Contract.Requires(this.Constraints != null); +#else + public LinearConstraintSystem/*!*/ Project(IVariable/*!*/ dim) { + Contract.Requires(dim != null); + Contract.Requires(this.Constraints != null); + Contract.Ensures(Contract.Result<LinearConstraintSystem>() != null); +#endif + + + ArrayList /*LinearConstraint!*//*!*/ cc = Project(dim, Constraints); + Contract.Assert(cc != null); + return new LinearConstraintSystem(cc); + } + +#if DEBUG_PRINT + public LinearConstraintSystem Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName){ +Contract.Requires(newName != null); +Contract.Requires(oldName != null); + 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){Contract.Requires(oldName != null);Contract.Requires(newName != null); +#else + public LinearConstraintSystem/*!*/ Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName) { + Contract.Requires(oldName != null); + Contract.Requires(newName != null); + Contract.Ensures(Contract.Result<LinearConstraintSystem>() != null); +#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; + Contract.Assert(dims != null); + if (!dims.Contains(oldName)) { + return this; + } + + LinearConstraintSystem z = new LinearConstraintSystem(); + z.FrameDimensions = cce.NonNull((HashSet/*!*/ /*IVariable!*/)dims.Clone()); + z.FrameDimensions.Remove(oldName); + z.FrameDimensions.Add(newName); + + z.Constraints = new ArrayList /*LinearConstraint!*/ (this.Constraints.Count); + foreach (LinearConstraint/*!*/ lc in cce.NonNull(this.Constraints)) { + Contract.Assert(lc != null); + z.Constraints.Add(lc.Rename(oldName, newName)); + } + z.FrameVertices = RenameInFE(cce.NonNull(this.FrameVertices), oldName, newName); + z.FrameRays = RenameInFE(cce.NonNull(this.FrameRays), oldName, newName); + z.FrameLines = RenameInFE(cce.NonNull(this.FrameLines), oldName, newName); + return z; + } + + static ArrayList /*FrameElement*/ RenameInFE(ArrayList/*!*/ /*FrameElement*/ list, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + Contract.Requires(list != null); + Contract.Requires(newName != null); + Contract.Requires(oldName != null); + ArrayList/*FrameElement!*//*!*/ z = new ArrayList/*FrameElement!*/ (list.Count); + Contract.Assert(z != null); + foreach (FrameElement/*!*/ fe in list) { + Contract.Assert(fe != null); + 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) { + Contract.Requires(constraints != null); + Contract.Requires(dim != null); + Contract.Ensures(Contract.Result<ArrayList>() != null); + // 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) { + Contract.Assert(cc != null); + Rational coeff = cc[dim]; + if (coeff.IsZero) { + LinearConstraint lc = cce.NonNull(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/*!*/)cce.NonNull(eq[eq.Count - 1]); + eq.RemoveAt(eq.Count - 1); + Rational eqC = -eqConstraint[dim]; + + foreach (ArrayList /*LinearConstraint!*/ list in new ArrayList[] { eq, negative, positive }) { + Contract.Assert(list != null); + foreach (LinearConstraint/*!*/ lcX in list) { + Contract.Assert(lcX != null); + LinearConstraint lc = cce.NonNull(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) { + Contract.Assert(cn != null); + Rational dn = -cn[dim]; + System.Diagnostics.Debug.Assert(dn.IsNonNegative); + foreach (LinearConstraint/*!*/ cp in positive) { + Contract.Assert(cp != null); + 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 = cce.NonNull((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 { + Contract.Ensures(Contract.Result<string>() != null); + + return this.ToString(); + } + } + + public LambdaDimension() { + id = count; + count++; + } + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result<string>() != null); + return "lambda" + id; + } + [Pure] + public object DoVisit(ExprVisitor/*!*/ visitor) { + //Contract.Requires(visitor != null); + 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) { + Contract.Requires(vertex != null); + Contract.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 + Contract.Assert(Contract.ForAll(vertex.GetDefinedDimensions() , var=> 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 cce.NonNull(Constraints)) { + Contract.Assert(cc != null); + 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) { + Contract.Requires(ray != null); + Contract.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 + Contract.Assert(Contract.ForAll(ray.GetDefinedDimensions() , var=> 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 cce.NonNull(Constraints)) { + Contract.Assert(cc != null); + 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) { + Contract.Requires(line != null); + Contract.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 + Contract.Assert(Contract.ForAll(line.GetDefinedDimensions() , var=> 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 cce.NonNull(Constraints)) { + Contract.Assert(cc != null); + 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() { + Contract.Ensures(Contract.Result<ISet>() != null); + HashSet /*IVariable!*//*!*/ dims = new HashSet /*IVariable!*/ (); + foreach (ArrayList p in new ArrayList[] { FrameVertices, FrameRays, FrameLines }) { + if (p != null) { + foreach (FrameElement/*!*/ element in p) { + Contract.Assert(element != null); + foreach (IVariable/*!*/ dim in element.GetDefinedDimensions()) { + Contract.Assert(dim != null); + 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() { + Contract.Requires(this.Constraints != null); + SimplificationStatus[]/*!*/ status; + + SimplifyFrameElements(cce.NonNull(FrameVertices), true, Constraints, out status); + RemoveIrrelevantFrameElements(FrameVertices, status, null); + + SimplifyFrameElements(cce.NonNull(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) { + Contract.Requires(ff != null); + Contract.Requires(constraints != null); + Contract.Ensures(Contract.ValueAtReturn(out status) != null); + status = new SimplificationStatus[ff.Count]; + bool[,] sat = new bool[ff.Count, constraints.Count]; + for (int i = 0; i < ff.Count; i++) { + FrameElement f = (FrameElement/*!*/)cce.NonNull(ff[i]); + int cnt = 0; + for (int c = 0; c < constraints.Count; c++) { + LinearConstraint lc = (LinearConstraint/*!*/)cce.NonNull(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) { + Contract.Requires(status != null); + Contract.Requires(sat != null); + Contract.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) { + Contract.Requires(ff != null); + Contract.Requires(status != null); + Contract.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); + Contract.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; + } + Contract.Assume(this.FrameVertices != null); + Contract.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/*!*/)cce.NonNull(Constraints[i]); + int cnt = 0; // number of vertices and rays that saturate lc + for (int j = 0; j < FrameVertices.Count; j++) { + FrameElement vertex = (FrameElement/*!*/)cce.NonNull(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/*!*/)cce.NonNull(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/*!*/)cce.NonNull(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) { + Contract.Assert(lc != null); + lc.Normalize(); + } + } + + // -------------------------------------------------------------------------------------------------------- + // ------------------ Cloning routines -------------------------------------------------------------------- + // -------------------------------------------------------------------------------------------------------- + + public LinearConstraintSystem/*!*/ Clone() { + Contract.Ensures(Contract.Result<LinearConstraintSystem>() != null); + LinearConstraintSystem z = new LinearConstraintSystem(); + z.FrameDimensions = (IMutableSet /*IVariable!*//*!*/)cce.NonNull(this.FrameDimensions.Clone()); + if (this.Constraints != null) { + z.Constraints = DeeperListCopy_LC(this.Constraints); + z.FrameVertices = DeeperListCopy_FE(cce.NonNull(this.FrameVertices)); + z.FrameRays = DeeperListCopy_FE(cce.NonNull(this.FrameRays)); + z.FrameLines = DeeperListCopy_FE(cce.NonNull(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) { + Contract.Requires(list != null); + ArrayList /*LinearConstraint*/ z = new ArrayList /*LinearConstraint*/ (list.Count); + foreach (LinearConstraint/*!*/ lc in list) { + Contract.Assert(lc != null); + 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) { + Contract.Requires(list != null); + ArrayList /*FrameElement*/ z = new ArrayList /*FrameElement*/ (list.Count); + foreach (FrameElement/*!*/ fe in list) { + Contract.Assert(fe != null); + 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; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(name != null); + } + + + public string/*!*/ Name { + get { + Contract.Ensures(Contract.Result<string>() != null); + + return name; + } + } + + public TestVariable(string/*!*/ name) { + Contract.Requires(name != null); + this.name = name; + } + [Pure] + public object DoVisit(ExprVisitor/*!*/ visitor) { + //Contract.Requires(visitor != null); + return visitor.VisitVariable(this); + } + } + + public static void RunValidationA() { + IVariable/*!*/ dim1 = new TestVariable("X"); + IVariable/*!*/ dim2 = new TestVariable("Y"); + IVariable/*!*/ dim3 = new TestVariable("Z"); + Contract.Assert(dim1 != null); + Contract.Assert(dim2 != null); + Contract.Assert(dim3 != null); + + 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"); + Contract.Assert(X != null); + Contract.Assert(Y != null); + Contract.Assert(Z != null); + 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"); + Contract.Assert(dim1 != null); + Contract.Assert(dim2 != null); + Contract.Assert(dim3 != null); + + 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.cs b/Source/AIFramework/Polyhedra/PolyhedraAbstraction.cs index 06c0f483..6c914a54 100644 --- a/Source/AIFramework/Polyhedra/PolyhedraAbstraction.cs +++ b/Source/AIFramework/Polyhedra/PolyhedraAbstraction.cs @@ -1,762 +1,762 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-namespace Microsoft.AbstractInterpretationFramework {
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Diagnostics.Contracts;
- using Microsoft.Basetypes;
-
- using ISet = Microsoft.Boogie.GSet<object>;
- using HashSet = Microsoft.Boogie.GSet<object>;
-
- /// <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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(lcs != null);
- }
-
-
- /// <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]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- return lcs.ToString();
- }
-
- public override void Dump(string/*!*/ msg) {
- //Contract.Requires(msg != null);
- System.Console.WriteLine("PolyhedraLatticeElement.Dump({0}):", msg);
- lcs.Dump();
- }
-
- [Pure]
- public override ICollection<IVariable/*!*/>/*!*/ FreeVariables() {
- Contract.Ensures(cce.NonNullElements(Contract.Result<ICollection<IVariable>>()));
- return lcs.FreeVariables();
- }
-
- public PolyhedraLatticeElement(LinearConstraintSystem/*!*/ lcs) {
- Contract.Requires(lcs != null);
- this.lcs = lcs;
- }
-
- public override Element/*!*/ Clone() {
- Contract.Ensures(Contract.Result<Element>() != null);
- return new PolyhedraLatticeElement(cce.NonNull(lcs.Clone()));
- }
-
- } // class
-
- readonly ILinearExprFactory/*!*/ factory;
- readonly IPropExprFactory/*!*/ propFactory;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(log != null);
- Contract.Invariant(factory != null);
- Contract.Invariant(propFactory != null);
- }
-
-
- public PolyhedraLattice(ILinearExprFactory/*!*/ linearFactory, IPropExprFactory/*!*/ propFactory)
- : base(linearFactory) {
- Contract.Requires(propFactory != null);
- Contract.Requires(linearFactory != null);
- log.Enabled = Lattice.LogSwitch;
- this.factory = linearFactory;
- this.propFactory = propFactory;
- // base(linearFactory);
- }
-
- public override Element/*!*/ Top {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- return new PolyhedraLatticeElement(true);
- }
- }
-
- public override Element/*!*/ Bottom {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
-
- return new PolyhedraLatticeElement(false);
- }
- }
-
- public override bool IsBottom(Element/*!*/ element) {
- //Contract.Requires(element != null);
- PolyhedraLatticeElement e = (PolyhedraLatticeElement)element;
- return e.lcs.IsBottom();
- }
-
- public override bool IsTop(Element/*!*/ element) {
- //Contract.Requires(element != null);
- 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
- {
- //Contract.Requires(first != null);
- //Contract.Requires(second != null);
- PolyhedraLatticeElement a = (PolyhedraLatticeElement)first;
- PolyhedraLatticeElement b = (PolyhedraLatticeElement)second;
- return b.lcs.IsSubset(a.lcs);
- }
-
-
- public override string/*!*/ ToString(Element/*!*/ e) {
- //Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<string>() != null);
- return ((PolyhedraLatticeElement)e).lcs.ToString();
- }
-
- public override IExpr/*!*/ ToPredicate(Element/*!*/ element) {
- //Contract.Requires(element != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- PolyhedraLatticeElement e = (PolyhedraLatticeElement)element;
- return e.lcs.ConvertToExpression(factory);
- }
-
-
-
- public override Lattice.Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Lattice.Element>() != null);
- 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) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Lattice.Element>() != null);
- 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) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Lattice.Element>() != null);
- 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) {
- //Contract.Requires(variable != null);
- //Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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) {
- //Contract.Requires(newName != null);
- //Contract.Requires(oldName != null);
- //Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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) {
- //Contract.Requires(args != null);
- //Contract.Requires(f != null);
- 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) {
- //Contract.Requires(var2 != null);
- //Contract.Requires(var1 != null);
- //Contract.Requires(e != null);
- PolyhedraLatticeElement/*!*/ ple = (PolyhedraLatticeElement)cce.NonNull(e);
- Contract.Assume(ple.lcs.Constraints != null);
- ArrayList /*LinearConstraint!*//*!*/ clist = (ArrayList /*LinearConstraint!*/)cce.NonNull(ple.lcs.Constraints.Clone());
- LinearConstraint/*!*/ lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ);
- Contract.Assert(lc != null);
- 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) {
- //Contract.Requires(pred != null);
- //Contract.Requires(e != null);
- PolyhedraLatticeElement/*!*/ ple = (PolyhedraLatticeElement)Constrain(e, pred);
- Contract.Assert(ple != null);
- 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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(arg != null);
- }
-
-
- public PolyhedraLatticeNegation(IExpr/*!*/ arg) {
- Contract.Requires(arg != null);
- this.arg = arg;
- // base();
- }
-
- [Pure]
- public object DoVisit(ExprVisitor/*!*/ visitor) {
- //Contract.Requires(visitor != null);
- return visitor.VisitFunApp(this);
- }
-
- public IFunctionSymbol/*!*/ FunctionSymbol {
- get {
- Contract.Ensures(Contract.Result<IFunctionSymbol>() != null);
- return Prop.Not;
- }
- }
-
- public IList/*<IExpr!>*//*!*/ Arguments {
- get {
- Contract.Ensures(Contract.Result<IList>() != null);
-
- IExpr[] args = new IExpr[] { arg };
- return ArrayList.ReadOnly(args);
- }
- }
-
- public IFunApp/*!*/ CloneWithArguments(IList/*<IExpr!>*//*!*/ args) {
- //Contract.Requires(args != null);
- Contract.Ensures(Contract.Result<IFunApp>() != null);
- Contract.Assert(args.Count == 1);
- return new PolyhedraLatticeNegation((IExpr/*!*/)cce.NonNull(args[0]));
- }
- }
-
- public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/*<IVariable!>*//*!*/ prohibitedVars) {
- //Contract.Requires(prohibitedVars != null);
- //Contract.Requires(var != null);
- //Contract.Requires(expr != null);
- //Contract.Requires(q != null);
- //Contract.Requires(e != null);
- // BUGBUG: TODO: this method can be implemented in a more precise way
- return null;
- }
-
-
- public override Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr) {
- //Contract.Requires(expr != null);
- //Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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
- Contract.Assume(ple.lcs.Constraints != null);
- ArrayList /*LinearConstraint*/ clist = (ArrayList/*!*/ /*LinearConstraint*/)cce.NonNull(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>
- ///
- [ContractClass(typeof(LinearConditionContracts))]
- 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);
- }
- [ContractClassFor(typeof(LinearCondition))]
- abstract class LinearConditionContracts : LinearCondition {
- public override void AddToConstraintSystem(ArrayList clist) {
- Contract.Requires(clist != null);
- throw new NotImplementedException();
- }
- }
-
- class LCBottom : LinearCondition {
- public override void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist) {
- //Contract.Requires(clist != null);
- // 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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(constraint != null);
- }
-
- /// <summary>
- /// Precondition: positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ
- /// </summary>
- /// <param name="positive"></param>
- /// <param name="constraint"></param>
- public LinearConditionLiteral(bool positive, LinearConstraint/*!*/ constraint) {
- Contract.Requires(constraint != null);
- Contract.Requires(positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ);
- this.positive = positive;
- this.constraint = constraint;
- }
- public override void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist) {
- //Contract.Requires(clist != null);
- if (positive) {
- clist.Add(constraint);
- } else {
- Contract.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;
- Contract.Assert(s != null);
- if ((positive && s.Equals(Prop.False)) ||
- (!positive && s.Equals(Prop.True))) {
- return new LCBottom();
- } else if (s.Equals(Prop.Not)) {
- Contract.Assert(funapp.Arguments.Count == 1);
- return GetCond((IExpr/*!*/)cce.NonNull(funapp.Arguments[0]), !positive);
- } else if (funapp.Arguments.Count == 2) {
- IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[0]);
- IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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 */
- {
- Contract.Requires(le0 != null);
- Contract.Requires(le1 != null);
- 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 */
- {
- Contract.Requires(e != null);
- 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;
- Contract.Assert(funapp != null);
- IFunctionSymbol/*!*/ s = funapp.FunctionSymbol;
- Contract.Assert(s != null);
-
- if (s is IntSymbol) {
- return new LinearExpr(((IntSymbol)s).Value);
- } else if (s.Equals(Int.Negate)) {
- Contract.Assert(funapp.Arguments.Count == 1);
- LinearExpr le = AsExpr((IExpr/*!*/)cce.NonNull(funapp.Arguments[0]));
- if (le != null) {
- le.Negate();
- return le;
- }
- } else if (s.Equals(Int.Add) || s.Equals(Int.Sub) || s.Equals(Int.Mul)) {
- Contract.Assert(funapp.Arguments.Count == 2);
- IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[0]);
- IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(var != null);
- }
-
- public Term(BigNum coeff, IVariable/*!*/ var) {
- Contract.Requires(var != null);
- this.coeff = coeff;
- this.var = var;
- // base();
- }
- }
-
- public LinearExpr(BigNum x) {
- constant = x;
- }
-
- public LinearExpr(IVariable/*!*/ var) {
- Contract.Requires(var != null);
- 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) {
- Contract.Requires(var != null);
- 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 */
- {
- Contract.Requires(le != null);
- Contract.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) {
- Contract.Requires(var != null);
- 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;
- }
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System.Diagnostics.Contracts; + using Microsoft.Basetypes; + + using ISet = Microsoft.Boogie.GSet<object>; + using HashSet = Microsoft.Boogie.GSet<object>; + + /// <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; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(lcs != null); + } + + + /// <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] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result<string>() != null); + return lcs.ToString(); + } + + public override void Dump(string/*!*/ msg) { + //Contract.Requires(msg != null); + System.Console.WriteLine("PolyhedraLatticeElement.Dump({0}):", msg); + lcs.Dump(); + } + + [Pure] + public override ICollection<IVariable/*!*/>/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result<ICollection<IVariable>>())); + return lcs.FreeVariables(); + } + + public PolyhedraLatticeElement(LinearConstraintSystem/*!*/ lcs) { + Contract.Requires(lcs != null); + this.lcs = lcs; + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result<Element>() != null); + return new PolyhedraLatticeElement(cce.NonNull(lcs.Clone())); + } + + } // class + + readonly ILinearExprFactory/*!*/ factory; + readonly IPropExprFactory/*!*/ propFactory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(log != null); + Contract.Invariant(factory != null); + Contract.Invariant(propFactory != null); + } + + + public PolyhedraLattice(ILinearExprFactory/*!*/ linearFactory, IPropExprFactory/*!*/ propFactory) + : base(linearFactory) { + Contract.Requires(propFactory != null); + Contract.Requires(linearFactory != null); + log.Enabled = Lattice.LogSwitch; + this.factory = linearFactory; + this.propFactory = propFactory; + // base(linearFactory); + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result<Element>() != null); + return new PolyhedraLatticeElement(true); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result<Element>() != null); + + return new PolyhedraLatticeElement(false); + } + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; + return e.lcs.IsBottom(); + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + 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 + { + //Contract.Requires(first != null); + //Contract.Requires(second != null); + PolyhedraLatticeElement a = (PolyhedraLatticeElement)first; + PolyhedraLatticeElement b = (PolyhedraLatticeElement)second; + return b.lcs.IsSubset(a.lcs); + } + + + public override string/*!*/ ToString(Element/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result<string>() != null); + return ((PolyhedraLatticeElement)e).lcs.ToString(); + } + + public override IExpr/*!*/ ToPredicate(Element/*!*/ element) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + PolyhedraLatticeElement e = (PolyhedraLatticeElement)element; + return e.lcs.ConvertToExpression(factory); + } + + + + public override Lattice.Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Lattice.Element>() != null); + 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) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Lattice.Element>() != null); + 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) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Lattice.Element>() != null); + 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) { + //Contract.Requires(variable != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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) { + //Contract.Requires(newName != null); + //Contract.Requires(oldName != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + 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) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + //Contract.Requires(e != null); + PolyhedraLatticeElement/*!*/ ple = (PolyhedraLatticeElement)cce.NonNull(e); + Contract.Assume(ple.lcs.Constraints != null); + ArrayList /*LinearConstraint!*//*!*/ clist = (ArrayList /*LinearConstraint!*/)cce.NonNull(ple.lcs.Constraints.Clone()); + LinearConstraint/*!*/ lc = new LinearConstraint(LinearConstraint.ConstraintRelation.EQ); + Contract.Assert(lc != null); + 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) { + //Contract.Requires(pred != null); + //Contract.Requires(e != null); + PolyhedraLatticeElement/*!*/ ple = (PolyhedraLatticeElement)Constrain(e, pred); + Contract.Assert(ple != null); + 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; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(arg != null); + } + + + public PolyhedraLatticeNegation(IExpr/*!*/ arg) { + Contract.Requires(arg != null); + this.arg = arg; + // base(); + } + + [Pure] + public object DoVisit(ExprVisitor/*!*/ visitor) { + //Contract.Requires(visitor != null); + return visitor.VisitFunApp(this); + } + + public IFunctionSymbol/*!*/ FunctionSymbol { + get { + Contract.Ensures(Contract.Result<IFunctionSymbol>() != null); + return Prop.Not; + } + } + + public IList/*<IExpr!>*//*!*/ Arguments { + get { + Contract.Ensures(Contract.Result<IList>() != null); + + IExpr[] args = new IExpr[] { arg }; + return ArrayList.ReadOnly(args); + } + } + + public IFunApp/*!*/ CloneWithArguments(IList/*<IExpr!>*//*!*/ args) { + //Contract.Requires(args != null); + Contract.Ensures(Contract.Result<IFunApp>() != null); + Contract.Assert(args.Count == 1); + return new PolyhedraLatticeNegation((IExpr/*!*/)cce.NonNull(args[0])); + } + } + + public override IExpr/*?*/ EquivalentExpr(Element/*!*/ e, IQueryable/*!*/ q, IExpr/*!*/ expr, IVariable/*!*/ var, ISet/*<IVariable!>*//*!*/ prohibitedVars) { + //Contract.Requires(prohibitedVars != null); + //Contract.Requires(var != null); + //Contract.Requires(expr != null); + //Contract.Requires(q != null); + //Contract.Requires(e != null); + // BUGBUG: TODO: this method can be implemented in a more precise way + return null; + } + + + public override Element/*!*/ Constrain(Element/*!*/ e, IExpr/*!*/ expr) { + //Contract.Requires(expr != null); + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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 + Contract.Assume(ple.lcs.Constraints != null); + ArrayList /*LinearConstraint*/ clist = (ArrayList/*!*/ /*LinearConstraint*/)cce.NonNull(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> + /// + [ContractClass(typeof(LinearConditionContracts))] + 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); + } + [ContractClassFor(typeof(LinearCondition))] + abstract class LinearConditionContracts : LinearCondition { + public override void AddToConstraintSystem(ArrayList clist) { + Contract.Requires(clist != null); + throw new NotImplementedException(); + } + } + + class LCBottom : LinearCondition { + public override void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist) { + //Contract.Requires(clist != null); + // 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; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(constraint != null); + } + + /// <summary> + /// Precondition: positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ + /// </summary> + /// <param name="positive"></param> + /// <param name="constraint"></param> + public LinearConditionLiteral(bool positive, LinearConstraint/*!*/ constraint) { + Contract.Requires(constraint != null); + Contract.Requires(positive || constraint.Relation == LinearConstraint.ConstraintRelation.EQ); + this.positive = positive; + this.constraint = constraint; + } + public override void AddToConstraintSystem(ArrayList/*!*/ /*LinearConstraint*/ clist) { + //Contract.Requires(clist != null); + if (positive) { + clist.Add(constraint); + } else { + Contract.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; + Contract.Assert(s != null); + if ((positive && s.Equals(Prop.False)) || + (!positive && s.Equals(Prop.True))) { + return new LCBottom(); + } else if (s.Equals(Prop.Not)) { + Contract.Assert(funapp.Arguments.Count == 1); + return GetCond((IExpr/*!*/)cce.NonNull(funapp.Arguments[0]), !positive); + } else if (funapp.Arguments.Count == 2) { + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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 */ + { + Contract.Requires(le0 != null); + Contract.Requires(le1 != null); + 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 */ + { + Contract.Requires(e != null); + 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; + Contract.Assert(funapp != null); + IFunctionSymbol/*!*/ s = funapp.FunctionSymbol; + Contract.Assert(s != null); + + if (s is IntSymbol) { + return new LinearExpr(((IntSymbol)s).Value); + } else if (s.Equals(Int.Negate)) { + Contract.Assert(funapp.Arguments.Count == 1); + LinearExpr le = AsExpr((IExpr/*!*/)cce.NonNull(funapp.Arguments[0])); + if (le != null) { + le.Negate(); + return le; + } + } else if (s.Equals(Int.Add) || s.Equals(Int.Sub) || s.Equals(Int.Mul)) { + Contract.Assert(funapp.Arguments.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(funapp.Arguments[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(var != null); + } + + public Term(BigNum coeff, IVariable/*!*/ var) { + Contract.Requires(var != null); + this.coeff = coeff; + this.var = var; + // base(); + } + } + + public LinearExpr(BigNum x) { + constant = x; + } + + public LinearExpr(IVariable/*!*/ var) { + Contract.Requires(var != null); + 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) { + Contract.Requires(var != null); + 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 */ + { + Contract.Requires(le != null); + Contract.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) { + Contract.Requires(var != null); + 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.cs b/Source/AIFramework/Polyhedra/SimplexTableau.cs index 4d734c27..347c7c45 100644 --- a/Source/AIFramework/Polyhedra/SimplexTableau.cs +++ b/Source/AIFramework/Polyhedra/SimplexTableau.cs @@ -1,630 +1,630 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-namespace Microsoft.AbstractInterpretationFramework {
- using System.Collections;
- using System;
- using System.Diagnostics.Contracts;
- using Microsoft.Basetypes;
- using IMutableSet = Microsoft.Boogie.GSet<object>;
- using HashSet = Microsoft.Boogie.GSet<object>;
-
-
- /// <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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(m != null);
- Contract.Invariant(inBasis != null);
- Contract.Invariant(basisColumns != null);
- }
-
- readonly ArrayList /*IVariable!*//*!*/ dims;
- readonly int[]/*!*/ basisColumns;
- readonly int[]/*!*/ inBasis;
- bool constructionDone = false;
-
- void CheckInvariant() {
- Contract.Assert(rows == m.GetLength(0));
- Contract.Assert(1 <= columns && columns == m.GetLength(1));
- Contract.Assert(0 <= numInitialVars);
- Contract.Assert(0 <= numSlackVars && numSlackVars <= rows);
- Contract.Assert(numInitialVars + numSlackVars + 1 == columns);
- Contract.Assert(rhsColumn == columns - 1);
- Contract.Assert(dims.Count == numInitialVars);
- Contract.Assert(basisColumns.Length == rows);
- Contract.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++) {
- Contract.Assert(m[i, j].IsZero);
- }
- numColumnsInBasis++;
- } else if (c == -1) {
- Contract.Assert(!constructionDone);
- numUninitializedRowInfo++;
- } else {
- // basis column is a column
- Contract.Assert(0 <= c && c < numInitialVars + numSlackVars);
- // basis column is unique
- Contract.Assert(!b[c]);
- b[c] = true;
- // column is marked as being in basis
- Contract.Assert(inBasis[c] == i);
- // basis column really is a basis column
- for (int j = 0; j < rows; j++) {
- if (j == i) {
- Contract.Assert(m[j, c].HasValue(1));// == (Rational)new Rational(1)));
- } else {
- Contract.Assert(m[j, c].IsZero);
- }
- }
- }
- }
- // no other columns are marked as being in basis
- foreach (int i in inBasis) {
- if (0 <= i) {
- Contract.Assert(i < rows);
- numColumnsInBasis++;
- } else {
- Contract.Assert(i == -1);
- }
- }
- Contract.Assert(rows - numUninitializedRowInfo <= numColumnsInBasis && numColumnsInBasis <= rows);
- Contract.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) {
- Contract.Requires(constraints != null);
-#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) {
- Contract.Assert(cc != null);
- foreach (IVariable/*!*/ dim in cc.coefficients.Keys) {
- Contract.Assert(dim != null);
- 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) {
- Contract.Assert(cc != null);
- for (int i = 0; i < dims.Count; i++) {
- m[r, i] = cc[(IVariable)cce.NonNull(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++;
- }
- Contract.Assert(r == constraints.Count);
- Contract.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
- Contract.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++) {
- Contract.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() {
- Contract.Ensures(Contract.Result<IMutableSet>() != null);
- HashSet /*IVariable!*/ z = new HashSet /*IVariable!*/ ();
- foreach (IVariable/*!*/ dim in dims) {
- Contract.Assert(dim != null);
- 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) {
- Contract.Ensures(Contract.Result<Rational[]>() != null);
- Contract.Assert(0 <= r && r < rows);
- Contract.Assert(0 <= c && c < columns - 1);
- Contract.Assert(m[r, c].IsNonZero);
- Contract.Assert(inBasis[c] == -1); // follows from invariant and m[r,c] != 0
- Contract.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) {
- Contract.Requires(undo != null);
- Contract.Assert(0 <= r && r < rows);
- Contract.Assert(0 <= c && c < columns - 1);
- Contract.Assert(m[r, c].HasValue(1));
- Contract.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;
- Contract.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) {
- Contract.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) {
- Contract.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
- Contract.Assert(inBasis[c] == -1);
- Contract.Assert(inBasis[i] == k);
- Contract.Assert(m[k, rhsColumn].IsNonNegative);
- goto START_ANEW;
- }
- }
- feasibleBasis = false;
- }
- }
- return feasibleBasis;
- START_ANEW:
- ;
- }
- }
- }
-
- /// <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);
- Contract.Assert(inBasis[k] == -1);
- Contract.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) {
- Contract.Requires(constraints != null);
- Contract.Requires(lines != null);
- // 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)cce.NonNull(dims[i]), Rational.ONE);
- lc.SetCoefficient((IVariable)cce.NonNull(dims[i]), Rational.ONE);
- } else if (inBasis[i] != -1) {
- // i is a basis column
- Contract.Assert(m[inBasis[i], i].HasValue(1));
- Rational val = -m[inBasis[i], i0];
- fe.AddCoordinate((IVariable)cce.NonNull(dims[i]), val);
- lc.SetCoefficient((IVariable)cce.NonNull(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) {
- Contract.Requires(vertices != null);
- Contract.Requires(rays != null);
- 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) {
- Contract.Requires(rays != null);
- Contract.Requires(vertices != null);
- Contract.Requires(basesSeenSoFar != null);
- 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) {
- Contract.Assert(basis != null);
- Contract.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)cce.NonNull(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)cce.NonNull(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("* ");
- Contract.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();
- }
- }
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System.Collections; + using System; + using System.Diagnostics.Contracts; + using Microsoft.Basetypes; + using IMutableSet = Microsoft.Boogie.GSet<object>; + using HashSet = Microsoft.Boogie.GSet<object>; + + + /// <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; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(m != null); + Contract.Invariant(inBasis != null); + Contract.Invariant(basisColumns != null); + } + + readonly ArrayList /*IVariable!*//*!*/ dims; + readonly int[]/*!*/ basisColumns; + readonly int[]/*!*/ inBasis; + bool constructionDone = false; + + void CheckInvariant() { + Contract.Assert(rows == m.GetLength(0)); + Contract.Assert(1 <= columns && columns == m.GetLength(1)); + Contract.Assert(0 <= numInitialVars); + Contract.Assert(0 <= numSlackVars && numSlackVars <= rows); + Contract.Assert(numInitialVars + numSlackVars + 1 == columns); + Contract.Assert(rhsColumn == columns - 1); + Contract.Assert(dims.Count == numInitialVars); + Contract.Assert(basisColumns.Length == rows); + Contract.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++) { + Contract.Assert(m[i, j].IsZero); + } + numColumnsInBasis++; + } else if (c == -1) { + Contract.Assert(!constructionDone); + numUninitializedRowInfo++; + } else { + // basis column is a column + Contract.Assert(0 <= c && c < numInitialVars + numSlackVars); + // basis column is unique + Contract.Assert(!b[c]); + b[c] = true; + // column is marked as being in basis + Contract.Assert(inBasis[c] == i); + // basis column really is a basis column + for (int j = 0; j < rows; j++) { + if (j == i) { + Contract.Assert(m[j, c].HasValue(1));// == (Rational)new Rational(1))); + } else { + Contract.Assert(m[j, c].IsZero); + } + } + } + } + // no other columns are marked as being in basis + foreach (int i in inBasis) { + if (0 <= i) { + Contract.Assert(i < rows); + numColumnsInBasis++; + } else { + Contract.Assert(i == -1); + } + } + Contract.Assert(rows - numUninitializedRowInfo <= numColumnsInBasis && numColumnsInBasis <= rows); + Contract.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) { + Contract.Requires(constraints != null); +#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) { + Contract.Assert(cc != null); + foreach (IVariable/*!*/ dim in cc.coefficients.Keys) { + Contract.Assert(dim != null); + 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) { + Contract.Assert(cc != null); + for (int i = 0; i < dims.Count; i++) { + m[r, i] = cc[(IVariable)cce.NonNull(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++; + } + Contract.Assert(r == constraints.Count); + Contract.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 + Contract.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++) { + Contract.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() { + Contract.Ensures(Contract.Result<IMutableSet>() != null); + HashSet /*IVariable!*/ z = new HashSet /*IVariable!*/ (); + foreach (IVariable/*!*/ dim in dims) { + Contract.Assert(dim != null); + 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) { + Contract.Ensures(Contract.Result<Rational[]>() != null); + Contract.Assert(0 <= r && r < rows); + Contract.Assert(0 <= c && c < columns - 1); + Contract.Assert(m[r, c].IsNonZero); + Contract.Assert(inBasis[c] == -1); // follows from invariant and m[r,c] != 0 + Contract.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) { + Contract.Requires(undo != null); + Contract.Assert(0 <= r && r < rows); + Contract.Assert(0 <= c && c < columns - 1); + Contract.Assert(m[r, c].HasValue(1)); + Contract.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; + Contract.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) { + Contract.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) { + Contract.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 + Contract.Assert(inBasis[c] == -1); + Contract.Assert(inBasis[i] == k); + Contract.Assert(m[k, rhsColumn].IsNonNegative); + goto START_ANEW; + } + } + feasibleBasis = false; + } + } + return feasibleBasis; + START_ANEW: + ; + } + } + } + + /// <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); + Contract.Assert(inBasis[k] == -1); + Contract.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) { + Contract.Requires(constraints != null); + Contract.Requires(lines != null); + // 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)cce.NonNull(dims[i]), Rational.ONE); + lc.SetCoefficient((IVariable)cce.NonNull(dims[i]), Rational.ONE); + } else if (inBasis[i] != -1) { + // i is a basis column + Contract.Assert(m[inBasis[i], i].HasValue(1)); + Rational val = -m[inBasis[i], i0]; + fe.AddCoordinate((IVariable)cce.NonNull(dims[i]), val); + lc.SetCoefficient((IVariable)cce.NonNull(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) { + Contract.Requires(vertices != null); + Contract.Requires(rays != null); + 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) { + Contract.Requires(rays != null); + Contract.Requires(vertices != null); + Contract.Requires(basesSeenSoFar != null); + 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) { + Contract.Assert(basis != null); + Contract.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)cce.NonNull(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)cce.NonNull(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("* "); + Contract.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.cs b/Source/AIFramework/VariableMap/ConstantAbstraction.cs index d8f17a3c..d73fc28b 100644 --- a/Source/AIFramework/VariableMap/ConstantAbstraction.cs +++ b/Source/AIFramework/VariableMap/ConstantAbstraction.cs @@ -1,251 +1,251 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System.Diagnostics.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]
- public override System.Collections.Generic.ICollection<IVariable/*!*/>/*!*/ FreeVariables() {
- Contract.Ensures(cce.NonNullElements(Contract.Result<System.Collections.Generic.ICollection<IVariable>>()));
- return cce.NonNull(new System.Collections.Generic.List<IVariable/*!*/>()).AsReadOnly();
- }
-
- public override Element/*!*/ Clone() {
- Contract.Ensures(Contract.Result<Element>() != null);
- if (this.IsConstant)
- return new Elt(constantValue);
- else
- return new Elt(domainValue);
- }
- }
-
- readonly IIntExprFactory/*!*/ factory;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(factory != null);
- }
-
-
- public ConstantLattice(IIntExprFactory/*!*/ factory) {
- Contract.Requires(factory != null);
- this.factory = factory;
- // base();
- }
-
- public override Element/*!*/ Top {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- return new Elt(Value.Top);
- }
- }
-
- public override Element/*!*/ Bottom {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- return new Elt(Value.Bottom);
- }
- }
-
- public override bool IsTop(Element/*!*/ element) {
- //Contract.Requires(element != null);
- Elt e = (Elt)element;
- return e.domainValue == Value.Top;
- }
-
- public override bool IsBottom(Element/*!*/ element) {
- //Contract.Requires(element != null);
- Elt e = (Elt)element;
- return e.domainValue == Value.Bottom;
- }
-
- public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- return Join(first, second);
- }
-
- protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that
- {
- //Contract.Requires(first!= null);
- //Contract.Requires(second != null);
- Elt a = (Elt)first;
- Elt b = (Elt)second;
- return a.Constant.Equals(b.Constant);
- }
-
- public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) {
- //Contract.Requires(element != null);
- //Contract.Requires(var != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- return factory.Eq(var, cce.NonNull(GetFoldExpr(element)));
- }
-
- public override IExpr GetFoldExpr(Element/*!*/ element) {
- //Contract.Requires(element != null);
- Elt e = (Elt)element;
- Contract.Assert(e.domainValue == Value.Constant);
- return factory.Const(e.constantValue);
- }
-
- public override bool Understands(IFunctionSymbol/*!*/ f, IList/*<IExpr!>*//*!*/ args) {
- //Contract.Requires(args != null);
- //Contract.Requires(f != null);
- return f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq);
- }
-
- public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) {
- //Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<Element>() != null);
-
- IFunApp nary = e as IFunApp;
- if (nary != null) {
- if (nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) {
- IList/*<IExpr!>*//*!*/ args = nary.Arguments;
- Contract.Assert(args != null);
- Contract.Assert(args.Count == 2);
- IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]);
- IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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) {
- Contract.Requires(expr != null);
- 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;
- Contract.Assert(args != null);
- Contract.Assert(args.Count == 1);
- IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]);
-
- if (Fold(arg0, out z)) {
- z = z.Neg;
- return true;
- }
-
- } else if (e.Arguments.Count == 2) {
- IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(e.Arguments[0]);
- IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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;
- }
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.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] + public override System.Collections.Generic.ICollection<IVariable/*!*/>/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result<System.Collections.Generic.ICollection<IVariable>>())); + return cce.NonNull(new System.Collections.Generic.List<IVariable/*!*/>()).AsReadOnly(); + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result<Element>() != null); + if (this.IsConstant) + return new Elt(constantValue); + else + return new Elt(domainValue); + } + } + + readonly IIntExprFactory/*!*/ factory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(factory != null); + } + + + public ConstantLattice(IIntExprFactory/*!*/ factory) { + Contract.Requires(factory != null); + this.factory = factory; + // base(); + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result<Element>() != null); + return new Elt(Value.Top); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result<Element>() != null); + return new Elt(Value.Bottom); + } + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.domainValue == Value.Top; + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.domainValue == Value.Bottom; + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Element>() != null); + return Join(first, second); + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that + { + //Contract.Requires(first!= null); + //Contract.Requires(second != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + return a.Constant.Equals(b.Constant); + } + + public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { + //Contract.Requires(element != null); + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + return factory.Eq(var, cce.NonNull(GetFoldExpr(element))); + } + + public override IExpr GetFoldExpr(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + Contract.Assert(e.domainValue == Value.Constant); + return factory.Const(e.constantValue); + } + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/*<IExpr!>*//*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + return f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); + } + + public override Element/*!*/ EvaluatePredicate(IExpr/*!*/ e) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result<Element>() != null); + + IFunApp nary = e as IFunApp; + if (nary != null) { + if (nary.FunctionSymbol.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq)) { + IList/*<IExpr!>*//*!*/ args = nary.Arguments; + Contract.Assert(args != null); + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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) { + Contract.Requires(expr != null); + 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; + Contract.Assert(args != null); + Contract.Assert(args.Count == 1); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + + if (Fold(arg0, out z)) { + z = z.Neg; + return true; + } + + } else if (e.Arguments.Count == 2) { + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(e.Arguments[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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.cs b/Source/AIFramework/VariableMap/ConstantExpressions.cs index fcf49b25..185c700e 100644 --- a/Source/AIFramework/VariableMap/ConstantExpressions.cs +++ b/Source/AIFramework/VariableMap/ConstantExpressions.cs @@ -1,538 +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);
+//----------------------------------------------------------------------------- +// +// 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)
- {
+ } + } + + /// <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
- {
+ + // 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
- {
+ } + 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
+ } + 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))
- {
+ foreach(IVariable v in depRight) + { + if(!result.variableDependences.ContainsKey(v)) + { result.variableDependences.Remove(v); - }
- }
- }
-
- // Now we remove the dependencies with variables not in variableBindings
+ } + } + } + + // 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);
+ + 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()
- {
+ } + } + + /// <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
+ 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.cs b/Source/AIFramework/VariableMap/DynamicTypeLattice.cs index 78bd61a0..edda7c1e 100644 --- a/Source/AIFramework/VariableMap/DynamicTypeLattice.cs +++ b/Source/AIFramework/VariableMap/DynamicTypeLattice.cs @@ -1,511 +1,511 @@ -//-----------------------------------------------------------------------------
-//
-// 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 System.Diagnostics.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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
-
- Contract.Invariant(what != What.Bottom || ty == null && manyBounds == null);
- Contract.Invariant(manyBounds == null || what == What.Bounds);
- Contract.Invariant(manyBounds == null || Contract.ForAll(0, manyBounds.Length, i => manyBounds[i] != null));
- }
- public Elt(What what, IExpr ty) {
- Contract.Requires(what != What.Bottom || ty == null);
- Contract.Requires(what != What.Exact || ty != null);
- this.what = what;
- this.ty = ty;
- this.manyBounds = null;
- }
-
- public Elt(IExpr[]/*!*/ bounds) {
- Contract.Requires(bounds != null);
- Contract.Requires(Contract.ForAll(0, bounds.Length, i => 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) {
- Contract.Requires(bounds != null);
- Contract.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) {
- Contract.Assert(k != n);
- if (n == 1) {
- Contract.Assert(this.ty == null);
- this.ty = bound;
- } else {
- Contract.Assume(manyBounds != null);
- manyBounds[k] = bound;
- }
- k++;
- }
- }
- Contract.Assert(k == n);
- }
-
- public int BoundsCount {
- get {
- Contract.Ensures(0 <= Contract.Result<int>());
- if (manyBounds != null) {
- return manyBounds.Length;
- } else if (ty != null) {
- return 1;
- } else {
- return 0;
- }
- }
- }
-
- [Pure]
- public override System.Collections.Generic.ICollection<IVariable/*!*/>/*!*/ FreeVariables() {
- Contract.Ensures(cce.NonNullElements(Contract.Result<System.Collections.Generic.ICollection<IVariable>>()));
- return cce.NonNull(new System.Collections.Generic.List<IVariable/*!*/>()).AsReadOnly();
- }
-
- public override Element/*!*/ Clone() {
- Contract.Ensures(Contract.Result<Element>() != null);
- if (this.manyBounds != null)
- return new Elt(this.manyBounds);
- else
- return new Elt(this.what, this.ty);
- }
- }
-
- readonly ITypeExprFactory/*!*/ factory;
- readonly IPropExprFactory/*!*/ propFactory;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(factory != null);
- Contract.Invariant(propFactory != null);
- }
-
-
- public DynamicTypeLattice(ITypeExprFactory/*!*/ factory, IPropExprFactory/*!*/ propFactory) {
- Contract.Requires(propFactory != null);
- Contract.Requires(factory != null);
- this.factory = factory;
- this.propFactory = propFactory;
- // base();
- }
-
- public override Element/*!*/ Top {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- return new Elt(What.Bounds, null);
- }
- }
-
- public override Element/*!*/ Bottom {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- return new Elt(What.Bottom, null);
- }
- }
-
- public override bool IsTop(Element/*!*/ element) {
- //Contract.Requires(element != null);
- Elt e = (Elt)element;
- return e.what == What.Bounds && e.ty == null && e.manyBounds == null;
- }
-
- public override bool IsBottom(Element/*!*/ element) {
- //Contract.Requires(element != null);
- Elt e = (Elt)element;
- return e.what == What.Bottom;
- }
-
- public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- Elt a = (Elt)first;
- Elt b = (Elt)second;
- Contract.Assert(a.what != What.Bottom && b.what != What.Bottom);
- if (a.what == What.Exact && b.what == What.Exact) {
- Contract.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.
- Contract.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) {
- Contract.Assert(a.ty != null && b.ty != null);
- IExpr join = factory.JoinTypes(a.ty, b.ty);
- Contract.Assert(join != null);
- 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(cce.NonNull(a.manyBounds));
- }
- int bStart = allBounds.Count;
- if (b.ty != null) {
- allBounds.Add(b.ty);
- } else {
- allBounds.AddRange(cce.NonNull(b.manyBounds));
- }
- // compute the join of each pair, putting non-redundant joins into "result"
- for (int i = 0; i < bStart; i++) {
- IExpr/*!*/ aBound = cce.NonNull((IExpr/*!*/)allBounds[i]);
- for (int j = bStart; j < allBounds.Count; j++) {
- IExpr/*!*/ bBound = (IExpr/*!*/)cce.NonNull(allBounds[j]);
-
- IExpr/*!*/ join = factory.JoinTypes(aBound, bBound);
- Contract.Assert(join != null);
-
- int k = 0;
- while (k < result.Count) {
- IExpr/*!*/ r = (IExpr/*!*/)cce.NonNull(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) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- Elt a = (Elt)first;
- Elt b = (Elt)second;
- Contract.Assert(a.what != What.Bottom && b.what != What.Bottom);
-
- if (a.what == What.Exact && b.what == What.Exact) {
- Contract.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;
- }
- Contract.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.
- Contract.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) {
- Contract.Assert(bound != null);
- if (!factory.IsSubType(a.ty, bound)) {
- return Bottom;
- }
- }
- }
- return a;
- } else {
- // Both operands are Bounds.
- Contract.Assert(a.what == What.Bounds && b.what == What.Bounds);
-
- // Take all the bounds, but prune those bounds that follow from others.
- Contract.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) {
- Contract.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(cce.NonNull(a.manyBounds));
- }
- int bStart = allBounds.Count;
- if (b.ty != null) {
- allBounds.Add(b.ty);
- } else {
- allBounds.AddRange(cce.NonNull(b.manyBounds));
- }
- for (int i = 0; i < bStart; i++) {
- IExpr/*!*/ aBound = cce.NonNull((IExpr)allBounds[i]);
- for (int j = bStart; j < allBounds.Count; j++) {
- IExpr bBound = (IExpr/*! Wouldn't the non-null typing in the original Spec# code had made bBound never null,
- * thus negating the need for the continue statement?*/
- )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: {
- }
- }
- Contract.Assert(1 <= n);
- return new Elt(allBounds, n);
- }
- }
-
- public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- return Join(first, second);
- }
-
- protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that
- {
- //Contract.Requires(first != null);
- //Contract.Requires(second != null);
- Elt/*!*/ a = (Elt/*!*/)cce.NonNull(first);
- Elt/*!*/ b = (Elt/*!*/)cce.NonNull(second);
- Contract.Assert(a.what != What.Bottom && b.what != What.Bottom);
-
- if (a.what == What.Exact && b.what == What.Exact) {
- Contract.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) {
- Contract.Assert(a.ty != null);
- if (b.ty != null) {
- return factory.IsSubType(a.ty, b.ty);
- } else {
- return Contract.ForAll(b.manyBounds, bound => factory.IsSubType(a.ty, bound));
- }
- } else {
- Contract.Assert(a.what == What.Bounds && b.what == What.Bounds);
- Contract.Assert(a.ty != null || a.manyBounds != null); // a precondition is that a is not Top
- Contract.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 Contract.ForAll(b.manyBounds, bound => factory.IsSubType(a.ty, bound));
- } else if (b.ty != null) {
- return Contract.Exists(a.manyBounds, bound => factory.IsSubType(bound, b.ty));
- } else {
- return Contract.ForAll(b.manyBounds, bBound => Contract.Exists(a.manyBounds, aBound => factory.IsSubType(aBound, bBound)));
- }
- }
- }
-
- public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) {
- //Contract.Requires(element != null);
- //Contract.Requires(var != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- Elt e = (Elt)element;
- switch (e.what) {
- case What.Bottom:
- return propFactory.False;
- case What.Exact:
- return factory.IsExactlyA(var, cce.NonNull(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/*!*/)cce.NonNull(e.manyBounds)[0]);
- for (int i = 1; i < e.manyBounds.Length; i++) {
- p = propFactory.And(p, factory.IsA(var, (IExpr/*!*/)cce.NonNull(e.manyBounds[i])));
- }
- return p;
- }
- default: {
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
- throw new System.Exception();
- }
- }
-
- public override IExpr GetFoldExpr(Element/*!*/ e) {
- //Contract.Requires(e != null);
- // cannot fold into an expression that can be substituted for the variable
- return null;
- }
-
- public override bool Understands(IFunctionSymbol/*!*/ f, IList/*<IExpr!>*//*!*/ args) {
- //Contract.Requires(args != null);
- //Contract.Requires(f != null);
- bool isEq = f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq);
- if (isEq || f.Equals(Microsoft.AbstractInterpretationFramework.Value.Subtype)) {
- Contract.Assert(args.Count == 2);
- IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]);
- IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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)) {
- Contract.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) {
- //Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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;
- Contract.Assert(args != null);
- Contract.Assert(args.Count == 2);
- IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]);
- IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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)) {
- Contract.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;
- }
-
- }
-}
+//----------------------------------------------------------------------------- +// +// 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 System.Diagnostics.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; + [ContractInvariantMethod] + void ObjectInvariant() { + + Contract.Invariant(what != What.Bottom || ty == null && manyBounds == null); + Contract.Invariant(manyBounds == null || what == What.Bounds); + Contract.Invariant(manyBounds == null || Contract.ForAll(0, manyBounds.Length, i => manyBounds[i] != null)); + } + public Elt(What what, IExpr ty) { + Contract.Requires(what != What.Bottom || ty == null); + Contract.Requires(what != What.Exact || ty != null); + this.what = what; + this.ty = ty; + this.manyBounds = null; + } + + public Elt(IExpr[]/*!*/ bounds) { + Contract.Requires(bounds != null); + Contract.Requires(Contract.ForAll(0, bounds.Length, i => 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) { + Contract.Requires(bounds != null); + Contract.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) { + Contract.Assert(k != n); + if (n == 1) { + Contract.Assert(this.ty == null); + this.ty = bound; + } else { + Contract.Assume(manyBounds != null); + manyBounds[k] = bound; + } + k++; + } + } + Contract.Assert(k == n); + } + + public int BoundsCount { + get { + Contract.Ensures(0 <= Contract.Result<int>()); + if (manyBounds != null) { + return manyBounds.Length; + } else if (ty != null) { + return 1; + } else { + return 0; + } + } + } + + [Pure] + public override System.Collections.Generic.ICollection<IVariable/*!*/>/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result<System.Collections.Generic.ICollection<IVariable>>())); + return cce.NonNull(new System.Collections.Generic.List<IVariable/*!*/>()).AsReadOnly(); + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result<Element>() != null); + if (this.manyBounds != null) + return new Elt(this.manyBounds); + else + return new Elt(this.what, this.ty); + } + } + + readonly ITypeExprFactory/*!*/ factory; + readonly IPropExprFactory/*!*/ propFactory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(factory != null); + Contract.Invariant(propFactory != null); + } + + + public DynamicTypeLattice(ITypeExprFactory/*!*/ factory, IPropExprFactory/*!*/ propFactory) { + Contract.Requires(propFactory != null); + Contract.Requires(factory != null); + this.factory = factory; + this.propFactory = propFactory; + // base(); + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result<Element>() != null); + return new Elt(What.Bounds, null); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result<Element>() != null); + return new Elt(What.Bottom, null); + } + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.what == What.Bounds && e.ty == null && e.manyBounds == null; + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.what == What.Bottom; + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Element>() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); + if (a.what == What.Exact && b.what == What.Exact) { + Contract.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. + Contract.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) { + Contract.Assert(a.ty != null && b.ty != null); + IExpr join = factory.JoinTypes(a.ty, b.ty); + Contract.Assert(join != null); + 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(cce.NonNull(a.manyBounds)); + } + int bStart = allBounds.Count; + if (b.ty != null) { + allBounds.Add(b.ty); + } else { + allBounds.AddRange(cce.NonNull(b.manyBounds)); + } + // compute the join of each pair, putting non-redundant joins into "result" + for (int i = 0; i < bStart; i++) { + IExpr/*!*/ aBound = cce.NonNull((IExpr/*!*/)allBounds[i]); + for (int j = bStart; j < allBounds.Count; j++) { + IExpr/*!*/ bBound = (IExpr/*!*/)cce.NonNull(allBounds[j]); + + IExpr/*!*/ join = factory.JoinTypes(aBound, bBound); + Contract.Assert(join != null); + + int k = 0; + while (k < result.Count) { + IExpr/*!*/ r = (IExpr/*!*/)cce.NonNull(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) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Element>() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); + + if (a.what == What.Exact && b.what == What.Exact) { + Contract.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; + } + Contract.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. + Contract.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) { + Contract.Assert(bound != null); + if (!factory.IsSubType(a.ty, bound)) { + return Bottom; + } + } + } + return a; + } else { + // Both operands are Bounds. + Contract.Assert(a.what == What.Bounds && b.what == What.Bounds); + + // Take all the bounds, but prune those bounds that follow from others. + Contract.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) { + Contract.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(cce.NonNull(a.manyBounds)); + } + int bStart = allBounds.Count; + if (b.ty != null) { + allBounds.Add(b.ty); + } else { + allBounds.AddRange(cce.NonNull(b.manyBounds)); + } + for (int i = 0; i < bStart; i++) { + IExpr/*!*/ aBound = cce.NonNull((IExpr)allBounds[i]); + for (int j = bStart; j < allBounds.Count; j++) { + IExpr bBound = (IExpr/*! Wouldn't the non-null typing in the original Spec# code had made bBound never null, + * thus negating the need for the continue statement?*/ + )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: { + } + } + Contract.Assert(1 <= n); + return new Elt(allBounds, n); + } + } + + public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Element>() != null); + return Join(first, second); + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that + { + //Contract.Requires(first != null); + //Contract.Requires(second != null); + Elt/*!*/ a = (Elt/*!*/)cce.NonNull(first); + Elt/*!*/ b = (Elt/*!*/)cce.NonNull(second); + Contract.Assert(a.what != What.Bottom && b.what != What.Bottom); + + if (a.what == What.Exact && b.what == What.Exact) { + Contract.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) { + Contract.Assert(a.ty != null); + if (b.ty != null) { + return factory.IsSubType(a.ty, b.ty); + } else { + return Contract.ForAll(b.manyBounds, bound => factory.IsSubType(a.ty, bound)); + } + } else { + Contract.Assert(a.what == What.Bounds && b.what == What.Bounds); + Contract.Assert(a.ty != null || a.manyBounds != null); // a precondition is that a is not Top + Contract.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 Contract.ForAll(b.manyBounds, bound => factory.IsSubType(a.ty, bound)); + } else if (b.ty != null) { + return Contract.Exists(a.manyBounds, bound => factory.IsSubType(bound, b.ty)); + } else { + return Contract.ForAll(b.manyBounds, bBound => Contract.Exists(a.manyBounds, aBound => factory.IsSubType(aBound, bBound))); + } + } + } + + public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { + //Contract.Requires(element != null); + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + Elt e = (Elt)element; + switch (e.what) { + case What.Bottom: + return propFactory.False; + case What.Exact: + return factory.IsExactlyA(var, cce.NonNull(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/*!*/)cce.NonNull(e.manyBounds)[0]); + for (int i = 1; i < e.manyBounds.Length; i++) { + p = propFactory.And(p, factory.IsA(var, (IExpr/*!*/)cce.NonNull(e.manyBounds[i]))); + } + return p; + } + default: { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + throw new System.Exception(); + } + } + + public override IExpr GetFoldExpr(Element/*!*/ e) { + //Contract.Requires(e != null); + // cannot fold into an expression that can be substituted for the variable + return null; + } + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/*<IExpr!>*//*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + bool isEq = f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq); + if (isEq || f.Equals(Microsoft.AbstractInterpretationFramework.Value.Subtype)) { + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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)) { + Contract.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) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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; + Contract.Assert(args != null); + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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)) { + Contract.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.cs b/Source/AIFramework/VariableMap/Intervals.cs index 0bf82cf4..98bf9007 100644 --- a/Source/AIFramework/VariableMap/Intervals.cs +++ b/Source/AIFramework/VariableMap/Intervals.cs @@ -1,871 +1,871 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Collections;
-//using System.Compiler.Analysis;
-using Microsoft.AbstractInterpretationFramework.Collections;
-using System.Diagnostics.Contracts;
-using Microsoft.Basetypes;
-
-/////////////////////////////////////////////////////////////////////////////////
-// An implementation of the interval abstract domain
-/////////////////////////////////////////////////////////////////////////////////
-
-namespace Microsoft.AbstractInterpretationFramework {
- public class IntervalLattice : MicroLattice {
- readonly ILinearExprFactory/*!*/ factory;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(factory != null);
- }
-
-
- public IntervalLattice(ILinearExprFactory/*!*/ factory) {
- Contract.Requires(factory != null);
- this.factory = factory;
- // base();
- }
-
- public override bool UnderstandsBasicArithmetics {
- get {
- return true;
- }
- }
-
- public override Element/*!*/ Top {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
-
- return IntervalElement.Top;
- }
- }
-
- public override Element/*!*/ Bottom {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
-
- return IntervalElement.Bottom;
- }
- }
-
- /// <summary>
- /// The paramter is the top?
- /// </summary>
- public override bool IsTop(Element/*!*/ element) {
- //Contract.Requires(element != null);
- IntervalElement interval = (IntervalElement)element;
-
- return interval.IsTop();
- }
-
- /// <summary>
- /// The parameter is the bottom?
- /// </summary>
- public override bool IsBottom(Element/*!*/ element) {
- //Contract.Requires(element != null);
- IntervalElement interval = (IntervalElement)element;
-
- return interval.IsBottom();
- }
-
- /// <summary>
- /// The classic, pointwise, join of intervals
- /// </summary>
- public override Element/*!*/ NontrivialJoin(Element/*!*/ left, Element/*!*/ right) {
- //Contract.Requires(right != null);
- //Contract.Requires(left != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left);
- IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(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) {
- //Contract.Requires(right != null);
- //Contract.Requires(left != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left);
- IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(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) {
- //Contract.Requires(right != null);
- //Contract.Requires(left != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- IntervalElement/*!*/ prevInterval = (IntervalElement/*!*/)cce.NonNull(left);
- IntervalElement/*!*/ nextInterval = (IntervalElement/*!*/)cce.NonNull(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) {
- //Contract.Requires(right != null);
- //Contract.Requires(left != null);
- IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left);
- IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(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) {
- //Contract.Requires(element != null);
- 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) {
- //Contract.Requires(element != null);
- //Contract.Requires(var != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- IntervalElement/*!*/ interval = (IntervalElement/*!*/)cce.NonNull(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) {
- //Contract.Requires(args != null);
- //Contract.Requires(f != null);
- 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) {
- //Contract.Requires(pred != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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) {
- //Contract.Requires(pred != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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/*!*/)cce.NonNull(fun.Arguments[0]);
- IExpr/*!*/ rightArg = (IExpr/*!*/)cce.NonNull(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) {
- Contract.Requires((exp != null));
- Contract.Ensures(Contract.Result<IntervalElement>() != null);
-
- IntervalElement/*!*/ retVal = (IntervalElement/*!*/)cce.NonNull(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/*!*/)cce.NonNull(fun.Arguments[0]);
- IntervalElement/*!*/ argEval = Eval(arg, state);
- Contract.Assert(argEval != null);
- IntervalElement/*!*/ zero = IntervalElement.Factory(BigNum.ZERO);
- Contract.Assert(zero != null);
-
- retVal = zero - argEval;
- } else if (fun.Arguments.Count == 2) {
- IExpr/*!*/ left = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]);
- IExpr/*!*/ right = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]);
-
- IntervalElement/*!*/ leftVal = Eval(left, state);
- Contract.Assert(leftVal != null);
- IntervalElement/*!*/ rightVal = Eval(right, state);
- Contract.Assert(rightVal != null);
-
- 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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(inf != null);
- Contract.Invariant(sup != null);
- }
-
- public ExtendedInt/*!*/ Inf {
- get {
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
-
- return inf;
- }
- }
-
- public ExtendedInt/*!*/ Sup {
- get {
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
-
- 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) {
- Contract.Requires(sup != null);
- Contract.Requires(inf != null);
- this.inf = inf;
- this.sup = sup;
- // base();
- }
-
- // Construct an Interval
- public static IntervalElement/*!*/ Factory(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) {
- Contract.Requires((sup != null));
- Contract.Requires((inf != null));
- Contract.Ensures(Contract.Result<IntervalElement>() != null);
- 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) {
- Contract.Ensures(Contract.Result<IntervalElement>() != null);
- return new IntervalElement(i);
- }
-
- public static IntervalElement/*!*/ Factory(BigNum inf, BigNum sup) {
- Contract.Ensures(Contract.Result<IntervalElement>() != null);
- ExtendedInt/*!*/ i = ExtendedInt.Factory(inf);
- ExtendedInt/*!*/ s = ExtendedInt.Factory(sup);
-
- return Factory(i, s);
- }
-
- static public IntervalElement/*!*/ Top {
- get {
- Contract.Ensures(Contract.Result<IntervalElement>() != null);
-
- return TopInterval;
- }
- }
-
- static public IntervalElement/*!*/ Bottom {
- get {
- Contract.Ensures(Contract.Result<IntervalElement>() != null);
-
- 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) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<IntervalElement>() != null);
- ExtendedInt/*!*/ inf = a.inf + b.inf;
- Contract.Assert(inf != null);
- ExtendedInt/*!*/ sup = a.sup + b.sup;
- Contract.Assert(sup != null);
-
- return Factory(inf, sup);
- }
-
- // Subtraction
- public static IntervalElement/*!*/ operator -(IntervalElement/*!*/ a, IntervalElement/*!*/ b) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<IntervalElement>() != null);
- ExtendedInt/*!*/ inf = a.inf - b.sup;
- Contract.Assert(inf != null);
-
- ExtendedInt/*!*/ sup = a.sup - b.inf;
- Contract.Assert(sup != null);
- IntervalElement/*!*/ sub = Factory(inf, sup);
- Contract.Assert(sub != null);
-
- return sub;
- }
-
- // Multiplication
- public static IntervalElement/*!*/ operator *(IntervalElement/*!*/ a, IntervalElement/*!*/ b) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<IntervalElement>() != null);
- ExtendedInt/*!*/ infinf = a.inf * b.inf;
- Contract.Assert(infinf != null);
- ExtendedInt/*!*/ infsup = a.inf * b.sup;
- Contract.Assert(infsup != null);
- ExtendedInt/*!*/ supinf = a.sup * b.inf;
- Contract.Assert(supinf != null);
- ExtendedInt/*!*/ supsup = a.sup * b.sup;
- Contract.Assert(supsup != null);
-
- ExtendedInt/*!*/ inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup);
- Contract.Assert(inf != null);
- ExtendedInt/*!*/ sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup);
- Contract.Assert(sup != null);
-
- return Factory(inf, sup);
- }
-
- // Division
- public static IntervalElement/*!*/ operator /(IntervalElement/*!*/ a, IntervalElement/*!*/ b) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<IntervalElement>() != null);
- if (b.inf.IsZero && b.sup.IsZero) // Check division by zero
- return IntervalElement.Top;
-
- ExtendedInt/*!*/ infinf = a.inf / b.inf;
- Contract.Assert(infinf != null);
- ExtendedInt/*!*/ infsup = a.inf / b.sup;
- Contract.Assert(infsup != null);
- ExtendedInt/*!*/ supinf = a.sup / b.inf;
- Contract.Assert(supinf != null);
- ExtendedInt/*!*/ supsup = a.sup / b.sup;
- Contract.Assert(supsup != null);
-
- ExtendedInt/*!*/ inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup);
- Contract.Assert(inf != null);
- ExtendedInt/*!*/ sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup);
- Contract.Assert(sup != null);
-
- return Factory(inf, sup);
- }
-
- // Division
- public static IntervalElement/*!*/ operator %(IntervalElement/*!*/ a, IntervalElement/*!*/ b) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<IntervalElement>() != null);
- if (b.inf.IsZero && b.sup.IsZero) // Check division by zero
- return IntervalElement.Top;
-
- ExtendedInt/*!*/ infinf = a.inf % b.inf;
- Contract.Assert(infinf != null);
- ExtendedInt/*!*/ infsup = a.inf % b.sup;
- Contract.Assert(infsup != null);
- ExtendedInt/*!*/ supinf = a.sup % b.inf;
- Contract.Assert(supinf != null);
- ExtendedInt/*!*/ supsup = a.sup % b.sup;
- Contract.Assert(supsup != null);
-
- 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() {
- Contract.Ensures(Contract.Result<Element>() != null);
- // Real copying should not be needed because intervals are immutable?
- return this;
- /*
- int valInf = this.inf.Value;
- int valSup = this.sup.Value;
-
- ExtendedInt clonedInf = ExtendedInt.Factory(valInf);
- ExtendedInt clonedSup = ExtendedInt.Factory(valSup);
-
- return Factory(clonedInf, clonedSup);
- */
- }
-
- [Pure]
- public override System.Collections.Generic.ICollection<IVariable/*!*/>/*!*/ FreeVariables() {
- Contract.Ensures(cce.NonNullElements(Contract.Result<System.Collections.Generic.ICollection<IVariable>>()));
- return cce.NonNull(new System.Collections.Generic.List<IVariable/*!*/>()).AsReadOnly();
- }
-
- [Pure]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- return "[" + this.inf + ", " + this.sup + "]";
- }
-
- #endregion
- }
- }
-
-
- /// The interface for an extended integer
- ///
- [ContractClass(typeof(ExtendedIntContracts))]
- abstract class ExtendedInt {
- private static readonly PlusInfinity/*!*/ cachedPlusInf = new PlusInfinity();
- private static readonly MinusInfinity/*!*/ cachedMinusInf = new MinusInfinity();
-
- static public ExtendedInt/*!*/ PlusInfinity {
- get {
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
-
- return cachedPlusInf;
- }
- }
-
- static public ExtendedInt/*!*/ MinusInfinity {
- get {
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
-
- 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) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
- 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) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
- 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) {
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
- // BUGBUG: Some compiler error prevents the unary minus operator from being used
- return UnaryMinus(a);
- }
-
- // Unary minus
- public static ExtendedInt/*!*/ UnaryMinus(ExtendedInt/*!*/ a) {
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
- 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) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
- 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) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
- 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) {
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
- 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) {
- Contract.Requires(sup != null);
- Contract.Requires(inf != null);
- return inf.CompareTo(sup) < 0;
- }
-
- public static bool operator >(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) {
- Contract.Requires(sup != null);
- Contract.Requires(inf != null);
- return inf.CompareTo(sup) > 0;
- }
-
- public static bool operator <=(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) {
- Contract.Requires(sup != null);
- Contract.Requires(inf != null);
- return inf.CompareTo(sup) <= 0;
- }
-
- public static bool operator >=(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) {
- Contract.Requires(sup != null);
- Contract.Requires(inf != null);
- Contract.Requires(inf != null && sup != null);
- return inf.CompareTo(sup) >= 0;
- }
-
- public static ExtendedInt/*!*/ Inf(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) {
- Contract.Requires(sup != null);
- Contract.Requires(inf != null);
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
- if (inf < sup)
- return inf;
- else
- return sup;
- }
-
- public static ExtendedInt/*!*/ Inf(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b, ExtendedInt/*!*/ c, ExtendedInt/*!*/ d) {
- Contract.Requires(d != null);
- Contract.Requires(c != null);
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
- ExtendedInt/*!*/ infab = Inf(a, b);
- Contract.Assert(infab != null);
- ExtendedInt/*!*/ infcd = Inf(c, d);
- Contract.Assert(infcd != null);
-
- return Inf(infab, infcd);
- }
-
- public static ExtendedInt/*!*/ Sup(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) {
- Contract.Requires(sup != null);
- Contract.Requires(inf != null);
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
- if (inf > sup)
- return inf;
- else
- return sup;
- }
-
- public static ExtendedInt/*!*/ Sup(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b, ExtendedInt/*!*/ c, ExtendedInt/*!*/ d) {
- Contract.Requires(d != null);
- Contract.Requires(c != null);
- Contract.Requires(b != null);
- Contract.Requires(a != null);
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
- ExtendedInt/*!*/ supab = Sup(a, b);
- Contract.Assert(supab != null);
- ExtendedInt/*!*/ supcd = Sup(c, d);
- Contract.Assert(supcd != null);
-
- return Sup(supab, supcd);
- }
-
- #endregion
-
- // Return the ExtendedInt corresponding to the value
- public static ExtendedInt/*!*/ Factory(BigNum val) {
- Contract.Ensures(Contract.Result<ExtendedInt>() != null);
- return new PureInteger(val);
- }
- }
- [ContractClassFor(typeof(ExtendedInt))]
- abstract class ExtendedIntContracts : ExtendedInt {
- public override int CompareTo(ExtendedInt that) {
- Contract.Requires(that != null);
- throw new NotImplementedException();
- }
- }
-
- // Stands for a normal (finite) integer x
- class PureInteger : ExtendedInt {
- public PureInteger(BigNum i) {
- this.val = i;
- }
-
- [Pure]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- 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) {
- //Contract.Requires(that != null);
- if (that is PlusInfinity)
- return -1;
- else if (that is PureInteger)
- return this.Value.CompareTo(that.Value);
- else // then that is a MinusInfinity
- return 1;
- }
- }
-
- abstract class InfinitaryInt : ExtendedInt {
- public override BigNum Value {
- get {
- throw new InvalidOperationException();
- }
- }
- }
-
- class PlusInfinity : InfinitaryInt {
- [Pure]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- return "+oo";
- }
-
- public override int Signum {
- get {
- return 1;
- }
- }
-
- public override int CompareTo(ExtendedInt/*!*/ that) {
- //Contract.Requires(that != null);
- if (that is PlusInfinity)
- return 0;
- else
- return 1;
- }
- }
-
- class MinusInfinity : InfinitaryInt {
- [Pure]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- return "-oo";
- }
-
- public override int Signum {
- get {
- return -1;
- }
- }
-
- public override int CompareTo(ExtendedInt/*!*/ that) {
- //Contract.Requires(that != null);
- if (that is MinusInfinity)
- return 0;
- else
- return -1;
- }
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections; +//using System.Compiler.Analysis; +using Microsoft.AbstractInterpretationFramework.Collections; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; + +///////////////////////////////////////////////////////////////////////////////// +// An implementation of the interval abstract domain +///////////////////////////////////////////////////////////////////////////////// + +namespace Microsoft.AbstractInterpretationFramework { + public class IntervalLattice : MicroLattice { + readonly ILinearExprFactory/*!*/ factory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(factory != null); + } + + + public IntervalLattice(ILinearExprFactory/*!*/ factory) { + Contract.Requires(factory != null); + this.factory = factory; + // base(); + } + + public override bool UnderstandsBasicArithmetics { + get { + return true; + } + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result<Element>() != null); + + return IntervalElement.Top; + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result<Element>() != null); + + return IntervalElement.Bottom; + } + } + + /// <summary> + /// The paramter is the top? + /// </summary> + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + IntervalElement interval = (IntervalElement)element; + + return interval.IsTop(); + } + + /// <summary> + /// The parameter is the bottom? + /// </summary> + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + IntervalElement interval = (IntervalElement)element; + + return interval.IsBottom(); + } + + /// <summary> + /// The classic, pointwise, join of intervals + /// </summary> + public override Element/*!*/ NontrivialJoin(Element/*!*/ left, Element/*!*/ right) { + //Contract.Requires(right != null); + //Contract.Requires(left != null); + Contract.Ensures(Contract.Result<Element>() != null); + IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); + IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(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) { + //Contract.Requires(right != null); + //Contract.Requires(left != null); + Contract.Ensures(Contract.Result<Element>() != null); + IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); + IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(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) { + //Contract.Requires(right != null); + //Contract.Requires(left != null); + Contract.Ensures(Contract.Result<Element>() != null); + IntervalElement/*!*/ prevInterval = (IntervalElement/*!*/)cce.NonNull(left); + IntervalElement/*!*/ nextInterval = (IntervalElement/*!*/)cce.NonNull(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) { + //Contract.Requires(right != null); + //Contract.Requires(left != null); + IntervalElement/*!*/ leftInterval = (IntervalElement/*!*/)cce.NonNull(left); + IntervalElement/*!*/ rightInterval = (IntervalElement/*!*/)cce.NonNull(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) { + //Contract.Requires(element != null); + 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) { + //Contract.Requires(element != null); + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + IntervalElement/*!*/ interval = (IntervalElement/*!*/)cce.NonNull(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) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + 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) { + //Contract.Requires(pred != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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) { + //Contract.Requires(pred != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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/*!*/)cce.NonNull(fun.Arguments[0]); + IExpr/*!*/ rightArg = (IExpr/*!*/)cce.NonNull(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) { + Contract.Requires((exp != null)); + Contract.Ensures(Contract.Result<IntervalElement>() != null); + + IntervalElement/*!*/ retVal = (IntervalElement/*!*/)cce.NonNull(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/*!*/)cce.NonNull(fun.Arguments[0]); + IntervalElement/*!*/ argEval = Eval(arg, state); + Contract.Assert(argEval != null); + IntervalElement/*!*/ zero = IntervalElement.Factory(BigNum.ZERO); + Contract.Assert(zero != null); + + retVal = zero - argEval; + } else if (fun.Arguments.Count == 2) { + IExpr/*!*/ left = (IExpr/*!*/)cce.NonNull(fun.Arguments[0]); + IExpr/*!*/ right = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); + + IntervalElement/*!*/ leftVal = Eval(left, state); + Contract.Assert(leftVal != null); + IntervalElement/*!*/ rightVal = Eval(right, state); + Contract.Assert(rightVal != null); + + 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; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(inf != null); + Contract.Invariant(sup != null); + } + + public ExtendedInt/*!*/ Inf { + get { + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + + return inf; + } + } + + public ExtendedInt/*!*/ Sup { + get { + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + + 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) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + this.inf = inf; + this.sup = sup; + // base(); + } + + // Construct an Interval + public static IntervalElement/*!*/ Factory(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires((sup != null)); + Contract.Requires((inf != null)); + Contract.Ensures(Contract.Result<IntervalElement>() != null); + 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) { + Contract.Ensures(Contract.Result<IntervalElement>() != null); + return new IntervalElement(i); + } + + public static IntervalElement/*!*/ Factory(BigNum inf, BigNum sup) { + Contract.Ensures(Contract.Result<IntervalElement>() != null); + ExtendedInt/*!*/ i = ExtendedInt.Factory(inf); + ExtendedInt/*!*/ s = ExtendedInt.Factory(sup); + + return Factory(i, s); + } + + static public IntervalElement/*!*/ Top { + get { + Contract.Ensures(Contract.Result<IntervalElement>() != null); + + return TopInterval; + } + } + + static public IntervalElement/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result<IntervalElement>() != null); + + 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) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<IntervalElement>() != null); + ExtendedInt/*!*/ inf = a.inf + b.inf; + Contract.Assert(inf != null); + ExtendedInt/*!*/ sup = a.sup + b.sup; + Contract.Assert(sup != null); + + return Factory(inf, sup); + } + + // Subtraction + public static IntervalElement/*!*/ operator -(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<IntervalElement>() != null); + ExtendedInt/*!*/ inf = a.inf - b.sup; + Contract.Assert(inf != null); + + ExtendedInt/*!*/ sup = a.sup - b.inf; + Contract.Assert(sup != null); + IntervalElement/*!*/ sub = Factory(inf, sup); + Contract.Assert(sub != null); + + return sub; + } + + // Multiplication + public static IntervalElement/*!*/ operator *(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<IntervalElement>() != null); + ExtendedInt/*!*/ infinf = a.inf * b.inf; + Contract.Assert(infinf != null); + ExtendedInt/*!*/ infsup = a.inf * b.sup; + Contract.Assert(infsup != null); + ExtendedInt/*!*/ supinf = a.sup * b.inf; + Contract.Assert(supinf != null); + ExtendedInt/*!*/ supsup = a.sup * b.sup; + Contract.Assert(supsup != null); + + ExtendedInt/*!*/ inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); + Contract.Assert(inf != null); + ExtendedInt/*!*/ sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); + Contract.Assert(sup != null); + + return Factory(inf, sup); + } + + // Division + public static IntervalElement/*!*/ operator /(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<IntervalElement>() != null); + if (b.inf.IsZero && b.sup.IsZero) // Check division by zero + return IntervalElement.Top; + + ExtendedInt/*!*/ infinf = a.inf / b.inf; + Contract.Assert(infinf != null); + ExtendedInt/*!*/ infsup = a.inf / b.sup; + Contract.Assert(infsup != null); + ExtendedInt/*!*/ supinf = a.sup / b.inf; + Contract.Assert(supinf != null); + ExtendedInt/*!*/ supsup = a.sup / b.sup; + Contract.Assert(supsup != null); + + ExtendedInt/*!*/ inf = ExtendedInt.Inf(infinf, infsup, supinf, supsup); + Contract.Assert(inf != null); + ExtendedInt/*!*/ sup = ExtendedInt.Sup(infinf, infsup, supinf, supsup); + Contract.Assert(sup != null); + + return Factory(inf, sup); + } + + // Division + public static IntervalElement/*!*/ operator %(IntervalElement/*!*/ a, IntervalElement/*!*/ b) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<IntervalElement>() != null); + if (b.inf.IsZero && b.sup.IsZero) // Check division by zero + return IntervalElement.Top; + + ExtendedInt/*!*/ infinf = a.inf % b.inf; + Contract.Assert(infinf != null); + ExtendedInt/*!*/ infsup = a.inf % b.sup; + Contract.Assert(infsup != null); + ExtendedInt/*!*/ supinf = a.sup % b.inf; + Contract.Assert(supinf != null); + ExtendedInt/*!*/ supsup = a.sup % b.sup; + Contract.Assert(supsup != null); + + 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() { + Contract.Ensures(Contract.Result<Element>() != null); + // Real copying should not be needed because intervals are immutable? + return this; + /* + int valInf = this.inf.Value; + int valSup = this.sup.Value; + + ExtendedInt clonedInf = ExtendedInt.Factory(valInf); + ExtendedInt clonedSup = ExtendedInt.Factory(valSup); + + return Factory(clonedInf, clonedSup); + */ + } + + [Pure] + public override System.Collections.Generic.ICollection<IVariable/*!*/>/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result<System.Collections.Generic.ICollection<IVariable>>())); + return cce.NonNull(new System.Collections.Generic.List<IVariable/*!*/>()).AsReadOnly(); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result<string>() != null); + return "[" + this.inf + ", " + this.sup + "]"; + } + + #endregion + } + } + + + /// The interface for an extended integer + /// + [ContractClass(typeof(ExtendedIntContracts))] + abstract class ExtendedInt { + private static readonly PlusInfinity/*!*/ cachedPlusInf = new PlusInfinity(); + private static readonly MinusInfinity/*!*/ cachedMinusInf = new MinusInfinity(); + + static public ExtendedInt/*!*/ PlusInfinity { + get { + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + + return cachedPlusInf; + } + } + + static public ExtendedInt/*!*/ MinusInfinity { + get { + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + + 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) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + 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) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + 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) { + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + // BUGBUG: Some compiler error prevents the unary minus operator from being used + return UnaryMinus(a); + } + + // Unary minus + public static ExtendedInt/*!*/ UnaryMinus(ExtendedInt/*!*/ a) { + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + 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) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + 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) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + 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) { + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + 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) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + return inf.CompareTo(sup) < 0; + } + + public static bool operator >(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + return inf.CompareTo(sup) > 0; + } + + public static bool operator <=(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + return inf.CompareTo(sup) <= 0; + } + + public static bool operator >=(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + Contract.Requires(inf != null && sup != null); + return inf.CompareTo(sup) >= 0; + } + + public static ExtendedInt/*!*/ Inf(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + if (inf < sup) + return inf; + else + return sup; + } + + public static ExtendedInt/*!*/ Inf(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b, ExtendedInt/*!*/ c, ExtendedInt/*!*/ d) { + Contract.Requires(d != null); + Contract.Requires(c != null); + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + ExtendedInt/*!*/ infab = Inf(a, b); + Contract.Assert(infab != null); + ExtendedInt/*!*/ infcd = Inf(c, d); + Contract.Assert(infcd != null); + + return Inf(infab, infcd); + } + + public static ExtendedInt/*!*/ Sup(ExtendedInt/*!*/ inf, ExtendedInt/*!*/ sup) { + Contract.Requires(sup != null); + Contract.Requires(inf != null); + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + if (inf > sup) + return inf; + else + return sup; + } + + public static ExtendedInt/*!*/ Sup(ExtendedInt/*!*/ a, ExtendedInt/*!*/ b, ExtendedInt/*!*/ c, ExtendedInt/*!*/ d) { + Contract.Requires(d != null); + Contract.Requires(c != null); + Contract.Requires(b != null); + Contract.Requires(a != null); + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + ExtendedInt/*!*/ supab = Sup(a, b); + Contract.Assert(supab != null); + ExtendedInt/*!*/ supcd = Sup(c, d); + Contract.Assert(supcd != null); + + return Sup(supab, supcd); + } + + #endregion + + // Return the ExtendedInt corresponding to the value + public static ExtendedInt/*!*/ Factory(BigNum val) { + Contract.Ensures(Contract.Result<ExtendedInt>() != null); + return new PureInteger(val); + } + } + [ContractClassFor(typeof(ExtendedInt))] + abstract class ExtendedIntContracts : ExtendedInt { + public override int CompareTo(ExtendedInt that) { + Contract.Requires(that != null); + throw new NotImplementedException(); + } + } + + // Stands for a normal (finite) integer x + class PureInteger : ExtendedInt { + public PureInteger(BigNum i) { + this.val = i; + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result<string>() != null); + 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) { + //Contract.Requires(that != null); + if (that is PlusInfinity) + return -1; + else if (that is PureInteger) + return this.Value.CompareTo(that.Value); + else // then that is a MinusInfinity + return 1; + } + } + + abstract class InfinitaryInt : ExtendedInt { + public override BigNum Value { + get { + throw new InvalidOperationException(); + } + } + } + + class PlusInfinity : InfinitaryInt { + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result<string>() != null); + return "+oo"; + } + + public override int Signum { + get { + return 1; + } + } + + public override int CompareTo(ExtendedInt/*!*/ that) { + //Contract.Requires(that != null); + if (that is PlusInfinity) + return 0; + else + return 1; + } + } + + class MinusInfinity : InfinitaryInt { + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result<string>() != null); + return "-oo"; + } + + public override int Signum { + get { + return -1; + } + } + + public override int CompareTo(ExtendedInt/*!*/ that) { + //Contract.Requires(that != null); + if (that is MinusInfinity) + return 0; + else + return -1; + } + } +} diff --git a/Source/AIFramework/VariableMap/MicroLattice.cs b/Source/AIFramework/VariableMap/MicroLattice.cs index ef98f8f7..f46349b7 100644 --- a/Source/AIFramework/VariableMap/MicroLattice.cs +++ b/Source/AIFramework/VariableMap/MicroLattice.cs @@ -1,105 +1,105 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-namespace Microsoft.AbstractInterpretationFramework
-{
- using System.Diagnostics.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>
- ///
- [ContractClass(typeof(MicroLatticeContracts))]
- 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){
-Contract.Requires(e != null);
-Contract.Ensures(Contract.Result<Element>() != null);
- 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);
- }
- [ContractClassFor(typeof(MicroLattice))]
- public abstract class MicroLatticeContracts : MicroLattice {
- public override IExpr ToPredicate(IVariable v, MathematicalLattice.Element e) {
- Contract.Requires(v != null);
- Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- throw new System.NotImplementedException();
- }
- public override bool Understands(IFunctionSymbol f, IList args) {
- Contract.Requires(f != null);
- Contract.Requires(args != null);
- throw new System.NotImplementedException();
- }
- public override Element EvaluatePredicate(IExpr e) {
- Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- throw new System.NotImplementedException();
- }
- public override IExpr GetFoldExpr(MathematicalLattice.Element e) {
- Contract.Requires(e != null);
- throw new System.NotImplementedException();
- }
- }
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework +{ + using System.Diagnostics.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> + /// + [ContractClass(typeof(MicroLatticeContracts))] + 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){ +Contract.Requires(e != null); +Contract.Ensures(Contract.Result<Element>() != null); + 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); + } + [ContractClassFor(typeof(MicroLattice))] + public abstract class MicroLatticeContracts : MicroLattice { + public override IExpr ToPredicate(IVariable v, MathematicalLattice.Element e) { + Contract.Requires(v != null); + Contract.Requires(e != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + throw new System.NotImplementedException(); + } + public override bool Understands(IFunctionSymbol f, IList args) { + Contract.Requires(f != null); + Contract.Requires(args != null); + throw new System.NotImplementedException(); + } + public override Element EvaluatePredicate(IExpr e) { + Contract.Requires(e != null); + Contract.Ensures(Contract.Result<Element>() != null); + throw new System.NotImplementedException(); + } + public override IExpr GetFoldExpr(MathematicalLattice.Element e) { + Contract.Requires(e != null); + throw new System.NotImplementedException(); + } + } }
\ No newline at end of file diff --git a/Source/AIFramework/VariableMap/Nullness.cs b/Source/AIFramework/VariableMap/Nullness.cs index 613f55e0..474792e0 100644 --- a/Source/AIFramework/VariableMap/Nullness.cs +++ b/Source/AIFramework/VariableMap/Nullness.cs @@ -1,260 +1,260 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System.Diagnostics.Contracts;
-namespace Microsoft.AbstractInterpretationFramework {
- using System.Collections;
- using System.Diagnostics;
- //using System.Compiler.Analysis;
-
- public class NullnessLattice : MicroLattice {
- readonly INullnessFactory/*!*/ factory;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(factory != null);
- }
-
-
- public NullnessLattice(INullnessFactory/*!*/ factory) {
- Contract.Requires(factory != null);
- 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]
- public override System.Collections.Generic.ICollection<IVariable/*!*/>/*!*/ FreeVariables() {
- Contract.Ensures(cce.NonNullElements(Contract.Result<System.Collections.Generic.ICollection<IVariable>>()));
- return cce.NonNull(new System.Collections.Generic.List<IVariable/*!*/>()).AsReadOnly();
- }
-
- public override Element/*!*/ Clone() {
- Contract.Ensures(Contract.Result<Element>() != null);
- return new Elt(this.value);
- }
- }
-
-
- public override Element/*!*/ Top {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- return new Elt(Value.MayBeNull);
- }
- }
-
- public override Element/*!*/ Bottom {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- return new Elt(Value.Bottom);
- }
- }
-
- public static Element/*!*/ Null {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- return new Elt(Value.Null);
- }
- }
-
- public static Element/*!*/ NotNull {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- return new Elt(Value.NotNull);
- }
- }
-
- public override bool IsTop(Element/*!*/ element) {
- //Contract.Requires(element != null);
- Elt e = (Elt)element;
- return e.value == Value.MayBeNull;
- }
-
- public override bool IsBottom(Element/*!*/ element) {
- //Contract.Requires(element != null);
- Elt e = (Elt)element;
- return e.value == Value.Bottom;
- }
-
- public override Lattice.Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Lattice.Element>() != null);
- 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) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Lattice.Element>() != null);
- Elt a = (Elt)first;
- Elt b = (Elt)second;
- return (a.value == b.value) ? a : (Elt)Bottom;
- }
-
- public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- return Join(first, second);
- }
-
- protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that
- {
- //Contract.Requires(first != null);
- //Contract.Requires(second != null);
- Elt a = (Elt)first;
- Elt b = (Elt)second;
- return a.value == b.value;
- }
-
- public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) {
- //Contract.Requires(element != null);
- //Contract.Requires(var != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- 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);
- }
- {
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
- throw new System.Exception();
- }
-
- public override IExpr GetFoldExpr(Element/*!*/ e) {
- //Contract.Requires(e != null);
- 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) {
- //Contract.Requires(args != null);
- //Contract.Requires(f != null);
- if (f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq) ||
- f.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) {
-
- Contract.Assert(args.Count == 2);
- IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]);
- IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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) {
- //Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- 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;
- Contract.Assert(args != null);
- Contract.Assert(args.Count == 2);
- IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]);
- IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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
-
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System.Diagnostics.Contracts; +namespace Microsoft.AbstractInterpretationFramework { + using System.Collections; + using System.Diagnostics; + //using System.Compiler.Analysis; + + public class NullnessLattice : MicroLattice { + readonly INullnessFactory/*!*/ factory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(factory != null); + } + + + public NullnessLattice(INullnessFactory/*!*/ factory) { + Contract.Requires(factory != null); + 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] + public override System.Collections.Generic.ICollection<IVariable/*!*/>/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result<System.Collections.Generic.ICollection<IVariable>>())); + return cce.NonNull(new System.Collections.Generic.List<IVariable/*!*/>()).AsReadOnly(); + } + + public override Element/*!*/ Clone() { + Contract.Ensures(Contract.Result<Element>() != null); + return new Elt(this.value); + } + } + + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result<Element>() != null); + return new Elt(Value.MayBeNull); + } + } + + public override Element/*!*/ Bottom { + get { + Contract.Ensures(Contract.Result<Element>() != null); + return new Elt(Value.Bottom); + } + } + + public static Element/*!*/ Null { + get { + Contract.Ensures(Contract.Result<Element>() != null); + return new Elt(Value.Null); + } + } + + public static Element/*!*/ NotNull { + get { + Contract.Ensures(Contract.Result<Element>() != null); + return new Elt(Value.NotNull); + } + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.value == Value.MayBeNull; + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return e.value == Value.Bottom; + } + + public override Lattice.Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Lattice.Element>() != null); + 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) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Lattice.Element>() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + return (a.value == b.value) ? a : (Elt)Bottom; + } + + public override Element/*!*/ Widen(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Element>() != null); + return Join(first, second); + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) // this <= that + { + //Contract.Requires(first != null); + //Contract.Requires(second != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + return a.value == b.value; + } + + public override IExpr/*!*/ ToPredicate(IVariable/*!*/ var, Element/*!*/ element) { + //Contract.Requires(element != null); + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + 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); + } + { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + throw new System.Exception(); + } + + public override IExpr GetFoldExpr(Element/*!*/ e) { + //Contract.Requires(e != null); + 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) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + if (f.Equals(Microsoft.AbstractInterpretationFramework.Value.Eq) || + f.Equals(Microsoft.AbstractInterpretationFramework.Value.Neq)) { + + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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) { + //Contract.Requires(e != null); + Contract.Ensures(Contract.Result<Element>() != null); + 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; + Contract.Assert(args != null); + Contract.Assert(args.Count == 2); + IExpr/*!*/ arg0 = (IExpr/*!*/)cce.NonNull(args[0]); + IExpr/*!*/ arg1 = (IExpr/*!*/)cce.NonNull(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.cs b/Source/AIFramework/VariableMap/VariableMapLattice.cs index 172cef01..752d3f01 100644 --- a/Source/AIFramework/VariableMap/VariableMapLattice.cs +++ b/Source/AIFramework/VariableMap/VariableMapLattice.cs @@ -1,854 +1,854 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-namespace Microsoft.AbstractInterpretationFramework {
- using System.Diagnostics.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.GSet<object>;
- using ISet = Microsoft.Boogie.GSet<object>;
- using Set = Microsoft.Boogie.GSet<object>;
- using HashSet = Microsoft.Boogie.GSet<object>;
-
- /// <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() {
- Contract.Ensures(Contract.Result<Element>() != null);
- return new Elt(this.constraints);
- }
-
- [Pure]
- public override string/*!*/ ToString() {
- Contract.Ensures(Contract.Result<string>() != null);
- if (constraints == null) {
- return "<bottom>";
- }
- string s = "[";
- string sep = "";
- foreach (IVariable/*!*/ v in cce.NonNull(constraints.Keys)) {
- Contract.Assert(v != null);
- Element m = (Element)constraints[v];
- s += sep + v.Name + " -> " + m;
- sep = ", ";
- }
- return s + "]";
- }
-
- public static readonly Elt/*!*/ Top = new Elt(true);
- public static readonly Elt/*!*/ Bottom = new Elt(false);
-
-
- public Elt(IFunctionalMap constraints) {
- this.constraints = constraints;
- }
-
- public bool IsBottom {
- get {
- return this.constraints == null;
- }
- }
-
- public int Count {
- get {
- return this.constraints == null ? 0 : this.constraints.Count;
- }
- }
-
- public IEnumerable/*<IVariable>*//*!*/ Variables {
- get {
- Contract.Requires(!this.IsBottom);
- Contract.Ensures(Contract.Result<IEnumerable>() != null);
- Contract.Assume(this.constraints != null);
- return cce.NonNull(this.constraints.Keys);
- }
- }
-
- public IEnumerable/*<IVariable>*//*!*/ SortedVariables(/*maybe null*/ IComparer variableComparer) {
- Contract.Ensures(Contract.Result<IEnumerable>() != null);
- 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 {
- Contract.Requires(!this.IsBottom);
- Contract.Requires(key != null);
- Contract.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) {
- Contract.Requires(microLattice != null);
- Contract.Requires(value != null);
- Contract.Requires(var != null);
- Contract.Requires((!this.IsBottom));
- Contract.Ensures(Contract.Result<Elt>() != null);
- Contract.Assume(this.constraints != null);
- Contract.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) {
- Contract.Requires(microLattice != null);
- Contract.Requires(value != null);
- Contract.Requires(var != null);
- Contract.Ensures(Contract.Result<Elt>() != null);
- if (microLattice.IsBottom(value)) {
- return Bottom;
- }
- if (microLattice.IsTop(value)) {
- return this.Remove(var, microLattice);
- }
-
- Contract.Assume(this.constraints != null);
- Contract.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) {
- Contract.Requires(var != null);
- Contract.Ensures(Contract.Result<Elt>() != null);
- if (this.IsBottom) {
- return this;
- }
- Contract.Assume(this.constraints != null);
- return new Elt(this.constraints.Remove(var));
- }
-
- public Elt/*!*/ Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName, MicroLattice/*!*/ microLattice) {
- Contract.Requires(microLattice != null);
- Contract.Requires(newName != null);
- Contract.Requires(oldName != null);
- Contract.Requires((!this.IsBottom));
- Contract.Ensures(Contract.Result<Elt>() != null);
- Element value = this[oldName];
- if (value == null) {
- return this;
- } // 'oldName' isn't in the map, so neither will be 'newName'
- Contract.Assume(this.constraints != null);
- IFunctionalMap newMap = this.constraints.Remove(oldName);
- newMap = newMap.Add(newName, value);
- return new Elt(newMap);
- }
-
- [Pure]
- public override ICollection<IVariable/*!*/>/*!*/ FreeVariables() {
- Contract.Ensures(cce.NonNullElements(Contract.Result<ICollection<IVariable>>()));
- throw new System.NotImplementedException();
- }
-
- } // class
-
- private readonly MicroLattice/*!*/ microLattice;
-
- private readonly IPropExprFactory/*!*/ propExprFactory;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(microLattice != null);
- Contract.Invariant(propExprFactory != null);
- }
-
-
- private readonly /*maybe null*/IComparer variableComparer;
-
- public VariableMapLattice(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valueExprFactory, MicroLattice/*!*/ microLattice, /*maybe null*/IComparer variableComparer)
- : base(valueExprFactory) {
- Contract.Requires(microLattice != null);
- Contract.Requires(valueExprFactory != null);
- Contract.Requires(propExprFactory != null);
- this.propExprFactory = propExprFactory;
- this.microLattice = microLattice;
- this.variableComparer = variableComparer;
- // base(valueExprFactory);
- }
-
- protected override object/*!*/ UniqueId {
- get {
- Contract.Ensures(Contract.Result<object>() != null);
- return this.microLattice.GetType();
- }
- }
-
- public override Element/*!*/ Top {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- return Elt.Top;
- }
- }
-
- public override Element Bottom {
- get {
- Contract.Ensures(Contract.Result<Element>() != null);
- return Elt.Bottom;
- }
- }
-
- public override bool IsTop(Element/*!*/ element) {
- //Contract.Requires(element != null);
- Elt e = (Elt)element;
- return !e.IsBottom && e.Count == 0;
- }
-
- public override bool IsBottom(Element/*!*/ element) {
- //Contract.Requires(element != null);
- return ((Elt)element).IsBottom;
- }
-
- protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- 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) {
- Contract.Assert(var != null);
- Element thisValue = cce.NonNull(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) {
- Contract.Assert(var != null);
- if (a.Lookup(var) != null) {
- continue;
- } // we checked this case in the loop above
-
- Element thatValue = cce.NonNull(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) {
- Contract.Requires((newValue != null));
- Contract.Requires((var != null));
- Contract.Requires((element != null));
- Contract.Ensures(Contract.Result<Elt>() != null);
- 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) {
- //Contract.Requires(element != null);
- Contract.Ensures(Contract.Result<string>() != null);
- 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)) {
- Contract.Assert(key != null);
- if (k++ > 0) {
- buffer.Append("; ");
- }
- buffer.AppendFormat("{0} = {1}", key, e[key]);
- }
- return buffer.ToString();
- }
-
- public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- Elt a = (Elt)first;
- Elt b = (Elt)second;
-
- IFunctionalMap newMap = FunctionalHashtable.Empty;
- foreach (IVariable/*!*/ key in a.Variables) {
- Contract.Assert(key != null);
- 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);
- Contract.Assert(join != null);
-
- // System.Console.WriteLine("{0} join {1} = {2} ", this.ToString(a), ToString(b), ToString(join));
-
- return join;
- }
-
- public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) {
- //Contract.Requires(second != null);
- //Contract.Requires(first != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- Elt a = (Elt)first;
- Elt b = (Elt)second;
-
- IFunctionalMap newMap = FunctionalHashtable.Empty;
- foreach (IVariable/*!*/ key in a.Variables) {
- Contract.Assert(key != null);
- Element/*!*/ aValue = cce.NonNull(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) {
- Contract.Assert(key != null);
- 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) {
- //Contract.Requires((second != null));
- //Contract.Requires((first != null));
- Contract.Ensures(Contract.Result<Element>() != null);
- 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) {
- Contract.Assert(key != null);
- 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);
- Contract.Assert(widen != null);
- // 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) {
- Contract.Requires(ignoreVars != null);
- Contract.Requires(e != null);
- Contract.Ensures(Contract.Result<ISet>() != null);
- 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) {
- Contract.Assert(arg != null);
- 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, cce.NonNull(Set.Union(ignoreVars, x))));
- } else if (e is IUnknown) {
- // skip (actually, it would be appropriate to return the universal set of all variables)
- } else {
- Debug.Assert(false, "case not handled: " + e);
- }
- return s;
- }
-
-
- private static ArrayList/*<IExpr>*//*!*/ FindConjuncts(IExpr e) {
- Contract.Ensures(Contract.Result<ArrayList>() != null);
- 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) {
- Contract.Ensures(!Contract.Result<bool>() || Contract.ValueAtReturn(out left) != null && Contract.ValueAtReturn(out 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) {
- Contract.Requires(expr != null);
- // 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/*!*/)cce.NonNull(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/*!*/)cce.NonNull(fun.Arguments[0]);
- IExpr/*!*/ right = (IExpr/*!*/)cce.NonNull(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) {
- //Contract.Requires(element != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- 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)) {
- Contract.Assert(variable != null);
- 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) {
- //Contract.Requires(variable != null);
- //Contract.Requires(element != null);
- Contract.Ensures(Contract.Result<Element>() != null);
- return cce.NonNull((Elt)element).Remove(variable, this.microLattice);
- }
-
- private delegate IExpr/*!*/ OnUnableToInline(IVariable/*!*/ var);
- private IExpr/*!*/ IdentityVarToExpr(IVariable/*!*/ var) {
- //Contract.Requires(var != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- 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) {
- Contract.Requires(unableToInline != null);
- Contract.Requires(notInlineable != null);
- Contract.Requires(expr != null);
- Contract.Requires(element != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- 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) {
- Contract.Assert(arg != null);
- 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,
- cce.NonNull(Set.Union(notInlineable, x)), unableToInline)
- );
- }
-
- // else
-
- if (expr is IUnknown) {
- return expr;
- } else {
- throw
- new System.NotImplementedException("cannot inline identifies in expression " + expr);
- }
- }
-
-
- public override Element/*!*/ Constrain(Element/*!*/ element, IExpr/*!*/ expr) {
- //Contract.Requires(expr != null);
- //Contract.Requires(element != null);
- //Contract.Ensures(Contract.Result<Element>() != null);
- Elt/*!*/ result = (Elt)element;
- Contract.Assert(result != null);
-
- if (IsBottom(element)) {
- return result; // == element
- }
-
- expr = InlineVariables(result, expr, cce.NonNull(Set.Empty), new OnUnableToInline(IdentityVarToExpr));
-
- foreach (IExpr/*!*/ conjunct in FindConjuncts(expr)) {
- Contract.Assert(conjunct != null);
- IVariable left, right;
-
- if (IsSimpleEquality(conjunct, out left, out right)) {
- #region The conjunct is a simple equality
-
-
- Contract.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) {
- Contract.Assert(v != null);
- var = v;
- } // why is there no better way to get the elements?
- Contract.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/*!*/)cce.NonNull(fun.Arguments[0]);
- IExpr/*!*/ rightArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]);
- IExpr/*!*/ var = (leftArg is IVariable) ? leftArg : rightArg;
-
- Element/*!*/ value = this.microLattice.EvaluatePredicateWithState(conjunct, result.Constraints);
- Contract.Assert(value != null);
- result = AddConstraint(result, (IVariable/*!*/)cce.NonNull(var), value);
- }
- #endregion
- }
- }
- }
- return result;
- }
-
-
- public override Element/*!*/ Rename(Element/*!*/ element, IVariable/*!*/ oldName, IVariable/*!*/ newName) {
- //Contract.Requires(newName != null);
- //Contract.Requires(oldName != null);
- //Contract.Requires(element != null);
- //Contract.Ensures(Contract.Result<Element>() != null);
- if (IsBottom(element)) {
- return element;
- } else {
- return ((Elt)element).Rename(oldName, newName, this.microLattice);
- }
- }
-
-
- public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) {
- //Contract.Requires(args != null);
- //Contract.Requires(f != null);
- 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;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(var != null);
- }
-
- public EquivalentExprInlineCallback(IVariable/*!*/ var) {
- Contract.Requires(var != null);
- this.var = var;
- // base();
- }
-
- public IExpr/*!*/ ThrowOnUnableToInline(IVariable/*!*/ othervar)
- //throws EquivalentExprException;
- {
- Contract.Requires(othervar != null);
- Contract.Ensures(Contract.Result<IExpr>() != null);
- Contract.EnsuresOnThrow<EquivalentExprException>(true);
- 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) {
- //Contract.Requires(prohibitedVars != null);
- //Contract.Requires(var != null);
- //Contract.Requires(expr != null);
- //Contract.Requires(q != null);
- //Contract.Requires(e != null);
- try {
- EquivalentExprInlineCallback closure = new EquivalentExprInlineCallback(var);
- return InlineVariables((Elt)e, expr, cce.NonNull(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) {
- //Contract.Requires(pred != null);
- //Contract.Requires(e != null);
- 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) {
- //Contract.Requires(var2 != null);
- //Contract.Requires(var1 != null);
- //Contract.Requires(e != null);
- return Answer.Maybe;
- }
-
- public override void Validate() {
- base.Validate();
- microLattice.Validate();
- }
-
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +namespace Microsoft.AbstractInterpretationFramework { + using System.Diagnostics.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.GSet<object>; + using ISet = Microsoft.Boogie.GSet<object>; + using Set = Microsoft.Boogie.GSet<object>; + using HashSet = Microsoft.Boogie.GSet<object>; + + /// <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() { + Contract.Ensures(Contract.Result<Element>() != null); + return new Elt(this.constraints); + } + + [Pure] + public override string/*!*/ ToString() { + Contract.Ensures(Contract.Result<string>() != null); + if (constraints == null) { + return "<bottom>"; + } + string s = "["; + string sep = ""; + foreach (IVariable/*!*/ v in cce.NonNull(constraints.Keys)) { + Contract.Assert(v != null); + Element m = (Element)constraints[v]; + s += sep + v.Name + " -> " + m; + sep = ", "; + } + return s + "]"; + } + + public static readonly Elt/*!*/ Top = new Elt(true); + public static readonly Elt/*!*/ Bottom = new Elt(false); + + + public Elt(IFunctionalMap constraints) { + this.constraints = constraints; + } + + public bool IsBottom { + get { + return this.constraints == null; + } + } + + public int Count { + get { + return this.constraints == null ? 0 : this.constraints.Count; + } + } + + public IEnumerable/*<IVariable>*//*!*/ Variables { + get { + Contract.Requires(!this.IsBottom); + Contract.Ensures(Contract.Result<IEnumerable>() != null); + Contract.Assume(this.constraints != null); + return cce.NonNull(this.constraints.Keys); + } + } + + public IEnumerable/*<IVariable>*//*!*/ SortedVariables(/*maybe null*/ IComparer variableComparer) { + Contract.Ensures(Contract.Result<IEnumerable>() != null); + 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 { + Contract.Requires(!this.IsBottom); + Contract.Requires(key != null); + Contract.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) { + Contract.Requires(microLattice != null); + Contract.Requires(value != null); + Contract.Requires(var != null); + Contract.Requires((!this.IsBottom)); + Contract.Ensures(Contract.Result<Elt>() != null); + Contract.Assume(this.constraints != null); + Contract.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) { + Contract.Requires(microLattice != null); + Contract.Requires(value != null); + Contract.Requires(var != null); + Contract.Ensures(Contract.Result<Elt>() != null); + if (microLattice.IsBottom(value)) { + return Bottom; + } + if (microLattice.IsTop(value)) { + return this.Remove(var, microLattice); + } + + Contract.Assume(this.constraints != null); + Contract.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) { + Contract.Requires(var != null); + Contract.Ensures(Contract.Result<Elt>() != null); + if (this.IsBottom) { + return this; + } + Contract.Assume(this.constraints != null); + return new Elt(this.constraints.Remove(var)); + } + + public Elt/*!*/ Rename(IVariable/*!*/ oldName, IVariable/*!*/ newName, MicroLattice/*!*/ microLattice) { + Contract.Requires(microLattice != null); + Contract.Requires(newName != null); + Contract.Requires(oldName != null); + Contract.Requires((!this.IsBottom)); + Contract.Ensures(Contract.Result<Elt>() != null); + Element value = this[oldName]; + if (value == null) { + return this; + } // 'oldName' isn't in the map, so neither will be 'newName' + Contract.Assume(this.constraints != null); + IFunctionalMap newMap = this.constraints.Remove(oldName); + newMap = newMap.Add(newName, value); + return new Elt(newMap); + } + + [Pure] + public override ICollection<IVariable/*!*/>/*!*/ FreeVariables() { + Contract.Ensures(cce.NonNullElements(Contract.Result<ICollection<IVariable>>())); + throw new System.NotImplementedException(); + } + + } // class + + private readonly MicroLattice/*!*/ microLattice; + + private readonly IPropExprFactory/*!*/ propExprFactory; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(microLattice != null); + Contract.Invariant(propExprFactory != null); + } + + + private readonly /*maybe null*/IComparer variableComparer; + + public VariableMapLattice(IPropExprFactory/*!*/ propExprFactory, IValueExprFactory/*!*/ valueExprFactory, MicroLattice/*!*/ microLattice, /*maybe null*/IComparer variableComparer) + : base(valueExprFactory) { + Contract.Requires(microLattice != null); + Contract.Requires(valueExprFactory != null); + Contract.Requires(propExprFactory != null); + this.propExprFactory = propExprFactory; + this.microLattice = microLattice; + this.variableComparer = variableComparer; + // base(valueExprFactory); + } + + protected override object/*!*/ UniqueId { + get { + Contract.Ensures(Contract.Result<object>() != null); + return this.microLattice.GetType(); + } + } + + public override Element/*!*/ Top { + get { + Contract.Ensures(Contract.Result<Element>() != null); + return Elt.Top; + } + } + + public override Element Bottom { + get { + Contract.Ensures(Contract.Result<Element>() != null); + return Elt.Bottom; + } + } + + public override bool IsTop(Element/*!*/ element) { + //Contract.Requires(element != null); + Elt e = (Elt)element; + return !e.IsBottom && e.Count == 0; + } + + public override bool IsBottom(Element/*!*/ element) { + //Contract.Requires(element != null); + return ((Elt)element).IsBottom; + } + + protected override bool AtMost(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + 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) { + Contract.Assert(var != null); + Element thisValue = cce.NonNull(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) { + Contract.Assert(var != null); + if (a.Lookup(var) != null) { + continue; + } // we checked this case in the loop above + + Element thatValue = cce.NonNull(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) { + Contract.Requires((newValue != null)); + Contract.Requires((var != null)); + Contract.Requires((element != null)); + Contract.Ensures(Contract.Result<Elt>() != null); + 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) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result<string>() != null); + 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)) { + Contract.Assert(key != null); + if (k++ > 0) { + buffer.Append("; "); + } + buffer.AppendFormat("{0} = {1}", key, e[key]); + } + return buffer.ToString(); + } + + public override Element/*!*/ NontrivialJoin(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Element>() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + IFunctionalMap newMap = FunctionalHashtable.Empty; + foreach (IVariable/*!*/ key in a.Variables) { + Contract.Assert(key != null); + 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); + Contract.Assert(join != null); + + // System.Console.WriteLine("{0} join {1} = {2} ", this.ToString(a), ToString(b), ToString(join)); + + return join; + } + + public override Element/*!*/ NontrivialMeet(Element/*!*/ first, Element/*!*/ second) { + //Contract.Requires(second != null); + //Contract.Requires(first != null); + Contract.Ensures(Contract.Result<Element>() != null); + Elt a = (Elt)first; + Elt b = (Elt)second; + + IFunctionalMap newMap = FunctionalHashtable.Empty; + foreach (IVariable/*!*/ key in a.Variables) { + Contract.Assert(key != null); + Element/*!*/ aValue = cce.NonNull(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) { + Contract.Assert(key != null); + 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) { + //Contract.Requires((second != null)); + //Contract.Requires((first != null)); + Contract.Ensures(Contract.Result<Element>() != null); + 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) { + Contract.Assert(key != null); + 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); + Contract.Assert(widen != null); + // 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) { + Contract.Requires(ignoreVars != null); + Contract.Requires(e != null); + Contract.Ensures(Contract.Result<ISet>() != null); + 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) { + Contract.Assert(arg != null); + 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, cce.NonNull(Set.Union(ignoreVars, x)))); + } else if (e is IUnknown) { + // skip (actually, it would be appropriate to return the universal set of all variables) + } else { + Debug.Assert(false, "case not handled: " + e); + } + return s; + } + + + private static ArrayList/*<IExpr>*//*!*/ FindConjuncts(IExpr e) { + Contract.Ensures(Contract.Result<ArrayList>() != null); + 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) { + Contract.Ensures(!Contract.Result<bool>() || Contract.ValueAtReturn(out left) != null && Contract.ValueAtReturn(out 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) { + Contract.Requires(expr != null); + // 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/*!*/)cce.NonNull(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/*!*/)cce.NonNull(fun.Arguments[0]); + IExpr/*!*/ right = (IExpr/*!*/)cce.NonNull(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) { + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + 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)) { + Contract.Assert(variable != null); + 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) { + //Contract.Requires(variable != null); + //Contract.Requires(element != null); + Contract.Ensures(Contract.Result<Element>() != null); + return cce.NonNull((Elt)element).Remove(variable, this.microLattice); + } + + private delegate IExpr/*!*/ OnUnableToInline(IVariable/*!*/ var); + private IExpr/*!*/ IdentityVarToExpr(IVariable/*!*/ var) { + //Contract.Requires(var != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + 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) { + Contract.Requires(unableToInline != null); + Contract.Requires(notInlineable != null); + Contract.Requires(expr != null); + Contract.Requires(element != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + 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) { + Contract.Assert(arg != null); + 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, + cce.NonNull(Set.Union(notInlineable, x)), unableToInline) + ); + } + + // else + + if (expr is IUnknown) { + return expr; + } else { + throw + new System.NotImplementedException("cannot inline identifies in expression " + expr); + } + } + + + public override Element/*!*/ Constrain(Element/*!*/ element, IExpr/*!*/ expr) { + //Contract.Requires(expr != null); + //Contract.Requires(element != null); + //Contract.Ensures(Contract.Result<Element>() != null); + Elt/*!*/ result = (Elt)element; + Contract.Assert(result != null); + + if (IsBottom(element)) { + return result; // == element + } + + expr = InlineVariables(result, expr, cce.NonNull(Set.Empty), new OnUnableToInline(IdentityVarToExpr)); + + foreach (IExpr/*!*/ conjunct in FindConjuncts(expr)) { + Contract.Assert(conjunct != null); + IVariable left, right; + + if (IsSimpleEquality(conjunct, out left, out right)) { + #region The conjunct is a simple equality + + + Contract.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) { + Contract.Assert(v != null); + var = v; + } // why is there no better way to get the elements? + Contract.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/*!*/)cce.NonNull(fun.Arguments[0]); + IExpr/*!*/ rightArg = (IExpr/*!*/)cce.NonNull(fun.Arguments[1]); + IExpr/*!*/ var = (leftArg is IVariable) ? leftArg : rightArg; + + Element/*!*/ value = this.microLattice.EvaluatePredicateWithState(conjunct, result.Constraints); + Contract.Assert(value != null); + result = AddConstraint(result, (IVariable/*!*/)cce.NonNull(var), value); + } + #endregion + } + } + } + return result; + } + + + public override Element/*!*/ Rename(Element/*!*/ element, IVariable/*!*/ oldName, IVariable/*!*/ newName) { + //Contract.Requires(newName != null); + //Contract.Requires(oldName != null); + //Contract.Requires(element != null); + //Contract.Ensures(Contract.Result<Element>() != null); + if (IsBottom(element)) { + return element; + } else { + return ((Elt)element).Rename(oldName, newName, this.microLattice); + } + } + + + public override bool Understands(IFunctionSymbol/*!*/ f, IList/*!*/ args) { + //Contract.Requires(args != null); + //Contract.Requires(f != null); + 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; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(var != null); + } + + public EquivalentExprInlineCallback(IVariable/*!*/ var) { + Contract.Requires(var != null); + this.var = var; + // base(); + } + + public IExpr/*!*/ ThrowOnUnableToInline(IVariable/*!*/ othervar) + //throws EquivalentExprException; + { + Contract.Requires(othervar != null); + Contract.Ensures(Contract.Result<IExpr>() != null); + Contract.EnsuresOnThrow<EquivalentExprException>(true); + 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) { + //Contract.Requires(prohibitedVars != null); + //Contract.Requires(var != null); + //Contract.Requires(expr != null); + //Contract.Requires(q != null); + //Contract.Requires(e != null); + try { + EquivalentExprInlineCallback closure = new EquivalentExprInlineCallback(var); + return InlineVariables((Elt)e, expr, cce.NonNull(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) { + //Contract.Requires(pred != null); + //Contract.Requires(e != null); + 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) { + //Contract.Requires(var2 != null); + //Contract.Requires(var1 != null); + //Contract.Requires(e != null); + return Answer.Maybe; + } + + public override void Validate() { + base.Validate(); + microLattice.Validate(); + } + + } +} diff --git a/Source/AIFramework/cce.cs b/Source/AIFramework/cce.cs index ef594484..1e0b12a5 100644 --- a/Source/AIFramework/cce.cs +++ b/Source/AIFramework/cce.cs @@ -1,193 +1,193 @@ -using System;
-using SA=System.Attribute;
-using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-using System.Text;
-//using Microsoft.Boogie;
-
-/// <summary>
-/// A class containing static methods to extend the functionality of Code Contracts
-/// </summary>
-
-public static class cce {
- //[Pure]
- //public static bool NonNullElements<T>(Microsoft.Dafny.Graph<T> collection) {
- // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents());
- //}
- [Pure]
- public static T NonNull<T>(T t) {
- Contract.Assert(t != null);
- return t;
- }
- [Pure]
- public static bool NonNullElements<T>(IEnumerable<T> collection) {
- return collection != null && Contract.ForAll(collection, c => c != null);
- }
- [Pure]
- public static bool NonNullElements<TKey, TValue>(IDictionary<TKey, TValue> collection) {
- return collection != null && Contract.ForAll(collection, pair => NonNullElements(pair));
- }
- //[Pure]
- //public static bool NonNullElements(VariableSeq collection) {
- // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null);
- //}
- /// <summary>
- /// For possibly-null lists of non-null elements
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="collection"></param>
- /// <param name="nullability">If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>!</param>
- /// <returns></returns>
- [Pure]
- public static bool NonNullElements<T>(IEnumerable<T> collection, bool nullability) {
- return (nullability && collection == null) || cce.NonNullElements(collection);
- //Should be the same as:
- /*if(nullability&&collection==null)
- * return true;
- * return cce.NonNullElements(collection)
- */
-
- }
- [Pure]
- public static bool NonNullElements<TKey, TValue>(KeyValuePair<TKey, TValue> kvp) {
- return kvp.Key != null && kvp.Value != null;
- }
- [Pure]
- public static bool NonNullElements<T>(IEnumerator<T> iEnumerator) {
- return iEnumerator != null;
- }
- //[Pure]
- //public static bool NonNullElements<T>(Graphing.Graph<T> graph) {
- // return cce.NonNullElements(graph.TopologicalSort());
- //}
- [Pure]
- public static void BeginExpose(object o) {
- }
- [Pure]
- public static void EndExpose() {
- }
- [Pure]
- public static bool IsPeerConsistent(object o) {
- return true;
- }
- [Pure]
- public static bool IsConsistent(object o) {
- return true;
- }
- [Pure]
- public static bool IsExposable(object o) {
- return true;
- }
- [Pure]
- public static bool IsExposed(object o) {
- return true;
- }
- [Pure]
- public static bool IsNew(object o) {
- return true;
- }
- public static class Owner {
- [Pure]
- public static bool Same(object o, object p) {
- return true;
- }
- [Pure]
- public static void AssignSame(object o, object p) {
- }
- [Pure]
- public static object ElementProxy(object o) {
- return o;
- }
- [Pure]
- public static bool None(object o) {
- return true;
- }
- [Pure]
- public static bool Different(object o, object p) {
- return true;
- }
- [Pure]
- public static bool New(object o) {
- return true;
- }
- }
- [Pure]
- public static void LoopInvariant(bool p) {
- Contract.Assert(p);
- }
- public class UnreachableException : Exception {
- public UnreachableException() {
- }
- }
- //[Pure]
- //public static bool IsValid(Microsoft.Dafny.Expression expression) {
- // return true;
- //}
- //public static List<T> toList<T>(PureCollections.Sequence s) {
- // List<T> toRet = new List<T>();
- // foreach (T t in s.elems)
- // if(t!=null)
- // toRet.Add(t);
- // return toRet;
- //}
-
- //internal static bool NonNullElements(Set set) {
- // return set != null && Contract.ForAll(0,set.Count, i => set[i] != null);
- //}
-}
-
-public class PeerAttribute : SA {
-}
-public class RepAttribute : SA {
-}
-public class CapturedAttribute : SA {
-}
-public class NotDelayedAttribute : SA {
-}
-public class NoDefaultContractAttribute : SA {
-}
-public class VerifyAttribute : SA {
- public VerifyAttribute(bool b) {
-
- }
-}
-public class StrictReadonlyAttribute : SA {
-}
-public class AdditiveAttribute : SA {
-}
-public class ReadsAttribute : SA {
- public enum Reads {
- Nothing,
- Everything,
- };
- public ReadsAttribute(object o) {
- }
-}
-public class GlobalAccessAttribute : SA {
- public GlobalAccessAttribute(bool b) {
- }
-}
-public class EscapesAttribute : SA {
- public EscapesAttribute(bool b, bool b_2) {
- }
-}
-public class NeedsContractsAttribute : SA {
- public NeedsContractsAttribute() {
- }
- public NeedsContractsAttribute(bool ret, bool parameters) {
- }
- public NeedsContractsAttribute(bool ret, int[] parameters) {
- }
-}
-public class ImmutableAttribute : SA {
-}
-public class InsideAttribute : SA {
-}
-public class SpecPublicAttribute : SA {
-}
-public class ElementsPeerAttribute : SA {
-}
-public class ResultNotNewlyAllocatedAttribute : SA {
-}
-public class OnceAttribute : SA {
+using System; +using SA=System.Attribute; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Text; +//using Microsoft.Boogie; + +/// <summary> +/// A class containing static methods to extend the functionality of Code Contracts +/// </summary> + +public static class cce { + //[Pure] + //public static bool NonNullElements<T>(Microsoft.Dafny.Graph<T> collection) { + // return collection != null && cce.NonNullElements(collection.TopologicallySortedComponents()); + //} + [Pure] + public static T NonNull<T>(T t) { + Contract.Assert(t != null); + return t; + } + [Pure] + public static bool NonNullElements<T>(IEnumerable<T> collection) { + return collection != null && Contract.ForAll(collection, c => c != null); + } + [Pure] + public static bool NonNullElements<TKey, TValue>(IDictionary<TKey, TValue> collection) { + return collection != null && Contract.ForAll(collection, pair => NonNullElements(pair)); + } + //[Pure] + //public static bool NonNullElements(VariableSeq collection) { + // return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); + //} + /// <summary> + /// For possibly-null lists of non-null elements + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="collection"></param> + /// <param name="nullability">If true, the collection is treated as an IEnumerable<T!>?, rather than an IEnumerable<T!>!</param> + /// <returns></returns> + [Pure] + public static bool NonNullElements<T>(IEnumerable<T> collection, bool nullability) { + return (nullability && collection == null) || cce.NonNullElements(collection); + //Should be the same as: + /*if(nullability&&collection==null) + * return true; + * return cce.NonNullElements(collection) + */ + + } + [Pure] + public static bool NonNullElements<TKey, TValue>(KeyValuePair<TKey, TValue> kvp) { + return kvp.Key != null && kvp.Value != null; + } + [Pure] + public static bool NonNullElements<T>(IEnumerator<T> iEnumerator) { + return iEnumerator != null; + } + //[Pure] + //public static bool NonNullElements<T>(Graphing.Graph<T> graph) { + // return cce.NonNullElements(graph.TopologicalSort()); + //} + [Pure] + public static void BeginExpose(object o) { + } + [Pure] + public static void EndExpose() { + } + [Pure] + public static bool IsPeerConsistent(object o) { + return true; + } + [Pure] + public static bool IsConsistent(object o) { + return true; + } + [Pure] + public static bool IsExposable(object o) { + return true; + } + [Pure] + public static bool IsExposed(object o) { + return true; + } + [Pure] + public static bool IsNew(object o) { + return true; + } + public static class Owner { + [Pure] + public static bool Same(object o, object p) { + return true; + } + [Pure] + public static void AssignSame(object o, object p) { + } + [Pure] + public static object ElementProxy(object o) { + return o; + } + [Pure] + public static bool None(object o) { + return true; + } + [Pure] + public static bool Different(object o, object p) { + return true; + } + [Pure] + public static bool New(object o) { + return true; + } + } + [Pure] + public static void LoopInvariant(bool p) { + Contract.Assert(p); + } + public class UnreachableException : Exception { + public UnreachableException() { + } + } + //[Pure] + //public static bool IsValid(Microsoft.Dafny.Expression expression) { + // return true; + //} + //public static List<T> toList<T>(PureCollections.Sequence s) { + // List<T> toRet = new List<T>(); + // foreach (T t in s.elems) + // if(t!=null) + // toRet.Add(t); + // return toRet; + //} + + //internal static bool NonNullElements(Set set) { + // return set != null && Contract.ForAll(0,set.Count, i => set[i] != null); + //} +} + +public class PeerAttribute : SA { +} +public class RepAttribute : SA { +} +public class CapturedAttribute : SA { +} +public class NotDelayedAttribute : SA { +} +public class NoDefaultContractAttribute : SA { +} +public class VerifyAttribute : SA { + public VerifyAttribute(bool b) { + + } +} +public class StrictReadonlyAttribute : SA { +} +public class AdditiveAttribute : SA { +} +public class ReadsAttribute : SA { + public enum Reads { + Nothing, + Everything, + }; + public ReadsAttribute(object o) { + } +} +public class GlobalAccessAttribute : SA { + public GlobalAccessAttribute(bool b) { + } +} +public class EscapesAttribute : SA { + public EscapesAttribute(bool b, bool b_2) { + } +} +public class NeedsContractsAttribute : SA { + public NeedsContractsAttribute() { + } + public NeedsContractsAttribute(bool ret, bool parameters) { + } + public NeedsContractsAttribute(bool ret, int[] parameters) { + } +} +public class ImmutableAttribute : SA { +} +public class InsideAttribute : SA { +} +public class SpecPublicAttribute : SA { +} +public class ElementsPeerAttribute : SA { +} +public class ResultNotNewlyAllocatedAttribute : SA { +} +public class OnceAttribute : SA { }
\ No newline at end of file |