3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-20 07:36:38 +00:00

merge with master

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2022-04-16 18:30:03 +02:00
commit 3533bf486f
223 changed files with 7175 additions and 2167 deletions

30
.github/workflows/cross-build.yml vendored Normal file
View file

@ -0,0 +1,30 @@
name: RISC V and PowerPC 64
on:
push:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
container: ubuntu:jammy
strategy:
fail-fast: false
matrix:
arch: [ aarch64, riscv64, powerpc64 ]
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Install cross build tools
run: apt update && apt install -y ninja-build cmake python3 g++-11-${{ matrix.arch }}-linux-gnu
env:
DEBIAN_FRONTEND: noninteractive
- name: Configure CMake and build
run: |
mkdir build && cd build
cmake -DCMAKE_CXX_COMPILER=${{ matrix.arch }}-linux-gnu-g++-11 ../
make -j$(nproc)

1
.gitignore vendored
View file

@ -81,6 +81,7 @@ src/api/js/build/
src/api/js/**/*.d.ts
!src/api/js/scripts/*.js
!src/api/js/src/*.js
debug/*
out/**
*.bak

View file

@ -2,7 +2,7 @@
cmake_minimum_required(VERSION 3.4)
set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_compiler_flags_overrides.cmake")
project(Z3 VERSION 4.8.15.0 LANGUAGES CXX C)
project(Z3 VERSION 4.8.16.0 LANGUAGES CXX C)
################################################################################
# Project version
@ -198,7 +198,9 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "GNU")
message(STATUS "Platform: GNU/Hurd")
list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_HURD_")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
# Does macOS really not need any special flags?
if (TARGET_ARCHITECTURE STREQUAL "arm64")
set(CMAKE_OSX_ARCHITECTURES "arm64")
endif()
message(STATUS "Platform: Darwin")
elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
message(STATUS "Platform: FreeBSD")
@ -431,6 +433,11 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
string(APPEND CMAKE_SHARED_LINKER_FLAGS " /RELEASE")
endif()
################################################################################
# Check atomic linking as needed
################################################################################
include(${PROJECT_SOURCE_DIR}/cmake/check_link_atomic.cmake)
################################################################################
# Report default CMake flags
################################################################################

View file

@ -80,7 +80,7 @@ A 32 bit build should work similarly (but is untested); the same is true for 32/
By default, it will install z3 executable at ``PREFIX/bin``, libraries at
``PREFIX/lib``, and include files at ``PREFIX/include``, where ``PREFIX``
installation prefix if inferred by the ``mk_make.py`` script. It is usually
installation prefix is inferred by the ``mk_make.py`` script. It is usually
``/usr`` for most Linux distros, and ``/usr/local`` for FreeBSD and macOS. Use
the ``--prefix=`` command line option to change the install prefix. For example:
@ -158,7 +158,7 @@ You can install the Python wrapper for Z3 for the latest release from pypi using
Use the ``--python`` command line flag with ``mk_make.py`` to enable building these.
Note that is required on certain platforms that the Python package directory
Note that it is required on certain platforms that the Python package directory
(``site-packages`` on most distributions and ``dist-packages`` on Debian based
distributions) live under the install prefix. If you use a non standard prefix
you can use the ``--pypkgdir`` option to change the Python package directory
@ -199,6 +199,11 @@ The Julia package [Z3.jl](https://github.com/ahumenberger/Z3.jl) wraps the C++ A
A WebAssembly build with associated TypeScript typings is published on npm as [z3-solver](https://www.npmjs.com/package/z3-solver). Information about building these bindings can be found in [src/api/js](src/api/js).
### Smalltalk (``Pharo`` / ``Smalltalk/X``)
Project [MachineArithmetic](https://github.com/shingarov/MachineArithmetic) provides Smalltalk interface
to Z3's C API. For more information, see [MachineArithmetic/README.md](https://github.com/shingarov/MachineArithmetic/blob/pure-z3/MachineArithmetic/README.md)
## System Overview
![System Diagram](https://github.com/Z3Prover/doc/blob/master/programmingz3/images/Z3Overall.jpg)
@ -215,5 +220,6 @@ A WebAssembly build with associated TypeScript typings is published on npm as [z
* C
* OCaml
* [Julia](https://github.com/ahumenberger/Z3.jl)
* [Smalltalk](https://github.com/shingarov/MachineArithmetic/blob/pure-z3/MachineArithmetic/README.md) (supports Pharo and Smalltalk/X)

View file

@ -10,6 +10,10 @@ Version 4.8.next
- native word level bit-vector solving.
- introduction of simple induction lemmas to handle a limited repertoire of induction proofs.
Version 4.8.15
==============
- elaborate user propagator API. Change id based scheme to expressions
- includes a Web Assembly ffi API thanks to Kevin Gibbons
Version 4.8.14
==============

View file

@ -217,12 +217,12 @@ jobs:
$(setupCmd1)
$(setupCmd2)
$(setupCmd3)
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" $(arch)
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" $(arch)
cmake $(bindings) -G "NMake Makefiles" ../
nmake
cd ..
- script: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" $(arch)
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" $(arch)
pushd build\python
python z3test.py z3
python z3test.py z3num

View file

@ -0,0 +1,23 @@
set(ATOMIC_TEST_SOURCE "
#include <atomic>
std::atomic<int> x;
std::atomic<short> y;
std::atomic<char> z;
std::atomic<long long> w;
int main() {
++z;
++y;
++w;
return ++x;
}")
CHECK_CXX_SOURCE_COMPILES("${ATOMIC_TEST_SOURCE}" BUILTIN_ATOMIC)
if (NOT BUILTIN_ATOMIC)
set(CMAKE_REQUIRED_LIBRARIES atomic)
CHECK_CXX_SOURCE_COMPILES("${ATOMIC_TEST_SOURCE}" ATOMICS_REQUIRE_LIBATOMIC)
unset(CMAKE_REQUIRED_LIBRARIES)
if (ATOMICS_REQUIRE_LIBATOMIC)
list(APPEND Z3_DEPENDENT_LIBS atomic)
else()
message(FATAL_ERROR "Host compiler must support std::atomic!")
endif()
endif()

View file

@ -5,6 +5,10 @@
#error CMAKE_TARGET_ARCH_i686
#elif defined(__x86_64__) || defined(_M_X64)
#error CMAKE_TARGET_ARCH_x86_64
#elif defined(__ARM_ARCH_ISA_A64)
#error CMAKE_TARGET_ARCH_arm64
#elif defined(__ARM_ARCH)
#error CMAKE_TARGET_ARCH_arm
#else
#error CMAKE_TARGET_ARCH_unknown
#endif

View file

@ -4,11 +4,10 @@
Z3 is a high-performance theorem prover being developed at <a class="el"
href="http://research.microsoft.com">Microsoft Research</a>.
<b>The Z3 website is at <a class="el" href="http://github.com/z3prover">http://github.com/z3prover.</a>.</b>
<b>The Z3 website is at <a class="el" href="http://github.com/z3prover">http://github.com/z3prover</a>.</b>
This website hosts the automatically generated documentation for the Z3 APIs.
- \ref @C_API@
- \ref @CPP_API@ @DOTNET_API@ @JAVA_API@ @PYTHON_API@ @OCAML_API@
- Try Z3 online at <a href="http://rise4fun.com/z3">RiSE4Fun</a>.
*/

View file

@ -270,8 +270,7 @@ ALIASES = "beginfaq=<ul>" \
"emph{1}=<em>\1</em>" \
"extdoc{2}=<a class=\"el\" href=\"\1\">\2</a>" \
"nicebox{1}=<div class=\"fragment\"><pre class=\"fragment\">\1</pre></div>" \
"ccode{1}=<tt>\1</tt>" \
"zframe=<iframe allowtransparency=\"true\" frameborder=\"0\" style=\"width:600px;height:600px\" src=\"http://rise4fun.com/z3?frame=1&menu=0\"> </iframe>"
"ccode{1}=<tt>\1</tt>"
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"

View file

@ -64,8 +64,7 @@ ALIASES = "beginfaq=<ul>" \
"emph{1}=<em>\1</em>" \
"extdoc{2}=<a class=\"el\" href=\"\1\">\2</a>" \
"nicebox{1}=<div class=\"fragment\"><pre class=\"fragment\">\1</pre></div>" \
"ccode{1}=<tt>\1</tt>" \
"zframe=<iframe allowtransparency=\"true\" frameborder=\"0\" style=\"width:600px;height:600px\" src=\"http://rise4fun.com/z3?frame=1&menu=0\"> </iframe>"
"ccode{1}=<tt>\1</tt>"
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO

View file

@ -1868,7 +1868,7 @@ class JavaExample
}
} else
{
System.out.println("BUG, the constraints are satisfiable.");
System.out.println("BUG, the constraints are not satisfiable.");
}
}

View file

