3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-14 23:05:26 +00:00

Add MSF plugins

This commit is contained in:
Anh-Dung Phan 2013-12-27 11:18:10 -08:00
parent 58f8181a74
commit 5cc4cc8226
24 changed files with 2683 additions and 0 deletions

View 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
}
}

View file

@ -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")]

View file

@ -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>

View 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;
}
}
}

View 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();
}
}
}

View 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
}
}

View 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);
}
}
}

View file

@ -0,0 +1,9 @@
using Microsoft.SolverFoundation.Services;
using System;
namespace Microsoft.SolverFoundation.Plugin.Z3
{
public class Z3MILPDirective : Z3BaseDirective
{
}
}

View 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) { }
}
}

View 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) {
}
}
}

View file

@ -0,0 +1,9 @@
using Microsoft.SolverFoundation.Services;
using System;
namespace Microsoft.SolverFoundation.Plugin.Z3
{
public class Z3TermDirective : Z3BaseDirective
{
}
}

View 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) { }
}
}

View 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)
{
}
}
}