3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-27 02:45:51 +00:00

Merge branch 'opt' of https://git01.codeplex.com/z3 into opt

This commit is contained in:
unknown 2015-01-28 17:54:26 -08:00
commit f020b7c7b8
380 changed files with 66767 additions and 3722 deletions

1
.gitignore vendored
View file

@ -18,6 +18,7 @@ ocamlz3
# Emacs temp files
\#*\#
# Directories with generated code and documentation
release/*
build/*
build-dist/*
dist/*

View file

@ -1,5 +1,10 @@
RELEASE NOTES
Version 4.3.3
=============
- Fixed bug in floating point models
Version 4.3.2
=============

View file

@ -21,6 +21,7 @@ void demorgan() {
// adding the negation of the conjecture as a constraint.
s.add(!conjecture);
std::cout << s << "\n";
std::cout << s.to_smt2() << "\n";
switch (s.check()) {
case unsat: std::cout << "de-Morgan is valid\n"; break;
case sat: std::cout << "de-Morgan is not valid\n"; break;
@ -974,6 +975,30 @@ void substitute_example() {
std::cout << new_f << std::endl;
}
void opt_example() {
context c;
optimize opt(c);
params p(c);
p.set("priority",c.str_symbol("pareto"));
opt.set(p);
expr x = c.int_const("x");
expr y = c.int_const("y");
opt.add(10 >= x && x >= 0);
opt.add(10 >= y && y >= 0);
opt.add(x + y <= 11);
optimize::handle h1 = opt.maximize(x);
optimize::handle h2 = opt.maximize(y);
check_result r = sat;
while (true) {
if (sat == opt.check()) {
std::cout << x << ": " << opt.lower(h1) << " " << y << ": " << opt.lower(h2) << "\n";
}
else {
break;
}
}
}
int main() {
try {
demorgan(); std::cout << "\n";
@ -1012,6 +1037,7 @@ int main() {
expr_vector_example(); std::cout << "\n";
exists_expr_vector_example(); std::cout << "\n";
substitute_example(); std::cout << "\n";
opt_example(); std::cout << "\n";
std::cout << "done\n";
}
catch (exception & ex) {

View file

@ -759,7 +759,7 @@ namespace test_mapi
foreach (BoolExpr a in g.Formulas)
solver.Assert(a);
if (solver.Check() != Status.SATISFIABLE)
if (solver.Check() != Status.SATISFIABLE)
throw new TestFailedException();
ApplyResult ar = ApplyTactic(ctx, ctx.MkTactic("simplify"), g);

20
examples/msf/README Normal file
View file

@ -0,0 +1,20 @@
In order to use Z3 MSF plugin, follow the following steps:
1. Compile latest Z3 .NET API (from any branch consisting of opt features) and copy 'libz3.dll' and 'Microsoft.Z3.dll' to the folder of 'Z3MSFPlugin.sln'.
2. Retrieve 'Microsoft.Solver.Foundation.dll' from http://archive.msdn.microsoft.com/solverfoundation/Release/ProjectReleases.aspx?ReleaseId=1799,
preferably using DLL only version. Copy 'Microsoft.Solver.Foundation.dll' to the folder of 'Z3MSFPlugin.sln'
3. Build 'Z3MSFPlugin.sln'. Note that you have to compile using x86 target for Microsoft.Z3.dll 32-bit and x64 target for Microsoft.Z3.dll 64-bit.
The solution consists of a plugin project, a test project with a few simple test cases and a command line projects for external OML, MPS and SMPS models.
To retrieve SMT2 models which are native to Z3, set the logging file in corresponding directives or solver params e.g.
var p = new Z3MILPParams();
p.SMT2LogFile = "model.smt2";
For more details, check out the commands in 'Validator\Program.cs'.
Enjoy!

View file

@ -0,0 +1,60 @@
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="MsfConfig"
type="Microsoft.SolverFoundation.Services.MsfConfigSection, Microsoft.Solver.Foundation"
allowLocation="true"
allowDefinition="Everywhere"
allowExeDefinition="MachineToApplication"
restartOnExternalChanges="true"
requirePermission="true"/>
</configSections>
<MsfConfig>
<MsfPluginSolvers>
<MsfPluginSolver name="Microsoft Z3 MILP Solver"
capability="MILP"
assembly="SolverFoundation.Plugin.Z3.dll"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPParams"/>
<MsfPluginSolver name="Microsoft Z3 MILP Solver"
capability="LP"
assembly="SolverFoundation.Plugin.Z3.dll"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="MILP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="LP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="MINLP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="NLP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
</MsfPluginSolvers>
</MsfConfig>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>

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.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SolverFoundation.Plugin.Z3.Tests")]
[assembly: AssemblyCopyright("Copyright © 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("27657eee-ca7b-4996-a905-86a3f4584988")]
// 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,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SolverFoundation.Common;
using Microsoft.SolverFoundation.Solvers;
using Microsoft.SolverFoundation.Services;
using Microsoft.SolverFoundation.Plugin.Z3;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.SolverFoundation.Plugin.Z3.Tests
{
[TestClass]
public class ServiceTests
{
[TestInitialize]
public void SetUp()
{
SolverContext context = SolverContext.GetContext();
context.ClearModel();
}
private void TestService1(Directive directive)
{
SolverContext context = SolverContext.GetContext();
Model model = context.CreateModel();
Decision x1 = new Decision(Domain.RealRange(0, 2), "x1");
Decision x2 = new Decision(Domain.RealRange(0, 2), "x2");
Decision z = new Decision(Domain.IntegerRange(0, 1), "z");
model.AddDecisions(x1, x2, z);
model.AddConstraint("Row0", x1 - z <= 1);
model.AddConstraint("Row1", x2 + z <= 2);
Goal goal = model.AddGoal("Goal0", GoalKind.Maximize, x1 + x2);
Solution solution = context.Solve(directive);
Assert.IsTrue(goal.ToInt32() == 3);
context.ClearModel();
}
private void TestService2(Directive directive)
{
SolverContext context = SolverContext.GetContext();
Model model = context.CreateModel();
Decision x1 = new Decision(Domain.RealNonnegative, "x1");
Decision x2 = new Decision(Domain.RealNonnegative, "x2");
Decision z = new Decision(Domain.IntegerRange(0, 1), "z");
Rational M = 100;
model.AddDecisions(x1, x2, z);
model.AddConstraint("Row0", x1 + x2 >= 1);
model.AddConstraint("Row1", x1 - z * 100 <= 0);
model.AddConstraint("Row2", x2 + z * 100 <= 100);
Goal goal = model.AddGoal("Goal0", GoalKind.Maximize, x1 + x2);
Solution solution = context.Solve(directive);
Assert.IsTrue(goal.ToInt32() == 100);
context.ClearModel();
}
[TestMethod]
public void TestService1()
{
TestService1(new Z3MILPDirective());
TestService1(new Z3TermDirective());
}
[TestMethod]
public void TestService2()
{
TestService2(new Z3MILPDirective());
TestService2(new Z3TermDirective());
}
}
}

View file

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{280AEE2F-1FDB-4A27-BE37-14DC154C873B}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.SolverFoundation.Plugin.Z3.Tests</RootNamespace>
<AssemblyName>SolverFoundation.Plugin.Z3.Tests</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<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>
<PlatformTarget>x86</PlatformTarget>
</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>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Solver.Foundation">
<HintPath>..\Microsoft.Solver.Foundation.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ServiceTests.cs" />
<Compile Include="SolverTests.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SolverFoundation.Plugin.Z3\SolverFoundation.Plugin.Z3.csproj">
<Project>{7340e664-f648-4ff7-89b2-f4da424996d3}</Project>
<Name>SolverFoundation.Plugin.Z3</Name>
</ProjectReference>
</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,132 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SolverFoundation.Common;
using Microsoft.SolverFoundation.Solvers;
using Microsoft.SolverFoundation.Services;
using Microsoft.SolverFoundation.Plugin.Z3;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Microsoft.SolverFoundation.Plugin.Z3.Tests
{
[TestClass]
public class SolverTests
{
[TestMethod]
public void TestMILPSolver1()
{
var solver = new Z3MILPSolver();
int goal;
solver.AddRow("goal", out goal);
int x1, x2, z;
// 0 <= x1 <= 2
solver.AddVariable("x1", out x1);
solver.SetBounds(x1, 0, 2);
// 0 <= x2 <= 2
solver.AddVariable("x2", out x2);
solver.SetBounds(x2, 0, 2);
// z is an integer in [0,1]
solver.AddVariable("z", out z);
solver.SetIntegrality(z, true);
solver.SetBounds(z, 0, 1);
//max x1 + x2
solver.SetCoefficient(goal, x1, 1);
solver.SetCoefficient(goal, x2, 1);
solver.AddGoal(goal, 1, false);
// 0 <= x1 -z <= 1
int row1;
solver.AddRow("rowI1", out row1);
solver.SetBounds(row1, 0, 1);
solver.SetCoefficient(row1, x1, 1);
solver.SetCoefficient(row1, z, -1);
// 0 <= x2 + z <= 2
int row2;
solver.AddRow("rowI2", out row2);
solver.SetBounds(row2, 0, 2);
solver.SetCoefficient(row2, x2, 1);
solver.SetCoefficient(row2, z, 1);
var p = new Z3MILPParams();
solver.Solve(p);
Assert.IsTrue(solver.Result == LinearResult.Optimal);
Assert.AreEqual(solver.GetValue(x1), 2 * Rational.One);
Assert.AreEqual(solver.GetValue(x2), Rational.One);
Assert.AreEqual(solver.GetValue(z), Rational.One);
Assert.AreEqual(solver.GetValue(goal), 3 * Rational.One);
}
[TestMethod]
public void TestMILPSolver2()
{
var solver = new Z3MILPSolver();
int goal, extraGoal;
Rational M = 100;
solver.AddRow("goal", out goal);
int x1, x2, z;
// 0 <= x1 <= 100
solver.AddVariable("x1", out x1);
solver.SetBounds(x1, 0, M);
// 0 <= x2 <= 100
solver.AddVariable("x2", out x2);
solver.SetBounds(x2, 0, M);
// z is an integer in [0,1]
solver.AddVariable("z", out z);
solver.SetIntegrality(z, true);
solver.SetBounds(z, 0, 1);
solver.SetCoefficient(goal, x1, 1);
solver.SetCoefficient(goal, x2, 2);
solver.AddGoal(goal, 1, false);
solver.AddRow("extraGoal", out extraGoal);
solver.SetCoefficient(extraGoal, x1, 2);
solver.SetCoefficient(extraGoal, x2, 1);
solver.AddGoal(extraGoal, 2, false);
// x1 + x2 >= 1
int row;
solver.AddRow("row", out row);
solver.SetBounds(row, 1, Rational.PositiveInfinity);
solver.SetCoefficient(row, x1, 1);
solver.SetCoefficient(row, x2, 1);
// x1 - M*z <= 0
int row1;
solver.AddRow("rowI1", out row1);
solver.SetBounds(row1, Rational.NegativeInfinity, 0);
solver.SetCoefficient(row1, x1, 1);
solver.SetCoefficient(row1, z, -M);
// x2 - M* (1-z) <= 0
int row2;
solver.AddRow("rowI2", out row2);
solver.SetBounds(row2, Rational.NegativeInfinity, M);
solver.SetCoefficient(row2, x2, 1);
solver.SetCoefficient(row2, z, M);
var p = new Z3MILPParams();
p.OptKind = OptimizationKind.BoundingBox;
solver.Solve(p);
Assert.IsTrue(solver.Result == LinearResult.Optimal);
Assert.AreEqual(solver.GetValue(goal), 200 * Rational.One);
Assert.AreEqual(solver.GetValue(extraGoal), 200 * Rational.One);
}
}
}

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,60 @@
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="MsfConfig"
type="Microsoft.SolverFoundation.Services.MsfConfigSection, Microsoft.Solver.Foundation"
allowLocation="true"
allowDefinition="Everywhere"
allowExeDefinition="MachineToApplication"
restartOnExternalChanges="true"
requirePermission="true"/>
</configSections>
<MsfConfig>
<MsfPluginSolvers>
<MsfPluginSolver name="Microsoft Z3 MILP Solver"
capability="MILP"
assembly="SolverFoundation.Plugin.Z3.dll"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPParams"/>
<MsfPluginSolver name="Microsoft Z3 MILP Solver"
capability="LP"
assembly="SolverFoundation.Plugin.Z3.dll"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="MILP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="LP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="MINLP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="NLP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
</MsfPluginSolvers>
</MsfConfig>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>

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,149 @@
<?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>
<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>
<ErrorReport>prompt</ErrorReport>
</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>
<ErrorReport>prompt</ErrorReport>
</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>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Solver.Foundation">
<HintPath>..\Microsoft.Solver.Foundation.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Z3, Version=4.3.2.0, Culture=neutral, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Microsoft.Z3.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Xml.Linq">
</Reference>
<Reference Include="System.Data.DataSetExtensions">
</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>
<None Include="App.config" />
</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)
{
}
}
}

View file

@ -0,0 +1,60 @@
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="MsfConfig"
type="Microsoft.SolverFoundation.Services.MsfConfigSection, Microsoft.Solver.Foundation"
allowLocation="true"
allowDefinition="Everywhere"
allowExeDefinition="MachineToApplication"
restartOnExternalChanges="true"
requirePermission="true"/>
</configSections>
<MsfConfig>
<MsfPluginSolvers>
<MsfPluginSolver name="Microsoft Z3 MILP Solver"
capability="MILP"
assembly="SolverFoundation.Plugin.Z3.dll"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPParams"/>
<MsfPluginSolver name="Microsoft Z3 MILP Solver"
capability="LP"
assembly="SolverFoundation.Plugin.Z3.dll"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="MILP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="LP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="MINLP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="NLP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
</MsfPluginSolvers>
</MsfConfig>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>

View file

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="MsfConfig"
type="Microsoft.SolverFoundation.Services.MsfConfigSection, Microsoft.Solver.Foundation"
allowLocation="true"
allowDefinition="Everywhere"
allowExeDefinition="MachineToApplication"
restartOnExternalChanges="true"
requirePermission="true" />
</configSections>
<MsfConfig>
<MsfPluginSolvers>
<MsfPluginSolver name="Microsoft Z3 MILP Solver"
capability="MILP"
assembly="SolverFoundation.Plugin.Z3.dll"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPParams"/>
<MsfPluginSolver name="Microsoft Z3 MILP Solver"
capability="LP"
assembly="SolverFoundation.Plugin.Z3.dll"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3MILPParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="MILP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="LP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="MINLP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
<MsfPluginSolver name="Microsoft Z3 Term Solver"
capability="NLP"
assembly="SolverFoundation.Plugin.Z3.dll"
interface="Microsoft.SolverFoundation.Services.ITermSolver"
solverclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermSolver"
directiveclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermDirective"
parameterclass="Microsoft.SolverFoundation.Plugin.Z3.Z3TermParams"/>
</MsfPluginSolvers>
</MsfConfig>
</configuration>

View file

@ -0,0 +1,194 @@
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using Microsoft.SolverFoundation.Common;
using Microsoft.SolverFoundation.Solvers;
using Microsoft.SolverFoundation.Plugin.Z3;
using Microsoft.SolverFoundation.Services;
using System.Text;
namespace Validator
{
class Program
{
static void LoadModel(SolverContext context, string fileName)
{
string ext = Path.GetExtension(fileName).ToLower();
if (ext == ".mps")
{
context.LoadModel(FileFormat.MPS, Path.GetFullPath(fileName));
}
else if (ext == ".smps")
{
context.LoadModel(FileFormat.SMPS, Path.GetFullPath(fileName));
}
else if (ext == ".oml")
{
context.LoadModel(FileFormat.OML, Path.GetFullPath(fileName));
}
else
{
throw new NotSupportedException("This file format hasn't been supported.");
}
}
static void ExecuteZ3(string fileName, Z3BaseDirective directive)
{
SolverContext context = SolverContext.GetContext();
try
{
LoadModel(context, fileName);
Solution solution = context.Solve(directive);
Report report = solution.GetReport();
Console.Write("{0}", report);
}
catch (Exception e)
{
Console.WriteLine("Skipping unsolvable instance in {0} with error message '{1}'.", fileName, e.Message);
}
finally
{
context.ClearModel();
}
}
static void ConvertToSMT2(string fileName, Z3BaseDirective directive)
{
SolverContext context = SolverContext.GetContext();
try
{
LoadModel(context, fileName);
if (context.CurrentModel.Goals.Any())
{
directive.SMT2LogFile = Path.ChangeExtension(fileName, ".smt2");
context.Solve(() => true, directive);
}
}
catch (Exception e)
{
Console.WriteLine("Skipping unconvertable instance in {0} with error message '{1}'.", fileName, e.Message);
}
finally
{
context.ClearModel();
}
}
static void ValidateZ3(string fileName, Z3BaseDirective directive)
{
SolverContext context = SolverContext.GetContext();
try
{
LoadModel(context, fileName);
if (context.CurrentModel.Goals.Any())
{
var msfDirective = (directive is Z3MILPDirective) ? (Directive)new MixedIntegerProgrammingDirective() { TimeLimit = 10000 }
: (Directive)new Directive() { TimeLimit = 10000 };
var sol1 = context.Solve(msfDirective);
Console.WriteLine("Solved the model using MSF.");
Console.Write("{0}", sol1.GetReport());
var expectedGoals = sol1.Goals.Select(x => x.ToDouble());
context.ClearModel();
context.LoadModel(FileFormat.OML, Path.GetFullPath(fileName));
directive.SMT2LogFile = Path.ChangeExtension(fileName, ".smt2");
var sol2 = context.Solve(directive);
//Console.Write("{0}", sol2.GetReport());
var actualGoals = sol2.Goals.Select(x => x.ToDouble());
Console.WriteLine("Solved the model using Z3.");
var goalPairs = expectedGoals.Zip(actualGoals, (expected, actual) => new { expected, actual }).ToArray();
bool validated = goalPairs.All(p => Math.Abs(p.expected - p.actual) <= 0.0001);
if (validated)
{
Console.WriteLine("INFO: Two solvers give approximately the same results.");
}
else
{
Console.Error.WriteLine("ERROR: Discrepancy found between results.");
if (!validated && File.Exists(directive.SMT2LogFile))
{
var sb = new StringBuilder();
for(int i = 0; i < goalPairs.Length; i++)
{
sb.AppendFormat("\n(echo \"Goal {0}: actual |-> {1:0.0000}, expected |-> {2:0.0000}\")",
i + 1, goalPairs[i].actual, goalPairs[i].expected);
}
Console.Error.WriteLine(sb.ToString());
File.AppendAllText(directive.SMT2LogFile, sb.ToString());
}
}
}
else
{
Console.WriteLine("Ignoring this instance without having any goal.");
}
}
catch (Exception e)
{
Console.WriteLine("Skipping unsolvable instance in {0} with error message '{1}'.",
fileName, e.Message);
}
finally
{
context.ClearModel();
}
}
static void Main(string[] args)
{
Z3BaseDirective directive = new Z3MILPDirective();
for (int i = 0; i < args.Length; ++i) {
if (args[i] == "-s" || args[i] == "-solve")
{
ExecuteZ3(args[i + 1], directive);
return;
}
if (args[i] == "-c" || args[i] == "-convert")
{
ConvertToSMT2(args[i + 1], directive);
return;
}
if (args[i] == "-v" || args[i] == "-validate")
{
ValidateZ3(args[i + 1], directive);
return;
}
if (args[i] == "-t" || args[i] == "-term")
{
directive = new Z3TermDirective();
}
}
if (args.Length > 0)
{
ExecuteZ3(args[0], directive);
return;
}
Console.WriteLine(@"
Validator is a simple command line to migrate benchmarks from OML, MPS and SMPS to SMT2 formats.
Commands:
-solve <file_name> : solving the model using Z3
-convert <file_name> : converting the model into SMT2 format
-validate <file_name> : validating by comparing results between Z3 and MSF solvers
-term : change the default Z3 MILP solver to Z3 Term solver
where <file_name> is any file with OML, MPS or SMPS extension.
Examples:
Validator.exe -convert model.mps
Validator.exe -term -solve model.oml
");
}
}
}

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("testSolver")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("testSolver")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2009")]
[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("c03c1084-d119-483f-80fe-c639eae75959")]
// 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,123 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{54835857-129F-44C9-B529-A42158647B36}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Validator</RootNamespace>
<AssemblyName>Validator</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<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>
</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>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
<ErrorReport>prompt</ErrorReport>
</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>MinimumRecommendedRules.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>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Solver.Foundation">
<HintPath>..\Microsoft.Solver.Foundation.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
</Reference>
<Reference Include="System.Xml.Linq">
</Reference>
<Reference Include="System.Data.DataSetExtensions">
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="MicrosoftSolverFoundationForExcel.dll.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SolverFoundation.Plugin.Z3\SolverFoundation.Plugin.Z3.csproj">
<Project>{7340e664-f648-4ff7-89b2-f4da424996d3}</Project>
<Name>SolverFoundation.Plugin.Z3</Name>
</ProjectReference>
</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,125 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SolverFoundation.Plugin.Z3", "SolverFoundation.Plugin.Z3\SolverFoundation.Plugin.Z3.csproj", "{7340E664-F648-4FF7-89B2-F4DA424996D3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SolverFoundation.Plugin.Z3.Tests", "SolverFoundation.Plugin.Z3.Tests\SolverFoundation.Plugin.Z3.Tests.csproj", "{280AEE2F-1FDB-4A27-BE37-14DC154C873B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Validator", "Validator\Validator.csproj", "{54835857-129F-44C9-B529-A42158647B36}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F1E99540-BA5E-46DF-9E29-6146A309CD18}"
ProjectSection(SolutionItems) = preProject
README = README
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
commercial_64|Any CPU = commercial_64|Any CPU
commercial_64|Mixed Platforms = commercial_64|Mixed Platforms
commercial_64|x64 = commercial_64|x64
commercial_64|x86 = commercial_64|x86
commercial|Any CPU = commercial|Any CPU
commercial|Mixed Platforms = commercial|Mixed Platforms
commercial|x64 = commercial|x64
commercial|x86 = commercial|x86
Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|Any CPU.ActiveCfg = commercial_64|Any CPU
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|Any CPU.Build.0 = commercial_64|Any CPU
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|Mixed Platforms.ActiveCfg = commercial_64|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|Mixed Platforms.Build.0 = commercial_64|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|x64.ActiveCfg = commercial_64|Any CPU
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|x86.ActiveCfg = commercial_64|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial_64|x86.Build.0 = commercial_64|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|Any CPU.ActiveCfg = commercial|Any CPU
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|Any CPU.Build.0 = commercial|Any CPU
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|Mixed Platforms.ActiveCfg = commercial|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|Mixed Platforms.Build.0 = commercial|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|x64.ActiveCfg = commercial|Any CPU
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|x86.ActiveCfg = commercial|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.commercial|x86.Build.0 = commercial|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|Mixed Platforms.Build.0 = Debug|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|x64.ActiveCfg = Debug|Any CPU
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|x86.ActiveCfg = Debug|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Debug|x86.Build.0 = Debug|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|Any CPU.Build.0 = Release|Any CPU
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|Mixed Platforms.ActiveCfg = Release|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|Mixed Platforms.Build.0 = Release|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|x64.ActiveCfg = Release|Any CPU
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|x86.ActiveCfg = Release|x86
{7340E664-F648-4FF7-89B2-F4DA424996D3}.Release|x86.Build.0 = Release|x86
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial_64|Any CPU.ActiveCfg = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial_64|Any CPU.Build.0 = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial_64|Mixed Platforms.ActiveCfg = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial_64|Mixed Platforms.Build.0 = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial_64|x64.ActiveCfg = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial_64|x86.ActiveCfg = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial|Any CPU.ActiveCfg = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial|Any CPU.Build.0 = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial|Mixed Platforms.ActiveCfg = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial|Mixed Platforms.Build.0 = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial|x64.ActiveCfg = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.commercial|x86.ActiveCfg = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|x64.ActiveCfg = Debug|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|x86.ActiveCfg = Debug|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Debug|x86.Build.0 = Debug|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|Any CPU.Build.0 = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|x64.ActiveCfg = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|x86.ActiveCfg = Release|Any CPU
{280AEE2F-1FDB-4A27-BE37-14DC154C873B}.Release|x86.Build.0 = Release|Any CPU
{54835857-129F-44C9-B529-A42158647B36}.commercial_64|Any CPU.ActiveCfg = Release|Any CPU
{54835857-129F-44C9-B529-A42158647B36}.commercial_64|Any CPU.Build.0 = Release|Any CPU
{54835857-129F-44C9-B529-A42158647B36}.commercial_64|Mixed Platforms.ActiveCfg = Release|x86
{54835857-129F-44C9-B529-A42158647B36}.commercial_64|Mixed Platforms.Build.0 = Release|x86
{54835857-129F-44C9-B529-A42158647B36}.commercial_64|x64.ActiveCfg = Release|x64
{54835857-129F-44C9-B529-A42158647B36}.commercial_64|x64.Build.0 = Release|x64
{54835857-129F-44C9-B529-A42158647B36}.commercial_64|x86.ActiveCfg = Release|x86
{54835857-129F-44C9-B529-A42158647B36}.commercial_64|x86.Build.0 = Release|x86
{54835857-129F-44C9-B529-A42158647B36}.commercial|Any CPU.ActiveCfg = Release|Any CPU
{54835857-129F-44C9-B529-A42158647B36}.commercial|Any CPU.Build.0 = Release|Any CPU
{54835857-129F-44C9-B529-A42158647B36}.commercial|Mixed Platforms.ActiveCfg = Release|x86
{54835857-129F-44C9-B529-A42158647B36}.commercial|Mixed Platforms.Build.0 = Release|x86
{54835857-129F-44C9-B529-A42158647B36}.commercial|x64.ActiveCfg = Release|x64
{54835857-129F-44C9-B529-A42158647B36}.commercial|x64.Build.0 = Release|x64
{54835857-129F-44C9-B529-A42158647B36}.commercial|x86.ActiveCfg = Release|x86
{54835857-129F-44C9-B529-A42158647B36}.commercial|x86.Build.0 = Release|x86
{54835857-129F-44C9-B529-A42158647B36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{54835857-129F-44C9-B529-A42158647B36}.Debug|Any CPU.Build.0 = Debug|Any CPU
{54835857-129F-44C9-B529-A42158647B36}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{54835857-129F-44C9-B529-A42158647B36}.Debug|Mixed Platforms.Build.0 = Debug|x86
{54835857-129F-44C9-B529-A42158647B36}.Debug|x64.ActiveCfg = Debug|x64
{54835857-129F-44C9-B529-A42158647B36}.Debug|x64.Build.0 = Debug|x64
{54835857-129F-44C9-B529-A42158647B36}.Debug|x86.ActiveCfg = Debug|x86
{54835857-129F-44C9-B529-A42158647B36}.Debug|x86.Build.0 = Debug|x86
{54835857-129F-44C9-B529-A42158647B36}.Release|Any CPU.ActiveCfg = Release|Any CPU
{54835857-129F-44C9-B529-A42158647B36}.Release|Any CPU.Build.0 = Release|Any CPU
{54835857-129F-44C9-B529-A42158647B36}.Release|Mixed Platforms.ActiveCfg = Release|x86
{54835857-129F-44C9-B529-A42158647B36}.Release|Mixed Platforms.Build.0 = Release|x86
{54835857-129F-44C9-B529-A42158647B36}.Release|x64.ActiveCfg = Release|x64
{54835857-129F-44C9-B529-A42158647B36}.Release|x64.Build.0 = Release|x64
{54835857-129F-44C9-B529-A42158647B36}.Release|x86.ActiveCfg = Release|x86
{54835857-129F-44C9-B529-A42158647B36}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -9,12 +9,13 @@ from mk_util import *
# Z3 Project definition
def init_project_def():
set_version(4, 3, 2, 0)
set_version(4, 3, 3, 0)
add_lib('util', [])
add_lib('polynomial', ['util'], 'math/polynomial')
add_lib('sat', ['util'])
add_lib('nlsat', ['polynomial', 'sat'])
add_lib('hilbert', ['util'], 'math/hilbert')
add_lib('simplex', ['util'], 'math/simplex')
add_lib('interval', ['util'], 'math/interval')
add_lib('realclosure', ['interval'], 'math/realclosure')
add_lib('subpaving', ['interval'], 'math/subpaving')
@ -49,7 +50,7 @@ def init_project_def():
add_lib('smt_params', ['ast', 'simplifier', 'pattern', 'bit_blaster'], 'smt/params')
add_lib('proto_model', ['model', 'simplifier', 'smt_params'], 'smt/proto_model')
add_lib('smt', ['bit_blaster', 'macros', 'normal_forms', 'cmd_context', 'proto_model',
'substitution', 'grobner', 'euclid', 'proof_checker', 'pattern', 'parser_util', 'fpa'])
'substitution', 'grobner', 'euclid', 'simplex', 'proof_checker', 'pattern', 'parser_util', 'fpa'])
add_lib('user_plugin', ['smt'], 'smt/user_plugin')
add_lib('bv_tactics', ['tactic', 'bit_blaster'], 'tactic/bv')
add_lib('fuzzing', ['ast'], 'test/fuzzing')
@ -61,25 +62,27 @@ def init_project_def():
add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe'], 'muz/base')
add_lib('transforms', ['muz', 'hilbert'], 'muz/transforms')
add_lib('rel', ['muz', 'transforms'], 'muz/rel')
add_lib('pdr', ['muz', 'transforms', 'arith_tactics', 'smt_tactic'], 'muz/pdr')
add_lib('pdr', ['muz', 'transforms', 'arith_tactics', 'core_tactics', 'smt_tactic'], 'muz/pdr')
add_lib('clp', ['muz', 'transforms'], 'muz/clp')
add_lib('tab', ['muz', 'transforms'], 'muz/tab')
add_lib('bmc', ['muz', 'transforms'], 'muz/bmc')
add_lib('ddnf', ['muz', 'transforms', 'rel'], 'muz/ddnf')
add_lib('duality_intf', ['muz', 'transforms', 'duality'], 'muz/duality')
add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'duality_intf'], 'muz/fp')
add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'duality_intf', 'ddnf'], 'muz/fp')
add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe'], 'tactic/smtlogics')
add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv')
add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa_tactics', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio')
add_lib('smtparser', ['portfolio'], 'parsers/smt')
add_lib('opt', ['smt', 'smtlogic_tactics', 'sls_tactic'], 'opt')
# add_dll('foci2', ['util'], 'interp/foci2stub',
# dll_name='foci2',
# export_files=['foci2stub.cpp'])
# add_lib('interp', ['solver','foci2'])
API_files = ['z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_interp.h']
add_lib('api', ['portfolio', 'user_plugin', 'smtparser', 'realclosure', 'interp'],
add_lib('api', ['portfolio', 'user_plugin', 'smtparser', 'realclosure', 'interp', 'opt'],
includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files)
add_exe('shell', ['api', 'sat', 'extra_cmds'], exe_name='z3')
add_exe('test', ['api', 'fuzzing'], exe_name='test-z3', install=False)
add_exe('shell', ['api', 'sat', 'extra_cmds','opt'], exe_name='z3')
add_exe('test', ['api', 'fuzzing', 'simplex'], exe_name='test-z3', install=False)
add_dll('api_dll', ['api', 'sat', 'extra_cmds'], 'api/dll',
reexports=['api'],
dll_name='libz3',

View file

@ -979,6 +979,11 @@ def def_API(name, result, params):
log_c.write(" }\n")
log_c.write(" Au(a%s);\n" % sz)
exe_c.write("in.get_uint_array(%s)" % i)
elif ty == INT:
log_c.write("U(a%s[i]);" % i)
log_c.write(" }\n")
log_c.write(" Au(a%s);\n" % sz)
exe_c.write("in.get_int_array(%s)" % i)
else:
error ("unsupported parameter for %s, %s" % (ty, name, p))
elif kind == OUT_ARRAY:

View file

@ -24,6 +24,7 @@ Revision History:
#include"bv_decl_plugin.h"
#include"datatype_decl_plugin.h"
#include"array_decl_plugin.h"
#include"pb_decl_plugin.h"
#include"ast_translation.h"
#include"ast_pp.h"
#include"ast_ll_pp.h"
@ -1075,7 +1076,6 @@ extern "C" {
case OP_BSREM_I:
case OP_BUREM_I:
case OP_BSMOD_I:
return Z3_OP_UNINTERPRETED;
default:
UNREACHABLE();
@ -1084,9 +1084,10 @@ extern "C" {
}
if (mk_c(c)->get_dt_fid() == _d->get_family_id()) {
switch(_d->get_decl_kind()) {
case OP_DT_CONSTRUCTOR: return Z3_OP_DT_CONSTRUCTOR;
case OP_DT_RECOGNISER: return Z3_OP_DT_RECOGNISER;
case OP_DT_ACCESSOR: return Z3_OP_DT_ACCESSOR;
case OP_DT_CONSTRUCTOR: return Z3_OP_DT_CONSTRUCTOR;
case OP_DT_RECOGNISER: return Z3_OP_DT_RECOGNISER;
case OP_DT_ACCESSOR: return Z3_OP_DT_ACCESSOR;
case OP_DT_UPDATE_FIELD: return Z3_OP_DT_UPDATE_FIELD;
default:
UNREACHABLE();
return Z3_OP_UNINTERPRETED;
@ -1124,6 +1125,15 @@ extern "C" {
}
}
if (mk_c(c)->get_pb_fid() == _d->get_family_id()) {
switch(_d->get_decl_kind()) {
case OP_PB_LE: return Z3_OP_PB_LE;
case OP_PB_GE: return Z3_OP_PB_GE;
case OP_AT_MOST_K: return Z3_OP_PB_AT_MOST;
default: UNREACHABLE();
}
}
return Z3_OP_UNINTERPRETED;
Z3_CATCH_RETURN(Z3_OP_UNINTERPRETED);
}

View file

@ -37,9 +37,7 @@ extern "C" {
catch (z3_exception & ex) {
// The error handler is only available for contexts
// Just throw a warning.
std::ostringstream buffer;
buffer << "Error setting " << param_id << ", " << ex.msg();
warning_msg(buffer.str().c_str());
warning_msg(ex.msg());
}
}
@ -64,9 +62,7 @@ extern "C" {
catch (z3_exception & ex) {
// The error handler is only available for contexts
// Just throw a warning.
std::ostringstream buffer;
buffer << "Error setting " << param_id << ": " << ex.msg();
warning_msg(buffer.str().c_str());
warning_msg(ex.msg());
return Z3_FALSE;
}
}
@ -92,9 +88,7 @@ extern "C" {
catch (z3_exception & ex) {
// The error handler is only available for contexts
// Just throw a warning.
std::ostringstream buffer;
buffer << "Error setting " << param_id << ": " << ex.msg();
warning_msg(buffer.str().c_str());
warning_msg(ex.msg());
}
}

View file

@ -109,6 +109,7 @@ namespace api {
m_basic_fid = m().get_basic_family_id();
m_arith_fid = m().mk_family_id("arith");
m_bv_fid = m().mk_family_id("bv");
m_pb_fid = m().mk_family_id("pb");
m_array_fid = m().mk_family_id("array");
m_dt_fid = m().mk_family_id("datatype");
m_datalog_fid = m().mk_family_id("datalog_relation");

View file

@ -75,6 +75,7 @@ namespace api {
family_id m_bv_fid;
family_id m_dt_fid;
family_id m_datalog_fid;
family_id m_pb_fid;
datatype_decl_plugin * m_dt_plugin;
std::string m_string_buffer; // temporary buffer used to cache strings sent to the "external" world.
@ -121,6 +122,7 @@ namespace api {
family_id get_bv_fid() const { return m_bv_fid; }
family_id get_dt_fid() const { return m_dt_fid; }
family_id get_datalog_fid() const { return m_datalog_fid; }
family_id get_pb_fid() const { return m_pb_fid; }
datatype_decl_plugin * get_dt_plugin() const { return m_dt_plugin; }
Z3_error_code get_error_code() const { return m_error_code; }

View file

@ -125,7 +125,7 @@ namespace api {
return "unknown";
}
}
std::string to_string(unsigned num_queries, expr*const* queries) {
std::string to_string(unsigned num_queries, expr* const* queries) {
std::stringstream str;
m_context.display_smt2(num_queries, queries, str);
return str.str();
@ -466,13 +466,16 @@ extern "C" {
ast_manager& m = mk_c(c)->m();
Z3_ast_vector_ref* v = alloc(Z3_ast_vector_ref, m);
mk_c(c)->save_object(v);
expr_ref_vector rules(m);
expr_ref_vector rules(m), queries(m);
svector<symbol> names;
to_fixedpoint_ref(d)->ctx().get_rules_as_formulas(rules, names);
to_fixedpoint_ref(d)->ctx().get_rules_as_formulas(rules, queries, names);
for (unsigned i = 0; i < rules.size(); ++i) {
v->m_ast_vector.push_back(rules[i].get());
}
for (unsigned i = 0; i < queries.size(); ++i) {
v->m_ast_vector.push_back(m.mk_not(queries[i].get()));
}
RETURN_Z3(of_ast_vector(v));
Z3_CATCH_RETURN(0);
}

View file

@ -618,4 +618,25 @@ extern "C" {
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_datatype_update_field(
__in Z3_context c, __in Z3_func_decl f, __in Z3_ast t, __in Z3_ast v) {
Z3_TRY;
LOG_Z3_datatype_update_field(c, f, t, v);
RESET_ERROR_CODE();
ast_manager & m = mk_c(c)->m();
func_decl* _f = to_func_decl(f);
expr* _t = to_expr(t);
expr* _v = to_expr(v);
expr* args[2] = { _t, _v };
sort* domain[2] = { m.get_sort(_t), m.get_sort(_v) };
parameter param(_f);
func_decl * d = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_DT_UPDATE_FIELD, 1, &param, 2, domain);
app* r = m.mk_app(d, 2, args);
mk_c(c)->save_ast_trail(r);
check_sorts(c, r);
RETURN_Z3(of_ast(r));
Z3_CATCH_RETURN(0);
}
};

243
src/api/api_opt.cpp Normal file
View file

@ -0,0 +1,243 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
api_opt.cpp
Abstract:
API for optimization
Author:
Nikolaj Bjorner (nbjorner) 2013-12-3.
Revision History:
--*/
#include<iostream>
#include"z3.h"
#include"api_log_macros.h"
#include"api_stats.h"
#include"api_context.h"
#include"api_util.h"
#include"api_model.h"
#include"opt_context.h"
#include"cancel_eh.h"
#include"scoped_timer.h"
extern "C" {
struct Z3_optimize_ref : public api::object {
opt::context* m_opt;
Z3_optimize_ref():m_opt(0) {}
virtual ~Z3_optimize_ref() { dealloc(m_opt); }
};
inline Z3_optimize_ref * to_optimize(Z3_optimize o) { return reinterpret_cast<Z3_optimize_ref *>(o); }
inline Z3_optimize of_optimize(Z3_optimize_ref * o) { return reinterpret_cast<Z3_optimize>(o); }
inline opt::context* to_optimize_ptr(Z3_optimize o) { return to_optimize(o)->m_opt; }
Z3_optimize Z3_API Z3_mk_optimize(Z3_context c) {
Z3_TRY;
LOG_Z3_mk_optimize(c);
RESET_ERROR_CODE();
Z3_optimize_ref * o = alloc(Z3_optimize_ref);
o->m_opt = alloc(opt::context,mk_c(c)->m());
mk_c(c)->save_object(o);
RETURN_Z3(of_optimize(o));
Z3_CATCH_RETURN(0);
}
void Z3_API Z3_optimize_inc_ref(Z3_context c, Z3_optimize o) {
Z3_TRY;
LOG_Z3_optimize_inc_ref(c, o);
RESET_ERROR_CODE();
to_optimize(o)->inc_ref();
Z3_CATCH;
}
void Z3_API Z3_optimize_dec_ref(Z3_context c, Z3_optimize o) {
Z3_TRY;
LOG_Z3_optimize_dec_ref(c, o);
RESET_ERROR_CODE();
to_optimize(o)->dec_ref();
Z3_CATCH;
}
void Z3_API Z3_optimize_assert(Z3_context c, Z3_optimize o, Z3_ast a) {
Z3_TRY;
LOG_Z3_optimize_assert(c, o, a);
RESET_ERROR_CODE();
CHECK_FORMULA(a,);
to_optimize_ptr(o)->add_hard_constraint(to_expr(a));
Z3_CATCH;
}
unsigned Z3_API Z3_optimize_assert_soft(Z3_context c, Z3_optimize o, Z3_ast a, Z3_string weight, Z3_symbol id) {
Z3_TRY;
LOG_Z3_optimize_assert_soft(c, o, a, weight, id);
RESET_ERROR_CODE();
CHECK_FORMULA(a,0);
rational w(weight);
return to_optimize_ptr(o)->add_soft_constraint(to_expr(a), w, to_symbol(id));
Z3_CATCH_RETURN(0);
}
unsigned Z3_API Z3_optimize_maximize(Z3_context c, Z3_optimize o, Z3_ast t) {
Z3_TRY;
LOG_Z3_optimize_maximize(c, o, t);
RESET_ERROR_CODE();
CHECK_VALID_AST(t,0);
return to_optimize_ptr(o)->add_objective(to_app(t), true);
Z3_CATCH_RETURN(0);
}
unsigned Z3_API Z3_optimize_minimize(Z3_context c, Z3_optimize o, Z3_ast t) {
Z3_TRY;
LOG_Z3_optimize_minimize(c, o, t);
RESET_ERROR_CODE();
CHECK_VALID_AST(t,0);
return to_optimize_ptr(o)->add_objective(to_app(t), false);
Z3_CATCH_RETURN(0);
}
void Z3_API Z3_optimize_push(Z3_context c,Z3_optimize d) {
Z3_TRY;
LOG_Z3_optimize_push(c, d);
RESET_ERROR_CODE();
to_optimize_ptr(d)->push();
Z3_CATCH;
}
void Z3_API Z3_optimize_pop(Z3_context c,Z3_optimize d) {
Z3_TRY;
LOG_Z3_optimize_pop(c, d);
RESET_ERROR_CODE();
to_optimize_ptr(d)->pop(1);
Z3_CATCH;
}
Z3_lbool Z3_API Z3_optimize_check(Z3_context c, Z3_optimize o) {
Z3_TRY;
LOG_Z3_optimize_check(c, o);
RESET_ERROR_CODE();
lbool r = l_undef;
cancel_eh<opt::context> eh(*to_optimize_ptr(o));
unsigned timeout = to_optimize_ptr(o)->get_params().get_uint("timeout", mk_c(c)->get_timeout());
api::context::set_interruptable si(*(mk_c(c)), eh);
{
scoped_timer timer(timeout, &eh);
try {
r = to_optimize_ptr(o)->optimize();
}
catch (z3_exception& ex) {
mk_c(c)->handle_exception(ex);
r = l_undef;
}
// to_optimize_ref(d).cleanup();
}
return of_lbool(r);
Z3_CATCH_RETURN(Z3_L_UNDEF);
}
Z3_model Z3_API Z3_optimize_get_model(Z3_context c, Z3_optimize o) {
Z3_TRY;
LOG_Z3_optimize_get_model(c, o);
RESET_ERROR_CODE();
model_ref _m;
to_optimize_ptr(o)->get_model(_m);
Z3_model_ref * m_ref = alloc(Z3_model_ref);
if (_m) {
m_ref->m_model = _m;
}
else {
m_ref->m_model = alloc(model, mk_c(c)->m());
}
mk_c(c)->save_object(m_ref);
RETURN_Z3(of_model(m_ref));
Z3_CATCH_RETURN(0);
}
void Z3_API Z3_optimize_set_params(Z3_context c, Z3_optimize o, Z3_params p) {
Z3_TRY;
LOG_Z3_optimize_set_params(c, o, p);
RESET_ERROR_CODE();
param_descrs descrs;
to_optimize_ptr(o)->collect_param_descrs(descrs);
to_params(p)->m_params.validate(descrs);
params_ref pr = to_param_ref(p);
to_optimize_ptr(o)->updt_params(pr);
Z3_CATCH;
}
Z3_param_descrs Z3_API Z3_optimize_get_param_descrs(Z3_context c, Z3_optimize o) {
Z3_TRY;
LOG_Z3_optimize_get_param_descrs(c, o);
RESET_ERROR_CODE();
Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref);
mk_c(c)->save_object(d);
to_optimize_ptr(o)->collect_param_descrs(d->m_descrs);
Z3_param_descrs r = of_param_descrs(d);
RETURN_Z3(r);
Z3_CATCH_RETURN(0);
}
// get lower value or current approximation
Z3_ast Z3_API Z3_optimize_get_lower(Z3_context c, Z3_optimize o, unsigned idx) {
Z3_TRY;
LOG_Z3_optimize_get_lower(c, o, idx);
RESET_ERROR_CODE();
expr_ref e = to_optimize_ptr(o)->get_lower(idx);
mk_c(c)->save_ast_trail(e);
RETURN_Z3(of_expr(e));
Z3_CATCH_RETURN(0);
}
// get upper or current approximation
Z3_ast Z3_API Z3_optimize_get_upper(Z3_context c, Z3_optimize o, unsigned idx) {
Z3_TRY;
LOG_Z3_optimize_get_upper(c, o, idx);
RESET_ERROR_CODE();
expr_ref e = to_optimize_ptr(o)->get_upper(idx);
mk_c(c)->save_ast_trail(e);
RETURN_Z3(of_expr(e));
Z3_CATCH_RETURN(0);
}
Z3_string Z3_API Z3_optimize_to_string(Z3_context c, Z3_optimize o) {
Z3_TRY;
LOG_Z3_optimize_to_string(c, o);
RESET_ERROR_CODE();
return mk_c(c)->mk_external_string(to_optimize_ptr(o)->to_string());
Z3_CATCH_RETURN("");
}
Z3_string Z3_API Z3_optimize_get_help(Z3_context c, Z3_optimize d) {
Z3_TRY;
LOG_Z3_optimize_get_help(c, d);
RESET_ERROR_CODE();
std::ostringstream buffer;
param_descrs descrs;
to_optimize_ptr(d)->collect_param_descrs(descrs);
descrs.display(buffer);
return mk_c(c)->mk_external_string(buffer.str());
Z3_CATCH_RETURN("");
}
Z3_stats Z3_API Z3_optimize_get_statistics(Z3_context c,Z3_optimize d) {
Z3_TRY;
LOG_Z3_optimize_get_statistics(c, d);
RESET_ERROR_CODE();
Z3_stats_ref * st = alloc(Z3_stats_ref);
to_optimize_ptr(d)->collect_statistics(st->m_stats);
mk_c(c)->save_object(st);
Z3_stats r = of_stats(st);
RETURN_Z3(r);
Z3_CATCH_RETURN(0);
}
};

61
src/api/api_pb.cpp Normal file
View file

@ -0,0 +1,61 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
api_pb.cpp
Abstract:
API for pb theory
Author:
Nikolaj Bjorner (nbjorner) 2013-11-13.
Revision History:
--*/
#include<iostream>
#include"z3.h"
#include"api_log_macros.h"
#include"api_context.h"
#include"api_util.h"
#include"pb_decl_plugin.h"
extern "C" {
Z3_ast Z3_API Z3_mk_atmost(Z3_context c, unsigned num_args,
Z3_ast const args[], unsigned k) {
Z3_TRY;
LOG_Z3_mk_atmost(c, num_args, args, k);
RESET_ERROR_CODE();
parameter param(k);
pb_util util(mk_c(c)->m());
ast* a = util.mk_at_most_k(num_args, to_exprs(args), k);
mk_c(c)->save_ast_trail(a);
check_sorts(c, a);
RETURN_Z3(of_ast(a));
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_mk_pble(Z3_context c, unsigned num_args,
Z3_ast const args[], int _coeffs[],
int k) {
Z3_TRY;
LOG_Z3_mk_pble(c, num_args, args, _coeffs, k);
RESET_ERROR_CODE();
pb_util util(mk_c(c)->m());
vector<rational> coeffs;
for (unsigned i = 0; i < num_args; ++i) {
coeffs.push_back(rational(_coeffs[i]));
}
ast* a = util.mk_le(num_args, coeffs.c_ptr(), to_exprs(args), rational(k));
mk_c(c)->save_ast_trail(a);
check_sorts(c, a);
RETURN_Z3(of_ast(a));
Z3_CATCH_RETURN(0);
}
};

View file

@ -1314,6 +1314,26 @@ namespace z3 {
expr_vector assertions() const { Z3_ast_vector r = Z3_solver_get_assertions(ctx(), m_solver); check_error(); return expr_vector(ctx(), r); }
expr proof() const { Z3_ast r = Z3_solver_get_proof(ctx(), m_solver); check_error(); return expr(ctx(), r); }
friend std::ostream & operator<<(std::ostream & out, solver const & s) { out << Z3_solver_to_string(s.ctx(), s); return out; }
std::string to_smt2(char const* status = "unknown") {
array<Z3_ast> es(assertions());
Z3_ast const* fmls = es.ptr();
Z3_ast fml = 0;
unsigned sz = es.size();
if (sz > 0) {
--sz;
fml = fmls[sz];
}
else {
fml = ctx().bool_val(true);
}
return std::string(Z3_benchmark_to_smtlib_string(
ctx(),
"", "", status, "",
sz,
fmls,
fml));
}
};
class goal : public object {
@ -1513,6 +1533,62 @@ namespace z3 {
}
};
class optimize : public object {
Z3_optimize m_opt;
public:
class handle {
unsigned m_h;
public:
handle(unsigned h): m_h(h) {}
unsigned h() const { return m_h; }
};
optimize(context& c):object(c) { m_opt = Z3_mk_optimize(c); Z3_optimize_inc_ref(c, m_opt); }
~optimize() { Z3_optimize_dec_ref(ctx(), m_opt); }
operator Z3_optimize() const { return m_opt; }
void add(expr const& e) {
assert(e.is_bool());
Z3_optimize_assert(ctx(), m_opt, e);
}
handle add(expr const& e, unsigned weight) {
assert(e.is_bool());
std::stringstream strm;
strm << weight;
return handle(Z3_optimize_assert_soft(ctx(), m_opt, e, strm.str().c_str(), 0));
}
handle add(expr const& e, char const* weight) {
assert(e.is_bool());
return handle(Z3_optimize_assert_soft(ctx(), m_opt, e, weight, 0));
}
handle maximize(expr const& e) {
return handle(Z3_optimize_maximize(ctx(), m_opt, e));
}
handle minimize(expr const& e) {
return handle(Z3_optimize_minimize(ctx(), m_opt, e));
}
void push() {
Z3_optimize_push(ctx(), m_opt);
}
void pop() {
Z3_optimize_pop(ctx(), m_opt);
}
check_result check() { Z3_lbool r = Z3_optimize_check(ctx(), m_opt); check_error(); return to_check_result(r); }
model get_model() const { Z3_model m = Z3_optimize_get_model(ctx(), m_opt); check_error(); return model(ctx(), m); }
void set(params const & p) { Z3_optimize_set_params(ctx(), m_opt, p); check_error(); }
expr lower(handle const& h) {
Z3_ast r = Z3_optimize_get_lower(ctx(), m_opt, h.h());
check_error();
return expr(ctx(), r);
}
expr upper(handle const& h) {
Z3_ast r = Z3_optimize_get_upper(ctx(), m_opt, h.h());
check_error();
return expr(ctx(), r);
}
stats statistics() const { Z3_stats r = Z3_optimize_get_statistics(ctx(), m_opt); check_error(); return stats(ctx(), r); }
friend std::ostream & operator<<(std::ostream & out, optimize const & s) { out << Z3_optimize_to_string(s.ctx(), s.m_opt); return out; }
std::string help() const { char const * r = Z3_optimize_get_help(ctx(), m_opt); check_error(); return r; }
};
inline tactic fail_if(probe const & p) {
Z3_tactic r = Z3_tactic_fail_if(p.ctx(), p);
p.check_error();

View file

@ -449,6 +449,19 @@ namespace Microsoft.Z3
return MkDatatypeSorts(MkSymbols(names), c);
}
/// <summary>
/// Update a datatype field at expression t with value v.
/// The function performs a record update at t. The field
/// that is passed in as argument is updated with value v,
/// the remainig fields of t are unchanged.
/// </summary>
public Expr MkUpdateField(FuncDecl field, Expr t, Expr v)
{
return Expr.Create(this, Native.Z3_datatype_update_field(
nCtx, field.NativeObject,
t.NativeObject, v.NativeObject));
}
#endregion
#endregion
@ -2251,6 +2264,36 @@ namespace Microsoft.Z3
}
#endregion
#region Pseudo-Boolean constraints
/// <summary>
/// Create an at-most-k constraint.
/// </summary>
public BoolExpr MkAtMost(BoolExpr[] args, uint k)
{
Contract.Requires(args != null);
Contract.Requires(Contract.Result<BoolExpr[]>() != null);
CheckContextMatch(args);
return new BoolExpr(this, Native.Z3_mk_atmost(nCtx, (uint) args.Length,
AST.ArrayToNative(args), k));
}
/// <summary>
/// Create a pseudo-Boolean less-or-equal constraint.
/// </summary>
public BoolExpr MkPBLe(int[] coeffs, BoolExpr[] args, int k)
{
Contract.Requires(args != null);
Contract.Requires(coeffs != null);
Contract.Requires(args.Length == coeffs.Length);
Contract.Requires(Contract.Result<BoolExpr[]>() != null);
CheckContextMatch(args);
return new BoolExpr(this, Native.Z3_mk_pble(nCtx, (uint) args.Length,
AST.ArrayToNative(args),
coeffs, k));
}
#endregion
#region Numerals
#region General Numerals
@ -3438,6 +3481,18 @@ namespace Microsoft.Z3
}
#endregion
#region Optimization
/// <summary>
/// Create an Optimization context.
/// </summary>
public Optimize MkOptimize()
{
Contract.Ensures(Contract.Result<Optimize>() != null);
return new Optimize(this);
}
#endregion
#region Miscellaneous
/// <summary>
@ -3594,6 +3649,7 @@ namespace Microsoft.Z3
Contract.Invariant(m_Statistics_DRQ != null);
Contract.Invariant(m_Tactic_DRQ != null);
Contract.Invariant(m_Fixedpoint_DRQ != null);
Contract.Invariant(m_Optimize_DRQ != null);
}
readonly private AST.DecRefQueue m_AST_DRQ = new AST.DecRefQueue();
@ -3611,6 +3667,7 @@ namespace Microsoft.Z3
readonly private Statistics.DecRefQueue m_Statistics_DRQ = new Statistics.DecRefQueue();
readonly private Tactic.DecRefQueue m_Tactic_DRQ = new Tactic.DecRefQueue();
readonly private Fixedpoint.DecRefQueue m_Fixedpoint_DRQ = new Fixedpoint.DecRefQueue();
readonly private Optimize.DecRefQueue m_Optimize_DRQ = new Optimize.DecRefQueue();
internal AST.DecRefQueue AST_DRQ { get { Contract.Ensures(Contract.Result<AST.DecRefQueue>() != null); return m_AST_DRQ; } }
internal ASTMap.DecRefQueue ASTMap_DRQ { get { Contract.Ensures(Contract.Result<ASTMap.DecRefQueue>() != null); return m_ASTMap_DRQ; } }
@ -3627,6 +3684,7 @@ namespace Microsoft.Z3
internal Statistics.DecRefQueue Statistics_DRQ { get { Contract.Ensures(Contract.Result<Statistics.DecRefQueue>() != null); return m_Statistics_DRQ; } }
internal Tactic.DecRefQueue Tactic_DRQ { get { Contract.Ensures(Contract.Result<Tactic.DecRefQueue>() != null); return m_Tactic_DRQ; } }
internal Fixedpoint.DecRefQueue Fixedpoint_DRQ { get { Contract.Ensures(Contract.Result<Fixedpoint.DecRefQueue>() != null); return m_Fixedpoint_DRQ; } }
internal Optimize.DecRefQueue Optimize_DRQ { get { Contract.Ensures(Contract.Result<Optimize.DecRefQueue>() != null); return m_Optimize_DRQ; } }
internal long refCount = 0;
@ -3670,6 +3728,7 @@ namespace Microsoft.Z3
Statistics_DRQ.Clear(this);
Tactic_DRQ.Clear(this);
Fixedpoint_DRQ.Clear(this);
Optimize_DRQ.Clear(this);
m_boolSort = null;
m_intSort = null;

