mirror of
https://github.com/Z3Prover/z3
synced 2025-08-14 23:05:26 +00:00
Add MSF plugins
This commit is contained in:
parent
58f8181a74
commit
5cc4cc8226
24 changed files with 2683 additions and 0 deletions
92
examples/msf/SolverFoundation.Plugin.Z3/AbortWorker.cs
Normal file
92
examples/msf/SolverFoundation.Plugin.Z3/AbortWorker.cs
Normal file
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Microsoft.Z3;
|
||||
|
||||
namespace Microsoft.SolverFoundation.Plugin.Z3
|
||||
{
|
||||
/// <summary>
|
||||
/// Thread that will wait until the query abort function returns true or
|
||||
/// the stop method is called. If the abort function returns true at some
|
||||
/// point it will issue a softCancel() call to Z3.
|
||||
/// </summary>
|
||||
internal class AbortWorker
|
||||
{
|
||||
#region Private Members
|
||||
|
||||
/// <summary>The Z3 solver</summary>
|
||||
private Microsoft.Z3.Context _context;
|
||||
/// <summary>The abort function to use to check if we are aborted</summary>
|
||||
private Func<bool> _QueryAbortFunction;
|
||||
/// <summary>Flag indicating that worker should stop</summary>
|
||||
private bool _stop = false;
|
||||
/// <summary>Flag indicating that we have been sent an abort signal</summary>
|
||||
private bool _aborted = false;
|
||||
|
||||
#endregion Private Members
|
||||
|
||||
#region Construction
|
||||
|
||||
/// <summary>
|
||||
/// Worker constructor taking a Z3 instance and a function to periodically
|
||||
/// check for aborts.
|
||||
/// </summary>
|
||||
/// <param name="z3">Z3 instance</param>
|
||||
/// <param name="queryAbortFunction">method to call to check for aborts</param>
|
||||
public AbortWorker(Context context, Func<bool> queryAbortFunction)
|
||||
{
|
||||
_context = context;
|
||||
_QueryAbortFunction = queryAbortFunction;
|
||||
}
|
||||
|
||||
#endregion Construction
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Stop the abort worker.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
_stop = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is true if we have been aborted.
|
||||
/// </summary>
|
||||
public bool Aborted
|
||||
{
|
||||
get
|
||||
{
|
||||
return _aborted;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the abort worker. The worker checks the abort method
|
||||
/// periodically until either it is stopped by a call to the Stop()
|
||||
/// method or it gets an abort signal. In the latter case it will
|
||||
/// issue a soft abort signal to Z3.
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
// We go until someone stops us
|
||||
_stop = false;
|
||||
while (!_stop && !_QueryAbortFunction())
|
||||
{
|
||||
// Wait for a while
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
// If we were stopped on abort, cancel z3
|
||||
if (!_stop)
|
||||
{
|
||||
_context.Interrupt();
|
||||
_aborted = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SolverFoundation.Plugin.Z3")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("SolverFoundation.Plugin.Z3")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("ed1476c0-96de-4d2c-983d-3888b140c3ad")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,185 @@
|
|||
<?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.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{7340E664-F648-4FF7-89B2-F4DA424996D3}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Microsoft.SolverFoundation.Plugin.Z3</RootNamespace>
|
||||
<AssemblyName>SolverFoundation.Plugin.Z3</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>
|
||||
</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 />
|
||||
</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>
|
||||
<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)' == 'commercial|AnyCPU'">
|
||||
<OutputPath>bin\commercial\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<CodeAnalysisLogFile>bin\Release\Z3Solver.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>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'commercial_64|AnyCPU'">
|
||||
<OutputPath>bin\commercial_64\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<CodeAnalysisLogFile>bin\Release\Z3Solver.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>
|
||||
<CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
|
||||
<CodeAnalysisFailOnMissingRules>false</CodeAnalysisFailOnMissingRules>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'commercial|x86'">
|
||||
<OutputPath>bin\x86\commercial\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'commercial_64|x86'">
|
||||
<OutputPath>bin\x86\commercial_64\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Solver.Foundation">
|
||||
<HintPath>..\Microsoft.Solver.Foundation.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Z3">
|
||||
<HintPath>..\Microsoft.Z3.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Xml.Linq">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.DataSetExtensions">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AbortWorker.cs" />
|
||||
<Compile Include="Utils.cs" />
|
||||
<Compile Include="Z3BaseDirective.cs" />
|
||||
<Compile Include="Z3BaseParams.cs" />
|
||||
<Compile Include="Z3BaseSolver.cs" />
|
||||
<Compile Include="Z3MILPDirective.cs" />
|
||||
<Compile Include="Z3MILPParams.cs" />
|
||||
<Compile Include="Z3MILPSolver.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Z3TermDirective.cs" />
|
||||
<Compile Include="Z3TermParams.cs" />
|
||||
<Compile Include="Z3TermSolver.cs" />
|
||||
</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>
|
124
examples/msf/SolverFoundation.Plugin.Z3/Utils.cs
Normal file
124
examples/msf/SolverFoundation.Plugin.Z3/Utils.cs
Normal file
|
@ -0,0 +1,124 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Z3;
|
||||
using Microsoft.SolverFoundation.Common;
|
||||
|
||||
namespace Microsoft.SolverFoundation.Plugin.Z3
|
||||
{
|
||||
public class Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the Z3 term corresponding to the MSF rational number.
|
||||
/// </summary>
|
||||
/// <param name="rational">The MSF rational</param>
|
||||
/// <returns>The Z3 term</returns>
|
||||
public static ArithExpr GetNumeral(Context context, Rational rational, Sort sort = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
sort = rational.IsInteger() ? ((Sort)context.IntSort) : (sort == null ? (Sort)context.RealSort : sort);
|
||||
return (ArithExpr)context.MkNumeral(rational.ToString(), sort);
|
||||
}
|
||||
catch (Z3Exception e)
|
||||
{
|
||||
Console.Error.WriteLine("Conversion of {0} failed:\n {1}", rational, e);
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
private static long BASE = 10 ^ 18;
|
||||
|
||||
private static Rational ToRational(System.Numerics.BigInteger bi)
|
||||
{
|
||||
if (System.Numerics.BigInteger.Abs(bi) <= BASE)
|
||||
{
|
||||
return (Rational)((long)bi);
|
||||
}
|
||||
return BASE * ToRational(bi / BASE) + ToRational(bi % BASE);
|
||||
}
|
||||
|
||||
public static Rational ToRational(IntNum i)
|
||||
{
|
||||
return ToRational(i.BigInteger);
|
||||
}
|
||||
|
||||
public static Rational ToRational(RatNum r)
|
||||
{
|
||||
return ToRational(r.BigIntNumerator) / ToRational(r.BigIntDenominator);
|
||||
}
|
||||
|
||||
public static Rational ToRational(Expr expr)
|
||||
{
|
||||
Debug.Assert(expr is ArithExpr, "Only accept ArithExpr for now.");
|
||||
var e = expr as ArithExpr;
|
||||
|
||||
if (e is IntNum)
|
||||
{
|
||||
Debug.Assert(expr.IsIntNum, "Number should be an integer.");
|
||||
return ToRational(expr as IntNum);
|
||||
}
|
||||
|
||||
if (e is RatNum)
|
||||
{
|
||||
Debug.Assert(expr.IsRatNum, "Number should be a rational.");
|
||||
return ToRational(expr as RatNum);
|
||||
}
|
||||
|
||||
if (e.IsAdd)
|
||||
{
|
||||
Rational r = Rational.Zero;
|
||||
foreach (var arg in e.Args)
|
||||
{
|
||||
r += ToRational(arg);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
if (e.IsMul)
|
||||
{
|
||||
Rational r = Rational.One;
|
||||
foreach (var arg in e.Args)
|
||||
{
|
||||
r *= ToRational(arg);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
if (e.IsUMinus)
|
||||
{
|
||||
return -ToRational(e.Args[0]);
|
||||
}
|
||||
|
||||
if (e.IsDiv)
|
||||
{
|
||||
return ToRational(e.Args[0]) / ToRational(e.Args[1]);
|
||||
}
|
||||
|
||||
if (e.IsSub)
|
||||
{
|
||||
Rational r = ToRational(e.Args[0]);
|
||||
for (int i = 1; i < e.Args.Length; ++i)
|
||||
{
|
||||
r -= ToRational(e.Args[i]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
if (e.IsConst && e.FuncDecl.Name.ToString() == "oo")
|
||||
{
|
||||
return Rational.PositiveInfinity;
|
||||
}
|
||||
|
||||
if (e.IsConst && e.FuncDecl.Name.ToString() == "epsilon")
|
||||
{
|
||||
return Rational.One/Rational.PositiveInfinity;
|
||||
}
|
||||
|
||||
Debug.Assert(false, "Should not happen");
|
||||
return Rational.One;
|
||||
}
|
||||
}
|
||||
}
|
101
examples/msf/SolverFoundation.Plugin.Z3/Z3BaseDirective.cs
Normal file
101
examples/msf/SolverFoundation.Plugin.Z3/Z3BaseDirective.cs
Normal file
|
@ -0,0 +1,101 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using Microsoft.SolverFoundation.Services;
|
||||
|
||||
namespace Microsoft.SolverFoundation.Plugin.Z3
|
||||
{
|
||||
/// <summary>
|
||||
/// Combining objective functions
|
||||
/// </summary>
|
||||
public enum OptimizationKind
|
||||
{
|
||||
Lexicographic,
|
||||
BoundingBox,
|
||||
ParetoOptimal
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Algorithm for solving cardinality constraints
|
||||
/// </summary>
|
||||
public enum CardinalityAlgorithm
|
||||
{
|
||||
FuMalik,
|
||||
CoreMaxSAT
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Algorithm for solving pseudo-boolean constraints
|
||||
/// </summary>
|
||||
public enum PseudoBooleanAlgorithm
|
||||
{
|
||||
WeightedMaxSAT,
|
||||
IterativeWeightedMaxSAT,
|
||||
BisectionWeightedMaxSAT,
|
||||
WeightedPartialMaxSAT2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strategy for solving arithmetic optimization
|
||||
/// </summary>
|
||||
public enum ArithmeticStrategy
|
||||
{
|
||||
Basic,
|
||||
Farkas
|
||||
}
|
||||
|
||||
public abstract class Z3BaseDirective : Directive
|
||||
{
|
||||
protected OptimizationKind _optKind;
|
||||
protected CardinalityAlgorithm _cardAlgorithm;
|
||||
protected PseudoBooleanAlgorithm _pboAlgorithm;
|
||||
protected ArithmeticStrategy _arithStrategy;
|
||||
|
||||
protected string _smt2LogFile;
|
||||
|
||||
public Z3BaseDirective()
|
||||
{
|
||||
Arithmetic = Arithmetic.Exact;
|
||||
}
|
||||
|
||||
public OptimizationKind OptKind
|
||||
{
|
||||
get { return _optKind; }
|
||||
set { _optKind = value; }
|
||||
}
|
||||
|
||||
public CardinalityAlgorithm CardinalityAlgorithm
|
||||
{
|
||||
get { return _cardAlgorithm; }
|
||||
set { _cardAlgorithm = value; }
|
||||
}
|
||||
|
||||
public PseudoBooleanAlgorithm PseudoBooleanAlgorithm
|
||||
{
|
||||
get { return _pboAlgorithm; }
|
||||
set { _pboAlgorithm = value; }
|
||||
}
|
||||
|
||||
public ArithmeticStrategy ArithmeticStrategy
|
||||
{
|
||||
get { return _arithStrategy; }
|
||||
set { _arithStrategy = value; }
|
||||
}
|
||||
|
||||
public string SMT2LogFile
|
||||
{
|
||||
get { return _smt2LogFile; }
|
||||
set { _smt2LogFile = value; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(this.GetType().Name);
|
||||
sb.Append("(");
|
||||
sb.AppendFormat("OptKind: {0}, ", _optKind);
|
||||
sb.AppendFormat("SMT2LogFile: {0}", _smt2LogFile);
|
||||
sb.Append(")");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
103
examples/msf/SolverFoundation.Plugin.Z3/Z3BaseParams.cs
Normal file
103
examples/msf/SolverFoundation.Plugin.Z3/Z3BaseParams.cs
Normal file
|
@ -0,0 +1,103 @@
|
|||
using Microsoft.SolverFoundation.Services;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SolverFoundation.Plugin.Z3
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of the solver parameters for Z3
|
||||
/// </summary>
|
||||
public class Z3BaseParams : ISolverParameters
|
||||
{
|
||||
#region Private Members
|
||||
|
||||
/// <summary>The abort method we can call (defaults to always false)
|
||||
protected Func<bool> _queryAbortFunction = delegate() { return false; };
|
||||
|
||||
/// <summary>The directive to use</summary>
|
||||
protected Directive _directive = null;
|
||||
|
||||
protected OptimizationKind _optKind;
|
||||
protected CardinalityAlgorithm _cardAlgorithm;
|
||||
protected PseudoBooleanAlgorithm _pboAlgorithm;
|
||||
protected ArithmeticStrategy _arithStrategy;
|
||||
|
||||
protected string _smt2LogFile;
|
||||
|
||||
#endregion Private Members
|
||||
|
||||
#region Construction
|
||||
|
||||
public Z3BaseParams() { }
|
||||
|
||||
public Z3BaseParams(Directive directive)
|
||||
{
|
||||
_directive = directive;
|
||||
|
||||
var z3Directive = directive as Z3BaseDirective;
|
||||
if (z3Directive != null)
|
||||
{
|
||||
_optKind = z3Directive.OptKind;
|
||||
_cardAlgorithm = z3Directive.CardinalityAlgorithm;
|
||||
_pboAlgorithm = z3Directive.PseudoBooleanAlgorithm;
|
||||
_arithStrategy = z3Directive.ArithmeticStrategy;
|
||||
_smt2LogFile = z3Directive.SMT2LogFile;
|
||||
}
|
||||
}
|
||||
|
||||
public Z3BaseParams(Func<bool> queryAbortFunction)
|
||||
{
|
||||
_queryAbortFunction = queryAbortFunction;
|
||||
}
|
||||
|
||||
public Z3BaseParams(Z3BaseParams z3Parameters)
|
||||
{
|
||||
_queryAbortFunction = z3Parameters._queryAbortFunction;
|
||||
}
|
||||
|
||||
#endregion Construction
|
||||
|
||||
#region ISolverParameters Members
|
||||
|
||||
/// <summary>
|
||||
/// Getter for the abort method
|
||||
/// </summary>
|
||||
public Func<bool> QueryAbort
|
||||
{
|
||||
get { return _queryAbortFunction; }
|
||||
set { _queryAbortFunction = value; }
|
||||
}
|
||||
|
||||
public OptimizationKind OptKind
|
||||
{
|
||||
get { return _optKind; }
|
||||
set { _optKind = value; }
|
||||
}
|
||||
|
||||
public CardinalityAlgorithm CardinalityAlgorithm
|
||||
{
|
||||
get { return _cardAlgorithm; }
|
||||
set { _cardAlgorithm = value; }
|
||||
}
|
||||
|
||||
public PseudoBooleanAlgorithm PseudoBooleanAlgorithm
|
||||
{
|
||||
get { return _pboAlgorithm; }
|
||||
set { _pboAlgorithm = value; }
|
||||
}
|
||||
|
||||
public ArithmeticStrategy ArithmeticStrategy
|
||||
{
|
||||
get { return _arithStrategy; }
|
||||
set { _arithStrategy = value; }
|
||||
}
|
||||
|
||||
public string SMT2LogFile
|
||||
{
|
||||
get { return _smt2LogFile; }
|
||||
set { _smt2LogFile = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
381
examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs
Normal file
381
examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs
Normal file
|
@ -0,0 +1,381 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Z3;
|
||||
using Microsoft.SolverFoundation.Common;
|
||||
using Microsoft.SolverFoundation.Services;
|
||||
|
||||
namespace Microsoft.SolverFoundation.Plugin.Z3
|
||||
{
|
||||
internal enum Z3Result
|
||||
{
|
||||
Optimal,
|
||||
LocalOptimal,
|
||||
Feasible,
|
||||
Interrupted,
|
||||
Infeasible
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The basic solver class to take care of transformation from an MSF instance to an Z3 instance
|
||||
/// </summary>
|
||||
internal class Z3BaseSolver
|
||||
{
|
||||
/// <summary>Representing MSF model</summary>
|
||||
private IRowVariableModel _model;
|
||||
|
||||
/// <summary>The Z3 solver we are currently using</summary>
|
||||
private Context _context = null;
|
||||
|
||||
/// <summary>Default optimization solver</summary>
|
||||
private Optimize _optSolver = null;
|
||||
|
||||
/// <summary>Marks when we are inside the Solve() method</summary>
|
||||
private bool _isSolving = false;
|
||||
|
||||
/// <summary>A map from MSF variable ids to Z3 variables</summary>
|
||||
private Dictionary<int, Expr> _variables = new Dictionary<int, Expr>();
|
||||
|
||||
/// <summary>A map from MSF variable ids to Z3 goal ids</summary>
|
||||
private Dictionary<IGoal, uint> _goals = new Dictionary<IGoal, uint>();
|
||||
|
||||
internal Z3BaseSolver(IRowVariableModel model)
|
||||
{
|
||||
_model = model;
|
||||
}
|
||||
|
||||
internal Context Context
|
||||
{
|
||||
get { return _context; }
|
||||
}
|
||||
|
||||
internal Dictionary<int, Expr> Variables
|
||||
{
|
||||
get { return _variables; }
|
||||
}
|
||||
|
||||
internal Dictionary<IGoal, uint> Goals
|
||||
{
|
||||
get { return _goals; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destructs a currently active Z3 solver and the associated data.
|
||||
/// </summary>
|
||||
internal void DestructSolver(bool checkInSolve)
|
||||
{
|
||||
if (_context != null)
|
||||
{
|
||||
if (checkInSolve && !_isSolving)
|
||||
{
|
||||
_variables.Clear();
|
||||
if (!_isSolving)
|
||||
{
|
||||
_optSolver.Dispose();
|
||||
_context.Dispose();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error.WriteLine("Z3 destruction is invoked while in Solving phase.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a Z3 solver to be used.
|
||||
/// </summary>
|
||||
internal void ConstructSolver(Z3BaseParams parameters)
|
||||
{
|
||||
// If Z3 is there already, kill it
|
||||
if (_context != null)
|
||||
{
|
||||
DestructSolver(false);
|
||||
}
|
||||
|
||||
_context = new Context();
|
||||
_optSolver = _context.MkOptimize();
|
||||
var p = _context.MkParams();
|
||||
|
||||
switch (parameters.OptKind)
|
||||
{
|
||||
case OptimizationKind.BoundingBox:
|
||||
p.Add("priority", _context.MkSymbol("box"));
|
||||
break;
|
||||
case OptimizationKind.Lexicographic:
|
||||
p.Add("priority", _context.MkSymbol("lex"));
|
||||
break;
|
||||
case OptimizationKind.ParetoOptimal:
|
||||
p.Add("priority", _context.MkSymbol("pareto"));
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false, String.Format("Unknown optimization option {0}", parameters.OptKind));
|
||||
break;
|
||||
}
|
||||
|
||||
switch (parameters.CardinalityAlgorithm)
|
||||
{
|
||||
case CardinalityAlgorithm.FuMalik:
|
||||
p.Add("maxsat_engine", _context.MkSymbol("fu_malik"));
|
||||
break;
|
||||
case CardinalityAlgorithm.CoreMaxSAT:
|
||||
p.Add("maxsat_engine", _context.MkSymbol("core_maxsat"));
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false, String.Format("Unknown cardinality algorithm option {0}", parameters.CardinalityAlgorithm));
|
||||
break;
|
||||
}
|
||||
|
||||
switch (parameters.PseudoBooleanAlgorithm)
|
||||
{
|
||||
case PseudoBooleanAlgorithm.WeightedMaxSAT:
|
||||
p.Add("wmaxsat_engine", _context.MkSymbol("wmax"));
|
||||
break;
|
||||
case PseudoBooleanAlgorithm.IterativeWeightedMaxSAT:
|
||||
p.Add("wmaxsat_engine", _context.MkSymbol("iwmax"));
|
||||
break;
|
||||
case PseudoBooleanAlgorithm.BisectionWeightedMaxSAT:
|
||||
p.Add("wmaxsat_engine", _context.MkSymbol("bwmax"));
|
||||
break;
|
||||
case PseudoBooleanAlgorithm.WeightedPartialMaxSAT2:
|
||||
p.Add("wmaxsat_engine", _context.MkSymbol("wpm2"));
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false, String.Format("Unknown pseudo-boolean algorithm option {0}", parameters.PseudoBooleanAlgorithm));
|
||||
break;
|
||||
}
|
||||
|
||||
switch (parameters.ArithmeticStrategy)
|
||||
{
|
||||
case ArithmeticStrategy.Basic:
|
||||
p.Add("engine", _context.MkSymbol("basic"));
|
||||
break;
|
||||
case ArithmeticStrategy.Farkas:
|
||||
p.Add("engine", _context.MkSymbol("farkas"));
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false, String.Format("Unknown arithmetic strategy option {0}", parameters.ArithmeticStrategy));
|
||||
break;
|
||||
}
|
||||
|
||||
_optSolver.Parameters = p;
|
||||
}
|
||||
|
||||
internal ArithExpr GetVariable(int vid)
|
||||
{
|
||||
Expr variable;
|
||||
if (!_variables.TryGetValue(vid, out variable))
|
||||
{
|
||||
AddVariable(vid);
|
||||
variable = _variables[vid];
|
||||
}
|
||||
return (ArithExpr)variable;
|
||||
}
|
||||
|
||||
internal void AssertBool(BoolExpr row)
|
||||
{
|
||||
_optSolver.Assert(row);
|
||||
}
|
||||
|
||||
internal void AssertArith(int vid, ArithExpr variable)
|
||||
{
|
||||
// Get the bounds on the row
|
||||
Rational lower, upper;
|
||||
_model.GetBounds(vid, out lower, out upper);
|
||||
|
||||
// Case of equality
|
||||
if (lower == upper)
|
||||
{
|
||||
// Create the equality term
|
||||
Expr eqConst = GetNumeral(lower, variable.Sort);
|
||||
BoolExpr constraint = _context.MkEq(eqConst, variable);
|
||||
// Assert the constraint
|
||||
_optSolver.Assert(constraint);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If upper bound is finite assert the upper bound constraint
|
||||
if (lower.IsFinite)
|
||||
{
|
||||
// Create the lower Bound constraint
|
||||
ArithExpr lowerTerm = GetNumeral(lower, variable.Sort);
|
||||
BoolExpr constraint = _context.MkLe(lowerTerm, variable);
|
||||
// Assert the constraint
|
||||
_optSolver.Assert(constraint);
|
||||
}
|
||||
// If lower bound is finite assert the lower bound constraint
|
||||
if (upper.IsFinite)
|
||||
{
|
||||
// Create the upper bound constraint
|
||||
ArithExpr upperTerm = GetNumeral(upper, variable.Sort);
|
||||
BoolExpr constraint = _context.MkGe(upperTerm, variable);
|
||||
// Assert the constraint
|
||||
_optSolver.Assert(constraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a MSF variable with the coresponding assertion to the Z3 variables.
|
||||
/// </summary>
|
||||
/// <param name="vid">The MSF id of the variable</param>
|
||||
internal void AddVariable(int vid)
|
||||
{
|
||||
// Is the variable an integer
|
||||
bool isInteger = _model.GetIntegrality(vid);
|
||||
|
||||
// Construct the sort we will be using
|
||||
Sort sort = isInteger ? (Sort)_context.IntSort : (Sort)_context.RealSort;
|
||||
|
||||
// Get the variable key
|
||||
object key = _model.GetKeyFromIndex(vid);
|
||||
|
||||
// Try to construct the name
|
||||
string name;
|
||||
if (key != null) name = String.Format("x_{0}_{1}", key, vid);
|
||||
else name = String.Format("x_{0}", vid);
|
||||
ArithExpr variable = (ArithExpr)_context.MkConst(name, sort);
|
||||
|
||||
// Create the variable and add it to the map
|
||||
Debug.Assert(!_variables.ContainsKey(vid), "Variable names should be unique.");
|
||||
_variables.Add(vid, variable);
|
||||
|
||||
AssertArith(vid, variable);
|
||||
}
|
||||
|
||||
internal ArithExpr GetNumeral(Rational rational, Sort sort = null)
|
||||
{
|
||||
return Utils.GetNumeral(_context, rational, sort);
|
||||
}
|
||||
|
||||
internal void Solve(Z3BaseParams parameters, IEnumerable<IGoal> modelGoals,
|
||||
Action<int> addRow, Func<int, ArithExpr> mkGoalRow, Action<Z3Result> setResult)
|
||||
{
|
||||
_variables.Clear();
|
||||
_goals.Clear();
|
||||
|
||||
try
|
||||
{
|
||||
// Mark that we are in solving phase
|
||||
_isSolving = true;
|
||||
|
||||
// Construct Z3
|
||||
ConstructSolver(parameters);
|
||||
|
||||
// Add all the variables
|
||||
foreach (int vid in _model.VariableIndices)
|
||||
{
|
||||
AddVariable(vid);
|
||||
}
|
||||
|
||||
// Add all the rows
|
||||
foreach (int rid in _model.RowIndices)
|
||||
{
|
||||
addRow(rid);
|
||||
}
|
||||
|
||||
// Add enabled goals to optimization problem
|
||||
foreach (IGoal g in modelGoals)
|
||||
{
|
||||
if (!g.Enabled) continue;
|
||||
|
||||
ArithExpr gr = mkGoalRow(g.Index);
|
||||
if (g.Minimize)
|
||||
_goals.Add(g, _optSolver.MkMinimize(gr));
|
||||
else
|
||||
_goals.Add(g, _optSolver.MkMaximize(gr));
|
||||
}
|
||||
|
||||
if (_goals.Any() && parameters.SMT2LogFile != null)
|
||||
{
|
||||
Debug.WriteLine("Dumping SMT2 benchmark to log file...");
|
||||
File.WriteAllText(parameters.SMT2LogFile, _optSolver.ToString());
|
||||
}
|
||||
|
||||
bool aborted = parameters.QueryAbort();
|
||||
|
||||
if (!aborted)
|
||||
{
|
||||
// Start the abort thread
|
||||
AbortWorker abortWorker = new AbortWorker(_context, parameters.QueryAbort);
|
||||
Thread abortThread = new Thread(abortWorker.Start);
|
||||
abortThread.Start();
|
||||
|
||||
// Now solve the problem
|
||||
Status status = _optSolver.Check();
|
||||
|
||||
// Stop the abort thread
|
||||
abortWorker.Stop();
|
||||
abortThread.Join();
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case Status.SATISFIABLE:
|
||||
Microsoft.Z3.Model model = _optSolver.Model;
|
||||
Debug.Assert(model != null, "Should be able to get Z3 model.");
|
||||
// Remember the solution values
|
||||
foreach (KeyValuePair<int, Expr> pair in _variables)
|
||||
{
|
||||
var value = Utils.ToRational(model.Eval(pair.Value, true));
|
||||
_model.SetValue(pair.Key, value);
|
||||
}
|
||||
// Remember all objective values
|
||||
foreach (var pair in _goals)
|
||||
{
|
||||
var optimalValue = Utils.ToRational(_optSolver.GetUpper(pair.Value));
|
||||
_model.SetValue(pair.Key.Index, optimalValue);
|
||||
}
|
||||
model.Dispose();
|
||||
setResult(_goals.Any() ? Z3Result.Optimal : Z3Result.Feasible);
|
||||
break;
|
||||
case Status.UNSATISFIABLE:
|
||||
setResult(Z3Result.Infeasible);
|
||||
break;
|
||||
case Status.UNKNOWN:
|
||||
if (abortWorker.Aborted)
|
||||
{
|
||||
Microsoft.Z3.Model subOptimalModel = _optSolver.Model;
|
||||
if (subOptimalModel != null && subOptimalModel.NumConsts != 0)
|
||||
{
|
||||
// Remember the solution values
|
||||
foreach (KeyValuePair<int, Expr> pair in _variables)
|
||||
{
|
||||
var value = Utils.ToRational(subOptimalModel.Eval(pair.Value, true));
|
||||
_model.SetValue(pair.Key, value);
|
||||
}
|
||||
// Remember all objective values
|
||||
foreach (var pair in _goals)
|
||||
{
|
||||
var optimalValue = Utils.ToRational(_optSolver.GetUpper(pair.Value));
|
||||
_model.SetValue(pair.Key.Index, optimalValue);
|
||||
}
|
||||
subOptimalModel.Dispose();
|
||||
|
||||
setResult(Z3Result.LocalOptimal);
|
||||
}
|
||||
else
|
||||
setResult(Z3Result.Infeasible);
|
||||
}
|
||||
else
|
||||
setResult(Z3Result.Interrupted);
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false, "Unrecognized Z3 Status");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isSolving = false;
|
||||
}
|
||||
|
||||
// Now kill Z3
|
||||
DestructSolver(true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using Microsoft.SolverFoundation.Services;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SolverFoundation.Plugin.Z3
|
||||
{
|
||||
public class Z3MILPDirective : Z3BaseDirective
|
||||
{
|
||||
}
|
||||
}
|
19
examples/msf/SolverFoundation.Plugin.Z3/Z3MILPParams.cs
Normal file
19
examples/msf/SolverFoundation.Plugin.Z3/Z3MILPParams.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using Microsoft.SolverFoundation.Services;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SolverFoundation.Plugin.Z3
|
||||
{
|
||||
public class Z3MILPParams : Z3BaseParams
|
||||
{
|
||||
// Need these constructors for reflection done by plugin model
|
||||
|
||||
public Z3MILPParams() : base() { }
|
||||
|
||||
public Z3MILPParams(Directive directive) : base(directive) { }
|
||||
|
||||
public Z3MILPParams(Func<bool> queryAbortFunction) : base(queryAbortFunction) { }
|
||||
|
||||
public Z3MILPParams(Z3BaseParams z3Parameters) : base (z3Parameters) { }
|
||||
}
|
||||
|
||||
}
|
230
examples/msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs
Normal file
230
examples/msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs
Normal file
|
@ -0,0 +1,230 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
|
||||
using Microsoft.Z3;
|
||||
using Microsoft.SolverFoundation.Common;
|
||||
using Microsoft.SolverFoundation.Services;
|
||||
using Microsoft.SolverFoundation.Plugin;
|
||||
|
||||
namespace Microsoft.SolverFoundation.Plugin.Z3
|
||||
{
|
||||
/// <summary>
|
||||
/// The class is implementation of the MSF mixed linear programming solver
|
||||
/// using the Microsoft Z3 solver as the backend.
|
||||
/// </summary>
|
||||
public class Z3MILPSolver : LinearModel, ILinearSolver, ILinearSolution, IReportProvider
|
||||
{
|
||||
#region Private members
|
||||
|
||||
private LinearResult _result;
|
||||
private LinearSolutionQuality _solutionQuality;
|
||||
private Z3BaseSolver _solver;
|
||||
|
||||
#endregion Private members
|
||||
|
||||
#region Solver construction and destruction
|
||||
|
||||
/// <summary>Constructor that initializes the base clases</summary>
|
||||
public Z3MILPSolver() : base(null)
|
||||
{
|
||||
_result = LinearResult.Feasible;
|
||||
_solver = new Z3BaseSolver(this);
|
||||
}
|
||||
|
||||
/// <summary>Constructor that initializes the base clases</summary>
|
||||
public Z3MILPSolver(ISolverEnvironment context) : this() { }
|
||||
|
||||
/// <summary>
|
||||
/// Shutdown can be called when when the solver is not active, i.e.
|
||||
/// when it is done with Solve() or it has gracefully returns from Solve()
|
||||
/// after an abort.
|
||||
/// </summary>
|
||||
public void Shutdown() { _solver.DestructSolver(true); }
|
||||
|
||||
#endregion Solver construction and destruction
|
||||
|
||||
#region Obtaining information about the solution
|
||||
|
||||
public ILinearSolverReport GetReport(LinearSolverReportType reportType)
|
||||
{
|
||||
// We don't support sensitivity report
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion Obtaining information about the solution
|
||||
|
||||
#region Construction of the problem
|
||||
|
||||
/// <summary>
|
||||
/// Get corresponding Z3 formula of a MSF row.
|
||||
/// </summary>
|
||||
/// <param name="rid">The MSF row id</param>
|
||||
private ArithExpr MkGoalRow(int rid)
|
||||
{
|
||||
// Start with the 0 term
|
||||
List<ArithExpr> row = new List<ArithExpr>();
|
||||
|
||||
// Now, add all the entries of this row
|
||||
foreach (LinearEntry entry in GetRowEntries(rid))
|
||||
{
|
||||
// Get the variable and constant in the row
|
||||
ArithExpr e = _solver.GetVariable(entry.Index);
|
||||
if (!entry.Value.IsOne)
|
||||
{
|
||||
e = _solver.Context.MkMul(_solver.GetNumeral(entry.Value, e.Sort), e);
|
||||
}
|
||||
row.Add(e);
|
||||
}
|
||||
switch (row.Count)
|
||||
{
|
||||
case 0: return _solver.GetNumeral(new Rational());
|
||||
case 1: return row[0];
|
||||
default: return _solver.Context.MkAdd(row.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a MSF row to the Z3 assertions.
|
||||
/// </summary>
|
||||
/// <param name="rid">The MSF row id</param>
|
||||
private void AddRow(int rid)
|
||||
{
|
||||
// Start with the 0 term
|
||||
ArithExpr row = MkGoalRow(rid);
|
||||
_solver.AssertArith(rid, row);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set results based on internal solver status
|
||||
/// </summary>
|
||||
private void SetResult(Z3Result status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case Z3Result.Optimal:
|
||||
_result = LinearResult.Optimal;
|
||||
_solutionQuality = LinearSolutionQuality.Exact;
|
||||
break;
|
||||
case Z3Result.LocalOptimal:
|
||||
_result = LinearResult.Feasible;
|
||||
_solutionQuality = LinearSolutionQuality.Approximate;
|
||||
break;
|
||||
case Z3Result.Feasible:
|
||||
_result = LinearResult.Feasible;
|
||||
_solutionQuality = LinearSolutionQuality.Exact;
|
||||
break;
|
||||
case Z3Result.Infeasible:
|
||||
_result = LinearResult.InfeasiblePrimal;
|
||||
_solutionQuality = LinearSolutionQuality.None;
|
||||
break;
|
||||
case Z3Result.Interrupted:
|
||||
_result = LinearResult.Interrupted;
|
||||
_solutionQuality = LinearSolutionQuality.None;
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false, "Unrecognized Z3 Result");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Construction of the problem
|
||||
|
||||
#region Solving the problem
|
||||
|
||||
/// <summary>
|
||||
/// Starts solving the problem using the Z3 solver.
|
||||
/// </summary>
|
||||
/// <param name="parameters">Parameters to the solver</param>
|
||||
/// <returns>The solution to the problem</returns>
|
||||
public ILinearSolution Solve(ISolverParameters parameters)
|
||||
{
|
||||
// Get the Z3 parameters
|
||||
var z3Params = parameters as Z3BaseParams;
|
||||
Debug.Assert(z3Params != null, "Parameters should be an instance of Z3BaseParams.");
|
||||
|
||||
_solver.Solve(z3Params, Goals, AddRow, MkGoalRow, SetResult);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion Solving the problem
|
||||
|
||||
#region ILinearSolution Members
|
||||
|
||||
public Rational GetSolutionValue(int goalIndex)
|
||||
{
|
||||
var goal = Goals.ElementAt(goalIndex);
|
||||
Debug.Assert(goal != null, "Goal should be an element of the goal list.");
|
||||
return GetValue(goal.Index);
|
||||
}
|
||||
|
||||
public void GetSolvedGoal(int goalIndex, out object key, out int vid, out bool minimize, out bool optimal)
|
||||
{
|
||||
var goal = Goals.ElementAt(goalIndex);
|
||||
Debug.Assert(goal != null, "Goal should be an element of the goal list.");
|
||||
key = goal.Key;
|
||||
vid = goal.Index;
|
||||
minimize = goal.Minimize;
|
||||
optimal = _result == LinearResult.Optimal;
|
||||
}
|
||||
|
||||
// LpResult is LP relaxation assignment.
|
||||
|
||||
public LinearResult LpResult
|
||||
{
|
||||
get { return _result; }
|
||||
}
|
||||
|
||||
public Rational MipBestBound
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(GoalCount > 0, "MipBestBound is only applicable for optimization instances.");
|
||||
return GetSolutionValue(0);
|
||||
}
|
||||
}
|
||||
|
||||
public LinearResult MipResult
|
||||
{
|
||||
get { return _result; }
|
||||
}
|
||||
|
||||
public LinearResult Result
|
||||
{
|
||||
get { return _result; }
|
||||
}
|
||||
|
||||
public LinearSolutionQuality SolutionQuality
|
||||
{
|
||||
get { return _solutionQuality; }
|
||||
}
|
||||
|
||||
public int SolvedGoalCount
|
||||
{
|
||||
get { return GoalCount; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public Report GetReport(SolverContext context, Solution solution, SolutionMapping solutionMapping)
|
||||
{
|
||||
LinearSolutionMapping lpSolutionMapping = solutionMapping as LinearSolutionMapping;
|
||||
if (lpSolutionMapping == null && solutionMapping != null)
|
||||
throw new ArgumentException("solutionMapping is not a LinearSolutionMapping", "solutionMapping");
|
||||
return new Z3LinearSolverReport(context, this, solution, lpSolutionMapping);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class implementing the LinearReport.
|
||||
/// </summary>
|
||||
public class Z3LinearSolverReport : LinearReport
|
||||
{
|
||||
public Z3LinearSolverReport(SolverContext context, ISolver solver, Solution solution, LinearSolutionMapping solutionMapping)
|
||||
: base(context, solver, solution, solutionMapping) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using Microsoft.SolverFoundation.Services;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SolverFoundation.Plugin.Z3
|
||||
{
|
||||
public class Z3TermDirective : Z3BaseDirective
|
||||
{
|
||||
}
|
||||
}
|
17
examples/msf/SolverFoundation.Plugin.Z3/Z3TermParams.cs
Normal file
17
examples/msf/SolverFoundation.Plugin.Z3/Z3TermParams.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using Microsoft.SolverFoundation.Services;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.SolverFoundation.Plugin.Z3
|
||||
{
|
||||
public class Z3TermParams : Z3BaseParams
|
||||
{
|
||||
public Z3TermParams() : base() { }
|
||||
|
||||
public Z3TermParams(Directive directive) : base(directive) { }
|
||||
|
||||
public Z3TermParams(Func<bool> queryAbortFunction) : base(queryAbortFunction) { }
|
||||
|
||||
public Z3TermParams(Z3BaseParams z3Parameters) : base(z3Parameters) { }
|
||||
}
|
||||
|
||||
}
|
382
examples/msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs
Normal file
382
examples/msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs
Normal file
|
@ -0,0 +1,382 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Globalization;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.SolverFoundation.Common;
|
||||
using Microsoft.SolverFoundation.Properties;
|
||||
using Microsoft.SolverFoundation.Solvers;
|
||||
using Microsoft.SolverFoundation.Services;
|
||||
using Microsoft.Z3;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.SolverFoundation.Plugin.Z3
|
||||
{
|
||||
/// <summary>
|
||||
/// The class is implementation of the MSF constraint solver
|
||||
/// using the Microsoft Z3 solver as the backend.
|
||||
/// This solver supports Int, Real constraints and their arbitrary boolean combinations.
|
||||
/// </summary>
|
||||
public class Z3TermSolver : TermModel, ITermSolver, INonlinearSolution, IReportProvider
|
||||
{
|
||||
private NonlinearResult _result;
|
||||
private Z3BaseSolver _solver;
|
||||
|
||||
/// <summary>Constructor that initializes the base clases</summary>
|
||||
public Z3TermSolver() : base(null)
|
||||
{
|
||||
_solver = new Z3BaseSolver(this);
|
||||
}
|
||||
|
||||
/// <summary>Constructor that initializes the base clases</summary>
|
||||
public Z3TermSolver(ISolverEnvironment context) : this() { }
|
||||
|
||||
/// <summary>
|
||||
/// Shutdown can be called when when the solver is not active, i.e.
|
||||
/// when it is done with Solve() or it has gracefully returns from Solve()
|
||||
/// after an abort.
|
||||
/// </summary>
|
||||
public void Shutdown() { _solver.DestructSolver(true); }
|
||||
|
||||
private BoolExpr MkBool(int rid)
|
||||
{
|
||||
var context = _solver.Context;
|
||||
|
||||
if (IsConstant(rid))
|
||||
{
|
||||
Rational lower, upper;
|
||||
GetBounds(rid, out lower, out upper);
|
||||
Debug.Assert(lower == upper);
|
||||
if (lower.IsZero) return context.MkFalse();
|
||||
return context.MkTrue();
|
||||
}
|
||||
if (IsOperation(rid))
|
||||
{
|
||||
BoolExpr[] children;
|
||||
ArithExpr[] operands;
|
||||
TermModelOperation op = GetOperation(rid);
|
||||
switch(op) {
|
||||
case TermModelOperation.And:
|
||||
Debug.Assert(GetOperandCount(rid) >= 2, "Conjunction requires at least two operands.");
|
||||
children = (GetOperands(rid)).Select(x => MkBool(x)).ToArray();
|
||||
return context.MkAnd(children);
|
||||
case TermModelOperation.Or:
|
||||
Debug.Assert(GetOperandCount(rid) >= 2, "Disjunction requires at least two operands.");
|
||||
children = (GetOperands(rid)).Select(x => MkBool(x)).ToArray();
|
||||
return context.MkOr(children);
|
||||
case TermModelOperation.Not:
|
||||
Debug.Assert(GetOperandCount(rid) == 1, "Negation is unary.");
|
||||
return context.MkNot(MkBool(GetOperand(rid, 0)));
|
||||
case TermModelOperation.If:
|
||||
Debug.Assert(GetOperandCount(rid) == 3, "If is ternary.");
|
||||
BoolExpr b = MkBool(GetOperand(rid, 0));
|
||||
Expr x1 = MkBool(GetOperand(rid, 1));
|
||||
Expr x2 = MkBool(GetOperand(rid, 2));
|
||||
return (BoolExpr)context.MkITE(b, x1, x2);
|
||||
case TermModelOperation.Unequal:
|
||||
Debug.Assert(GetOperandCount(rid) >= 2, "Distinct should have at least two operands.");
|
||||
return context.MkDistinct((GetOperands(rid)).Select(x => MkTerm(x)).ToArray());
|
||||
case TermModelOperation.Greater:
|
||||
case TermModelOperation.Less:
|
||||
case TermModelOperation.GreaterEqual:
|
||||
case TermModelOperation.LessEqual:
|
||||
case TermModelOperation.Equal:
|
||||
Debug.Assert(GetOperandCount(rid) >= 2, "Comparison should have at least two operands.");
|
||||
operands = (GetOperands(rid)).Select(x => MkTerm(x)).ToArray();
|
||||
return ReduceComparison(GetOperation(rid), operands);
|
||||
case TermModelOperation.Identity:
|
||||
Debug.Assert(GetOperandCount(rid) == 1, "Identity takes exactly one operand.");
|
||||
return MkBool(GetOperand(rid, 0));
|
||||
default:
|
||||
return context.MkEq(MkTerm(rid), _solver.GetNumeral(Rational.One));
|
||||
}
|
||||
}
|
||||
return context.MkEq(MkTerm(rid), _solver.GetNumeral(Rational.One));
|
||||
}
|
||||
|
||||
private ArithExpr MkBoolToArith(BoolExpr e)
|
||||
{
|
||||
var context = _solver.Context;
|
||||
return (ArithExpr)context.MkITE(e, _solver.GetNumeral(Rational.One), _solver.GetNumeral(Rational.Zero));
|
||||
}
|
||||
|
||||
private ArithExpr MkTerm(int rid)
|
||||
{
|
||||
var context = _solver.Context;
|
||||
|
||||
if (IsConstant(rid))
|
||||
{
|
||||
Rational lower, upper;
|
||||
GetBounds(rid, out lower, out upper);
|
||||
Debug.Assert(lower == upper);
|
||||
return _solver.GetNumeral(lower);
|
||||
}
|
||||
else if (IsOperation(rid))
|
||||
{
|
||||
ArithExpr[] operands;
|
||||
TermModelOperation op = GetOperation(rid);
|
||||
switch(op)
|
||||
{
|
||||
case TermModelOperation.And:
|
||||
case TermModelOperation.Or:
|
||||
case TermModelOperation.Not:
|
||||
case TermModelOperation.Unequal:
|
||||
case TermModelOperation.Greater:
|
||||
case TermModelOperation.Less:
|
||||
case TermModelOperation.GreaterEqual:
|
||||
case TermModelOperation.LessEqual:
|
||||
case TermModelOperation.Equal:
|
||||
return MkBoolToArith(MkBool(rid));
|
||||
case TermModelOperation.If:
|
||||
Debug.Assert(GetOperandCount(rid) == 3, "If is ternary.");
|
||||
BoolExpr b = MkBool(GetOperand(rid, 0));
|
||||
Expr x1 = MkTerm(GetOperand(rid, 1));
|
||||
Expr x2 = MkTerm(GetOperand(rid, 2));
|
||||
return (ArithExpr)context.MkITE(b, x1, x2);
|
||||
case TermModelOperation.Plus:
|
||||
Debug.Assert(GetOperandCount(rid) >= 2, "Plus takes at least two operands.");
|
||||
operands = (GetOperands(rid)).Select(x => MkTerm(x)).ToArray();
|
||||
return context.MkAdd(operands);
|
||||
case TermModelOperation.Minus:
|
||||
Debug.Assert(GetOperandCount(rid) == 1, "Minus takes exactly one operand.");
|
||||
return context.MkUnaryMinus(MkTerm(GetOperand(rid, 0)));
|
||||
case TermModelOperation.Times:
|
||||
Debug.Assert(GetOperandCount(rid) >= 2, "Times requires at least two operands.");
|
||||
operands = (GetOperands(rid)).Select(x => MkTerm(x)).ToArray();
|
||||
return context.MkMul(operands);
|
||||
case TermModelOperation.Identity:
|
||||
Debug.Assert(GetOperandCount(rid) == 1, "Identity takes exactly one operand.");
|
||||
return MkTerm(GetOperand(rid, 0));
|
||||
case TermModelOperation.Abs:
|
||||
Debug.Assert(GetOperandCount(rid) == 1, "Abs takes exactly one operand.");
|
||||
ArithExpr e = MkTerm(GetOperand(rid, 0));
|
||||
ArithExpr minusE = context.MkUnaryMinus(e);
|
||||
ArithExpr zero = _solver.GetNumeral(Rational.Zero);
|
||||
return (ArithExpr)context.MkITE(context.MkGe(e, zero), e, minusE);
|
||||
default:
|
||||
Console.Error.WriteLine("{0} operation isn't supported.", op);
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return _solver.GetVariable(rid);
|
||||
}
|
||||
}
|
||||
|
||||
private BoolExpr ReduceComparison(TermModelOperation type, ArithExpr[] operands)
|
||||
{
|
||||
var context = _solver.Context;
|
||||
Debug.Assert(operands.Length >= 2);
|
||||
Func<ArithExpr, ArithExpr, BoolExpr> mkComparison;
|
||||
switch (type)
|
||||
{
|
||||
case TermModelOperation.Greater:
|
||||
mkComparison = (x, y) => context.MkGt(x, y);
|
||||
break;
|
||||
case TermModelOperation.Less:
|
||||
mkComparison = (x, y) => context.MkLt(x, y);
|
||||
break;
|
||||
case TermModelOperation.GreaterEqual:
|
||||
mkComparison = (x, y) => context.MkGe(x, y);
|
||||
break;
|
||||
case TermModelOperation.LessEqual:
|
||||
mkComparison = (x, y) => context.MkLe(x, y);
|
||||
break;
|
||||
case TermModelOperation.Equal:
|
||||
mkComparison = (x, y) => context.MkEq(x, y);
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
BoolExpr current = mkComparison(operands[0], operands[1]);
|
||||
for (int i = 1; i < operands.Length - 1; ++i)
|
||||
current = context.MkAnd(current, mkComparison(operands[i], operands[i + 1]));
|
||||
return current;
|
||||
}
|
||||
|
||||
private bool IsBoolRow(int rid)
|
||||
{
|
||||
Rational lower, upper;
|
||||
GetBounds(rid, out lower, out upper);
|
||||
|
||||
return lower == upper && lower.IsOne && IsBoolTerm(rid);
|
||||
}
|
||||
|
||||
private bool IsBoolTerm(int rid)
|
||||
{
|
||||
if (IsConstant(rid))
|
||||
{
|
||||
Rational lower, upper;
|
||||
GetBounds(rid, out lower, out upper);
|
||||
Debug.Assert(lower == upper);
|
||||
return lower.IsOne || lower.IsZero;
|
||||
}
|
||||
if (IsOperation(rid))
|
||||
{
|
||||
TermModelOperation op = GetOperation(rid);
|
||||
switch (op)
|
||||
{
|
||||
case TermModelOperation.And:
|
||||
case TermModelOperation.Or:
|
||||
case TermModelOperation.Not:
|
||||
case TermModelOperation.LessEqual:
|
||||
case TermModelOperation.Less:
|
||||
case TermModelOperation.Greater:
|
||||
case TermModelOperation.GreaterEqual:
|
||||
case TermModelOperation.Unequal:
|
||||
case TermModelOperation.Equal:
|
||||
return true;
|
||||
case TermModelOperation.If:
|
||||
return IsBoolTerm(GetOperand(rid, 1)) &&
|
||||
IsBoolTerm(GetOperand(rid, 2));
|
||||
case TermModelOperation.Identity:
|
||||
return IsBoolTerm(GetOperand(rid, 0));
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a MSF row to the Z3 assertions.
|
||||
/// </summary>
|
||||
/// <param name="rid">The MSF row id</param>
|
||||
private void AddRow(int rid)
|
||||
{
|
||||
if (IsConstant(rid))
|
||||
return;
|
||||
|
||||
if (IsBoolRow(rid))
|
||||
{
|
||||
_solver.AssertBool(MkBool(rid));
|
||||
return;
|
||||
}
|
||||
// Start with the 0 term
|
||||
ArithExpr row = MkTerm(rid);
|
||||
_solver.AssertArith(rid, row);
|
||||
}
|
||||
|
||||
private TermModelOperation[] _supportedOperations =
|
||||
{ TermModelOperation.And,
|
||||
TermModelOperation.Or,
|
||||
TermModelOperation.Not,
|
||||
TermModelOperation.Unequal,
|
||||
TermModelOperation.Greater,
|
||||
TermModelOperation.Less,
|
||||
TermModelOperation.GreaterEqual,
|
||||
TermModelOperation.LessEqual,
|
||||
TermModelOperation.Equal,
|
||||
TermModelOperation.If,
|
||||
TermModelOperation.Plus,
|
||||
TermModelOperation.Minus,
|
||||
TermModelOperation.Times,
|
||||
TermModelOperation.Identity,
|
||||
TermModelOperation.Abs };
|
||||
|
||||
/// <summary>
|
||||
/// Gets the operations supported by the solver.
|
||||
/// </summary>
|
||||
/// <returns>All the TermModelOperations supported by the solver.</returns>
|
||||
public IEnumerable<TermModelOperation> SupportedOperations
|
||||
{
|
||||
get { return _supportedOperations; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set results based on internal solver status
|
||||
/// </summary>
|
||||
private void SetResult(Z3Result status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case Z3Result.Optimal:
|
||||
_result = NonlinearResult.Optimal;
|
||||
break;
|
||||
case Z3Result.LocalOptimal:
|
||||
_result = NonlinearResult.LocalOptimal;
|
||||
break;
|
||||
case Z3Result.Feasible:
|
||||
_result = NonlinearResult.Feasible;
|
||||
break;
|
||||
case Z3Result.Infeasible:
|
||||
_result = NonlinearResult.Infeasible;
|
||||
break;
|
||||
case Z3Result.Interrupted:
|
||||
_result = NonlinearResult.Interrupted;
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false, "Unrecognized Z3 Result");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts solving the problem using the Z3 solver.
|
||||
/// </summary>
|
||||
/// <param name="parameters">Parameters to the solver</param>
|
||||
/// <returns>The solution to the problem</returns>
|
||||
public INonlinearSolution Solve(ISolverParameters parameters)
|
||||
{
|
||||
// Get the Z3 parameters
|
||||
var z3Params = parameters as Z3BaseParams;
|
||||
Debug.Assert(z3Params != null, "Parameters should be an instance of Z3BaseParams.");
|
||||
|
||||
_solver.Solve(z3Params, Goals, AddRow, MkTerm, SetResult);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
double INonlinearSolution.GetValue(int vid)
|
||||
{
|
||||
Debug.Assert(_solver.Variables.ContainsKey(vid), "This index should correspond to a variable.");
|
||||
return GetValue(vid).ToDouble();
|
||||
}
|
||||
|
||||
public int SolvedGoalCount
|
||||
{
|
||||
get { return GoalCount; }
|
||||
}
|
||||
|
||||
public double GetSolutionValue(int goalIndex)
|
||||
{
|
||||
var goal = Goals.ElementAt(goalIndex);
|
||||
Debug.Assert(goal != null, "Goal should be an element of the goal list.");
|
||||
return GetValue(goal.Index).ToDouble();
|
||||
}
|
||||
|
||||
public void GetSolvedGoal(int goalIndex, out object key, out int vid, out bool minimize, out bool optimal)
|
||||
{
|
||||
var goal = Goals.ElementAt(goalIndex);
|
||||
Debug.Assert(goal != null, "Goal should be an element of the goal list.");
|
||||
key = goal.Key;
|
||||
vid = goal.Index;
|
||||
minimize = goal.Minimize;
|
||||
optimal = _result == NonlinearResult.Optimal;
|
||||
}
|
||||
|
||||
public NonlinearResult Result
|
||||
{
|
||||
get { return _result; }
|
||||
}
|
||||
|
||||
public Report GetReport(SolverContext context, Solution solution, SolutionMapping solutionMapping)
|
||||
{
|
||||
PluginSolutionMapping pluginSolutionMapping = solutionMapping as PluginSolutionMapping;
|
||||
if (pluginSolutionMapping == null && solutionMapping != null)
|
||||
throw new ArgumentException("solutionMapping is not a LinearSolutionMapping", "solutionMapping");
|
||||
return new Z3TermSolverReport(context, this, solution, pluginSolutionMapping);
|
||||
}
|
||||
}
|
||||
|
||||
public class Z3TermSolverReport : Report
|
||||
{
|
||||
public Z3TermSolverReport(SolverContext context, ISolver solver, Solution solution, PluginSolutionMapping pluginSolutionMapping)
|
||||
: base(context, solver, solution, pluginSolutionMapping)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue