diff --git a/.gitignore b/.gitignore
index 65a69bf51..2158b8633 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@ ocamlz3
# Emacs temp files
\#*\#
# Directories with generated code and documentation
+release/*
build/*
build-dist/*
dist/*
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index fa4857e32..ad2dcaf00 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -1,5 +1,10 @@
RELEASE NOTES
+Version 4.3.3
+=============
+
+- Fixed bug in floating point models
+
Version 4.3.2
=============
diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp
index b348e7d36..ba706a769 100644
--- a/examples/c++/example.cpp
+++ b/examples/c++/example.cpp
@@ -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) {
diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs
index 4361cab96..a20978d62 100644
--- a/examples/dotnet/Program.cs
+++ b/examples/dotnet/Program.cs
@@ -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);
diff --git a/examples/msf/README b/examples/msf/README
new file mode 100644
index 000000000..d6e56f72f
--- /dev/null
+++ b/examples/msf/README
@@ -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!
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/msf/SolverFoundation.Plugin.Z3.Tests/App.config b/examples/msf/SolverFoundation.Plugin.Z3.Tests/App.config
new file mode 100644
index 000000000..75e2872f1
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3.Tests/App.config
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/msf/SolverFoundation.Plugin.Z3.Tests/Properties/AssemblyInfo.cs b/examples/msf/SolverFoundation.Plugin.Z3.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..b58f97eda
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3.Tests/Properties/AssemblyInfo.cs
@@ -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")]
diff --git a/examples/msf/SolverFoundation.Plugin.Z3.Tests/ServiceTests.cs b/examples/msf/SolverFoundation.Plugin.Z3.Tests/ServiceTests.cs
new file mode 100644
index 000000000..25a8e2d26
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3.Tests/ServiceTests.cs
@@ -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());
+ }
+
+ }
+}
diff --git a/examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverFoundation.Plugin.Z3.Tests.csproj b/examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverFoundation.Plugin.Z3.Tests.csproj
new file mode 100644
index 000000000..24cecfa10
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverFoundation.Plugin.Z3.Tests.csproj
@@ -0,0 +1,70 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {280AEE2F-1FDB-4A27-BE37-14DC154C873B}
+ Library
+ Properties
+ Microsoft.SolverFoundation.Plugin.Z3.Tests
+ SolverFoundation.Plugin.Z3.Tests
+ v4.0
+ 512
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ x86
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ x86
+
+
+
+ ..\Microsoft.Solver.Foundation.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {7340e664-f648-4ff7-89b2-f4da424996d3}
+ SolverFoundation.Plugin.Z3
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverTests.cs b/examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverTests.cs
new file mode 100644
index 000000000..c2cd0c270
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3.Tests/SolverTests.cs
@@ -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);
+ }
+ }
+}
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/AbortWorker.cs b/examples/msf/SolverFoundation.Plugin.Z3/AbortWorker.cs
new file mode 100644
index 000000000..99d6fe17a
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/AbortWorker.cs
@@ -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
+{
+ ///
+ /// 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.
+ ///
+ internal class AbortWorker
+ {
+ #region Private Members
+
+ /// The Z3 solver
+ private Microsoft.Z3.Context _context;
+ /// The abort function to use to check if we are aborted
+ private Func _QueryAbortFunction;
+ /// Flag indicating that worker should stop
+ private bool _stop = false;
+ /// Flag indicating that we have been sent an abort signal
+ private bool _aborted = false;
+
+ #endregion Private Members
+
+ #region Construction
+
+ ///
+ /// Worker constructor taking a Z3 instance and a function to periodically
+ /// check for aborts.
+ ///
+ /// Z3 instance
+ /// method to call to check for aborts
+ public AbortWorker(Context context, Func queryAbortFunction)
+ {
+ _context = context;
+ _QueryAbortFunction = queryAbortFunction;
+ }
+
+ #endregion Construction
+
+ #region Public Methods
+
+ ///
+ /// Stop the abort worker.
+ ///
+ public void Stop()
+ {
+ _stop = true;
+ }
+
+ ///
+ /// Is true if we have been aborted.
+ ///
+ public bool Aborted
+ {
+ get
+ {
+ return _aborted;
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ 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
+ }
+}
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/App.config b/examples/msf/SolverFoundation.Plugin.Z3/App.config
new file mode 100644
index 000000000..75e2872f1
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/App.config
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Properties/AssemblyInfo.cs b/examples/msf/SolverFoundation.Plugin.Z3/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..b30c01ab4
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/Properties/AssemblyInfo.cs
@@ -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")]
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/SolverFoundation.Plugin.Z3.csproj b/examples/msf/SolverFoundation.Plugin.Z3/SolverFoundation.Plugin.Z3.csproj
new file mode 100644
index 000000000..0b30e1677
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/SolverFoundation.Plugin.Z3.csproj
@@ -0,0 +1,149 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {7340E664-F648-4FF7-89B2-F4DA424996D3}
+ Library
+ Properties
+ Microsoft.SolverFoundation.Plugin.Z3
+ SolverFoundation.Plugin.Z3
+ v4.0
+ 512
+ false
+
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ AllRules.ruleset
+
+
+ bin\commercial\
+ TRACE
+ true
+ pdbonly
+ AnyCPU
+ prompt
+
+
+ bin\commercial_64\
+ TRACE
+ true
+ pdbonly
+ AnyCPU
+ prompt
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ prompt
+ AllRules.ruleset
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ prompt
+ AllRules.ruleset
+
+
+ bin\x86\commercial\
+ TRACE
+ true
+ pdbonly
+ x86
+ prompt
+ AllRules.ruleset
+
+
+ bin\x86\commercial_64\
+ TRACE
+ true
+ pdbonly
+ x86
+ prompt
+
+
+
+ ..\Microsoft.Solver.Foundation.dll
+
+
+ False
+ ..\Microsoft.Z3.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Utils.cs b/examples/msf/SolverFoundation.Plugin.Z3/Utils.cs
new file mode 100644
index 000000000..71c8647a1
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/Utils.cs
@@ -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
+ {
+ ///
+ /// Returns the Z3 term corresponding to the MSF rational number.
+ ///
+ /// The MSF rational
+ /// The Z3 term
+ 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;
+ }
+ }
+}
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseDirective.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseDirective.cs
new file mode 100644
index 000000000..e1403f698
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseDirective.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Text;
+using Microsoft.SolverFoundation.Services;
+
+namespace Microsoft.SolverFoundation.Plugin.Z3
+{
+ ///
+ /// Combining objective functions
+ ///
+ public enum OptimizationKind
+ {
+ Lexicographic,
+ BoundingBox,
+ ParetoOptimal
+ };
+
+ ///
+ /// Algorithm for solving cardinality constraints
+ ///
+ public enum CardinalityAlgorithm
+ {
+ FuMalik,
+ CoreMaxSAT
+ }
+
+ ///
+ /// Algorithm for solving pseudo-boolean constraints
+ ///
+ public enum PseudoBooleanAlgorithm
+ {
+ WeightedMaxSAT,
+ IterativeWeightedMaxSAT,
+ BisectionWeightedMaxSAT,
+ WeightedPartialMaxSAT2
+ }
+
+ ///
+ /// Strategy for solving arithmetic optimization
+ ///
+ 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();
+ }
+ }
+}
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseParams.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseParams.cs
new file mode 100644
index 000000000..6585181ec
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseParams.cs
@@ -0,0 +1,103 @@
+using Microsoft.SolverFoundation.Services;
+using System;
+
+namespace Microsoft.SolverFoundation.Plugin.Z3
+{
+ ///
+ /// Implementation of the solver parameters for Z3
+ ///
+ public class Z3BaseParams : ISolverParameters
+ {
+ #region Private Members
+
+ /// The abort method we can call (defaults to always false)
+ protected Func _queryAbortFunction = delegate() { return false; };
+
+ /// The directive to use
+ 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 queryAbortFunction)
+ {
+ _queryAbortFunction = queryAbortFunction;
+ }
+
+ public Z3BaseParams(Z3BaseParams z3Parameters)
+ {
+ _queryAbortFunction = z3Parameters._queryAbortFunction;
+ }
+
+ #endregion Construction
+
+ #region ISolverParameters Members
+
+ ///
+ /// Getter for the abort method
+ ///
+ public Func 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
+ }
+
+}
\ No newline at end of file
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs
new file mode 100644
index 000000000..54e3893f0
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3BaseSolver.cs
@@ -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
+ }
+
+ ///
+ /// The basic solver class to take care of transformation from an MSF instance to an Z3 instance
+ ///
+ internal class Z3BaseSolver
+ {
+ /// Representing MSF model
+ private IRowVariableModel _model;
+
+ /// The Z3 solver we are currently using
+ private Context _context = null;
+
+ /// Default optimization solver
+ private Optimize _optSolver = null;
+
+ /// Marks when we are inside the Solve() method
+ private bool _isSolving = false;
+
+ /// A map from MSF variable ids to Z3 variables
+ private Dictionary _variables = new Dictionary();
+
+ /// A map from MSF variable ids to Z3 goal ids
+ private Dictionary _goals = new Dictionary();
+
+ internal Z3BaseSolver(IRowVariableModel model)
+ {
+ _model = model;
+ }
+
+ internal Context Context
+ {
+ get { return _context; }
+ }
+
+ internal Dictionary Variables
+ {
+ get { return _variables; }
+ }
+
+ internal Dictionary Goals
+ {
+ get { return _goals; }
+ }
+
+ ///
+ /// Destructs a currently active Z3 solver and the associated data.
+ ///
+ 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.");
+ }
+ }
+ }
+
+ ///
+ /// Constructs a Z3 solver to be used.
+ ///
+ 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);
+ }
+ }
+ }
+
+ ///
+ /// Adds a MSF variable with the coresponding assertion to the Z3 variables.
+ ///
+ /// The MSF id of the variable
+ 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 modelGoals,
+ Action addRow, Func mkGoalRow, Action 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 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 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);
+ }
+ }
+}
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPDirective.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPDirective.cs
new file mode 100644
index 000000000..69f9ff6c1
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPDirective.cs
@@ -0,0 +1,9 @@
+using Microsoft.SolverFoundation.Services;
+using System;
+
+namespace Microsoft.SolverFoundation.Plugin.Z3
+{
+ public class Z3MILPDirective : Z3BaseDirective
+ {
+ }
+}
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPParams.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPParams.cs
new file mode 100644
index 000000000..38bd9040a
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPParams.cs
@@ -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 queryAbortFunction) : base(queryAbortFunction) { }
+
+ public Z3MILPParams(Z3BaseParams z3Parameters) : base (z3Parameters) { }
+ }
+
+}
\ No newline at end of file
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs
new file mode 100644
index 000000000..b31f6de97
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3MILPSolver.cs
@@ -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
+{
+ ///
+ /// The class is implementation of the MSF mixed linear programming solver
+ /// using the Microsoft Z3 solver as the backend.
+ ///
+ 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
+
+ /// Constructor that initializes the base clases
+ public Z3MILPSolver() : base(null)
+ {
+ _result = LinearResult.Feasible;
+ _solver = new Z3BaseSolver(this);
+ }
+
+ /// Constructor that initializes the base clases
+ public Z3MILPSolver(ISolverEnvironment context) : this() { }
+
+ ///
+ /// 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.
+ ///
+ 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
+
+ ///
+ /// Get corresponding Z3 formula of a MSF row.
+ ///
+ /// The MSF row id
+ private ArithExpr MkGoalRow(int rid)
+ {
+ // Start with the 0 term
+ List row = new List();
+
+ // 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());
+ }
+ }
+
+ ///
+ /// Adds a MSF row to the Z3 assertions.
+ ///
+ /// The MSF row id
+ private void AddRow(int rid)
+ {
+ // Start with the 0 term
+ ArithExpr row = MkGoalRow(rid);
+ _solver.AssertArith(rid, row);
+ }
+
+ ///
+ /// Set results based on internal solver status
+ ///
+ 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
+
+ ///
+ /// Starts solving the problem using the Z3 solver.
+ ///
+ /// Parameters to the solver
+ /// The solution to the problem
+ 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);
+ }
+ }
+
+ ///
+ /// Class implementing the LinearReport.
+ ///
+ public class Z3LinearSolverReport : LinearReport
+ {
+ public Z3LinearSolverReport(SolverContext context, ISolver solver, Solution solution, LinearSolutionMapping solutionMapping)
+ : base(context, solver, solution, solutionMapping) {
+ }
+ }
+}
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3TermDirective.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermDirective.cs
new file mode 100644
index 000000000..12dcb6e84
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermDirective.cs
@@ -0,0 +1,9 @@
+using Microsoft.SolverFoundation.Services;
+using System;
+
+namespace Microsoft.SolverFoundation.Plugin.Z3
+{
+ public class Z3TermDirective : Z3BaseDirective
+ {
+ }
+}
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3TermParams.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermParams.cs
new file mode 100644
index 000000000..48a90afe1
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermParams.cs
@@ -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 queryAbortFunction) : base(queryAbortFunction) { }
+
+ public Z3TermParams(Z3BaseParams z3Parameters) : base(z3Parameters) { }
+ }
+
+}
\ No newline at end of file
diff --git a/examples/msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs
new file mode 100644
index 000000000..3317b9a4d
--- /dev/null
+++ b/examples/msf/SolverFoundation.Plugin.Z3/Z3TermSolver.cs
@@ -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
+{
+ ///
+ /// 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.
+ ///
+ public class Z3TermSolver : TermModel, ITermSolver, INonlinearSolution, IReportProvider
+ {
+ private NonlinearResult _result;
+ private Z3BaseSolver _solver;
+
+ /// Constructor that initializes the base clases
+ public Z3TermSolver() : base(null)
+ {
+ _solver = new Z3BaseSolver(this);
+ }
+
+ /// Constructor that initializes the base clases
+ public Z3TermSolver(ISolverEnvironment context) : this() { }
+
+ ///
+ /// 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.
+ ///
+ 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 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;
+ }
+
+ ///
+ /// Adds a MSF row to the Z3 assertions.
+ ///
+ /// The MSF row id
+ 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 };
+
+ ///
+ /// Gets the operations supported by the solver.
+ ///
+ /// All the TermModelOperations supported by the solver.
+ public IEnumerable SupportedOperations
+ {
+ get { return _supportedOperations; }
+ }
+
+ ///
+ /// Set results based on internal solver status
+ ///
+ 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;
+ }
+ }
+
+ ///
+ /// Starts solving the problem using the Z3 solver.
+ ///
+ /// Parameters to the solver
+ /// The solution to the problem
+ 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)
+ {
+ }
+ }
+}
diff --git a/examples/msf/Validator/App.config b/examples/msf/Validator/App.config
new file mode 100644
index 000000000..75e2872f1
--- /dev/null
+++ b/examples/msf/Validator/App.config
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/msf/Validator/MicrosoftSolverFoundationForExcel.dll.config b/examples/msf/Validator/MicrosoftSolverFoundationForExcel.dll.config
new file mode 100644
index 000000000..cd9dcad25
--- /dev/null
+++ b/examples/msf/Validator/MicrosoftSolverFoundationForExcel.dll.config
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/msf/Validator/Program.cs b/examples/msf/Validator/Program.cs
new file mode 100644
index 000000000..758c65c78
--- /dev/null
+++ b/examples/msf/Validator/Program.cs
@@ -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 : solving the model using Z3
+ -convert : converting the model into SMT2 format
+ -validate : validating by comparing results between Z3 and MSF solvers
+ -term : change the default Z3 MILP solver to Z3 Term solver
+
+ where is any file with OML, MPS or SMPS extension.
+
+Examples:
+ Validator.exe -convert model.mps
+ Validator.exe -term -solve model.oml
+
+");
+ }
+ }
+}
diff --git a/examples/msf/Validator/Properties/AssemblyInfo.cs b/examples/msf/Validator/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..eb2f8ed71
--- /dev/null
+++ b/examples/msf/Validator/Properties/AssemblyInfo.cs
@@ -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")]
diff --git a/examples/msf/Validator/Validator.csproj b/examples/msf/Validator/Validator.csproj
new file mode 100644
index 000000000..cfea3c80b
--- /dev/null
+++ b/examples/msf/Validator/Validator.csproj
@@ -0,0 +1,123 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.21022
+ 2.0
+ {54835857-129F-44C9-B529-A42158647B36}
+ Exe
+ Properties
+ Validator
+ Validator
+ v4.0
+ 512
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ true
+ GlobalSuppressions.cs
+ prompt
+
+
+ bin\x64\Release\
+ TRACE
+ true
+ pdbonly
+ x64
+ true
+ GlobalSuppressions.cs
+ prompt
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+
+
+
+ ..\Microsoft.Solver.Foundation.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {7340e664-f648-4ff7-89b2-f4da424996d3}
+ SolverFoundation.Plugin.Z3
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/msf/Z3MSFPlugin.sln b/examples/msf/Z3MSFPlugin.sln
new file mode 100644
index 000000000..c3af1dc22
--- /dev/null
+++ b/examples/msf/Z3MSFPlugin.sln
@@ -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
diff --git a/scripts/mk_project.py b/scripts/mk_project.py
index 170124bd8..2e620b46b 100644
--- a/scripts/mk_project.py
+++ b/scripts/mk_project.py
@@ -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',
diff --git a/scripts/update_api.py b/scripts/update_api.py
index 2fbf42cca..e10a2aa75 100644
--- a/scripts/update_api.py
+++ b/scripts/update_api.py
@@ -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:
diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp
index c2864ca2d..0ab027f69 100644
--- a/src/api/api_ast.cpp
+++ b/src/api/api_ast.cpp
@@ -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);
}
diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp
index c46e7363d..5b385a872 100644
--- a/src/api/api_config_params.cpp
+++ b/src/api/api_config_params.cpp
@@ -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());
}
}
diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp
index b10621d43..b8470839f 100644
--- a/src/api/api_context.cpp
+++ b/src/api/api_context.cpp
@@ -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");
diff --git a/src/api/api_context.h b/src/api/api_context.h
index e0c95b07b..8b4418c9a 100644
--- a/src/api/api_context.h
+++ b/src/api/api_context.h
@@ -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; }
diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp
index ad6b5ad69..2d2b50f3d 100644
--- a/src/api/api_datalog.cpp
+++ b/src/api/api_datalog.cpp
@@ -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 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);
}
diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp
index f3a275508..fae8a21bc 100644
--- a/src/api/api_datatype.cpp
+++ b/src/api/api_datatype.cpp
@@ -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, ¶m, 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);
+ }
+
+
};
diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp
new file mode 100644
index 000000000..d9369092a
--- /dev/null
+++ b/src/api/api_opt.cpp
@@ -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
+#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(o); }
+ inline Z3_optimize of_optimize(Z3_optimize_ref * o) { return reinterpret_cast(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 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);
+ }
+
+
+
+};
diff --git a/src/api/api_pb.cpp b/src/api/api_pb.cpp
new file mode 100644
index 000000000..6d5a56d2c
--- /dev/null
+++ b/src/api/api_pb.cpp
@@ -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
+#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 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);
+ }
+
+
+};
diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h
index c35208d86..a180bdabe 100644
--- a/src/api/c++/z3++.h
+++ b/src/api/c++/z3++.h
@@ -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 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();
diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs
index 1c03d76b6..13e78e495 100644
--- a/src/api/dotnet/Context.cs
+++ b/src/api/dotnet/Context.cs
@@ -449,6 +449,19 @@ namespace Microsoft.Z3
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)
+ {
+ 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
+
+ ///
+ /// Create an at-most-k constraint.
+ ///
+ public BoolExpr MkAtMost(BoolExpr[] args, uint k)
+ {
+ Contract.Requires(args != null);
+ Contract.Requires(Contract.Result() != null);
+ CheckContextMatch(args);
+ return new BoolExpr(this, Native.Z3_mk_atmost(nCtx, (uint) args.Length,
+ AST.ArrayToNative(args), k));
+ }
+
+ ///
+ /// Create a pseudo-Boolean less-or-equal constraint.
+ ///
+ 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() != 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
+ ///
+ /// Create an Optimization context.
+ ///
+ public Optimize MkOptimize()
+ {
+ Contract.Ensures(Contract.Result() != null);
+
+ return new Optimize(this);
+ }
+ #endregion
+
#region Miscellaneous
///
@@ -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() != null); return m_AST_DRQ; } }
internal ASTMap.DecRefQueue ASTMap_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_ASTMap_DRQ; } }
@@ -3627,6 +3684,7 @@ namespace Microsoft.Z3
internal Statistics.DecRefQueue Statistics_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Statistics_DRQ; } }
internal Tactic.DecRefQueue Tactic_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Tactic_DRQ; } }
internal Fixedpoint.DecRefQueue Fixedpoint_DRQ { get { Contract.Ensures(Contract.Result() != null); return m_Fixedpoint_DRQ; } }
+ internal Optimize.DecRefQueue Optimize_DRQ { get { Contract.Ensures(Contract.Result() != 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;
diff --git a/src/api/dotnet/Deprecated.cs b/src/api/dotnet/Deprecated.cs
new file mode 100644
index 000000000..aa6dffb45
--- /dev/null
+++ b/src/api/dotnet/Deprecated.cs
@@ -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
+{
+ ///
+ /// The main interaction with Z3 happens via the Context.
+ ///
+ [ContractVerification(true)]
+ public class Deprecated
+ {
+
+ ///
+ /// Creates a backtracking point.
+ ///
+ ///
+ public static void Push(Context ctx) {
+ Native.Z3_push(ctx.nCtx);
+ }
+
+ ///
+ /// Backtracks backtracking points.
+ ///
+ /// Note that an exception is thrown if is not smaller than NumScopes
+ ///
+ public static void Pop(Context ctx, uint n = 1) {
+ Native.Z3_pop(ctx.nCtx, n);
+ }
+
+ ///
+ /// Assert a constraint (or multiple) into the solver.
+ ///
+ 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);
+ }
+ }
+ ///
+ /// Checks whether the assertions in the context are consistent or not.
+ ///
+ public static Status Check(Context ctx, List 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;
+ }
+ }
+
+ ///
+ /// Retrieves an assignment to atomic propositions for a satisfiable context.
+ ///
+ public static BoolExpr GetAssignment(Context ctx)
+ {
+ IntPtr x = Native.Z3_get_context_assignment(ctx.nCtx);
+ return (BoolExpr)Expr.Create(ctx, x);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/api/dotnet/Fixedpoint.cs b/src/api/dotnet/Fixedpoint.cs
index 3f40b220b..6d75235c6 100644
--- a/src/api/dotnet/Fixedpoint.cs
+++ b/src/api/dotnet/Fixedpoint.cs
@@ -304,6 +304,19 @@ namespace Microsoft.Z3
}
///
+ /// Fixedpoint statistics.
+ ///
+ public Statistics Statistics
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result() != null);
+
+ return new Statistics(Context, Native.Z3_fixedpoint_get_statistics(Context.nCtx, NativeObject));
+ }
+ }
+
+ ///
/// Parse an SMT-LIB2 file with fixedpoint rules.
/// Add the rules to the current fixedpoint context.
/// Return the set of queries in the file.
diff --git a/src/api/dotnet/Microsoft.Z3.csproj b/src/api/dotnet/Microsoft.Z3.csproj
index cc7d3c0c5..36bd6ad02 100644
--- a/src/api/dotnet/Microsoft.Z3.csproj
+++ b/src/api/dotnet/Microsoft.Z3.csproj
@@ -19,12 +19,12 @@
true
full
false
- ..\..\..\..\..\cwinter\bugs\z3bugs\Debug\
+ ..\Debug\
DEBUG;TRACE
prompt
4
true
- C:\cwinter\bugs\z3bugs\Debug\Microsoft.Z3.XML
+ ..\Debug\Microsoft.Z3.XML
False
False
True
@@ -254,7 +254,7 @@
true
- ..\..\..\..\..\cwinter\bugs\z3bugs\Debug\
+ ..\x86\Debug\
DEBUG;TRACE
true
full
@@ -266,7 +266,7 @@
MinimumRecommendedRules.ruleset
;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets
;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules
- C:\cwinter\bugs\z3bugs\Debug\Microsoft.Z3.XML
+ ..\x86\Debug\Microsoft.Z3.XML
bin\x86\Release\
diff --git a/src/api/dotnet/Optimize.cs b/src/api/dotnet/Optimize.cs
new file mode 100644
index 000000000..ed7d1d60a
--- /dev/null
+++ b/src/api/dotnet/Optimize.cs
@@ -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
+{
+ ///
+ /// Object for managing optimizization context
+ ///
+ [ContractVerification(true)]
+ public class Optimize : Z3Object
+ {
+ ///
+ /// A string that describes all available optimize solver parameters.
+ ///
+ public string Help
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return Native.Z3_optimize_get_help(Context.nCtx, NativeObject);
+ }
+ }
+
+ ///
+ /// Sets the optimize solver parameters.
+ ///
+ public Params Parameters
+ {
+ set
+ {
+ Contract.Requires(value != null);
+ Context.CheckContextMatch(value);
+ Native.Z3_optimize_set_params(Context.nCtx, NativeObject, value.NativeObject);
+ }
+ }
+
+ ///
+ /// Retrieves parameter descriptions for Optimize solver.
+ ///
+ public ParamDescrs ParameterDescriptions
+ {
+ get { return new ParamDescrs(Context, Native.Z3_optimize_get_param_descrs(Context.nCtx, NativeObject)); }
+ }
+
+ ///
+ /// Assert a constraint (or multiple) into the optimize solver.
+ ///
+ 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);
+ }
+ }
+
+ ///
+ /// Alias for Assert.
+ ///
+ public void Add(params BoolExpr[] constraints)
+ {
+ Assert(constraints);
+ }
+
+ ///
+ /// Handle to objectives returned by objective functions.
+ ///
+ public class Handle
+ {
+ Optimize opt;
+ uint handle;
+ internal Handle(Optimize opt, uint h)
+ {
+ this.opt = opt;
+ this.handle = h;
+ }
+
+ ///
+ /// Retrieve a lower bound for the objective handle.
+ ///
+ public ArithExpr Lower
+ {
+ get { return opt.GetLower(handle); }
+ }
+
+ ///
+ /// Retrieve an upper bound for the objective handle.
+ ///
+ public ArithExpr Upper
+ {
+ get { return opt.GetUpper(handle); }
+ }
+
+ ///
+ /// Retrieve the value of an objective.
+ ///
+ public ArithExpr Value
+ {
+ get { return Lower; }
+ }
+ }
+
+ ///
+ /// Assert soft constraint
+ ///
+ ///
+ /// Return an objective which associates with the group of constraints.
+ ///
+ 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));
+ }
+
+
+ ///
+ ///
+ /// Check satisfiability of asserted constraints.
+ /// Produce a model that (when the objectives are bounded and
+ /// don't use strict inequalities) meets the objectives.
+ ///
+ ///
+ 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;
+ }
+ }
+
+ ///
+ /// Creates a backtracking point.
+ ///
+ ///
+ public void Push()
+ {
+ Native.Z3_optimize_push(Context.nCtx, NativeObject);
+ }
+
+ ///
+ /// Backtrack one backtracking point.
+ ///
+ /// Note that an exception is thrown if Pop is called without a corresponding Push
+ ///
+ public void Pop()
+ {
+ Native.Z3_optimize_pop(Context.nCtx, NativeObject);
+ }
+
+
+ ///
+ /// The model of the last Check.
+ ///
+ ///
+ /// The result is null if Check was not invoked before,
+ /// if its results was not SATISFIABLE, or if model production is not enabled.
+ ///
+ 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);
+ }
+ }
+
+ ///
+ /// 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.
+ ///
+ public Handle MkMaximize(ArithExpr e)
+ {
+ return new Handle(this, Native.Z3_optimize_maximize(Context.nCtx, NativeObject, e.NativeObject));
+ }
+
+ ///
+ /// Declare an arithmetical minimization objective.
+ /// Similar to MkMaximize.
+ ///
+ public Handle MkMinimize(ArithExpr e)
+ {
+ return new Handle(this, Native.Z3_optimize_minimize(Context.nCtx, NativeObject, e.NativeObject));
+ }
+
+ ///
+ /// Retrieve a lower bound for the objective handle.
+ ///
+ private ArithExpr GetLower(uint index)
+ {
+ return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_lower(Context.nCtx, NativeObject, index));
+ }
+
+
+ ///
+ /// Retrieve an upper bound for the objective handle.
+ ///
+ private ArithExpr GetUpper(uint index)
+ {
+ return (ArithExpr)Expr.Create(Context, Native.Z3_optimize_get_upper(Context.nCtx, NativeObject, index));
+ }
+
+
+ ///
+ /// Print the context to a string (SMT-LIB parseable benchmark).
+ ///
+ public override string ToString()
+ {
+ return Native.Z3_optimize_to_string(Context.nCtx, NativeObject);
+ }
+
+ ///
+ /// Optimize statistics.
+ ///
+ public Statistics Statistics
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result() != 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
+ }
+}
diff --git a/src/api/dotnet/Params.cs b/src/api/dotnet/Params.cs
index c33728491..cd6ac248d 100644
--- a/src/api/dotnet/Params.cs
+++ b/src/api/dotnet/Params.cs
@@ -79,6 +79,7 @@ namespace Microsoft.Z3
Native.Z3_params_set_symbol(Context.nCtx, NativeObject, name.NativeObject, value.NativeObject);
}
+
///
/// Adds a parameter setting.
///
@@ -118,6 +119,7 @@ namespace Microsoft.Z3
///
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);
diff --git a/src/api/dotnet/Readme.NET35 b/src/api/dotnet/Readme.NET35
new file mode 100644
index 000000000..73743fd15
--- /dev/null
+++ b/src/api/dotnet/Readme.NET35
@@ -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"
diff --git a/src/api/java/Context.java b/src/api/java/Context.java
index 4fbd79be2..5de82026f 100644
--- a/src/api/java/Context.java
+++ b/src/api/java/Context.java
@@ -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.
**/
diff --git a/src/api/java/Fixedpoint.java b/src/api/java/Fixedpoint.java
index 57e1e105a..f7d2bc7b7 100644
--- a/src/api/java/Fixedpoint.java
+++ b/src/api/java/Fixedpoint.java
@@ -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);
diff --git a/src/api/python/z3.py b/src/api/python/z3.py
index e58e47640..ca04c419b 100644
--- a/src/api/python/z3.py
+++ b/src/api/python/z3.py
@@ -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
diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py
index d1d85d30e..bd4c72477 100644
--- a/src/api/python/z3printer.py
+++ b/src/api/python/z3printer.py
@@ -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):
diff --git a/src/api/python/z3types.py b/src/api/python/z3types.py
index 5d59368ff..e01b78238 100644
--- a/src/api/python/z3types.py
+++ b/src/api/python/z3types.py
@@ -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
diff --git a/src/api/z3_api.h b/src/api/z3_api.h
index 4dcca078d..d21c979e8 100644
--- a/src/api/z3_api.h
+++ b/src/api/z3_api.h
@@ -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
/*@}*/
diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp
index acdb10bf6..dd18f865c 100644
--- a/src/api/z3_replayer.cpp
+++ b/src/api/z3_replayer.cpp
@@ -22,12 +22,14 @@ Notes:
#include"stream_buffer.h"
#include"symbol.h"
#include"trace.h"
+#include
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 m_heap;
svector 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 > m_obj_arrays;
vector > m_sym_arrays;
vector m_unsigned_arrays;
+ vector > 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(m_args[i].m_uint));
}
}
+ if (k == INT64) {
+ aidx = m_int_arrays.size();
+ nk = INT_ARRAY;
+ m_int_arrays.push_back(svector());
+ svector & v = m_int_arrays.back();
+ for (unsigned i = asz - sz; i < asz; i++) {
+ v.push_back(static_cast(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(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(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(m_args[pos].m_uint);
ptr_vector & 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(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(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(const_cast(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(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(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(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(m_args[pos].m_uint);
ptr_vector 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(&(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(&(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);
}
diff --git a/src/api/z3_replayer.h b/src/api/z3_replayer.h
index 6de4bdb39..412032eb7 100644
--- a/src/api/z3_replayer.h
+++ b/src/api/z3_replayer.h
@@ -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;
diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp
index 9d1f4343f..5245b9685 100644
--- a/src/ast/arith_decl_plugin.cpp
+++ b/src/ast/arith_decl_plugin.cpp
@@ -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()) {
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index 68f7596ee..47079f4c6 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -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(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);
diff --git a/src/ast/ast.h b/src/ast/ast.h
index 68f08e1ac..c336174f5 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -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 & 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);
diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp
index 77c8ac58f..cf2c0478f 100644
--- a/src/ast/ast_smt2_pp.cpp
+++ b/src/ast/ast_smt2_pp.cpp
@@ -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 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(n), m) << std::endl;
diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h
index aa84d6e03..68d669a5e 100644
--- a/src/ast/ast_smt2_pp.h
+++ b/src/ast/ast_smt2_pp.h
@@ -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
diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp
index 59e5c04b9..0484753c5 100644
--- a/src/ast/ast_smt_pp.cpp
+++ b/src/ast/ast_smt_pp.cpp
@@ -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 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";
diff --git a/src/ast/ast_trail.h b/src/ast/ast_trail.h
new file mode 100644
index 000000000..94039875e
--- /dev/null
+++ b/src/ast/ast_trail.h
@@ -0,0 +1,76 @@
+/*++
+Copyright (c) 2006 Microsoft Corporation
+
+Module Name:
+
+ ast_trail.h
+
+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
+class ast2ast_trailmap {
+ ref_vector m_domain;
+ ref_vector m_range;
+ obj_map 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
+class ast2ast_trail : public trail {
+ ast2ast_trailmap& m_map;
+public:
+ ast2ast_trail(ast2ast_trailmap& m, S* s, T* t) :
+ m_map(m) {
+ m.insert(s,t);
+ }
+
+ virtual void undo(Ctx& ctx) {
+ m_map.pop();
+ }
+};
+
+
+#endif /* _AST_TRAIL_H_ */
+
diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp
index ee3271b9b..d707f0178 100644
--- a/src/ast/datatype_decl_plugin.cpp
+++ b/src/ast/datatype_decl_plugin.cpp
@@ -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 & 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 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 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";
}
}
diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h
index 96b678fb2..2218963c3 100644
--- a/src/ast/datatype_decl_plugin.h
+++ b/src/ast/datatype_decl_plugin.h
@@ -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 & op_names, symbol const & logic);
+
private:
bool is_value_visit(expr * arg, ptr_buffer & 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 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(); }
diff --git a/src/ast/expr_map.h b/src/ast/expr_map.h
index 5ab6545f8..3e6f71e86 100644
--- a/src/ast/expr_map.h
+++ b/src/ast/expr_map.h
@@ -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
diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp
index 5f92b4d94..c23de3bfa 100644
--- a/src/ast/fpa/fpa2bv_converter.cpp
+++ b/src/ast/fpa/fpa2bv_converter.cpp
@@ -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();
}
diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp
index abcc97882..75b4e55f4 100644
--- a/src/ast/macros/macro_manager.cpp
+++ b/src/ast/macros/macro_manager.cpp
@@ -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;
diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp
index 83362f5b3..b93dd7657 100644
--- a/src/ast/pattern/pattern_inference.cpp
+++ b/src/ast/pattern/pattern_inference.cpp
@@ -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 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 & 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=).",
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()) {
diff --git a/src/ast/pattern/pattern_inference.h b/src/ast/pattern/pattern_inference.h
index 97897835c..152f7f459 100644
--- a/src/ast/pattern/pattern_inference.h
+++ b/src/ast/pattern/pattern_inference.h
@@ -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 m_bindings;
typedef std::pair 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);
};
diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp
new file mode 100644
index 000000000..36103c4f0
--- /dev/null
+++ b/src/ast/pb_decl_plugin.cpp
@@ -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 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 & 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 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 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 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 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, ¶m, 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, ¶m, 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;
+}
diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h
new file mode 100644
index 000000000..0bc8eab17
--- /dev/null
+++ b/src/ast/pb_decl_plugin.h
@@ -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 & 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_ */
+
diff --git a/src/ast/reg_decl_plugins.cpp b/src/ast/reg_decl_plugins.cpp
index ab1844e07..6a996d288 100644
--- a/src/ast/reg_decl_plugins.cpp
+++ b/src/ast/reg_decl_plugins.cpp
@@ -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));
+ }
}
diff --git a/src/ast/rewriter/ast_counter.cpp b/src/ast/rewriter/ast_counter.cpp
index 6f49a232f..f1ec03528 100644
--- a/src/ast/rewriter/ast_counter.cpp
+++ b/src/ast/rewriter/ast_counter.cpp
@@ -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(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();
}
diff --git a/src/ast/rewriter/ast_counter.h b/src/ast/rewriter/ast_counter.h
index e7251079f..8b3ec3bbd 100644
--- a/src/ast/rewriter/ast_counter.h
+++ b/src/ast/rewriter/ast_counter.h
@@ -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 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 m_sorts;
expr_fast_mark1 m_visited;
+ expr_free_vars m_fv;
ptr_vector 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 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); }
diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h
index b579d698e..b762817e4 100644
--- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h
+++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h
@@ -1038,6 +1038,11 @@ void bit_blaster_tpl::mk_ext_rotate_left_right(unsigned sz, expr * const *
mk_rotate_right(sz, a_bits, static_cast(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());
diff --git a/src/ast/rewriter/datatype_rewriter.cpp b/src/ast/rewriter/datatype_rewriter.cpp
index 8c55ba498..be198c3d9 100644
--- a/src/ast/rewriter/datatype_rewriter.cpp
+++ b/src/ast/rewriter/datatype_rewriter.cpp
@@ -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 const * acc = m_util.get_constructor_accessors(c_decl);
+ SASSERT(acc && acc->size() == a->get_num_args());
+ unsigned num = acc->size();
+ ptr_buffer 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();
}
diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp
index a4886ad1a..37fcdfe6a 100644
--- a/src/ast/rewriter/expr_safe_replace.cpp
+++ b/src/ast/rewriter/expr_safe_replace.cpp
@@ -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 cache;
- ptr_vector 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() {
diff --git a/src/ast/rewriter/expr_safe_replace.h b/src/ast/rewriter/expr_safe_replace.h
index ad626d18f..1f21d35e9 100644
--- a/src/ast/rewriter/expr_safe_replace.h
+++ b/src/ast/rewriter/expr_safe_replace.h
@@ -29,9 +29,12 @@ class expr_safe_replace {
expr_ref_vector m_src;
expr_ref_vector m_dst;
obj_map m_subst;
+ obj_map m_cache;
+ ptr_vector 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__ */
diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp
new file mode 100644
index 000000000..ce6e294c7
--- /dev/null
+++ b/src/ast/rewriter/pb_rewriter.cpp
@@ -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 arg_t;
+ typedef vector 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 const& a,
+ std::pair const& b) {
+ return a.first->get_id() < b.first->get_id();
+ }
+
+ };
+};
+
+expr_ref pb_rewriter::translate_pb2lia(obj_map& 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 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 > 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 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;
+}
+
+
diff --git a/src/ast/rewriter/pb_rewriter.h b/src/ast/rewriter/pb_rewriter.h
new file mode 100644
index 000000000..4c9aaaaf1
--- /dev/null
+++ b/src/ast/rewriter/pb_rewriter.h
@@ -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
+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 m_coeffs;
+ ptr_vector 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& vars, expr* fml);
+ expr_ref mk_validate_rewrite(app_ref& e1, app_ref& e2);
+ void dump_pb_rewrite(expr* fml);
+};
+
+#endif
diff --git a/src/ast/rewriter/pb_rewriter_def.h b/src/ast/rewriter/pb_rewriter_def.h
new file mode 100644
index 000000000..38efd2097
--- /dev/null
+++ b/src/ast/rewriter/pb_rewriter_def.h
@@ -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
+void pb_rewriter_util::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
+void pb_rewriter_util::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
+lbool pb_rewriter_util::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
+void pb_rewriter_util::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
diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h
index 036221f96..12da0069d 100644
--- a/src/ast/rewriter/poly_rewriter_def.h
+++ b/src/ast/rewriter/poly_rewriter_def.h
@@ -34,6 +34,8 @@ void poly_rewriter::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
diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp
index 0e2c8e781..cca2b593e 100644
--- a/src/ast/rewriter/th_rewriter.cpp
+++ b/src/ast/rewriter/th_rewriter.cpp
@@ -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),
diff --git a/src/ast/rewriter/var_subst.cpp b/src/ast/rewriter/var_subst.cpp
index 930267dad..1d01ef85c 100644
--- a/src/ast/rewriter/var_subst.cpp
+++ b/src/ast/rewriter/var_subst.cpp
@@ -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& todo, unsigned offset, expr* e, ptr_vector& sorts) {
+static void get_free_vars_offset(expr_sparse_mark& mark, ptr_vector& todo, unsigned offset, expr* e, ptr_vector& 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& todo, unsigne
switch(e->get_kind()) {
case AST_QUANTIFIER: {
quantifier* q = to_quantifier(e);
- ast_mark mark1;
+ expr_sparse_mark mark1;
ptr_vector 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& todo, unsigne
void get_free_vars(expr* e, ptr_vector& sorts) {
- ast_mark mark;
+ expr_sparse_mark mark;
ptr_vector todo;
get_free_vars_offset(mark, todo, 0, e, sorts);
}
-void get_free_vars(ast_mark& mark, ptr_vector& todo, expr* e, ptr_vector& sorts) {
+void get_free_vars(expr_sparse_mark& mark, ptr_vector& todo, expr* e, ptr_vector& 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);
+}
diff --git a/src/ast/rewriter/var_subst.h b/src/ast/rewriter/var_subst.h
index ffc21e691..7db756d30 100644
--- a/src/ast/rewriter/var_subst.h
+++ b/src/ast/rewriter/var_subst.h
@@ -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& sorts);
-void get_free_vars(ast_mark& mark, ptr_vector& todo, expr* e, ptr_vector& sorts);
+class expr_free_vars {
+ expr_sparse_mark m_mark;
+ ptr_vector m_sorts;
+ ptr_vector 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
diff --git a/src/ast/simplifier/base_simplifier.h b/src/ast/simplifier/base_simplifier.h
index 4afe5c9d7..26bb43838 100644
--- a/src/ast/simplifier/base_simplifier.h
+++ b/src/ast/simplifier/base_simplifier.h
@@ -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 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_ */
diff --git a/src/ast/simplifier/bv_elim.cpp b/src/ast/simplifier/bv_elim.cpp
index 5c19a245e..fc4e7534b 100644
--- a/src/ast/simplifier/bv_elim.cpp
+++ b/src/ast/simplifier/bv_elim.cpp
@@ -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;
diff --git a/src/ast/simplifier/datatype_simplifier_plugin.cpp b/src/ast/simplifier/datatype_simplifier_plugin.cpp
index 129c0e34b..b434a8bd0 100644
--- a/src/ast/simplifier/datatype_simplifier_plugin.cpp
+++ b/src/ast/simplifier/datatype_simplifier_plugin.cpp
@@ -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();
}
diff --git a/src/ast/simplifier/elim_bounds.cpp b/src/ast/simplifier/elim_bounds.cpp
index ce15d9eb1..41ce18549 100644
--- a/src/ast/simplifier/elim_bounds.cpp
+++ b/src/ast/simplifier/elim_bounds.cpp
@@ -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);
}
diff --git a/src/ast/simplifier/pull_ite_tree.cpp b/src/ast/simplifier/pull_ite_tree.cpp
index 080dd5545..05bb3d885 100644
--- a/src/ast/simplifier/pull_ite_tree.cpp
+++ b/src/ast/simplifier/pull_ite_tree.cpp
@@ -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;
}
diff --git a/src/ast/simplifier/push_app_ite.cpp b/src/ast/simplifier/push_app_ite.cpp
index cec84d1f5..e33f0d094 100644
--- a/src/ast/simplifier/push_app_ite.cpp
+++ b/src/ast/simplifier/push_app_ite.cpp
@@ -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(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);
}
diff --git a/src/ast/simplifier/simplifier.cpp b/src/ast/simplifier/simplifier.cpp
index c9f72f4d5..5358e01e4 100644
--- a/src/ast/simplifier/simplifier.cpp
+++ b/src/ast/simplifier/simplifier.cpp
@@ -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 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 & 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 & args, vector
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 & args, vector
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;
}
diff --git a/src/ast/simplifier/simplifier.h b/src/ast/simplifier/simplifier.h
index 7c5bc3102..78e28bea9 100644
--- a/src/ast/simplifier/simplifier.h
+++ b/src/ast/simplifier/simplifier.h
@@ -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();
diff --git a/src/ast/substitution/substitution_tree.cpp b/src/ast/substitution/substitution_tree.cpp
index 037d51e32..6aaa2da66 100644
--- a/src/ast/substitution/substitution_tree.cpp
+++ b/src/ast/substitution/substitution_tree.cpp
@@ -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
diff --git a/src/ast/substitution/substitution_tree.h b/src/ast/substitution/substitution_tree.h
index caa3d37cb..07723a8e4 100644
--- a/src/ast/substitution/substitution_tree.h
+++ b/src/ast/substitution/substitution_tree.h
@@ -123,6 +123,8 @@ class substitution_tree {
template
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();
diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp
index 731608524..4a51da9b0 100644
--- a/src/cmd_context/cmd_context.cpp
+++ b/src/cmd_context/cmd_context.cpp
@@ -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& 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 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::iterator it = fids.begin();
svector::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 eh(*get_opt());
+ scoped_ctrl_c ctrlc(eh);
+ scoped_timer timer(timeout, &eh);
+ ptr_vector 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 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());
}
diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h
index 8ad07e8cc..4e93992d1 100644
--- a/src/cmd_context/cmd_context.h
+++ b/src/cmd_context/cmd_context.h
@@ -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 & 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 m_scopes;
scoped_ptr m_solver_factory;
scoped_ptr m_interpolating_solver_factory;
- ref m_solver;
+ ref m_solver;
ref m_check_sat_result;
+ ref 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& 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(this)->init_manager(); return *m_manager; }
+ ast_manager & m() const { const_cast(this)->init_manager(); return *m_manager; }
virtual ast_manager & get_ast_manager() { return m(); }
pdecl_manager & pm() const { if (!m_pmanager) const_cast(this)->init_manager(); return *m_pmanager; }
sexpr_manager & sm() const { if (!m_sexpr_manager) const_cast(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);
diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp
index f87c8d264..f4ec140ef 100644
--- a/src/cmd_context/context_params.cpp
+++ b/src/cmd_context/context_params.cpp
@@ -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());
}
}
diff --git a/src/duality/duality.h b/src/duality/duality.h
old mode 100755
new mode 100644
index edd89d78f..04527450c
--- a/src/duality/duality.h
+++ b/src/duality/duality.h
@@ -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);
diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp
index f2824c9b0..cb71bd99c 100755
--- a/src/duality/duality_rpfp.cpp
+++ b/src/duality/duality_rpfp.cpp
@@ -2643,6 +2643,10 @@ namespace Duality {
GetGroundLitsUnderQuants(memo,f.body(),res,1);
return;
}
+ if(f.is_var()){
+ // std::cout << "foo!\n";
+ return;
+ }
if(under && f.is_ground())
res.push_back(f);
}
@@ -3065,10 +3069,14 @@ namespace Duality {
node->Annotation.SetEmpty();
hash_set *core = new hash_set;
core->insert(node->Outgoing->dual);
+ expr prev_annot = ctx.bool_val(false);
+ expr prev_impl = ctx.bool_val(false);
+ int repeated_case_count = 0;
while(1){
by_case_counter++;
is.push();
expr annot = !GetAnnotation(node);
+ Transformer old_annot = node->Annotation;
is.add(annot);
if(is.check() == unsat){
is.pop(1);
@@ -3076,56 +3084,70 @@ namespace Duality {
}
is.pop(1);
Push();
- ConstrainEdgeLocalized(node->Outgoing,is.get_implicant());
+ expr the_impl = is.get_implicant();
+ if(eq(the_impl,prev_impl)){
+ // std::cout << "got old implicant\n";
+ repeated_case_count++;
+ }
+ prev_impl = the_impl;
+ ConstrainEdgeLocalized(node->Outgoing,the_impl);
ConstrainEdgeLocalized(node->Outgoing,!GetAnnotation(node)); //TODO: need this?
- check_result foo = Check(root);
- if(foo != unsat){
- slvr().print("should_be_unsat.smt2");
- throw "should be unsat";
- }
- std::vector assumps, axioms_to_add;
- slvr().get_proof().get_assumptions(assumps);
- for(unsigned i = 0; i < assumps.size(); i++){
- (*core).insert(assumps[i]);
- if(axioms_needed.find(assumps[i]) != axioms_needed.end()){
- axioms_to_add.push_back(assumps[i]);
- axioms_needed.erase(assumps[i]);
- }
- }
- // AddToProofCore(*core);
- Transformer old_annot = node->Annotation;
- SolveSingleNode(root,node);
-
- {
- expr itp = GetAnnotation(node);
- dualModel = is.get_model(); // TODO: what does this mean?
- std::vector case_lits;
- itp = StrengthenFormulaByCaseSplitting(itp, case_lits);
- SetAnnotation(node,itp);
- node->Annotation.Formula = node->Annotation.Formula.simplify();
- }
-
- for(unsigned i = 0; i < axioms_to_add.size(); i++)
- is.add(axioms_to_add[i]);
-#define TEST_BAD
-#ifdef TEST_BAD
{
- static int bad_count = 0, num_bads = 1;
- if(bad_count >= num_bads){
- bad_count = 0;
- num_bads = num_bads * 2;
+ check_result foo = Check(root);
+ if(foo != unsat){
Pop(1);
is.pop(1);
delete core;
timer_stop("InterpolateByCases");
- throw Bad();
+ throw ReallyBad();
+ // slvr().print("should_be_unsat.smt2");
+ // throw "should be unsat";
}
- bad_count++;
- }
-#endif
+ std::vector assumps, axioms_to_add;
+ slvr().get_proof().get_assumptions(assumps);
+ for(unsigned i = 0; i < assumps.size(); i++){
+ (*core).insert(assumps[i]);
+ if(axioms_needed.find(assumps[i]) != axioms_needed.end()){
+ axioms_to_add.push_back(assumps[i]);
+ axioms_needed.erase(assumps[i]);
+ }
+ }
+ // AddToProofCore(*core);
+ SolveSingleNode(root,node);
- if(node->Annotation.IsEmpty()){
+ {
+ expr itp = GetAnnotation(node);
+ dualModel = is.get_model(); // TODO: what does this mean?
+ std::vector case_lits;
+ itp = StrengthenFormulaByCaseSplitting(itp, case_lits);
+ SetAnnotation(node,itp);
+ node->Annotation.Formula = node->Annotation.Formula.simplify();
+ }
+
+ for(unsigned i = 0; i < axioms_to_add.size(); i++)
+ is.add(axioms_to_add[i]);
+
+#define TEST_BAD
+#ifdef TEST_BAD
+ {
+ static int bad_count = 0, num_bads = 1;
+ if(bad_count >= num_bads){
+ bad_count = 0;
+ num_bads = num_bads * 2;
+ Pop(1);
+ is.pop(1);
+ delete core;
+ timer_stop("InterpolateByCases");
+ throw Bad();
+ }
+ bad_count++;
+ }
+#endif
+ }
+
+ if(node->Annotation.IsEmpty() || eq(node->Annotation.Formula,prev_annot) || (repeated_case_count > 0 && !axioms_added) || (repeated_case_count >= 10)){
+// looks_bad:
if(!axioms_added){
// add the axioms in the off chance they are useful
const std::vector &theory = ls->get_axioms();
@@ -3134,6 +3156,7 @@ namespace Duality {
axioms_added = true;
}
else {
+ //#define KILL_ON_BAD_INTERPOLANT
#ifdef KILL_ON_BAD_INTERPOLANT
std::cout << "bad in InterpolateByCase -- core:\n";
#if 0
@@ -3175,10 +3198,11 @@ namespace Duality {
is.pop(1);
delete core;
timer_stop("InterpolateByCases");
- throw Bad();
+ throw ReallyBad();
}
}
Pop(1);
+ prev_annot = node->Annotation.Formula;
node->Annotation.UnionWith(old_annot);
}
if(proof_core)
diff --git a/src/duality/duality_solver.cpp b/src/duality/duality_solver.cpp
old mode 100755
new mode 100644
index 69759f9bb..b40ab9370
--- a/src/duality/duality_solver.cpp
+++ b/src/duality/duality_solver.cpp
@@ -2279,6 +2279,18 @@ namespace Duality {
// bad interpolants can get us here
throw DoRestart();
}
+ catch(const RPFP::ReallyBad &){
+ // this could be caused by incompleteness
+ for(unsigned i = 0; i < expansions.size(); i++){
+ Node *node = expansions[i];
+ node->map->Annotation.SetFull();
+ std::vector &chs = node->map->Outgoing->Children;
+ for(unsigned j = 0; j < chs.size(); j++)
+ chs[j]->Annotation.SetFull();
+ reporter->Message("incompleteness: cleared annotation and child annotations");
+ }
+ throw DoRestart();
+ }
catch(char const *msg){
// bad interpolants can get us here
reporter->Message(std::string("interpolation failure:") + msg);
diff --git a/src/duality/duality_wrapper.h b/src/duality/duality_wrapper.h
old mode 100755
new mode 100644
index 979717580..0e367129d
--- a/src/duality/duality_wrapper.h
+++ b/src/duality/duality_wrapper.h
@@ -1489,4 +1489,3 @@ namespace std {
}
#endif
-
diff --git a/src/interp/iz3base.h b/src/interp/iz3base.h
index bca9b8518..956191290 100755
--- a/src/interp/iz3base.h
+++ b/src/interp/iz3base.h
@@ -161,7 +161,7 @@ class iz3base : public iz3mgr, public scopes {
stl_ext::hash_map simplify_memo;
stl_ext::hash_map frame_map; // map assertions to frames
- int frames; // number of frames
+ // int frames; // number of frames
protected:
void add_frame_range(int frame, ast t);
diff --git a/src/interp/iz3hash.h b/src/interp/iz3hash.h
index cd94f0e04..5d401d49f 100644
--- a/src/interp/iz3hash.h
+++ b/src/interp/iz3hash.h
@@ -56,7 +56,7 @@ namespace hash_space {
class hash {
public:
size_t operator()(const std::string &s) const {
- return string_hash(s.c_str(), s.size(), 0);
+ return string_hash(s.c_str(), static_cast(s.size()), 0);
}
};
@@ -111,7 +111,7 @@ namespace hash_space {
4294967291ul
};
- inline unsigned long next_prime(unsigned long n) {
+ inline size_t next_prime(size_t n) {
const unsigned long* to = primes + (int)num_primes;
for(const unsigned long* p = primes; p < to; p++)
if(*p >= n) return *p;
@@ -378,7 +378,7 @@ namespace hash_space {
void resize(size_t new_size) {
const size_t old_n = buckets.size();
if (new_size <= old_n) return;
- const size_t n = next_prime(new_size);
+ const size_t n = next_prime(static_cast(new_size));
if (n <= old_n) return;
Table tmp(n, (Entry*)(0));
for (size_t i = 0; i < old_n; ++i) {
diff --git a/src/interp/iz3mgr.cpp b/src/interp/iz3mgr.cpp
index a39065922..e3ac59dfd 100755
--- a/src/interp/iz3mgr.cpp
+++ b/src/interp/iz3mgr.cpp
@@ -778,6 +778,8 @@ int iz3mgr::occurs_in(ast var, ast e){
bool iz3mgr::solve_arith(const ast &v, const ast &x, const ast &y, ast &res){
+ if(occurs_in(v,y))
+ return false;
if(op(x) == Plus){
int n = num_args(x);
for(int i = 0; i < n; i++){
@@ -801,8 +803,8 @@ iz3mgr::ast iz3mgr::cont_eq(stl_ext::hash_set &cont_eq_memo, bool truth, as
return ast();
cont_eq_memo.insert(e);
if(!truth && op(e) == Equal){
- if(arg(e,0) == v) return(arg(e,1));
- if(arg(e,1) == v) return(arg(e,0));
+ if(arg(e,0) == v && !occurs_in(v,arg(e,1))) return(arg(e,1));
+ if(arg(e,1) == v && !occurs_in(v,arg(e,0))) return(arg(e,0));
ast res;
if(solve_arith(v,arg(e,0),arg(e,1),res)) return res;
if(solve_arith(v,arg(e,1),arg(e,0),res)) return res;
diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h
index 3ec2c42d1..7f66bb2d8 100755
--- a/src/interp/iz3mgr.h
+++ b/src/interp/iz3mgr.h
@@ -278,7 +278,8 @@ class iz3mgr {
}
symb sym(ast t){
- return to_app(t.raw())->get_decl();
+ raw_ast *_ast = t.raw();
+ return is_app(_ast) ? to_app(_ast)->get_decl() : 0;
}
std::string string_of_symbol(symb s){
diff --git a/src/interp/iz3proof_itp.cpp b/src/interp/iz3proof_itp.cpp
index 52ddcd64f..251a56e7a 100755
--- a/src/interp/iz3proof_itp.cpp
+++ b/src/interp/iz3proof_itp.cpp
@@ -1027,7 +1027,7 @@ class iz3proof_itp_impl : public iz3proof_itp {
linear_comb(Aineqs,coeff,make(Leq,make_int(rational(0)),make(Sub,term2,term1)));
}
else {
- ast pf = extract_rewrites(make(concat,mk_true(),rest),p1);
+ ast pf = extract_rewrites(make(concat,mk_true(),last),p1);
ast new_normal = fix_normal(term1,term2,pf);
normals = merge_normal_chains(normals,cons_normal(new_normal,mk_true()), Aproves, Bproves);
}
@@ -2747,7 +2747,8 @@ class iz3proof_itp_impl : public iz3proof_itp {
ast orig_e = e;
pf = make_refl(e); // proof that e = e
- prover::range erng = pv->ast_scope(e);
+ // prover::range erng =
+ pv->ast_scope(e);
#if 0
if(!(erng.lo > erng.hi) && pv->ranges_intersect(pv->ast_scope(e),rng)){
return e; // this term occurs in range, so it's O.K.
diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp
index 26786d57a..f65ec72d4 100755
--- a/src/interp/iz3translate.cpp
+++ b/src/interp/iz3translate.cpp
@@ -1712,11 +1712,17 @@ public:
std::cout << "foo!\n";
// no idea why this shows up
- if(dk == PR_MODUS_PONENS_OEQ)
+ if(dk == PR_MODUS_PONENS_OEQ){
if(conc(prem(proof,0)) == con){
res = translate_main(prem(proof,0),expect_clause);
return res;
}
+ if(expect_clause && op(con) == Or){ // skolemization does this
+ Iproof::node clause = translate_main(prem(proof,0),true);
+ res = RewriteClause(clause,prem(proof,1));
+ return res;
+ }
+ }
#if 0
if(1 && dk == PR_TRANSITIVITY && pr(prem(proof,1)) == PR_COMMUTATIVITY){
@@ -1800,7 +1806,9 @@ public:
}
break;
}
- case PR_MONOTONICITY: {
+ case PR_QUANT_INTRO:
+ case PR_MONOTONICITY:
+ {
std::vector eqs; eqs.resize(args.size());
for(unsigned i = 0; i < args.size(); i++)
eqs[i] = conc(prem(proof,i));
diff --git a/src/math/simplex/network_flow.h b/src/math/simplex/network_flow.h
new file mode 100644
index 000000000..e0b415c03
--- /dev/null
+++ b/src/math/simplex/network_flow.h
@@ -0,0 +1,200 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ network_flow.h
+
+Abstract:
+
+ Implements Network Simplex algorithm for min cost flow problem
+
+Author:
+
+ Anh-Dung Phan (t-anphan) 2013-10-24
+
+Notes:
+
+ This will be used to solve the dual of min cost flow problem
+ i.e. optimization of difference constraint.
+
+ We need a function to reduce DL constraints to min cost flow problem
+ and another function to convert from min cost flow solution to DL solution.
+
+ It remains unclear how to convert DL assignment to a basic feasible solution of Network Simplex.
+ A naive approach is to run an algorithm on max flow in order to get a spanning tree.
+
+--*/
+#ifndef _NETWORK_FLOW_H_
+#define _NETWORK_FLOW_H_
+
+#include"inf_rational.h"
+#include"diff_logic.h"
+#include"spanning_tree.h"
+
+namespace smt {
+
+ enum min_flow_result {
+ // Min cost flow problem is infeasible.
+ // Diff logic optimization could be unbounded or infeasible.
+ INFEASIBLE,
+ // Min cost flow and diff logic optimization are both optimal.
+ OPTIMAL,
+ // Min cost flow problem is unbounded.
+ // Diff logic optimization has to be infeasible.
+ UNBOUNDED,
+ };
+
+ enum pivot_rule {
+ // First eligible edge pivot rule
+ // Edges are traversed in a wraparound fashion
+ FIRST_ELIGIBLE,
+ // Best eligible edge pivot rule
+ // The best edge is selected in every iteration
+ BEST_ELIGIBLE,
+ // Candidate list pivot rule
+ // Major iterations: candidate list is built from eligible edges (in a wraparound way)
+ // Minor iterations: the best edge is selected from the list
+ CANDIDATE_LIST
+ };
+
+ // Solve minimum cost flow problem using Network Simplex algorithm
+ template
+ class network_flow : private Ext {
+ private:
+ enum edge_state {
+ LOWER = 1,
+ BASIS = 0,
+ };
+
+ typedef dl_var node;
+ typedef dl_edge edge;
+ typedef dl_graph graph;
+ typedef typename Ext::numeral numeral;
+ typedef typename Ext::fin_numeral fin_numeral;
+
+ class pivot_rule_impl {
+ protected:
+ graph & m_graph;
+ svector & m_states;
+ vector & m_potentials;
+ edge_id & m_enter_id;
+ bool edge_in_tree(edge_id id) const { return m_states[id] == BASIS; }
+ public:
+ pivot_rule_impl(graph & g, vector & potentials,
+ svector & states, edge_id & enter_id)
+ : m_graph(g),
+ m_potentials(potentials),
+ m_states(states),
+ m_enter_id(enter_id) {
+ }
+ virtual ~pivot_rule_impl() {}
+ virtual bool choose_entering_edge() = 0;
+ virtual pivot_rule rule() const = 0;
+ };
+
+ class first_eligible_pivot : public pivot_rule_impl {
+ edge_id m_next_edge;
+ public:
+ first_eligible_pivot(graph & g, vector & potentials,
+ svector & states, edge_id & enter_id) :
+ pivot_rule_impl(g, potentials, states, enter_id),
+ m_next_edge(0) {
+ }
+ virtual bool choose_entering_edge();
+ virtual pivot_rule rule() const { return FIRST_ELIGIBLE; }
+ };
+
+ class best_eligible_pivot : public pivot_rule_impl {
+ public:
+ best_eligible_pivot(graph & g, vector & potentials,
+ svector & states, edge_id & enter_id) :
+ pivot_rule_impl(g, potentials, states, enter_id) {
+ }
+ virtual pivot_rule rule() const { return BEST_ELIGIBLE; }
+ virtual bool choose_entering_edge();
+ };
+
+ class candidate_list_pivot : public pivot_rule_impl {
+ private:
+ edge_id m_next_edge;
+ svector m_candidates;
+ unsigned m_num_candidates;
+ unsigned m_minor_step;
+ unsigned m_current_length;
+ static const unsigned NUM_CANDIDATES = 10;
+ static const unsigned MINOR_STEP_LIMIT = 5;
+
+ public:
+ candidate_list_pivot(graph & g, vector & potentials,
+ svector & states, edge_id & enter_id) :
+ pivot_rule_impl(g, potentials, states, enter_id),
+ m_next_edge(0),
+ m_minor_step(0),
+ m_current_length(0),
+ m_num_candidates(NUM_CANDIDATES),
+ m_candidates(m_num_candidates) {
+ }
+
+ virtual pivot_rule rule() const { return CANDIDATE_LIST; }
+
+ virtual bool choose_entering_edge();
+ };
+
+ graph m_graph;
+ scoped_ptr m_tree;
+ scoped_ptr m_pivot;
+ vector m_balances; // nodes + 1 |-> [b -1b] Denote supply/demand b_i on node i
+ vector m_potentials; // nodes + 1 |-> initial: +/- 1
+ // Duals of flows which are convenient to compute dual solutions
+ // become solutions to Dual simplex.
+ vector m_flows; // edges + nodes |-> assignemnt Basic feasible flows
+ svector m_states;
+ unsigned m_step;
+ edge_id m_enter_id;
+ edge_id m_leave_id;
+ optional m_delta;
+
+ // Initialize the network with a feasible spanning tree
+ void initialize();
+
+ void update_potentials();
+
+ void update_flows();
+
+ bool choose_entering_edge(pivot_rule pr);
+
+ // Send as much flow as possible around the cycle, the first basic edge with flow 0 will leave
+ // Return false if the problem is unbounded
+ bool choose_leaving_edge();
+
+ void update_spanning_tree();
+
+ numeral get_cost() const;
+
+ bool edge_in_tree(edge_id id) const;
+
+ bool is_infeasible();
+ bool check_well_formed();
+ bool check_optimal();
+
+ void display_primal(std::ofstream & os);
+ void display_dual(std::ofstream & os);
+ void display_spanning_tree(std::ofstream & os);
+ void display_system(std::ofstream & os);
+
+ public:
+
+ network_flow(graph & g, vector const & balances);
+
+ // Minimize cost flows
+ // Return true if found an optimal solution, and return false if unbounded
+ min_flow_result min_cost(pivot_rule pr = FIRST_ELIGIBLE);
+
+ // Compute the optimal solution
+ numeral get_optimal_solution(vector & result, bool is_dual);
+
+ };
+}
+
+#endif
diff --git a/src/math/simplex/network_flow_def.h b/src/math/simplex/network_flow_def.h
new file mode 100644
index 000000000..93e1ded9a
--- /dev/null
+++ b/src/math/simplex/network_flow_def.h
@@ -0,0 +1,526 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ network_flow_def.h
+
+Abstract:
+
+ Implements Network Simplex algorithm for min cost flow problem
+
+Author:
+
+ Anh-Dung Phan (t-anphan) 2013-10-24
+
+Notes:
+
+--*/
+
+#ifndef _NETWORK_FLOW_DEF_H_
+#define _NETWORK_FLOW_DEF_H_
+
+#include"network_flow.h"
+#include"uint_set.h"
+#include"spanning_tree_def.h"
+
+namespace smt {
+
+ template
+ bool network_flow::first_eligible_pivot::choose_entering_edge() {
+ numeral cost = numeral::zero();
+ int num_edges = m_graph.get_num_edges();
+ for (int i = m_next_edge; i < m_next_edge + num_edges; ++i) {
+ edge_id id = i % num_edges;
+ if (edge_in_tree(id)) {
+ continue;
+ }
+ node src = m_graph.get_source(id);
+ node tgt = m_graph.get_target(id);
+ cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id);
+ if (cost.is_pos()) {
+ m_next_edge = m_enter_id = id;
+ return true;
+ }
+ }
+ return false;
+ };
+
+ template
+ bool network_flow::best_eligible_pivot::choose_entering_edge() {
+ unsigned num_edges = m_graph.get_num_edges();
+ numeral cost = numeral::zero();
+ for (unsigned i = 0; i < num_edges; ++i) {
+ node src = m_graph.get_source(i);
+ node tgt = m_graph.get_target(i);
+ if (!edge_in_tree(i)) {
+ numeral new_cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(i);
+ if (new_cost > cost) {
+ cost = new_cost;
+ m_enter_id = i;
+ }
+ }
+ }
+ return cost.is_pos();
+ };
+
+ template
+ bool network_flow::candidate_list_pivot::choose_entering_edge() {
+ numeral cost = numeral::zero();
+ if (m_current_length == 0 || m_minor_step == MINOR_STEP_LIMIT) {
+ // Build the candidate list
+ unsigned num_edges = m_graph.get_num_edges();
+ m_current_length = 0;
+ for (unsigned i = m_next_edge; i < m_next_edge + num_edges; ++i) {
+ edge_id id = (i >= num_edges) ? i - num_edges : i;
+ node src = m_graph.get_source(id);
+ node tgt = m_graph.get_target(id);
+ if (!edge_in_tree(id)) {
+ numeral new_cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id);
+ if (new_cost.is_pos()) {
+ m_candidates[m_current_length] = id;
+ ++m_current_length;
+ if (new_cost > cost) {
+ cost = new_cost;
+ m_enter_id = id;
+ }
+ }
+ if (m_current_length >= m_num_candidates) break;
+ }
+ }
+ m_next_edge = m_enter_id;
+ m_minor_step = 1;
+ return cost.is_pos();
+ }
+
+ ++m_minor_step;
+ for (unsigned i = 0; i < m_current_length; ++i) {
+ edge_id id = m_candidates[i];
+ node src = m_graph.get_source(id);
+ node tgt = m_graph.get_target(id);
+ if (!edge_in_tree(id)) {
+ numeral new_cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(id);
+ if (new_cost > cost) {
+ cost = new_cost;
+ m_enter_id = id;
+ }
+ // Remove stale candidates
+ if (!new_cost.is_pos()) {
+ --m_current_length;
+ m_candidates[i] = m_candidates[m_current_length];
+ --i;
+ }
+ }
+ }
+ return cost.is_pos();
+ };
+
+ template
+ network_flow::network_flow(graph & g, vector const & balances) :
+ m_balances(balances) {
+ // Network flow graph has the edges in the reversed order compared to constraint graph
+ // We only take enabled edges from the original graph
+ for (unsigned i = 0; i < g.get_num_nodes(); ++i) {
+ m_graph.init_var(i);
+ }
+ vector const & es = g.get_all_edges();
+ for (unsigned i = 0; i < es.size(); ++i) {
+ edge const & e = es[i];
+ if (e.is_enabled()) {
+ m_graph.add_edge(e.get_target(), e.get_source(), e.get_weight(), explanation());
+ }
+ }
+ TRACE("network_flow", {
+ tout << "Difference logic optimization:" << std::endl;
+ display_dual(tout);
+ tout << "Minimum cost flow:" << std::endl;
+ display_primal(tout);
+ };);
+
+ m_step = 0;
+ m_tree = alloc(basic_spanning_tree, m_graph);
+ }
+
+
+ template
+ void network_flow::initialize() {
+ TRACE("network_flow", tout << "initialize...\n";);
+ // Create an artificial root node to construct initial spanning tree
+ unsigned num_nodes = m_graph.get_num_nodes();
+ unsigned num_edges = m_graph.get_num_edges();
+
+ node root = num_nodes;
+ m_graph.init_var(root);
+
+ m_potentials.resize(num_nodes + 1);
+ m_potentials[root] = numeral::zero();
+
+ m_balances.resize(num_nodes + 1);
+ fin_numeral sum_supply = fin_numeral::zero();
+ for (unsigned i = 0; i < num_nodes; ++i) {
+ sum_supply += m_balances[i];
+ }
+ m_balances[root] = -sum_supply;
+
+ m_flows.resize(num_nodes + num_edges);
+ m_flows.fill(numeral::zero());
+ m_states.resize(num_nodes + num_edges);
+ m_states.fill(LOWER);
+
+ // Create artificial edges from/to root node to/from other nodes and initialize the spanning tree
+ svector tree;
+ for (unsigned i = 0; i < num_nodes; ++i) {
+ bool is_forward = !m_balances[i].is_neg();
+ m_states[num_edges + i] = BASIS;
+ node src = is_forward ? i : root;
+ node tgt = is_forward ? root : i;
+ m_flows[num_edges + i] = is_forward ? m_balances[i] : -m_balances[i];
+ m_potentials[i] = is_forward ? numeral::one() : -numeral::one();
+ tree.push_back(m_graph.add_edge(src, tgt, numeral::one(), explanation()));
+ }
+
+ m_tree->initialize(tree);
+
+ TRACE("network_flow",
+ tout << pp_vector("Potentials", m_potentials);
+ tout << pp_vector("Flows", m_flows);
+ tout << "Cost: " << get_cost() << "\n";
+ tout << "Spanning tree:\n";
+ display_spanning_tree(tout);
+ display_primal(tout););
+ SASSERT(check_well_formed());
+ }
+
+ template
+ void network_flow::update_potentials() {
+ node src = m_graph.get_source(m_enter_id);
+ node tgt = m_graph.get_target(m_enter_id);
+ numeral cost = m_potentials[src] - m_potentials[tgt] - m_graph.get_weight(m_enter_id);
+ numeral change;
+ node start;
+ if (m_tree->in_subtree_t2(tgt)) {
+ change = cost;
+ start = tgt;
+ }
+ else {
+ change = -cost;
+ start = src;
+ }
+ SASSERT(m_tree->in_subtree_t2(start));
+ TRACE("network_flow", tout << "update_potentials of T_" << start << " with change = " << change << "...\n";);
+ svector descendants;
+ m_tree->get_descendants(start, descendants);
+ SASSERT(descendants.size() >= 1);
+ for (unsigned i = 0; i < descendants.size(); ++i) {
+ node u = descendants[i];
+ m_potentials[u] += change;
+ }
+ TRACE("network_flow", tout << pp_vector("Potentials", m_potentials););
+ }
+
+ template
+ void network_flow::update_flows() {
+ m_flows[m_enter_id] += *m_delta;
+ node src = m_graph.get_source(m_enter_id);
+ node tgt = m_graph.get_target(m_enter_id);
+ svector path;
+ svector against;
+ m_tree->get_path(src, tgt, path, against);
+ SASSERT(path.size() >= 1);
+ for (unsigned i = 0; i < path.size(); ++i) {
+ edge_id e_id = path[i];
+ m_flows[e_id] += against[i] ? - *m_delta : *m_delta;
+ }
+ TRACE("network_flow", tout << pp_vector("Flows", m_flows););
+ }
+
+ template
+ bool network_flow::choose_leaving_edge() {
+ node src = m_graph.get_source(m_enter_id);
+ node tgt = m_graph.get_target(m_enter_id);
+ m_delta.set_invalid();
+ edge_id leave_id = null_edge_id;
+ svector path;
+ svector against;
+ m_tree->get_path(src, tgt, path, against);
+ SASSERT(path.size() >= 1);
+ for (unsigned i = 0; i < path.size(); ++i) {
+ edge_id e_id = path[i];
+ if (against[i] && (!m_delta || m_flows[e_id] < *m_delta)) {
+ m_delta = m_flows[e_id];
+ leave_id = e_id;
+ }
+ }
+ m_leave_id = leave_id;
+
+ return m_delta;
+ }
+
+ template
+ void network_flow