View file

@ -0,0 +1,111 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
Deprecated.cs
Abstract:
Expose deprecated features for use from the managed API
those who use them for experiments.
Author:
Christoph Wintersteiger (cwinter) 2012-03-15
Notes:
--*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics.Contracts;
namespace Microsoft.Z3
{
/// <summary>
/// The main interaction with Z3 happens via the Context.
/// </summary>
[ContractVerification(true)]
public class Deprecated
{
/// <summary>
/// Creates a backtracking point.
/// </summary>
/// <seealso cref="Pop"/>
public static void Push(Context ctx) {
Native.Z3_push(ctx.nCtx);
}
/// <summary>
/// Backtracks <paramref name="n"/> backtracking points.
/// </summary>
/// <remarks>Note that an exception is thrown if <paramref name="n"/> is not smaller than <c>NumScopes</c></remarks>
/// <seealso cref="Push"/>
public static void Pop(Context ctx, uint n = 1) {
Native.Z3_pop(ctx.nCtx, n);
}
/// <summary>
/// Assert a constraint (or multiple) into the solver.
/// </summary>
public static void Assert(Context ctx, params BoolExpr[] constraints)
{
Contract.Requires(constraints != null);
Contract.Requires(Contract.ForAll(constraints, c => c != null));
ctx.CheckContextMatch(constraints);
foreach (BoolExpr a in constraints)
{
Native.Z3_assert_cnstr(ctx.nCtx, a.NativeObject);
}
}
/// <summary>
/// Checks whether the assertions in the context are consistent or not.
/// </summary>
public static Status Check(Context ctx, List<BoolExpr> core, ref Model model, ref Expr proof, params Expr[] assumptions)
{
Z3_lbool r;
model = null;
proof = null;
if (assumptions == null || assumptions.Length == 0)
r = (Z3_lbool)Native.Z3_check(ctx.nCtx);
else {
IntPtr mdl = IntPtr.Zero, prf = IntPtr.Zero;
uint core_size = 0;
IntPtr[] native_core = new IntPtr[assumptions.Length];
r = (Z3_lbool)Native.Z3_check_assumptions(ctx.nCtx,
(uint)assumptions.Length, AST.ArrayToNative(assumptions),
ref mdl, ref prf, ref core_size, native_core);
for (uint i = 0; i < core_size; i++)
core.Add((BoolExpr)Expr.Create(ctx, native_core[i]));
if (mdl != IntPtr.Zero) {
model = new Model(ctx, mdl);
}
if (prf != IntPtr.Zero) {
proof = Expr.Create(ctx, prf);
}
}
switch (r)
{
case Z3_lbool.Z3_L_TRUE: return Status.SATISFIABLE;
case Z3_lbool.Z3_L_FALSE: return Status.UNSATISFIABLE;
default: return Status.UNKNOWN;
}
}
/// <summary>
/// Retrieves an assignment to atomic propositions for a satisfiable context.
/// </summary>
public static BoolExpr GetAssignment(Context ctx)
{
IntPtr x = Native.Z3_get_context_assignment(ctx.nCtx);
return (BoolExpr)Expr.Create(ctx, x);
}
}
}

View file

@ -304,6 +304,19 @@ namespace Microsoft.Z3
}
/// <summary>
/// Fixedpoint statistics.
/// </summary>
public Statistics Statistics
{
get
{
Contract.Ensures(Contract.Result<Statistics>() != null);
return new Statistics(Context, Native.Z3_fixedpoint_get_statistics(Context.nCtx, NativeObject));
}
}
/// <summary>
/// Parse an SMT-LIB2 file with fixedpoint rules.
/// Add the rules to the current fixedpoint context.
/// Return the set of queries in the file.

View file

@ -19,12 +19,12 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\..\..\..\cwinter\bugs\z3bugs\Debug\</OutputPath>
<OutputPath>..\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>C:\cwinter\bugs\z3bugs\Debug\Microsoft.Z3.XML</DocumentationFile>
<DocumentationFile>..\Debug\Microsoft.Z3.XML</DocumentationFile>
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
@ -254,7 +254,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\..\..\..\..\cwinter\bugs\z3bugs\Debug\</OutputPath>
<OutputPath>..\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
@ -266,7 +266,7 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.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>
<DocumentationFile>C:\cwinter\bugs\z3bugs\Debug\Microsoft.Z3.XML</DocumentationFile>
<DocumentationFile>..\x86\Debug\Microsoft.Z3.XML</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>

296
src/api/dotnet/Optimize.cs Normal file
View file

@ -0,0 +1,296 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
Optimize.cs
Abstract:
Z3 Managed API: Optimizes
Author:
Nikolaj Bjorner (nbjorner) 2013-12-03
Notes:
--*/
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
namespace Microsoft.Z3
{
/// <summary>
/// Object for managing optimizization context
/// </summary>
[ContractVerification(true)]
public class Optimize : Z3Object
{
/// <summary>
/// A string that describes all available optimize solver parameters.
/// </summary>
public string Help
{
get
{
Contract.Ensures(Contract.Result<string>() != null);
return Native.Z3_optimize_get_help(Context.nCtx, NativeObject);
}
}
/// <summary>
/// Sets the optimize solver parameters.
/// </summary>
public Params Parameters
{
set
{
Contract.Requires(value != null);
Context.CheckContextMatch(value);
Native.Z3_optimize_set_params(Context.nCtx, NativeObject, value.NativeObject);
}
}
/// <summary>
/// Retrieves parameter descriptions for Optimize solver.
/// </summary>
public ParamDescrs ParameterDescriptions
{
get { return new ParamDescrs(Context, Native.Z3_optimize_get_param_descrs(Context.nCtx, NativeObject)); }
}
/// <summary>
/// Assert a constraint (or multiple) into the optimize solver.
/// </summary>
public void Assert(params BoolExpr[] constraints)
{
Contract.Requires(constraints != null);
Contract.Requires(Contract.ForAll(constraints, c => c != null));
Context.CheckContextMatch(constraints);
foreach (BoolExpr a in constraints)
{
Native.Z3_optimize_assert(Context.nCtx, NativeObject, a.NativeObject);
}
}
/// <summary>
/// Alias for Assert.
/// </summary>
public void Add(params BoolExpr[] constraints)
{
Assert(constraints);
}
/// <summary>
/// Handle to objectives returned by objective functions.
/// </summary>
public class Handle
{
Optimize opt;
uint handle;
internal Handle(Optimize opt, uint h)
{
this.opt = opt;
this.handle = h;
}
/// <summary>
/// Retrieve a lower bound for the objective handle.
/// </summary>
public ArithExpr Lower
{
get { return opt.GetLower(handle); }
}
/// <summary>
/// Retrieve an upper bound for the objective handle.
/// </summary>
public ArithExpr Upper
{
get { return opt.GetUpper(handle); }
}
/// <summary>
/// Retrieve the value of an objective.
/// </summary>
public ArithExpr Value
{
get { return Lower; }
}
}
/// <summary>
/// Assert soft constraint
/// </summary>
/// <remarks>
/// Return an objective which associates with the group of constraints.
/// </remarks>
public Handle AssertSoft(BoolExpr constraint, uint weight, string group)
{
Context.CheckContextMatch(constraint);
Symbol s = Context.MkSymbol(group);
return new Handle(this, Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject));
}
///
/// <summary>
/// Check satisfiability of asserted constraints.
/// Produce a model that (when the objectives are bounded and
/// don't use strict inequalities) meets the objectives.
/// </summary>
///
public Status Check() {
Z3_lbool r = (Z3_lbool)Native.Z3_optimize_check(Context.nCtx, NativeObject);
switch (r)
{
case Z3_lbool.Z3_L_TRUE:
return Status.SATISFIABLE;
case Z3_lbool.Z3_L_FALSE:
return Status.UNSATISFIABLE;
default:
return Status.UNKNOWN;
}
}
/// <summary>
/// Creates a backtracking point.
/// </summary>
/// <seealso cref="Pop"/>
public void Push()
{
Native.Z3_optimize_push(Context.nCtx, NativeObject);
}
/// <summary>
/// Backtrack one backtracking point.
/// </summary>
/// <remarks>Note that an exception is thrown if Pop is called without a corresponding <c>Push</c></remarks>
/// <seealso cref="Push"/>
public void Pop()
{
Native.Z3_optimize_pop(Context.nCtx, NativeObject);
}
/// <summary>
/// The model of the last <c>Check</c>.
/// </summary>
/// <remarks>
/// The result is <c>null</c> if <c>Check</c> was not invoked before,
/// if its results was not <c>SATISFIABLE</c>, or if model production is not enabled.
/// </remarks>
public Model Model
{
get
{
IntPtr x = Native.Z3_optimize_get_model(Context.nCtx, NativeObject);
if (x == IntPtr.Zero)
return null;
else
return new Model(Context, x);
}
}
/// <summary>
/// Declare an arithmetical maximization objective.
/// Return a handle to the objective. The handle is used as
/// to retrieve the values of objectives after calling Check.
/// </summary>
public Handle MkMaximize(ArithExpr e)
{
return new Handle(this, Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject));
}
/// <summary>
/// Declare an arithmetical minimization objective.
/// Similar to MkMaximize.
/// </summary>
public Handle MkMinimize(ArithExpr e)
{
return new Handle(this, Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject));
}
/// <summary>
/// Retrieve a lower bound for the objective handle.
/// </summary>
private ArithExpr GetLower(uint index)
{
return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index));
}
/// <summary>
/// Retrieve an upper bound for the objective handle.
/// </summary>
private ArithExpr GetUpper(uint index)
{
return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index));
}
/// <summary>
/// Print the context to a string (SMT-LIB parseable benchmark).
/// </summary>
public override string ToString()
{
return Native.Z3_optimize_to_string(Context.nCtx, NativeObject);
}
/// <summary>
/// Optimize statistics.
/// </summary>
public Statistics Statistics
{
get
{
Contract.Ensures(Contract.Result<Statistics>() != null);
return new Statistics(Context, Native.Z3_optimize_get_statistics(Context.nCtx, NativeObject));
}
}
#region Internal
internal Optimize(Context ctx, IntPtr obj)
: base(ctx, obj)
{
Contract.Requires(ctx != null);
}
internal Optimize(Context ctx)
: base(ctx, Native.Z3_mk_optimize(ctx.nCtx))
{
Contract.Requires(ctx != null);
}
internal class DecRefQueue : IDecRefQueue
{
public override void IncRef(Context ctx, IntPtr obj)
{
Native.Z3_optimize_inc_ref(ctx.nCtx, obj);
}
public override void DecRef(Context ctx, IntPtr obj)
{
Native.Z3_optimize_dec_ref(ctx.nCtx, obj);
}
};
internal override void IncRef(IntPtr o)
{
Context.Optimize_DRQ.IncAndClear(Context, o);
base.IncRef(o);
}
internal override void DecRef(IntPtr o)
{
Context.Optimize_DRQ.Add(o);
base.DecRef(o);
}
#endregion
}
}

View file

@ -79,6 +79,7 @@ namespace Microsoft.Z3
Native.Z3_params_set_symbol(Context.nCtx, NativeObject, name.NativeObject, value.NativeObject);
}
/// <summary>
/// Adds a parameter setting.
/// </summary>
@ -118,6 +119,7 @@ namespace Microsoft.Z3
/// </summary>
public void Add(string name, string value)
{
Contract.Requires(name != null);
Contract.Requires(value != null);
Native.Z3_params_set_symbol(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, Context.MkSymbol(value).NativeObject);

View file

@ -0,0 +1,9 @@
The default Z3 bindings for .NET are built for the .NET framework version 4.
Should the need arise, it is also possible to build them for .NET 3.5; the
instructions are as follows:
In the project properties of Microsoft.Z3.csproj:
- Under 'Application': Change Target framework to .NET Framework 3.5
- Under 'Build': Add FRAMEWORK_LT_4 to the condidional compilation symbols
- Remove the reference to System.Numerics
- Install the NuGet Package "Microsoft Code Contracts for Net3.5"

View file

@ -375,6 +375,23 @@ public class Context extends IDisposable
return mkDatatypeSorts(MkSymbols(names), c);
}
/**
* Update a datatype field at expression t with value v.
* The function performs a record update at t. The field
* that is passed in as argument is updated with value v,
* the remainig fields of t are unchanged.
**/
public Expr MkUpdateField(FuncDecl field, Expr t, Expr v)
throws Z3Exception
{
return Expr.create
(this,
Native.datatypeUpdateField
(nCtx(), field.getNativeObject(),
t.getNativeObject(), v.getNativeObject()));
}
/**
* Creates a new function declaration.
**/

View file