@ -5,43 +5,34 @@ from z3.z3util import get_vars
Modified from the example in pysmt
https://github.com/pysmt/pysmt/blob/97088bf3b0d64137c3099ef79a4e153b10ccfda7/examples/efsmt.py
'''
def efsmt(y, phi, maxloops=None):
"""Solving exists x. forall y. phi(x, y)"""
vars = get_vars(phi)
x = [item for item in vars if item not in y]
esolver = Solver()
fsolver = Solver()
esolver.add(BoolVal(True))
def efsmt(ys, phi, maxloops = None):
"""Solving exists xs. forall ys. phi(x, y)"""
xs = [x for x in get_vars(phi) if x not in ys]
E = Solver()
F = Solver()
E.add(BoolVal(True))
loops = 0
while maxloops is None or loops <= maxloops:
loops += 1
eres = esolver.check()
if eres == unsat:
return unsat
else:
emodel = esolver.model()
tau = [emodel.eval(var, True) for var in x]
sub_phi = phi
for i in range(len(x)):
sub_phi = simplify(substitute(sub_phi, (x[i], tau[i])))
fsolver.add(Not(sub_phi))
if fsolver.check() == sat:
fmodel = fsolver.model()
sigma = [fmodel.eval(v, True) for v in y]
sub_phi = phi
for j in range(len(y)):
sub_phi = simplify(substitute(sub_phi, (y[j], sigma[j])))
esolver.add(sub_phi)
eres = E.check()
if eres == sat:
emodel = E.model()
sub_phi = substitute(phi, [(x, emodel.eval(x, True)) for x in xs])
F.push()
F.add(Not(sub_phi))
fres = F.check()
if fres == sat:
fmodel = F.model()
sub_phi = substitute(phi, [(y, fmodel.eval(y, True)) for y in ys])
E.add(sub_phi)
else:
return sat
return fres, [(x, emodel.eval(x, True)) for x in xs]
F.pop()
else:
return eres
return unknown
def test():
x, y, z = Reals("x y z")
fmla = Implies(And(y > 0, y < 10), y - 2 * x < 7)
fmlb = And(y > 3, x == 1)
print(efsmt([y], fmla))
print(efsmt([y], fmlb))
test()
x, y, z = Reals("x y z")
print(efsmt([y], Implies(And(y > 0, y < 10), y - 2 * x < 7)))
print(efsmt([y], And(y > 3, x == 1)))

View file

@ -17,13 +17,71 @@ def visitor(e, seen):
yield e
return
x, y = Ints('x y')
fml = x + x + y > 2
seen = {}
for e in visitor(fml, seen):
if is_const(e) and e.decl().kind() == Z3_OP_UNINTERPRETED:
print("Variable", e)
else:
print(e)
def modify(e, fn):
seen = {}
def visit(e):
if e in seen:
pass
elif fn(e) is not None:
seen[e] = fn(e)
elif is_and(e):
chs = [visit(ch) for ch in e.children()]
seen[e] = And(chs)
elif is_or(e):
chs = [visit(ch) for ch in e.children()]
seen[e] = Or(chs)
elif is_app(e):
chs = [visit(ch) for ch in e.children()]
seen[e] = e.decl()(chs)
elif is_quantifier(e):
# Note: does not work for Lambda that requires a separate case
body = visit(e.body())
is_forall = e.is_forall()
num_pats = e.num_patterns()
pats = (Pattern * num_pats)()
for i in range(num_pats):
pats[i] = e.pattern(i).ast
num_decls = e.num_vars()
sorts = (Sort * num_decls)()
names = (Symbol * num_decls)()
for i in range(num_decls):
sorts[i] = e.var_sort(i).ast
names[i] = to_symbol(e.var_name(i), e.ctx)
r = QuantifierRef(Z3_mk_quantifier(e.ctx_ref(), is_forall, e.weight(), num_pats, pats, num_decls, sorts, names, body.ast), e.ctx)
seen[e] = r
else:
seen[e] = e
return seen[e]
return visit(e)
if __name__ == "__main__":
x, y = Ints('x y')
fml = x + x + y > 2
seen = {}
for e in visitor(fml, seen):
if is_const(e) and e.decl().kind() == Z3_OP_UNINTERPRETED:
print("Variable", e)
else:
print(e)
s = SolverFor("HORN")
inv = Function('inv', IntSort(), IntSort(), BoolSort())
i, ip, j, jp = Ints('i ip j jp')
s.add(ForAll([i, j], Implies(i == 0, inv(i, j))))
s.add(ForAll([i, ip, j, jp], Implies(And(inv(i, j), i < 10, ip == i + 1), inv(ip, jp))))
s.add(ForAll([i, j], Implies(And(inv(i, j), i >= 10), i == 10)))
a0, a1, a2 = Ints('a0 a1 a2')
b0, b1, b2 = Ints('b0 b1 b2')
x = Var(0, IntSort())
y = Var(1, IntSort())
template = And(a0 + a1*x + a2*y >= 0, b0 + b1*x + b2*y >= 0)
def update(e):
if is_app(e) and eq(e.decl(), inv):
return substitute_vars(template, (e.arg(0)), e.arg(1))
return None
for f in s.assertions():
f_new = modify(f, update)
print(f_new)

View file

@ -24,7 +24,15 @@ message(STATUS "Z3_FOUND: ${Z3_FOUND}")
message(STATUS "Found Z3 ${Z3_VERSION_STRING}")
message(STATUS "Z3_DIR: ${Z3_DIR}")
add_executable(user_propagator_example example.cpp)
add_executable(user_propagator_example
example.cpp
common.h
user_propagator.h
user_propagator_with_theory.h
user_propagator_subquery_maximisation.h
user_propagator_internal_maximisation.h
user_propagator_created_maximisation.h)
target_include_directories(user_propagator_example PRIVATE ${Z3_CXX_INCLUDE_DIRS})
target_link_libraries(user_propagator_example PRIVATE ${Z3_LIBRARIES})

View file

@ -0,0 +1,77 @@
#pragma once
#include <algorithm>
#include <chrono>
#include <iostream>
#include <random>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <cstring>
#include <optional>
#include "z3++.h"
using std::to_string;
#define SIZE(x) std::extent<decltype(x)>::value
// #define VERBOSE // Log events
#ifdef VERBOSE
#define WriteEmptyLine std::cout << std::endl
#define WriteLine(x) std::cout << (x) << std::endl
#define Write(x) std::cout << x
#else
#define WriteEmptyLine
#define WriteLine(x)
#define Write(x)
#endif
int log2i(unsigned n) {
if (n <= 0) {
return 0;
}
if (n <= 2) {
return 1;
}
unsigned l = 1;
int i = 0;
while (l < n) {
l <<= 1;
i++;
}
return i;
}
typedef std::vector<unsigned> simple_model;
// For putting z3 expressions in hash-tables
namespace std {
template<>
struct hash<simple_model> {
std::size_t operator()(const simple_model &m) const {
size_t hash = 0;
for (unsigned i = 0; i < m.size(); i++) {
hash *= m.size();
hash += m[i];
}
return hash;
}
};
template<>
struct hash<z3::expr> {
std::size_t operator()(const z3::expr &k) const {
return k.hash();
}
};
// Do not use Z3's == operator in the hash table
template<>
struct equal_to<z3::expr> {
bool operator()(const z3::expr &lhs, const z3::expr &rhs) const {
return z3::eq(lhs, rhs);
}
};
}

View file

@ -1,13 +1,8 @@
#include <algorithm>
#include <chrono>
#include <iostream>
#include <random>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <cstring>
#include "z3++.h"
#include "user_propagator.h"
#include "user_propagator_with_theory.h"
#include "user_propagator_subquery_maximisation.h"
#include "user_propagator_internal_maximisation.h"
#include "user_propagator_created_maximisation.h"
/**
* The program solves the n-queens problem (number of solutions) with 4 different approaches
@ -20,206 +15,57 @@
*/
using namespace std::chrono;
using std::to_string;
#define QUEEN
#define REPETITIONS 5
#define SIZE(x) std::extent<decltype(x)>::value
#define MIN_BOARD 4
#define MAX_BOARD1 12
#define MAX_BOARD2 12
#ifdef LOG
#define WriteEmptyLine std::cout << std::endl
#define WriteLine(x) std::cout << (x) << std::endl
#define Write(x) std::cout << x
#else
#define WriteEmptyLine
#define WriteLine(x)
#define Write(x)
#endif
typedef std::vector<unsigned> model;
struct model_hash_function {
std::size_t operator()(const model &m) const {
size_t hash = 0;
for (unsigned i = 0; i < m.size(); i++) {
hash *= m.size();
hash += m[i];
}
return hash;
}
};
class user_propagator : public z3::user_propagator_base {
protected:
unsigned board;
std::unordered_map<unsigned, unsigned>& id_mapping;
model currentModel;
std::unordered_set<model, model_hash_function> modelSet;
std::vector<unsigned> fixedValues;
std::stack<unsigned> fixedCnt;
int solutionId = 1;
public:
int getModelCount() const {
return solutionId - 1;
}
void final() final {
this->conflict((unsigned) fixedValues.size(), fixedValues.data());
if (modelSet.find(currentModel) != modelSet.end()) {
WriteLine("Got already computed model");
return;
}
Write("Model #" << solutionId << ":\n");
solutionId++;
#ifdef LOG
for (unsigned i = 0; i < fixedValues.size(); i++) {
unsigned id = fixedValues[i];
WriteLine("q" + to_string(id_mapping[id]) + " = " + to_string(currentModel[id]));
}
#endif
modelSet.insert(currentModel);
WriteEmptyLine;
}
static unsigned bvToInt(z3::expr e) {
return (unsigned)e.get_numeral_int();
}
void fixed(unsigned id, z3::expr const &e) override {
fixedValues.push_back(id);
unsigned value = bvToInt(e);
currentModel[id_mapping[id]] = value;
}
user_propagator(z3::solver *s, std::unordered_map<unsigned, unsigned>& idMapping, unsigned board)
: user_propagator_base(s), board(board), id_mapping(idMapping), currentModel(board, (unsigned)-1) {
this->register_fixed();
this->register_final();
}
virtual ~user_propagator() = default;
void push() override {
fixedCnt.push((unsigned) fixedValues.size());
}
void pop(unsigned num_scopes) override {
for (unsigned i = 0; i < num_scopes; i++) {
unsigned lastCnt = fixedCnt.top();
fixedCnt.pop();
for (auto j = fixedValues.size(); j > lastCnt; j--) {
currentModel[fixedValues[j - 1]] = (unsigned)-1;
}
fixedValues.resize(lastCnt);
}
}
user_propagator_base *fresh(Z3_context) override { return this; }
};
class user_propagator_with_theory : public user_propagator {
public:
void fixed(unsigned id, z3::expr const &e) override {
unsigned queenId = id_mapping[id];
unsigned queenPos = bvToInt(e);
if (queenPos >= board) {
this->conflict(1, &id);
return;
}
for (unsigned fixed : fixedValues) {
unsigned otherId = id_mapping[fixed];
unsigned otherPos = currentModel[fixed];
if (queenPos == otherPos) {
const unsigned conflicting[] = {id, fixed};
this->conflict(2, conflicting);
continue;
}
#ifdef QUEEN
int diffY = abs((int)queenId - (int)otherId);
int diffX = abs((int)queenPos - (int)otherPos);
if (diffX == diffY) {
const unsigned conflicting[] = {id, fixed};
this->conflict(2, conflicting);
}
#endif
}
fixedValues.push_back(id);
currentModel[id_mapping[id]] = queenPos;
}
user_propagator_with_theory(z3::solver *s, std::unordered_map<unsigned, unsigned>& idMapping, unsigned board)
: user_propagator(s, idMapping, board) {}
};
int log2i(unsigned n) {
if (n <= 0) {
return 0;
}
if (n <= 2) {
return 1;
}
unsigned l = 1;
int i = 0;
while (l < n) {
l <<= 1;
i++;
}
return i;
}
std::vector<z3::expr> createQueens(z3::context &context, unsigned num) {
std::vector<z3::expr> queens;
int bits = log2i(num) + 1 /*to detect potential overflow in the diagonal*/;
z3::expr_vector createQueens(z3::context &context, unsigned num, int bits, std::string prefix) {
z3::expr_vector queens(context);
for (unsigned i = 0; i < num; i++) {
queens.push_back(context.bv_const((std::string("q") + to_string(i)).c_str(), bits));
queens.push_back(context.bv_const((prefix + "q" + to_string(i)).c_str(), bits));
}
return queens;
}
void createConstraints(z3::context &context, z3::solver &solver, const std::vector<z3::expr> &queens) {
z3::expr_vector createQueens(z3::context &context, unsigned num) {
return createQueens(context, num, log2i(num) + 1, "");
}
z3::expr createConstraints(z3::context &context, const z3::expr_vector &queens) {
z3::expr_vector assertions(context);
for (unsigned i = 0; i < queens.size(); i++) {
// assert column range
solver.add(z3::uge(queens[i], 0));
solver.add(z3::ule(queens[i], (int) (queens.size() - 1)));
assertions.push_back(z3::uge(queens[i], 0));
assertions.push_back(z3::ule(queens[i], (int) (queens.size() - 1)));
}
z3::expr_vector distinct(context);
for (const z3::expr &queen : queens) {
for (const z3::expr &queen: queens) {
distinct.push_back(queen);
}
solver.add(z3::distinct(distinct));
assertions.push_back(z3::distinct(distinct));
#ifdef QUEEN
for (unsigned i = 0; i < queens.size(); i++) {
for (unsigned j = i + 1; j < queens.size(); j++) {
solver.add((int)(j - i) != (queens[j] - queens[i]));
solver.add((int)(j - i) != (queens[i] - queens[j]));
assertions.push_back((int) (j - i) != (queens[j] - queens[i]));
assertions.push_back((int) (j - i) != (queens[i] - queens[j]));
}
}
#endif
return z3::mk_and(assertions);
}
int test01(unsigned num, bool simple) {
z3::context context;
z3::solver solver(context, !simple ? Z3_mk_solver(context) : Z3_mk_simple_solver(context));
std::vector<z3::expr> queens = createQueens(context, num);
z3::expr_vector queens = createQueens(context, num);
createConstraints(context, solver, queens);
solver.add(createConstraints(context, queens));
int solutionId = 1;
@ -260,8 +106,8 @@ inline int test1(unsigned num) {
int test23(unsigned num, bool withTheory) {
z3::context context;
z3::solver solver(context, Z3_mk_simple_solver(context));
std::unordered_map<unsigned, unsigned> idMapping;
z3::solver solver(context, z3::solver::simple());
std::unordered_map<z3::expr, unsigned> idMapping;
user_propagator *propagator;
if (!withTheory) {
@ -271,15 +117,15 @@ int test23(unsigned num, bool withTheory) {
propagator = new user_propagator_with_theory(&solver, idMapping, num);
}
std::vector<z3::expr> queens = createQueens(context, num);
z3::expr_vector queens = createQueens(context, num);
for (unsigned i = 0; i < queens.size(); i++) {
unsigned id = propagator->add(queens[i]);
idMapping[id] = i;
propagator->add(queens[i]);
idMapping[queens[i]] = i;
}
if (!withTheory) {
createConstraints(context, solver, queens);
solver.add(createConstraints(context, queens));
}
solver.check();
@ -296,50 +142,246 @@ inline int test3(unsigned num) {
return test23(num, true);
}
int test4(unsigned num) {
z3::context context;
z3::solver solver(context, z3::solver::simple());
z3::expr_vector queens1 = createQueens(context, num, log2i(num * num), ""); // square to avoid overflow during summation
z3::expr valid1 = createConstraints(context, queens1);
z3::expr_vector queens2 = createQueens(context, num, log2i(num * num), "forall_");
z3::expr valid2 = createConstraints(context, queens2);
z3::expr manhattanSum1 = context.bv_val(0, queens1[0].get_sort().bv_size());
z3::expr manhattanSum2 = context.bv_val(0, queens2[0].get_sort().bv_size());
for (int i = 1; i < queens1.size(); i++) {
manhattanSum1 = manhattanSum1 + z3::ite(z3::uge(queens1[i], queens1[i - 1]), queens1[i] - queens1[i - 1], queens1[i - 1] - queens1[i]);
manhattanSum2 = manhattanSum2 + z3::ite(z3::uge(queens2[i], queens2[i - 1]), queens2[i] - queens2[i - 1], queens2[i - 1] - queens2[i]);
}
solver.add(valid1 && z3::forall(queens2, z3::implies(valid2, manhattanSum1 >= manhattanSum2)));
solver.check();
z3::model model = solver.get_model();
int max = 0;
int prev, curr;
curr = model.eval(queens1[0]).get_numeral_int();
for (unsigned i = 1; i < num; i++) {
prev = curr;
curr = model.eval(queens1[i]).get_numeral_int();
max += abs(curr - prev);
}
return max;
}
int test5(unsigned num) {
z3::context context;
z3::solver solver(context, z3::solver::simple());
std::unordered_map<z3::expr, unsigned> idMapping;
z3::expr_vector queens = createQueens(context, num, log2i(num * num), "");
solver.add(createConstraints(context, queens));
user_propagator_subquery_maximisation propagator(&solver, idMapping, num, queens);
for (unsigned i = 0; i < queens.size(); i++) {
propagator.add(queens[i]);
idMapping[queens[i]] = i;
}
solver.check();
z3::model model = solver.get_model();
int max = 0;
int prev, curr;
curr = model.eval(queens[0]).get_numeral_int();
for (unsigned i = 1; i < num; i++) {
prev = curr;
curr = model.eval(queens[i]).get_numeral_int();
max += abs(curr - prev);
}
return max;
}
int test6(unsigned num) {
z3::context context;
z3::solver solver(context, z3::solver::simple());
std::unordered_map<z3::expr, unsigned> idMapping;
z3::expr_vector queens = createQueens(context, num, log2i(num * num), "");
solver.add(createConstraints(context, queens));
user_propagator_internal_maximisation propagator(&solver, idMapping, num, queens);
for (unsigned i = 0; i < queens.size(); i++) {
propagator.add(queens[i]);
idMapping[queens[i]] = i;
}
solver.check();
return propagator.best;
}
int test7(unsigned num) {
z3::context context;
z3::solver solver(context, z3::solver::simple());
z3::expr_vector queens1 = createQueens(context, num, log2i(num * num), "");
z3::expr_vector queens2 = createQueens(context, num, log2i(num * num), "forall_");
z3::expr manhattanSum1 = context.bv_val(0, queens1[0].get_sort().bv_size());
z3::expr manhattanSum2 = context.bv_val(0, queens2[0].get_sort().bv_size());
for (int i = 1; i < queens1.size(); i++) {
manhattanSum1 = manhattanSum1 + z3::ite(z3::uge(queens1[i], queens1[i - 1]), queens1[i] - queens1[i - 1], queens1[i - 1] - queens1[i]);
manhattanSum2 = manhattanSum2 + z3::ite(z3::uge(queens2[i], queens2[i - 1]), queens2[i] - queens2[i - 1], queens2[i - 1] - queens2[i]);
}
z3::sort_vector domain(context);
for (int i = 0; i < queens1.size(); i++) {
domain.push_back(queens1[i].get_sort());
}
z3::func_decl validFunc = context.user_propagate_function(context.str_symbol("valid"), domain, context.bool_sort());
solver.add(validFunc(queens1) && z3::forall(queens2, z3::implies(validFunc(queens2), manhattanSum1 >= manhattanSum2)));
user_propagator_created_maximisation propagator(&solver, num);
solver.check();
z3::model model = solver.get_model();
int max = 0;
int prev, curr;
curr = model.eval(queens1[0]).get_numeral_int();
for (unsigned i = 1; i < num; i++) {
prev = curr;
curr = model.eval(queens1[i]).get_numeral_int();
max += abs(curr - prev);
}
return max;
}
int main() {
for (int num = 4; num <= 11; num++) {
for (int num = MIN_BOARD; num <= MAX_BOARD1; num++) {
std::cout << "num = " << num << ":\n" << std::endl;
unsigned seed = (unsigned) high_resolution_clock::now().time_since_epoch().count();
const char *testName[] =
{
"BV + Blocking clauses (Default solver)",
"BV + Blocking clauses (Simple solver)",
"BV + Adding conflicts",
"Custom theory + conflicts",
};
int permutation[4] = {0, 1, 2, 3,};
double timeResults[REPETITIONS * SIZE(permutation)];
for (int rep = 0; rep < REPETITIONS; rep++) {
// Execute strategies in a randomised order
std::shuffle(&permutation[0], &permutation[SIZE(permutation) - 1], std::default_random_engine(seed));
for (int i : permutation) {
int modelCount = -1;
auto now1 = high_resolution_clock::now();
switch (i) {
case 0:
modelCount = test0(num);
break;
case 1:
modelCount = test1(num);
break;
case 2:
modelCount = test2(num);
break;
case 3:
modelCount = test3(num);
break;
default:
WriteLine("Unknown case");
break;
}
auto now2 = high_resolution_clock::now();
duration<double, std::milli> ms = now2 - now1;
std::cout << testName[i] << " took " << ms.count() << "ms (" << modelCount << " models)" << std::endl;
timeResults[rep * SIZE(permutation) + i] = ms.count();
WriteLine("-------------");
}
}
std::cout << "\n" << std::endl;
for (unsigned i = 0; i < SIZE(permutation); i++) {
std::cout << testName[i];
double sum = 0;
for (int j = 0; j < REPETITIONS; j++) {
std::cout << " " << timeResults[j * SIZE(permutation) + i] << "ms";
sum += timeResults[j * SIZE(permutation) + i];
}
std::cout << " | avg: " << sum / REPETITIONS << "ms" << std::endl;
}
std::cout << std::endl;
}
z3::set_param("smt.ematching", "false");
z3::set_param("smt.mbqi", "true");
std::cout << "\nMaximal distance:" << std::endl;
for (int num = MIN_BOARD; num <= MAX_BOARD2; num++) {
std::cout << "num = " << num << ":\n" << std::endl;
unsigned seed = (unsigned) high_resolution_clock::now().time_since_epoch().count();
const char *testName[] =
{
"BV + Blocking clauses (Default solver)",
"BV + Blocking clauses (Simple solver)",
"BV + Adding conflicts",
"Custom theory + conflicts",
};
int permutation[4] =
{
0,
1,
2,
3,
"Ordinary/Direct Encoding",
"SubQuery in final",
"Assert Smaller in final",
"created",
};
int permutation[4] = {0, 1, 2, 3,};
double timeResults[REPETITIONS * SIZE(permutation)];
for (int rep = 0; rep < REPETITIONS; rep++) {
// Execute strategies in a randomised order
std::shuffle(&permutation[0], &permutation[SIZE(permutation) - 1], std::default_random_engine(seed));
for (int i : permutation) {
int modelCount = -1;
for (int i: permutation) {
int max = -1;
auto now1 = high_resolution_clock::now();
switch (i) {
case 0:
modelCount = test0(num);
switch (i + 4) {
case 4:
max = test4(num);
break;
case 1:
modelCount = test1(num);
case 5:
max = test5(num);
break;
case 2:
modelCount = test2(num);
case 6:
max = test6(num);
break;
case 3:
modelCount = test3(num);
case 7:
max = test7(num);
break;
default:
WriteLine("Unknown case");
@ -347,7 +389,7 @@ int main() {
}
auto now2 = high_resolution_clock::now();
duration<double, std::milli> ms = now2 - now1;
std::cout << testName[i] << " took " << ms.count() << "ms (" << modelCount << " models)" << std::endl;
std::cout << testName[i] << " took " << ms.count() << "ms. Max: " << max << std::endl;
timeResults[rep * SIZE(permutation) + i] = ms.count();
WriteLine("-------------");
}
@ -367,4 +409,4 @@ int main() {
std::cout << std::endl;
}
}
}

Binary file not shown.

View file

@ -0,0 +1,87 @@
#pragma once
#include "common.h"
class user_propagator : public z3::user_propagator_base {
protected:
unsigned board;
std::unordered_map<z3::expr, unsigned> &queenToY;
simple_model currentModel;
std::unordered_set<simple_model> modelSet;
z3::expr_vector fixedValues;
std::stack<unsigned> fixedCnt;
int solutionNr = 1;
public:
int getModelCount() const {
return solutionNr - 1;
}
void final() override {
this->conflict(fixedValues);
if (modelSet.find(currentModel) != modelSet.end()) {
WriteLine("Got already computed model");
return;
}
Write("Model #" << solutionNr << ":\n");
solutionNr++;
#ifdef VERBOSE
for (unsigned i = 0; i < fixedValues.size(); i++) {
z3::expr fixed = fixedValues[i];
WriteLine("q" + to_string(queenToY[fixed]) + " = " + to_string(currentModel[queenToY[fixed]]));
}
#endif
modelSet.insert(currentModel);
WriteEmptyLine;
}
static unsigned bvToInt(z3::expr const &e) {
return (unsigned) e.get_numeral_int();
}
void fixed(z3::expr const &ast, z3::expr const &value) override {
fixedValues.push_back(ast);
unsigned valueBv = bvToInt(value);
currentModel[queenToY[ast]] = valueBv;
}
user_propagator(z3::context &c, std::unordered_map<z3::expr, unsigned> &queenToY, unsigned board)
: user_propagator_base(c), board(board), queenToY(queenToY), fixedValues(c), currentModel(board, (unsigned) -1) {
this->register_fixed();
this->register_final();
}
user_propagator(z3::solver *s, std::unordered_map<z3::expr, unsigned> &idMapping, unsigned board)
: user_propagator_base(s), board(board), queenToY(idMapping), fixedValues(s->ctx()), currentModel(board, (unsigned) -1) {
this->register_fixed();
this->register_final();
}
~user_propagator() = default;
void push() override {
fixedCnt.push((unsigned) fixedValues.size());
}
void pop(unsigned num_scopes) override {
for (unsigned i = 0; i < num_scopes; i++) {
unsigned lastCnt = fixedCnt.top();
fixedCnt.pop();
// Remove fixed values from model
for (unsigned j = fixedValues.size(); j > lastCnt; j--) {
currentModel[queenToY[fixedValues[j - 1]]] = (unsigned) -1;
}
fixedValues.resize(lastCnt);
}
}
user_propagator_base *fresh(z3::context &) override {
return this;
}
};

View file

@ -0,0 +1,338 @@
#pragma once
#include "common.h"
class user_propagator_created_maximisation : public z3::user_propagator_base {
std::unordered_map<z3::expr, z3::expr_vector> argToFcts;
std::unordered_map<z3::expr, z3::expr_vector> fctToArgs;
std::unordered_map<z3::expr, unsigned> currentModel;
z3::expr_vector fixedValues;
std::vector<unsigned> fixedCnt;
user_propagator_created_maximisation* childPropagator = nullptr;
user_propagator_created_maximisation* parentPropagator = nullptr;
int board;
int nesting; // Just for logging (0 ... main solver; 1 ... sub-solver)
public:
user_propagator_created_maximisation(z3::context &c, user_propagator_created_maximisation* parentPropagator, unsigned board, int nesting) :
z3::user_propagator_base(c), fixedValues(c), parentPropagator(parentPropagator), board(board), nesting(nesting) {
this->register_fixed();
this->register_final();
this->register_created();
}
user_propagator_created_maximisation(z3::solver *s, unsigned board) :
z3::user_propagator_base(s), fixedValues(s->ctx()), board(board), nesting(0) {
this->register_fixed();
this->register_final();
this->register_created();
}
~user_propagator_created_maximisation() {
delete childPropagator;
}
void final() override {
WriteLine("Final (" + to_string(nesting) + ")");
}
void push() override {
WriteLine("Push (" + to_string(nesting) + ")");
fixedCnt.push_back((unsigned) fixedValues.size());
}
void pop(unsigned num_scopes) override {
WriteLine("Pop (" + to_string(nesting) + ")");
for (unsigned i = 0; i < num_scopes; i++) {
unsigned lastCnt = fixedCnt.back();
fixedCnt.pop_back();
for (auto j = fixedValues.size(); j > lastCnt; j--) {
currentModel.erase(fixedValues[j - 1]);
}
fixedValues.resize(lastCnt);
}
}
void checkValidPlacement(std::vector<z3::expr_vector> &conflicts, const z3::expr &fct, const z3::expr_vector &args, const std::vector<unsigned> &argValues, int pos) {
unsigned queenId = pos;
unsigned queenPos = argValues[pos];
z3::expr queenPosExpr = args[pos];
if (queenPos >= board) {
z3::expr_vector conflicting(ctx());
conflicting.push_back(fct);
conflicting.push_back(queenPosExpr);
conflicts.push_back(conflicting);
return;
}
for (unsigned otherId = 0; otherId < argValues.size(); otherId++) {
if (otherId == pos)
continue;
unsigned otherPos = argValues[otherId];
z3::expr otherPosExpr = args[otherId];
if (otherPos == (unsigned)-1)
continue; // We apparently do not have this value
if (queenPos == otherPos) {
z3::expr_vector conflicting(ctx());
conflicting.push_back(fct);
conflicting.push_back(queenPosExpr);
conflicting.push_back(otherPosExpr);
conflicts.push_back(conflicting);
}
int diffY = abs((int) queenId - (int) otherId);
int diffX = abs((int) queenPos - (int) otherPos);
if (diffX == diffY) {
z3::expr_vector conflicting(ctx());
conflicting.push_back(fct);
conflicting.push_back(queenPosExpr);
conflicting.push_back(otherPosExpr);
conflicts.push_back(conflicting);
}
}
}
unsigned getValues(const z3::expr &fct, std::vector<unsigned> &argValues) const {
z3::expr_vector args = fctToArgs.at(fct);
unsigned fixed = 0;
for (const z3::expr &arg: args) {
if (currentModel.contains(arg)) {
argValues.push_back(currentModel.at(arg));
fixed++;
}
else
argValues.push_back((unsigned) -1); // no value so far
}
return fixed;
}
user_propagator_base *fresh(z3::context &ctx) override {
WriteLine("Fresh context");
childPropagator = new user_propagator_created_maximisation(ctx, this, board, nesting + 1);
return childPropagator;
}
void fixed(const z3::expr &expr, const z3::expr &value) override {
// Could be optimized!
WriteLine("Fixed (" + to_string(nesting) + ") " + expr.to_string() + " to " + value.to_string());
unsigned v = value.is_true() ? 1 : (value.is_false() ? 0 : value.get_numeral_uint());
currentModel[expr] = v;
fixedValues.push_back(expr);
z3::expr_vector effectedFcts(ctx());
bool fixedFct = fctToArgs.contains(expr);
if (fixedFct) {
// fixed the value of a function
effectedFcts.push_back(expr);
}
else {
// fixed the value of a function's argument
effectedFcts = argToFcts.at(expr);
}
for (const z3::expr& fct : effectedFcts) {
if (!currentModel.contains(fct))
// we do not know yet whether to expect a valid or invalid placement
continue;
std::vector<unsigned> values;
unsigned fixedArgsCnt = getValues(fct, values);
bool fctValue = currentModel[fct];
z3::expr_vector args = fctToArgs.at(fct);
if (!fctValue) {
// expect invalid placement ...
if (fixedArgsCnt != board)
// we expect an invalid placement, but not all queen positions have been placed yet
return;
std::vector<z3::expr_vector> conflicts;
for (unsigned i = 0; i < args.size(); i++) {
if (values[i] != (unsigned)-1)
checkValidPlacement(conflicts, expr, args, values, i);
}
if (conflicts.empty()) {
// ... but we got a valid one
z3::expr_vector conflicting(ctx());
conflicting.push_back(fct);
for (const z3::expr &arg: args) {
if (!arg.is_numeral())
conflicting.push_back(arg);
}
this->conflict(conflicting);
}
else {
// ... and everything is fine; we have at least one conflict
}
}
else {
// expect valid placement ...
std::vector<z3::expr_vector> conflicts;
if (fixedFct){
for (unsigned i = 0; i < args.size(); i++) {
if (values[i] != (unsigned)-1) // check all set queens
checkValidPlacement(conflicts, expr, args, values, i);
}
}
else {
for (unsigned i = 0; i < args.size(); i++) {
if (z3::eq(args[i], expr)) // only check newly fixed values
checkValidPlacement(conflicts, fct, args, values, i);
}
}
if (conflicts.size() > 0) {
// ... but we got an invalid one
for (const z3::expr_vector &conflicting: conflicts)
this->conflict(conflicting);
}
else {
// ... and everything is fine; no conflict
}
}
}
}
// void fixed(const z3::expr &expr, const z3::expr &value) override {
// WriteLine("Fixed (" + to_string(nesting) + ") " + expr.to_string() + " to " + value.to_string());
// unsigned v = value.is_true() ? 1 : (value.is_false() ? 0 : value.get_numeral_uint());
// currentModel[expr] = v;
// fixedValues.push_back(expr);
//
// if (fctToArgs.contains(expr)) {
// // fixed the value of a function
//
// std::vector<unsigned> values;
// unsigned fixedArgsCnt = getValues(expr, values);
//
// if (!v && fixedArgsCnt != board)
// // we expect an invalid placement, but not all queen positions have been placed yet
// return;
//
// z3::expr_vector args = fctToArgs.at(expr);
//
// std::vector<z3::expr_vector> conflicts;
// for (unsigned i = 0; i < args.size(); i++) {
// if (values[i] != (unsigned)-1)
// checkValidPlacement(conflicts, expr, args, values, i);
// }
// if (v) {
// //we expected a valid queen placement
// if (conflicts.size() > 0) {
// // ... but we got an invalid one
// for (const z3::expr_vector &conflicting: conflicts)
// this->conflict(conflicting);
// }
// else {
// // everything fine; no conflict
// }
// }
// else {
// // we expect an invalid queen placement
// if (conflicts.empty()) {
// // ... but we got a valid one
// z3::expr_vector conflicting(ctx());
// conflicting.push_back(expr);
// for (const z3::expr &arg: args) {
// if (!arg.is_numeral())
// conflicting.push_back(arg);
// }
// this->conflict(conflicting);
// }
// else {
// // everything fine; we have at least one conflict
// }
// }
// }
// else {
// // fixed the value of a function argument
//
// z3::expr_vector effectedFcts = argToFcts.at(expr);
//
// for (const z3::expr& fct : effectedFcts) {
// if (!currentModel.contains(fct))
// // we do not know yet whether to expect a valid or invalid placement
// continue;
//
// std::vector<unsigned> values;
// unsigned fixedArgsCnt = getValues(fct, values);
// bool fctValue = currentModel[fct];
// z3::expr_vector args = fctToArgs.at(fct);
//
// if (!fctValue) {
// // expect invalid placement
// if (fixedArgsCnt != board)
// // we expect an invalid placement, but not all queen positions have been placed yet
// return;
// std::vector<z3::expr_vector> conflicts;
// for (unsigned i = 0; i < args.size(); i++) {
// if (values[i] != (unsigned)-1)
// checkValidPlacement(conflicts, expr, args, values, i);
// }
//
// if (conflicts.empty()) {
// // ... but we got a valid one
// z3::expr_vector conflicting(ctx());
// conflicting.push_back(fct);
// for (const z3::expr &arg: args) {
// if (!arg.is_numeral())
// conflicting.push_back(arg);
// }
// this->conflict(conflicting);
// }
// else {
// // everything fine; we have at least one conflict
// }
// }
// else {
// // expect valid placement
// std::vector<z3::expr_vector> conflicts;
// for (unsigned i = 0; i < args.size(); i++) {
// if (z3::eq(args[i], expr)) // only check newly fixed values
// checkValidPlacement(conflicts, fct, args, values, i);
// }
// if (conflicts.size() > 0) {
// // ... but we got an invalid one
// for (const z3::expr_vector &conflicting: conflicts)
// this->conflict(conflicting);
// }
// else {
// // everything fine; no conflict
// }
// }
// }
// }
// }
void created(const z3::expr &func) override {
WriteLine("Created (" + to_string(nesting) + "): " + func.to_string());
z3::expr_vector args = func.args();
for (unsigned i = 0; i < args.size(); i++) {
z3::expr arg = args[i];
if (!arg.is_numeral()) {
WriteLine("Registered " + arg.to_string());
this->add(arg);
}
else {
currentModel[arg] = arg.get_numeral_uint();
// Skip registering as argument is a fixed BV;
}
argToFcts.try_emplace(arg, ctx()).first->second.push_back(func);
}
fctToArgs.emplace(std::make_pair(func, args));
}
};

View file

@ -0,0 +1,30 @@
#pragma once
#include "user_propagator_with_theory.h"
class user_propagator_internal_maximisation : public user_propagator_with_theory {
z3::expr manhattanSum;
public:
int best = -1;
user_propagator_internal_maximisation(z3::solver *s, std::unordered_map<z3::expr, unsigned> &idMapping, unsigned board, z3::expr_vector queens)
: user_propagator_with_theory(s, idMapping, board),
manhattanSum(s->ctx().bv_val(0, queens[0].get_sort().bv_size())) {
for (int i = 1; i < queens.size(); i++) {
manhattanSum = manhattanSum + z3::ite(z3::uge(queens[i], queens[i - 1]), queens[i] - queens[i - 1], queens[i - 1] - queens[i]);
}
}
void final() override {
int current = 0;
for (unsigned i = 1; i < board; i++) {
current += abs((signed) currentModel[i] - (signed) currentModel[i - 1]);
}
best = std::max(current, best);
this->propagate(z3::expr_vector(ctx()), z3::ugt(manhattanSum, best));
}
};

View file

@ -0,0 +1,51 @@
#pragma once
#include "user_propagator.h"
class user_propagator_subquery_maximisation : public user_propagator {
z3::expr assertion;
z3::expr_vector queens;
z3::expr manhattanSum;
public:
user_propagator_subquery_maximisation(z3::solver *s, std::unordered_map<z3::expr, unsigned> &idMapping, unsigned board, z3::expr_vector queens)
: user_propagator(s, idMapping, board),
assertion(mk_and(s->assertions())),
queens(queens), manhattanSum(s->ctx().bv_val(0, queens[0].get_sort().bv_size())) {
for (int i = 1; i < queens.size(); i++) {
manhattanSum = manhattanSum + z3::ite(z3::uge(queens[i], queens[i - 1]), queens[i] - queens[i - 1], queens[i - 1] - queens[i]);
}
}
void final() override {
int max1 = 0;
for (unsigned i = 1; i < board; i++) {
max1 += abs((signed) currentModel[i] - (signed) currentModel[i - 1]);
}
z3::expr_vector vec(ctx());
int max2 = 0;
z3::solver subquery(ctx(), z3::solver::simple());
subquery.add(assertion);
subquery.add(z3::ugt(manhattanSum, max1));
if (subquery.check() == z3::unsat)
return; // model is already maximal
z3::model counterExample = subquery.get_model();
int prev, curr = -1;
for (int i = 0; i < queens.size(); i++) {
prev = curr;
curr = counterExample.eval(queens[i]).get_numeral_int();
if (i == 0) continue;
max2 += abs(curr - prev);
}
this->propagate(vec, z3::uge(manhattanSum, max2));
}
};

View file

@ -0,0 +1,50 @@
#pragma once
#include "user_propagator.h"
class user_propagator_with_theory : public user_propagator {
public:
user_propagator_with_theory(z3::context &c, std::unordered_map<z3::expr, unsigned> &idMapping, unsigned board)
: user_propagator(c, idMapping, board) {}
user_propagator_with_theory(z3::solver *s, std::unordered_map<z3::expr, unsigned> &idMapping, unsigned board)
: user_propagator(s, idMapping, board) {}
void fixed(z3::expr const &ast, z3::expr const &value) override {
unsigned queenId = queenToY[ast];
unsigned queenPos = bvToInt(value);
if (queenPos >= board) {
z3::expr_vector conflicting(ast.ctx());
conflicting.push_back(ast);
this->conflict(conflicting);
return;
}
for (const z3::expr &fixed: fixedValues) {
unsigned otherId = queenToY[fixed];
unsigned otherPos = currentModel[queenToY[fixed]];
if (queenPos == otherPos) {
z3::expr_vector conflicting(ast.ctx());
conflicting.push_back(ast);
conflicting.push_back(fixed);
this->conflict(conflicting);
continue;
}
int diffY = abs((int) queenId - (int) otherId);
int diffX = abs((int) queenPos - (int) otherPos);
if (diffX == diffY) {
z3::expr_vector conflicting(ast.ctx());
conflicting.push_back(ast);
conflicting.push_back(fixed);
this->conflict(conflicting);
}
}
fixedValues.push_back(ast);
currentModel[queenToY[ast]] = queenPos;
}
};

View file

@ -18,7 +18,7 @@ jobs:
displayName: Build
inputs:
script:
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{parameters.BuildArchitecture}} &&
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{parameters.BuildArchitecture}} &&
python scripts\mk_win_dist.py
--${{parameters.BuildArchitecture}}-only
--dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk

View file

@ -644,7 +644,7 @@ def mk_gparams_register_modules_internal(h_files_full_path, path):
for code in cmds:
fout.write('{ param_descrs d; %s(d); gparams::register_global(d); }\n' % code)
for (mod, code) in mod_cmds:
fout.write('{ std::function<param_descrs *(void)> f = []() { auto* d = alloc(param_descrs); %s(*d); return d; }; gparams::register_module("%s", f); }\n' % (code, mod))
fout.write('{ auto f = []() { auto* d = alloc(param_descrs); %s(*d); return d; }; gparams::register_module("%s", f); }\n' % (code, mod))
for (mod, descr) in mod_descrs:
fout.write('gparams::register_module_descr("%s", "%s");\n' % (mod, descr))
fout.write('}\n')

View file

@ -8,7 +8,7 @@
from mk_util import *
def init_version():
set_version(4, 8, 15, 0)
set_version(4, 8, 16, 0)
# Z3 Project definition
def init_project_def():

View file

@ -56,6 +56,7 @@ def display_help():
print(" -f, --force force script to regenerate Makefiles.")
print(" --nodotnet do not include .NET bindings in the binary distribution files.")
print(" --dotnet-key=<file> sign the .NET assembly with the private key in <file>.")
print(" --arch=<arch> set architecture (to arm64) to force arm64 build")
print(" --nojava do not include Java bindings in the binary distribution files.")
print(" --nopython do not include Python bindings in the binary distribution files.")
print(" --githash include git hash in the Zip file.")
@ -72,6 +73,7 @@ def parse_options():
'nojava',
'nodotnet',
'dotnet-key=',
'arch=',
'githash',
'nopython'
])
@ -96,6 +98,11 @@ def parse_options():
JAVA_ENABLED = False
elif opt == '--githash':
GIT_HASH = True
elif opt == '--arch':
if arg == "arm64":
mk_util.IS_ARCH_ARM64 = True
else:
raise MKException("Invalid architecture directive '%s'. Legal directives: arm64" % arg)
else:
raise MKException("Invalid command line option '%s'" % opt)
set_build_dir(path)
@ -119,6 +126,8 @@ def mk_build_dir(path):
opts.append('--git-describe')
if PYTHON_ENABLED:
opts.append('--python')
if mk_util.IS_ARCH_ARM64:
opts.append('--arm64=true')
if subprocess.call(opts) != 0:
raise MKException("Failed to generate build directory at '%s'" % path)
@ -172,7 +181,9 @@ def get_os_name():
def get_z3_name():
major, minor, build, revision = get_version()
if sys.maxsize >= 2**32:
if mk_util.IS_ARCH_ARM64:
platform = "arm64"
elif sys.maxsize >= 2**32:
platform = "x64"
else:
platform = "x86"

View file

@ -69,6 +69,7 @@ IS_WINDOWS=False
IS_LINUX=False
IS_HURD=False
IS_OSX=False
IS_ARCH_ARM64=False
IS_FREEBSD=False
IS_NETBSD=False
IS_OPENBSD=False
@ -114,6 +115,7 @@ ALWAYS_DYNAMIC_BASE=False
FPMATH="Default"
FPMATH_FLAGS="-mfpmath=sse -msse -msse2"
FPMATH_ENABLED=getenv("FPMATH_ENABLED", "True")
def check_output(cmd):
@ -277,7 +279,13 @@ def test_gmp(cc):
def test_fpmath(cc):
global FPMATH_FLAGS
global FPMATH_FLAGS, IS_ARCH_ARM64, IS_OSX
if FPMATH_ENABLED == "False":
FPMATH_FLAGS=""
return "Disabled"
if IS_ARCH_ARM64 and IS_OSX:
FPMATH_FLAGS = ""
return "Disabled-ARM64"
if is_verbose():
print("Testing floating point support...")
t = TempFile('tstsse.cpp')
@ -616,8 +624,12 @@ elif os.name == 'posix':
LINUX_X64=True
else:
LINUX_X64=False
if os.name == 'posix' and os.uname()[4] == 'arm64':
IS_ARCH_ARM64 = True
def display_help(exit_code):
print("mk_make.py: Z3 Makefile generator\n")
print("This script generates the Makefile for the Z3 theorem prover.")
@ -640,6 +652,7 @@ def display_help(exit_code):
print(" -x, --x64 create 64 binary when using Visual Studio.")
else:
print(" --x86 force 32-bit x86 build on x64 systems.")
print(" --arm64=<bool> forcearm64 bit build on/off (supported for Darwin).")
print(" -m, --makefiles generate only makefiles.")
if IS_WINDOWS:
print(" -v, --vsproj generate Visual Studio Project Files.")
@ -682,11 +695,11 @@ def parse_options():
global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM
global DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED
global LINUX_X64, SLOW_OPTIMIZE, LOG_SYNC, SINGLE_THREADED
global GUARD_CF, ALWAYS_DYNAMIC_BASE
global GUARD_CF, ALWAYS_DYNAMIC_BASE, IS_ARCH_ARM64
try:
options, remainder = getopt.gnu_getopt(sys.argv[1:],
'b:df:sxhmcvtnp:gj',
['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf',
'b:df:sxa:hmcvtnp:gj',
['build=', 'debug', 'silent', 'x64', 'arm64=', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf',
'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js',
'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'pypkgdir=', 'python', 'staticbin', 'log-sync', 'single-threaded'])
except:
@ -709,6 +722,8 @@ def parse_options():
VS_X64 = True
elif opt in ('--x86'):
LINUX_X64=False
elif opt in ('--arm64'):
IS_ARCH_ARM64 = arg in ('true','on','True','TRUE')
elif opt in ('-h', '--help'):
display_help(0)
elif opt in ('-m', '--makefiles'):
@ -1678,6 +1693,7 @@ class DotNetDLLComponent(Component):
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<LangVersion>8.0</LangVersion>
<DefineConstants>$(DefineConstants);DOTNET_CORE</DefineConstants>
<DebugType>portable</DebugType>
<AssemblyName>Microsoft.Z3</AssemblyName>
@ -1995,7 +2011,7 @@ class MLComponent(Component):
LIBZ3 = LIBZ3 + ' ' + ' '.join(map(lambda x: '-cclib ' + x, LDFLAGS.split()))
stubs_install_path = '$$(%s printconf path)/stublibs' % OCAMLFIND
stubs_install_path = '$$(%s printconf destdir)/stublibs' % OCAMLFIND
if not STATIC_LIB:
loadpath = '-ccopt -L' + stubs_install_path
dllpath = '-dllpath ' + stubs_install_path
@ -2076,7 +2092,7 @@ class MLComponent(Component):
out.write(' %s' % ((os.path.join(self.sub_dir, 'z3ml.cmxa'))))
out.write(' %s' % ((os.path.join(self.sub_dir, 'z3ml.cmxs'))))
out.write(' %s' % ((os.path.join(self.sub_dir, 'dllz3ml'))))
if is_windows() or is_cygwin_mingw():
if is_windows() or is_cygwin_mingw() or is_msys2():
out.write('.dll')
else:
out.write('.so') # .so also on OSX!
@ -2426,7 +2442,7 @@ def mk_config():
if ONLY_MAKEFILES:
return
config = open(os.path.join(BUILD_DIR, 'config.mk'), 'w')
global CXX, CC, GMP, GUARD_CF, STATIC_BIN, GIT_HASH, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS, LOG_SYNC, SINGLE_THREADED
global CXX, CC, GMP, GUARD_CF, STATIC_BIN, GIT_HASH, CPPFLAGS, CXXFLAGS, LDFLAGS, EXAMP_DEBUG_FLAG, FPMATH_FLAGS, LOG_SYNC, SINGLE_THREADED, IS_ARCH_ARM64
if IS_WINDOWS:
CXXFLAGS = '/nologo /Zi /D WIN32 /D _WINDOWS /EHsc /GS /Gd /std:c++17'
config.write(
@ -2624,13 +2640,18 @@ def mk_config():
SLIBFLAGS = '%s -m32' % SLIBFLAGS
if TRACE or DEBUG_MODE:
CPPFLAGS = '%s -D_TRACE' % CPPFLAGS
if is_cygwin_mingw():
if is_cygwin_mingw() or is_msys2():
# when cross-compiling with MinGW, we need to statically link its standard libraries
# and to make it create an import library.
SLIBEXTRAFLAGS = '%s -static-libgcc -static-libstdc++ -Wl,--out-implib,libz3.dll.a' % SLIBEXTRAFLAGS
LDFLAGS = '%s -static-libgcc -static-libstdc++' % LDFLAGS
if sysname == 'Linux' and machine.startswith('armv7') or machine.startswith('armv8'):
CXXFLAGS = '%s -fpic' % CXXFLAGS
if IS_OSX and IS_ARCH_ARM64:
print("Setting arm64")
CXXFLAGS = '%s -arch arm64' % CXXFLAGS
LDFLAGS = '%s -arch arm64' % LDFLAGS
SLIBEXTRAFLAGS = '%s -arch arm64' % SLIBEXTRAFLAGS
config.write('PREFIX=%s\n' % PREFIX)
config.write('CC=%s\n' % CC)

View file

@ -1,5 +1,9 @@
variables:
ReleaseVersion: '4.8.15'
Major: '4'
Minor: '8'
Patch: '16'
NightlyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId)-$(Build.DefinitionName)
stages:
- stage: Build
@ -19,6 +23,21 @@ stages:
artifactName: 'Mac'
targetPath: $(Build.ArtifactStagingDirectory)
- job: MacArm64
displayName: "Mac ARM64 Build"
pool:
vmImage: "macOS-latest"
steps:
- script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64
- script: git clone https://github.com/z3prover/z3test z3test
- script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/.
- task: PublishPipelineArtifact@1
inputs:
artifactName: 'MacArm64'
targetPath: $(Build.ArtifactStagingDirectory)
- job: Ubuntu
displayName: "Ubuntu build"
pool:
@ -92,7 +111,7 @@ stages:
- task: CmdLine@2
inputs:
script:
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86 &
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86 &
python scripts\mk_win_dist.py
--x86-only
--dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk
@ -115,7 +134,7 @@ stages:
- task: CmdLine@2
inputs:
script:
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 &
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 &
python scripts\mk_win_dist.py
--x64-only
--dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk
@ -130,6 +149,8 @@ stages:
targetPath: $(Build.ArtifactStagingDirectory)
artifactName: 'Windows64'
- stage: Package
jobs:
- job: NuGet64
@ -158,6 +179,11 @@ stages:
inputs:
artifact: 'Mac'
path: $(Agent.TempDirectory)\package
- task: DownloadPipelineArtifact@2
displayName: 'Download macOS Arm64 Build'
inputs:
artifact: 'MacArm64'
path: $(Agent.TempDirectory)\package
- task: NuGetToolInstaller@0
inputs:
versionSpec: 5.x
@ -170,7 +196,7 @@ stages:
workingDirectory: $(Agent.TempDirectory)\package
arguments:
$(Agent.TempDirectory)\package
$(ReleaseVersion)
$(NightlyVersion)
$(Build.Repository.Uri)
$(Build.SourceBranchName)
$(Build.SourceVersion)
@ -180,13 +206,18 @@ stages:
displayName: 'NuGet Pack Symbols'
inputs:
command: custom
arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.sym.nuspec -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out'
versioningScheme: byPrereleaseNumber
majorVersion: $(Major)
minorVersion: $(Minor)
patchVersion: $(Patch)
arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.sym.nuspec -Version $(NightlyVersion) -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out'
- task: EsrpCodeSigning@1
continueOnError: true
displayName: 'Sign Package'
inputs:
ConnectedServiceName: 'z3-esrp-signing-2'
FolderPath: $(Build.ArtifactStagingDirectory)
Pattern: Microsoft.Z3.$(ReleaseVersion).nupkg
Pattern: Microsoft.Z3.$(NightlyVersion).nupkg
signConfigType: 'inlineSignParams'
inlineOperation: |
[
@ -209,11 +240,12 @@ stages:
MaxConcurrency: '50'
MaxRetryAttempts: '5'
- task: EsrpCodeSigning@1
continueOnError: true
displayName: 'Sign Symbol Package'
inputs:
ConnectedServiceName: 'z3-esrp-signing-2'
FolderPath: $(Build.ArtifactStagingDirectory)
Pattern: Microsoft.Z3.$(ReleaseVersion).snupkg
Pattern: Microsoft.Z3.$(NightlyVersion).snupkg
signConfigType: 'inlineSignParams'
inlineOperation: |
[
@ -268,7 +300,7 @@ stages:
workingDirectory: $(Agent.TempDirectory)\package
arguments:
$(Agent.TempDirectory)\package
$(ReleaseVersion)
$(NightlyVersion)
$(Build.Repository.Uri)
$(Build.SourceBranchName)
$(Build.SourceVersion)
@ -279,13 +311,18 @@ stages:
displayName: 'NuGet Pack Symbols'
inputs:
command: custom
arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.x86.sym.nuspec -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out'
versioningScheme: byPrereleaseNumber
majorVersion: $(Major)
minorVersion: $(Minor)
patchVersion: $(Patch)
arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.x86.sym.nuspec -Version $(NightlyVersion) -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out'
- task: EsrpCodeSigning@1
continueOnError: true
displayName: 'Sign Package'
inputs:
ConnectedServiceName: 'z3-esrp-signing-2'
FolderPath: $(Build.ArtifactStagingDirectory)
Pattern: Microsoft.Z3.x86.$(ReleaseVersion).nupkg
Pattern: Microsoft.Z3.x86.$(NightlyVersion).nupkg
signConfigType: 'inlineSignParams'
inlineOperation: |
[
@ -308,11 +345,12 @@ stages:
MaxConcurrency: '50'
MaxRetryAttempts: '5'
- task: EsrpCodeSigning@1
continueOnError: true
displayName: 'Sign Symbol Package'
inputs:
ConnectedServiceName: 'z3-esrp-signing-2'
FolderPath: $(Build.ArtifactStagingDirectory)
Pattern: Microsoft.Z3.x86.$(ReleaseVersion).snupkg
Pattern: Microsoft.Z3.x86.$(NightlyVersion).snupkg
signConfigType: 'inlineSignParams'
inlineOperation: |
[
@ -361,7 +399,12 @@ stages:
inputs:
artifactName: 'Mac'
targetPath: $(Agent.TempDirectory)
- script: cd $(Agent.TempDirectory); mkdir osx-bin; cd osx-bin; unzip ../*osx*.zip
- task: DownloadPipelineArtifact@2
inputs:
artifactName: 'MacArm64'
targetPath: $(Agent.TempDirectory)
- script: cd $(Agent.TempDirectory); mkdir osx-x64-bin; cd osx-x64-bin; unzip ../*x64-osx*.zip
- script: cd $(Agent.TempDirectory); mkdir osx-arm64-bin; cd osx-arm64-bin; unzip ../*arm64-osx*.zip
- script: cd $(Agent.TempDirectory); mkdir linux-bin; cd linux-bin; unzip ../*glibc*.zip
- script: cd $(Agent.TempDirectory); mkdir win32-bin; cd win32-bin; unzip ../*x86-win*.zip
- script: cd $(Agent.TempDirectory); mkdir win64-bin; cd win64-bin; unzip ../*x64-win*.zip
@ -371,16 +414,19 @@ stages:
- script: cd src/api/python; echo $(Agent.TempDirectory)/linux-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel
- script: cd src/api/python; echo $(Agent.TempDirectory)/win32-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel
- script: cd src/api/python; echo $(Agent.TempDirectory)/win64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel
- script: cd src/api/python; echo $(Agent.TempDirectory)/osx-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel
- script: cd src/api/python; echo $(Agent.TempDirectory)/osx-x64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel
- script: cd src/api/python; echo $(Agent.TempDirectory)/osx-arm64-bin/* | xargs printf 'PACKAGE_FROM_RELEASE=%s\n' | xargs -I '{}' env '{}' python3 setup.py bdist_wheel
- task: PublishPipelineArtifact@0
inputs:
artifactName: 'Python packages'
targetPath: src/api/python/dist
- stage: Deployment
jobs:
- job: Deploy
displayName: "Deploy into GitHub"
continueOnError: true
pool:
vmImage: "ubuntu-latest"
steps:
@ -399,6 +445,11 @@ stages:
inputs:
artifactName: 'Mac'
targetPath: tmp
- task: DownloadPipelineArtifact@2
displayName: "Download MacArm64"
inputs:
artifactName: 'MacArm64'
targetPath: tmp
- task: DownloadPipelineArtifact@2
displayName: "Download Ubuntu"
inputs:
@ -425,6 +476,7 @@ stages:
artifactName: 'NuGet32'
targetPath: tmp
- task: GitHubRelease@0
continueOnError: true
inputs:
gitHubConnection: Z3GitHub
repositoryName: 'Z3Prover/z3'
@ -433,6 +485,7 @@ stages:
tagSource: 'manual'
tag: 'Nightly'
- task: GitHubRelease@0
continueOnError: true
inputs:
gitHubConnection: Z3GitHub
repositoryName: 'Z3Prover/z3'
@ -448,5 +501,41 @@ stages:
isDraft: false
isPreRelease: true
- stage: NugetPublishNightly
jobs:
# Publish to nightly feed on Azure
- job: NuGetPublishNightly
displayName: "Push nuget packages to Azure Feed"
steps:
- task: NuGetAuthenticate@0
displayName: 'NuGet Authenticate'
- task: NuGetToolInstaller@0
inputs:
versionSpec: 5.x
checkLatest: false
- task: DownloadPipelineArtifact@2
displayName: 'Download NuGet x86 Package'
inputs:
artifact: 'NuGet32'
path: $(Agent.TempDirectory)/x86
- task: DownloadPipelineArtifact@2
displayName: 'Download NuGet x64 Package'
inputs:
artifact: 'NuGet'
path: $(Agent.TempDirectory)/x64
- task: NuGetCommand@2
displayName: 'NuGet Nightly x64 push'
inputs:
command: push
publishVstsFeed: 'Z3Nightly'
packagesToPush: $(Agent.TempDirectory)/x64/*.nupkg
allowPackageConflicts: true
- task: NuGetCommand@2
displayName: 'NuGet Nightly x86 push'
inputs:
command: push
publishVstsFeed: 'Z3Nightly'
packagesToPush: $(Agent.TempDirectory)/x86/*.nupkg
allowPackageConflicts: true
# TBD: run regression tests on generated binaries.

View file

@ -6,7 +6,7 @@
trigger: none
variables:
ReleaseVersion: '4.8.15'
ReleaseVersion: '4.8.16'
stages:
@ -155,8 +155,8 @@ stages:
- stage: Package
jobs:
- job: NuGetPackage
displayName: "NuGet packaging"
- job: NuGet64
displayName: "NuGet 64 packaging"
pool:
vmImage: "windows-latest"
steps:
@ -171,11 +171,6 @@ stages:
inputs:
artifact: 'WindowsBuild-x64'
path: $(Agent.TempDirectory)\package
- task: DownloadPipelineArtifact@2
displayName: 'Download Win32 Build'
inputs:
artifact: 'WindowsBuild-x86'
path: $(Agent.TempDirectory)\package
- task: DownloadPipelineArtifact@2
displayName: 'Download Ubuntu Build'
inputs:
@ -186,6 +181,10 @@ stages:
inputs:
artifact: 'macOSBuild'
path: $(Agent.TempDirectory)\package
- task: NuGetToolInstaller@0
inputs:
versionSpec: 5.x
checkLatest: false
- task: PythonScript@0
displayName: 'Python: assemble files'
inputs:
@ -200,10 +199,6 @@ stages:
$(Build.SourceVersion)
$(Build.SourcesDirectory)
symbols
- task: NuGetToolInstaller@0
inputs:
versionSpec: 5.x
checkLatest: false
- task: NugetCommand@2
displayName: 'NuGet Pack Symbols'
inputs:
@ -266,7 +261,107 @@ stages:
- task: PublishPipelineArtifact@1
inputs:
targetPath: $(Build.ArtifactStagingDirectory)
artifactName: 'NuGetPackage'
artifactName: 'NuGet'
- job: NuGet32
displayName: "NuGet 32 packaging"
pool:
vmImage: "windows-latest"
steps:
- powershell: write-host $(System.DefinitionId)
displayName: 'System.DefinitionId'
- powershell: write-host $(Build.BuildId)
displayName: 'Build.BuildId'
- powershell: write-host $(System.TeamProjectId)
displayName: 'System.TeamProjectId'
- task: DownloadPipelineArtifact@2
displayName: 'Download Win32 Build'
inputs:
artifact: 'WindowsBuild-x86'
path: $(Agent.TempDirectory)\package
- task: NuGetToolInstaller@0
inputs:
versionSpec: 5.x
checkLatest: false
- task: PythonScript@0
displayName: 'Python: assemble files'
inputs:
scriptSource: 'filepath'
scriptPath: scripts\mk_nuget_task.py
workingDirectory: $(Agent.TempDirectory)\package
arguments:
$(Agent.TempDirectory)\package
$(ReleaseVersion)
$(Build.Repository.Uri)
$(Build.SourceBranchName)
$(Build.SourceVersion)
$(Build.SourcesDirectory)
symbols
x86
- task: NugetCommand@2
displayName: 'NuGet Pack Symbols'
inputs:
command: custom
arguments: 'pack $(Agent.TempDirectory)\package\out\Microsoft.Z3.x86.sym.nuspec -OutputDirectory $(Build.ArtifactStagingDirectory) -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath $(Agent.TempDirectory)\package\out'
- task: EsrpCodeSigning@1
displayName: 'Sign Package'
inputs:
ConnectedServiceName: 'z3-esrp-signing-2'
FolderPath: $(Build.ArtifactStagingDirectory)
Pattern: Microsoft.Z3.x86.$(ReleaseVersion).nupkg
signConfigType: 'inlineSignParams'
inlineOperation: |
[
{
"KeyCode" : "CP-401405",
"OperationCode" : "NuGetSign",
"Parameters" : {},
"ToolName" : "sign",
"ToolVersion" : "1.0"
},
{
"KeyCode" : "CP-401405",
"OperationCode" : "NuGetVerify",
"Parameters" : {},
"ToolName" : "sign",
"ToolVersion" : "1.0"
}
]
SessionTimeout: '60'
MaxConcurrency: '50'
MaxRetryAttempts: '5'
- task: EsrpCodeSigning@1
displayName: 'Sign Symbol Package'
inputs:
ConnectedServiceName: 'z3-esrp-signing-2'
FolderPath: $(Build.ArtifactStagingDirectory)
Pattern: Microsoft.Z3.x86.$(ReleaseVersion).snupkg
signConfigType: 'inlineSignParams'
inlineOperation: |
[
{
"KeyCode" : "CP-401405",
"OperationCode" : "NuGetSign",
"Parameters" : {},
"ToolName" : "sign",
"ToolVersion" : "1.0"
},
{
"KeyCode" : "CP-401405",
"OperationCode" : "NuGetVerify",
"Parameters" : {},
"ToolName" : "sign",
"ToolVersion" : "1.0"
}
]
SessionTimeout: '60'
MaxConcurrency: '50'
MaxRetryAttempts: '5'
- task: PublishPipelineArtifact@1
inputs:
targetPath: $(Build.ArtifactStagingDirectory)
artifactName: 'NuGet32'
- job: PythonPackage
displayName: "Python packaging"
@ -350,9 +445,14 @@ stages:
artifact: 'WindowsBuild-x64'
path: $(Agent.TempDirectory)
- task: DownloadPipelineArtifact@2
displayName: 'Download NuGet Package'
displayName: 'Download NuGet64 Package'
inputs:
artifact: 'NuGetPackage'
artifact: 'NuGet'
path: $(Agent.TempDirectory)
- task: DownloadPipelineArtifact@2
displayName: 'Download NuGet32 Package'
inputs:
artifact: 'NuGet32'
path: $(Agent.TempDirectory)
- task: GitHubRelease@0
inputs:

View file

@ -1820,13 +1820,13 @@ _error_handler_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_uint)
_lib.Z3_set_error_handler.restype = None
_lib.Z3_set_error_handler.argtypes = [ContextObj, _error_handler_type]
push_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p)
pop_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_uint)
push_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p)
pop_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint)
fresh_eh_type = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p)
fixed_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint, ctypes.c_void_p)
fixed_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p)
final_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p)
eq_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint, ctypes.c_uint)
eq_eh_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p)
_lib.Z3_solver_propagate_init.restype = None
_lib.Z3_solver_propagate_init.argtypes = [ContextObj, SolverObj, ctypes.c_void_p, push_eh_type, pop_eh_type, fresh_eh_type]

View file

@ -309,6 +309,22 @@ extern "C" {
Z3_CATCH_RETURN(nullptr);
}
Z3_sort Z3_API Z3_get_array_sort_domain_n(Z3_context c, Z3_sort t, unsigned idx) {
Z3_TRY;
LOG_Z3_get_array_sort_domain_n(c, t, idx);
RESET_ERROR_CODE();
CHECK_VALID_AST(t, nullptr);
if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() &&
to_sort(t)->get_decl_kind() == ARRAY_SORT &&
get_array_arity(to_sort(t)) > idx) {
Z3_sort r = reinterpret_cast<Z3_sort>(get_array_domain(to_sort(t), idx));
RETURN_Z3(r);
}
SET_ERROR_CODE(Z3_INVALID_ARG, nullptr);
RETURN_Z3(nullptr);
Z3_CATCH_RETURN(nullptr);
}
Z3_sort Z3_API Z3_get_array_sort_range(Z3_context c, Z3_sort t) {
Z3_TRY;
LOG_Z3_get_array_sort_range(c, t);

View file

@ -164,7 +164,7 @@ extern "C" {
return;
}
recfun_replace replace(m);
p.set_definition(replace, pd, true, n, _vars.data(), abs_body);
p.set_definition(replace, pd, false, n, _vars.data(), abs_body);
Z3_CATCH;
}
@ -355,7 +355,7 @@ extern "C" {
return mk_c(c)->mk_external_string(buffer.str());
}
else {
return mk_c(c)->mk_external_string(_s.bare_str());
return mk_c(c)->mk_external_string(_s.str());
}
Z3_CATCH_RETURN("");
}
@ -1224,15 +1224,21 @@ extern "C" {
case OP_RE_PLUS: return Z3_OP_RE_PLUS;
case OP_RE_STAR: return Z3_OP_RE_STAR;
case OP_RE_OPTION: return Z3_OP_RE_OPTION;
case OP_RE_RANGE: return Z3_OP_RE_RANGE;
case OP_RE_CONCAT: return Z3_OP_RE_CONCAT;
case OP_RE_UNION: return Z3_OP_RE_UNION;
case OP_RE_DIFF: return Z3_OP_RE_DIFF;
case OP_RE_POWER: return Z3_OP_RE_POWER;
case OP_RE_INTERSECT: return Z3_OP_RE_INTERSECT;
case OP_RE_LOOP: return Z3_OP_RE_LOOP;
case OP_RE_FULL_SEQ_SET: return Z3_OP_RE_FULL_SET;
//case OP_RE_FULL_CHAR_SET: return Z3_OP_RE_FULL_SET;
case OP_RE_POWER: return Z3_OP_RE_POWER;
case OP_RE_COMPLEMENT: return Z3_OP_RE_COMPLEMENT;
case OP_RE_EMPTY_SET: return Z3_OP_RE_EMPTY_SET;
case OP_RE_FULL_SEQ_SET: return Z3_OP_RE_FULL_SET;
case OP_RE_FULL_CHAR_SET: return Z3_OP_RE_FULL_CHAR_SET;
case OP_RE_OF_PRED: return Z3_OP_RE_OF_PRED;
case OP_RE_REVERSE: return Z3_OP_RE_REVERSE;
case OP_RE_DERIVATIVE: return Z3_OP_RE_DERIVATIVE;
default:
return Z3_OP_INTERNAL;
}
@ -1323,6 +1329,9 @@ extern "C" {
}
}
if (mk_c(c)->recfun().get_family_id() == _d->get_family_id())
return Z3_OP_RECURSIVE;
return Z3_OP_UNINTERPRETED;
Z3_CATCH_RETURN(Z3_OP_UNINTERPRETED);
}

View file

@ -88,7 +88,7 @@ void Sy(Z3_symbol sym) {
*g_z3_log << "# " << s.get_num();
}
else {
*g_z3_log << "$ |" << ll_escaped{s.bare_str()} << '|';
*g_z3_log << "$ |" << ll_escaped{s.str().c_str()} << '|';
}
*g_z3_log << std::endl;
}

View file

@ -315,6 +315,17 @@ extern "C" {
Z3_CATCH_RETURN(nullptr);
}
Z3_ast Z3_API Z3_mk_re_power(Z3_context c, Z3_ast r, unsigned n) {
Z3_TRY;
LOG_Z3_mk_re_power(c, r, n);
RESET_ERROR_CODE();
app* a = mk_c(c)->sutil().re.mk_power(to_expr(r), n);
mk_c(c)->save_ast_trail(a);
RETURN_Z3(of_ast(a));
Z3_CATCH_RETURN(nullptr);
}
MK_UNARY(Z3_mk_re_plus, mk_c(c)->get_seq_fid(), OP_RE_PLUS, SKIP);
MK_UNARY(Z3_mk_re_star, mk_c(c)->get_seq_fid(), OP_RE_STAR, SKIP);
MK_UNARY(Z3_mk_re_option, mk_c(c)->get_seq_fid(), OP_RE_OPTION, SKIP);

View file

@ -114,7 +114,7 @@ extern "C" {
}
solver2smt2_pp::solver2smt2_pp(ast_manager& m, const std::string& file):
m_pp_util(m), m_out(file), m_tracked(m) {
m_pp_util(m), m_out(file, std::ofstream::trunc | std::ofstream::out), m_tracked(m) {
if (!m_out) {
throw default_exception("could not open " + file + " for output");
}
@ -564,7 +564,7 @@ extern "C" {
init_solver(c, s);
Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m());
mk_c(c)->save_object(v);
expr_ref_vector trail = to_solver_ref(s)->get_trail();
expr_ref_vector trail = to_solver_ref(s)->get_trail(UINT_MAX);
for (expr* f : trail) {
v->m_ast_vector.push_back(f);
}
@ -883,8 +883,8 @@ extern "C" {
Z3_TRY;
RESET_ERROR_CODE();
init_solver(c, s);
user_propagator::push_eh_t _push = push_eh;
user_propagator::pop_eh_t _pop = pop_eh;
user_propagator::push_eh_t _push = (void(*)(void*,user_propagator::callback*)) push_eh;
user_propagator::pop_eh_t _pop = (void(*)(void*,user_propagator::callback*,unsigned)) pop_eh;
user_propagator::fresh_eh_t _fresh = [=](void * user_ctx, ast_manager& m, user_propagator::context_obj*& _ctx) {
ast_context_params params;
params.set_foreign_manager(&m);
@ -902,7 +902,7 @@ extern "C" {
Z3_fixed_eh fixed_eh) {
Z3_TRY;
RESET_ERROR_CODE();
user_propagator::fixed_eh_t _fixed = (void(*)(void*,user_propagator::callback*,unsigned,expr*))fixed_eh;
user_propagator::fixed_eh_t _fixed = (void(*)(void*,user_propagator::callback*,expr*,expr*))fixed_eh;
to_solver_ref(s)->user_propagate_register_fixed(_fixed);
Z3_CATCH;
}
@ -924,7 +924,7 @@ extern "C" {
Z3_eq_eh eq_eh) {
Z3_TRY;
RESET_ERROR_CODE();
user_propagator::eq_eh_t _eq = (void(*)(void*,user_propagator::callback*,unsigned,unsigned))eq_eh;
user_propagator::eq_eh_t _eq = (void(*)(void*,user_propagator::callback*,expr*,expr*))eq_eh;
to_solver_ref(s)->user_propagate_register_eq(_eq);
Z3_CATCH;
}
@ -935,43 +935,54 @@ extern "C" {
Z3_eq_eh diseq_eh) {
Z3_TRY;
RESET_ERROR_CODE();
user_propagator::eq_eh_t _diseq = (void(*)(void*,user_propagator::callback*,unsigned,unsigned))diseq_eh;
user_propagator::eq_eh_t _diseq = (void(*)(void*,user_propagator::callback*,expr*,expr*))diseq_eh;
to_solver_ref(s)->user_propagate_register_diseq(_diseq);
Z3_CATCH;
}
unsigned Z3_API Z3_solver_propagate_register(Z3_context c, Z3_solver s, Z3_ast e) {
void Z3_API Z3_solver_propagate_register(Z3_context c, Z3_solver s, Z3_ast e) {
Z3_TRY;
LOG_Z3_solver_propagate_register(c, s, e);
RESET_ERROR_CODE();
return to_solver_ref(s)->user_propagate_register_expr(to_expr(e));
Z3_CATCH_RETURN(0);
to_solver_ref(s)->user_propagate_register_expr(to_expr(e));
Z3_CATCH;
}
unsigned Z3_API Z3_solver_propagate_register_cb(Z3_context c, Z3_solver_callback s, Z3_ast e) {
void Z3_API Z3_solver_propagate_register_cb(Z3_context c, Z3_solver_callback s, Z3_ast e) {
Z3_TRY;
LOG_Z3_solver_propagate_register_cb(c, s, e);
RESET_ERROR_CODE();
return reinterpret_cast<user_propagator::callback*>(s)->register_cb(to_expr(e));
Z3_CATCH_RETURN(0);
reinterpret_cast<user_propagator::callback*>(s)->register_cb(to_expr(e));
Z3_CATCH;
}
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback s, unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, Z3_ast conseq) {
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback s, unsigned num_fixed, Z3_ast const* fixed_ids, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq) {
Z3_TRY;
LOG_Z3_solver_propagate_consequence(c, s, num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, conseq);
RESET_ERROR_CODE();
reinterpret_cast<user_propagator::callback*>(s)->propagate_cb(num_fixed, fixed_ids, num_eqs, eq_lhs, eq_rhs, to_expr(conseq));
expr* const * _fixed_ids = (expr* const*) fixed_ids;
expr* const * _eq_lhs = (expr*const*) eq_lhs;
expr* const * _eq_rhs = (expr*const*) eq_rhs;
reinterpret_cast<user_propagator::callback*>(s)->propagate_cb(num_fixed, _fixed_ids, num_eqs, _eq_lhs, _eq_rhs, to_expr(conseq));
Z3_CATCH;
}
void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh) {
Z3_TRY;
RESET_ERROR_CODE();
user_propagator::created_eh_t c = (void(*)(void*, user_propagator::callback*, expr*, unsigned))created_eh;
user_propagator::created_eh_t c = (void(*)(void*, user_propagator::callback*, expr*))created_eh;
to_solver_ref(s)->user_propagate_register_created(c);
Z3_CATCH;
}
void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh) {
Z3_TRY;
RESET_ERROR_CODE();
user_propagator::decide_eh_t c = (void(*)(void*, user_propagator::callback*, expr**, unsigned*, lbool*))decide_eh;
to_solver_ref(s)->user_propagate_register_decide(c);
Z3_CATCH;
}
Z3_func_decl Z3_API Z3_solver_propagate_declare(Z3_context c, Z3_symbol name, unsigned n, Z3_sort* domain, Z3_sort range) {
Z3_TRY;
LOG_Z3_solver_propagate_declare(c, name, n, domain, range);

View file

@ -331,8 +331,8 @@ extern "C" {
if (idx >= mk_c(c)->num_tactics()) {
SET_ERROR_CODE(Z3_IOB, nullptr);
return "";
}
return mk_c(c)->get_tactic(idx)->get_name().bare_str();
}
return mk_c(c)->mk_external_string(mk_c(c)->get_tactic(idx)->get_name().str().c_str());
Z3_CATCH_RETURN("");
}
@ -352,7 +352,7 @@ extern "C" {
SET_ERROR_CODE(Z3_IOB, nullptr);
return "";
}
return mk_c(c)->get_probe(idx)->get_name().bare_str();
return mk_c(c)->mk_external_string(mk_c(c)->get_probe(idx)->get_name().str().c_str());
Z3_CATCH_RETURN("");
}

View file

@ -25,6 +25,7 @@ Notes:
#include<string>
#include<sstream>
#include<memory>
#include<vector>
#include<z3.h>
#include<limits.h>
#include<functional>
@ -155,9 +156,10 @@ namespace z3 {
class context {
private:
friend class user_propagator_base;
bool m_enable_exceptions;
rounding_mode m_rounding_mode;
Z3_context m_ctx;
Z3_context m_ctx = nullptr;
void init(config & c) {
set_context(Z3_mk_context_rc(c));
}
@ -173,7 +175,6 @@ namespace z3 {
context(context const &) = delete;
context & operator=(context const &) = delete;
friend class scoped_context;
context(Z3_context c) { set_context(c); }
void detach() { m_ctx = nullptr; }
public:
@ -394,14 +395,6 @@ namespace z3 {
expr_vector parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls);
};
class scoped_context final {
context m_ctx;
public:
scoped_context(Z3_context c): m_ctx(c) {}
~scoped_context() { m_ctx.detach(); }
context& operator()() { return m_ctx; }
};
template<typename T>
class array {
@ -509,7 +502,7 @@ namespace z3 {
ast(context & c):object(c), m_ast(0) {}
ast(context & c, Z3_ast n):object(c), m_ast(n) { Z3_inc_ref(ctx(), m_ast); }
ast(ast const & s) :object(s), m_ast(s.m_ast) { Z3_inc_ref(ctx(), m_ast); }
~ast() { if (m_ast) Z3_dec_ref(*m_ctx, m_ast); }
~ast() { if (m_ast) { Z3_dec_ref(*m_ctx, m_ast); } }
operator Z3_ast() const { return m_ast; }
operator bool() const { return m_ast != 0; }
ast & operator=(ast const & s) {
@ -550,7 +543,7 @@ namespace z3 {
~ast_vector_tpl() { Z3_ast_vector_dec_ref(ctx(), m_vector); }
operator Z3_ast_vector() const { return m_vector; }
unsigned size() const { return Z3_ast_vector_size(ctx(), m_vector); }
T operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast<T>()(ctx(), r); }
T operator[](unsigned i) const { Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast<T>()(ctx(), r); }
void push_back(T const & e) { Z3_ast_vector_push(ctx(), m_vector, e); check_error(); }
void resize(unsigned sz) { Z3_ast_vector_resize(ctx(), m_vector, sz); check_error(); }
T back() const { return operator[](size() - 1); }
@ -1157,6 +1150,19 @@ namespace z3 {
\pre i < num_args()
*/
expr arg(unsigned i) const { Z3_ast r = Z3_get_app_arg(ctx(), *this, i); check_error(); return expr(ctx(), r); }
/**
\brief Return a vector of all the arguments of this application.
This method assumes the expression is an application.
\pre is_app()
*/
expr_vector args() const {
expr_vector vec(ctx());
unsigned argCnt = num_args();
for (unsigned i = 0; i < argCnt; i++)
vec.push_back(arg(i));
return vec;
}
/**
\brief Return the 'body' of this quantifier.
@ -2327,7 +2333,7 @@ namespace z3 {
inline expr pble(expr_vector const& es, int const* coeffs, int bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
context& ctx = es[0u].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_pble(ctx, _es.size(), _es.ptr(), coeffs, bound);
ctx.check_error();
@ -2335,7 +2341,7 @@ namespace z3 {
}
inline expr pbge(expr_vector const& es, int const* coeffs, int bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
context& ctx = es[0u].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_pbge(ctx, _es.size(), _es.ptr(), coeffs, bound);
ctx.check_error();
@ -2343,7 +2349,7 @@ namespace z3 {
}
inline expr pbeq(expr_vector const& es, int const* coeffs, int bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
context& ctx = es[0u].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_pbeq(ctx, _es.size(), _es.ptr(), coeffs, bound);
ctx.check_error();
@ -2351,7 +2357,7 @@ namespace z3 {
}
inline expr atmost(expr_vector const& es, unsigned bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
context& ctx = es[0u].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_atmost(ctx, _es.size(), _es.ptr(), bound);
ctx.check_error();
@ -2359,7 +2365,7 @@ namespace z3 {
}
inline expr atleast(expr_vector const& es, unsigned bound) {
assert(es.size() > 0);
context& ctx = es[0].ctx();
context& ctx = es[0u].ctx();
array<Z3_ast> _es(es);
Z3_ast r = Z3_mk_atleast(ctx, _es.size(), _es.ptr(), bound);
ctx.check_error();
@ -2367,7 +2373,7 @@ namespace z3 {
}
inline expr sum(expr_vector const& args) {
assert(args.size() > 0);
context& ctx = args[0].ctx();
context& ctx = args[0u].ctx();
array<Z3_ast> _args(args);
Z3_ast r = Z3_mk_add(ctx, _args.size(), _args.ptr());
ctx.check_error();
@ -2376,7 +2382,7 @@ namespace z3 {
inline expr distinct(expr_vector const& args) {
assert(args.size() > 0);
context& ctx = args[0].ctx();
context& ctx = args[0u].ctx();
array<Z3_ast> _args(args);
Z3_ast r = Z3_mk_distinct(ctx, _args.size(), _args.ptr());
ctx.check_error();
@ -2405,14 +2411,14 @@ namespace z3 {
Z3_ast r;
assert(args.size() > 0);
if (args.size() == 1) {
return args[0];
return args[0u];
}
context& ctx = args[0].ctx();
context& ctx = args[0u].ctx();
array<Z3_ast> _args(args);
if (Z3_is_seq_sort(ctx, args[0].get_sort())) {
if (Z3_is_seq_sort(ctx, args[0u].get_sort())) {
r = Z3_mk_seq_concat(ctx, _args.size(), _args.ptr());
}
else if (Z3_is_re_sort(ctx, args[0].get_sort())) {
else if (Z3_is_re_sort(ctx, args[0u].get_sort())) {
r = Z3_mk_re_concat(ctx, _args.size(), _args.ptr());
}
else {
@ -2442,7 +2448,7 @@ namespace z3 {
inline expr mk_xor(expr_vector const& args) {
if (args.empty())
return args.ctx().bool_val(false);
expr r = args[0];
expr r = args[0u];
for (unsigned i = 1; i < args.size(); ++i)
r = r ^ args[i];
return r;
@ -2581,9 +2587,9 @@ namespace z3 {
friend std::ostream & operator<<(std::ostream & out, model const & m);
std::string to_string() const { return std::string(Z3_model_to_string(ctx(), m_model)); }
std::string to_string() const { return m_model ? std::string(Z3_model_to_string(ctx(), m_model)) : "null"; }
};
inline std::ostream & operator<<(std::ostream & out, model const & m) { out << Z3_model_to_string(m.ctx(), m); return out; }
inline std::ostream & operator<<(std::ostream & out, model const & m) { return out << m.to_string(); }
class stats : public object {
Z3_stats m_stats;
@ -2627,7 +2633,8 @@ namespace z3 {
Z3_solver m_solver;
void init(Z3_solver s) {
m_solver = s;
Z3_solver_inc_ref(ctx(), s);
if (s)
Z3_solver_inc_ref(ctx(), s);
}
public:
struct simple {};
@ -2636,7 +2643,7 @@ namespace z3 {
solver(context & c, simple):object(c) { init(Z3_mk_simple_solver(c)); }
solver(context & c, Z3_solver s):object(c) { init(s); }
solver(context & c, char const * logic):object(c) { init(Z3_mk_solver_for_logic(c, c.str_symbol(logic))); }
solver(context & c, solver const& src, translate): object(c) { init(Z3_solver_translate(src.ctx(), src, c)); }
solver(context & c, solver const& src, translate): object(c) { Z3_solver s = Z3_solver_translate(src.ctx(), src, c); check_error(); init(s); }
solver(solver const & s):object(s) { init(s.m_solver); }
~solver() { Z3_solver_dec_ref(ctx(), m_solver); }
operator Z3_solver() const { return m_solver; }
@ -2764,7 +2771,7 @@ namespace z3 {
assert(!m_end && !m_empty);
m_cube = m_solver.cube(m_vars, m_cutoff);
m_cutoff = 0xFFFFFFFF;
if (m_cube.size() == 1 && m_cube[0].is_false()) {
if (m_cube.size() == 1 && m_cube[0u].is_false()) {
m_cube = z3::expr_vector(m_solver.ctx());
m_end = true;
}
@ -2998,7 +3005,7 @@ namespace z3 {
}
array<Z3_tactic> buffer(n);
for (unsigned i = 0; i < n; ++i) buffer[i] = tactics[i];
return tactic(tactics[0].ctx(), Z3_tactic_par_or(tactics[0].ctx(), n, buffer.ptr()));
return tactic(tactics[0u].ctx(), Z3_tactic_par_or(tactics[0u].ctx(), n, buffer.ptr()));
}
inline tactic par_and_then(tactic const & t1, tactic const & t2) {
@ -3797,7 +3804,7 @@ namespace z3 {
}
inline expr re_intersect(expr_vector const& args) {
assert(args.size() > 0);
context& ctx = args[0].ctx();
context& ctx = args[0u].ctx();
array<Z3_ast> _args(args);
Z3_ast r = Z3_mk_re_intersect(ctx, _args.size(), _args.ptr());
ctx.check_error();
@ -3932,56 +3939,65 @@ namespace z3 {
class user_propagator_base {
typedef std::function<void(unsigned, expr const&)> fixed_eh_t;
typedef std::function<void(expr const&, expr const&)> fixed_eh_t;
typedef std::function<void(void)> final_eh_t;
typedef std::function<void(unsigned, unsigned)> eq_eh_t;
typedef std::function<void(unsigned, expr const&)> created_eh_t;
typedef std::function<void(expr const&, expr const&)> eq_eh_t;
typedef std::function<void(expr const&)> created_eh_t;
typedef std::function<void(expr&, unsigned&, Z3_lbool&)> decide_eh_t;
final_eh_t m_final_eh;
eq_eh_t m_eq_eh;
fixed_eh_t m_fixed_eh;
created_eh_t m_created_eh;
decide_eh_t m_decide_eh;
solver* s;
Z3_context c;
Z3_solver_callback cb { nullptr };
context* c;
std::vector<z3::context*> subcontexts;
Z3_context ctx() {
return c ? c : (Z3_context)s->ctx();
}
Z3_solver_callback cb { nullptr };
struct scoped_cb {
user_propagator_base& p;
scoped_cb(void* _p, Z3_solver_callback cb):p(*static_cast<user_propagator_base*>(_p)) {
p.cb = cb;
}
~scoped_cb() {
p.cb = nullptr;
~scoped_cb() {
p.cb = nullptr;
}
};
static void push_eh(void* p) {
static void push_eh(void* _p, Z3_solver_callback cb) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
scoped_cb _cb(p, cb);
static_cast<user_propagator_base*>(p)->push();
}
static void pop_eh(void* p, unsigned num_scopes) {
static_cast<user_propagator_base*>(p)->pop(num_scopes);
}
static void* fresh_eh(void* p, Z3_context ctx) {
return static_cast<user_propagator_base*>(p)->fresh(ctx);
}
static void fixed_eh(void* _p, Z3_solver_callback cb, unsigned id, Z3_ast _value) {
static void pop_eh(void* _p, Z3_solver_callback cb, unsigned num_scopes) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
scoped_cb _cb(p, cb);
scoped_context ctx(p->ctx());
expr value(ctx(), _value);
static_cast<user_propagator_base*>(p)->m_fixed_eh(id, value);
static_cast<user_propagator_base*>(_p)->pop(num_scopes);
}
static void eq_eh(void* p, Z3_solver_callback cb, unsigned x, unsigned y) {
static void* fresh_eh(void* _p, Z3_context ctx) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
context* c = new context(ctx);
p->subcontexts.push_back(c);
return p->fresh(*c);
}
static void fixed_eh(void* _p, Z3_solver_callback cb, Z3_ast _var, Z3_ast _value) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
scoped_cb _cb(p, cb);
static_cast<user_propagator_base*>(p)->m_eq_eh(x, y);
expr value(p->ctx(), _value);
expr var(p->ctx(), _var);
p->m_fixed_eh(var, value);
}
static void eq_eh(void* _p, Z3_solver_callback cb, Z3_ast _x, Z3_ast _y) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
scoped_cb _cb(p, cb);
expr x(p->ctx(), _x), y(p->ctx(), _y);
p->m_eq_eh(x, y);
}
static void final_eh(void* p, Z3_solver_callback cb) {
@ -3989,69 +4005,89 @@ namespace z3 {
static_cast<user_propagator_base*>(p)->m_final_eh();
}
static void created_eh(void* _p, Z3_solver_callback cb, Z3_ast _e, unsigned id) {
static void created_eh(void* _p, Z3_solver_callback cb, Z3_ast _e) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
scoped_cb _cb(p, cb);
scoped_context ctx(p->ctx());
expr e(ctx(), _e);
static_cast<user_propagator_base*>(p)->m_created_eh(id, e);
expr e(p->ctx(), _e);
p->m_created_eh(e);
}
static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast* _val, unsigned* bit, Z3_lbool* is_pos) {
user_propagator_base* p = static_cast<user_propagator_base*>(_p);
scoped_cb _cb(p, cb);
expr val(p->ctx(), *_val);
p->m_decide_eh(val, *bit, *is_pos);
// TBD: life time of val is within the scope of this callback.
*_val = val;
}
public:
user_propagator_base(Z3_context c) : s(nullptr), c(c) {}
user_propagator_base(context& c) : s(nullptr), c(&c) {}
user_propagator_base(solver* s): s(s), c(nullptr) {
Z3_solver_propagate_init(ctx(), *s, this, push_eh, pop_eh, fresh_eh);
Z3_solver_propagate_init(ctx(), *s, this, push_eh, pop_eh, fresh_eh);
}
virtual void push() = 0;
virtual void pop(unsigned num_scopes) = 0;
virtual ~user_propagator_base() = default;
virtual ~user_propagator_base() {
for (auto& subcontext : subcontexts) {
subcontext->detach(); // detach first; the subcontexts will be freed internally!
delete subcontext;
}
}
context& ctx() {
return c ? *c : s->ctx();
}
/**
\brief user_propagators created using \c fresh() are created during
\brief user_propagators created using \c fresh() are created during
search and their lifetimes are restricted to search time. They should
be garbage collected by the propagator used to invoke \c fresh().
The life-time of the Z3_context object can only be assumed valid during
callbacks, such as \c fixed(), which contains expressions based on the
context.
*/
virtual user_propagator_base* fresh(Z3_context ctx) = 0;
virtual user_propagator_base* fresh(context& ctx) = 0;
/**
\brief register callbacks.
Callbacks can only be registered with user_propagators
that were created using a solver.
that were created using a solver.
*/
void register_fixed(fixed_eh_t& f) {
assert(s);
m_fixed_eh = f;
Z3_solver_propagate_fixed(ctx(), *s, fixed_eh);
void register_fixed(fixed_eh_t& f) {
m_fixed_eh = f;
if (s) {
Z3_solver_propagate_fixed(ctx(), *s, fixed_eh);
}
}
void register_fixed() {
assert(s);
m_fixed_eh = [this](unsigned id, expr const& e) {
m_fixed_eh = [this](expr const &id, expr const &e) {
fixed(id, e);
};
Z3_solver_propagate_fixed(ctx(), *s, fixed_eh);
if (s) {
Z3_solver_propagate_fixed(ctx(), *s, fixed_eh);
}
}
void register_eq(eq_eh_t& f) {
assert(s);
m_eq_eh = f;
Z3_solver_propagate_eq(ctx(), *s, eq_eh);
void register_eq(eq_eh_t& f) {
m_eq_eh = f;
if (s) {
Z3_solver_propagate_eq(ctx(), *s, eq_eh);
}
}
void register_eq() {
assert(s);
m_eq_eh = [this](unsigned x, unsigned y) {
m_eq_eh = [this](expr const& x, expr const& y) {
eq(x, y);
};
Z3_solver_propagate_eq(ctx(), *s, eq_eh);
if (s) {
Z3_solver_propagate_eq(ctx(), *s, eq_eh);
}
}
/**
@ -4059,51 +4095,74 @@ namespace z3 {
During the final check stage, all propagations have been processed.
This is an opportunity for the user-propagator to delay some analysis
that could be expensive to perform incrementally. It is also an opportunity
for the propagator to implement branch and bound optimization.
for the propagator to implement branch and bound optimization.
*/
void register_final(final_eh_t& f) {
assert(s);
m_final_eh = f;
Z3_solver_propagate_final(ctx(), *s, final_eh);
void register_final(final_eh_t& f) {
m_final_eh = f;
if (s) {
Z3_solver_propagate_final(ctx(), *s, final_eh);
}
}
void register_final() {
assert(s);
void register_final() {
m_final_eh = [this]() {
final();
};
Z3_solver_propagate_final(ctx(), *s, final_eh);
if (s) {
Z3_solver_propagate_final(ctx(), *s, final_eh);
}
}
void register_created(created_eh_t& c) {
assert(s);
m_created_eh = c;
Z3_solver_propagate_created(ctx(), *s, created_eh);
if (s) {
Z3_solver_propagate_created(ctx(), *s, created_eh);
}
}
void register_created() {
m_created_eh = [this](unsigned id, expr const& e) {
created(id, e);
m_created_eh = [this](expr const& e) {
created(e);
};
Z3_solver_propagate_created(ctx(), *s, created_eh);
if (s) {
Z3_solver_propagate_created(ctx(), *s, created_eh);
}
}
void register_decide(decide_eh_t& c) {
m_decide_eh = c;
if (s) {
Z3_solver_propagate_decide(ctx(), *s, decide_eh);
}
}
virtual void fixed(unsigned /*id*/, expr const& /*e*/) { }
void register_decide() {
m_decide_eh = [this](expr& val, unsigned& bit, Z3_lbool& is_pos) {
decide(val, bit, is_pos);
};
if (s) {
Z3_solver_propagate_decide(ctx(), *s, decide_eh);
}
}
virtual void eq(unsigned /*x*/, unsigned /*y*/) { }
virtual void fixed(expr const& /*id*/, expr const& /*e*/) { }
virtual void eq(expr const& /*x*/, expr const& /*y*/) { }
virtual void final() { }
virtual void created(unsigned /*id*/, expr const& /*e*/) {}
virtual void created(expr const& /*e*/) {}
virtual void decide(expr& /*val*/, unsigned& /*bit*/, Z3_lbool& /*is_pos*/) {}
/**
\brief tracks \c e by a unique identifier that is returned by the call.
If the \c fixed() callback is registered and if \c e is a Boolean or Bit-vector,
If the \c fixed() callback is registered and if \c e is a Boolean or Bit-vector,
the \c fixed() callback gets invoked when \c e is bound to a value.
If the \c eq() callback is registered, then equalities between registered expressions
are reported.
are reported.
A consumer can use the \c propagate or \c conflict functions to invoke propagations
or conflicts as a consequence of these callbacks. These functions take a list of identifiers
for registered expressions that have been fixed. The list of identifiers must correspond to
@ -4111,40 +4170,43 @@ namespace z3 {
correspond to equalities that have been registered during a callback.
*/
unsigned add(expr const& e) {
void add(expr const& e) {
if (cb)
return Z3_solver_propagate_register_cb(ctx(), cb, e);
if (s)
return Z3_solver_propagate_register(ctx(), *s, e);
assert(false);
return 0;
Z3_solver_propagate_register_cb(ctx(), cb, e);
else if (s)
Z3_solver_propagate_register(ctx(), *s, e);
else
assert(false);
}
void conflict(unsigned num_fixed, unsigned const* fixed) {
void conflict(expr_vector const& fixed) {
assert(cb);
scoped_context _ctx(ctx());
expr conseq = _ctx().bool_val(false);
Z3_solver_propagate_consequence(ctx(), cb, num_fixed, fixed, 0, nullptr, nullptr, conseq);
expr conseq = ctx().bool_val(false);
array<Z3_ast> _fixed(fixed);
Z3_solver_propagate_consequence(ctx(), cb, fixed.size(), _fixed.ptr(), 0, nullptr, nullptr, conseq);
}
void propagate(unsigned num_fixed, unsigned const* fixed, expr const& conseq) {
void propagate(expr_vector const& fixed, expr const& conseq) {
assert(cb);
assert(conseq.ctx() == ctx());
Z3_solver_propagate_consequence(ctx(), cb, num_fixed, fixed, 0, nullptr, nullptr, conseq);
assert((Z3_context)conseq.ctx() == (Z3_context)ctx());
array<Z3_ast> _fixed(fixed);
Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), 0, nullptr, nullptr, conseq);
}
void propagate(unsigned num_fixed, unsigned const* fixed,
unsigned num_eqs, unsigned const* lhs, unsigned const * rhs,
void propagate(expr_vector const& fixed,
expr_vector const& lhs, expr_vector const& rhs,
expr const& conseq) {
assert(cb);
assert(conseq.ctx() == ctx());
Z3_solver_propagate_consequence(ctx(), cb, num_fixed, fixed, num_eqs, lhs, rhs, conseq);
assert((Z3_context)conseq.ctx() == (Z3_context)ctx());
assert(lhs.size() == rhs.size());
array<Z3_ast> _fixed(fixed);
array<Z3_ast> _lhs(lhs);
array<Z3_ast> _rhs(rhs);
Z3_solver_propagate_consequence(ctx(), cb, _fixed.size(), _fixed.ptr(), lhs.size(), _lhs.ptr(), _rhs.ptr(), conseq);
}
};
}
/**@}*/

View file

@ -100,7 +100,7 @@ namespace Microsoft.Z3
{
get
{
ASTVector res = new ASTVector(Context, Native.Z3_ast_map_keys(Context.nCtx, NativeObject));
using ASTVector res = new ASTVector(Context, Native.Z3_ast_map_keys(Context.nCtx, NativeObject));
return res.ToArray();
}
}

View file

@ -22,7 +22,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Z3
{
/// <summary>
@ -41,24 +40,48 @@ namespace Microsoft.Z3
#region Operators
private static ArithExpr MkNum(ArithExpr e, int i) { return (ArithExpr)e.Context.MkNumeral(i, e.Context.MkIntSort()); }
private static ArithExpr MkNum(ArithExpr e, int i)
{
using var sort = e.Context.MkIntSort();
return (ArithExpr)e.Context.MkNumeral(i, sort);
}
private static ArithExpr MkNum(ArithExpr e, double d) { return (ArithExpr)e.Context.MkNumeral(d.ToString(), e.Context.MkRealSort()); }
private static ArithExpr MkNum(ArithExpr e, double d)
{
using var sort = e.Context.MkRealSort();
return (ArithExpr)e.Context.MkNumeral(d.ToString(), sort);
}
/// <summary> Operator overloading for arithmetical division operator (over reals) </summary>
public static ArithExpr operator /(ArithExpr a, ArithExpr b) { return a.Context.MkDiv(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator /(ArithExpr a, int b) { return a / MkNum(a, b); }
public static ArithExpr operator /(ArithExpr a, int b)
{
using var denominator = MkNum(a, b);
return a / denominator;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator /(ArithExpr a, double b) { return a / MkNum(a, b); }
public static ArithExpr operator /(ArithExpr a, double b)
{
using var denominator = MkNum(a, b);
return a / denominator;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator /(int a, ArithExpr b) { return MkNum(b, a) / b; }
public static ArithExpr operator /(int a, ArithExpr b)
{
using var numerator = MkNum(b, a);
return numerator / b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator /(double a, ArithExpr b) { return MkNum(b, a) / b; }
public static ArithExpr operator /(double a, ArithExpr b)
{
using var numerator = MkNum(b, a);
return numerator / b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator -(ArithExpr a) { return a.Context.MkUnaryMinus(a); }
@ -67,106 +90,218 @@ namespace Microsoft.Z3
public static ArithExpr operator -(ArithExpr a, ArithExpr b) { return a.Context.MkSub(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator -(ArithExpr a, int b) { return a - MkNum(a, b); }
public static ArithExpr operator -(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a - rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator -(ArithExpr a, double b) { return a - MkNum(a, b); }
public static ArithExpr operator -(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a - rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator -(int a, ArithExpr b) { return MkNum(b, a) - b; }
public static ArithExpr operator -(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs - b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator -(double a, ArithExpr b) { return MkNum(b, a) - b; }
public static ArithExpr operator -(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs - b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator +(ArithExpr a, ArithExpr b) { return a.Context.MkAdd(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator +(ArithExpr a, int b) { return a + MkNum(a, b); }
public static ArithExpr operator +(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a + rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator +(ArithExpr a, double b) { return a + MkNum(a, b); }
public static ArithExpr operator +(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a + rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator +(int a, ArithExpr b) { return MkNum(b, a) + b; }
public static ArithExpr operator +(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs + b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator +(double a, ArithExpr b) { return MkNum(b, a) + b; }
public static ArithExpr operator +(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs + b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator *(ArithExpr a, ArithExpr b) { return a.Context.MkMul(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator *(ArithExpr a, int b) { return a * MkNum(a, b); }
public static ArithExpr operator *(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a * rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator *(ArithExpr a, double b) { return a * MkNum(a, b); }
public static ArithExpr operator *(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a * rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator *(int a, ArithExpr b) { return MkNum(b, a) * b; }
public static ArithExpr operator *(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs * b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static ArithExpr operator *(double a, ArithExpr b) { return MkNum(b, a) * b; }
public static ArithExpr operator *(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs * b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <=(ArithExpr a, ArithExpr b) { return a.Context.MkLe(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <=(ArithExpr a, int b) { return a <= MkNum(a, b); }
public static BoolExpr operator <=(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a <= rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <=(ArithExpr a, double b) { return a <= MkNum(a, b); }
public static BoolExpr operator <=(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a <= rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <=(int a, ArithExpr b) { return MkNum(b, a) <= b; }
public static BoolExpr operator <=(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs <= b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <=(double a, ArithExpr b) { return MkNum(b, a) <= b; }
public static BoolExpr operator <=(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs <= b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <(ArithExpr a, ArithExpr b) { return a.Context.MkLt(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <(ArithExpr a, int b) { return a < MkNum(a, b); }
public static BoolExpr operator <(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a < rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <(ArithExpr a, double b) { return a < MkNum(a, b); }
public static BoolExpr operator <(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a < rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <(int a, ArithExpr b) { return MkNum(b, a) < b; }
public static BoolExpr operator <(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs < b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator <(double a, ArithExpr b) { return MkNum(b, a) < b; }
public static BoolExpr operator <(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs < b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >(ArithExpr a, ArithExpr b) { return a.Context.MkGt(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >(ArithExpr a, int b) { return a > MkNum(a, b); }
public static BoolExpr operator >(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a > rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >(ArithExpr a, double b) { return a > MkNum(a, b); }
public static BoolExpr operator >(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a > rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >(int a, ArithExpr b) { return MkNum(b, a) > b; }
public static BoolExpr operator >(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs > b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >(double a, ArithExpr b) { return MkNum(b, a) > b; }
public static BoolExpr operator >(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs > b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >=(ArithExpr a, ArithExpr b) { return a.Context.MkGe(a, b); }
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >=(ArithExpr a, int b) { return a >= MkNum(a, b); }
public static BoolExpr operator >=(ArithExpr a, int b)
{
using var rhs = MkNum(a, b);
return a >= rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >=(ArithExpr a, double b) { return a >= MkNum(a, b); }
public static BoolExpr operator >=(ArithExpr a, double b)
{
using var rhs = MkNum(a, b);
return a >= rhs;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >=(int a, ArithExpr b) { return MkNum(b, a) >= b; }
public static BoolExpr operator >=(int a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs >= b;
}
/// <summary> Operator overloading for arithmetical operator </summary>
public static BoolExpr operator >=(double a, ArithExpr b) { return MkNum(b, a) >= b; }
public static BoolExpr operator >=(double a, ArithExpr b)
{
using var lhs = MkNum(b, a);
return lhs >= b;
}
#endregion
}

View file

@ -85,6 +85,10 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE
ListSort.cs
Log.cs
Model.cs
NativeContext.cs
NativeFuncInterp.cs
NativeModel.cs
NativeSolver.cs
Optimize.cs
ParamDescrs.cs
Params.cs

View file

@ -18,10 +18,10 @@ Notes:
--*/
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
namespace Microsoft.Z3
{
@ -202,8 +202,8 @@ namespace Microsoft.Z3
/// </summary>
public UninterpretedSort MkUninterpretedSort(string str)
{
return MkUninterpretedSort(MkSymbol(str));
using var sym = MkSymbol(str);
return MkUninterpretedSort(sym);
}
/// <summary>
@ -231,7 +231,6 @@ namespace Microsoft.Z3
return new BitVecSort(this, Native.Z3_mk_bv_sort(nCtx, size));
}
/// <summary>
/// Create a new sequence sort.
/// </summary>
@ -314,7 +313,17 @@ namespace Microsoft.Z3
{
Debug.Assert(enumNames != null);
return new EnumSort(this, MkSymbol(name), MkSymbols(enumNames));
var enumSymbols = MkSymbols(enumNames);
try
{
using var symbol = MkSymbol(name);
return new EnumSort(this, symbol, enumSymbols);
}
finally
{
foreach (var enumSymbol in enumSymbols)
enumSymbol.Dispose();
}
}
/// <summary>
@ -338,7 +347,8 @@ namespace Microsoft.Z3
Debug.Assert(elemSort != null);
CheckContextMatch(elemSort);
return new ListSort(this, MkSymbol(name), elemSort);
using var symbol = MkSymbol(name);
return new ListSort(this, symbol, elemSort);
}
/// <summary>
@ -365,8 +375,8 @@ namespace Microsoft.Z3
/// <param name="size">The size of the sort</param>
public FiniteDomainSort MkFiniteDomainSort(string name, ulong size)
{
return new FiniteDomainSort(this, MkSymbol(name), size);
using var symbol = MkSymbol(name);
return new FiniteDomainSort(this, symbol, size);
}
@ -401,7 +411,18 @@ namespace Microsoft.Z3
public Constructor MkConstructor(string name, string recognizer, string[] fieldNames = null, Sort[] sorts = null, uint[] sortRefs = null)
{
return new Constructor(this, MkSymbol(name), MkSymbol(recognizer), MkSymbols(fieldNames), sorts, sortRefs);
using var nameSymbol = MkSymbol(name);
using var recognizerSymbol = MkSymbol(recognizer);
var fieldSymbols = MkSymbols(fieldNames);
try
{
return new Constructor(this, nameSymbol, recognizerSymbol, fieldSymbols, sorts, sortRefs);
}
finally
{
foreach (var fieldSymbol in fieldSymbols)
fieldSymbol.Dispose();
}
}
/// <summary>
@ -428,7 +449,8 @@ namespace Microsoft.Z3
Debug.Assert(constructors.All(c => c != null));
CheckContextMatch<Constructor>(constructors);
return new DatatypeSort(this, MkSymbol(name), constructors);
using var symbol = MkSymbol(name);
return new DatatypeSort(this, symbol, constructors);
}
/// <summary>
@ -477,7 +499,16 @@ namespace Microsoft.Z3
//Debug.Assert(Contract.ForAll(0, c.Length, j => c[j] != null));
//Debug.Assert(names.All(name => name != null));
return MkDatatypeSorts(MkSymbols(names), c);
var symbols = MkSymbols(names);
try
{
return MkDatatypeSorts(symbols, c);
}
finally
{
foreach (var symbol in symbols)
symbol.Dispose();
}
}
/// <summary>
@ -485,7 +516,7 @@ namespace Microsoft.Z3
/// The function performs a record update at t. The field
/// that is passed in as argument is updated with value v,
/// the remaining fields of t are unchanged.
/// </summary>
/// </summary>
public Expr MkUpdateField(FuncDecl field, Expr t, Expr v)
{
return Expr.Create(this, Native.Z3_datatype_update_field(
@ -538,7 +569,8 @@ namespace Microsoft.Z3
CheckContextMatch<Sort>(domain);
CheckContextMatch(range);
return new FuncDecl(this, MkSymbol(name), domain, range);
using var symbol = MkSymbol(name);
return new FuncDecl(this, symbol, domain, range);
}
/// <summary>
@ -551,7 +583,8 @@ namespace Microsoft.Z3
CheckContextMatch<Sort>(domain);
CheckContextMatch(range);
return new FuncDecl(this, MkSymbol(name), domain, range, true);
using var symbol = MkSymbol(name);
return new FuncDecl(this, symbol, domain, range, true);
}
/// <summary>
@ -560,14 +593,14 @@ namespace Microsoft.Z3
/// MkRecFuncDecl. The body may contain recursive uses of the function or
/// other mutually recursive functions.
/// </summary>
public void AddRecDef(FuncDecl f, Expr[] args, Expr body)
{
CheckContextMatch(f);
CheckContextMatch<Expr>(args);
CheckContextMatch(body);
public void AddRecDef(FuncDecl f, Expr[] args, Expr body)
{
CheckContextMatch(f);
CheckContextMatch<Expr>(args);
CheckContextMatch(body);
IntPtr[] argsNative = AST.ArrayToNative(args);
Native.Z3_add_rec_def(nCtx, f.NativeObject, (uint)args.Length, argsNative, body.NativeObject);
}
Native.Z3_add_rec_def(nCtx, f.NativeObject, (uint)args.Length, argsNative, body.NativeObject);
}
/// <summary>
/// Creates a new function declaration.
@ -579,8 +612,9 @@ namespace Microsoft.Z3
CheckContextMatch(domain);
CheckContextMatch(range);
using var symbol = MkSymbol(name);
Sort[] q = new Sort[] { domain };
return new FuncDecl(this, MkSymbol(name), q, range);
return new FuncDecl(this, symbol, q, range);
}
/// <summary>
@ -619,7 +653,8 @@ namespace Microsoft.Z3
Debug.Assert(range != null);
CheckContextMatch(range);
return new FuncDecl(this, MkSymbol(name), null, range);
using var symbol = MkSymbol(name);
return new FuncDecl(this, symbol, null, range);
}
/// <summary>
@ -687,7 +722,8 @@ namespace Microsoft.Z3
{
Debug.Assert(range != null);
return MkConst(MkSymbol(name), range);
using var symbol = MkSymbol(name);
return MkConst(symbol, range);
}
/// <summary>
@ -728,8 +764,8 @@ namespace Microsoft.Z3
/// </summary>
public BoolExpr MkBoolConst(string name)
{
return (BoolExpr)MkConst(MkSymbol(name), BoolSort);
using var symbol = MkSymbol(name);
return (BoolExpr)MkConst(symbol, BoolSort);
}
/// <summary>
@ -778,7 +814,8 @@ namespace Microsoft.Z3
{
Debug.Assert(name != null);
return (BitVecExpr)MkConst(name, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecExpr)MkConst(name, sort);
}
/// <summary>
@ -786,8 +823,8 @@ namespace Microsoft.Z3
/// </summary>
public BitVecExpr MkBVConst(string name, uint size)
{
return (BitVecExpr)MkConst(name, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecExpr)MkConst(name, sort);
}
#endregion
@ -811,7 +848,7 @@ namespace Microsoft.Z3
public Expr MkApp(FuncDecl f, IEnumerable<Expr> args)
{
Debug.Assert(f != null);
Debug.Assert(args == null || args.All( a => a != null));
Debug.Assert(args == null || args.All(a => a != null));
CheckContextMatch(f);
CheckContextMatch(args);
@ -948,16 +985,12 @@ namespace Microsoft.Z3
Debug.Assert(ts != null);
Debug.Assert(ts.All(a => a != null));
CheckContextMatch<BoolExpr>(ts);
BoolExpr r = null;
foreach (var t in ts) {
if (r == null)
r = t;
else
r = MkXor(r, t);
}
if (r == null)
r = MkTrue();
return r;
return ts.Aggregate(MkFalse(), (r, t) =>
{
using (r)
return MkXor(r, t);
});
}
/// <summary>
@ -2032,7 +2065,8 @@ namespace Microsoft.Z3
Debug.Assert(domain != null);
Debug.Assert(range != null);
return (ArrayExpr)MkConst(name, MkArraySort(domain, range));
using var sort = MkArraySort(domain, range);
return (ArrayExpr)MkConst(name, sort);
}
/// <summary>
@ -2043,7 +2077,9 @@ namespace Microsoft.Z3
Debug.Assert(domain != null);
Debug.Assert(range != null);
return (ArrayExpr)MkConst(MkSymbol(name), MkArraySort(domain, range));
using var symbol = MkSymbol(name);
using var sort = MkArraySort(domain, range);
return (ArrayExpr)MkConst(symbol, sort);
}
@ -2343,7 +2379,7 @@ namespace Microsoft.Z3
CheckContextMatch(elem);
CheckContextMatch(set);
return (BoolExpr) Expr.Create(this, Native.Z3_mk_set_member(nCtx, elem.NativeObject, set.NativeObject));
return (BoolExpr)Expr.Create(this, Native.Z3_mk_set_member(nCtx, elem.NativeObject, set.NativeObject));
}
/// <summary>
@ -2356,7 +2392,7 @@ namespace Microsoft.Z3
CheckContextMatch(arg1);
CheckContextMatch(arg2);
return (BoolExpr) Expr.Create(this, Native.Z3_mk_set_subset(nCtx, arg1.NativeObject, arg2.NativeObject));
return (BoolExpr)Expr.Create(this, Native.Z3_mk_set_subset(nCtx, arg1.NativeObject, arg2.NativeObject));
}
#endregion
@ -2366,7 +2402,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create the empty sequence.
/// </summary>
public SeqExpr MkEmptySeq(Sort s)
public SeqExpr MkEmptySeq(Sort s)
{
Debug.Assert(s != null);
return new SeqExpr(this, Native.Z3_mk_seq_empty(nCtx, s.NativeObject));
@ -2375,7 +2411,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create the singleton sequence.
/// </summary>
public SeqExpr MkUnit(Expr elem)
public SeqExpr MkUnit(Expr elem)
{
Debug.Assert(elem != null);
return new SeqExpr(this, Native.Z3_mk_seq_unit(nCtx, elem.NativeObject));
@ -2384,7 +2420,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create a string constant.
/// </summary>
public SeqExpr MkString(string s)
public SeqExpr MkString(string s)
{
Debug.Assert(s != null);
return new SeqExpr(this, Native.Z3_mk_string(nCtx, s));
@ -2393,7 +2429,7 @@ namespace Microsoft.Z3
/// <summary>
/// Convert an integer expression to a string.
/// </summary>
public SeqExpr IntToString(Expr e)
public SeqExpr IntToString(Expr e)
{
Debug.Assert(e != null);
Debug.Assert(e is ArithExpr);
@ -2413,7 +2449,8 @@ namespace Microsoft.Z3
/// <summary>
/// Convert a bit-vector expression, represented as an signed number, to a string.
/// </summary>
public SeqExpr SbvToString(Expr e) {
public SeqExpr SbvToString(Expr e)
{
Debug.Assert(e != null);
Debug.Assert(e is ArithExpr);
return new SeqExpr(this, Native.Z3_mk_sbv_to_str(nCtx, e.NativeObject));
@ -2422,7 +2459,7 @@ namespace Microsoft.Z3
/// <summary>
/// Convert an integer expression to a string.
/// </summary>
public IntExpr StringToInt(Expr e)
public IntExpr StringToInt(Expr e)
{
Debug.Assert(e != null);
Debug.Assert(e is SeqExpr);
@ -2449,13 +2486,13 @@ namespace Microsoft.Z3
public IntExpr MkLength(SeqExpr s)
{
Debug.Assert(s != null);
return (IntExpr) Expr.Create(this, Native.Z3_mk_seq_length(nCtx, s.NativeObject));
return (IntExpr)Expr.Create(this, Native.Z3_mk_seq_length(nCtx, s.NativeObject));
}
/// <summary>
/// Check for sequence prefix.
/// </summary>
public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2)
public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2)
{
Debug.Assert(s1 != null);
Debug.Assert(s2 != null);
@ -2466,7 +2503,7 @@ namespace Microsoft.Z3
/// <summary>
/// Check for sequence suffix.
/// </summary>
public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2)
public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2)
{
Debug.Assert(s1 != null);
Debug.Assert(s2 != null);
@ -2477,7 +2514,7 @@ namespace Microsoft.Z3
/// <summary>
/// Check for sequence containment of s2 in s1.
/// </summary>
public BoolExpr MkContains(SeqExpr s1, SeqExpr s2)
public BoolExpr MkContains(SeqExpr s1, SeqExpr s2)
{
Debug.Assert(s1 != null);
Debug.Assert(s2 != null);
@ -2488,7 +2525,7 @@ namespace Microsoft.Z3
/// <summary>
/// Check if the string s1 is lexicographically strictly less than s2.
/// </summary>
public BoolExpr MkStringLt(SeqExpr s1, SeqExpr s2)
public BoolExpr MkStringLt(SeqExpr s1, SeqExpr s2)
{
Debug.Assert(s1 != null);
Debug.Assert(s2 != null);
@ -2497,9 +2534,9 @@ namespace Microsoft.Z3
}
/// <summary>
/// Check if the string s1 is lexicographically strictly less than s2.
/// Check if the string s1 is lexicographically less or equal to s2.
/// </summary>
public BoolExpr MkStringLe(SeqExpr s1, SeqExpr s2)
public BoolExpr MkStringLe(SeqExpr s1, SeqExpr s2)
{
Debug.Assert(s1 != null);
Debug.Assert(s2 != null);
@ -2568,10 +2605,10 @@ namespace Microsoft.Z3
/// <summary>
/// Convert a regular expression that accepts sequence s.
/// </summary>
public ReExpr MkToRe(SeqExpr s)
public ReExpr MkToRe(SeqExpr s)
{
Debug.Assert(s != null);
return new ReExpr(this, Native.Z3_mk_seq_to_re(nCtx, s.NativeObject));
return new ReExpr(this, Native.Z3_mk_seq_to_re(nCtx, s.NativeObject));
}
@ -2583,7 +2620,7 @@ namespace Microsoft.Z3
Debug.Assert(s != null);
Debug.Assert(re != null);
CheckContextMatch(s, re);
return new BoolExpr(this, Native.Z3_mk_seq_in_re(nCtx, s.NativeObject, re.NativeObject));
return new BoolExpr(this, Native.Z3_mk_seq_in_re(nCtx, s.NativeObject, re.NativeObject));
}
/// <summary>
@ -2592,7 +2629,7 @@ namespace Microsoft.Z3
public ReExpr MkStar(ReExpr re)
{
Debug.Assert(re != null);
return new ReExpr(this, Native.Z3_mk_re_star(nCtx, re.NativeObject));
return new ReExpr(this, Native.Z3_mk_re_star(nCtx, re.NativeObject));
}
/// <summary>
@ -2601,7 +2638,7 @@ namespace Microsoft.Z3
public ReExpr MkLoop(ReExpr re, uint lo, uint hi = 0)
{
Debug.Assert(re != null);
return new ReExpr(this, Native.Z3_mk_re_loop(nCtx, re.NativeObject, lo, hi));
return new ReExpr(this, Native.Z3_mk_re_loop(nCtx, re.NativeObject, lo, hi));
}
/// <summary>
@ -2610,7 +2647,7 @@ namespace Microsoft.Z3
public ReExpr MkPlus(ReExpr re)
{
Debug.Assert(re != null);
return new ReExpr(this, Native.Z3_mk_re_plus(nCtx, re.NativeObject));
return new ReExpr(this, Native.Z3_mk_re_plus(nCtx, re.NativeObject));
}
/// <summary>
@ -2619,7 +2656,7 @@ namespace Microsoft.Z3
public ReExpr MkOption(ReExpr re)
{
Debug.Assert(re != null);
return new ReExpr(this, Native.Z3_mk_re_option(nCtx, re.NativeObject));
return new ReExpr(this, Native.Z3_mk_re_option(nCtx, re.NativeObject));
}
/// <summary>
@ -2628,7 +2665,7 @@ namespace Microsoft.Z3
public ReExpr MkComplement(ReExpr re)
{
Debug.Assert(re != null);
return new ReExpr(this, Native.Z3_mk_re_complement(nCtx, re.NativeObject));
return new ReExpr(this, Native.Z3_mk_re_complement(nCtx, re.NativeObject));
}
/// <summary>
@ -2670,7 +2707,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create a difference regular expression.
/// </summary>
public ReExpr MkDiff(ReExpr a, ReExpr b)
public ReExpr MkDiff(ReExpr a, ReExpr b)
{
Debug.Assert(a != null);
Debug.Assert(b != null);
@ -2682,7 +2719,7 @@ namespace Microsoft.Z3
/// Create the empty regular expression.
/// The sort s should be a regular expression.
/// </summary>
public ReExpr MkEmptyRe(Sort s)
public ReExpr MkEmptyRe(Sort s)
{
Debug.Assert(s != null);
return new ReExpr(this, Native.Z3_mk_re_empty(nCtx, s.NativeObject));
@ -2692,7 +2729,7 @@ namespace Microsoft.Z3
/// Create the full regular expression.
/// The sort s should be a regular expression.
/// </summary>
public ReExpr MkFullRe(Sort s)
public ReExpr MkFullRe(Sort s)
{
Debug.Assert(s != null);
return new ReExpr(this, Native.Z3_mk_re_full(nCtx, s.NativeObject));
@ -2702,7 +2739,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create a range expression.
/// </summary>
public ReExpr MkRange(SeqExpr lo, SeqExpr hi)
public ReExpr MkRange(SeqExpr lo, SeqExpr hi)
{
Debug.Assert(lo != null);
Debug.Assert(hi != null);
@ -2713,7 +2750,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create less than or equal to between two characters.
/// </summary>
public BoolExpr MkCharLe(Expr ch1, Expr ch2)
public BoolExpr MkCharLe(Expr ch1, Expr ch2)
{
Debug.Assert(ch1 != null);
Debug.Assert(ch2 != null);
@ -2723,7 +2760,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create an integer (code point) from character.
/// </summary>
public IntExpr CharToInt(Expr ch)
public IntExpr CharToInt(Expr ch)
{
Debug.Assert(ch != null);
return new IntExpr(this, Native.Z3_mk_char_to_int(nCtx, ch.NativeObject));
@ -2732,7 +2769,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create a bit-vector (code point) from character.
/// </summary>
public BitVecExpr CharToBV(Expr ch)
public BitVecExpr CharToBV(Expr ch)
{
Debug.Assert(ch != null);
return new BitVecExpr(this, Native.Z3_mk_char_to_bv(nCtx, ch.NativeObject));
@ -2741,7 +2778,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create a character from a bit-vector (code point).
/// </summary>
public Expr CharFromBV(BitVecExpr bv)
public Expr CharFromBV(BitVecExpr bv)
{
Debug.Assert(bv != null);
return new Expr(this, Native.Z3_mk_char_from_bv(nCtx, bv.NativeObject));
@ -2750,7 +2787,7 @@ namespace Microsoft.Z3
/// <summary>
/// Create a check if the character is a digit.
/// </summary>
public BoolExpr MkIsDigit(Expr ch)
public BoolExpr MkIsDigit(Expr ch)
{
Debug.Assert(ch != null);
return new BoolExpr(this, Native.Z3_mk_char_is_digit(nCtx, ch.NativeObject));
@ -2768,7 +2805,7 @@ namespace Microsoft.Z3
Debug.Assert(args != null);
CheckContextMatch<BoolExpr>(args);
var ts = args.ToArray();
return new BoolExpr(this, Native.Z3_mk_atmost(nCtx, (uint) ts.Length,
return new BoolExpr(this, Native.Z3_mk_atmost(nCtx, (uint)ts.Length,
AST.ArrayToNative(ts), k));
}
@ -2780,7 +2817,7 @@ namespace Microsoft.Z3
Debug.Assert(args != null);
CheckContextMatch<BoolExpr>(args);
var ts = args.ToArray();
return new BoolExpr(this, Native.Z3_mk_atleast(nCtx, (uint) ts.Length,
return new BoolExpr(this, Native.Z3_mk_atleast(nCtx, (uint)ts.Length,
AST.ArrayToNative(ts), k));
}
@ -2789,13 +2826,13 @@ namespace Microsoft.Z3
/// </summary>
public BoolExpr MkPBLe(int[] coeffs, BoolExpr[] args, int k)
{
Debug.Assert(args != null);
Debug.Assert(coeffs != null);
Debug.Assert(args.Length == coeffs.Length);
CheckContextMatch<BoolExpr>(args);
return new BoolExpr(this, Native.Z3_mk_pble(nCtx, (uint) args.Length,
AST.ArrayToNative(args),
coeffs, k));
Debug.Assert(args != null);
Debug.Assert(coeffs != null);
Debug.Assert(args.Length == coeffs.Length);
CheckContextMatch<BoolExpr>(args);
return new BoolExpr(this, Native.Z3_mk_pble(nCtx, (uint)args.Length,
AST.ArrayToNative(args),
coeffs, k));
}
/// <summary>
@ -2803,26 +2840,26 @@ namespace Microsoft.Z3
/// </summary>
public BoolExpr MkPBGe(int[] coeffs, BoolExpr[] args, int k)
{
Debug.Assert(args != null);
Debug.Assert(coeffs != null);
Debug.Assert(args.Length == coeffs.Length);
CheckContextMatch<BoolExpr>(args);
return new BoolExpr(this, Native.Z3_mk_pbge(nCtx, (uint) args.Length,
AST.ArrayToNative(args),
coeffs, k));
Debug.Assert(args != null);
Debug.Assert(coeffs != null);
Debug.Assert(args.Length == coeffs.Length);
CheckContextMatch<BoolExpr>(args);
return new BoolExpr(this, Native.Z3_mk_pbge(nCtx, (uint)args.Length,
AST.ArrayToNative(args),
coeffs, k));
}
/// <summary>
/// Create a pseudo-Boolean equal constraint.
/// </summary>
public BoolExpr MkPBEq(int[] coeffs, BoolExpr[] args, int k)
{
Debug.Assert(args != null);
Debug.Assert(coeffs != null);
Debug.Assert(args.Length == coeffs.Length);
CheckContextMatch<BoolExpr>(args);
return new BoolExpr(this, Native.Z3_mk_pbeq(nCtx, (uint) args.Length,
AST.ArrayToNative(args),
coeffs, k));
Debug.Assert(args != null);
Debug.Assert(coeffs != null);
Debug.Assert(args.Length == coeffs.Length);
CheckContextMatch<BoolExpr>(args);
return new BoolExpr(this, Native.Z3_mk_pbeq(nCtx, (uint)args.Length,
AST.ArrayToNative(args),
coeffs, k));
}
#endregion
@ -3040,8 +3077,8 @@ namespace Microsoft.Z3
/// <param name="size">the size of the bit-vector</param>
public BitVecNum MkBV(string v, uint size)
{
return (BitVecNum)MkNumeral(v, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecNum)MkNumeral(v, sort);
}
/// <summary>
@ -3051,8 +3088,8 @@ namespace Microsoft.Z3
/// <param name="size">the size of the bit-vector</param>
public BitVecNum MkBV(int v, uint size)
{
return (BitVecNum)MkNumeral(v, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecNum)MkNumeral(v, sort);
}
/// <summary>
@ -3062,8 +3099,8 @@ namespace Microsoft.Z3
/// <param name="size">the size of the bit-vector</param>
public BitVecNum MkBV(uint v, uint size)
{
return (BitVecNum)MkNumeral(v, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecNum)MkNumeral(v, sort);
}
/// <summary>
@ -3073,8 +3110,8 @@ namespace Microsoft.Z3
/// <param name="size">the size of the bit-vector</param>
public BitVecNum MkBV(long v, uint size)
{
return (BitVecNum)MkNumeral(v, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecNum)MkNumeral(v, sort);
}
/// <summary>
@ -3084,8 +3121,8 @@ namespace Microsoft.Z3
/// <param name="size">the size of the bit-vector</param>
public BitVecNum MkBV(ulong v, uint size)
{
return (BitVecNum)MkNumeral(v, MkBitVecSort(size));
using var sort = MkBitVecSort(size);
return (BitVecNum)MkNumeral(v, sort);
}
/// <summary>
@ -3332,7 +3369,7 @@ namespace Microsoft.Z3
uint cd = AST.ArrayLength(decls);
if (csn != cs || cdn != cd)
throw new Z3Exception("Argument size mismatch");
ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_string(nCtx, str,
using ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_string(nCtx, str,
AST.ArrayLength(sorts), Symbol.ArrayToNative(sortNames), AST.ArrayToNative(sorts),
AST.ArrayLength(decls), Symbol.ArrayToNative(declNames), AST.ArrayToNative(decls)));
return assertions.ToBoolExprArray();
@ -3351,7 +3388,7 @@ namespace Microsoft.Z3
uint cd = AST.ArrayLength(decls);
if (csn != cs || cdn != cd)
throw new Z3Exception("Argument size mismatch");
ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_file(nCtx, fileName,
using ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_file(nCtx, fileName,
AST.ArrayLength(sorts), Symbol.ArrayToNative(sortNames), AST.ArrayToNative(sorts),
AST.ArrayLength(decls), Symbol.ArrayToNative(declNames), AST.ArrayToNative(decls)));
return assertions.ToBoolExprArray();
@ -3836,8 +3873,8 @@ namespace Microsoft.Z3
/// <seealso cref="MkSolver(Symbol)"/>
public Solver MkSolver(string logic)
{
return MkSolver(MkSymbol(logic));
using var symbol = MkSymbol(logic);
return MkSolver(symbol);
}
/// <summary>
@ -4085,7 +4122,7 @@ namespace Microsoft.Z3
/// <param name="negative">indicates whether the result should be negative.</param>
public FPNum MkFPZero(FPSort s, bool negative)
{
return new FPNum(this, Native.Z3_mk_fpa_zero(nCtx, s.NativeObject, (byte)(negative ? 1 : 0)));
return new FPNum(this, Native.Z3_mk_fpa_zero(nCtx, s.NativeObject, (byte)(negative ? 1 : 0)));
}
/// <summary>
@ -4127,7 +4164,7 @@ namespace Microsoft.Z3
/// <param name="s">FloatingPoint sort.</param>
public FPNum MkFPNumeral(bool sgn, uint sig, int exp, FPSort s)
{
return new FPNum(this, Native.Z3_mk_fpa_numeral_int_uint(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject));
return new FPNum(this, Native.Z3_mk_fpa_numeral_int_uint(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject));
}
/// <summary>
@ -4139,7 +4176,7 @@ namespace Microsoft.Z3
/// <param name="s">FloatingPoint sort.</param>
public FPNum MkFPNumeral(bool sgn, Int64 exp, UInt64 sig, FPSort s)
{
return new FPNum(this, Native.Z3_mk_fpa_numeral_int64_uint64(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject));
return new FPNum(this, Native.Z3_mk_fpa_numeral_int64_uint64(nCtx, (byte)(sgn ? 1 : 0), exp, sig, s.NativeObject));
}
/// <summary>
@ -4825,12 +4862,12 @@ namespace Microsoft.Z3
/// <summary>
/// ASTVector DRQ
/// </summary>
public IDecRefQueue ASTVector_DRQ { get { return m_ASTVector_DRQ; } }
public IDecRefQueue ASTVector_DRQ { get { return m_ASTVector_DRQ; } }
/// <summary>
/// ApplyResult DRQ
/// </summary>
public IDecRefQueue ApplyResult_DRQ { get { return m_ApplyResult_DRQ; } }
public IDecRefQueue ApplyResult_DRQ { get { return m_ApplyResult_DRQ; } }
/// <summary>
/// FuncEntry DRQ
@ -4926,10 +4963,16 @@ namespace Microsoft.Z3
Fixedpoint_DRQ.Clear(this);
Optimize_DRQ.Clear(this);
if (m_boolSort != null) m_boolSort.Dispose();
if (m_intSort != null) m_intSort.Dispose();
if (m_realSort != null) m_realSort.Dispose();
if (m_stringSort != null) m_stringSort.Dispose();
if (m_charSort != null) m_charSort.Dispose();
m_boolSort = null;
m_intSort = null;
m_realSort = null;
m_stringSort = null;
m_charSort = null;
if (refCount == 0 && m_ctx != IntPtr.Zero)
{
m_n_err_handler = null;
@ -4937,7 +4980,7 @@ namespace Microsoft.Z3
m_ctx = IntPtr.Zero;
Native.Z3_del_context(ctx);
}
else
else
GC.ReRegisterForFinalize(this);
}
#endregion

View file

@ -79,7 +79,7 @@ namespace Microsoft.Z3
FuncDecl[][] res = new FuncDecl[n][];
for (uint i = 0; i < n; i++)
{
FuncDecl fd = new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, i));
using FuncDecl fd = new FuncDecl(Context, Native.Z3_get_datatype_sort_constructor(Context.nCtx, NativeObject, i));
uint ds = fd.DomainSize;
FuncDecl[] tmp = new FuncDecl[ds];
for (uint j = 0; j < ds; j++)

View file

@ -74,7 +74,8 @@ namespace Microsoft.Z3
/// <returns></returns>
public Expr Const(uint inx)
{
return Context.MkApp(ConstDecl(inx));
using var decl = ConstDecl(inx);
return Context.MkApp(decl);
}
/// <summary>

View file

@ -255,7 +255,7 @@ namespace Microsoft.Z3
get
{
ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_rules(Context.nCtx, NativeObject));
using ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_rules(Context.nCtx, NativeObject));
return av.ToBoolExprArray();
}
}
@ -268,7 +268,7 @@ namespace Microsoft.Z3
get
{
ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_assertions(Context.nCtx, NativeObject));
using ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_get_assertions(Context.nCtx, NativeObject));
return av.ToBoolExprArray();
}
}
@ -292,7 +292,7 @@ namespace Microsoft.Z3
/// </summary>
public BoolExpr[] ParseFile(string file)
{
ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_file(Context.nCtx, NativeObject, file));
using ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_file(Context.nCtx, NativeObject, file));
return av.ToBoolExprArray();
}
@ -301,7 +301,7 @@ namespace Microsoft.Z3
/// </summary>
public BoolExpr[] ParseString(string s)
{
ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_string(Context.nCtx, NativeObject, s));
using ASTVector av = new ASTVector(Context, Native.Z3_fixedpoint_from_string(Context.nCtx, NativeObject, s));
return av.ToBoolExprArray();
}

View file

@ -203,8 +203,8 @@ namespace Microsoft.Z3
/// <remarks>Essentially invokes the `simplify' tactic on the goal.</remarks>
public Goal Simplify(Params p = null)
{
Tactic t = Context.MkTactic("simplify");
ApplyResult res = t.Apply(this, p);
using Tactic t = Context.MkTactic("simplify");
using ApplyResult res = t.Apply(this, p);
if (res.NumSubgoals == 0)
throw new Z3Exception("No subgoals");

View file

@ -32,6 +32,8 @@
<Authors>Microsoft</Authors>
<Company>Microsoft</Company>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<!-- Code contract & signing properties -->

View file

@ -87,7 +87,8 @@ namespace Microsoft.Z3
if (Native.Z3_is_as_array(Context.nCtx, n) == 0)
throw new Z3Exception("Argument was not an array constant");
IntPtr fd = Native.Z3_get_as_array_func_decl(Context.nCtx, n);
return FuncInterp(new FuncDecl(Context, fd));
using var decl = new FuncDecl(Context, fd);
return FuncInterp(decl);
}
}
else
@ -241,7 +242,7 @@ namespace Microsoft.Z3
/// Evaluate expression to a double, assuming it is a numeral already.
/// </summary>
public double Double(Expr t) {
var r = Eval(t, true);
using var r = Eval(t, true);
return Native.Z3_get_numeral_double(Context.nCtx, r.NativeObject);
}
@ -283,7 +284,7 @@ namespace Microsoft.Z3
{
Debug.Assert(s != null);
ASTVector av = new ASTVector(Context, Native.Z3_model_get_sort_universe(Context.nCtx, NativeObject, s.NativeObject));
using ASTVector av = new ASTVector(Context, Native.Z3_model_get_sort_universe(Context.nCtx, NativeObject, s.NativeObject));
return av.ToExprArray();
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,104 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
NativeFuncInterp.cs
Abstract:
Z3 Managed API: Function Interpretations
Author:
Christoph Wintersteiger (cwinter) 2012-03-21
Notes:
--*/
using System.Diagnostics;
using System;
namespace Microsoft.Z3
{
using Z3_context = System.IntPtr;
using Z3_ast = System.IntPtr;
using Z3_app = System.IntPtr;
using Z3_sort = System.IntPtr;
using Z3_func_decl = System.IntPtr;
using Z3_model = System.IntPtr;
using Z3_func_interp = System.IntPtr;
using Z3_func_entry = System.IntPtr;
/// <summary>
/// A function interpretation is represented as a finite map and an 'else' value.
/// Each entry in the finite map represents the value of a function given a set of arguments.
/// </summary>
public class NativeFuncInterp
{
/// <summary>
/// Evaluation entry of a function
/// </summary>
public class Entry
{
/// <summary>
/// Argument values that define entry
/// </summary>
public Z3_ast[] Arguments;
/// <summary>
/// Result of applying function to Arguments in the interpretation
/// </summary>
public Z3_ast Result;
}
/// <summary>
/// Function that is interpreted
/// </summary>
public Z3_func_decl Declaration;
/// <summary>
/// Set of non-default entries defining the function graph
/// </summary>
public Entry[] Entries;
/// <summary>
/// Default cause of the function interpretation
/// </summary>
public Z3_ast Else;
#region Internal
internal NativeFuncInterp(NativeContext ctx, NativeModel mdl, Z3_func_decl decl, Z3_func_interp fi)
{
Debug.Assert(ctx != null);
Z3_context nCtx = ctx.nCtx;
Native.Z3_func_interp_inc_ref(nCtx, fi);
Declaration = decl;
Else = Native.Z3_func_interp_get_else(nCtx, fi);
uint numEntries = Native.Z3_func_interp_get_num_entries(nCtx, fi);
uint numArgs = Native.Z3_func_interp_get_arity(nCtx, fi);
Entries = new Entry[numEntries];
for (uint j = 0; j < numEntries; ++j)
{
var ntvEntry = Native.Z3_func_interp_get_entry(nCtx, fi, j);
Entries[j] = new Entry();
Native.Z3_func_entry_inc_ref(nCtx, ntvEntry);
Entries[j].Arguments = new Z3_ast[numArgs];
for (uint i = 0; i < numArgs; ++i)
Entries[j].Arguments[i] = Native.Z3_func_entry_get_arg(nCtx, ntvEntry, i);
Entries[j].Result = Native.Z3_func_entry_get_value(nCtx, ntvEntry);
Native.Z3_func_entry_dec_ref(nCtx, ntvEntry);
}
Native.Z3_func_interp_dec_ref(nCtx, fi);
}
#endregion
}
}

View file

@ -0,0 +1,383 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
NativeModel.cs
Abstract:
Z3 Managed API: Models
Native interface to model objects.
Author:
Christoph Wintersteiger (cwinter) 2012-03-21
Nikolaj Bjorner (nbjorner) 2022-03-01
Notes:
--*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
namespace Microsoft.Z3
{
using Z3_ast = System.IntPtr;
using Z3_func_decl = System.IntPtr;
using Z3_sort = System.IntPtr;
/// <summary>
/// A Model contains interpretations (assignments) of constants and functions.
/// </summary>
public class NativeModel : IDisposable
{
/// <summary>
/// Retrieves the interpretation (the assignment) of <paramref name="a"/> in the model.
/// </summary>
/// <param name="a">A Constant</param>
/// <returns>An expression if the constant has an interpretation in the model, null otherwise.</returns>
public Z3_ast ConstInterp(Z3_ast a) => ConstFuncInterp(Native.Z3_get_app_decl(ntvContext.nCtx, a));
/// <summary>
/// Retrieves the interpretation (the assignment) of <paramref name="f"/> in the model.
/// </summary>
/// <param name="f">A function declaration of zero arity</param>
/// <returns>An expression if the function has an interpretation in the model, null otherwise.</returns>
public Z3_ast ConstFuncInterp(Z3_func_decl f)
{
if (Native.Z3_get_arity(ntvContext.nCtx, f) != 0)
throw new Z3Exception("Non-zero arity functions have FunctionInterpretations as a model. Use FuncInterp.");
return Native.Z3_model_get_const_interp(ntvContext.nCtx, NativeObject, f);
}
/// <summary>
/// Retrieves the interpretation (the assignment) of a non-constant <paramref name="f"/> in the model.
/// </summary>
/// <param name="f">A function declaration of non-zero arity</param>
/// <returns>A FunctionInterpretation if the function has an interpretation in the model, null otherwise.</returns>
public NativeFuncInterp FuncInterp(Z3_func_decl f)
{
Z3_sort_kind sk = (Z3_sort_kind)Native.Z3_get_sort_kind(ntvContext.nCtx, Native.Z3_get_range(ntvContext.nCtx, f));
if (Native.Z3_get_arity(ntvContext.nCtx, f) == 0)
{
IntPtr n = Native.Z3_model_get_const_interp(ntvContext.nCtx, NativeObject, f);
if (sk == Z3_sort_kind.Z3_ARRAY_SORT)
{
if (n == IntPtr.Zero)
return null;
else
{
if (Native.Z3_is_as_array(ntvContext.nCtx, n) == 0)
throw new Z3Exception("Argument was not an array constant");
var fd = Native.Z3_get_as_array_func_decl(ntvContext.nCtx, n);
return new NativeFuncInterp(ntvContext, this, f, fd);
}
}
else
{
throw new Z3Exception("Constant functions do not have a function interpretation; use ConstInterp");
}
}
else
{
IntPtr n = Native.Z3_model_get_func_interp(ntvContext.nCtx, NativeObject, f);
if (n == IntPtr.Zero)
return null;
else
return new NativeFuncInterp(ntvContext, this, f, n);
}
}
/// <summary>
/// The number of constants that have an interpretation in the model.
/// </summary>
public uint NumConsts
{
get { return Native.Z3_model_get_num_consts(ntvContext.nCtx, NativeObject); }
}
/// <summary>
/// The function declarations of the constants in the model.
/// </summary>
public Z3_func_decl[] ConstDecls
{
get
{
uint n = NumConsts;
Z3_func_decl[] res = new Z3_func_decl[n];
for (uint i = 0; i < n; i++)
res[i] = Native.Z3_model_get_const_decl(ntvContext.nCtx, NativeObject, i);
return res;
}
}
/// <summary>
/// Enumerate constants in model.
/// </summary>
public IEnumerable<KeyValuePair<Z3_func_decl, Z3_ast>> Consts
{
get
{
uint nc = NumConsts;
for (uint i = 0; i < nc; ++i)
{
var f = Native.Z3_model_get_const_decl(ntvContext.nCtx, NativeObject, i);
IntPtr n = Native.Z3_model_get_const_interp(ntvContext.nCtx, NativeObject, f);
if (n == IntPtr.Zero) continue;
yield return new KeyValuePair<Z3_func_decl, Z3_ast>(f, n);
}
}
}
/// <summary>
/// The number of function interpretations in the model.
/// </summary>
public uint NumFuncs
{
get { return Native.Z3_model_get_num_funcs(ntvContext.nCtx, NativeObject); }
}
/// <summary>
/// The function declarations of the function interpretations in the model.
/// </summary>
public Z3_func_decl[] FuncDecls
{
get
{
uint n = NumFuncs;
Z3_func_decl[] res = new Z3_func_decl[n];
for (uint i = 0; i < n; i++)
res[i] = Native.Z3_model_get_func_decl(ntvContext.nCtx, NativeObject, i);
return res;
}
}
/// <summary>
/// All symbols that have an interpretation in the model.
/// </summary>
public Z3_func_decl[] Decls
{
get
{
uint nFuncs = NumFuncs;
uint nConsts = NumConsts;
uint n = nFuncs + nConsts;
Z3_func_decl[] res = new Z3_func_decl[n];
for (uint i = 0; i < nConsts; i++)
res[i] = Native.Z3_model_get_const_decl(ntvContext.nCtx, NativeObject, i);
for (uint i = 0; i < nFuncs; i++)
res[nConsts + i] = Native.Z3_model_get_func_decl(ntvContext.nCtx, NativeObject, i);
return res;
}
}
/// <summary>
/// A ModelEvaluationFailedException is thrown when an expression cannot be evaluated by the model.
/// </summary>
public class ModelEvaluationFailedException : Z3Exception
{
/// <summary>
/// An exception that is thrown when model evaluation fails.
/// </summary>
public ModelEvaluationFailedException() : base() { }
}
/// <summary>
/// Evaluates the expression <paramref name="t"/> in the current model.
/// </summary>
/// <remarks>
/// This function may fail if <paramref name="t"/> contains quantifiers,
/// is partial (MODEL_PARTIAL enabled), or if <paramref name="t"/> is not well-sorted.
/// In this case a <c>ModelEvaluationFailedException</c> is thrown.
/// </remarks>
/// <param name="t">An expression</param>
/// <param name="completion">
/// When this flag is enabled, a model value will be assigned to any constant
/// or function that does not have an interpretation in the model.
/// </param>
/// <returns>The evaluation of <paramref name="t"/> in the model.</returns>
public Z3_ast Eval(Z3_ast t, bool completion = false)
{
IntPtr v = IntPtr.Zero;
if (Native.Z3_model_eval(ntvContext.nCtx, NativeObject, t, (byte)(completion ? 1 : 0), ref v) == (byte)0)
throw new ModelEvaluationFailedException();
else
return v;
}
/// <summary>
/// Alias for <c>Eval</c>.
/// </summary>
public Z3_ast Evaluate(Z3_ast t, bool completion = false) => Eval(t, completion);
/// <summary>
/// Evaluate expression to a double, assuming it is a numeral already.
/// </summary>
public double Double(Z3_ast t)
{
var r = Eval(t, true);
return Native.Z3_get_numeral_double(ntvContext.nCtx, r);
}
/// <summary>
/// An array value obtained by untangling a model assignment.
/// </summary>
public class ArrayValue
{
/// <summary>
/// One dimensional array of indices where the array is updated
/// </summary>
public KeyValuePair<Z3_ast, Z3_ast>[] Updates;
/// <summary>
/// default Else case
/// </summary>
public Z3_ast Else;
/// <summary>
/// Domain for array
/// Updates.Keys
/// </summary>
public Z3_ast[] Domain;
/// <summary>
/// Range for array
/// Updates.Values
/// </summary>
public Z3_ast[] Range;
}
/// <summary>
/// Convert the interpretation of t into a sequence of array updates
/// </summary>
/// <param name="t"></param>
/// <param name="result"></param>
/// <returns>null if the argument does evaluate to a sequence of stores to an array</returns>
public bool TryGetArrayValue(Z3_ast t, out ArrayValue result)
{
var r = Eval(t, true);
// check that r is a sequence of store over a constant default array.
var updates = new Dictionary<Z3_ast, Z3_ast>();
result = null;
while (true)
{
if (ntvContext.GetAstKind(r) != Z3_ast_kind.Z3_APP_AST)
return false;
Z3_func_decl f = ntvContext.GetAppDecl(r);
var kind = ntvContext.GetDeclKind(f);
if (kind == Z3_decl_kind.Z3_OP_CONST_ARRAY)
{
result = new ArrayValue();
result.Else = ntvContext.GetAppArg(r, 0);
result.Updates = updates.ToArray();
result.Domain = updates.Keys.ToArray();
result.Range = updates.Values.ToArray();
return true;
}
else if (kind == Z3_decl_kind.Z3_OP_STORE)
{
Debug.Assert(ntvContext.GetNumArgs(r) == 3);
updates[ntvContext.GetAppArg(r, 1)] = ntvContext.GetAppArg(r, 2);
r = ntvContext.GetAppArg(r, 0);
}
else
{
return false;
}
}
}
/// <summary>
/// The number of uninterpreted sorts that the model has an interpretation for.
/// </summary>
public uint NumSorts { get { return Native.Z3_model_get_num_sorts(ntvContext.nCtx, NativeObject); } }
/// <summary>
/// The uninterpreted sorts that the model has an interpretation for.
/// </summary>
/// <remarks>
/// Z3 also provides an interpretation for uninterpreted sorts used in a formula.
/// The interpretation for a sort is a finite set of distinct values. We say this finite set is
/// the "universe" of the sort.
/// </remarks>
/// <seealso cref="NumSorts"/>
public Z3_sort[] Sorts
{
get
{
uint n = NumSorts;
Z3_sort[] res = new Z3_sort[n];
for (uint i = 0; i < n; i++)
res[i] = Native.Z3_model_get_sort(ntvContext.nCtx, NativeObject, i);
return res;
}
}
/// <summary>
/// Conversion of models to strings.
/// </summary>
/// <returns>A string representation of the model.</returns>
public override string ToString()
{
return Native.Z3_model_to_string(ntvContext.nCtx, NativeObject);
}
IntPtr NativeObject;
NativeContext ntvContext;
internal NativeModel(NativeContext ctx, IntPtr obj)
{
ntvContext = ctx;
NativeObject = obj;
Debug.Assert(ctx != null);
Native.Z3_model_inc_ref(ctx.nCtx, obj);
}
/// <summary>
/// Finalizer.
/// </summary>
~NativeModel()
{
Dispose();
}
/// <summary>
/// Disposes of the underlying native Z3 object.
/// </summary>
public void Dispose()
{
if (NativeObject != IntPtr.Zero)
{
Native.Z3_model_dec_ref(ntvContext.nCtx, NativeObject);
NativeObject = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
}
}

View file

@ -0,0 +1,451 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
NativeSolver.cs
Abstract:
Z3 Managed API: Native Solver
Author:
Christoph Wintersteiger (cwinter) 2012-03-22
Nikolaj Bjorner (nbjorner) 2022-03-01
Notes:
--*/
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Z3
{
using Z3_ast = System.IntPtr;
using Z3_context = System.IntPtr;
using Z3_func_decl = System.IntPtr;
using Z3_params = System.IntPtr;
using Z3_solver = System.IntPtr;
using Z3_sort = System.IntPtr;
using Z3_symbol = System.IntPtr;
/// <summary>
/// Solvers.
/// </summary>
public class NativeSolver : IDisposable
{
/// <summary>
/// A string that describes all available solver parameters.
/// </summary>
public string Help => Native.Z3_solver_get_help(nCtx, z3solver);
private void SetParam(Action<Z3_params> setter)
{
Z3_params p = Native.Z3_mk_params(nCtx);
Native.Z3_params_inc_ref(nCtx, p);
setter(p);
Native.Z3_solver_set_params(nCtx, z3solver, p);
Native.Z3_params_dec_ref(nCtx, p);
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, bool value)
{
SetParam((Z3_params p) => Native.Z3_params_set_bool(nCtx, p, Native.Z3_mk_string_symbol(nCtx, name), (byte)(value ? 1 : 0)));
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, uint value)
{
SetParam((Z3_params p) => Native.Z3_params_set_uint(nCtx, p, Native.Z3_mk_string_symbol(nCtx, name), value));
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, double value)
{
SetParam((Z3_params p) => Native.Z3_params_set_double(nCtx, p, Native.Z3_mk_string_symbol(nCtx, name), value));
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, string value)
{
var value_sym = Native.Z3_mk_string_symbol(nCtx, value);
SetParam((Z3_params p) => Native.Z3_params_set_symbol(nCtx, p, Native.Z3_mk_string_symbol(nCtx, name), value_sym));
}
#if false
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, Symbol value) { Parameters = Context.MkParams().Add(name, value); }
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, bool value) { Parameters = Context.MkParams().Add(name, value); }
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, uint value) { Parameters = Context.MkParams().Add(name, value); }
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, double value) { Parameters = Context.MkParams().Add(name, value); }
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, string value) { Parameters = Context.MkParams().Add(name, value); }
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); }
/// <summary>
/// Retrieves parameter descriptions for solver.
/// </summary>
public ParamDescrs ParameterDescriptions
{
get { return new ParamDescrs(Context, Native.Z3_solver_get_param_descrs(nCtx, NativeObject)); }
}
#endif
/// <summary>
/// The current number of backtracking points (scopes).
/// </summary>
/// <seealso cref="Pop"/>
/// <seealso cref="Push"/>
public uint NumScopes => Native.Z3_solver_get_num_scopes(nCtx, z3solver);
/// <summary>
/// Creates a backtracking point.
/// </summary>
/// <seealso cref="Pop"/>
public void Push() => Native.Z3_solver_push(nCtx, z3solver);
/// <summary>
/// Backtracks <paramref name="n"/> backtracking points.
/// </summary>
/// <remarks>Note that an exception is thrown if <paramref name="n"/> is not smaller than <c>NumScopes</c></remarks>
/// <seealso cref="Push"/>
public void Pop(uint n = 1) => Native.Z3_solver_pop(nCtx, z3solver, n);
/// <summary>
/// Resets the Solver.
/// </summary>
/// <remarks>This removes all assertions from the solver.</remarks>
public void Reset() => Native.Z3_solver_reset(nCtx, z3solver);
/// <summary>
/// Assert a constraint (or multiple) into the solver.
/// </summary>
public void Assert(params Z3_ast[] constraints)
{
Debug.Assert(constraints != null);
Debug.Assert(constraints.All(c => c != IntPtr.Zero));
foreach (Z3_ast a in constraints)
{
Native.Z3_solver_assert(nCtx, z3solver, a);
}
}
/// <summary>
/// Alias for Assert.
/// </summary>
public void Add(params Z3_ast[] constraints) => Assert(constraints);
/// <summary>
/// Alias for Assert.
/// </summary>
public void Add(IEnumerable<Z3_ast> constraints) => Assert(constraints.ToArray());
/// <summary>
/// Add constraints to ensure the function f can only be injective.
/// Example:
/// for function f : D1 x D2 -> R
/// assert axioms
/// forall (x1 : D1, x2 : D2) x1 = inv1(f(x1,x2))
/// forall (x1 : D1, x2 : D2) x2 = inv2(f(x1,x2))
/// </summary>
/// <param name="f"></param>
public void AssertInjective(Z3_func_decl f)
{
uint arity = Native.Z3_get_arity(nCtx, f);
Z3_sort range = Native.Z3_get_range(nCtx, f);
Z3_ast[] vars = new Z3_ast[arity];
Z3_sort[] sorts = new Z3_sort[arity];
Z3_symbol[] names = new Z3_symbol[arity];
for (uint i = 0; i < arity; ++i)
{
Z3_sort domain = Native.Z3_get_domain(nCtx, f, i);
vars[i] = ntvContext.MkBound(arity - i - 1, domain);
sorts[i] = domain;
names[i] = Native.Z3_mk_int_symbol(nCtx, (int)i);
}
Z3_ast app_f = IntPtr.Zero; // Context.MkApp(f, vars);
for (uint i = 0; i < arity; ++i)
{
Z3_sort domain = Native.Z3_get_domain(nCtx, f, i);
Z3_func_decl proj = ntvContext.MkFreshFuncDecl("inv", new Z3_sort[] { range }, domain);
Z3_ast body = ntvContext.MkEq(vars[i], ntvContext.MkApp(proj, app_f));
Z3_ast q = ntvContext.MkForall(names, sorts, body);
Assert(q);
}
}
/// <summary>
/// Assert multiple constraints into the solver, and track them (in the unsat) core
/// using the Boolean constants in ps.
/// </summary>
/// <remarks>
/// This API is an alternative to <see cref="Check(Z3_ast[])"/> with assumptions for extracting unsat cores.
/// Both APIs can be used in the same solver. The unsat core will contain a combination
/// of the Boolean variables provided using <see cref="AssertAndTrack(Z3_ast[],Z3_ast[])"/>
/// and the Boolean literals
/// provided using <see cref="Check(Z3_ast[])"/> with assumptions.
/// </remarks>
public void AssertAndTrack(Z3_ast[] constraints, Z3_ast[] ps)
{
Debug.Assert(constraints != null);
Debug.Assert(constraints.All(c => c != IntPtr.Zero));
Debug.Assert(ps.All(c => c != IntPtr.Zero));
if (constraints.Length != ps.Length)
throw new Z3Exception("Argument size mismatch");
for (int i = 0; i < constraints.Length; i++)
Native.Z3_solver_assert_and_track(nCtx, z3solver, constraints[i], ps[i]);
}
/// <summary>
/// Assert a constraint into the solver, and track it (in the unsat) core
/// using the Boolean constant p.
/// </summary>
/// <remarks>
/// This API is an alternative to <see cref="Check(Z3_ast[])"/> with assumptions for extracting unsat cores.
/// Both APIs can be used in the same solver. The unsat core will contain a combination
/// of the Boolean variables provided using <see cref="AssertAndTrack(Z3_ast[],Z3_ast[])"/>
/// and the Boolean literals
/// provided using <see cref="Check(Z3_ast[])"/> with assumptions.
/// </remarks>
public void AssertAndTrack(Z3_ast constraint, Z3_ast p)
{
Debug.Assert(constraint != null);
Debug.Assert(p != null);
Native.Z3_solver_assert_and_track(nCtx, z3solver, constraint, p);
}
/// <summary>
/// Load solver assertions from a file.
/// </summary>
public void FromFile(string file)
=> Native.Z3_solver_from_file(nCtx, z3solver, file);
/// <summary>
/// Load solver assertions from a string.
/// </summary>
public void FromString(string str)
=> Native.Z3_solver_from_string(nCtx, z3solver, str);
/// <summary>
/// The number of assertions in the solver.
/// </summary>
public uint NumAssertions
=> (uint)ntvContext.ToArray(Native.Z3_solver_get_assertions(nCtx, z3solver)).Length;
/// <summary>
/// The set of asserted formulas.
/// </summary>
public Z3_ast[] Assertions
=> ntvContext.ToArray(Native.Z3_solver_get_assertions(nCtx, z3solver));
/// <summary>
/// Currently inferred units.
/// </summary>
public Z3_ast[] Units
=> ntvContext.ToArray(Native.Z3_solver_get_units(nCtx, z3solver));
/// <summary>
/// Checks whether the assertions in the solver are consistent or not.
/// </summary>
/// <remarks>
/// <seealso cref="Model"/>
/// <seealso cref="UnsatCore"/>
/// <seealso cref="Proof"/>
/// </remarks>
public Status Check(params Z3_ast[] assumptions)
{
Z3_lbool r;
if (assumptions == null || assumptions.Length == 0)
r = (Z3_lbool)Native.Z3_solver_check(nCtx, z3solver);
else
r = (Z3_lbool)Native.Z3_solver_check_assumptions(nCtx, z3solver, (uint)assumptions.Length, assumptions);
return lboolToStatus(r);
}
/// <summary>
/// Checks whether the assertions in the solver are consistent or not.
/// </summary>
/// <remarks>
/// <seealso cref="Model"/>
/// <seealso cref="UnsatCore"/>
/// <seealso cref="Proof"/>
/// </remarks>
public Status Check(IEnumerable<Z3_ast> assumptions)
{
Z3_lbool r;
Z3_ast[] asms = assumptions.ToArray();
if (asms.Length == 0)
r = (Z3_lbool)Native.Z3_solver_check(nCtx, z3solver);
else
r = (Z3_lbool)Native.Z3_solver_check_assumptions(nCtx, z3solver, (uint)asms.Length, asms);
return lboolToStatus(r);
}
/// <summary>
/// The model of the last <c>Check(params Expr[] assumptions)</c>.
/// </summary>
/// <remarks>
/// The result is <c>null</c> if <c>Check(params Expr[] assumptions)</c> was not invoked before,
/// if its results was not <c>SATISFIABLE</c>, or if model production is not enabled.
/// </remarks>
public NativeModel Model
{
get
{
IntPtr x = Native.Z3_solver_get_model(nCtx, z3solver);
return x == IntPtr.Zero
? null
: new NativeModel(ntvContext, x);
}
}
/// <summary>
/// The proof of the last <c>Check(params Expr[] assumptions)</c>.
/// </summary>
/// <remarks>
/// The result is <c>null</c> if <c>Check(params Expr[] assumptions)</c> was not invoked before,
/// if its results was not <c>UNSATISFIABLE</c>, or if proof production is disabled.
/// </remarks>
public Z3_ast Proof
=> Native.Z3_solver_get_proof(nCtx, z3solver);
/// <summary>
/// The unsat core of the last <c>Check</c>.
/// </summary>
/// <remarks>
/// The unsat core is a subset of <c>Assertions</c>
/// The result is empty if <c>Check</c> was not invoked before,
/// if its results was not <c>UNSATISFIABLE</c>, or if core production is disabled.
/// </remarks>
public Z3_ast[] UnsatCore
=> ntvContext.ToArray(Native.Z3_solver_get_unsat_core(nCtx, z3solver));
/// <summary>
/// A brief justification of why the last call to <c>Check</c> returned <c>UNKNOWN</c>.
/// </summary>
public string ReasonUnknown
=> Native.Z3_solver_get_reason_unknown(nCtx, z3solver);
/// <summary>
/// Create a clone of the current solver with respect to <c>ctx</c>.
/// </summary>
public NativeSolver Translate(NativeContext ctx)
{
Debug.Assert(ctx != null);
return new NativeSolver(ctx, Native.Z3_solver_translate(nCtx, z3solver, ctx.nCtx));
}
/// <summary>
/// Import model converter from other solver.
/// </summary>
public void ImportModelConverter(NativeSolver src)
{
Debug.Assert(src != null);
Native.Z3_solver_import_model_converter(nCtx, src.z3solver, z3solver);
}
/// <summary>
/// Solver statistics.
/// </summary>
public Statistics.Entry[] Statistics
{
get
{
var stats = Native.Z3_solver_get_statistics(nCtx, z3solver);
return ntvContext.GetStatistics(stats);
}
}
/// <summary>
/// A string representation of the solver.
/// </summary>
public override string ToString()
{
return Native.Z3_solver_to_string(nCtx, z3solver);
}
#region Internal
readonly NativeContext ntvContext;
Z3_solver z3solver;
Z3_context nCtx => ntvContext.nCtx;
internal NativeSolver(NativeContext nativeCtx, Z3_solver z3solver)
{
Debug.Assert(nativeCtx != null);
Debug.Assert(z3solver != IntPtr.Zero);
this.ntvContext = nativeCtx;
this.z3solver = z3solver;
Native.Z3_solver_inc_ref(nCtx, z3solver);
}
/// <summary>
/// Finalizer.
/// </summary>
~NativeSolver()
{
Dispose();
}
/// <summary>
/// Disposes of the underlying native Z3 object.
/// </summary>
public void Dispose()
{
if (z3solver != IntPtr.Zero)
{
Native.Z3_solver_dec_ref(nCtx, z3solver);
z3solver = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
private Status lboolToStatus(Z3_lbool r)
{
switch (r)
{
case Z3_lbool.Z3_L_TRUE: return Status.SATISFIABLE;
case Z3_lbool.Z3_L_FALSE: return Status.UNSATISFIABLE;
default: return Status.UNKNOWN;
}
}
#endregion
}
}

View file

@ -212,7 +212,7 @@ namespace Microsoft.Z3
public Handle AssertSoft(BoolExpr constraint, uint weight, string group)
{
Context.CheckContextMatch(constraint);
Symbol s = Context.MkSymbol(group);
using Symbol s = Context.MkSymbol(group);
return new Handle(this, Native.Z3_optimize_assert_soft(Context.nCtx, NativeObject, constraint.NativeObject, weight.ToString(), s.NativeObject));
}
@ -289,7 +289,7 @@ namespace Microsoft.Z3
get
{
ASTVector core = new ASTVector(Context, Native.Z3_optimize_get_unsat_core(Context.nCtx, NativeObject));
using ASTVector core = new ASTVector(Context, Native.Z3_optimize_get_unsat_core(Context.nCtx, NativeObject));
return core.ToBoolExprArray();
}
}
@ -337,7 +337,7 @@ namespace Microsoft.Z3
/// </summary>
private Expr[] GetLowerAsVector(uint index)
{
ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_lower_as_vector(Context.nCtx, NativeObject, index));
using ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_lower_as_vector(Context.nCtx, NativeObject, index));
return v.ToExprArray();
}
@ -347,7 +347,7 @@ namespace Microsoft.Z3
/// </summary>
private Expr[] GetUpperAsVector(uint index)
{
ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_upper_as_vector(Context.nCtx, NativeObject, index));
using ASTVector v = new ASTVector(Context, Native.Z3_optimize_get_upper_as_vector(Context.nCtx, NativeObject, index));
return v.ToExprArray();
}
@ -396,7 +396,7 @@ namespace Microsoft.Z3
get
{
ASTVector assertions = new ASTVector(Context, Native.Z3_optimize_get_assertions(Context.nCtx, NativeObject));
using ASTVector assertions = new ASTVector(Context, Native.Z3_optimize_get_assertions(Context.nCtx, NativeObject));
return assertions.ToBoolExprArray();
}
}
@ -409,7 +409,7 @@ namespace Microsoft.Z3
get
{
ASTVector objectives = new ASTVector(Context, Native.Z3_optimize_get_objectives(Context.nCtx, NativeObject));
using ASTVector objectives = new ASTVector(Context, Native.Z3_optimize_get_objectives(Context.nCtx, NativeObject));
return objectives.ToExprArray();
}
}

View file

@ -62,7 +62,7 @@ namespace Microsoft.Z3
{
get
{
IntNum n = Numerator;
using IntNum n = Numerator;
return BigInteger.Parse(n.ToString());
}
}
@ -74,7 +74,7 @@ namespace Microsoft.Z3
{
get
{
IntNum n = Denominator;
using IntNum n = Denominator;
return BigInteger.Parse(n.ToString());
}
}

View file

@ -58,43 +58,92 @@ namespace Microsoft.Z3
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, bool value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(string name, bool value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, uint value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(string name, uint value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, double value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(string name, double value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, string value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(string name, string value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(string name, Symbol value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(string name, Symbol value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, bool value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(Symbol name, bool value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, uint value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(Symbol name, uint value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, double value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(Symbol name, double value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, string value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(Symbol name, string value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
/// <summary>
/// Sets parameter on the solver
/// </summary>
public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); }
public void Set(Symbol name, Symbol value)
{
using var parameters = Context.MkParams().Add(name, value);
Parameters = parameters;
}
@ -245,7 +294,7 @@ namespace Microsoft.Z3
{
get
{
ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject));
using ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject));
return assertions.Size;
}
}
@ -258,7 +307,7 @@ namespace Microsoft.Z3
get
{
ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject));
using ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_assertions(Context.nCtx, NativeObject));
return assertions.ToBoolExprArray();
}
}
@ -271,7 +320,7 @@ namespace Microsoft.Z3
get
{
ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_units(Context.nCtx, NativeObject));
using ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_units(Context.nCtx, NativeObject));
return assertions.ToBoolExprArray();
}
}
@ -330,9 +379,9 @@ namespace Microsoft.Z3
/// </remarks>
public Status Consequences(IEnumerable<BoolExpr> assumptions, IEnumerable<Expr> variables, out BoolExpr[] consequences)
{
ASTVector result = new ASTVector(Context);
ASTVector asms = new ASTVector(Context);
ASTVector vars = new ASTVector(Context);
using ASTVector result = new ASTVector(Context);
using ASTVector asms = new ASTVector(Context);
using ASTVector vars = new ASTVector(Context);
foreach (var asm in assumptions) asms.Push(asm);
foreach (var v in variables) vars.Push(v);
Z3_lbool r = (Z3_lbool)Native.Z3_solver_get_consequences(Context.nCtx, NativeObject, asms.NativeObject, vars.NativeObject, result.NativeObject);
@ -391,7 +440,7 @@ namespace Microsoft.Z3
get
{
ASTVector core = new ASTVector(Context, Native.Z3_solver_get_unsat_core(Context.nCtx, NativeObject));
using ASTVector core = new ASTVector(Context, Native.Z3_solver_get_unsat_core(Context.nCtx, NativeObject));
return core.ToBoolExprArray();
}
}
@ -424,14 +473,14 @@ namespace Microsoft.Z3
/// </summary>
public IEnumerable<BoolExpr[]> Cube()
{
ASTVector cv = new ASTVector(Context);
using ASTVector cv = new ASTVector(Context);
if (CubeVariables != null)
foreach (var b in CubeVariables) cv.Push(b);
while (true) {
var lvl = BacktrackLevel;
BacktrackLevel = uint.MaxValue;
ASTVector r = new ASTVector(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, cv.NativeObject, lvl));
using ASTVector r = new ASTVector(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, cv.NativeObject, lvl));
var v = r.ToBoolExprArray();
CubeVariables = cv.ToBoolExprArray();
if (v.Length == 1 && v[0].IsFalse) {

View file

@ -23,6 +23,9 @@ using System.Diagnostics;
namespace Microsoft.Z3
{
using Z3_context = System.IntPtr;
using Z3_stats = System.IntPtr;
/// <summary>
/// Objects of this class track statistical information about solvers.
/// </summary>
@ -123,25 +126,29 @@ namespace Microsoft.Z3
{
get
{
uint n = Size;
Entry[] res = new Entry[n];
for (uint i = 0; i < n; i++)
{
Entry e;
string k = Native.Z3_stats_get_key(Context.nCtx, NativeObject, i);
if (Native.Z3_stats_is_uint(Context.nCtx, NativeObject, i) != 0)
e = new Entry(k, Native.Z3_stats_get_uint_value(Context.nCtx, NativeObject, i));
else if (Native.Z3_stats_is_double(Context.nCtx, NativeObject, i) != 0)
e = new Entry(k, Native.Z3_stats_get_double_value(Context.nCtx, NativeObject, i));
else
throw new Z3Exception("Unknown data entry value");
res[i] = e;
}
return res;
return NativeEntries(Context.nCtx, NativeObject);
}
}
internal static Entry[] NativeEntries(Z3_context ctx, Z3_stats stats)
{
uint n = Native.Z3_stats_size(ctx, stats);
Entry[] res = new Entry[n];
for (uint i = 0; i < n; i++)
{
Entry e;
string k = Native.Z3_stats_get_key(ctx, stats, i);
if (Native.Z3_stats_is_uint(ctx, stats, i) != 0)
e = new Entry(k, Native.Z3_stats_get_uint_value(ctx, stats, i));
else if (Native.Z3_stats_is_double(ctx, stats, i) != 0)
e = new Entry(k, Native.Z3_stats_get_double_value(ctx, stats, i));
else
throw new Z3Exception("Unknown data entry value");
res[i] = e;
}
return res;
}
/// <summary>
/// The statistical counters.
/// </summary>

View file

@ -2106,6 +2106,26 @@ public class Context implements AutoCloseable {
return (BoolExpr) Expr.create(this, Native.mkSeqContains(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
}
/**
* Check if the string s1 is lexicographically strictly less than s2.
*/
public BoolExpr MkStringLt(SeqSort<CharSort> s1, SeqSort<CharSort> s2)
{
checkContextMatch(s1, s2);
return new BoolExpr(this, Native.mkStrLt(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
}
/**
* Check if the string s1 is lexicographically less or equal to s2.
*/
public BoolExpr MkStringLe(SeqSort<CharSort> s1, SeqSort<CharSort> s2)
{
checkContextMatch(s1, s2);
return new BoolExpr(this, Native.mkStrLe(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
}
/**
* Retrieve sequence of length one at index.
*/
@ -2180,6 +2200,14 @@ public class Context implements AutoCloseable {
return (ReExpr<R>) Expr.create(this, Native.mkReStar(nCtx(), re.getNativeObject()));
}
/**
* Create power regular expression.
*/
public <R extends Sort> ReExpr<R> mkPower(Expr<ReSort<R>> re, int n)
{
return (ReExpr<R>) Expr.create(this, Native.mkRePower(nCtx(), re.getNativeObject(), n));
}
/**
* Take the lower and upper-bounded Kleene star of a regular expression.
*/
@ -4038,6 +4066,37 @@ public class Context implements AutoCloseable {
return new BitVecExpr(this, Native.mkFpaToFpIntReal(nCtx(), rm.getNativeObject(), exp.getNativeObject(), sig.getNativeObject(), s.getNativeObject()));
}
/**
* Creates or a linear order.
* @param index The index of the order.
* @param sort The sort of the order.
*/
public <R extends Sort> FuncDecl<BoolSort> mkLinearOrder(R sort, int index) {
return (FuncDecl<BoolSort>) FuncDecl.create(
this,
Native.mkLinearOrder(
nCtx(),
sort.getNativeObject(),
index
)
);
}
/**
* Creates or a partial order.
* @param index The index of the order.
* @param sort The sort of the order.
*/
public <R extends Sort> FuncDecl<BoolSort> mkPartialOrder(R sort, int index) {
return (FuncDecl<BoolSort>) FuncDecl.create(
this,
Native.mkPartialOrder(
nCtx(),
sort.getNativeObject(),
index
)
);
}
/**
* Wraps an AST.

View file

@ -294,7 +294,8 @@ static struct custom_operations Z3_ast_plus_custom_ops = {
Z3_ast_compare_ext
};
MK_CTX_OF(ast, 16) // let's say 16 bytes per ast
// FUDGE
MK_CTX_OF(ast, 8) // let's say 16 bytes per ast
#define MK_PLUS_OBJ_NO_REF(X, USED) \
typedef struct { \
@ -410,25 +411,26 @@ MK_CTX_OF(ast, 16) // let's say 16 bytes per ast
\
MK_CTX_OF(X, USED)
MK_PLUS_OBJ_NO_REF(symbol, 32)
MK_PLUS_OBJ_NO_REF(constructor, 32)
MK_PLUS_OBJ_NO_REF(constructor_list, 32)
MK_PLUS_OBJ_NO_REF(rcf_num, 32)
MK_PLUS_OBJ(params, 128)
MK_PLUS_OBJ(param_descrs, 128)
MK_PLUS_OBJ(model, 512)
MK_PLUS_OBJ(func_interp, 128)
MK_PLUS_OBJ(func_entry, 128)
MK_PLUS_OBJ(goal, 128)
MK_PLUS_OBJ(tactic, 128)
MK_PLUS_OBJ(probe, 128)
MK_PLUS_OBJ(apply_result, 128)
MK_PLUS_OBJ(solver, 20 * 1000 * 1000) // pretend a solver is 20MB
MK_PLUS_OBJ(stats, 128)
MK_PLUS_OBJ(ast_map, 1024 * 2)
MK_PLUS_OBJ(ast_vector, 128)
MK_PLUS_OBJ(fixedpoint, 20 * 1000 * 1000)
MK_PLUS_OBJ(optimize, 20 * 1000 * 1000)
// FUDGE
MK_PLUS_OBJ_NO_REF(symbol, 16)
MK_PLUS_OBJ_NO_REF(constructor, 16)
MK_PLUS_OBJ_NO_REF(constructor_list, 16)
MK_PLUS_OBJ_NO_REF(rcf_num, 16)
MK_PLUS_OBJ(params, 64)
MK_PLUS_OBJ(param_descrs, 64)
MK_PLUS_OBJ(model, 64)
MK_PLUS_OBJ(func_interp, 32)
MK_PLUS_OBJ(func_entry, 32)
MK_PLUS_OBJ(goal, 64)
MK_PLUS_OBJ(tactic, 64)
MK_PLUS_OBJ(probe, 64)
MK_PLUS_OBJ(apply_result, 32)
MK_PLUS_OBJ(solver, 20 * 1000)
MK_PLUS_OBJ(stats, 32)
MK_PLUS_OBJ(ast_map, 32)
MK_PLUS_OBJ(ast_vector, 32)
MK_PLUS_OBJ(fixedpoint, 20 * 1000)
MK_PLUS_OBJ(optimize, 20 * 1000)
#ifdef __cplusplus
extern "C" {

View file

@ -42,8 +42,6 @@ add_custom_command(OUTPUT "${z3py_bindings_build_dest}/z3/z3core.py"
${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN}
"${PROJECT_SOURCE_DIR}/scripts/update_api.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
# FIXME: When update_api.py no longer uses ``mk_util`` drop this dependency
"${PROJECT_SOURCE_DIR}/scripts/mk_util.py"
COMMENT "Generating z3core.py"
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
)

View file

@ -5,3 +5,4 @@ recursive-include core *.cmake
recursive-include core/src *
recursive-include core/cmake *
recursive-include core/scripts *
include pyproject.toml

View file

@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools>=46.4.0", "wheel", "cmake"]
build-backend = "setuptools.build_meta"

View file

@ -154,16 +154,10 @@ def _copy_bins():
_clean_bins()
python_dir = None
if RELEASE_DIR is not None:
python_dir = os.path.join(RELEASE_DIR, 'bin', 'python')
elif SRC_DIR == SRC_DIR_LOCAL:
python_dir = os.path.join(SRC_DIR, 'src', 'api', 'python')
if python_dir is not None:
py_z3_build_dir = os.path.join(BUILD_DIR, 'python', 'z3')
root_z3_dir = os.path.join(ROOT_DIR, 'z3')
shutil.copy(os.path.join(py_z3_build_dir, 'z3core.py'), root_z3_dir)
shutil.copy(os.path.join(py_z3_build_dir, 'z3consts.py'), root_z3_dir)
py_z3_build_dir = os.path.join(BUILD_DIR, 'python', 'z3')
root_z3_dir = os.path.join(ROOT_DIR, 'z3')
shutil.copy(os.path.join(py_z3_build_dir, 'z3core.py'), root_z3_dir)
shutil.copy(os.path.join(py_z3_build_dir, 'z3consts.py'), root_z3_dir)
# STEP 2: Copy the shared library, the executable and the headers
@ -184,6 +178,20 @@ def _copy_bins():
continue
shutil.copy(os.path.join(header_dir, fname), os.path.join(HEADERS_DIR, fname))
# This hack lets z3 installed libs link on M1 macs; it is a hack, not a proper fix
# @TODO: Linked issue: https://github.com/Z3Prover/z3/issues/5926
major_minor = '.'.join(_z3_version().split('.')[:2])
link_name = None
if BUILD_PLATFORM in ('win32', 'cygwin', 'win'):
pass # TODO: When windows VMs work on M1, fill this in
elif BUILD_PLATFORM in ('darwin', 'osx'):
split = LIBRARY_FILE.split('.')
link_name = split[0] + '.' + major_minor + '.' + split[1]
else:
link_name = LIBRARY_FILE + '.' + major_minor
if link_name:
os.symlink(LIBRARY_FILE, os.path.join(LIBS_DIR, link_name), True)
def _copy_sources():
"""
Prepare for a source distribution by assembling a minimal set of source files needed
@ -281,6 +289,8 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv:
osver = '.'.join(osver.split('.')[:2])
if arch == 'x64':
plat_name ='macosx_%s_x86_64' % osver.replace('.', '_')
elif arch == 'arm64':
plat_name ='macosx_%s_arm64' % osver.replace('.', '_')
else:
raise Exception(f"idk how os {distos} {osver} works. what goes here?")
else:
@ -291,7 +301,6 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv:
sys.argv.insert(idx + 1, plat_name)
sys.argv.insert(idx + 2, '--universal') # supports py2+py3. if --plat-name is not specified this will also mean that the package can be installed on any machine regardless of architecture, so watch out!
setup(
name='z3-solver',
version=_z3_version(),

View file

@ -12,8 +12,6 @@ Z3 is used in many applications such as: software/hardware verification and test
constraint solving, analysis of hybrid systems, security, biology (in silico analysis),
and geometrical problems.
Several online tutorials for Z3Py are available at:
http://rise4fun.com/Z3Py/tutorial/guide
Please send feedback, comments and/or corrections on the Issue tracker for
https://github.com/Z3prover/z3.git. Your comments are very valuable.
@ -103,9 +101,6 @@ def get_version():
def get_full_version():
return Z3_get_full_version()
# We use _z3_assert instead of the assert command because we want to
# produce nice error messages in Z3Py at rise4fun.com
def _z3_assert(cond, msg):
if not cond:
@ -1771,7 +1766,7 @@ def Xor(a, b, ctx=None):
>>> Xor(p, q)
Xor(p, q)
>>> simplify(Xor(p, q))
Not(p) == q
Not(p == q)
"""
ctx = _get_ctx(_ctx_from_ast_arg_list([a, b], ctx))
s = BoolSort(ctx)
@ -2015,8 +2010,7 @@ class QuantifierRef(BoolRef):
"""
if z3_debug():
_z3_assert(self.is_lambda(), "quantifier should be a lambda expression")
arg = self.sort().domain().cast(arg)
return _to_expr_ref(Z3_mk_select(self.ctx_ref(), self.as_ast(), arg.as_ast()), self.ctx)
return _array_select(self, arg)
def weight(self):
"""Return the weight annotation of `self`.
@ -2285,6 +2279,9 @@ class ArithSortRef(SortRef):
"""
return self.kind() == Z3_INT_SORT
def is_bool(self):
return False
def subsort(self, other):
"""Return `True` if `self` is a subsort of `other`."""
return self.is_int() and is_arith_sort(other) and other.is_real()
@ -4496,6 +4493,11 @@ class ArraySortRef(SortRef):
"""
return _to_sort_ref(Z3_get_array_sort_domain(self.ctx_ref(), self.ast), self.ctx)
def domain_n(self, i):
"""Return the domain of the array sort `self`.
"""
return _to_sort_ref(Z3_get_array_sort_domain_n(self.ctx_ref(), self.ast, i), self.ctx)
def range(self):
"""Return the range of the array sort `self`.
@ -4527,6 +4529,10 @@ class ArrayRef(ExprRef):
"""
return self.sort().domain()
def domain_n(self, i):
"""Shorthand for self.sort().domain_n(i)`."""
return self.sort().domain_n(i)
def range(self):
"""Shorthand for `self.sort().range()`.
@ -4546,13 +4552,21 @@ class ArrayRef(ExprRef):
>>> a[i].sexpr()
'(select a i)'
"""
arg = self.domain().cast(arg)
return _to_expr_ref(Z3_mk_select(self.ctx_ref(), self.as_ast(), arg.as_ast()), self.ctx)
return _array_select(self, arg)
def default(self):
return _to_expr_ref(Z3_mk_array_default(self.ctx_ref(), self.as_ast()), self.ctx)
def _array_select(ar, arg):
if isinstance(arg, tuple):
args = [ar.domain_n(i).cast(arg[i]) for i in range(len(arg))]
_args, sz = _to_ast_array(args)
return _to_expr_ref(Z3_mk_select_n(ar.ctx_ref(), ar.as_ast(), sz, _args), ar.ctx)
arg = ar.domain().cast(arg)
return _to_expr_ref(Z3_mk_select(ar.ctx_ref(), ar.as_ast(), arg.as_ast()), ar.ctx)
def is_array_sort(a):
return Z3_get_sort_kind(a.ctx.ref(), Z3_get_sort(a.ctx.ref(), a.ast)) == Z3_ARRAY_SORT
@ -4679,7 +4693,7 @@ def ArraySort(*sig):
return ArraySortRef(Z3_mk_array_sort_n(ctx.ref(), arity, dom, r.ast), ctx)
def Array(name, dom, rng):
def Array(name, *sorts):
"""Return an array constant named `name` with the given domain and range sorts.
>>> a = Array('a', IntSort(), IntSort())
@ -4688,12 +4702,12 @@ def Array(name, dom, rng):
>>> a[0]
a[0]
"""
s = ArraySort(dom, rng)
s = ArraySort(sorts)
ctx = s.ctx
return ArrayRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), s.ast), ctx)
def Update(a, i, v):
def Update(a, *args):
"""Return a Z3 store array expression.
>>> a = Array('a', IntSort(), IntSort())
@ -4709,10 +4723,20 @@ def Update(a, i, v):
"""
if z3_debug():
_z3_assert(is_array_sort(a), "First argument must be a Z3 array expression")
i = a.sort().domain().cast(i)
v = a.sort().range().cast(v)
args = _get_args(args)
ctx = a.ctx
return _to_expr_ref(Z3_mk_store(ctx.ref(), a.as_ast(), i.as_ast(), v.as_ast()), ctx)
if len(args) <= 1:
raise Z3Exception("array update requires index and value arguments")
if len(args) == 2:
i = args[0]
v = args[1]
i = a.sort().domain().cast(i)
v = a.sort().range().cast(v)
return _to_expr_ref(Z3_mk_store(ctx.ref(), a.as_ast(), i.as_ast(), v.as_ast()), ctx)
v = a.sort().range().cast(args[-1])
idxs = [a.sort().domain_n(i).cast(args[i]) for i in range(len(args)-1)]
_args, sz = _to_ast_array(idxs)
return _to_expr_ref(Z3_mk_store_n(ctx.ref(), a.as_ast(), sz, _args, v.as_ast()), ctx)
def Default(a):
@ -4726,7 +4750,7 @@ def Default(a):
return a.default()
def Store(a, i, v):
def Store(a, *args):
"""Return a Z3 store array expression.
>>> a = Array('a', IntSort(), IntSort())
@ -4740,10 +4764,10 @@ def Store(a, i, v):
>>> prove(Implies(i != j, s[j] == a[j]))
proved
"""
return Update(a, i, v)
return Update(a, args)
def Select(a, i):
def Select(a, *args):
"""Return a Z3 select array expression.
>>> a = Array('a', IntSort(), IntSort())
@ -4753,9 +4777,10 @@ def Select(a, i):
>>> eq(Select(a, i), a[i])
True
"""
args = _get_args(args)
if z3_debug():
_z3_assert(is_array_sort(a), "First argument must be a Z3 array expression")
return a[i]
return a[args]
def Map(f, *args):
@ -6569,6 +6594,19 @@ class ModelRef(Z3PPObject):
"""Update the interpretation of a constant"""
if is_expr(x):
x = x.decl()
if is_func_decl(x) and x.arity() != 0 and isinstance(value, FuncInterp):
fi1 = value.f
fi2 = Z3_add_func_interp(x.ctx_ref(), self.model, x.ast, value.else_value().ast);
fi2 = FuncInterp(fi2, x.ctx)
for i in range(value.num_entries()):
e = value.entry(i)
n = Z3_func_entry_get_num_args(x.ctx_ref(), e.entry)
v = AstVector()
for j in range(n):
v.push(entry.arg_value(j))
val = Z3_func_entry_get_value(x.ctx_ref(), e.entry)
Z3_func_interp_add_entry(x.ctx_ref(), fi2.f, v.vector, val)
return
if not is_func_decl(x) or x.arity() != 0:
raise Z3Exception("Expecting 0-ary function or constant expression")
value = _py2expr(value)
@ -8856,7 +8894,7 @@ def _pb_args_coeffs(args, default_ctx=None):
for i in range(len(coeffs)):
_z3_check_cint_overflow(coeffs[i], "coefficient")
_coeffs[i] = coeffs[i]
return ctx, sz, _args, _coeffs
return ctx, sz, _args, _coeffs, args
def PbLe(args, k):
@ -8866,7 +8904,7 @@ def PbLe(args, k):
>>> f = PbLe(((a,1),(b,3),(c,2)), 3)
"""
_z3_check_cint_overflow(k, "k")
ctx, sz, _args, _coeffs = _pb_args_coeffs(args)
ctx, sz, _args, _coeffs, args = _pb_args_coeffs(args)
return BoolRef(Z3_mk_pble(ctx.ref(), sz, _args, _coeffs, k), ctx)
@ -8877,7 +8915,7 @@ def PbGe(args, k):
>>> f = PbGe(((a,1),(b,3),(c,2)), 3)
"""
_z3_check_cint_overflow(k, "k")
ctx, sz, _args, _coeffs = _pb_args_coeffs(args)
ctx, sz, _args, _coeffs, args = _pb_args_coeffs(args)
return BoolRef(Z3_mk_pbge(ctx.ref(), sz, _args, _coeffs, k), ctx)
@ -8888,7 +8926,7 @@ def PbEq(args, k, ctx=None):
>>> f = PbEq(((a,1),(b,3),(c,2)), 3)
"""
_z3_check_cint_overflow(k, "k")
ctx, sz, _args, _coeffs = _pb_args_coeffs(args)
ctx, sz, _args, _coeffs, args = _pb_args_coeffs(args)
return BoolRef(Z3_mk_pbeq(ctx.ref(), sz, _args, _coeffs, k), ctx)
@ -8982,7 +9020,7 @@ def prove(claim, show=False, **keywords):
def _solve_html(*args, **keywords):
"""Version of function `solve` used in RiSE4Fun."""
"""Version of function `solve` that renders HTML output."""
show = keywords.pop("show", False)
s = Solver()
s.set(**keywords)
@ -9006,7 +9044,7 @@ def _solve_html(*args, **keywords):
def _solve_using_html(s, *args, **keywords):
"""Version of function `solve_using` used in RiSE4Fun."""
"""Version of function `solve_using` that renders HTML."""
show = keywords.pop("show", False)
if z3_debug():
_z3_assert(isinstance(s, Solver), "Solver object expected")
@ -9031,7 +9069,7 @@ def _solve_using_html(s, *args, **keywords):
def _prove_html(claim, show=False, **keywords):
"""Version of function `prove` used in RiSE4Fun."""
"""Version of function `prove` that renders HTML."""
if z3_debug():
_z3_assert(is_bool(claim), "Z3 Boolean expression expected")
s = Solver()
@ -11215,12 +11253,16 @@ def ensure_prop_closures():
_prop_closures = PropClosures()
def user_prop_push(ctx):
_prop_closures.get(ctx).push()
def user_prop_push(ctx, cb):
prop = _prop_closures.get(ctx)
prop.cb = cb
prop.push()
def user_prop_pop(ctx, num_scopes):
_prop_closures.get(ctx).pop(num_scopes)
def user_prop_pop(ctx, cb, num_scopes):
prop = _prop_closures.get(ctx)
prop.cb = cb
pop(num_scopes)
def user_prop_fresh(id, ctx):
@ -11230,31 +11272,38 @@ def user_prop_fresh(id, ctx):
_prop_closures.set(new_prop.id, new_prop)
return ctypes.c_void_p(new_prop.id)
def to_Ast(ptr,):
ast = Ast(ptr)
super(ctypes.c_void_p, ast).__init__(ptr)
return ast
def user_prop_fixed(ctx, cb, id, value):
prop = _prop_closures.get(ctx)
prop.cb = cb
prop.fixed(id, _to_expr_ref(ctypes.c_void_p(value), prop.ctx()))
id = _to_expr_ref(to_Ast(id), prop.ctx())
value = _to_expr_ref(to_Ast(value), prop.ctx())
prop.fixed(id, value)
prop.cb = None
def user_prop_final(ctx, cb):
prop = _prop_closures.get(ctx)
prop.cb = cb
prop.final()
prop.cb = None
def user_prop_eq(ctx, cb, x, y):
prop = _prop_closures.get(ctx)
prop.cb = cb
x = _to_expr_ref(to_Ast(x), prop.ctx())
y = _to_expr_ref(to_Ast(y), prop.ctx())
prop.eq(x, y)
prop.cb = None
def user_prop_diseq(ctx, cb, x, y):
prop = _prop_closures.get(ctx)
prop.cb = cb
x = _to_expr_ref(to_Ast(x), prop.ctx())
y = _to_expr_ref(to_Ast(y), prop.ctx())
prop.diseq(x, y)
prop.cb = None
@ -11352,24 +11401,18 @@ class UserPropagateBase:
def add(self, e):
assert self.solver
assert not self._ctx
return Z3_solver_propagate_register(self.ctx_ref(), self.solver.solver, e.ast)
Z3_solver_propagate_register(self.ctx_ref(), self.solver.solver, e.ast)
#
# Propagation can only be invoked as during a fixed or final callback.
#
def propagate(self, e, ids, eqs=[]):
num_fixed = len(ids)
_ids = (ctypes.c_uint * num_fixed)()
for i in range(num_fixed):
_ids[i] = ids[i]
_ids, num_fixed = _to_ast_array(ids)
num_eqs = len(eqs)
_lhs = (ctypes.c_uint * num_eqs)()
_rhs = (ctypes.c_uint * num_eqs)()
for i in range(num_eqs):
_lhs[i] = eqs[i][0]
_rhs[i] = eqs[i][1]
_lhs, _num_lhs = _to_ast_array([x for x, y in eqs])
_rhs, _num_rhs = _to_ast_array([y for x, y in eqs])
Z3_solver_propagate_consequence(e.ctx.ref(), ctypes.c_void_p(
self.cb), num_fixed, _ids, num_eqs, _lhs, _rhs, e.ast)
def conflict(self, ids):
self.propagate(BoolVal(False, self.ctx()), ids, eqs=[])
def conflict(self, deps):
self.propagate(BoolVal(False, self.ctx()), deps, eqs=[])

View file

@ -996,6 +996,8 @@ typedef enum
information is exposed. Tools may use the string representation of the
function declaration to obtain more information.
- Z3_OP_RECURSIVE: function declared as recursive
- Z3_OP_UNINTERPRETED: kind used for uninterpreted symbols.
*/
typedef enum {
@ -1220,13 +1222,17 @@ typedef enum {
Z3_OP_RE_CONCAT,
Z3_OP_RE_UNION,
Z3_OP_RE_RANGE,
Z3_OP_RE_DIFF,
Z3_OP_RE_INTERSECT,
Z3_OP_RE_LOOP,
Z3_OP_RE_POWER,
Z3_OP_RE_INTERSECT,
Z3_OP_RE_DIFF,
Z3_OP_RE_COMPLEMENT,
Z3_OP_RE_EMPTY_SET,
Z3_OP_RE_FULL_SET,
Z3_OP_RE_COMPLEMENT,
Z3_OP_RE_FULL_CHAR_SET,
Z3_OP_RE_OF_PRED,
Z3_OP_RE_REVERSE,
Z3_OP_RE_DERIVATIVE,
// char
Z3_OP_CHAR_CONST,
@ -1316,6 +1322,7 @@ typedef enum {
Z3_OP_FPA_BV2RM,
Z3_OP_INTERNAL,
Z3_OP_RECURSIVE,
Z3_OP_UNINTERPRETED
} Z3_decl_kind;
@ -1430,13 +1437,14 @@ Z3_DECLARE_CLOSURE(Z3_error_handler, void, (Z3_context c, Z3_error_code e));
/**
\brief callback functions for user propagator.
*/
Z3_DECLARE_CLOSURE(Z3_push_eh, void, (void* ctx));
Z3_DECLARE_CLOSURE(Z3_pop_eh, void, (void* ctx, unsigned num_scopes));
Z3_DECLARE_CLOSURE(Z3_push_eh, void, (void* ctx, Z3_solver_callback cb));
Z3_DECLARE_CLOSURE(Z3_pop_eh, void, (void* ctx, Z3_solver_callback cb, unsigned num_scopes));
Z3_DECLARE_CLOSURE(Z3_fresh_eh, void*, (void* ctx, Z3_context new_context));
Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, unsigned id, Z3_ast value));
Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, unsigned x, unsigned y));
Z3_DECLARE_CLOSURE(Z3_fixed_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t, Z3_ast value));
Z3_DECLARE_CLOSURE(Z3_eq_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast s, Z3_ast t));
Z3_DECLARE_CLOSURE(Z3_final_eh, void, (void* ctx, Z3_solver_callback cb));
Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast e, unsigned id));
Z3_DECLARE_CLOSURE(Z3_created_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast t));
Z3_DECLARE_CLOSURE(Z3_decide_eh, void, (void* ctx, Z3_solver_callback cb, Z3_ast*, unsigned*, Z3_lbool*));
/**
@ -3817,6 +3825,13 @@ extern "C" {
*/
Z3_ast Z3_API Z3_mk_re_loop(Z3_context c, Z3_ast r, unsigned lo, unsigned hi);
/**
\brief Create a power regular expression.
def_API('Z3_mk_re_power', AST, (_in(CONTEXT), _in(AST), _in(UINT)))
*/
Z3_ast Z3_API Z3_mk_re_power(Z3_context c, Z3_ast, unsigned n);
/**
\brief Create the intersection of the regular languages.
@ -4358,11 +4373,27 @@ extern "C" {
\sa Z3_mk_array_sort
\sa Z3_get_sort_kind
\sa Z3_get_array_sort_domain_n
def_API('Z3_get_array_sort_domain', SORT, (_in(CONTEXT), _in(SORT)))
*/
Z3_sort Z3_API Z3_get_array_sort_domain(Z3_context c, Z3_sort t);
/**
\brief Return the i'th domain sort of an n-dimensional array.
\pre Z3_get_sort_kind(c, t) == Z3_ARRAY_SORT
\sa Z3_mk_array_sort
\sa Z3_get_sort_kind
\sa Z3_get_array_sort_domain
def_API('Z3_get_array_sort_domain_n', SORT, (_in(CONTEXT), _in(SORT), _in(UINT)))
*/
Z3_sort Z3_API Z3_get_array_sort_domain_n(Z3_context c, Z3_sort t, unsigned idx);
/**
\brief Return the range of the given array sort.
@ -6672,6 +6703,13 @@ extern "C" {
/**
\brief register a user-properator with the solver.
\param c - context.
\param s - solver object.
\param user_context - a context used to maintain state for callbacks.
\param push_eh - a callback invoked when scopes are pushed
\param pop_eh - a callback invoked when scopes are poped
\param fresh_eh - a solver may spawn new solvers internally. This callback is used to produce a fresh user_context to be associated with fresh solvers.
*/
void Z3_API Z3_solver_propagate_init(
@ -6694,11 +6732,15 @@ extern "C" {
/**
\brief register a callback on final check.
This provides freedom to the propagator to delay actions or implement a branch-and bound solver.
The final check is invoked when all decision variables have been assigned by the solver.
The final_eh callback takes as argument the original user_context that was used
when calling \c Z3_solver_propagate_init, and it takes a callback context for propagations.
If may use the callback context to invoke the \c Z3_solver_propagate_consequence function.
If the callback context gets used, the solver continues.
The \c final_eh callback takes as argument the original user_context that was used
when calling \c Z3_solver_propagate_init, and it takes a callback context with the
opaque type \c Z3_solver_callback.
The callback context is passed as argument to invoke the \c Z3_solver_propagate_consequence function.
The callback context can only be accessed (for propagation and for dynamically registering expressions) within a callback.
If the callback context gets used for propagation or conflicts, those propagations take effect and
may trigger new decision variables to be set.
*/
void Z3_API Z3_solver_propagate_final(Z3_context c, Z3_solver s, Z3_final_eh final_eh);
@ -6717,6 +6759,14 @@ extern "C" {
* The registered function appears at the top level and is created using \ref Z3_propagate_solver_declare.
*/
void Z3_API Z3_solver_propagate_created(Z3_context c, Z3_solver s, Z3_created_eh created_eh);
/**
* \brief register a callback when a the solver decides to split on a registered expression
* The callback may set passed expression to another registered expression which will be selected instead.
* In case the expression is a bitvector the bit to split on is determined by the bit argument and the
* truth-value to try first is given by is_pos
*/
void Z3_API Z3_solver_propagate_decide(Z3_context c, Z3_solver s, Z3_decide_eh decide_eh);
/**
Create uninterpreted function declaration for the user propagator.
@ -6734,10 +6784,10 @@ extern "C" {
\brief register an expression to propagate on with the solver.
Only expressions of type Bool and type Bit-Vector can be registered for propagation.
def_API('Z3_solver_propagate_register', UINT, (_in(CONTEXT), _in(SOLVER), _in(AST)))
def_API('Z3_solver_propagate_register', VOID, (_in(CONTEXT), _in(SOLVER), _in(AST)))
*/
unsigned Z3_API Z3_solver_propagate_register(Z3_context c, Z3_solver s, Z3_ast e);
void Z3_API Z3_solver_propagate_register(Z3_context c, Z3_solver s, Z3_ast e);
/**
\brief register an expression to propagate on with the solver.
@ -6745,9 +6795,9 @@ extern "C" {
Unlike \ref Z3_solver_propagate_register, this function takes a solver callback context
as argument. It can be invoked during a callback to register new expressions.
def_API('Z3_solver_propagate_register_cb', UINT, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(AST)))
def_API('Z3_solver_propagate_register_cb', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(AST)))
*/
unsigned Z3_API Z3_solver_propagate_register_cb(Z3_context c, Z3_solver_callback cb, Z3_ast e);
void Z3_API Z3_solver_propagate_register_cb(Z3_context c, Z3_solver_callback cb, Z3_ast e);
/**
\brief propagate a consequence based on fixed values.
@ -6755,10 +6805,10 @@ extern "C" {
The callback adds a propagation consequence based on the fixed values of the
\c ids.
def_API('Z3_solver_propagate_consequence', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, UINT), _in(UINT), _in_array(4, UINT), _in_array(4, UINT), _in(AST)))
def_API('Z3_solver_propagate_consequence', VOID, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, AST), _in(UINT), _in_array(4, AST), _in_array(4, AST), _in(AST)))
*/
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback, unsigned num_fixed, unsigned const* fixed_ids, unsigned num_eqs, unsigned const* eq_lhs, unsigned const* eq_rhs, Z3_ast conseq);
void Z3_API Z3_solver_propagate_consequence(Z3_context c, Z3_solver_callback, unsigned num_fixed, Z3_ast const* fixed, unsigned num_eqs, Z3_ast const* eq_lhs, Z3_ast const* eq_rhs, Z3_ast conseq);
/**
\brief Check whether the assertions in a given solver are consistent or not.

View file

@ -82,7 +82,7 @@ extern "C" {
\param c - context
\param o - optimization context
\param a - formula
\param weight - a positive weight, penalty for violating soft constraint
\param weight - a penalty for violating soft constraint. Negative weights convert into rewards.
\param id - optional identifier to group soft constraints
\sa Z3_optimize_assert

View file

@ -27,6 +27,7 @@ Revision History:
#include "ast/ast_util.h"
#include "ast/ast_smt2_pp.h"
#include "ast/array_decl_plugin.h"
#include "ast/arith_decl_plugin.h"
#include "ast/ast_translation.h"
#include "util/z3_version.h"
@ -233,8 +234,7 @@ std::ostream& operator<<(std::ostream& out, sort_size const & ss) {
// -----------------------------------
std::ostream & operator<<(std::ostream & out, sort_info const & info) {
operator<<(out, static_cast<decl_info const&>(info));
out << " :size " << info.get_num_elements();
return out;
return out << " :size " << info.get_num_elements();
}
// -----------------------------------
@ -1758,13 +1758,13 @@ ast * ast_manager::register_node_core(ast * n) {
switch (n->get_kind()) {
case AST_SORT:
if (to_sort(n)->m_info != nullptr) {
to_sort(n)->m_info = alloc(sort_info, *(to_sort(n)->get_info()));
to_sort(n)->m_info = alloc(sort_info, std::move(*(to_sort(n)->get_info())));
to_sort(n)->m_info->init_eh(*this);
}
break;
case AST_FUNC_DECL:
if (to_func_decl(n)->m_info != nullptr) {
to_func_decl(n)->m_info = alloc(func_decl_info, *(to_func_decl(n)->get_info()));
to_func_decl(n)->m_info = alloc(func_decl_info, std::move(*(to_func_decl(n)->get_info())));
to_func_decl(n)->m_info->init_eh(*this);
}
inc_array_ref(to_func_decl(n)->get_arity(), to_func_decl(n)->get_domain());
@ -1992,7 +1992,7 @@ sort * ast_manager::substitute(sort* s, unsigned n, sort * const * src, sort * c
return s;
}
decl_info dinfo(s->get_family_id(), s->get_decl_kind(), ps.size(), ps.data(), s->private_parameters());
sort_info sinfo(dinfo, s->get_num_elements());
sort_info sinfo(std::move(dinfo), s->get_num_elements());
return mk_sort(s->get_name(), &sinfo);
}
@ -2131,12 +2131,17 @@ bool ast_manager::coercion_needed(func_decl * decl, unsigned num_args, expr * co
expr* ast_manager::coerce_to(expr* e, sort* s) {
sort* se = e->get_sort();
if (s != se && s->get_family_id() == arith_family_id && se->get_family_id() == arith_family_id) {
if (s->get_decl_kind() == REAL_SORT) {
if (s->get_decl_kind() == REAL_SORT)
return mk_app(arith_family_id, OP_TO_REAL, e);
}
else {
return mk_app(arith_family_id, OP_TO_INT, e);
}
else
return mk_app(arith_family_id, OP_TO_INT, e);
}
if (s != se && s->get_family_id() == arith_family_id && is_bool(e)) {
arith_util au(*this);
if (s->get_decl_kind() == REAL_SORT)
return mk_ite(e, au.mk_real(1), au.mk_real(0));
else
return mk_ite(e, au.mk_int(1), au.mk_int(0));
}
else {
return e;
@ -2231,7 +2236,7 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar
std::ostringstream buffer;
buffer << "Wrong number of arguments (" << num_args
<< ") passed to function " << mk_pp(decl, *this);
throw ast_exception(buffer.str());
throw ast_exception(std::move(buffer).str());
}
app * r = nullptr;
if (num_args == 1 && decl->is_chainable() && decl->get_arity() == 2) {

View file

@ -367,8 +367,8 @@ public:
decl_info(family_id, k, num_parameters, parameters, private_parameters), m_num_elements(num_elements) {
}
sort_info(decl_info const& di, sort_size const& num_elements) :
decl_info(di), m_num_elements(num_elements) {}
sort_info(decl_info && di, sort_size const& num_elements) :
decl_info(std::move(di)), m_num_elements(num_elements) {}
bool is_infinite() const { return m_num_elements.is_infinite(); }
bool is_very_big() const { return m_num_elements.is_very_big(); }

View file

@ -47,18 +47,14 @@ format * smt2_pp_environment::pp_fdecl_name(symbol const & s, unsigned & len, bo
len = static_cast<unsigned>(str.length());
return mk_string(m, str);
}
else if (s.is_numerical()) {
std::string str = s.str();
len = static_cast<unsigned>(str.length());
return mk_string(m, str);
}
else if (!s.bare_str()) {
else if (s.is_null()) {
len = 4;
return mk_string(m, "null");
}
else {
len = static_cast<unsigned>(strlen(s.bare_str()));
return mk_string(m, s.bare_str());
std::string str = s.str();
len = static_cast<unsigned>(str.length());
return mk_string(m, str);
}
}

View file

@ -170,12 +170,20 @@ void ast_translation::mk_func_decl(func_decl * f, frame & fr) {
new_fi.set_injective(fi->is_injective());
new_fi.set_skolem(fi->is_skolem());
new_fi.set_idempotent(fi->is_idempotent());
new_fi.set_lambda(fi->is_lambda());
new_f = m_to_manager.mk_func_decl(f->get_name(),
f->get_arity(),
new_domain,
new_range,
new_fi);
if (new_fi.is_lambda()) {
quantifier* q = from().is_lambda_def(f);
ast_translation tr(from(), to());
quantifier* new_q = tr(q);
to().add_lambda_def(new_f, new_q);
}
}
TRACE("ast_translation",
tout << f->get_name() << " "; if (fi) tout << *fi; tout << "\n";

View file

@ -886,8 +886,8 @@ app * bv_util::mk_numeral(rational const & val, unsigned bv_size) const {
}
sort * bv_util::mk_sort(unsigned bv_size) {
parameter p[1] = { parameter(bv_size) };
return m_manager.mk_sort(get_fid(), BV_SORT, 1, p);
parameter p(bv_size);
return m_manager.mk_sort(get_fid(), BV_SORT, 1, &p);
}
unsigned bv_util::get_int2bv_size(parameter const& p) {

View file

@ -16,6 +16,7 @@ Author:
--*/
#include "util/gparams.h"
#include "ast/bv_decl_plugin.h"
#include "ast/char_decl_plugin.h"
#include "ast/arith_decl_plugin.h"
#include "ast/ast_pp.h"
@ -164,6 +165,14 @@ app* char_decl_plugin::mk_le(expr* a, expr* b) {
unsigned v1 = 0, v2 = 0;
if (a == b)
return m_manager->mk_true();
bv_util bv(*m_manager);
if (bv.is_bv(a))
return bv.mk_ule(a, b);
arith_util arith(*m_manager);
if (arith.is_int_real(a))
return arith.mk_le(a, b);
if (a->get_sort() != char_sort())
throw default_exception("range comparison is only supported for bit-vectors, int, real and characters");
bool c1 = is_const_char(a, v1);
bool c2 = is_const_char(b, v2);
if (c1 && c2)

View file

@ -69,8 +69,8 @@ namespace datatype {
domain.push_back(a->instantiate(ps)->get_range());
}
sort_ref range = get_def().instantiate(ps);
parameter pas[1] = { parameter(name()) };
return func_decl_ref(m.mk_func_decl(u().get_family_id(), OP_DT_CONSTRUCTOR, 1, pas, domain.size(), domain.data(), range), m);
parameter pas(name());
return func_decl_ref(m.mk_func_decl(u().get_family_id(), OP_DT_CONSTRUCTOR, 1, &pas, domain.size(), domain.data(), range), m);
}
func_decl_ref constructor::instantiate(sort* dt) const {
@ -1052,8 +1052,8 @@ namespace datatype {
func_decl * util::get_constructor_is(func_decl * con) {
SASSERT(is_constructor(con));
sort * datatype = con->get_range();
parameter ps[1] = { parameter(con)};
return m.mk_func_decl(fid(), OP_DT_IS, 1, ps, 1, &datatype);
parameter ps(con);
return m.mk_func_decl(fid(), OP_DT_IS, 1, &ps, 1, &datatype);
}
func_decl * util::get_constructor_recognizer(func_decl * con) {

View file

@ -293,11 +293,12 @@ namespace euf {
VERIFY(n->num_args() == 0 || !n->merge_enabled() || m_table.contains(n));
}
void egraph::set_value(enode* n, lbool value) {
void egraph::set_value(enode* n, lbool value, justification j) {
if (n->value() == l_undef) {
force_push();
TRACE("euf", tout << bpp(n) << " := " << value << "\n";);
n->set_value(value);
n->m_lit_justification = j;
m_updates.push_back(update_record(n, update_record::value_assignment()));
}
}
@ -657,6 +658,7 @@ namespace euf {
push_lca(n1->get_arg(1), n2->get_arg(0));
return;
}
TRACE("euf_verbose", tout << bpp(n1) << " " << bpp(n2) << "\n");
for (unsigned i = 0; i < n1->num_args(); ++i)
push_lca(n1->get_arg(i), n2->get_arg(i));
@ -713,6 +715,15 @@ namespace euf {
explain_todo(justifications);
}
template <typename T>
void egraph::explain_eq(ptr_vector<T>& justifications, enode* a, enode* b, justification const& j) {
if (j.is_external())
justifications.push_back(j.ext<T>());
else if (j.is_congruence())
push_congruence(a, b, j.is_commutative());
}
template <typename T>
void egraph::explain_eq(ptr_vector<T>& justifications, enode* a, enode* b) {
SASSERT(a->get_root() == b->get_root());
@ -746,11 +757,21 @@ namespace euf {
void egraph::explain_todo(ptr_vector<T>& justifications) {
for (unsigned i = 0; i < m_todo.size(); ++i) {
enode* n = m_todo[i];
if (n->m_target && !n->is_marked1()) {
if (n->is_marked1())
continue;
if (n->m_target) {
n->mark1();
CTRACE("euf_verbose", m_display_justification, n->m_justification.display(tout << n->get_expr_id() << " = " << n->m_target->get_expr_id() << " ", m_display_justification) << "\n";);
explain_eq(justifications, n, n->m_target, n->m_justification);
}
else if (!n->is_marked1() && n->value() != l_undef) {
n->mark1();
if (m.is_true(n->get_expr()) || m.is_false(n->get_expr()))
continue;
justification j = n->m_lit_justification;
SASSERT(j.is_external());
justifications.push_back(j.ext<T>());
}
}
}

View file

@ -226,12 +226,8 @@ namespace euf {
void erase_from_table(enode* p);
template <typename T>
void explain_eq(ptr_vector<T>& justifications, enode* a, enode* b, justification const& j) {
if (j.is_external())
justifications.push_back(j.ext<T>());
else if (j.is_congruence())
push_congruence(a, b, j.is_commutative());
}
void explain_eq(ptr_vector<T>& justifications, enode* a, enode* b, justification const& j);
template <typename T>
void explain_todo(ptr_vector<T>& justifications);
@ -295,7 +291,7 @@ namespace euf {
void add_th_var(enode* n, theory_var v, theory_id id);
void set_th_propagates_diseqs(theory_id id);
void set_merge_enabled(enode* n, bool enable_merge);
void set_value(enode* n, lbool value);
void set_value(enode* n, lbool value, justification j);
void set_bool_var(enode* n, unsigned v) { n->set_bool_var(v); }
void set_relevant(enode* n);
void set_default_relevant(bool b) { m_default_relevant = b; }

View file

@ -63,6 +63,7 @@ namespace euf {
enode* m_cg = nullptr;
th_var_list m_th_vars;
justification m_justification;
justification m_lit_justification;
unsigned m_num_args = 0;
signed char m_lbl_hash = -1; // It is different from -1, if enode is used in a pattern
approx_set m_lbls;
@ -133,6 +134,7 @@ namespace euf {
void del_th_var(theory_id id) { m_th_vars.del_var(id); }
void set_merge_enabled(bool m) { m_merge_enabled = m; }
void set_value(lbool v) { m_value = v; }
void set_justification(justification j) { m_justification = j; }
void set_is_equality() { m_is_equality = true; }
void set_bool_var(sat::bool_var v) { m_bool_var = v; }

View file

@ -33,11 +33,9 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
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'");
}
}
for (unsigned i = 0; i < arity; ++i)
if (!m.is_bool(domain[i]))
m.raise_exception("invalid non-Boolean sort applied to Pseudo-Boolean relation");
symbol sym;
switch(k) {
case OP_AT_LEAST_K: sym = m_at_least_sym; break;
@ -50,9 +48,8 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
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) {
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);
}
@ -93,11 +90,11 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
void pb_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
if (logic == symbol::null || logic == "QF_FD" || logic == "ALL" || logic == "HORN") {
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));
op_names.push_back(builtin_name(m_at_most_sym.str(), OP_AT_MOST_K));
op_names.push_back(builtin_name(m_at_least_sym.str(), OP_AT_LEAST_K));
op_names.push_back(builtin_name(m_pble_sym.str(), OP_PB_LE));
op_names.push_back(builtin_name(m_pbge_sym.str(), OP_PB_GE));
op_names.push_back(builtin_name(m_pbeq_sym.str(), OP_PB_EQ));
}
}

View file

@ -225,6 +225,11 @@ namespace recfun {
m_vars.append(n_vars, vars);
m_rhs = rhs;
if (!is_macro)
for (expr* e : subterms::all(m_rhs))
if (is_lambda(e))
throw default_exception("recursive definitions with lambdas are not supported");
expr_ref_vector conditions(m);
// is the function a macro (unconditional body)?
@ -233,6 +238,8 @@ namespace recfun {
add_case(name, 0, conditions, rhs);
return;
}
// analyze control flow of `rhs`, accumulating guards and
// rebuilding a `ite`-free RHS on the fly for each path in `rhs`.

View file

@ -9,6 +9,7 @@ z3_add_component(rewriter
bv_elim.cpp
bv_rewriter.cpp
cached_var_subst.cpp
char_rewriter.cpp
datatype_rewriter.cpp
der.cpp
distribute_forall.cpp

View file

@ -37,6 +37,7 @@ void bv_rewriter::updt_local_params(params_ref const & _p) {
m_extract_prop = p.bv_extract_prop();
m_ite2id = p.bv_ite2id();
m_le_extra = p.bv_le_extra();
m_le2extract = p.bv_le2extract();
set_sort_sums(p.bv_sort_ac());
}
@ -196,11 +197,11 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons
SASSERT(num_args == 1);
return mk_bit2bool(args[0], f->get_parameter(0).get_int(), result);
case OP_BSMUL_NO_OVFL:
return mk_bvsmul_no_overflow(num_args, args, result);
return mk_bvsmul_no_overflow(num_args, args, true, result);
case OP_BSMUL_NO_UDFL:
return mk_bvsmul_no_overflow(num_args, args, false, result);
case OP_BUMUL_NO_OVFL:
return mk_bvumul_no_overflow(num_args, args, result);
case OP_BSMUL_NO_UDFL:
return mk_bvsmul_no_underflow(num_args, args, result);
default:
return BR_FAILED;
}
@ -577,7 +578,7 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref
result = m().mk_eq(a, m_util.mk_numeral(numeral(0), bv_sz));
return BR_REWRITE1;
}
else if (first_non_zero < bv_sz - 1) {
else if (first_non_zero < bv_sz - 1 && m_le2extract) {
result = m().mk_and(m().mk_eq(m_mk_extract(bv_sz - 1, first_non_zero + 1, a), m_util.mk_numeral(numeral(0), bv_sz - first_non_zero - 1)),
m_util.mk_ule(m_mk_extract(first_non_zero, 0, a), m_mk_extract(first_non_zero, 0, b)));
return BR_REWRITE3;
@ -2802,30 +2803,51 @@ br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resu
return BR_FAILED;
}
br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, expr_ref & result) {
br_status bv_rewriter::mk_distinct(unsigned num_args, expr * const * args, expr_ref & result) {
if (num_args <= 1) {
result = m().mk_true();
return BR_DONE;
}
unsigned sz = get_bv_size(args[0]);
// check if num_args > 2^sz
if (sz >= 32)
return BR_FAILED;
if (num_args <= 1u << sz)
return BR_FAILED;
result = m().mk_false();
return BR_DONE;
}
br_status bv_rewriter::mk_bvsmul_no_overflow(unsigned num, expr * const * args, bool is_overflow, expr_ref & result) {
SASSERT(num == 2);
unsigned bv_sz;
rational a0_val, a1_val;
bool is_num1 = is_numeral(args[0], a0_val, bv_sz);
bool is_num2 = is_numeral(args[1], a1_val, bv_sz);
if (is_num1 && (a0_val.is_zero() || a0_val.is_one())) {
if (is_num1 && (a0_val.is_zero() || (bv_sz != 1 && a0_val.is_one()))) {
result = m().mk_true();
return BR_DONE;
}
if (is_num2 && (a1_val.is_zero() || a1_val.is_one())) {
if (is_num2 && (a1_val.is_zero() || (bv_sz != 1 && a1_val.is_one()))) {
result = m().mk_true();
return BR_DONE;
}
if (!is_num1 || !is_num2)
return BR_FAILED;
rational lim = rational::power_of_two(bv_sz);
bool sign0 = m_util.has_sign_bit(a0_val, bv_sz);
bool sign1 = m_util.has_sign_bit(a1_val, bv_sz);
if (sign0) a0_val = rational::power_of_two(bv_sz) - a0_val;
if (sign1) a1_val = rational::power_of_two(bv_sz) - a1_val;
rational lim = rational::power_of_two(bv_sz-1);
rational r = a0_val * a1_val;
bool sign1 = m_util.has_sign_bit(a0_val, bv_sz);
bool sign2 = m_util.has_sign_bit(a1_val, bv_sz);
result = m().mk_bool_val((sign1 != sign2) || r < lim);
if (is_overflow)
result = m().mk_bool_val(sign0 != sign1 || r < lim);
else
result = m().mk_bool_val(sign0 == sign1 || r <= lim);
return BR_DONE;
}
@ -2855,36 +2877,5 @@ br_status bv_rewriter::mk_bvumul_no_overflow(unsigned num, expr * const * args,
return BR_FAILED;
}
br_status bv_rewriter::mk_bvsmul_no_underflow(unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 2);
unsigned bv_sz;
rational a0_val, a1_val;
bool is_num1 = is_numeral(args[0], a0_val, bv_sz);
bool is_num2 = is_numeral(args[1], a1_val, bv_sz);
if (is_num1 && (a0_val.is_zero() || a0_val.is_one())) {
result = m().mk_true();
return BR_DONE;
}
if (is_num2 && (a1_val.is_zero() || a1_val.is_one())) {
result = m().mk_true();
return BR_DONE;
}
if (is_num1 && is_num2) {
rational ul = rational::power_of_two(bv_sz);
rational lim = rational::power_of_two(bv_sz-1);
if (a0_val >= lim) a0_val -= ul;
if (a1_val >= lim) a1_val -= ul;
rational mr = a0_val * a1_val;
rational neg_lim = -lim;
TRACE("bv_rewriter_bvsmul_no_underflow", tout << "a0:" << a0_val << " a1:" << a1_val << " mr:" << mr << " neg_lim:" << neg_lim << std::endl;);
result = m().mk_bool_val(mr >= neg_lim);
return BR_DONE;
}
return BR_FAILED;
}
template class poly_rewriter<bv_rewriter_core>;

View file

@ -62,6 +62,7 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
bool m_extract_prop;
bool m_bvnot_simpl;
bool m_le_extra;
bool m_le2extract;
bool is_zero_bit(expr * x, unsigned idx);
@ -134,9 +135,8 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
br_status mk_blast_eq_value(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_eq_concat(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_mkbv(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bvsmul_no_overflow(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bvsmul_no_overflow(unsigned num, expr * const * args, bool is_overflow, expr_ref & result);
br_status mk_bvumul_no_overflow(unsigned num, expr * const * args, expr_ref & result);
br_status mk_bvsmul_no_underflow(unsigned num, expr * const * args, expr_ref & result);
bool is_minus_one_times_t(expr * arg);
void mk_t1_add_t2_eq_c(expr * t1, expr * t2, expr * c, expr_ref & result);
@ -180,7 +180,8 @@ public:
bool is_urem_any(expr * e, expr * & dividend, expr * & divisor);
br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result);
br_status mk_ite_core(expr * c, expr * t, expr * e, expr_ref & resul);
br_status mk_ite_core(expr * c, expr * t, expr * e, expr_ref & result);
br_status mk_distinct(unsigned num_args, expr * const * args, expr_ref & result);
bool hi_div0() const { return m_hi_div0; }

View file

@ -0,0 +1,73 @@
/*++
Copyright (c) 2015 Microsoft Corporation
Module Name:
char_rewriter.cpp
Abstract:
Basic rewriting rules for character constraints
Author:
Nikolaj Bjorner (nbjorner) 2015-12-5
--*/
#include "util/debug.h"
#include "ast/rewriter/char_rewriter.h"
#include "ast/bv_decl_plugin.h"
#include "ast/arith_decl_plugin.h"
char_rewriter::char_rewriter(ast_manager& m):
m(m) {
m_char = static_cast<char_decl_plugin*>(m.get_plugin(m.mk_family_id("char")));
}
family_id char_rewriter::get_fid() {
return m_char->get_family_id();
}
br_status char_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(f->get_family_id() == get_fid());
br_status st = BR_FAILED;
switch (f->get_decl_kind()) {
case OP_CHAR_CONST:
break;
case OP_CHAR_LE:
break;
case OP_CHAR_TO_INT:
st = mk_char_to_int(args[0], result);
break;
case OP_CHAR_TO_BV:
break;
case OP_CHAR_FROM_BV:
st = mk_char_from_bv(args[0], result);
break;
case OP_CHAR_IS_DIGIT:
break;
}
return st;
}
br_status char_rewriter::mk_char_from_bv(expr* e, expr_ref& result) {
bv_util bv(m);
rational n;
if (bv.is_numeral(e, n) && n.is_unsigned() && n <= m_char->max_char()) {
result = m_char->mk_char(n.get_unsigned());
return BR_DONE;
}
return BR_FAILED;
}
br_status char_rewriter::mk_char_to_int(expr* e, expr_ref& result) {
unsigned n = 0;
if (m_char->is_const_char(e, n)) {
arith_util arith(m);
result = arith.mk_int(n);
return BR_DONE;
}
return BR_FAILED;
}

View file

@ -0,0 +1,57 @@
/*++
Copyright (c) 2015 Microsoft Corporation
Module Name:
char_rewriter.h
Abstract:
Basic rewriting rules for characters constraints.
Author:
Nikolaj Bjorner (nbjorner) 2022-03-10
Notes:
--*/
#pragma once
#include "ast/char_decl_plugin.h"
#include "ast/rewriter/rewriter_types.h"
#include "util/params.h"
#include "util/lbool.h"
/**
\brief Cheap rewrite rules for character constraints
*/
class char_rewriter {
ast_manager& m;
char_decl_plugin* m_char;
br_status mk_char_from_bv(expr* e, expr_ref& result);
br_status mk_char_to_int(expr* e, expr_ref& result);
public:
char_rewriter(ast_manager& m);
family_id get_fid();
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
expr_ref mk_app(func_decl* f, expr_ref_vector const& args) { return mk_app(f, args.size(), args.data()); }
expr_ref mk_app(func_decl* f, unsigned n, expr* const* args) {
expr_ref result(m);
if (f->get_family_id() != get_fid() ||
BR_FAILED == mk_app_core(f, n, args, result))
result = m.mk_app(f, n, args);
return result;
}
};

View file

@ -23,7 +23,8 @@ Revision History:
expr_ref func_decl_replace::operator()(expr* e) {
m_todo.push_back(e);
m_refs.push_back(e);
while (!m_todo.empty()) {
expr* a = m_todo.back(), *b;
if (m_cache.contains(a)) {

View file

@ -979,9 +979,8 @@ expr* poly_rewriter<Config>::merge_muls(expr* x, expr* y) {
template<typename Config>
bool poly_rewriter<Config>::hoist_ite(expr_ref& e) {
if (!m_hoist_ite) {
if (!m_hoist_ite)
return false;
}
obj_hashtable<expr> shared;
ptr_buffer<expr> adds;
expr_ref_vector bs(m()), pinned(m());

View file

@ -936,22 +936,13 @@ expr_ref seq_rewriter::mk_seq_last(expr* t) {
}
/*
* In general constructs substring(t,0,|t|-1) but if t = substring(s,0,k) then simplifies to substring(s,0,k-1)
* This method assumes that |t| > 0, thus, if t = substring(s,0,k) then k > 0 so substring(s,0,k-1) is correct.
* In general constructs substring(t,0,|t|-1)
* Incorrect comment: "but if t = substring(s,0,k) then simplifies to substring(s,0,k-1).
* This method assumes that |t| > 0, thus, if t = substring(s,0,k) then k > 0 so substring(s,0,k-1) is correct."
* No: if k > |s| then substring(s,0,k) = substring(s,0,k-1)
*/
expr_ref seq_rewriter::mk_seq_butlast(expr* t) {
expr_ref result(m());
expr* s, * j, * k;
rational v;
if (str().is_extract(t, s, j, k) && m_autil.is_numeral(j, v) && v.is_zero()) {
expr_ref_vector k_min_1(m());
k_min_1.push_back(k);
k_min_1.push_back(minus_one());
result = str().mk_substr(s, j, m_autil.mk_add_simplify(k_min_1));
}
else
result = str().mk_substr(t, zero(), m_autil.mk_sub(str().mk_length(t), one()));
return result;
return expr_ref(str().mk_substr(t, zero(), m_autil.mk_sub(str().mk_length(t), one())), m());
}
/*
@ -3128,8 +3119,8 @@ void seq_rewriter::mk_antimirov_deriv_rec(expr* e, expr* r, expr* path, expr_ref
expr_ref range(m());
expr_ref psi(m().mk_false(), m());
if (str().is_unit_string(r1, c1) && str().is_unit_string(r2, c2)) {
SASSERT(u().is_char(c1));
SASSERT(u().is_char(c2));
// SASSERT(u().is_char(c1));
// SASSERT(u().is_char(c2));
// case: c1 <= e <= c2
range = simplify_path(e, m().mk_and(u().mk_le(c1, e), u().mk_le(e, c2)));
psi = simplify_path(e, m().mk_and(path, range));
@ -5531,44 +5522,37 @@ lbool seq_rewriter::eq_length(expr* x, expr* y) {
maximal length (the sequence is bounded).
*/
bool seq_rewriter::min_length(expr* e, unsigned& len) {
bool seq_rewriter::min_length(unsigned sz, expr* const* ss, unsigned& len) {
ptr_buffer<expr> es;
for (unsigned i = 0; i < sz; ++i)
es.push_back(ss[i]);
zstring s;
len = 0;
if (str().is_unit(e)) {
len = 1;
return true;
bool bounded = true;
while (!es.empty()) {
expr* e = es.back();
es.pop_back();
if (str().is_unit(e))
len += 1;
else if (str().is_empty(e))
continue;
else if (str().is_string(e, s))
len += s.length();
else if (str().is_concat(e))
for (expr* arg : *to_app(e))
es.push_back(arg);
else
bounded = false;
}
else if (str().is_empty(e)) {
len = 0;
return true;
}
else if (str().is_string(e, s)) {
len = s.length();
return true;
}
else if (str().is_concat(e)) {
unsigned min_l = 0;
bool bounded = true;
for (expr* arg : *to_app(e)) {
if (!min_length(arg, min_l))
bounded = false;
len += min_l;
}
return bounded;
}
return false;
return bounded;
}
bool seq_rewriter::min_length(expr* e, unsigned& len) {
return min_length(1, &e, len);
}
bool seq_rewriter::min_length(expr_ref_vector const& es, unsigned& len) {
unsigned min_l = 0;
bool bounded = true;
len = 0;
for (expr* arg : es) {
if (!min_length(arg, min_l))
bounded = false;
len += min_l;
}
return bounded;
return min_length(es.size(), es.data(), len);
}
bool seq_rewriter::max_length(expr* e, rational& len) {

View file

@ -322,6 +322,7 @@ class seq_rewriter {
bool reduce_eq_empty(expr* l, expr* r, expr_ref& result);
bool min_length(expr_ref_vector const& es, unsigned& len);
bool min_length(expr* e, unsigned& len);
bool min_length(unsigned sz, expr* const* es, unsigned& len);
bool max_length(expr* e, rational& len);
lbool eq_length(expr* x, expr* y);
expr* concat_non_empty(expr_ref_vector& es);

View file

@ -21,6 +21,7 @@ Notes:
#include "ast/rewriter/bool_rewriter.h"
#include "ast/rewriter/arith_rewriter.h"
#include "ast/rewriter/bv_rewriter.h"
#include "ast/rewriter/char_rewriter.h"
#include "ast/rewriter/datatype_rewriter.h"
#include "ast/rewriter/array_rewriter.h"
#include "ast/rewriter/fpa_rewriter.h"
@ -48,6 +49,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
dl_rewriter m_dl_rw;
pb_rewriter m_pb_rw;
seq_rewriter m_seq_rw;
char_rewriter m_char_rw;
recfun_rewriter m_rec_rw;
arith_util m_a_util;
bv_util m_bv_util;
@ -58,7 +60,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
expr_substitution * m_subst = nullptr;
unsigned long long m_max_memory; // in bytes
bool m_new_subst = false;
unsigned m_max_steps = UINT_MAX;
unsigned m_max_steps = UINT_MAX;
bool m_pull_cheap_ite = true;
bool m_flat = true;
bool m_cache_all = false;
@ -178,7 +180,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
// theory dispatch for =
SASSERT(num == 2);
family_id s_fid = args[0]->get_sort()->get_family_id();
if (s_fid == m_a_rw.get_fid())
if (s_fid == m_a_rw.get_fid())
st = m_a_rw.mk_eq_core(args[0], args[1], result);
else if (s_fid == m_bv_rw.get_fid())
st = m_bv_rw.mk_eq_core(args[0], args[1], result);
@ -191,10 +193,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
else if (s_fid == m_seq_rw.get_fid())
st = m_seq_rw.mk_eq_core(args[0], args[1], result);
if (st != BR_FAILED)
return st;
}
if (k == OP_EQ) {
SASSERT(num == 2);
return st;
st = apply_tamagotchi(args[0], args[1], result);
if (st != BR_FAILED)
return st;
@ -208,16 +207,21 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
return st;
}
if ((k == OP_AND || k == OP_OR) && m_seq_rw.u().has_re()) {
st = m_seq_rw.mk_bool_app(f, num, args, result);
st = m_seq_rw.mk_bool_app(f, num, args, result);
if (st != BR_FAILED)
return st;
}
if (k == OP_EQ && m_seq_rw.u().has_seq() && is_app(args[0]) &&
if (k == OP_EQ && m_seq_rw.u().has_seq() && is_app(args[0]) &&
to_app(args[0])->get_family_id() == m_seq_rw.get_fid()) {
st = m_seq_rw.mk_eq_core(args[0], args[1], result);
if (st != BR_FAILED)
return st;
}
if (k == OP_DISTINCT && num > 0 && m_bv_rw.is_bv(args[0])) {
st = m_bv_rw.mk_distinct(num, args, result);
if (st != BR_FAILED)
return st;
}
return m_b_rw.mk_app_core(f, num, args, result);
}
@ -247,6 +251,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
return m_pb_rw.mk_app_core(f, num, args, result);
if (fid == m_seq_rw.get_fid())
return m_seq_rw.mk_app_core(f, num, args, result);
if (fid == m_char_rw.get_fid())
return m_char_rw.mk_app_core(f, num, args, result);
if (fid == m_rec_rw.get_fid())
return m_rec_rw.mk_app_core(f, num, args, result);
return BR_FAILED;
@ -295,6 +301,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
bool is_ite_value_tree(expr * t) {
if (!m().is_ite(t))
return false;
if (t->get_ref_count() != 1)
return false;
ptr_buffer<app> todo;
todo.push_back(to_app(t));
while (!todo.empty()) {
@ -303,12 +311,12 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
expr * arg1 = ite->get_arg(1);
expr * arg2 = ite->get_arg(2);
if (m().is_ite(arg1) && arg1->get_ref_count() == 1) // do not apply on shared terms, since it may blowup
if (m().is_ite(arg1) && arg1->get_ref_count() == 1) // do not apply on shared terms, since it may blow up
todo.push_back(to_app(arg1));
else if (!m().is_value(arg1))
return false;
if (m().is_ite(arg2) && arg2->get_ref_count() == 1) // do not apply on shared terms, since it may blowup
if (m().is_ite(arg2) && arg2->get_ref_count() == 1) // do not apply on shared terms, since it may blow up
todo.push_back(to_app(arg2));
else if (!m().is_value(arg2))
return false;
@ -319,7 +327,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
br_status pull_ite(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
if (num == 2 && m().is_bool(f->get_range()) && !m().is_bool(args[0])) {
if (m().is_ite(args[0])) {
if (m().is_value(args[1]))
if (m().is_value(args[1]) && args[0]->get_ref_count() == 1)
return pull_ite_core<false>(f, to_app(args[0]), to_app(args[1]), result);
if (m().is_ite(args[1]) && to_app(args[0])->get_arg(0) == to_app(args[1])->get_arg(0)) {
// (p (ite C A1 B1) (ite C A2 B2)) --> (ite (p A1 A2) (p B1 B2))
@ -329,17 +337,17 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
return BR_REWRITE2;
}
}
if (m().is_ite(args[1]) && m().is_value(args[0]))
if (m().is_ite(args[1]) && m().is_value(args[0]) && args[1]->get_ref_count() == 1)
return pull_ite_core<true>(f, to_app(args[1]), to_app(args[0]), result);
}
family_id fid = f->get_family_id();
if (num == 2 && (fid == m().get_basic_family_id() || fid == m_a_rw.get_fid() || fid == m_bv_rw.get_fid())) {
// (f v3 (ite c v1 v2)) --> (ite v (f v3 v1) (f v3 v2))
if (m().is_value(args[0]) && is_ite_value_tree(args[1]))
if (m().is_value(args[0]) && is_ite_value_tree(args[1]))
return pull_ite_core<true>(f, to_app(args[1]), to_app(args[0]), result);
// (f (ite c v1 v2) v3) --> (ite v (f v1 v3) (f v2 v3))
if (m().is_value(args[1]) && is_ite_value_tree(args[0]))
if (m().is_value(args[1]) && is_ite_value_tree(args[0]))
return pull_ite_core<false>(f, to_app(args[0]), to_app(args[1]), result);
}
return BR_FAILED;
@ -800,6 +808,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
m_dl_rw(m),
m_pb_rw(m),
m_seq_rw(m),
m_char_rw(m),
m_rec_rw(m),
m_a_util(m),
m_bv_util(m),

View file

@ -1053,6 +1053,12 @@ sort* seq_util::rex::to_seq(sort* re) {
return to_sort(re->get_parameter(0).get_ast());
}
app* seq_util::rex::mk_power(expr* r, unsigned n) {
parameter param(n);
return m.mk_app(m_fid, OP_RE_POWER, 1, &param, 1, &r);
}
app* seq_util::rex::mk_loop(expr* r, unsigned lo) {
parameter param(lo);
return m.mk_app(m_fid, OP_RE_LOOP, 1, &param, 1, &r);

View file

@ -502,6 +502,7 @@ public:
app* mk_star(expr* r) { return m.mk_app(m_fid, OP_RE_STAR, r); }
app* mk_plus(expr* r) { return m.mk_app(m_fid, OP_RE_PLUS, r); }
app* mk_opt(expr* r) { return m.mk_app(m_fid, OP_RE_OPTION, r); }
app* mk_power(expr* r, unsigned n);
app* mk_loop(expr* r, unsigned lo);
app* mk_loop(expr* r, unsigned lo, unsigned hi);
expr* mk_loop_proper(expr* r, unsigned lo, unsigned hi);

View file

@ -61,11 +61,11 @@ func_decl * special_relations_decl_plugin::mk_func_decl(
void special_relations_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
if (logic == symbol::null) {
op_names.push_back(builtin_name(m_po.bare_str(), OP_SPECIAL_RELATION_PO));
op_names.push_back(builtin_name(m_lo.bare_str(), OP_SPECIAL_RELATION_LO));
op_names.push_back(builtin_name(m_plo.bare_str(), OP_SPECIAL_RELATION_PLO));
op_names.push_back(builtin_name(m_to.bare_str(), OP_SPECIAL_RELATION_TO));
op_names.push_back(builtin_name(m_tc.bare_str(), OP_SPECIAL_RELATION_TC));
op_names.push_back(builtin_name(m_po.str(), OP_SPECIAL_RELATION_PO));
op_names.push_back(builtin_name(m_lo.str(), OP_SPECIAL_RELATION_LO));
op_names.push_back(builtin_name(m_plo.str(), OP_SPECIAL_RELATION_PLO));
op_names.push_back(builtin_name(m_to.str(), OP_SPECIAL_RELATION_TO));
op_names.push_back(builtin_name(m_tc.str(), OP_SPECIAL_RELATION_TC));
}
}

View file

@ -58,7 +58,7 @@ public:
cmd * c = ctx.find_cmd(s);
if (c == nullptr) {
std::string err_msg("unknown command '");
err_msg = err_msg + s.bare_str() + "'";
err_msg = err_msg + s.str() + "'";
throw cmd_exception(std::move(err_msg));
}
m_cmds.push_back(s);
@ -817,9 +817,9 @@ public:
sort_ref range(ctx.m());
array_sort_args.push_back(m_f->get_range());
range = array_sort->instantiate(ctx.pm(), array_sort_args.size(), array_sort_args.data());
parameter p[1] = { parameter(m_f) };
parameter p(m_f);
func_decl_ref new_map(ctx.m());
new_map = ctx.m().mk_func_decl(get_array_fid(ctx), OP_ARRAY_MAP, 1, p, domain.size(), domain.data(), range.get());
new_map = ctx.m().mk_func_decl(get_array_fid(ctx), OP_ARRAY_MAP, 1, &p, domain.size(), domain.data(), range.get());
if (new_map == 0)
throw cmd_exception("invalid array map operator");
ctx.insert(m_name, new_map);

View file

@ -1636,6 +1636,7 @@ void cmd_context::pop(unsigned n) {
restore_aux_pdecls(s.m_aux_pdecls_lim);
restore_assertions(s.m_assertions_lim);
restore_psort_inst(s.m_psort_inst_stack_lim);
m_dt_eh.get()->reset();
m_mcs.shrink(m_mcs.size() - n);
m_scopes.shrink(new_lvl);
if (!m_global_decls)
@ -1815,6 +1816,9 @@ void cmd_context::display_model(model_ref& mdl) {
}
void cmd_context::add_declared_functions(model& mdl) {
model_params p;
if (!p.user_functions())
return;
for (auto const& kv : m_func_decls) {
func_decl* f = kv.m_value.first();
if (f->get_family_id() == null_family_id && !mdl.has_interpretation(f)) {

View file

@ -267,6 +267,7 @@ protected:
cmd_context & m_owner;
datatype_util m_dt_util;
public:
void reset() { m_dt_util.reset(); }
dt_eh(cmd_context & owner);
~dt_eh() override;
void operator()(sort * dt, pdecl* pd) override;

View file

@ -57,6 +57,8 @@ public:
void execute(cmd_context & ctx) override {
model_ref md;
if (ctx.ignore_check())
return;
if (!ctx.is_model_available(md))
throw cmd_exception("model is not available");
if (!m_target)

View file

@ -156,8 +156,8 @@ public:
return false;
return m_sort == static_cast<psort_sort const *>(other)->m_sort;
}
void display(std::ostream & out) const override {
out << m_sort->get_name();
std::ostream& display(std::ostream & out) const override {
return out << m_sort->get_name();
}
};
@ -180,8 +180,8 @@ public:
get_num_params() == other->get_num_params() &&
m_idx == static_cast<psort_var const *>(other)->m_idx;
}
void display(std::ostream & out) const override {
out << "s_" << m_idx;
std::ostream& display(std::ostream & out) const override {
return out << "s_" << m_idx;
}
unsigned idx() const { return m_idx; }
};
@ -254,7 +254,7 @@ public:
}
return true;
}
void display(std::ostream & out) const override {
std::ostream& display(std::ostream & out) const override {
if (m_args.empty()) {
out << m_decl->get_name();
}
@ -267,6 +267,7 @@ public:
}
out << ")";
}
return out;
}
};
@ -342,12 +343,12 @@ void display_sort_args(std::ostream & out, unsigned num_params) {
out << ") ";
}
void psort_user_decl::display(std::ostream & out) const {
std::ostream& psort_user_decl::display(std::ostream & out) const {
out << "(declare-sort " << m_name;
display_sort_args(out, m_num_params);
if (m_def)
m_def->display(out);
out << ")";
return out << ")";
}
// -------------------
@ -364,8 +365,8 @@ sort * psort_dt_decl::instantiate(pdecl_manager & m, unsigned n, sort * const *
return m.instantiate_datatype(this, m_name, n, s);
}
void psort_dt_decl::display(std::ostream & out) const {
out << "(datatype-sort " << m_name << ")";
std::ostream& psort_dt_decl::display(std::ostream & out) const {
return out << "(datatype-sort " << m_name << ")";
}
// -------------------
@ -410,8 +411,8 @@ sort * psort_builtin_decl::instantiate(pdecl_manager & m, unsigned n, unsigned c
}
}
void psort_builtin_decl::display(std::ostream & out) const {
out << "(declare-builtin-sort " << m_name << ")";
std::ostream& psort_builtin_decl::display(std::ostream & out) const {
return out << "(declare-builtin-sort " << m_name << ")";
}
void ptype::display(std::ostream & out, pdatatype_decl const * const * dts) const {
@ -615,7 +616,7 @@ sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const *
}
void pdatatype_decl::display(std::ostream & out) const {
std::ostream& pdatatype_decl::display(std::ostream & out) const {
out << "(declare-datatype " << m_name;
display_sort_args(out, m_num_params);
bool first = true;
@ -631,7 +632,7 @@ void pdatatype_decl::display(std::ostream & out) const {
}
first = false;
}
out << ")";
return out << ")";
}
bool pdatatype_decl::commit(pdecl_manager& m) {
@ -645,9 +646,11 @@ bool pdatatype_decl::commit(pdecl_manager& m) {
datatype_decl * d_ptr = dts.m_buffer[0];
sort_ref_vector sorts(m.m());
bool is_ok = m.get_dt_plugin()->mk_datatypes(1, &d_ptr, m_num_params, ps.data(), sorts);
m.notify_mk_datatype(m_name);
if (is_ok && m_num_params == 0) {
m.notify_new_dt(sorts.get(0), this);
}
return is_ok;
}
@ -722,6 +725,7 @@ void pdecl_manager::notify_datatype(sort *r, psort_decl* p, unsigned n, sort* co
void pdecl_manager::push() {
m_notified_lim.push_back(m_notified_trail.size());
m_datatypes_lim.push_back(m_datatypes_trail.size());
}
void pdecl_manager::pop(unsigned n) {
@ -732,6 +736,16 @@ void pdecl_manager::pop(unsigned n) {
}
m_notified_trail.shrink(new_sz);
m_notified_lim.shrink(m_notified_lim.size() - n);
new_sz = m_datatypes_lim[m_datatypes_lim.size() - n];
if (new_sz != m_datatypes_trail.size()) {
datatype_util util(m());
for (unsigned i = m_datatypes_trail.size(); i-- > new_sz; )
util.plugin().remove(m_datatypes_trail[i]);
}
m_datatypes_trail.shrink(new_sz);
m_datatypes_lim.shrink(m_datatypes_lim.size() - n);
}
bool pdatatypes_decl::instantiate(pdecl_manager & m, sort * const * s) {
@ -751,16 +765,24 @@ bool pdatatypes_decl::commit(pdecl_manager& m) {
sort_ref_vector sorts(m.m());
bool is_ok = m.get_dt_plugin()->mk_datatypes(m_datatypes.size(), dts.m_buffer.data(), 0, nullptr, sorts);
if (is_ok) {
for (pdatatype_decl* d : m_datatypes) {
m.notify_mk_datatype(d->get_name());
}
for (unsigned i = 0; i < m_datatypes.size(); ++i) {
pdatatype_decl* d = m_datatypes[i];
if (d->get_num_params() == 0) {
if (d->get_num_params() == 0)
m.notify_new_dt(sorts.get(i), this);
}
}
}
return is_ok;
}
void pdecl_manager::notify_mk_datatype(symbol const& name) {
m_datatypes_trail.push_back(name);
}
struct pdecl_manager::sort_info {
psort_decl * m_decl;
@ -985,16 +1007,19 @@ void pdecl_manager::del_decl_core(pdecl * p) {
}
void pdecl_manager::del_decl(pdecl * p) {
TRACE("pdecl_manager", tout << "del psort "; p->display(tout); tout << "\n";);
TRACE("pdecl_manager", tout << "del psort "; p->display(tout); tout << "\n";);
if (p->is_psort()) {
psort * _p = static_cast<psort*>(p);
if (_p->is_sort_wrapper()) {
m_sort2psort.erase(static_cast<psort_sort*>(_p)->get_sort());
sort* s = static_cast<psort_sort*>(_p)->get_sort();
m_sort2psort.erase(s);
}
else {
m_table.erase(_p);
}
}
del_decl_core(p);
}

View file

@ -45,7 +45,7 @@ public:
unsigned get_id() const { return m_id; }
unsigned get_ref_count() const { return m_ref_count; }
unsigned hash() const { return m_id; }
virtual void display(std::ostream & out) const {}
virtual std::ostream& display(std::ostream & out) const { return out;}
virtual void reset_cache(pdecl_manager& m) {}
};
@ -123,7 +123,7 @@ protected:
~psort_user_decl() override {}
public:
sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override;
void display(std::ostream & out) const override;
std::ostream& display(std::ostream & out) const override;
};
class psort_builtin_decl : public psort_decl {
@ -137,7 +137,7 @@ protected:
public:
sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override;
sort * instantiate(pdecl_manager & m, unsigned n, unsigned const * s) override;
void display(std::ostream & out) const override;
std::ostream& display(std::ostream & out) const override;
};
class psort_dt_decl : public psort_decl {
@ -148,7 +148,7 @@ protected:
~psort_dt_decl() override {}
public:
sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override;
void display(std::ostream & out) const override;
std::ostream& display(std::ostream & out) const override;
};
@ -198,7 +198,7 @@ class paccessor_decl : public pdecl {
ptype const & get_type() const { return m_type; }
~paccessor_decl() override {}
public:
void display(std::ostream & out) const override { pdecl::display(out); }
std::ostream& display(std::ostream & out) const override { pdecl::display(out); return out; }
void display(std::ostream & out, pdatatype_decl const * const * dts) const;
};
@ -219,7 +219,7 @@ class pconstructor_decl : public pdecl {
constructor_decl * instantiate_decl(pdecl_manager & m, unsigned n, sort * const * s);
~pconstructor_decl() override {}
public:
void display(std::ostream & out) const override { pdecl::display(out); }
std::ostream& display(std::ostream & out) const override { pdecl::display(out); return out; }
void display(std::ostream & out, pdatatype_decl const * const * dts) const;
};
@ -237,7 +237,7 @@ class pdatatype_decl : public psort_decl {
~pdatatype_decl() override {}
public:
sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override;
void display(std::ostream & out) const override;
std::ostream& display(std::ostream & out) const override;
bool has_missing_refs(symbol & missing) const;
bool has_duplicate_accessors(symbol & repeated) const;
bool commit(pdecl_manager& m);
@ -289,6 +289,8 @@ class pdecl_manager {
obj_hashtable<sort> m_notified;
ptr_vector<sort> m_notified_trail;
unsigned_vector m_notified_lim;
svector<symbol> m_datatypes_trail;
unsigned_vector m_datatypes_lim;
void init_list();
void del_decl_core(pdecl * p);
@ -319,6 +321,7 @@ public:
sort * instantiate_datatype(psort_decl* p, symbol const& name, unsigned n, sort * const* s);
sort * instantiate(psort * s, unsigned num, sort * const * args);
void notify_datatype(sort *r, psort_decl* p, unsigned n, sort* const* s);
void notify_mk_datatype(symbol const& name);
void push();
void pop(unsigned n);

View file

@ -223,7 +223,7 @@ class lar_solver : public column_namer {
void insert_row_with_changed_bounds(unsigned rid);
void detect_rows_with_changed_bounds_for_column(unsigned j);
void detect_rows_with_changed_bounds();
void set_value_for_nbasic_column(unsigned j, const impq & new_val);
void update_x_and_inf_costs_for_columns_with_changed_bounds();
void update_x_and_inf_costs_for_columns_with_changed_bounds_tableau();
void solve_with_core_solver();
@ -355,6 +355,9 @@ public:
bp.consume(a, witness);
}
}
void set_value_for_nbasic_column(unsigned j, const impq& new_val);
// lp_assert(implied_bound_is_correctly_explained(ib, explanation)); }
constraint_index mk_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side);
void activate_check_on_equal(constraint_index, var_index&);

View file

@ -217,14 +217,14 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::fill_costs_bounds_
m_can_enter_basis[j] = true;
this->set_scaled_cost(j);
this->m_lower_bounds[j] = numeric_traits<T>::zero();
this->m_upper_bounds[j] =numeric_traits<T>::one();
this->m_upper_bounds[j] = numeric_traits<T>::one();
break;
}
case column_type::free_column: {
m_can_enter_basis[j] = true;
this->set_scaled_cost(j);
this->m_upper_bounds[j] = free_bound;
this->m_lower_bounds[j] = -free_bound;
this->m_upper_bounds[j] = free_bound;
this->m_lower_bounds[j] = -free_bound;
break;
}
case column_type::boxed:

View file

@ -2013,6 +2013,11 @@ namespace algebraic_numbers {
}
else {
algebraic_cell * c = a.to_algebraic();
if (c->m_i == 0) {
// undefined
c->m_i = upm().get_root_id(c->m_p_sz, c->m_p, lower(c)) + 1;
}
SASSERT(c->m_i > 0);
return c->m_i;
}
}

View file

@ -45,8 +45,8 @@ expr * array_factory::mk_array_interp(sort * s, func_interp * & fi) {
func_decl * f = mk_aux_decl_for_array_sort(m_manager, s);
fi = alloc(func_interp, m_manager, get_array_arity(s));
m_model.register_decl(f, fi);
parameter p[1] = { parameter(f) };
expr * val = m_manager.mk_app(get_family_id(), OP_AS_ARRAY, 1, p);
parameter p(f);
expr * val = m_manager.mk_app(get_family_id(), OP_AS_ARRAY, 1, &p);
register_value(val);
return val;
}

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