@ -319,6 +319,18 @@ public class Fixedpoint extends Z3Object
return res;
}
/**
* Fixedpoint statistics.
*
* @throws Z3Exception
**/
public Statistics getStatistics() throws Z3Exception
{
return new Statistics(getContext(), Native.fixedpointGetStatistics(
getContext().nCtx(), getNativeObject()));
}
Fixedpoint(Context ctx, long obj) throws Z3Exception
{
super(ctx, obj);

View file

@ -298,9 +298,8 @@ class AstRef(Z3PPObject):
return self.ast
def get_id(self):
"""Return unique identifier for object. It can be used for hash-tables and maps."""
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
"""Return unique identifier for object. It can be used for hash-tables and maps."""
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
def ctx_ref(self):
"""Return a reference to the C context where this AST node is stored."""
@ -453,8 +452,7 @@ class SortRef(AstRef):
return Z3_sort_to_ast(self.ctx_ref(), self.ast)
def get_id(self):
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
def kind(self):
"""Return the Z3 internal kind of a sort. This method can be used to test if `self` is one of the Z3 builtin sorts.
@ -555,6 +553,8 @@ def _to_sort_ref(s, ctx):
return ArraySortRef(s, ctx)
elif k == Z3_DATATYPE_SORT:
return DatatypeSortRef(s, ctx)
elif k == Z3_FINITE_DOMAIN_SORT:
return FiniteDomainSortRef(s, ctx)
return SortRef(s, ctx)
def _sort(ctx, a):
@ -595,7 +595,7 @@ class FuncDeclRef(AstRef):
return Z3_func_decl_to_ast(self.ctx_ref(), self.ast)
def get_id(self):
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
def as_func_decl(self):
return self.ast
@ -743,7 +743,7 @@ class ExprRef(AstRef):
return self.ast
def get_id(self):
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
def sort(self):
"""Return the sort of expression `self`.
@ -1540,7 +1540,7 @@ class PatternRef(ExprRef):
return Z3_pattern_to_ast(self.ctx_ref(), self.ast)
def get_id(self):
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
def is_pattern(a):
"""Return `True` if `a` is a Z3 pattern (hint for quantifier instantiation.
@ -1605,7 +1605,7 @@ class QuantifierRef(BoolRef):
return self.ast
def get_id(self):
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
return Z3_get_ast_id(self.ctx_ref(), self.as_ast())
def sort(self):
"""Return the Boolean sort."""
@ -6033,22 +6033,20 @@ class Solver(Z3PPObject):
return Z3_solver_to_string(self.ctx.ref(), self.solver)
def to_smt2(self):
"""return SMTLIB2 formatted benchmark for solver's assertions"""
es = self.assertions()
sz = len(es)
sz1 = sz
if sz1 > 0:
sz1 -= 1
v = (Ast * sz1)()
for i in range(sz1):
v[i] = es[i].as_ast()
if sz > 0:
e = es[sz1].as_ast()
else:
e = BoolVal(True, self.ctx).as_ast()
return Z3_benchmark_to_smtlib_string(self.ctx.ref(), "benchmark generated from python API", "", "unknown", "", sz1, v, e)
"""return SMTLIB2 formatted benchmark for solver's assertions"""
es = self.assertions()
sz = len(es)
sz1 = sz
if sz1 > 0:
sz1 -= 1
v = (Ast * sz1)()
for i in range(sz1):
v[i] = es[i].as_ast()
if sz > 0:
e = es[sz1].as_ast()
else:
e = BoolVal(True, self.ctx).as_ast()
return Z3_benchmark_to_smtlib_string(self.ctx.ref(), "benchmark generated from python API", "", "unknown", "", sz1, v, e)
def SolverFor(logic, ctx=None):
"""Create a solver customized for the given logic.
@ -6166,7 +6164,7 @@ class Fixedpoint(Z3PPObject):
Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, head.as_ast(), name)
else:
body = _get_args(body)
f = self.abstract(Implies(And(body),head))
f = self.abstract(Implies(And(body, self.ctx),head))
Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, f.as_ast(), name)
def rule(self, head, body = None, name = None):
@ -6183,7 +6181,7 @@ class Fixedpoint(Z3PPObject):
"""
query = _get_args(query)
sz = len(query)
if sz >= 1 and isinstance(query[0], FuncDecl):
if sz >= 1 and isinstance(query[0], FuncDeclRef):
_decls = (FuncDecl * sz)()
i = 0
for q in query:
@ -6194,7 +6192,7 @@ class Fixedpoint(Z3PPObject):
if sz == 1:
query = query[0]
else:
query = And(query)
query = And(query, self.ctx)
query = self.abstract(query, False)
r = Z3_fixedpoint_query(self.ctx.ref(), self.fixedpoint, query.as_ast())
return CheckSatResult(r)
@ -6213,7 +6211,7 @@ class Fixedpoint(Z3PPObject):
name = ""
name = to_symbol(name, self.ctx)
body = _get_args(body)
f = self.abstract(Implies(And(body),head))
f = self.abstract(Implies(And(body, self.ctx),head))
Z3_fixedpoint_update_rule(self.ctx.ref(), self.fixedpoint, f.as_ast(), name)
def get_answer(self):
@ -6310,6 +6308,166 @@ class Fixedpoint(Z3PPObject):
else:
return Exists(self.vars, fml)
#########################################
#
# Finite domain sorts
#
#########################################
class FiniteDomainSortRef(SortRef):
"""Finite domain sort."""
def size(self):
"""Return the size of the finite domain sort"""
r = (ctype.c_ulonglong * 1)()
if Z3_get_finite_domain_sort_size(self.ctx_ref(), self.ast(), r):
return r[0]
else:
raise Z3Exception("Failed to retrieve finite domain sort size")
def FiniteDomainSort(name, sz, ctx=None):
"""Create a named finite domain sort of a given size sz"""
ctx = _get_ctx(ctx)
return FiniteDomainSortRef(Z3_mk_finite_domain_sort(ctx.ref(), name, sz), ctx)
#########################################
#
# Optimize
#
#########################################
class OptimizeObjective:
def __init__(self, opt, value, is_max):
self._opt = opt
self._value = value
self._is_max = is_max
def lower(self):
opt = self._opt
return _to_expr_ref(Z3_optimize_get_lower(opt.ctx.ref(), opt.optimize, self._value), opt.ctx)
def upper(self):
opt = self._opt
return _to_expr_ref(Z3_optimize_get_upper(opt.ctx.ref(), opt.optimize, self._value), opt.ctx)
def value(self):
if self._is_max:
return self.upper()
else:
return self.lower()
class Optimize(Z3PPObject):
"""Optimize API provides methods for solving using objective functions and weighted soft constraints"""
def __init__(self, ctx=None):
self.ctx = _get_ctx(ctx)
self.optimize = Z3_mk_optimize(self.ctx.ref())
Z3_optimize_inc_ref(self.ctx.ref(), self.optimize)
def __del__(self):
if self.optimize != None:
Z3_optimize_dec_ref(self.ctx.ref(), self.optimize)
def set(self, *args, **keys):
"""Set a configuration option. The method `help()` return a string containing all available options.
"""
p = args2params(args, keys, self.ctx)
Z3_optimize_set_params(self.ctx.ref(), self.optimize, p.params)
def help(self):
"""Display a string describing all available options."""
print(Z3_optimize_get_help(self.ctx.ref(), self.optimize))
def param_descrs(self):
"""Return the parameter description set."""
return ParamDescrsRef(Z3_optimize_get_param_descrs(self.ctx.ref(), self.optimize), self.ctx)
def assert_exprs(self, *args):
"""Assert constraints as background axioms for the optimize solver."""
args = _get_args(args)
for arg in args:
if isinstance(arg, Goal) or isinstance(arg, AstVector):
for f in arg:
Z3_optimize_assert(self.ctx.ref(), self.optimize, f.as_ast())
else:
Z3_optimize_assert(self.ctx.ref(), self.optimize, arg.as_ast())
def add(self, *args):
"""Assert constraints as background axioms for the optimize solver. Alias for assert_expr."""
self.assert_exprs(*args)
def add_soft(self, arg, weight = "1", id = None):
"""Add soft constraint with optional weight and optional identifier.
If no weight is supplied, then the penalty for violating the soft constraint
is 1.
Soft constraints are grouped by identifiers. Soft constraints that are
added without identifiers are grouped by default.
"""
if _is_int(weight):
weight = "%d" % weight
if not isinstance(weight, str):
raise Z3Exception("weight should be a string or an integer")
if id == None:
id = ""
id = to_symbol(id, self.ctx)
v = Z3_optimize_assert_soft(self.ctx.ref(), self.optimize, arg.as_ast(), weight, id)
return OptimizeObjective(self, v, False)
def maximize(self, arg):
"""Add objective function to maximize."""
return OptimizeObjective(self, Z3_optimize_maximize(self.ctx.ref(), self.optimize, arg.as_ast()), True)
def minimize(self, arg):
"""Add objective function to minimize."""
return OptimizeObjective(self, Z3_optimize_minimize(self.ctx.ref(), self.optimize, arg.as_ast()), False)
def push(self):
"""create a backtracking point for added rules, facts and assertions"""
Z3_optimize_push(self.ctx.ref(), self.optimize)
def pop(self):
"""restore to previously created backtracking point"""
Z3_optimize_pop(self.ctx.ref(), self.optimize)
def check(self):
"""Check satisfiability while optimizing objective functions."""
return CheckSatResult(Z3_optimize_check(self.ctx.ref(), self.optimize))
def model(self):
"""Return a model for the last check()."""
try:
return ModelRef(Z3_optimize_get_model(self.ctx.ref(), self.optimize), self.ctx)
except Z3Exception:
raise Z3Exception("model is not available")
def lower(self, obj):
if not isinstance(obj, OptimizeObjective):
raise Z3Exception("Expecting objective handle returned by maximize/minimize")
return obj.lower()
def upper(self, obj):
if not isinstance(obj, OptimizeObjective):
raise Z3Exception("Expecting objective handle returned by maximize/minimize")
return obj.upper()
def __repr__(self):
"""Return a formatted string with all added rules and constraints."""
return self.sexpr()
def sexpr(self):
"""Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format.
"""
return Z3_optimize_to_string(self.ctx.ref(), self.optimize)
def statistics(self):
"""Return statistics for the last `query()`.
"""
return Statistics(Z3_optimize_get_statistics(self.ctx.ref(), self.optimize), self.ctx)
#########################################
#
# ApplyResult

View file

@ -842,6 +842,8 @@ class Formatter:
return self.pp_seq(a.assertions(), 0, [])
elif isinstance(a, z3.Fixedpoint):
return a.sexpr()
elif isinstance(a, z3.Optimize):
return a.sexpr()
elif isinstance(a, z3.ApplyResult):
return self.pp_seq_seq(a, 0, [])
elif isinstance(a, z3.ModelRef):

View file

@ -78,6 +78,10 @@ class FixedpointObj(ctypes.c_void_p):
def __init__(self, fixedpoint): self._as_parameter_ = fixedpoint
def from_param(obj): return obj
class OptimizeObj(ctypes.c_void_p):
def __init__(self, optimize): self._as_parameter_ = optimize
def from_param(obj): return obj
class ModelObj(ctypes.c_void_p):
def __init__(self, model): self._as_parameter_ = model
def from_param(obj): return obj

View file

@ -47,6 +47,7 @@ DEFINE_TYPE(Z3_func_interp);
#define Z3_func_interp_opt Z3_func_interp
DEFINE_TYPE(Z3_func_entry);
DEFINE_TYPE(Z3_fixedpoint);
DEFINE_TYPE(Z3_optimize);
DEFINE_TYPE(Z3_rcf_num);
DEFINE_VOID(Z3_theory_data);
#endif
@ -85,6 +86,7 @@ DEFINE_VOID(Z3_theory_data);
- \c Z3_func_interp: interpretation of a function in a model.
- \c Z3_func_entry: representation of the value of a \c Z3_func_interp at a particular point.
- \c Z3_fixedpoint: context for the recursive predicate solver.
- \c Z3_optimize: context for solving optimization queries.
- \c Z3_ast_vector: vector of \c Z3_ast objects.
- \c Z3_ast_map: mapping from \c Z3_ast to \c Z3_ast objects.
- \c Z3_goal: set of formulas that can be solved and/or transformed using tactics and solvers.
@ -875,6 +877,17 @@ typedef enum
- Z3_OP_DT_ACCESSOR: datatype accessor.
- Z3_OP_DT_UPDATE_FIELD: datatype field update.
- Z3_OP_PB_AT_MOST: Cardinality constraint.
E.g., x + y + z <= 2
- Z3_OP_PB_LE: Generalized Pseudo-Boolean cardinality constraint.
Example 2*x + 3*y <= 4
- Z3_OP_PB_GE: Generalized Pseudo-Boolean cardinality constraint.
Example 2*x + 3*y + 2*z >= 4
- Z3_OP_UNINTERPRETED: kind used for uninterpreted symbols.
*/
typedef enum {
@ -1055,6 +1068,12 @@ typedef enum {
Z3_OP_DT_CONSTRUCTOR=0x800,
Z3_OP_DT_RECOGNISER,
Z3_OP_DT_ACCESSOR,
Z3_OP_DT_UPDATE_FIELD,
// Pseudo Booleans
Z3_OP_PB_AT_MOST=0x900,
Z3_OP_PB_LE,
Z3_OP_PB_GE,
Z3_OP_UNINTERPRETED
} Z3_decl_kind;
@ -1192,6 +1211,7 @@ typedef enum
def_Type('FUNC_INTERP', 'Z3_func_interp', 'FuncInterpObj')
def_Type('FUNC_ENTRY', 'Z3_func_entry', 'FuncEntryObj')
def_Type('FIXEDPOINT', 'Z3_fixedpoint', 'FixedpointObj')
def_Type('OPTIMIZE', 'Z3_optimize', 'OptimizeObj')
def_Type('PARAM_DESCRS', 'Z3_param_descrs', 'ParamDescrs')
def_Type('RCF_NUM', 'Z3_rcf_num', 'RCFNumObj')
*/
@ -3734,6 +3754,28 @@ END_MLAPI_EXCLUDE
Z3_func_decl Z3_API Z3_get_datatype_sort_constructor_accessor(
__in Z3_context c, __in Z3_sort t, unsigned idx_c, unsigned idx_a);
/**
\brief Update record field with a value.
This corresponds to the 'with' construct in OCaml.
It has the effect of updating a record field with a given value.
The remaining fields are left unchanged. It is the record
equivalent of an array store (see \sa Z3_mk_store).
If the datatype has more than one constructor, then the update function
behaves as identity if there is a miss-match between the accessor and
constructor. For example ((_ update-field car) nil 1) is nil,
while ((_ update-field car) (cons 2 nil) 1) is (cons 1 nil).
\pre Z3_get_sort_kind(Z3_get_sort(c, t)) == Z3_get_domain(c, field_access, 1) == Z3_DATATYPE_SORT
\pre Z3_get_sort(c, value) == Z3_get_range(c, field_access)
def_API('Z3_datatype_update_field', AST, (_in(CONTEXT), _in(FUNC_DECL), _in(AST), _in(AST)))
*/
Z3_ast Z3_API Z3_datatype_update_field(
__in Z3_context c, __in Z3_func_decl field_access,
__in Z3_ast t, __in Z3_ast value);
/**
\brief Return arity of relation.
@ -3759,6 +3801,29 @@ END_MLAPI_EXCLUDE
Z3_sort Z3_API Z3_get_relation_column(__in Z3_context c, __in Z3_sort s, unsigned col);
/**
\brief Pseudo-Boolean relations.
Encode p1 + p2 + ... + pn <= k
def_API('Z3_mk_atmost', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in(UINT)))
*/
Z3_ast Z3_API Z3_mk_atmost(__in Z3_context c, __in unsigned num_args,
__in_ecount(num_args) Z3_ast const args[], __in unsigned k);
/**
\brief Pseudo-Boolean relations.
Encode k1*p1 + k2*p2 + ... + kn*pn <= k
def_API('Z3_mk_pble', AST, (_in(CONTEXT), _in(UINT), _in_array(1,AST), _in_array(1,INT), _in(INT)))
*/
Z3_ast Z3_API Z3_mk_pble(__in Z3_context c, __in unsigned num_args,
__in_ecount(num_args) Z3_ast const args[], __in_ecount(num_args) int coeffs[],
__in int k);
/**
\mlonly {3 {L Function Declarations}} \endmlonly
*/
@ -3988,6 +4053,12 @@ END_MLAPI_EXCLUDE
/**
\brief Return a unique identifier for \c t.
The identifier is unique up to structural equality. Thus, two ast nodes
created by the same context and having the same children and same function symbols
have the same identifiers. Ast nodes created in the same context, but having
different children or different functions have different identifiers.
Variables and quantifiers are also assigned different identifiers according to
their structure.
\mlonly \remark Implicitly used by [Pervasives.compare] for values of type [ast], [app], [sort], [func_decl], and [pattern]. \endmlonly
def_API('Z3_get_ast_id', UINT, (_in(CONTEXT), _in(AST)))
@ -3996,6 +4067,8 @@ END_MLAPI_EXCLUDE
/**
\brief Return a hash code for the given AST.
The hash code is structural. You can use Z3_get_ast_id interchangably with
this function.
\mlonly \remark Implicitly used by [Hashtbl.hash] for values of type [ast], [app], [sort], [func_decl], and [pattern]. \endmlonly
def_API('Z3_get_ast_hash', UINT, (_in(CONTEXT), _in(AST)))
@ -5904,6 +5977,197 @@ END_MLAPI_EXCLUDE
#endif
#endif
#ifdef CorML4
/**
@name Optimize facilities
*/
/*@{*/
/**
\brief Create a new optimize context.
\conly \remark User must use #Z3_optimize_inc_ref and #Z3_optimize_dec_ref to manage optimize objects.
\conly Even if the context was created using #Z3_mk_context instead of #Z3_mk_context_rc.
def_API('Z3_mk_optimize', OPTIMIZE, (_in(CONTEXT), ))
*/
Z3_optimize Z3_API Z3_mk_optimize(__in Z3_context c);
#ifdef Conly
/**
\brief Increment the reference counter of the given optimize context
def_API('Z3_optimize_inc_ref', VOID, (_in(CONTEXT), _in(OPTIMIZE)))
*/
void Z3_API Z3_optimize_inc_ref(__in Z3_context c,__in Z3_optimize d);
/**
\brief Decrement the reference counter of the given optimize context.
def_API('Z3_optimize_dec_ref', VOID, (_in(CONTEXT), _in(OPTIMIZE)))
*/
void Z3_API Z3_optimize_dec_ref(__in Z3_context c,__in Z3_optimize d);
#endif
/**
\brief Assert hard constraint to the optimization context.
def_API('Z3_optimize_assert', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(AST)))
*/
void Z3_API Z3_optimize_assert(Z3_context c, Z3_optimize o, Z3_ast a);
/**
\brief Assert soft constraint to the optimization context.
\param c - context
\param o - optimization context
\param a - formula
\param weight - a positive weight, penalty for violating soft constraint
\param id - optional identifier to group soft constraints
def_API('Z3_optimize_assert_soft', UINT, (_in(CONTEXT), _in(OPTIMIZE), _in(AST), _in(STRING), _in(SYMBOL)))
*/
unsigned Z3_API Z3_optimize_assert_soft(Z3_context c, Z3_optimize o, Z3_ast a, Z3_string weight, Z3_symbol id);
/**
\brief Add a maximization constraint.
\param c - context
\param o - optimization context
\param a - arithmetical term
def_API('Z3_optimize_maximize', UINT, (_in(CONTEXT), _in(OPTIMIZE), _in(AST)))
*/
unsigned Z3_API Z3_optimize_maximize(Z3_context c, Z3_optimize o, Z3_ast t);
/**
\brief Add a minimization constraint.
\param c - context
\param o - optimization context
\param a - arithmetical term
def_API('Z3_optimize_minimize', UINT, (_in(CONTEXT), _in(OPTIMIZE), _in(AST)))
*/
unsigned Z3_API Z3_optimize_minimize(Z3_context c, Z3_optimize o, Z3_ast t);
/**
\brief Create a backtracking point.
The optimize solver contains a set of rules, added facts and assertions.
The set of rules, facts and assertions are restored upon calling #Z3_optimize_pop.
\sa Z3_optimize_pop
def_API('Z3_optimize_push', VOID, (_in(CONTEXT), _in(OPTIMIZE)))
*/
void Z3_API Z3_optimize_push(Z3_context c,Z3_optimize d);
/**
\brief Backtrack one level.
\sa Z3_optimize_push
\pre The number of calls to pop cannot exceed calls to push.
def_API('Z3_optimize_pop', VOID, (_in(CONTEXT), _in(OPTIMIZE)))
*/
void Z3_API Z3_optimize_pop(Z3_context c,Z3_optimize d);
/**
\brief Check consistency and produce optimal values.
\param c - context
\param o - optimization context
def_API('Z3_optimize_check', INT, (_in(CONTEXT), _in(OPTIMIZE)))
*/
Z3_lbool Z3_API Z3_optimize_check(Z3_context c, Z3_optimize o);
/**
\brief Retrieve the model for the last #Z3_optimize_check
The error handler is invoked if a model is not available because
the commands above were not invoked for the given optimization
solver, or if the result was \c Z3_L_FALSE.
def_API('Z3_optimize_get_model', MODEL, (_in(CONTEXT), _in(OPTIMIZE)))
*/
Z3_model Z3_API Z3_optimize_get_model(Z3_context c, Z3_optimize o);
/**
\brief Set parameters on optimization context.
\param c - context
\param o - optimization context
\param p - parameters
def_API('Z3_optimize_set_params', VOID, (_in(CONTEXT), _in(OPTIMIZE), _in(PARAMS)))
*/
void Z3_API Z3_optimize_set_params(Z3_context c, Z3_optimize o, Z3_params p);
/**
\brief Return the parameter description set for the given optimize object.
\param c - context
\param o - optimization context
def_API('Z3_optimize_get_param_descrs', PARAM_DESCRS, (_in(CONTEXT), _in(OPTIMIZE)))
*/
Z3_param_descrs Z3_API Z3_optimize_get_param_descrs(Z3_context c, Z3_optimize o);
/**
\brief Retrieve lower bound value or approximation for the i'th optimization objective.
\param c - context
\param o - optimization context
\param idx - index of optimization objective
def_API('Z3_optimize_get_lower', AST, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT)))
*/
Z3_ast Z3_API Z3_optimize_get_lower(Z3_context c, Z3_optimize o, unsigned idx);
/**
\brief Retrieve upper bound value or approximation for the i'th optimization objective.
\param c - context
\param o - optimization context
\param idx - index of optimization objective
def_API('Z3_optimize_get_upper', AST, (_in(CONTEXT), _in(OPTIMIZE), _in(UINT)))
*/
Z3_ast Z3_API Z3_optimize_get_upper(Z3_context c, Z3_optimize o, unsigned idx);
/**
\brief Print the current context as a string.
\param c - context.
\param o - optimization context.
def_API('Z3_optimize_to_string', STRING, (_in(CONTEXT), _in(OPTIMIZE)))
*/
Z3_string Z3_API Z3_optimize_to_string(
__in Z3_context c,
__in Z3_optimize o);
/**
\brief Return a string containing a description of parameters accepted by optimize.
def_API('Z3_optimize_get_help', STRING, (_in(CONTEXT), _in(OPTIMIZE)))
*/
Z3_string Z3_API Z3_optimize_get_help(__in Z3_context c, __in Z3_optimize t);
/**
\brief Retrieve statistics information from the last call to #Z3_optimize_check
def_API('Z3_optimize_get_statistics', STATS, (_in(CONTEXT), _in(OPTIMIZE)))
*/
Z3_stats Z3_API Z3_optimize_get_statistics(__in Z3_context c,__in Z3_optimize d);
#endif
#ifdef CorML4
/*@}*/

View file

@ -22,12 +22,14 @@ Notes:
#include"stream_buffer.h"
#include"symbol.h"
#include"trace.h"
#include<sstream>
void register_z3_replayer_cmds(z3_replayer & in);
void throw_invalid_reference() {
TRACE("z3_replayer", tout << "invalid argument reference\n";);
throw z3_replayer_exception("invalid argument reference");
throw z3_replayer_exception("invalid argument reference1");
}
struct z3_replayer::imp {
@ -44,7 +46,37 @@ struct z3_replayer::imp {
size_t_map<void *> m_heap;
svector<z3_replayer_cmd> m_cmds;
enum value_kind { INT64, UINT64, DOUBLE, STRING, SYMBOL, OBJECT, UINT_ARRAY, SYMBOL_ARRAY, OBJECT_ARRAY };
enum value_kind { INT64, UINT64, DOUBLE, STRING, SYMBOL, OBJECT, UINT_ARRAY, INT_ARRAY, SYMBOL_ARRAY, OBJECT_ARRAY };
char const* kind2string(value_kind k) const {
switch (k) {
case INT64: return "int64";
case UINT64: return "uint64";
case DOUBLE: return "double";
case STRING: return "string";
case SYMBOL: return "symbol";
case OBJECT: return "object";
case UINT_ARRAY: return "uint_array";
case INT_ARRAY: return "int_array";
case SYMBOL_ARRAY: return "symbol_array";
case OBJECT_ARRAY: return "object_array";
default: UNREACHABLE(); return "unknown";
}
}
void check_arg(unsigned pos, value_kind k) const {
if (pos >= m_args.size()) {
TRACE("z3_replayer", tout << "too few arguments " << m_args.size() << " expecting " << kind2string(k) << "\n";);
throw z3_replayer_exception("invalid argument reference2");
}
if (m_args[pos].m_kind != k) {
std::stringstream strm;
strm << "expecting " << kind2string(k) << " at position "
<< pos << " but got " << kind2string(m_args[pos].m_kind);
throw z3_replayer_exception(strm.str().c_str());
}
}
struct value {
value_kind m_kind;
@ -68,6 +100,7 @@ struct z3_replayer::imp {
vector<ptr_vector<void> > m_obj_arrays;
vector<svector<Z3_symbol> > m_sym_arrays;
vector<unsigned_vector> m_unsigned_arrays;
vector<svector<int> > m_int_arrays;
imp(z3_replayer & o, std::istream & in):
m_owner(o),
@ -295,6 +328,15 @@ struct z3_replayer::imp {
v.push_back(static_cast<unsigned>(m_args[i].m_uint));
}
}
if (k == INT64) {
aidx = m_int_arrays.size();
nk = INT_ARRAY;
m_int_arrays.push_back(svector<int>());
svector<int> & v = m_int_arrays.back();
for (unsigned i = asz - sz; i < asz; i++) {
v.push_back(static_cast<int>(m_args[i].m_int));
}
}
else if (k == SYMBOL) {
aidx = m_sym_arrays.size();
nk = SYMBOL_ARRAY;
@ -457,8 +499,7 @@ struct z3_replayer::imp {
next(); skip_blank(); read_ptr(); skip_blank(); read_uint64();
unsigned pos = static_cast<unsigned>(m_uint64);
TRACE("z3_replayer", tout << "[" << m_line << "] " << "* " << m_ptr << " " << pos << "\n";);
if (pos >= m_args.size() || m_args[pos].m_kind != OBJECT)
throw_invalid_reference();
check_arg(pos, OBJECT);
m_heap.insert(m_ptr, m_args[pos].m_obj);
break;
}
@ -467,8 +508,7 @@ struct z3_replayer::imp {
// @ obj_id array_pos idx
next(); skip_blank(); read_ptr(); skip_blank(); read_uint64();
unsigned pos = static_cast<unsigned>(m_uint64);
if (pos >= m_args.size() || m_args[pos].m_kind != OBJECT_ARRAY)
throw_invalid_reference();
check_arg(pos, OBJECT_ARRAY);
unsigned aidx = static_cast<unsigned>(m_args[pos].m_uint);
ptr_vector<void> & v = m_obj_arrays[aidx];
skip_blank(); read_uint64();
@ -493,70 +533,65 @@ struct z3_replayer::imp {
}
int get_int(unsigned pos) const {
if (pos >= m_args.size() || m_args[pos].m_kind != INT64)
throw_invalid_reference();
check_arg(pos, INT64);
return static_cast<int>(m_args[pos].m_int);
}
__int64 get_int64(unsigned pos) const {
if (pos >= m_args.size() || m_args[pos].m_kind != INT64)
throw_invalid_reference();
check_arg(pos, INT64);
return m_args[pos].m_int;
}
unsigned get_uint(unsigned pos) const {
if (pos >= m_args.size() || m_args[pos].m_kind != UINT64)
throw_invalid_reference();
check_arg(pos, UINT64);
return static_cast<unsigned>(m_args[pos].m_uint);
}
__uint64 get_uint64(unsigned pos) const {
if (pos >= m_args.size() || m_args[pos].m_kind != UINT64)
throw_invalid_reference();
check_arg(pos, UINT64);
return m_args[pos].m_uint;
}
double get_double(unsigned pos) const {
if (pos >= m_args.size() || m_args[pos].m_kind != DOUBLE)
throw_invalid_reference();
check_arg(pos, DOUBLE);
return m_args[pos].m_double;
}
Z3_string get_str(unsigned pos) const {
if (pos >= m_args.size() || m_args[pos].m_kind != STRING)
throw_invalid_reference();
check_arg(pos, STRING);
return m_args[pos].m_str;
}
Z3_symbol get_symbol(unsigned pos) const {
if (pos >= m_args.size() || m_args[pos].m_kind != SYMBOL)
throw_invalid_reference();
check_arg(pos, SYMBOL);
return reinterpret_cast<Z3_symbol>(const_cast<char*>(m_args[pos].m_str));
}
void * get_obj(unsigned pos) const {
if (pos >= m_args.size() || m_args[pos].m_kind != OBJECT)
throw_invalid_reference();
check_arg(pos, OBJECT);
return m_args[pos].m_obj;
}
unsigned * get_uint_array(unsigned pos) const {
if (pos >= m_args.size() || m_args[pos].m_kind != UINT_ARRAY)
throw_invalid_reference();
check_arg(pos, UINT_ARRAY);
unsigned idx = static_cast<unsigned>(m_args[pos].m_uint);
return m_unsigned_arrays[idx].c_ptr();
}
int * get_int_array(unsigned pos) const {
check_arg(pos, INT_ARRAY);
unsigned idx = static_cast<unsigned>(m_args[pos].m_uint);
return m_int_arrays[idx].c_ptr();
}
Z3_symbol * get_symbol_array(unsigned pos) const {
if (pos >= m_args.size() || m_args[pos].m_kind != SYMBOL_ARRAY)
throw_invalid_reference();
check_arg(pos, SYMBOL_ARRAY);
unsigned idx = static_cast<unsigned>(m_args[pos].m_uint);
return m_sym_arrays[idx].c_ptr();
}
void ** get_obj_array(unsigned pos) const {
if (pos >= m_args.size() || m_args[pos].m_kind != OBJECT_ARRAY)
throw_invalid_reference();
check_arg(pos, OBJECT_ARRAY);
unsigned idx = static_cast<unsigned>(m_args[pos].m_uint);
ptr_vector<void> const & v = m_obj_arrays[idx];
TRACE("z3_replayer_bug", tout << "pos: " << pos << ", idx: " << idx << " size(): " << v.size() << "\n";
@ -565,38 +600,32 @@ struct z3_replayer::imp {
}
int * get_int_addr(unsigned pos) {
if (pos >= m_args.size() || m_args[pos].m_kind != INT64)
throw_invalid_reference();
check_arg(pos, INT64);
return reinterpret_cast<int*>(&(m_args[pos].m_int));
}
__int64 * get_int64_addr(unsigned pos) {
if (pos >= m_args.size() || m_args[pos].m_kind != INT64)
throw_invalid_reference();
check_arg(pos, INT64);
return &(m_args[pos].m_int);
}
unsigned * get_uint_addr(unsigned pos) {
if (pos >= m_args.size() || m_args[pos].m_kind != UINT64)
throw_invalid_reference();
check_arg(pos, UINT64);
return reinterpret_cast<unsigned*>(&(m_args[pos].m_uint));
}
__uint64 * get_uint64_addr(unsigned pos) {
if (pos >= m_args.size() || m_args[pos].m_kind != UINT64)
throw_invalid_reference();
check_arg(pos, UINT64);
return &(m_args[pos].m_uint);
}
Z3_string * get_str_addr(unsigned pos) {
if (pos >= m_args.size() || m_args[pos].m_kind != STRING)
throw_invalid_reference();
check_arg(pos, STRING);
return &(m_args[pos].m_str);
}
void ** get_obj_addr(unsigned pos) {
if (pos >= m_args.size() || m_args[pos].m_kind != OBJECT)
throw_invalid_reference();
check_arg(pos, OBJECT);
return &(m_args[pos].m_obj);
}
@ -615,6 +644,7 @@ struct z3_replayer::imp {
m_obj_arrays.reset();
m_sym_arrays.reset();
m_unsigned_arrays.reset();
m_int_arrays.reset();
}
@ -673,6 +703,10 @@ unsigned * z3_replayer::get_uint_array(unsigned pos) const {
return m_imp->get_uint_array(pos);
}
int * z3_replayer::get_int_array(unsigned pos) const {
return m_imp->get_int_array(pos);
}
Z3_symbol * z3_replayer::get_symbol_array(unsigned pos) const {
return m_imp->get_symbol_array(pos);
}

View file

@ -49,6 +49,7 @@ public:
void * get_obj(unsigned pos) const;
unsigned * get_uint_array(unsigned pos) const;
int * get_int_array(unsigned pos) const;
Z3_symbol * get_symbol_array(unsigned pos) const;
void ** get_obj_array(unsigned pos) const;

View file

@ -417,6 +417,7 @@ inline decl_kind arith_decl_plugin::fix_kind(decl_kind k, unsigned arity) {
app * arith_decl_plugin::mk_numeral(rational const & val, bool is_int) {
if (is_int && !val.is_int()) {
SASSERT(false);
m_manager->raise_exception("invalid rational value passed as an integer");
}
if (val.is_unsigned()) {

View file

@ -1013,6 +1013,17 @@ func_decl * basic_decl_plugin::mk_ite_decl(sort * s) {
return m_ite_decls[id];
}
sort* basic_decl_plugin::join(sort* s1, sort* s2) {
if (s1 == s2) return s1;
if (s1->get_family_id() == m_manager->m_arith_family_id &&
s2->get_family_id() == m_manager->m_arith_family_id) {
if (s1->get_decl_kind() == REAL_SORT) {
return s1;
}
}
return s2;
}
func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
switch (static_cast<basic_op_kind>(k)) {
@ -1025,10 +1036,10 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
case OP_IFF: return m_iff_decl;
case OP_IMPLIES: return m_implies_decl;
case OP_XOR: return m_xor_decl;
case OP_ITE: return arity == 3 ? mk_ite_decl(domain[1]) : 0;
case OP_ITE: return arity == 3 ? mk_ite_decl(join(domain[1], domain[2])) : 0;
// eq and oeq must have at least two arguments, they can have more since they are chainable
case OP_EQ: return arity >= 2 ? mk_eq_decl_core("=", OP_EQ, domain[0], m_eq_decls) : 0;
case OP_OEQ: return arity >= 2 ? mk_eq_decl_core("~", OP_OEQ, domain[0], m_oeq_decls) : 0;
case OP_EQ: return arity >= 2 ? mk_eq_decl_core("=", OP_EQ, join(domain[0],domain[1]), m_eq_decls) : 0;
case OP_OEQ: return arity >= 2 ? mk_eq_decl_core("~", OP_OEQ, join(domain[0],domain[1]), m_oeq_decls) : 0;
case OP_DISTINCT: {
func_decl_info info(m_family_id, OP_DISTINCT);
info.set_pairwise();
@ -1061,10 +1072,12 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
case OP_IFF: return m_iff_decl;
case OP_IMPLIES: return m_implies_decl;
case OP_XOR: return m_xor_decl;
case OP_ITE: return num_args == 3 ? mk_ite_decl(m_manager->get_sort(args[1])): 0;
case OP_ITE: return num_args == 3 ? mk_ite_decl(join(m_manager->get_sort(args[1]), m_manager->get_sort(args[2]))): 0;
// eq and oeq must have at least two arguments, they can have more since they are chainable
case OP_EQ: return num_args >= 2 ? mk_eq_decl_core("=", OP_EQ, m_manager->get_sort(args[0]), m_eq_decls) : 0;
case OP_OEQ: return num_args >= 2 ? mk_eq_decl_core("~", OP_OEQ, m_manager->get_sort(args[0]), m_oeq_decls) : 0;
case OP_EQ: return num_args >= 2 ? mk_eq_decl_core("=", OP_EQ, join(m_manager->get_sort(args[0]),
m_manager->get_sort(args[1])), m_eq_decls) : 0;
case OP_OEQ: return num_args >= 2 ? mk_eq_decl_core("~", OP_OEQ, join(m_manager->get_sort(args[0]),
m_manager->get_sort(args[1])), m_oeq_decls) : 0;
case OP_DISTINCT:
return decl_plugin::mk_func_decl(k, num_parameters, parameters, num_args, args, range);
default:
@ -2058,6 +2071,8 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar
return r;
}
func_decl * ast_manager::mk_fresh_func_decl(symbol const & prefix, symbol const & suffix, unsigned arity,
sort * const * domain, sort * range) {
func_decl_info info(null_family_id, null_decl_kind);

View file

@ -1100,6 +1100,7 @@ protected:
virtual void set_manager(ast_manager * m, family_id id);
func_decl * mk_eq_decl_core(char const * name, decl_kind k, sort * s, ptr_vector<func_decl> & cache);
func_decl * mk_ite_decl(sort * s);
sort* join(sort* s1, sort* s2);
public:
basic_decl_plugin();
@ -1378,7 +1379,7 @@ enum proof_gen_mode {
// -----------------------------------
class ast_manager {
protected:
friend class basic_decl_plugin;
protected:
struct config {
typedef ast_manager value_manager;
@ -2005,6 +2006,7 @@ public:
app * mk_false() { return m_false; }
app * mk_interp(expr * arg) { return mk_app(m_basic_family_id, OP_INTERP, arg); }
func_decl* mk_and_decl() {
sort* domain[2] = { m_bool_sort, m_bool_sort };
return mk_func_decl(m_basic_family_id, OP_AND, 0, 0, 2, domain);

View file

@ -77,6 +77,8 @@ bool smt2_pp_environment::is_indexed_fdecl(func_decl * f) const {
for (i = 0; i < num; i++) {
if (f->get_parameter(i).is_int())
continue;
if (f->get_parameter(i).is_rational())
continue;
if (f->get_parameter(i).is_ast() && is_func_decl(f->get_parameter(i).get_ast()))
continue;
break;
@ -105,9 +107,13 @@ format * smt2_pp_environment::pp_fdecl_params(format * fname, func_decl * f) {
ptr_buffer<format> fs;
fs.push_back(fname);
for (unsigned i = 0; i < num; i++) {
SASSERT(f->get_parameter(i).is_int() || (f->get_parameter(i).is_ast() && is_func_decl(f->get_parameter(i).get_ast())));
SASSERT(f->get_parameter(i).is_int() ||
f->get_parameter(i).is_rational() ||
(f->get_parameter(i).is_ast() && is_func_decl(f->get_parameter(i).get_ast())));
if (f->get_parameter(i).is_int())
fs.push_back(mk_int(get_manager(), f->get_parameter(i).get_int()));
else if (f->get_parameter(i).is_rational())
fs.push_back(mk_string(get_manager(), f->get_parameter(i).get_rational().to_string().c_str()));
else
fs.push_back(pp_fdecl_ref(to_func_decl(f->get_parameter(i).get_ast())));
}
@ -1126,6 +1132,26 @@ std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p) {
return out;
}
std::ostream& operator<<(std::ostream& out, expr_ref const& e) {
return out << mk_ismt2_pp(e.get(), e.get_manager());
}
std::ostream& operator<<(std::ostream& out, app_ref const& e) {
return out << mk_ismt2_pp(e.get(), e.get_manager());
}
std::ostream& operator<<(std::ostream& out, expr_ref_vector const& e) {
for (unsigned i = 0; i < e.size(); ++i)
out << mk_ismt2_pp(e[i], e.get_manager()) << "\n";
return out;
}
std::ostream& operator<<(std::ostream& out, app_ref_vector const& e) {
for (unsigned i = 0; i < e.size(); ++i)
out << mk_ismt2_pp(e[i], e.get_manager()) << "\n";
return out;
}
#ifdef Z3DEBUG
void pp(expr const * n, ast_manager & m) {
std::cout << mk_ismt2_pp(const_cast<expr*>(n), m) << std::endl;

View file

@ -110,4 +110,10 @@ struct mk_ismt2_pp {
std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p);
std::ostream& operator<<(std::ostream& out, expr_ref const& e);
std::ostream& operator<<(std::ostream& out, app_ref const& e);
std::ostream& operator<<(std::ostream& out, expr_ref_vector const& e);
std::ostream& operator<<(std::ostream& out, app_ref_vector const& e);
#endif

View file

@ -1058,7 +1058,8 @@ void ast_smt_pp::display_ast_smt2(std::ostream& strm, ast* a, unsigned indent, u
void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
ptr_vector<quantifier> ql;
decl_collector decls(m_manager);
ast_manager& m = m_manager;
decl_collector decls(m);
smt_renaming rn;
for (unsigned i = 0; i < m_assumptions.size(); ++i) {
@ -1069,7 +1070,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
}
decls.visit(n);
if (m_manager.is_proof(n)) {
if (m.is_proof(n)) {
strm << "(";
}
if (m_benchmark_name != symbol::null) {
@ -1078,7 +1079,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
if (m_source_info != symbol::null && m_source_info != symbol("")) {
strm << "; :source { " << m_source_info << " }\n";
}
if (m_manager.is_bool(n)) {
if (m.is_bool(n)) {
strm << "(set-info :status " << m_status << ")\n";
}
if (m_category != symbol::null && m_category != symbol("")) {
@ -1095,7 +1096,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
for (unsigned i = 0; i < decls.get_num_sorts(); ++i) {
sort* s = decls.get_sorts()[i];
if (!(*m_is_declared)(s)) {
smt_printer p(strm, m_manager, ql, rn, m_logic, true, true, m_simplify_implies, 0);
smt_printer p(strm, m, ql, rn, m_logic, true, true, m_simplify_implies, 0);
p.pp_sort_decl(sort_mark, s);
}
}
@ -1103,7 +1104,7 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
for (unsigned i = 0; i < decls.get_num_decls(); ++i) {
func_decl* d = decls.get_func_decls()[i];
if (!(*m_is_declared)(d)) {
smt_printer p(strm, m_manager, ql, rn, m_logic, true, true, m_simplify_implies, 0);
smt_printer p(strm, m, ql, rn, m_logic, true, true, m_simplify_implies, 0);
p(d);
strm << "\n";
}
@ -1112,34 +1113,36 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) {
for (unsigned i = 0; i < decls.get_num_preds(); ++i) {
func_decl* d = decls.get_pred_decls()[i];
if (!(*m_is_declared)(d)) {
smt_printer p(strm, m_manager, ql, rn, m_logic, true, true, m_simplify_implies, 0);
smt_printer p(strm, m, ql, rn, m_logic, true, true, m_simplify_implies, 0);
p(d);
strm << "\n";
}
}
for (unsigned i = 0; i < m_assumptions.size(); ++i) {
strm << "(assert\n";
smt_printer p(strm, m_manager, ql, rn, m_logic, false, true, m_simplify_implies, 0);
p(m_assumptions[i].get());
strm << ")\n";
smt_printer p(strm, m, ql, rn, m_logic, false, true, m_simplify_implies, 1);
strm << "(assert\n ";
p(m_assumptions[i].get());
strm << ")\n";
}
for (unsigned i = 0; i < m_assumptions_star.size(); ++i) {
strm << "(assert\n";
smt_printer p(strm, m_manager, ql, rn, m_logic, false, true, m_simplify_implies, 0);
p(m_assumptions_star[i].get());
smt_printer p(strm, m, ql, rn, m_logic, false, true, m_simplify_implies, 1);
strm << "(assert\n ";
p(m_assumptions_star[i].get());
strm << ")\n";
}
smt_printer p(strm, m_manager, ql, rn, m_logic, false, true, m_simplify_implies, 0);
if (m_manager.is_bool(n)) {
strm << "(assert\n";
p(n);
strm << ")\n";
smt_printer p(strm, m, ql, rn, m_logic, false, true, m_simplify_implies, 0);
if (m.is_bool(n)) {
if (!m.is_true(n)) {
strm << "(assert\n ";
p(n);
strm << ")\n";
}
strm << "(check-sat)\n";
}
else if (m_manager.is_proof(n)) {
else if (m.is_proof(n)) {
strm << "(proof\n";
p(n);
strm << "))\n";

76
src/ast/ast_trail.h Normal file
View file

@ -0,0 +1,76 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
ast_trail.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-06-02.
Revision History:
Extracted AST specific features from trail.h
nbjorner 2014-9-28
--*/
#ifndef _AST_TRAIL_H_
#define _AST_TRAIL_H_
#include"ast.h"
#include"trail.h"
template<typename S, typename T>
class ast2ast_trailmap {
ref_vector<S, ast_manager> m_domain;
ref_vector<T, ast_manager> m_range;
obj_map<S, T*> m_map;
public:
ast2ast_trailmap(ast_manager& m):
m_domain(m),
m_range(m),
m_map()
{}
bool find(S* s, T*& t) {
return m_map.find(s,t);
}
void insert(S* s, T* t) {
SASSERT(!m_map.contains(s));
m_domain.push_back(s);
m_range.push_back(t);
m_map.insert(s,t);
}
void pop() {
SASSERT(!m_domain.empty());
m_map.remove(m_domain.back());
m_domain.pop_back();
m_range.pop_back();
}
};
template<typename Ctx, typename S, typename T>
class ast2ast_trail : public trail<Ctx> {
ast2ast_trailmap<S,T>& m_map;
public:
ast2ast_trail(ast2ast_trailmap<S,T>& m, S* s, T* t) :
m_map(m) {
m.insert(s,t);
}
virtual void undo(Ctx& ctx) {
m_map.pop();
}
};
#endif /* _AST_TRAIL_H_ */

View file

@ -422,8 +422,55 @@ static sort * get_type(ast_manager & m, family_id datatype_fid, sort * source_da
}
}
func_decl * datatype_decl_plugin::mk_update_field(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
decl_kind k = OP_DT_UPDATE_FIELD;
ast_manager& m = *m_manager;
if (num_parameters != 1 || !parameters[0].is_ast()) {
m.raise_exception("invalid parameters for datatype field update");
return 0;
}
if (arity != 2) {
m.raise_exception("invalid number of arguments for datatype field update");
return 0;
}
func_decl* acc = 0;
if (is_func_decl(parameters[0].get_ast())) {
acc = to_func_decl(parameters[0].get_ast());
}
if (acc && !get_util().is_accessor(acc)) {
acc = 0;
}
if (!acc) {
m.raise_exception("datatype field update requires a datatype accessor as the second argument");
return 0;
}
sort* dom = acc->get_domain(0);
sort* rng = acc->get_range();
if (dom != domain[0]) {
m.raise_exception("first argument to field update should be a data-type");
return 0;
}
if (rng != domain[1]) {
std::ostringstream buffer;
buffer << "second argument to field update should be " << mk_ismt2_pp(rng, m)
<< " instead of " << mk_ismt2_pp(domain[1], m);
m.raise_exception(buffer.str().c_str());
return 0;
}
range = domain[0];
func_decl_info info(m_family_id, k, num_parameters, parameters);
return m.mk_func_decl(symbol("update_field"), arity, domain, range, info);
}
func_decl * datatype_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (k == OP_DT_UPDATE_FIELD) {
return mk_update_field(num_parameters, parameters, arity, domain, range);
}
if (num_parameters < 2 || !parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) {
m_manager->raise_exception("invalid parameters for datatype operator");
return 0;
@ -521,6 +568,9 @@ func_decl * datatype_decl_plugin::mk_func_decl(decl_kind k, unsigned num_paramet
return m_manager->mk_func_decl(a_name, arity, domain, a_type, info);
}
break;
case OP_DT_UPDATE_FIELD:
UNREACHABLE();
return 0;
default:
m_manager->raise_exception("invalid datatype operator kind");
return 0;
@ -672,6 +722,13 @@ bool datatype_decl_plugin::is_value(app * e) const {
return true;
}
void datatype_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
if (logic == symbol::null) {
op_names.push_back(builtin_name("update-field", OP_DT_UPDATE_FIELD));
}
}
datatype_util::datatype_util(ast_manager & m):
m_manager(m),
m_family_id(m.mk_family_id("datatype")),
@ -919,9 +976,9 @@ void datatype_util::display_datatype(sort *s0, std::ostream& strm) {
todo.push_back(s0);
mark.mark(s0, true);
while (!todo.empty()) {
sort* s = todo.back();
sort* s = todo.back();
todo.pop_back();
strm << s->get_name() << " =\n";
strm << s->get_name() << " =\n";
ptr_vector<func_decl> const * cnstrs = get_datatype_constructors(s);
for (unsigned i = 0; i < cnstrs->size(); ++i) {
@ -931,14 +988,14 @@ void datatype_util::display_datatype(sort *s0, std::ostream& strm) {
ptr_vector<func_decl> const * accs = get_constructor_accessors(cns);
for (unsigned j = 0; j < accs->size(); ++j) {
func_decl* acc = (*accs)[j];
sort* s1 = acc->get_range();
sort* s1 = acc->get_range();
strm << "(" << acc->get_name() << ": " << s1->get_name() << ") ";
if (is_datatype(s1) && are_siblings(s1, s0) && !mark.is_marked(s1)) {
mark.mark(s1, true);
todo.push_back(s1);
}
}
strm << "\n";
strm << "\n";
}
}

View file

@ -32,6 +32,7 @@ enum datatype_op_kind {
OP_DT_CONSTRUCTOR,
OP_DT_RECOGNISER,
OP_DT_ACCESSOR,
OP_DT_UPDATE_FIELD,
LAST_DT_OP
};
@ -149,8 +150,14 @@ public:
virtual bool is_unique_value(app * e) const { return is_value(e); }
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
private:
bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const;
func_decl * mk_update_field(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
};
class datatype_util {
@ -181,9 +188,11 @@ public:
bool is_constructor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_CONSTRUCTOR); }
bool is_recognizer(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_RECOGNISER); }
bool is_accessor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_ACCESSOR); }
bool is_update_field(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_UPDATE_FIELD); }
bool is_constructor(app * f) const { return is_app_of(f, m_family_id, OP_DT_CONSTRUCTOR); }
bool is_recognizer(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER); }
bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); }
bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); }
ptr_vector<func_decl> const * get_datatype_constructors(sort * ty);
unsigned get_datatype_num_constructors(sort * ty) { return get_datatype_constructors(ty)->size(); }
unsigned get_constructor_idx(func_decl * f) const { SASSERT(is_constructor(f)); return f->get_parameter(1).get_int(); }

View file

@ -44,6 +44,10 @@ public:
void erase(expr * k);
void reset();
void flush();
void set_store_proofs(bool f) {
if (m_store_proofs != f) flush();
m_store_proofs = f;
}
};
#endif

View file

@ -2155,15 +2155,15 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg
SASSERT(f->get_num_parameters() == 1);
SASSERT(f->get_parameter(0).is_int());
unsigned ebits = m_util.get_ebits(f->get_range());
unsigned sbits = m_util.get_sbits(f->get_range());
int width = f->get_parameter(0).get_int();
//unsigned ebits = m_util.get_ebits(f->get_range());
//unsigned sbits = m_util.get_sbits(f->get_range());
//int width = f->get_parameter(0).get_int();
expr * rm = args[0];
expr * x = args[1];
//expr * rm = args[0];
//expr * x = args[1];
expr * sgn, *s, *e;
split(x, sgn, s, e);
//expr * sgn, *s, *e;
//split(x, sgn, s, e);
NOT_IMPLEMENTED_YET();
}
@ -2173,15 +2173,15 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg
SASSERT(f->get_num_parameters() == 1);
SASSERT(f->get_parameter(0).is_int());
unsigned ebits = m_util.get_ebits(f->get_range());
unsigned sbits = m_util.get_sbits(f->get_range());
int width = f->get_parameter(0).get_int();
//unsigned ebits = m_util.get_ebits(f->get_range());
//unsigned sbits = m_util.get_sbits(f->get_range());
//int width = f->get_parameter(0).get_int();
expr * rm = args[0];
expr * x = args[1];
//expr * rm = args[0];
//expr * x = args[1];
expr * sgn, *s, *e;
split(x, sgn, s, e);
//expr * sgn, *s, *e;
//split(x, sgn, s, e);
NOT_IMPLEMENTED_YET();
}
@ -2189,15 +2189,15 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg
void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 1);
unsigned ebits = m_util.get_ebits(f->get_range());
unsigned sbits = m_util.get_sbits(f->get_range());
int width = f->get_parameter(0).get_int();
//unsigned ebits = m_util.get_ebits(f->get_range());
//unsigned sbits = m_util.get_sbits(f->get_range());
//int width = f->get_parameter(0).get_int();
expr * rm = args[0];
expr * x = args[1];
//expr * rm = args[0];
//expr * x = args[1];
expr * sgn, *s, *e;
split(x, sgn, s, e);
//expr * sgn, *s, *e;
//split(x, sgn, s, e);
NOT_IMPLEMENTED_YET();
}

View file

@ -255,9 +255,9 @@ bool macro_manager::macro_expander::get_subst(expr * _n, expr_ref & r, proof_ref
app * n = to_app(_n);
quantifier * q = 0;
func_decl * d = n->get_decl();
TRACE("macro_manager_bug", tout << "trying to expand:\n" << mk_pp(n, m_manager) << "\nd:\n" << d->get_name() << "\n";);
TRACE("macro_manager_bug", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";);
if (m_macro_manager.m_decl2macro.find(d, q)) {
TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m_manager) << "\n";);
TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";);
app * head = 0;
expr * def = 0;
m_macro_manager.get_head_def(q, d, head, def);
@ -272,17 +272,17 @@ bool macro_manager::macro_expander::get_subst(expr * _n, expr_ref & r, proof_ref
SASSERT(subst_args[nidx] == 0);
subst_args[nidx] = n->get_arg(i);
}
var_subst s(m_manager);
var_subst s(m);
s(def, num, subst_args.c_ptr(), r);
if (m_manager.proofs_enabled()) {
expr_ref instance(m_manager);
if (m.proofs_enabled()) {
expr_ref instance(m);
s(q->get_expr(), num, subst_args.c_ptr(), instance);
proof * qi_pr = m_manager.mk_quant_inst(m_manager.mk_or(m_manager.mk_not(q), instance), num, subst_args.c_ptr());
proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr());
proof * q_pr = 0;
m_macro_manager.m_decl2macro_pr.find(d, q_pr);
SASSERT(q_pr != 0);
proof * prs[2] = { qi_pr, q_pr };
p = m_manager.mk_unit_resolution(2, prs);
p = m.mk_unit_resolution(2, prs);
}
else {
p = 0;

View file

@ -116,7 +116,7 @@ void pattern_inference::collect::operator()(expr * n, unsigned num_bindings) {
n = e.m_node;
unsigned delta = e.m_delta;
TRACE("collect", tout << "processing: " << n->get_id() << " " << delta << " kind: " << n->get_kind() << "\n";);
TRACE("collect_info", tout << mk_pp(n, m_manager) << "\n";);
TRACE("collect_info", tout << mk_pp(n, m) << "\n";);
if (visit_children(n, delta)) {
m_todo.pop_back();
save_candidate(n, delta);
@ -170,9 +170,9 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
free_vars.insert(idx);
info * i = 0;
if (delta == 0)
i = alloc(info, m_manager, n, free_vars, 1);
i = alloc(info, m, n, free_vars, 1);
else
i = alloc(info, m_manager, m_manager.mk_var(idx, to_var(n)->get_sort()), free_vars, 1);
i = alloc(info, m, m.mk_var(idx, to_var(n)->get_sort()), free_vars, 1);
save(n, delta, i);
}
else {
@ -189,7 +189,7 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
}
if (c->get_num_args() == 0) {
save(n, delta, alloc(info, m_manager, n, uint_set(), 1));
save(n, delta, alloc(info, m, n, uint_set(), 1));
return;
}
@ -219,10 +219,10 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
app * new_node = 0;
if (changed)
new_node = m_manager.mk_app(decl, buffer.size(), buffer.c_ptr());
new_node = m.mk_app(decl, buffer.size(), buffer.c_ptr());
else
new_node = to_app(n);
save(n, delta, alloc(info, m_manager, new_node, free_vars, size));
save(n, delta, alloc(info, m, new_node, free_vars, size));
// Remark: arithmetic patterns are only used if they are nested inside other terms.
// That is, we never consider x + 1 as pattern. On the other hand, f(x+1) can be a pattern
// if arithmetic is not in the forbidden list.
@ -235,7 +235,7 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
decl_kind k = c->get_decl_kind();
if (!free_vars.empty() &&
(fid != m_afid || (fid == m_afid && !m_owner.m_nested_arith_only && (k == OP_DIV || k == OP_IDIV || k == OP_MOD || k == OP_REM || k == OP_MUL)))) {
TRACE("pattern_inference", tout << "potential candidate: \n" << mk_pp(new_node, m_manager) << "\n";);
TRACE("pattern_inference", tout << "potential candidate: \n" << mk_pp(new_node, m) << "\n";);
m_owner.add_candidate(new_node, free_vars, size);
}
return;
@ -338,7 +338,7 @@ bool pattern_inference::contains_subpattern::operator()(expr * n) {
uint_set const & s2 = e->get_data().m_value.m_free_vars;
SASSERT(s2.subset_of(s1));
if (s1 == s2) {
TRACE("pattern_inference", tout << mk_pp(n, m_owner.m_manager) << "\nis bigger than\n" << mk_pp(to_app(curr), m_owner.m_manager) << "\n";);
TRACE("pattern_inference", tout << mk_pp(n, m_owner.m) << "\nis bigger than\n" << mk_pp(to_app(curr), m_owner.m) << "\n";);
return true;
}
}
@ -411,7 +411,7 @@ void pattern_inference::candidates2unary_patterns(ptr_vector<app> const & candid
expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
info const & i = e->get_data().m_value;
if (i.m_free_vars.num_elems() == m_num_bindings) {
app * new_pattern = m_manager.mk_pattern(candidate);
app * new_pattern = m.mk_pattern(candidate);
result.push_back(new_pattern);
}
else {
@ -435,7 +435,7 @@ void pattern_inference::candidates2multi_patterns(unsigned max_num_patterns,
for (unsigned j = 0; j < m_pre_patterns.size(); j++) {
pre_pattern * curr = m_pre_patterns[j];
if (curr->m_free_vars.num_elems() == m_num_bindings) {
app * new_pattern = m_manager.mk_pattern(curr->m_exprs.size(), curr->m_exprs.c_ptr());
app * new_pattern = m.mk_pattern(curr->m_exprs.size(), curr->m_exprs.c_ptr());
result.push_back(new_pattern);
if (result.size() >= max_num_patterns)
return;
@ -489,7 +489,7 @@ bool pattern_inference::is_forbidden(app * n) const {
// occur outside of the quantifier. That is, Z3 will never match this kind of
// pattern.
if (m_params.m_pi_avoid_skolems && decl->is_skolem()) {
CTRACE("pattern_inference_skolem", decl->is_skolem(), tout << "ignoring: " << mk_pp(n, m_manager) << "\n";);
CTRACE("pattern_inference_skolem", decl->is_skolem(), tout << "ignoring: " << mk_pp(n, m) << "\n";);
return true;
}
if (is_forbidden(decl))
@ -509,8 +509,8 @@ bool pattern_inference::has_preferred_patterns(ptr_vector<app> & candidate_patte
expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
info const & i = e->get_data().m_value;
if (i.m_free_vars.num_elems() == m_num_bindings) {
TRACE("pattern_inference", tout << "found preferred pattern:\n" << mk_pp(candidate, m_manager) << "\n";);
app * p = m_manager.mk_pattern(candidate);
TRACE("pattern_inference", tout << "found preferred pattern:\n" << mk_pp(candidate, m) << "\n";);
app * p = m.mk_pattern(candidate);
result.push_back(p);
found = true;
}
@ -531,11 +531,11 @@ void pattern_inference::mk_patterns(unsigned num_bindings,
m_collect(n, num_bindings);
TRACE("pattern_inference",
tout << mk_pp(n, m_manager);
tout << mk_pp(n, m);
tout << "\ncandidates:\n";
unsigned num = m_candidates.size();
for (unsigned i = 0; i < num; i++) {
tout << mk_pp(m_candidates.get(i), m_manager) << "\n";
tout << mk_pp(m_candidates.get(i), m) << "\n";
});
if (!m_candidates.empty()) {
@ -543,7 +543,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings,
filter_looping_patterns(m_tmp1);
TRACE("pattern_inference",
tout << "candidates after removing looping-patterns:\n";
dump_app_vector(tout, m_tmp1, m_manager););
dump_app_vector(tout, m_tmp1, m););
SASSERT(!m_tmp1.empty());
if (!has_preferred_patterns(m_tmp1, result)) {
// continue if there are no preferred patterns
@ -552,7 +552,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings,
SASSERT(!m_tmp2.empty());
TRACE("pattern_inference",
tout << "candidates after removing bigger patterns:\n";
dump_app_vector(tout, m_tmp2, m_manager););
dump_app_vector(tout, m_tmp2, m););
m_tmp1.reset();
candidates2unary_patterns(m_tmp2, m_tmp1, result);
unsigned num_extra_multi_patterns = m_params.m_pi_max_multi_patterns;
@ -563,7 +563,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings,
std::stable_sort(m_tmp1.begin(), m_tmp1.end(), m_pattern_weight_lt);
TRACE("pattern_inference",
tout << "candidates after sorting:\n";
dump_app_vector(tout, m_tmp1, m_manager););
dump_app_vector(tout, m_tmp1, m););
candidates2multi_patterns(num_extra_multi_patterns, m_tmp1, result);
}
}
@ -577,7 +577,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings,
#include"database.h" // defines g_pattern_database
void pattern_inference::reduce1_quantifier(quantifier * q) {
TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m_manager) << "\n";);
TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";);
if (!q->is_forall()) {
simplifier::reduce1_quantifier(q);
return;
@ -587,27 +587,27 @@ void pattern_inference::reduce1_quantifier(quantifier * q) {
if (m_params.m_pi_use_database) {
m_database.initialize(g_pattern_database);
app_ref_vector new_patterns(m_manager);
app_ref_vector new_patterns(m);
unsigned new_weight;
if (m_database.match_quantifier(q, new_patterns, new_weight)) {
#ifdef Z3DEBUG
for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m_manager, new_patterns.get(i))); }
for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m, new_patterns.get(i))); }
#endif
quantifier_ref new_q(m_manager);
quantifier_ref new_q(m);
if (q->get_num_patterns() > 0) {
// just update the weight...
TRACE("pattern_inference", tout << "updating weight to: " << new_weight << "\n" << mk_pp(q, m_manager) << "\n";);
new_q = m_manager.update_quantifier_weight(q, new_weight);
TRACE("pattern_inference", tout << "updating weight to: " << new_weight << "\n" << mk_pp(q, m) << "\n";);
new_q = m.update_quantifier_weight(q, new_weight);
}
else {
quantifier_ref tmp(m_manager);
tmp = m_manager.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr());
new_q = m_manager.update_quantifier_weight(tmp, new_weight);
TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m_manager) << "\n";);
quantifier_ref tmp(m);
tmp = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr());
new_q = m.update_quantifier_weight(tmp, new_weight);
TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m) << "\n";);
}
proof * pr = 0;
if (m_manager.fine_grain_proofs())
pr = m_manager.mk_rewrite(q, new_q);
if (m.fine_grain_proofs())
pr = m.mk_rewrite(q, new_q);
cache_result(q, new_q, pr);
return;
}
@ -635,7 +635,7 @@ void pattern_inference::reduce1_quantifier(quantifier * q) {
new_no_patterns.push_back(new_pattern);
}
app_ref_buffer new_patterns(m_manager);
app_ref_buffer new_patterns(m);
if (m_params.m_pi_arith == AP_CONSERVATIVE)
m_forbidden.push_back(m_afid);
@ -677,26 +677,26 @@ void pattern_inference::reduce1_quantifier(quantifier * q) {
warning_msg("using non nested arith. pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_NON_NESTED_ARITH_WEIGHT=<val>).",
q->get_qid().str().c_str(), weight);
}
// verbose_stream() << mk_pp(q, m_manager) << "\n";
// verbose_stream() << mk_pp(q, m) << "\n";
}
}
}
quantifier_ref new_q(m_manager);
new_q = m_manager.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body);
quantifier_ref new_q(m);
new_q = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body);
if (weight != q->get_weight())
new_q = m_manager.update_quantifier_weight(new_q, weight);
proof_ref pr(m_manager);
if (m_manager.fine_grain_proofs()) {
new_q = m.update_quantifier_weight(new_q, weight);
proof_ref pr(m);
if (m.fine_grain_proofs()) {
if (new_body_pr == 0)
new_body_pr = m_manager.mk_reflexivity(new_body);
pr = m_manager.mk_quant_intro(q, new_q, new_body_pr);
new_body_pr = m.mk_reflexivity(new_body);
pr = m.mk_quant_intro(q, new_q, new_body_pr);
}
if (new_patterns.empty() && m_params.m_pi_pull_quantifiers) {
pull_quant pull(m_manager);
expr_ref new_expr(m_manager);
proof_ref new_pr(m_manager);
pull_quant pull(m);
expr_ref new_expr(m);
proof_ref new_pr(m);
pull(new_q, new_expr, new_pr);
quantifier * new_new_q = to_quantifier(new_expr);
if (new_new_q != new_q) {
@ -705,12 +705,12 @@ void pattern_inference::reduce1_quantifier(quantifier * q) {
if (m_params.m_pi_warnings) {
warning_msg("pulled nested quantifier to be able to find an useable pattern (quantifier id: %s)", q->get_qid().str().c_str());
}
new_q = m_manager.update_quantifier(new_new_q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_new_q->get_expr());
if (m_manager.fine_grain_proofs()) {
pr = m_manager.mk_transitivity(pr, new_pr);
pr = m_manager.mk_transitivity(pr, m_manager.mk_quant_intro(new_new_q, new_q, m_manager.mk_reflexivity(new_q->get_expr())));
new_q = m.update_quantifier(new_new_q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_new_q->get_expr());
if (m.fine_grain_proofs()) {
pr = m.mk_transitivity(pr, new_pr);
pr = m.mk_transitivity(pr, m.mk_quant_intro(new_new_q, new_q, m.mk_reflexivity(new_q->get_expr())));
}
TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m_manager) << "\n";);
TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m) << "\n";);
}
}
}
@ -719,7 +719,7 @@ void pattern_inference::reduce1_quantifier(quantifier * q) {
if (m_params.m_pi_warnings) {
warning_msg("failed to find a pattern for quantifier (quantifier id: %s)", q->get_qid().str().c_str());
}
TRACE("pi_failed", tout << mk_pp(q, m_manager) << "\n";);
TRACE("pi_failed", tout << mk_pp(q, m) << "\n";);
}
if (new_patterns.empty() && new_body == q->get_expr()) {

View file

@ -38,7 +38,7 @@ Revision History:
every instance of f(g(X)) is also an instance of f(X).
*/
class smaller_pattern {
ast_manager & m_manager;
ast_manager & m;
ptr_vector<expr> m_bindings;
typedef std::pair<expr *, expr *> expr_pair;
@ -54,7 +54,7 @@ class smaller_pattern {
public:
smaller_pattern(ast_manager & m):
m_manager(m) {
m(m) {
}
bool operator()(unsigned num_bindings, expr * p1, expr * p2);
@ -135,7 +135,7 @@ class pattern_inference : public simplifier {
m_node(n, m), m_free_vars(vars), m_size(sz) {}
};
ast_manager & m_manager;
ast_manager & m;
pattern_inference & m_owner;
family_id m_afid;
unsigned m_num_bindings;
@ -150,7 +150,7 @@ class pattern_inference : public simplifier {
void save_candidate(expr * n, unsigned delta);
void reset();
public:
collect(ast_manager & m, pattern_inference & o):m_manager(m), m_owner(o), m_afid(m.mk_family_id("arith")) {}
collect(ast_manager & m, pattern_inference & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {}
void operator()(expr * n, unsigned num_bindings);
};

282
src/ast/pb_decl_plugin.cpp Normal file
View file

@ -0,0 +1,282 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
pb_decl_plugin.cpp
Abstract:
Cardinality Constraints plugin
Author:
Nikolaj Bjorner (nbjorner) 2013-05-11
Revision History:
--*/
#include "pb_decl_plugin.h"
pb_decl_plugin::pb_decl_plugin():
m_at_most_sym("at-most"),
m_at_least_sym("at-least"),
m_pble_sym("pble"),
m_pbge_sym("pbge"),
m_pbeq_sym("pbeq")
{}
func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
SASSERT(m_manager);
ast_manager& m = *m_manager;
for (unsigned i = 0; i < arity; ++i) {
if (!m.is_bool(domain[i])) {
m.raise_exception("invalid non-Boolean sort applied to 'at-most'");
}
}
symbol sym;
switch(k) {
case OP_AT_LEAST_K: sym = m_at_least_sym; break;
case OP_AT_MOST_K: sym = m_at_most_sym; break;
case OP_PB_LE: sym = m_pble_sym; break;
case OP_PB_GE: sym = m_pbge_sym; break;
case OP_PB_EQ: sym = m_pbeq_sym; break;
default: break;
}
switch(k) {
case OP_AT_LEAST_K:
case OP_AT_MOST_K: {
if (num_parameters != 1 || !parameters[0].is_int() || parameters[0].get_int() < 0) {
m.raise_exception("function expects one non-negative integer parameter");
}
func_decl_info info(m_family_id, k, 1, parameters);
return m.mk_func_decl(sym, arity, domain, m.mk_bool_sort(), info);
}
case OP_PB_GE:
case OP_PB_LE:
case OP_PB_EQ: {
if (num_parameters != 1 + arity) {
m.raise_exception("function expects arity+1 rational parameters");
}
vector<parameter> params;
for (unsigned i = 0; i < num_parameters; ++i) {
parameter const& p = parameters[i];
if (p.is_int()) {
params.push_back(p);
}
else if (p.is_rational()) {
// HACK: ast pretty printer does not work with rationals.
rational r = p.get_rational();
if (r.is_int32()) {
params.push_back(parameter(r.get_int32()));
}
else {
params.push_back(p);
}
}
else {
m.raise_exception("functions 'pble/pbge/pbeq' expect arity+1 integer parameters");
}
}
func_decl_info info(m_family_id, k, num_parameters, params.c_ptr());
return m.mk_func_decl(sym, arity, domain, m.mk_bool_sort(), info);
}
default:
UNREACHABLE();
return 0;
}
}
void pb_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
if (logic == symbol::null) {
op_names.push_back(builtin_name(m_at_most_sym.bare_str(), OP_AT_MOST_K));
op_names.push_back(builtin_name(m_at_least_sym.bare_str(), OP_AT_LEAST_K));
op_names.push_back(builtin_name(m_pble_sym.bare_str(), OP_PB_LE));
op_names.push_back(builtin_name(m_pbge_sym.bare_str(), OP_PB_GE));
op_names.push_back(builtin_name(m_pbeq_sym.bare_str(), OP_PB_EQ));
}
}
app * pb_util::mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) {
vector<parameter> params;
params.push_back(parameter(k));
for (unsigned i = 0; i < num_args; ++i) {
params.push_back(parameter(coeffs[i]));
}
return m.mk_app(m_fid, OP_PB_LE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort());
}
app * pb_util::mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) {
vector<parameter> params;
params.push_back(parameter(k));
for (unsigned i = 0; i < num_args; ++i) {
params.push_back(parameter(coeffs[i]));
}
return m.mk_app(m_fid, OP_PB_GE, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort());
}
app * pb_util::mk_eq(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k) {
vector<parameter> params;
params.push_back(parameter(k));
for (unsigned i = 0; i < num_args; ++i) {
params.push_back(parameter(coeffs[i]));
}
return m.mk_app(m_fid, OP_PB_EQ, params.size(), params.c_ptr(), num_args, args, m.mk_bool_sort());
}
// ax + by < k
// <=>
// -ax - by >= -k + 1
// <=>
// a(1-x) + b(1-y) >= -k + a + b + 1
app * pb_util::mk_lt(unsigned num_args, rational const * _coeffs, expr * const * _args, rational const& _k) {
vector<rational> coeffs;
rational k(_k);
expr_ref_vector args(m);
expr* f;
rational d(denominator(k));
for (unsigned i = 0; i < num_args; ++i) {
coeffs.push_back(_coeffs[i]);
d = lcm(d, denominator(coeffs[i]));
if (m.is_not(_args[i], f)) {
args.push_back(f);
}
else {
args.push_back(m.mk_not(_args[i]));
}
}
if (!d.is_one()) {
k *= d;
for (unsigned i = 0; i < num_args; ++i) {
coeffs[i] *= d;
}
}
k.neg();
k += rational::one();
for (unsigned i = 0; i < num_args; ++i) {
k += coeffs[i];
}
return mk_ge(num_args, coeffs.c_ptr(), args.c_ptr(), k);
}
app * pb_util::mk_at_most_k(unsigned num_args, expr * const * args, unsigned k) {
parameter param(k);
return m.mk_app(m_fid, OP_AT_MOST_K, 1, &param, num_args, args, m.mk_bool_sort());
}
bool pb_util::is_at_most_k(func_decl *a) const {
return is_decl_of(a, m_fid, OP_AT_MOST_K);
}
bool pb_util::is_at_most_k(expr *a, rational& k) const {
if (is_at_most_k(a)) {
k = get_k(a);
return true;
}
else {
return false;
}
}
app * pb_util::mk_at_least_k(unsigned num_args, expr * const * args, unsigned k) {
parameter param(k);
return m.mk_app(m_fid, OP_AT_LEAST_K, 1, &param, num_args, args, m.mk_bool_sort());
}
bool pb_util::is_at_least_k(func_decl *a) const {
return is_decl_of(a, m_fid, OP_AT_LEAST_K);
}
bool pb_util::is_at_least_k(expr *a, rational& k) const {
if (is_at_least_k(a)) {
k = get_k(a);
return true;
}
else {
return false;
}
}
rational pb_util::get_k(func_decl *a) const {
parameter const& p = a->get_parameter(0);
if (is_at_most_k(a) || is_at_least_k(a)) {
return to_rational(p);
}
else {
SASSERT(is_le(a) || is_ge(a) || is_eq(a));
return to_rational(p);
}
}
bool pb_util::is_le(func_decl *a) const {
return is_decl_of(a, m_fid, OP_PB_LE);
}
bool pb_util::is_le(expr* a, rational& k) const {
if (is_le(a)) {
k = get_k(a);
return true;
}
else {
return false;
}
}
bool pb_util::is_ge(func_decl *a) const {
return is_decl_of(a, m_fid, OP_PB_GE);
}
bool pb_util::is_ge(expr* a, rational& k) const {
if (is_ge(a)) {
k = get_k(a);
return true;
}
else {
return false;
}
}
bool pb_util::is_eq(func_decl *a) const {
return is_decl_of(a, m_fid, OP_PB_EQ);
}
bool pb_util::is_eq(expr* a, rational& k) const {
if (is_eq(a)) {
k = get_k(a);
return true;
}
else {
return false;
}
}
rational pb_util::get_coeff(func_decl* a, unsigned index) const {
if (is_at_most_k(a) || is_at_least_k(a)) {
return rational::one();
}
SASSERT(is_le(a) || is_ge(a) || is_eq(a));
SASSERT(1 + index < a->get_num_parameters());
return to_rational(a->get_parameter(index + 1));
}
rational pb_util::to_rational(parameter const& p) const {
if (p.is_int()) {
return rational(p.get_int());
}
SASSERT(p.is_rational());
return p.get_rational();
}
bool pb_util::has_unit_coefficients(func_decl* f) const {
if (is_at_most_k(f) || is_at_least_k(f)) return true;
unsigned sz = f->get_arity();
for (unsigned i = 0; i < sz; ++i) {
if (!get_coeff(f, i).is_one()) return false;
}
return true;
}

123
src/ast/pb_decl_plugin.h Normal file
View file

@ -0,0 +1,123 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
pb_decl_plugin.h
Abstract:
Pseudo-Boolean and Cardinality Constraints plugin
Author:
Nikolaj Bjorner (nbjorner) 2013-05-11
Notes:
(at-most-k x1 .... x_n) means x1 + ... + x_n <= k
hence:
(not (at-most-k x1 .... x_n)) means x1 + ... + x_n >= k + 1
--*/
#ifndef _PB_DECL_PLUGIN_H_
#define _PB_DECL_PLUGIN_H_
#include"ast.h"
enum pb_op_kind {
OP_AT_MOST_K, // at most K Booleans are true.
OP_AT_LEAST_K, // at least K Booleans are true.
OP_PB_LE, // pseudo-Boolean <= (generalizes at_most_k)
OP_PB_GE, // pseudo-Boolean >=
OP_PB_EQ, // equality
LAST_PB_OP
};
class pb_decl_plugin : public decl_plugin {
symbol m_at_most_sym;
symbol m_at_least_sym;
symbol m_pble_sym;
symbol m_pbge_sym;
symbol m_pbeq_sym;
func_decl * mk_at_most(unsigned arity, unsigned k);
func_decl * mk_at_least(unsigned arity, unsigned k);
func_decl * mk_le(unsigned arity, rational const* coeffs, int k);
func_decl * mk_ge(unsigned arity, rational const* coeffs, int k);
func_decl * mk_eq(unsigned arity, rational const* coeffs, int k);
public:
pb_decl_plugin();
virtual ~pb_decl_plugin() {}
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
UNREACHABLE();
return 0;
}
virtual decl_plugin * mk_fresh() {
return alloc(pb_decl_plugin);
}
//
// Contract for func_decl:
// parameters[0] - integer (at most k elements)
// all sorts are Booleans
// parameters[1] .. parameters[arity] - coefficients
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
};
class pb_util {
ast_manager & m;
family_id m_fid;
public:
pb_util(ast_manager& m):m(m), m_fid(m.mk_family_id("pb")) {}
ast_manager & get_manager() const { return m; }
family_id get_family_id() const { return m_fid; }
app * mk_at_most_k(unsigned num_args, expr * const * args, unsigned k);
app * mk_at_least_k(unsigned num_args, expr * const * args, unsigned k);
app * mk_le(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k);
app * mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k);
app * mk_eq(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k);
app * mk_lt(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k);
bool is_at_most_k(func_decl *a) const;
bool is_at_most_k(expr *a) const { return is_app(a) && is_at_most_k(to_app(a)->get_decl()); }
bool is_at_most_k(expr *a, rational& k) const;
bool is_at_least_k(func_decl *a) const;
bool is_at_least_k(expr *a) const { return is_app(a) && is_at_least_k(to_app(a)->get_decl()); }
bool is_at_least_k(expr *a, rational& k) const;
rational get_k(func_decl *a) const;
rational get_k(expr *a) const { return get_k(to_app(a)->get_decl()); }
bool is_le(func_decl *a) const;
bool is_le(expr *a) const { return is_app(a) && is_le(to_app(a)->get_decl()); }
bool is_le(expr* a, rational& k) const;
bool is_ge(func_decl* a) const;
bool is_ge(expr* a) const { return is_app(a) && is_ge(to_app(a)->get_decl()); }
bool is_ge(expr* a, rational& k) const;
rational get_coeff(expr* a, unsigned index) const { return get_coeff(to_app(a)->get_decl(), index); }
rational get_coeff(func_decl* a, unsigned index) const;
bool has_unit_coefficients(func_decl* f) const;
bool has_unit_coefficients(expr* f) const { return is_app(f) && has_unit_coefficients(to_app(f)->get_decl()); }
bool is_eq(func_decl* f) const;
bool is_eq(expr* e) const { return is_app(e) && is_eq(to_app(e)->get_decl()); }
bool is_eq(expr* e, rational& k) const;
private:
rational to_rational(parameter const& p) const;
};
#endif /* _PB_DECL_PLUGIN_H_ */

View file

@ -25,6 +25,7 @@ Revision History:
#include"dl_decl_plugin.h"
#include"seq_decl_plugin.h"
#include"float_decl_plugin.h"
#include"pb_decl_plugin.h"
void reg_decl_plugins(ast_manager & m) {
if (!m.get_plugin(m.mk_family_id(symbol("arith")))) {
@ -48,4 +49,7 @@ void reg_decl_plugins(ast_manager & m) {
if (!m.get_plugin(m.mk_family_id(symbol("float")))) {
m.register_plugin(symbol("float"), alloc(float_decl_plugin));
}
if (!m.get_plugin(m.mk_family_id(symbol("pb")))) {
m.register_plugin(symbol("pb"), alloc(pb_decl_plugin));
}
}

View file

@ -18,12 +18,9 @@ Revision History:
--*/
#include "ast_counter.h"
#include "var_subst.h"
void counter::update(unsigned el, int delta) {
int & counter = get(el);
SASSERT(!m_stay_non_negative || counter>=0);
SASSERT(!m_stay_non_negative || static_cast<int>(counter)>=-delta);
counter += delta;
}
@ -92,16 +89,14 @@ int counter::get_max_counter_value() const {
void var_counter::count_vars(ast_manager & m, const app * pred, int coef) {
unsigned n = pred->get_num_args();
for (unsigned i = 0; i < n; i++) {
m_sorts.reset();
m_todo.reset();
m_mark.reset();
::get_free_vars(m_mark, m_todo, pred->get_arg(i), m_sorts);
for (unsigned j = 0; j < m_sorts.size(); ++j) {
if (m_sorts[j]) {
m_fv(pred->get_arg(i));
for (unsigned j = 0; j < m_fv.size(); ++j) {
if (m_fv[j]) {
update(j, coef);
}
}
}
m_fv.reset();
}

View file

@ -27,16 +27,16 @@ Revision History:
#include "ast.h"
#include "map.h"
#include "uint_set.h"
#include "var_subst.h"
class counter {
protected:
typedef u_map<int> map_impl;
map_impl m_data;
const bool m_stay_non_negative;
public:
typedef map_impl::iterator iterator;
counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {}
counter() {}
void reset() { m_data.reset(); }
iterator begin() const { return m_data.begin(); }
@ -69,14 +69,13 @@ public:
class var_counter : public counter {
protected:
ptr_vector<sort> m_sorts;
expr_fast_mark1 m_visited;
expr_free_vars m_fv;
ptr_vector<expr> m_todo;
ast_mark m_mark;
unsigned_vector m_scopes;
unsigned get_max_var(bool & has_var);
public:
var_counter(bool stay_non_negative = true): counter(stay_non_negative) {}
var_counter() {}
void count_vars(ast_manager & m, const app * t, int coef = 1);
unsigned get_max_var(expr* e);
unsigned get_next_var(expr* e);
@ -85,11 +84,10 @@ public:
class ast_counter {
typedef obj_map<ast, int> map_impl;
map_impl m_data;
bool m_stay_non_negative;
public:
typedef map_impl::iterator iterator;
ast_counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {}
ast_counter() {}
iterator begin() const { return m_data.begin(); }
iterator end() const { return m_data.end(); }
@ -99,7 +97,6 @@ class ast_counter {
}
void update(ast * el, int delta){
get(el) += delta;
SASSERT(!m_stay_non_negative || get(el) >= 0);
}
void inc(ast * el) { update(el, 1); }

View file

@ -1038,6 +1038,11 @@ void bit_blaster_tpl<Cfg>::mk_ext_rotate_left_right(unsigned sz, expr * const *
mk_rotate_right(sz, a_bits, static_cast<unsigned>(k.get_uint64()), out_bits);
}
else {
//
// Review: a better tuned implementation is possible by using shifts by power of two.
// e.g., looping over the bits of b_bits, then rotate by a power of two depending
// on the bit-position. This would get rid of the mk_urem.
//
expr_ref_vector sz_bits(m());
expr_ref_vector masked_b_bits(m());
expr_ref_vector eqs(m());

View file

@ -60,6 +60,32 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr
UNREACHABLE();
break;
}
case OP_DT_UPDATE_FIELD: {
SASSERT(num_args == 2);
if (!is_app(args[0]) || !m_util.is_constructor(to_app(args[0])))
return BR_FAILED;
app * a = to_app(args[0]);
func_decl * c_decl = a->get_decl();
if (c_decl != m_util.get_accessor_constructor(f)) {
result = a;
return BR_DONE;
}
ptr_vector<func_decl> const * acc = m_util.get_constructor_accessors(c_decl);
SASSERT(acc && acc->size() == a->get_num_args());
unsigned num = acc->size();
ptr_buffer<expr> new_args;
for (unsigned i = 0; i < num; ++i) {
if (f == (*acc)[i]) {
new_args.push_back(args[1]);
}
else {
new_args.push_back(a->get_arg(i));
}
}
result = m().mk_app(c_decl, num, new_args.c_ptr());
return BR_DONE;
}
default:
UNREACHABLE();
}

View file

@ -29,43 +29,39 @@ void expr_safe_replace::insert(expr* src, expr* dst) {
}
void expr_safe_replace::operator()(expr* e, expr_ref& res) {
obj_map<expr,expr*> cache;
ptr_vector<expr> todo, args;
expr_ref_vector refs(m);
todo.push_back(e);
m_todo.push_back(e);
expr* a, *b, *d;
todo.push_back(e);
while (!todo.empty()) {
a = todo.back();
if (cache.contains(a)) {
todo.pop_back();
while (!m_todo.empty()) {
a = m_todo.back();
if (m_cache.contains(a)) {
m_todo.pop_back();
}
else if (m_subst.find(a, b)) {
cache.insert(a, b);
todo.pop_back();
m_cache.insert(a, b);
m_todo.pop_back();
}
else if (is_var(a)) {
cache.insert(a, a);
todo.pop_back();
m_cache.insert(a, a);
m_todo.pop_back();
}
else if (is_app(a)) {
app* c = to_app(a);
unsigned n = c->get_num_args();
args.reset();
m_args.reset();
for (unsigned i = 0; i < n; ++i) {
if (cache.find(c->get_arg(i), d)) {
args.push_back(d);
if (m_cache.find(c->get_arg(i), d)) {
m_args.push_back(d);
}
else {
todo.push_back(c->get_arg(i));
m_todo.push_back(c->get_arg(i));
}
}
if (args.size() == n) {
b = m.mk_app(c->get_decl(), args.size(), args.c_ptr());
refs.push_back(b);
cache.insert(a, b);
todo.pop_back();
if (m_args.size() == n) {
b = m.mk_app(c->get_decl(), m_args.size(), m_args.c_ptr());
m_refs.push_back(b);
m_cache.insert(a, b);
m_todo.pop_back();
}
}
else {
@ -93,12 +89,16 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) {
}
replace(q->get_expr(), new_body);
b = m.update_quantifier(q, pats.size(), pats.c_ptr(), nopats.size(), nopats.c_ptr(), new_body);
refs.push_back(b);
cache.insert(a, b);
todo.pop_back();
m_refs.push_back(b);
m_cache.insert(a, b);
m_todo.pop_back();
}
}
res = cache.find(e);
res = m_cache.find(e);
m_cache.reset();
m_todo.reset();
m_args.reset();
m_refs.reset();
}
void expr_safe_replace::reset() {

View file

@ -29,9 +29,12 @@ class expr_safe_replace {
expr_ref_vector m_src;
expr_ref_vector m_dst;
obj_map<expr, expr*> m_subst;
obj_map<expr,expr*> m_cache;
ptr_vector<expr> m_todo, m_args;
expr_ref_vector m_refs;
public:
expr_safe_replace(ast_manager& m): m(m), m_src(m), m_dst(m) {}
expr_safe_replace(ast_manager& m): m(m), m_src(m), m_dst(m), m_refs(m) {}
void insert(expr* src, expr* dst);
@ -42,6 +45,8 @@ public:
void apply_substitution(expr* s, expr* def, expr_ref& t);
void reset();
bool empty() const { return m_subst.empty(); }
};
#endif /* __EXPR_SAFE_REPLACE_H__ */

View file

@ -0,0 +1,275 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
pb_rewriter.cpp
Abstract:
Basic rewriting rules for PB constraints.
Author:
Nikolaj Bjorner (nbjorner) 2013-14-12
Notes:
--*/
#include "pb_rewriter.h"
#include "pb_rewriter_def.h"
#include "ast_pp.h"
#include "ast_smt_pp.h"
class pb_ast_rewriter_util {
ast_manager& m;
expr_ref_vector m_refs;
public:
typedef std::pair<expr*, rational> arg_t;
typedef vector<arg_t> args_t;
typedef rational numeral;
pb_ast_rewriter_util(ast_manager& m): m(m), m_refs(m) {}
expr* negate(expr* e) {
if (m.is_true(e)) {
return m.mk_false();
}
if (m.is_false(e)) {
return m.mk_true();
}
if (m.is_not(e, e)) {
return e;
}
m_refs.push_back(m.mk_not(e));
return m_refs.back();
}
void display(std::ostream& out, expr* e) {
out << mk_pp(e, m);
}
bool is_negated(expr* e) const {
return m.is_not(e);
}
bool is_true(expr* e) const {
return m.is_true(e);
}
bool is_false(expr* e) const {
return m.is_false(e);
}
struct compare {
bool operator()(std::pair<expr*,rational> const& a,
std::pair<expr*,rational> const& b) {
return a.first->get_id() < b.first->get_id();
}
};
};
expr_ref pb_rewriter::translate_pb2lia(obj_map<expr,expr*>& vars, expr* fml) {
pb_util util(m());
arith_util a(m());
expr_ref result(m()), tmp(m());
expr_ref_vector es(m());
expr*const* args = to_app(fml)->get_args();
unsigned sz = to_app(fml)->get_num_args();
for (unsigned i = 0; i < sz; ++i) {
expr* e = args[i];
if (m().is_not(e, e)) {
es.push_back(a.mk_sub(a.mk_numeral(rational(1),true),vars.find(e)));
}
else {
es.push_back(vars.find(e));
}
}
if (util.is_at_most_k(fml) || util.is_at_least_k(fml)) {
if (es.empty()) {
tmp = a.mk_numeral(rational(0), true);
}
else {
tmp = a.mk_add(es.size(), es.c_ptr());
}
if (util.is_at_most_k(fml)) {
result = a.mk_le(tmp, a.mk_numeral(util.get_k(fml), false));
}
else {
result = a.mk_ge(tmp, a.mk_numeral(util.get_k(fml), false));
}
}
else if (util.is_le(fml) || util.is_ge(fml) || util.is_eq(fml)) {
for (unsigned i = 0; i < sz; ++i) {
es[i] = a.mk_mul(a.mk_numeral(util.get_coeff(fml, i),false), es[i].get());
}
if (es.empty()) {
tmp = a.mk_numeral(rational(0), true);
}
else {
tmp = a.mk_add(es.size(), es.c_ptr());
}
if (util.is_le(fml)) {
result = a.mk_le(tmp, a.mk_numeral(util.get_k(fml), false));
}
else if (util.is_ge(fml)) {
result = a.mk_ge(tmp, a.mk_numeral(util.get_k(fml), false));
}
else {
result = m().mk_eq(tmp, a.mk_numeral(util.get_k(fml), false));
}
}
else {
result = fml;
}
return result;
}
expr_ref pb_rewriter::mk_validate_rewrite(app_ref& e1, app_ref& e2) {
ast_manager& m = e1.get_manager();
arith_util a(m);
symbol name;
obj_map<expr,expr*> vars;
expr_ref_vector trail(m), fmls(m);
unsigned sz = to_app(e1)->get_num_args();
expr*const*args = to_app(e1)->get_args();
for (unsigned i = 0; i < sz; ++i) {
expr* e = args[i];
if (m.is_true(e)) {
if (!vars.contains(e)) {
trail.push_back(a.mk_numeral(rational(1), true));
vars.insert(e, trail.back());
}
continue;
}
if (m.is_false(e)) {
if (!vars.contains(e)) {
trail.push_back(a.mk_numeral(rational(0), true));
vars.insert(e, trail.back());
}
continue;
}
std::ostringstream strm;
strm << "x" << i;
name = symbol(strm.str().c_str());
trail.push_back(m.mk_const(name, a.mk_int()));
expr* x = trail.back();
m.is_not(e,e);
vars.insert(e, x);
fmls.push_back(a.mk_le(a.mk_numeral(rational(0), true), x));
fmls.push_back(a.mk_le(x, a.mk_numeral(rational(1), true)));
}
expr_ref tmp(m);
expr_ref fml1 = translate_pb2lia(vars, e1);
expr_ref fml2 = translate_pb2lia(vars, e2);
tmp = m.mk_not(m.mk_eq(fml1, fml2));
fmls.push_back(tmp);
tmp = m.mk_and(fmls.size(), fmls.c_ptr());
return tmp;
}
static unsigned s_lemma = 0;
void pb_rewriter::validate_rewrite(func_decl* f, unsigned sz, expr*const* args, expr_ref& fml) {
ast_manager& m = fml.get_manager();
app_ref tmp1(m), tmp2(m);
tmp1 = m.mk_app(f, sz, args);
tmp2 = to_app(fml);
expr_ref tmp = mk_validate_rewrite(tmp1, tmp2);
dump_pb_rewrite(tmp);
}
void pb_rewriter::dump_pb_rewrite(expr* fml) {
std::ostringstream strm;
strm << "pb_rewrite_" << (s_lemma++) << ".smt2";
std::ofstream out(strm.str().c_str());
ast_smt_pp pp(m());
pp.display_smt2(out, fml);
out.close();
}
br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
ast_manager& m = result.get_manager();
rational sum(0), maxsum(0);
for (unsigned i = 0; i < num_args; ++i) {
if (m.is_true(args[i])) {
sum += m_util.get_coeff(f, i);
maxsum += m_util.get_coeff(f, i);
}
else if (!m.is_false(args[i])) {
maxsum += m_util.get_coeff(f, i);
}
}
rational k = m_util.get_k(f);
vector<std::pair<expr*,rational> > vec;
for (unsigned i = 0; i < num_args; ++i) {
vec.push_back(std::make_pair(args[i], m_util.get_coeff(f, i)));
}
switch(f->get_decl_kind()) {
case OP_AT_MOST_K:
case OP_PB_LE:
for (unsigned i = 0; i < num_args; ++i) {
vec[i].second.neg();
}
k.neg();
break;
case OP_AT_LEAST_K:
case OP_PB_GE:
case OP_PB_EQ:
break;
default:
UNREACHABLE();
return BR_FAILED;
}
bool is_eq = f->get_decl_kind() == OP_PB_EQ;
pb_ast_rewriter_util pbu(m);
pb_rewriter_util<pb_ast_rewriter_util> util(pbu);
util.unique(vec, k, is_eq);
lbool is_sat = util.normalize(vec, k, is_eq);
util.prune(vec, k, is_eq);
switch (is_sat) {
case l_true:
result = m.mk_true();
break;
case l_false:
result = m.mk_false();
break;
default:
m_args.reset();
m_coeffs.reset();
for (unsigned i = 0; i < vec.size(); ++i) {
m_args.push_back(vec[i].first);
m_coeffs.push_back(vec[i].second);
}
if (is_eq) {
result = m_util.mk_eq(vec.size(), m_coeffs.c_ptr(), m_args.c_ptr(), k);
}
else {
result = m_util.mk_ge(vec.size(), m_coeffs.c_ptr(), m_args.c_ptr(), k);
}
break;
}
TRACE("pb",
expr_ref tmp(m);
tmp = m.mk_app(f, num_args, args);
tout << tmp << "\n";
tout << result << "\n";
);
TRACE("pb_validate",
validate_rewrite(f, num_args, args, result););
return BR_DONE;
}

View file

@ -0,0 +1,65 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
pb_rewriter.h
Abstract:
Basic rewriting rules for PB constraints.
Author:
Nikolaj Bjorner (nbjorner) 2013-14-12
Notes:
--*/
#ifndef _PB_REWRITER_H_
#define _PB_REWRITER_H_
#include"pb_decl_plugin.h"
#include"rewriter_types.h"
#include"params.h"
#include"lbool.h"
template<typename PBU>
class pb_rewriter_util {
PBU& m_util;
void display(std::ostream& out, typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq);
public:
pb_rewriter_util(PBU& u) : m_util(u) {}
void unique(typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq);
lbool normalize(typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq);
void prune(typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq);
};
/**
\brief Cheap rewrite rules for PB constraints
*/
class pb_rewriter {
pb_util m_util;
vector<rational> m_coeffs;
ptr_vector<expr> m_args;
void validate_rewrite(func_decl* f, unsigned sz, expr*const* args, expr_ref& fml);
public:
pb_rewriter(ast_manager & m, params_ref const & p = params_ref()):
m_util(m) {
}
ast_manager & m() const { return m_util.get_manager(); }
family_id get_fid() const { return m_util.get_family_id(); }
void updt_params(params_ref const & p) {}
static void get_param_descrs(param_descrs & r) {}
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
expr_ref translate_pb2lia(obj_map<expr,expr*>& vars, expr* fml);
expr_ref mk_validate_rewrite(app_ref& e1, app_ref& e2);
void dump_pb_rewrite(expr* fml);
};
#endif

View file

@ -0,0 +1,298 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
pb_rewriter_def.h
Abstract:
Basic rewriting rules for PB constraints.
Author:
Nikolaj Bjorner (nbjorner) 2013-14-12
Notes:
--*/
#ifndef _PB_REWRITER_DEF_H_
#define _PB_REWRITER_DEF_H_
#include"pb_rewriter.h"
template<typename PBU>
void pb_rewriter_util<PBU>::display(std::ostream& out, typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq) {
for (unsigned i = 0; i < args.size(); ++i) {
out << args[i].second << " * ";
m_util.display(out, args[i].first);
out << " ";
if (i+1 < args.size()) out << "+ ";
}
out << (is_eq?" = ":" >= ") << k << "\n";
}
template<typename PBU>
void pb_rewriter_util<PBU>::unique(typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq) {
TRACE("pb_verbose", display(tout << "pre-unique:", args, k, is_eq););
for (unsigned i = 0; i < args.size(); ++i) {
if (m_util.is_negated(args[i].first)) {
args[i].first = m_util.negate(args[i].first);
k -= args[i].second;
args[i].second = -args[i].second;
}
}
// remove constants
for (unsigned i = 0; i < args.size(); ++i) {
if (m_util.is_true(args[i].first)) {
k -= args[i].second;
std::swap(args[i], args[args.size()-1]);
args.pop_back();
--i;
}
else if (m_util.is_false(args[i].first)) {
std::swap(args[i], args[args.size()-1]);
args.pop_back();
--i;
}
}
// sort and coalesce arguments:
typename PBU::compare cmp;
std::sort(args.begin(), args.end(), cmp);
// coallesce
unsigned i, j;
for (i = 0, j = 1; j < args.size(); ++j) {
if (args[i].first == args[j].first) {
args[i].second += args[j].second;
}
else {
++i;
args[i] = args[j];
}
}
args.resize(i+1);
// remove 0s.
for (i = 0, j = 0; j < args.size(); ++j) {
if (!args[j].second.is_zero()) {
if (i != j) {
args[i] = args[j];
}
++i;
}
}
args.resize(i);
TRACE("pb_verbose", display(tout << "post-unique:", args, k, is_eq););
}
template<typename PBU>
lbool pb_rewriter_util<PBU>::normalize(typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq) {
TRACE("pb_verbose", display(tout << "pre-normalize:", args, k, is_eq););
DEBUG_CODE(
bool found = false;
for (unsigned i = 0; !found && i < args.size(); ++i) {
found = args[i].second.is_zero();
}
if (found) display(verbose_stream(), args, k, is_eq);
SASSERT(!found););
//
// Ensure all coefficients are positive:
// c*l + y >= k
// <=>
// c*(1-~l) + y >= k
// <=>
// c - c*~l + y >= k
// <=>
// -c*~l + y >= k - c
//
typename PBU::numeral sum(0);
for (unsigned i = 0; i < args.size(); ++i) {
typename PBU::numeral c = args[i].second;
if (c.is_neg()) {
args[i].second = -c;
args[i].first = m_util.negate(args[i].first);
k -= c;
}
sum += args[i].second;
}
// detect tautologies:
if (!is_eq && k <= PBU::numeral::zero()) {
args.reset();
k = PBU::numeral::zero();
return l_true;
}
if (is_eq && k.is_zero() && args.empty()) {
return l_true;
}
// detect infeasible constraints:
if (sum < k) {
args.reset();
k = PBU::numeral::one();
return l_false;
}
if (is_eq && k == sum) {
for (unsigned i = 0; i < args.size(); ++i) {
args[i].second = PBU::numeral::one();
}
typename PBU::numeral num(args.size());
k = num;
return l_undef;
}
bool all_int = true;
for (unsigned i = 0; all_int && i < args.size(); ++i) {
all_int = args[i].second.is_int();
}
if (!all_int) {
// normalize to integers.
typename PBU::numeral d(denominator(k));
for (unsigned i = 0; i < args.size(); ++i) {
d = lcm(d, denominator(args[i].second));
}
SASSERT(!d.is_one());
k *= d;
for (unsigned i = 0; i < args.size(); ++i) {
args[i].second *= d;
}
}
if (is_eq) {
TRACE("pb_verbose", display(tout << "post-normalize:", args, k, is_eq););
return l_undef;
}
// Ensure the largest coefficient is not larger than k:
sum = PBU::numeral::zero();
for (unsigned i = 0; i < args.size(); ++i) {
typename PBU::numeral c = args[i].second;
if (c > k) {
args[i].second = k;
}
sum += args[i].second;
}
SASSERT(!args.empty());
// normalize tight inequalities to unit coefficients.
if (sum == k) {
for (unsigned i = 0; i < args.size(); ++i) {
args[i].second = PBU::numeral::one();
}
typename PBU::numeral num(args.size());
k = num;
}
// apply cutting plane reduction:
typename PBU::numeral g(0);
for (unsigned i = 0; !g.is_one() && i < args.size(); ++i) {
typename PBU::numeral c = args[i].second;
if (c != k) {
if (g.is_zero()) {
g = c;
}
else {
g = gcd(g, c);
}
}
}
if (g.is_zero()) {
// all coefficients are equal to k.
for (unsigned i = 0; i < args.size(); ++i) {
SASSERT(args[i].second == k);
args[i].second = PBU::numeral::one();
}
k = PBU::numeral::one();
}
else if (g > PBU::numeral::one()) {
//
// Example 5x + 5y + 2z + 2u >= 5
// becomes 3x + 3y + z + u >= 3
//
typename PBU::numeral k_new = div(k, g);
if (!(k % g).is_zero()) { // k_new is the ceiling of k / g.
k_new++;
}
for (unsigned i = 0; i < args.size(); ++i) {
SASSERT(args[i].second.is_pos());
typename PBU::numeral c = args[i].second;
if (c == k) {
c = k_new;
}
else {
c = div(c, g);
}
args[i].second = c;
SASSERT(args[i].second.is_pos());
}
k = k_new;
}
//
// normalize coefficients that fall within a range
// k/n <= ... < k/(n-1) for some n = 1,2,...
//
// e.g, k/n <= min <= max < k/(n-1)
// k/min <= n, n-1 < k/max
// . floor(k/max) = ceil(k/min) - 1
// . floor(k/max) < k/max
//
// example: k = 5, min = 3, max = 4: 5/3 -> 2 5/4 -> 1, n = 2
// replace all coefficients by 1, and k by 2.
//
if (!k.is_one()) {
typename PBU::numeral min = args[0].second, max = args[0].second;
for (unsigned i = 1; i < args.size(); ++i) {
if (args[i].second < min) min = args[i].second;
if (args[i].second > max) max = args[i].second;
}
SASSERT(min.is_pos());
typename PBU::numeral n0 = k/max;
typename PBU::numeral n1 = floor(n0);
typename PBU::numeral n2 = ceil(k/min) - PBU::numeral::one();
if (n1 == n2 && !n0.is_int()) {
IF_VERBOSE(3, display(verbose_stream() << "set cardinality\n", args, k, is_eq););
for (unsigned i = 0; i < args.size(); ++i) {
args[i].second = PBU::numeral::one();
}
k = n1 + PBU::numeral::one();
}
}
TRACE("pb_verbose", display(tout << "post-normalize:", args, k, is_eq););
return l_undef;
}
template<typename PBU>
void pb_rewriter_util<PBU>::prune(typename PBU::args_t& args, typename PBU::numeral& k, bool is_eq) {
if (is_eq) {
return;
}
typename PBU::numeral nlt(0);
unsigned occ = 0;
for (unsigned i = 0; nlt < k && i < args.size(); ++i) {
if (args[i].second < k) {
nlt += args[i].second;
++occ;
}
}
if (0 < occ && nlt < k) {
for (unsigned i = 0; i < args.size(); ++i) {
if (args[i].second < k) {
args[i] = args.back();
args.pop_back();
--i;
}
}
unique(args, k, is_eq);
normalize(args, k, is_eq);
}
}
#endif

View file

@ -34,6 +34,8 @@ void poly_rewriter<Config>::updt_params(params_ref const & _p) {
m_hoist_mul = p.hoist_mul();
m_hoist_cmul = p.hoist_cmul();
m_som_blowup = p.som_blowup();
if (!m_flat) m_som = false;
if (m_som) m_hoist_mul = false;
}
template<typename Config>

View file

@ -25,6 +25,7 @@ Notes:
#include"array_rewriter.h"
#include"float_rewriter.h"
#include"dl_rewriter.h"
#include"pb_rewriter.h"
#include"rewriter_def.h"
#include"expr_substitution.h"
#include"ast_smt2_pp.h"
@ -41,6 +42,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
datatype_rewriter m_dt_rw;
float_rewriter m_f_rw;
dl_rewriter m_dl_rw;
pb_rewriter m_pb_rw;
arith_util m_a_util;
bv_util m_bv_util;
unsigned long long m_max_memory; // in bytes
@ -196,6 +198,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
return m_f_rw.mk_app_core(f, num, args, result);
if (fid == m_dl_rw.get_fid())
return m_dl_rw.mk_app_core(f, num, args, result);
if (fid == m_pb_rw.get_fid())
return m_pb_rw.mk_app_core(f, num, args, result);
return BR_FAILED;
}
@ -645,6 +649,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
m_dt_rw(m),
m_f_rw(m, p),
m_dl_rw(m),
m_pb_rw(m),
m_a_util(m),
m_bv_util(m),
m_used_dependencies(m),

View file

@ -164,7 +164,7 @@ void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref
tout << "\n----->\n" << mk_ismt2_pp(result, m) << "\n";);
}
static void get_free_vars_offset(ast_mark& mark, ptr_vector<expr>& todo, unsigned offset, expr* e, ptr_vector<sort>& sorts) {
static void get_free_vars_offset(expr_sparse_mark& mark, ptr_vector<expr>& todo, unsigned offset, expr* e, ptr_vector<sort>& sorts) {
todo.push_back(e);
while (!todo.empty()) {
e = todo.back();
@ -176,7 +176,7 @@ static void get_free_vars_offset(ast_mark& mark, ptr_vector<expr>& todo, unsigne
switch(e->get_kind()) {
case AST_QUANTIFIER: {
quantifier* q = to_quantifier(e);
ast_mark mark1;
expr_sparse_mark mark1;
ptr_vector<expr> todo1;
get_free_vars_offset(mark1, todo1, offset+q->get_num_decls(), q->get_expr(), sorts);
break;
@ -210,11 +210,33 @@ static void get_free_vars_offset(ast_mark& mark, ptr_vector<expr>& todo, unsigne
void get_free_vars(expr* e, ptr_vector<sort>& sorts) {
ast_mark mark;
expr_sparse_mark mark;
ptr_vector<expr> todo;
get_free_vars_offset(mark, todo, 0, e, sorts);
}
void get_free_vars(ast_mark& mark, ptr_vector<expr>& todo, expr* e, ptr_vector<sort>& sorts) {
void get_free_vars(expr_sparse_mark& mark, ptr_vector<expr>& todo, expr* e, ptr_vector<sort>& sorts) {
get_free_vars_offset(mark, todo, 0, e, sorts);
}
void expr_free_vars::reset() {
m_mark.reset();
m_sorts.reset();
SASSERT(m_todo.empty());
}
void expr_free_vars::set_default_sort(sort *s) {
for (unsigned i = 0; i < m_sorts.size(); ++i) {
if (!m_sorts[i]) m_sorts[i] = s;
}
}
void expr_free_vars::operator()(expr* e) {
reset();
get_free_vars_offset(m_mark, m_todo, 0, e, m_sorts);
}
void expr_free_vars::accumulate(expr* e) {
SASSERT(m_todo.empty());
get_free_vars_offset(m_mark, m_todo, 0, e, m_sorts);
}

View file

@ -81,9 +81,23 @@ void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref
Return the sorts of the free variables.
*/
void get_free_vars(expr* e, ptr_vector<sort>& sorts);
void get_free_vars(ast_mark& mark, ptr_vector<expr>& todo, expr* e, ptr_vector<sort>& sorts);
class expr_free_vars {
expr_sparse_mark m_mark;
ptr_vector<sort> m_sorts;
ptr_vector<expr> m_todo;
public:
void reset();
void operator()(expr* e);
void accumulate(expr* e);
bool empty() const { return m_sorts.empty(); }
unsigned size() const { return m_sorts.size(); }
sort* operator[](unsigned idx) const { return m_sorts[idx]; }
bool contains(unsigned idx) const { return idx < m_sorts.size() && m_sorts[idx] != 0; }
void set_default_sort(sort* s);
void reverse() { m_sorts.reverse(); }
sort*const* c_ptr() const { return m_sorts.c_ptr(); }
};
#endif

View file

@ -20,21 +20,32 @@ Notes:
#define _BASE_SIMPLIFIER_H_
#include"expr_map.h"
#include"ast_pp.h"
/**
\brief Implements basic functionality used by expression simplifiers.
*/
class base_simplifier {
protected:
ast_manager & m_manager;
ast_manager & m;
expr_map m_cache;
ptr_vector<expr> m_todo;
void cache_result(expr * n, expr * r, proof * p) { m_cache.insert(n, r, p); }
void cache_result(expr * n, expr * r, proof * p) {
m_cache.insert(n, r, p);
CTRACE("simplifier", !is_rewrite_proof(n, r, p),
tout << mk_pp(n, m) << "\n";
tout << mk_pp(r, m) << "\n";
tout << mk_pp(p, m) << "\n";);
SASSERT(is_rewrite_proof(n, r, p));
}
void reset_cache() { m_cache.reset(); }
void flush_cache() { m_cache.flush(); }
void get_cached(expr * n, expr * & r, proof * & p) const { m_cache.get(n, r, p); }
void reinitialize() { m_cache.set_store_proofs(m.fine_grain_proofs()); }
void visit(expr * n, bool & visited) {
if (!is_cached(n)) {
m_todo.push_back(n);
@ -44,11 +55,22 @@ protected:
public:
base_simplifier(ast_manager & m):
m_manager(m),
m(m),
m_cache(m, m.fine_grain_proofs()) {
}
bool is_cached(expr * n) const { return m_cache.contains(n); }
ast_manager & get_manager() { return m_manager; }
ast_manager & get_manager() { return m; }
bool is_rewrite_proof(expr* n, expr* r, proof* p) {
if (p &&
!m.is_undef_proof(p) &&
!(m.has_fact(p) &&
(m.is_eq(m.get_fact(p)) || m.is_oeq(m.get_fact(p)) || m.is_iff(m.get_fact(p))) &&
to_app(m.get_fact(p))->get_arg(0) == n &&
to_app(m.get_fact(p))->get_arg(1) == r)) return false;
return (!m.fine_grain_proofs() || p || (n == r));
}
};
#endif /* _BASE_SIMPLIFIER_H_ */

View file

@ -100,11 +100,11 @@ bool bv_elim_star::visit_quantifier(quantifier* q) {
}
void bv_elim_star::reduce1_quantifier(quantifier* q) {
quantifier_ref r(m_manager);
proof_ref pr(m_manager);
quantifier_ref r(m);
proof_ref pr(m);
m_bv_elim.elim(q, r);
if (m_manager.fine_grain_proofs()) {
pr = m_manager.mk_rewrite(q, r.get());
if (m.fine_grain_proofs()) {
pr = m.mk_rewrite(q, r.get());
}
else {
pr = 0;

View file

@ -81,6 +81,8 @@ bool datatype_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr *
}
UNREACHABLE();
}
case OP_DT_UPDATE_FIELD:
return false;
default:
UNREACHABLE();
}

View file

@ -203,20 +203,20 @@ void elim_bounds_star::reduce1_quantifier(quantifier * q) {
cache_result(q, q, 0);
return;
}
quantifier_ref new_q(m_manager);
quantifier_ref new_q(m);
expr * new_body = 0;
proof * new_pr;
get_cached(q->get_expr(), new_body, new_pr);
new_q = m_manager.update_quantifier(q, new_body);
expr_ref r(m_manager);
new_q = m.update_quantifier(q, new_body);
expr_ref r(m);
m_elim(new_q, r);
if (q == r.get()) {
cache_result(q, q, 0);
return;
}
proof_ref pr(m_manager);
if (m_manager.fine_grain_proofs())
pr = m_manager.mk_rewrite(q, r); // TODO: improve justification
proof_ref pr(m);
if (m.fine_grain_proofs())
pr = m.mk_rewrite(q, r); // TODO: improve justification
cache_result(q, r, pr);
}

View file

@ -187,7 +187,7 @@ pull_ite_tree_star::pull_ite_tree_star(ast_manager & m, simplifier & s):
bool pull_ite_tree_star::get_subst(expr * n, expr_ref & r, proof_ref & p) {
if (is_app(n) && is_target(to_app(n))) {
app_ref tmp(m_manager);
app_ref tmp(m);
m_proc(to_app(n), tmp, p);
r = tmp;
return true;
@ -199,10 +199,10 @@ bool pull_cheap_ite_tree_star::is_target(app * n) const {
bool r =
n->get_num_args() == 2 &&
n->get_family_id() != null_family_id &&
m_manager.is_bool(n) &&
(m_manager.is_value(n->get_arg(0)) || m_manager.is_value(n->get_arg(1))) &&
(m_manager.is_term_ite(n->get_arg(0)) || m_manager.is_term_ite(n->get_arg(1)));
TRACE("pull_ite_target", tout << mk_pp(n, m_manager) << "\nresult: " << r << "\n";);
m.is_bool(n) &&
(m.is_value(n->get_arg(0)) || m.is_value(n->get_arg(1))) &&
(m.is_term_ite(n->get_arg(0)) || m.is_term_ite(n->get_arg(1)));
TRACE("pull_ite_target", tout << mk_pp(n, m) << "\nresult: " << r << "\n";);
return r;
}

View file

@ -34,7 +34,7 @@ push_app_ite::~push_app_ite() {
int push_app_ite::has_ite_arg(unsigned num_args, expr * const * args) {
for (unsigned i = 0; i < num_args; i++)
if (m_manager.is_ite(args[i]))
if (m.is_ite(args[i]))
return i;
return -1;
}
@ -53,10 +53,10 @@ void push_app_ite::apply(func_decl * decl, unsigned num_args, expr * const * arg
expr ** args_prime = const_cast<expr**>(args);
expr * old = args_prime[ite_arg_idx];
args_prime[ite_arg_idx] = t;
expr_ref t_new(m_manager);
expr_ref t_new(m);
apply(decl, num_args, args_prime, t_new);
args_prime[ite_arg_idx] = e;
expr_ref e_new(m_manager);
expr_ref e_new(m);
apply(decl, num_args, args_prime, e_new);
args_prime[ite_arg_idx] = old;
expr * new_args[3] = { c, t_new, e_new };
@ -67,11 +67,11 @@ void push_app_ite::apply(func_decl * decl, unsigned num_args, expr * const * arg
\brief Default (conservative) implementation. Return true if there one and only one ite-term argument.
*/
bool push_app_ite::is_target(func_decl * decl, unsigned num_args, expr * const * args) {
if (m_manager.is_ite(decl))
if (m.is_ite(decl))
return false;
bool found_ite = false;
for (unsigned i = 0; i < num_args; i++) {
if (m_manager.is_ite(args[i]) && !m_manager.is_bool(args[i])) {
if (m.is_ite(args[i]) && !m.is_bool(args[i])) {
if (found_ite) {
if (m_conservative)
return false;
@ -83,7 +83,7 @@ bool push_app_ite::is_target(func_decl * decl, unsigned num_args, expr * const *
}
CTRACE("push_app_ite", found_ite, tout << "found target for push app ite:\n";
tout << decl->get_name();
for (unsigned i = 0; i < num_args; i++) tout << " " << mk_pp(args[i], m_manager);
for (unsigned i = 0; i < num_args; i++) tout << " " << mk_pp(args[i], m);
tout << "\n";);
return found_ite;
}
@ -94,19 +94,19 @@ void push_app_ite::operator()(expr * s, expr_ref & r, proof_ref & p) {
reduce_core(s);
get_cached(s, result, result_proof);
r = result;
switch (m_manager.proof_mode()) {
switch (m.proof_mode()) {
case PGM_DISABLED:
p = m_manager.mk_undef_proof();
p = m.mk_undef_proof();
break;
case PGM_COARSE:
if (result == s)
p = m_manager.mk_reflexivity(s);
p = m.mk_reflexivity(s);
else
p = m_manager.mk_rewrite_star(s, result, 0, 0);
p = m.mk_rewrite_star(s, result, 0, 0);
break;
case PGM_FINE:
if (result == s)
p = m_manager.mk_reflexivity(s);
p = m.mk_reflexivity(s);
else
p = result_proof;
break;
@ -171,24 +171,24 @@ void push_app_ite::reduce1_app(app * n) {
m_args.reset();
func_decl * decl = n->get_decl();
proof_ref p1(m_manager);
proof_ref p1(m);
get_args(n, m_args, p1);
expr_ref r(m_manager);
expr_ref r(m);
if (is_target(decl, m_args.size(), m_args.c_ptr()))
apply(decl, m_args.size(), m_args.c_ptr(), r);
else
mk_app(decl, m_args.size(), m_args.c_ptr(), r);
if (!m_manager.fine_grain_proofs())
if (!m.fine_grain_proofs())
cache_result(n, r, 0);
else {
expr * s = m_manager.mk_app(decl, m_args.size(), m_args.c_ptr());
expr * s = m.mk_app(decl, m_args.size(), m_args.c_ptr());
proof * p;
if (n == r)
p = 0;
else if (r != s)
p = m_manager.mk_transitivity(p1, m_manager.mk_rewrite(s, r));
p = m.mk_transitivity(p1, m.mk_rewrite(s, r));
else
p = p1;
cache_result(n, r, p);
@ -200,8 +200,8 @@ void push_app_ite::reduce1_quantifier(quantifier * q) {
proof * new_body_pr;
get_cached(q->get_expr(), new_body, new_body_pr);
quantifier * new_q = m_manager.update_quantifier(q, new_body);
proof * p = q == new_q ? 0 : m_manager.mk_quant_intro(q, new_q, new_body_pr);
quantifier * new_q = m.update_quantifier(q, new_body);
proof * p = q == new_q ? 0 : m.mk_quant_intro(q, new_q, new_body_pr);
cache_result(q, new_q, p);
}

View file

@ -61,16 +61,18 @@ void simplifier::enable_ac_support(bool flag) {
*/
void simplifier::operator()(expr * s, expr_ref & r, proof_ref & p) {
m_need_reset = true;
reinitialize();
expr * s_orig = s;
expr * old_s;
expr * result;
proof * result_proof;
switch (m_manager.proof_mode()) {
switch (m.proof_mode()) {
case PGM_DISABLED: // proof generation is disabled.
reduce_core(s);
// after executing reduce_core, the result of the simplification is in the cache
get_cached(s, result, result_proof);
r = result;
p = m_manager.mk_undef_proof();
p = m.mk_undef_proof();
break;
case PGM_COARSE: // coarse proofs... in this case, we do not produce a step by step (fine grain) proof to show the equivalence (or equisatisfiability) of s an r.
m_subst_proofs.reset(); // m_subst_proofs is an auxiliary vector that is used to justify substitutions. See comment on method get_subst.
@ -78,10 +80,10 @@ void simplifier::operator()(expr * s, expr_ref & r, proof_ref & p) {
get_cached(s, result, result_proof);
r = result;
if (result == s)
p = m_manager.mk_reflexivity(s);
p = m.mk_reflexivity(s);
else {
remove_duplicates(m_subst_proofs);
p = m_manager.mk_rewrite_star(s, result, m_subst_proofs.size(), m_subst_proofs.c_ptr());
p = m.mk_rewrite_star(s, result, m_subst_proofs.size(), m_subst_proofs.c_ptr());
}
break;
case PGM_FINE: // fine grain proofs... in this mode, every proof step (or most of them) is described.
@ -90,17 +92,20 @@ void simplifier::operator()(expr * s, expr_ref & r, proof_ref & p) {
// keep simplyfing until no further simplifications are possible.
while (s != old_s) {
TRACE("simplifier", tout << "simplification pass... " << s->get_id() << "\n";);
TRACE("simplifier_loop", tout << mk_ll_pp(s, m_manager) << "\n";);
TRACE("simplifier_loop", tout << mk_ll_pp(s, m) << "\n";);
reduce_core(s);
get_cached(s, result, result_proof);
if (result_proof != 0)
SASSERT(is_rewrite_proof(s, result, result_proof));
if (result_proof != 0) {
m_proofs.push_back(result_proof);
}
old_s = s;
s = result;
}
SASSERT(s != 0);
r = s;
p = m_proofs.empty() ? m_manager.mk_reflexivity(s) : m_manager.mk_transitivity(m_proofs.size(), m_proofs.c_ptr());
p = m_proofs.empty() ? m.mk_reflexivity(s) : m.mk_transitivity(m_proofs.size(), m_proofs.c_ptr());
SASSERT(is_rewrite_proof(s_orig, r, p));
break;
default:
UNREACHABLE();
@ -259,9 +264,9 @@ void simplifier::reduce1(expr * n) {
specific simplifications via plugins.
*/
void simplifier::reduce1_app(app * n) {
expr_ref r(m_manager);
proof_ref p(m_manager);
TRACE("reduce", tout << "reducing...\n" << mk_pp(n, m_manager) << "\n";);
expr_ref r(m);
proof_ref p(m);
TRACE("reduce", tout << "reducing...\n" << mk_pp(n, m) << "\n";);
if (get_subst(n, r, p)) {
TRACE("reduce", tout << "applying substitution...\n";);
cache_result(n, r, p);
@ -279,7 +284,7 @@ void simplifier::reduce1_app(app * n) {
void simplifier::reduce1_app_core(app * n) {
m_args.reset();
func_decl * decl = n->get_decl();
proof_ref p1(m_manager);
proof_ref p1(m);
// Stores the new arguments of n in m_args.
// Let n be of the form
// (decl arg_0 ... arg_{n-1})
@ -296,23 +301,23 @@ void simplifier::reduce1_app_core(app * n) {
// If none of the arguments have been simplified, and n is not a theory symbol,
// Then no simplification is possible, and we can cache the result of the simplification of n as n.
if (has_new_args || decl->get_family_id() != null_family_id) {
expr_ref r(m_manager);
TRACE("reduce", tout << "reduce1_app\n"; for(unsigned i = 0; i < m_args.size(); i++) tout << mk_ll_pp(m_args[i], m_manager););
expr_ref r(m);
TRACE("reduce", tout << "reduce1_app\n"; for(unsigned i = 0; i < m_args.size(); i++) tout << mk_ll_pp(m_args[i], m););
// the method mk_app invokes get_subst and plugins to simplify
// (decl arg_0' ... arg_{n-1}')
mk_app(decl, m_args.size(), m_args.c_ptr(), r);
if (!m_manager.fine_grain_proofs()) {
if (!m.fine_grain_proofs()) {
cache_result(n, r, 0);
}
else {
expr * s = m_manager.mk_app(decl, m_args.size(), m_args.c_ptr());
expr * s = m.mk_app(decl, m_args.size(), m_args.c_ptr());
proof * p;
if (n == r)
p = 0;
else if (r != s)
// we use a "theory rewrite generic proof" to justify the step
// s = (decl arg_0' ... arg_{n-1}') --> r
p = m_manager.mk_transitivity(p1, m_manager.mk_rewrite(s, r));
p = m.mk_transitivity(p1, m.mk_rewrite(s, r));
else
p = p1;
cache_result(n, r, p);
@ -354,11 +359,11 @@ bool is_ac_vector(app * n) {
}
void simplifier::reduce1_ac_app_core(app * n) {
app_ref n_c(m_manager);
proof_ref p1(m_manager);
app_ref n_c(m);
proof_ref p1(m);
mk_ac_congruent_term(n, n_c, p1);
TRACE("ac", tout << "expr:\n" << mk_pp(n, m_manager) << "\ncongruent term:\n" << mk_pp(n_c, m_manager) << "\n";);
expr_ref r(m_manager);
TRACE("ac", tout << "expr:\n" << mk_pp(n, m) << "\ncongruent term:\n" << mk_pp(n_c, m) << "\n";);
expr_ref r(m);
func_decl * decl = n->get_decl();
family_id fid = decl->get_family_id();
plugin * p = get_plugin(fid);
@ -376,7 +381,7 @@ void simplifier::reduce1_ac_app_core(app * n) {
// done...
}
else {
r = m_manager.mk_app(decl, m_args.size(), m_args.c_ptr());
r = m.mk_app(decl, m_args.size(), m_args.c_ptr());
}
}
else {
@ -385,7 +390,7 @@ void simplifier::reduce1_ac_app_core(app * n) {
get_ac_args(n_c, m_args, m_mults);
TRACE("ac", tout << "AC args:\n";
for (unsigned i = 0; i < m_args.size(); i++) {
tout << mk_pp(m_args[i], m_manager) << " * " << m_mults[i] << "\n";
tout << mk_pp(m_args[i], m) << " * " << m_mults[i] << "\n";
});
if (p != 0 && p->reduce(decl, m_args.size(), m_mults.c_ptr(), m_args.c_ptr(), r)) {
// done...
@ -393,12 +398,12 @@ void simplifier::reduce1_ac_app_core(app * n) {
else {
ptr_buffer<expr> new_args;
expand_args(m_args.size(), m_mults.c_ptr(), m_args.c_ptr(), new_args);
r = m_manager.mk_app(decl, new_args.size(), new_args.c_ptr());
r = m.mk_app(decl, new_args.size(), new_args.c_ptr());
}
}
TRACE("ac", tout << "AC result:\n" << mk_pp(r, m_manager) << "\n";);
TRACE("ac", tout << "AC result:\n" << mk_pp(r, m) << "\n";);
if (!m_manager.fine_grain_proofs()) {
if (!m.fine_grain_proofs()) {
cache_result(n, r, 0);
}
else {
@ -406,7 +411,7 @@ void simplifier::reduce1_ac_app_core(app * n) {
if (n == r.get())
p = 0;
else if (r.get() != n_c.get())
p = m_manager.mk_transitivity(p1, m_manager.mk_rewrite(n_c, r));
p = m.mk_transitivity(p1, m.mk_rewrite(n_c, r));
else
p = p1;
cache_result(n, r, p);
@ -416,8 +421,8 @@ void simplifier::reduce1_ac_app_core(app * n) {
static unsigned g_rewrite_lemma_id = 0;
void simplifier::dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr * const * args, expr* result) {
expr_ref arg(m_manager);
arg = m_manager.mk_app(decl, num_args, args);
expr_ref arg(m);
arg = m.mk_app(decl, num_args, args);
if (arg.get() != result) {
char buffer[128];
#ifdef _WINDOWS
@ -425,11 +430,11 @@ void simplifier::dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr *
#else
sprintf(buffer, "rewrite_lemma_%d.smt", g_rewrite_lemma_id);
#endif
ast_smt_pp pp(m_manager);
ast_smt_pp pp(m);
pp.set_benchmark_name("rewrite_lemma");
pp.set_status("unsat");
expr_ref n(m_manager);
n = m_manager.mk_not(m_manager.mk_eq(arg.get(), result));
expr_ref n(m);
n = m.mk_not(m.mk_eq(arg.get(), result));
std::ofstream out(buffer);
pp.display(out, n);
out.close();
@ -445,14 +450,14 @@ void simplifier::dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr *
*/
void simplifier::mk_app(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & result) {
m_need_reset = true;
if (m_manager.is_eq(decl)) {
sort * s = m_manager.get_sort(args[0]);
if (m.is_eq(decl)) {
sort * s = m.get_sort(args[0]);
plugin * p = get_plugin(s->get_family_id());
if (p != 0 && p->reduce_eq(args[0], args[1], result))
return;
}
else if (m_manager.is_distinct(decl)) {
sort * s = m_manager.get_sort(args[0]);
else if (m.is_distinct(decl)) {
sort * s = m.get_sort(args[0]);
plugin * p = get_plugin(s->get_family_id());
if (p != 0 && p->reduce_distinct(num_args, args, result))
return;
@ -464,7 +469,7 @@ void simplifier::mk_app(func_decl * decl, unsigned num_args, expr * const * args
//dump_rewrite_lemma(decl, num_args, args, result.get());
return;
}
result = m_manager.mk_app(decl, num_args, args);
result = m.mk_app(decl, num_args, args);
}
/**
@ -484,7 +489,7 @@ void simplifier::mk_congruent_term(app * n, app_ref & r, proof_ref & p) {
get_cached(arg, new_arg, arg_proof);
CTRACE("simplifier_bug", (arg != new_arg) != (arg_proof != 0),
tout << mk_ll_pp(arg, m_manager) << "\n---->\n" << mk_ll_pp(new_arg, m_manager) << "\n";
tout << mk_ll_pp(arg, m) << "\n---->\n" << mk_ll_pp(new_arg, m) << "\n";
tout << "#" << arg->get_id() << " #" << new_arg->get_id() << "\n";
tout << arg << " " << new_arg << "\n";);
@ -500,11 +505,11 @@ void simplifier::mk_congruent_term(app * n, app_ref & r, proof_ref & p) {
args.push_back(new_arg);
}
if (has_new_args) {
r = m_manager.mk_app(n->get_decl(), args.size(), args.c_ptr());
r = m.mk_app(n->get_decl(), args.size(), args.c_ptr());
if (m_use_oeq)
p = m_manager.mk_oeq_congruence(n, r, proofs.size(), proofs.c_ptr());
p = m.mk_oeq_congruence(n, r, proofs.size(), proofs.c_ptr());
else
p = m_manager.mk_congruence(n, r, proofs.size(), proofs.c_ptr());
p = m.mk_congruence(n, r, proofs.size(), proofs.c_ptr());
}
else {
r = n;
@ -523,8 +528,8 @@ void simplifier::mk_congruent_term(app * n, app_ref & r, proof_ref & p) {
bool simplifier::get_args(app * n, ptr_vector<expr> & result, proof_ref & p) {
bool has_new_args = false;
unsigned num = n->get_num_args();
if (m_manager.fine_grain_proofs()) {
app_ref r(m_manager);
if (m.fine_grain_proofs()) {
app_ref r(m);
mk_congruent_term(n, r, p);
result.append(r->get_num_args(), r->get_args());
SASSERT(n->get_num_args() == result.size());
@ -582,7 +587,7 @@ void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) {
new_args.push_back(new_arg);
if (arg != new_arg)
has_new_arg = true;
if (m_manager.fine_grain_proofs()) {
if (m.fine_grain_proofs()) {
proof * pr = 0;
m_ac_pr_cache.find(to_app(arg), pr);
if (pr != 0)
@ -601,7 +606,7 @@ void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) {
new_args.push_back(new_arg);
if (arg != new_arg)
has_new_arg = true;
if (m_manager.fine_grain_proofs() && pr != 0)
if (m.fine_grain_proofs() && pr != 0)
new_arg_prs.push_back(pr);
}
}
@ -610,14 +615,14 @@ void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) {
todo.pop_back();
if (!has_new_arg) {
m_ac_cache.insert(curr, curr);
if (m_manager.fine_grain_proofs())
if (m.fine_grain_proofs())
m_ac_pr_cache.insert(curr, 0);
}
else {
app * new_curr = m_manager.mk_app(f, new_args.size(), new_args.c_ptr());
app * new_curr = m.mk_app(f, new_args.size(), new_args.c_ptr());
m_ac_cache.insert(curr, new_curr);
if (m_manager.fine_grain_proofs()) {
proof * p = m_manager.mk_congruence(curr, new_curr, new_arg_prs.size(), new_arg_prs.c_ptr());
if (m.fine_grain_proofs()) {
proof * p = m.mk_congruence(curr, new_curr, new_arg_prs.size(), new_arg_prs.c_ptr());
m_ac_pr_cache.insert(curr, p);
}
}
@ -628,7 +633,7 @@ void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) {
app * new_n = 0;
m_ac_cache.find(n, new_n);
r = new_n;
if (m_manager.fine_grain_proofs()) {
if (m.fine_grain_proofs()) {
proof * new_pr = 0;
m_ac_pr_cache.find(n, new_pr);
p = new_pr;
@ -719,7 +724,7 @@ void simplifier::get_ac_args(app * n, ptr_vector<expr> & args, vector<rational>
SASSERT(!sorted_exprs.empty());
SASSERT(sorted_exprs[sorted_exprs.size()-1] == n);
TRACE("ac", tout << mk_ll_pp(n, m_manager, true, false) << "#" << n->get_id() << "\nsorted expressions...\n";
TRACE("ac", tout << mk_ll_pp(n, m, true, false) << "#" << n->get_id() << "\nsorted expressions...\n";
for (unsigned i = 0; i < sorted_exprs.size(); i++) {
tout << "#" << sorted_exprs[i]->get_id() << " ";
}
@ -754,10 +759,10 @@ void simplifier::get_ac_args(app * n, ptr_vector<expr> & args, vector<rational>
void simplifier::reduce1_quantifier(quantifier * q) {
expr * new_body;
proof * new_body_pr;
SASSERT(is_well_sorted(m_manager, q));
SASSERT(is_well_sorted(m, q));
get_cached(q->get_expr(), new_body, new_body_pr);
quantifier_ref q1(m_manager);
quantifier_ref q1(m);
proof * p1 = 0;
if (is_quantifier(new_body) &&
@ -774,7 +779,7 @@ void simplifier::reduce1_quantifier(quantifier * q) {
sorts.append(nested_q->get_num_decls(), nested_q->get_decl_sorts());
names.append(nested_q->get_num_decls(), nested_q->get_decl_names());
q1 = m_manager.mk_quantifier(q->is_forall(),
q1 = m.mk_quantifier(q->is_forall(),
sorts.size(),
sorts.c_ptr(),
names.c_ptr(),
@ -783,13 +788,13 @@ void simplifier::reduce1_quantifier(quantifier * q) {
q->get_qid(),
q->get_skid(),
0, 0, 0, 0);
SASSERT(is_well_sorted(m_manager, q1));
SASSERT(is_well_sorted(m, q1));
if (m_manager.fine_grain_proofs()) {
quantifier * q0 = m_manager.update_quantifier(q, new_body);
proof * p0 = q == q0 ? 0 : m_manager.mk_quant_intro(q, q0, new_body_pr);
p1 = m_manager.mk_pull_quant(q0, q1);
p1 = m_manager.mk_transitivity(p0, p1);
if (m.fine_grain_proofs()) {
quantifier * q0 = m.update_quantifier(q, new_body);
proof * p0 = q == q0 ? 0 : m.mk_quant_intro(q, q0, new_body_pr);
p1 = m.mk_pull_quant(q0, q1);
p1 = m.mk_transitivity(p0, p1);
}
}
else {
@ -802,7 +807,7 @@ void simplifier::reduce1_quantifier(quantifier * q) {
unsigned num = q->get_num_patterns();
for (unsigned i = 0; i < num; i++) {
get_cached(q->get_pattern(i), new_pattern, new_pattern_pr);
if (m_manager.is_pattern(new_pattern)) {
if (m.is_pattern(new_pattern)) {
new_patterns.push_back(new_pattern);
}
}
@ -815,7 +820,7 @@ void simplifier::reduce1_quantifier(quantifier * q) {
remove_duplicates(new_patterns);
remove_duplicates(new_no_patterns);
q1 = m_manager.mk_quantifier(q->is_forall(),
q1 = m.mk_quantifier(q->is_forall(),
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
@ -827,26 +832,26 @@ void simplifier::reduce1_quantifier(quantifier * q) {
new_patterns.c_ptr(),
new_no_patterns.size(),
new_no_patterns.c_ptr());
SASSERT(is_well_sorted(m_manager, q1));
SASSERT(is_well_sorted(m, q1));
TRACE("simplifier", tout << mk_pp(q, m_manager) << "\n" << mk_pp(q1, m_manager) << "\n";);
if (m_manager.fine_grain_proofs()) {
TRACE("simplifier", tout << mk_pp(q, m) << "\n" << mk_pp(q1, m) << "\n";);
if (m.fine_grain_proofs()) {
if (q != q1 && !new_body_pr) {
new_body_pr = m_manager.mk_rewrite(q->get_expr(), new_body);
new_body_pr = m.mk_rewrite(q->get_expr(), new_body);
}
p1 = q == q1 ? 0 : m_manager.mk_quant_intro(q, q1, new_body_pr);
p1 = q == q1 ? 0 : m.mk_quant_intro(q, q1, new_body_pr);
}
}
expr_ref r(m_manager);
elim_unused_vars(m_manager, q1, r);
expr_ref r(m);
elim_unused_vars(m, q1, r);
proof * pr = 0;
if (m_manager.fine_grain_proofs()) {
if (m.fine_grain_proofs()) {
proof * p2 = 0;
if (q1.get() != r.get())
p2 = m_manager.mk_elim_unused_vars(q1, r);
pr = m_manager.mk_transitivity(p1, p2);
p2 = m.mk_elim_unused_vars(q1, r);
pr = m.mk_transitivity(p1, p2);
}
cache_result(q, r, pr);
@ -892,7 +897,7 @@ bool subst_simplifier::get_subst(expr * n, expr_ref & r, proof_ref & p) {
m_subst_map->get(n, _r, _p);
r = _r;
p = _p;
if (m_manager.coarse_grain_proofs())
if (m.coarse_grain_proofs())
m_subst_proofs.push_back(p);
return true;
}

View file

@ -210,7 +210,7 @@ public:
plugin * get_plugin(family_id fid) const { return m_plugins.get_plugin(fid); }
ast_manager & get_manager() { return m_manager; }
ast_manager & get_manager() { return m; }
void borrow_plugins(simplifier const & s);
void release_plugins();

View file

@ -793,8 +793,10 @@ bool substitution_tree::visit(expr * e, st_visitor & st, node * r) {
}
else {
TRACE("st_bug", tout << "found match:\n"; m_subst->display(tout); tout << "m_subst: " << m_subst << "\n";);
if (!st(n->m_expr))
if (!st(n->m_expr)) {
clear_stack();
return false;
}
if (!backtrack())
break;
}
@ -806,12 +808,16 @@ bool substitution_tree::visit(expr * e, st_visitor & st, node * r) {
else if (!backtrack())
break;
}
clear_stack();
return true;
}
void substitution_tree::clear_stack() {
while (!m_bstack.empty()) {
m_subst->pop_scope();
m_bstack.pop_back();
}
m_subst->pop_scope();
return true;
}
template<substitution_tree::st_visit_mode Mode>

View file

@ -123,6 +123,8 @@ class substitution_tree {
template<st_visit_mode Mode>
void visit(expr * e, st_visitor & st, unsigned in_offset, unsigned st_offset, unsigned reg_offset);
void clear_stack();
public:
substitution_tree(ast_manager & m);
~substitution_tree();

View file

@ -25,6 +25,7 @@ Notes:
#include"datatype_decl_plugin.h"
#include"seq_decl_plugin.h"
#include"float_decl_plugin.h"
#include"pb_decl_plugin.h"
#include"ast_pp.h"
#include"var_subst.h"
#include"pp.h"
@ -314,8 +315,9 @@ cmd_context::cmd_context(bool main_ctx, ast_manager * m, symbol const & l):
m_numeral_as_real(false),
m_ignore_check(false),
m_exit_on_error(false),
m_manager(m),
m_manager(m),
m_own_manager(m == 0),
m_manager_initialized(false),
m_pmanager(0),
m_sexpr_manager(0),
m_regular("stdout", std::cout),
@ -326,8 +328,6 @@ cmd_context::cmd_context(bool main_ctx, ast_manager * m, symbol const & l):
install_core_tactic_cmds(*this);
install_interpolant_cmds(*this);
SASSERT(m != 0 || !has_manager());
if (m)
init_external_manager();
if (m_main_ctx) {
set_verbose_stream(diagnostic_stream());
}
@ -337,10 +337,10 @@ cmd_context::~cmd_context() {
if (m_main_ctx) {
set_verbose_stream(std::cerr);
}
reset(true);
finalize_cmds();
finalize_tactic_cmds();
finalize_probes();
reset(true);
m_solver = 0;
m_check_sat_result = 0;
}
@ -358,6 +358,18 @@ void cmd_context::set_cancel(bool f) {
m().set_cancel(f);
}
opt_wrapper* cmd_context::get_opt() {
return m_opt.get();
}
void cmd_context::set_opt(opt_wrapper* opt) {
m_opt = opt;
for (unsigned i = 0; i < m_scopes.size(); ++i) {
m_opt->push();
}
m_opt->set_logic(m_logic);
}
void cmd_context::global_params_updated() {
m_params.updt_params();
if (m_params.m_smtlib2_compliant)
@ -471,6 +483,16 @@ void cmd_context::register_plugin(symbol const & name, decl_plugin * p, bool ins
}
}
void cmd_context::load_plugin(symbol const & name, bool install, svector<family_id>& fids) {
family_id id = m_manager->get_family_id(name);
decl_plugin* p = m_manager->get_plugin(id);
if (install && p && fids.contains(id)) {
register_builtin_sorts(p);
register_builtin_ops(p);
}
fids.erase(id);
}
bool cmd_context::logic_has_arith_core(symbol const & s) const {
return
s == "QF_LRA" ||
@ -551,6 +573,7 @@ bool cmd_context::logic_has_floats() const {
return !has_logic() || m_logic == "QF_FPA" || m_logic == "QF_FPABV";
}
bool cmd_context::logic_has_array_core(symbol const & s) const {
return
s == "QF_AX" ||
@ -587,17 +610,27 @@ void cmd_context::init_manager_core(bool new_manager) {
register_builtin_sorts(basic);
register_builtin_ops(basic);
// the manager was created by the command context.
register_plugin(symbol("arith"), alloc(arith_decl_plugin), logic_has_arith());
register_plugin(symbol("bv"), alloc(bv_decl_plugin), logic_has_bv());
register_plugin(symbol("array"), alloc(array_decl_plugin), logic_has_array());
register_plugin(symbol("arith"), alloc(arith_decl_plugin), logic_has_arith());
register_plugin(symbol("bv"), alloc(bv_decl_plugin), logic_has_bv());
register_plugin(symbol("array"), alloc(array_decl_plugin), logic_has_array());
register_plugin(symbol("datatype"), alloc(datatype_decl_plugin), logic_has_datatype());
register_plugin(symbol("seq"), alloc(seq_decl_plugin), logic_has_seq());
register_plugin(symbol("float"), alloc(float_decl_plugin), logic_has_floats());
register_plugin(symbol("pb"), alloc(pb_decl_plugin), !has_logic());
}
else {
// the manager was created by an external module, we must register all plugins available in the manager.
// the manager was created by an external module
// we register all plugins available in the manager.
// unless the logic specifies otherwise.
svector<family_id> fids;
m_manager->get_range(fids);
load_plugin(symbol("arith"), logic_has_arith(), fids);
load_plugin(symbol("bv"), logic_has_bv(), fids);
load_plugin(symbol("array"), logic_has_array(), fids);
load_plugin(symbol("datatype"), logic_has_datatype(), fids);
load_plugin(symbol("seq"), logic_has_seq(), fids);
load_plugin(symbol("float"), logic_has_floats(), fids);
svector<family_id>::iterator it = fids.begin();
svector<family_id>::iterator end = fids.end();
for (; it != end; ++it) {
@ -620,12 +653,22 @@ void cmd_context::init_manager_core(bool new_manager) {
}
void cmd_context::init_manager() {
SASSERT(m_manager == 0);
SASSERT(m_pmanager == 0);
m_check_sat_result = 0;
m_manager = m_params.mk_ast_manager();
m_pmanager = alloc(pdecl_manager, *m_manager);
init_manager_core(true);
if (m_manager_initialized) {
// no-op
}
else if (m_manager) {
m_manager_initialized = true;
SASSERT(!m_own_manager);
init_external_manager();
}
else {
m_manager_initialized = true;
SASSERT(m_pmanager == 0);
m_check_sat_result = 0;
m_manager = m_params.mk_ast_manager();
m_pmanager = alloc(pdecl_manager, *m_manager);
init_manager_core(true);
}
}
void cmd_context::init_external_manager() {
@ -708,7 +751,7 @@ void cmd_context::insert(symbol const & s, func_decl * f) {
if (!m_global_decls) {
m_func_decls_stack.push_back(sf_pair(s, f));
}
TRACE("cmd_context", tout << "new sort decl\n" << mk_pp(f, m()) << "\n";);
TRACE("cmd_context", tout << "new function decl\n" << mk_pp(f, m()) << "\n";);
}
void cmd_context::insert(symbol const & s, psort_decl * p) {
@ -1141,7 +1184,6 @@ void cmd_context::insert_aux_pdecl(pdecl * p) {
}
void cmd_context::reset(bool finalize) {
m_check_sat_result = 0;
m_logic = symbol::null;
m_check_sat_result = 0;
m_numeral_as_real = false;
@ -1157,6 +1199,7 @@ void cmd_context::reset(bool finalize) {
restore_assertions(0);
if (m_solver)
m_solver = 0;
m_opt = 0;
m_pp_env = 0;
m_dt_eh = 0;
if (m_manager) {
@ -1165,12 +1208,15 @@ void cmd_context::reset(bool finalize) {
if (m_own_manager) {
dealloc(m_manager);
m_manager = 0;
m_manager_initialized = false;
}
else {
// doesn't own manager... so it cannot be deleted
// reinit cmd_context if this is not a finalization step
if (!finalize)
init_external_manager();
else
m_manager_initialized = false;
}
}
if (m_sexpr_manager) {
@ -1211,8 +1257,7 @@ void cmd_context::assert_expr(symbol const & name, expr * t) {
void cmd_context::push() {
m_check_sat_result = 0;
if (!has_manager())
init_manager();
init_manager();
m_scopes.push_back(scope());
scope & s = m_scopes.back();
s.m_func_decls_stack_lim = m_func_decls_stack.size();
@ -1222,6 +1267,8 @@ void cmd_context::push() {
s.m_assertions_lim = m_assertions.size();
if (m_solver)
m_solver->push();
if (m_opt)
m_opt->push();
}
void cmd_context::push(unsigned n) {
@ -1317,6 +1364,8 @@ void cmd_context::pop(unsigned n) {
if (m_solver) {
m_solver->pop(n);
}
if (m_opt)
m_opt->pop(n);
unsigned new_lvl = lvl - n;
scope & s = m_scopes[new_lvl];
restore_func_decls(s.m_func_decls_stack_lim);
@ -1332,17 +1381,49 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions
return;
IF_VERBOSE(100, verbose_stream() << "(started \"check-sat\")" << std::endl;);
TRACE("before_check_sat", dump_assertions(tout););
if (!has_manager())
init_manager();
if (m_solver) {
init_manager();
unsigned timeout = m_params.m_timeout;
scoped_watch sw(*this);
lbool r;
if (m_opt && !m_opt->empty()) {
bool was_pareto = false;
m_check_sat_result = get_opt();
cancel_eh<opt_wrapper> eh(*get_opt());
scoped_ctrl_c ctrlc(eh);
scoped_timer timer(timeout, &eh);
ptr_vector<expr> cnstr(m_assertions);
cnstr.append(num_assumptions, assumptions);
get_opt()->set_hard_constraints(cnstr);
try {
r = get_opt()->optimize();
while (r == l_true && get_opt()->is_pareto()) {
was_pareto = true;
get_opt()->display_assignment(regular_stream());
regular_stream() << "\n";
r = get_opt()->optimize();
}
}
catch (z3_error & ex) {
throw ex;
}
catch (z3_exception & ex) {
throw cmd_exception(ex.msg());
}
if (was_pareto && r == l_false) {
r = l_true;
}
get_opt()->set_status(r);
if (r != l_false && !was_pareto) {
get_opt()->display_assignment(regular_stream());
}
}
else if (m_solver) {
m_check_sat_result = m_solver.get(); // solver itself stores the result.
m_solver->set_progress_callback(this);
unsigned timeout = m_params.m_timeout;
scoped_watch sw(*this);
cancel_eh<solver> eh(*m_solver);
scoped_ctrl_c ctrlc(eh);
scoped_timer timer(timeout, &eh);
lbool r;
try {
r = m_solver->check_sat(num_assumptions, assumptions);
}
@ -1353,15 +1434,17 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions
throw cmd_exception(ex.msg());
}
m_solver->set_status(r);
display_sat_result(r);
validate_check_sat_result(r);
if (r == l_true)
validate_model();
}
else {
// There is no solver installed in the command context.
regular_stream() << "unknown" << std::endl;
return;
}
display_sat_result(r);
validate_check_sat_result(r);
if (r == l_true)
validate_model();
}
void cmd_context::display_sat_result(lbool r) {
@ -1538,6 +1621,9 @@ void cmd_context::display_statistics(bool show_total_time, double total_time) {
else if (m_solver) {
m_solver->collect_statistics(st);
}
else if (m_opt) {
m_opt->collect_statistics(st);
}
st.display_smt2(regular_stream());
}

View file

@ -111,6 +111,21 @@ struct builtin_decl {
builtin_decl(family_id fid, decl_kind k, builtin_decl * n = 0):m_fid(fid), m_decl(k), m_next(n) {}
};
class opt_wrapper : public check_sat_result {
public:
virtual bool empty() = 0;
virtual void push() = 0;
virtual void pop(unsigned n) = 0;
virtual void set_cancel(bool f) = 0;
virtual void reset_cancel() = 0;
virtual void cancel() = 0;
virtual lbool optimize() = 0;
virtual void set_hard_constraints(ptr_vector<expr> & hard) = 0;
virtual void display_assignment(std::ostream& out) = 0;
virtual bool is_pareto() = 0;
virtual void set_logic(symbol const& s) = 0;
};
class cmd_context : public progress_callback, public tactic_manager, public ast_printer_context {
public:
enum status {
@ -149,6 +164,7 @@ protected:
ast_manager * m_manager;
bool m_own_manager;
bool m_manager_initialized;
pdecl_manager * m_pmanager;
sexpr_manager * m_sexpr_manager;
check_logic m_check_logic;
@ -187,8 +203,9 @@ protected:
svector<scope> m_scopes;
scoped_ptr<solver_factory> m_solver_factory;
scoped_ptr<solver_factory> m_interpolating_solver_factory;
ref<solver> m_solver;
ref<solver> m_solver;
ref<check_sat_result> m_check_sat_result;
ref<opt_wrapper> m_opt;
stopwatch m_watch;
@ -212,7 +229,7 @@ protected:
void register_builtin_sorts(decl_plugin * p);
void register_builtin_ops(decl_plugin * p);
void register_plugin(symbol const & name, decl_plugin * p, bool install_names);
void load_plugin(symbol const & name, bool install_names, svector<family_id>& fids);
void init_manager_core(bool new_manager);
void init_manager();
void init_external_manager();
@ -256,6 +273,8 @@ public:
context_params & params() { return m_params; }
solver_factory &get_solver_factory() { return *m_solver_factory; }
solver_factory &get_interpolating_solver_factory() { return *m_interpolating_solver_factory; }
opt_wrapper* get_opt();
void set_opt(opt_wrapper* o);
void global_params_updated(); // this method should be invoked when global (and module) params are updated.
bool set_logic(symbol const & s);
bool has_logic() const { return m_logic != symbol::null; }
@ -293,7 +312,7 @@ public:
std::string reason_unknown() const;
bool has_manager() const { return m_manager != 0; }
ast_manager & m() const { if (!m_manager) const_cast<cmd_context*>(this)->init_manager(); return *m_manager; }
ast_manager & m() const { const_cast<cmd_context*>(this)->init_manager(); return *m_manager; }
virtual ast_manager & get_ast_manager() { return m(); }
pdecl_manager & pm() const { if (!m_pmanager) const_cast<cmd_context*>(this)->init_manager(); return *m_pmanager; }
sexpr_manager & sm() const { if (!m_sexpr_manager) const_cast<cmd_context*>(this)->m_sexpr_manager = alloc(sexpr_manager); return *m_sexpr_manager; }
@ -304,7 +323,8 @@ public:
check_sat_result * get_check_sat_result() const { return m_check_sat_result.get(); }
check_sat_state cs_state() const;
void validate_model();
void register_plugin(symbol const & name, decl_plugin * p, bool install_names);
bool is_func_decl(symbol const & s) const;
bool is_sort_decl(symbol const& s) const { return m_psort_decls.contains(s); }
void insert(cmd * c);

View file

@ -83,13 +83,13 @@ void context_params::set(char const * param, char const * value) {
set_bool(m_smtlib2_compliant, param, value);
}
else {
param_descrs d;
collect_param_descrs(d);
std::stringstream strm;
strm << "unknown parameter '" << p << "'\n";
strm << "Legal parameters are:\n";
d.display(strm, 2, false, false);
throw default_exception(strm.str());
param_descrs d;
collect_param_descrs(d);
std::stringstream strm;
strm << "unknown parameter '" << p << "'\n";
strm << "Legal parameters are:\n";
d.display(strm, 2, false, false);
throw default_exception(strm.str());
}
}

4
src/duality/duality.h Executable file → Normal file
View file

@ -778,6 +778,10 @@ protected:
struct Bad {
};
// thrown on more serious internal error
struct ReallyBad {
};
/** Pop a scope (see Push). Note, you cannot pop axioms. */
void Pop(int num_scopes);

Some files were not shown because too many files have changed in this diff Show more